Projects STRLCPY SeaMoon Commits d8c188af
🤬
Showing first 53 files as there are too many
  • ■ ■ ■ ■ ■
    .gitignore
    skipped 20 lines
    21 21  *.pem
    22 22  *.crt
    23 23  *.key
     24 +*.sql
    24 25   
    25 26  cmd/client/static/dist/*
    26 27  web/
    skipped 9 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/auth.go
    1  -package control
    2  - 
    3  -import (
    4  - "crypto/md5"
    5  - "encoding/hex"
    6  - "net/http"
    7  - "strings"
    8  - 
    9  - "github.com/gin-gonic/gin"
    10  - 
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    12  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    13  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    14  - "github.com/DVKunion/SeaMoon/pkg/tools"
    15  -)
    16  - 
    17  -type AuthController struct {
    18  - svc service.ApiService
    19  -}
    20  - 
    21  -func (a AuthController) Login(c *gin.Context) {
    22  - var obj *models.Auth
    23  - if err := c.ShouldBindJSON(&obj); err != nil {
    24  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    25  - return
    26  - }
    27  - if obj.Username == "" || obj.Password == "" {
    28  - c.JSON(http.StatusBadRequest, errorMsg(10003))
    29  - return
    30  - }
    31  - // 检查用户是否存在
    32  - data := a.svc.List(0, 1, false, service.Condition{Key: "USERNAME", Value: obj.Username}, service.Condition{Key: "TYPE", Value: types.Admin})
    33  - if len(data.([]models.Auth)) != 1 {
    34  - c.JSON(http.StatusForbidden, errorMsg(10010))
    35  - return
    36  - }
    37  - // 检查用户密码是否正确
    38  - target := data.([]models.Auth)[0]
    39  - hash := md5.New()
    40  - 
    41  - // 写入数据到哈希实例中
    42  - hash.Write([]byte(obj.Password))
    43  - 
    44  - // 计算哈希值
    45  - if target.Password != strings.ToLower(hex.EncodeToString(hash.Sum(nil))) {
    46  - c.JSON(http.StatusForbidden, errorMsg(10010))
    47  - return
    48  - }
    49  - 
    50  - token, err := JWTAuth(target.Username, target.Type)
    51  - if err != nil {
    52  - c.JSON(http.StatusForbidden, errorMsg(10010))
    53  - return
    54  - }
    55  - 
    56  - c.JSON(http.StatusOK, successMsg(1, token))
    57  -}
    58  - 
    59  -func (a AuthController) Passwd(c *gin.Context) {
    60  - var obj *models.Auth
    61  - if err := c.ShouldBindJSON(&obj); err != nil {
    62  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    63  - return
    64  - }
    65  - if obj.Username == "" || obj.Password == "" {
    66  - c.JSON(http.StatusBadRequest, errorMsg(10003))
    67  - return
    68  - }
    69  - // 检查用户是否存在
    70  - data := a.svc.List(0, 1, false, service.Condition{Key: "USERNAME", Value: obj.Username}, service.Condition{Key: "TYPE", Value: types.Admin})
    71  - if len(data.([]models.Auth)) != 1 {
    72  - c.JSON(http.StatusBadRequest, errorMsg(10002))
    73  - return
    74  - }
    75  - target := data.([]models.Auth)[0]
    76  - hash := md5.New()
    77  - 
    78  - // 写入数据到哈希实例中
    79  - hash.Write([]byte(obj.Password))
    80  - 
    81  - // 更新数据
    82  - target.Password = strings.ToLower(hex.EncodeToString(hash.Sum(nil)))
    83  - a.svc.Update(target.ID, &target)
    84  - // 更新 jwt secret 让之前的 token 失效
    85  - secret = []byte(tools.GenerateRandomString(64))
    86  - c.JSON(http.StatusOK, successMsg(1, "更新成功"))
    87  -}
    88  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/cloud.go
    1  -package control
    2  - 
    3  -import (
    4  - "net/http"
    5  - "strconv"
    6  - 
    7  - "github.com/gin-gonic/gin"
    8  - 
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    10  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    12  - "github.com/DVKunion/SeaMoon/cmd/client/sdk"
    13  -)
    14  - 
    15  -type CloudProviderController struct {
    16  - svc service.ApiService
    17  -}
    18  - 
    19  -func (cp CloudProviderController) ListCloudProviders(c *gin.Context) {
    20  - var ok bool
    21  - var count int64
    22  - var res = make([]*models.CloudProviderApi, 0)
    23  - var data []models.CloudProvider
    24  - id, err := getPathId(c)
    25  - page, size := getPageSize(c)
    26  - if err != nil {
    27  - count = cp.svc.Count()
    28  - if count < 0 {
    29  - c.JSON(http.StatusOK, successMsg(count, res))
    30  - return
    31  - }
    32  - data, ok = cp.svc.List(page, size, true).([]models.CloudProvider)
    33  - } else {
    34  - count = cp.svc.Count(service.Condition{
    35  - Key: "ID",
    36  - Value: strconv.Itoa(id),
    37  - })
    38  - if count < 0 {
    39  - c.JSON(http.StatusOK, successMsg(count, res))
    40  - return
    41  - }
    42  - data, ok = cp.svc.List(page, size, true, service.Condition{
    43  - Key: "ID",
    44  - Value: strconv.Itoa(id),
    45  - }).([]models.CloudProvider)
    46  - }
    47  - if !ok {
    48  - c.JSON(http.StatusBadRequest, errorMsg(10004))
    49  - }
    50  - // 处理 API
    51  - for _, d := range data {
    52  - api := models.ToApi(d, &models.CloudProviderApi{}, d.Extra())
    53  - res = append(res, api.(*models.CloudProviderApi))
    54  - }
    55  - c.JSON(http.StatusOK, successMsg(count, res))
    56  - return
    57  -}
    58  - 
    59  -func (cp CloudProviderController) ListActiveCloudProviders(c *gin.Context) {
    60  - var ok bool
    61  - var count int64
    62  - var res = make([]*models.CloudProviderApi, 0)
    63  - var data []models.CloudProvider
    64  - page, size := getPageSize(c)
    65  - count = cp.svc.Count(service.Condition{
    66  - Key: "Status",
    67  - Value: types.SUCCESS,
    68  - })
    69  - if count < 0 {
    70  - c.JSON(http.StatusOK, successMsg(count, res))
    71  - return
    72  - }
    73  - data, ok = cp.svc.List(page, size, true,
    74  - service.Condition{
    75  - Key: "Status",
    76  - Value: types.SUCCESS,
    77  - }).([]models.CloudProvider)
    78  - if !ok {
    79  - c.JSON(http.StatusBadRequest, errorMsg(10004))
    80  - }
    81  - for _, d := range data {
    82  - api := models.ToApi(d, &models.CloudProviderApi{}, d.Extra())
    83  - res = append(res, api.(*models.CloudProviderApi))
    84  - }
    85  - c.JSON(http.StatusOK, successMsg(count, res))
    86  - return
    87  -}
    88  - 
    89  -func (cp CloudProviderController) GetCloudProvider(c *gin.Context) {
    90  - id, err := getPathId(c)
    91  - if err != nil {
    92  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    93  - return
    94  - }
    95  - data, ok := cp.svc.GetById(uint(id)).(models.CloudProvider)
    96  - if !ok {
    97  - c.JSON(http.StatusBadRequest, errorMsg(10004))
    98  - }
    99  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(data, &models.CloudProviderApi{}, data.Extra())))
    100  -}
    101  - 
    102  -func (cp CloudProviderController) CreateCloudProvider(c *gin.Context) {
    103  - var obj models.CloudProviderCreateApi
    104  - if err := c.ShouldBindJSON(&obj); err != nil {
    105  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    106  - return
    107  - }
    108  - // 去重
    109  - if exist := service.Exist(cp.svc, service.Condition{
    110  - Key: "NAME",
    111  - Value: obj.Name,
    112  - }); exist {
    113  - c.JSON(http.StatusBadRequest, errorMsg(10001))
    114  - return
    115  - }
    116  - 
    117  - target := &models.CloudProvider{}
    118  - // 转换成对应的结构
    119  - models.ToModel(obj, target)
    120  - // 填充 null 字段
    121  - models.AutoFull(target)
    122  - target = cp.svc.Create(target).(*models.CloudProvider)
    123  - cp.sync(target.ID, c)
    124  -}
    125  - 
    126  -func (cp CloudProviderController) UpdateCloudProvider(c *gin.Context) {
    127  - var obj *models.CloudProviderCreateApi
    128  - if err := c.ShouldBindJSON(&obj); err != nil {
    129  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    130  - return
    131  - }
    132  - id, err := getPathId(c)
    133  - if err != nil {
    134  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    135  - return
    136  - }
    137  - 
    138  - target := &models.CloudProvider{}
    139  - // 转换成对应的结构
    140  - models.ToModel(obj, target)
    141  - target = cp.svc.Update(uint(id), target).(*models.CloudProvider)
    142  - 
    143  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(target, &models.CloudProviderApi{}, target.Extra())))
    144  -}
    145  - 
    146  -func (cp CloudProviderController) SyncCloudProvider(c *gin.Context) {
    147  - id, err := getPathId(c)
    148  - if err != nil {
    149  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    150  - return
    151  - }
    152  - cp.sync(uint(id), c)
    153  -}
    154  - 
    155  -func (cp CloudProviderController) DeleteCloudProvider(c *gin.Context) {
    156  - id, err := getPathId(c)
    157  - if err != nil {
    158  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    159  - return
    160  - }
    161  - 
    162  - obj := cp.svc.GetById(uint(id))
    163  - 
    164  - if obj == nil {
    165  - c.JSON(http.StatusBadRequest, errorMsg(100002))
    166  - return
    167  - }
    168  - 
    169  - cp.svc.Delete(uint(id))
    170  - c.JSON(http.StatusOK, successMsg(0, nil))
    171  -}
    172  - 
    173  -func (cp CloudProviderController) sync(id uint, c *gin.Context) {
    174  - target := cp.svc.GetById(id).(*models.CloudProvider)
    175  - 
    176  - err := sdk.GetSDK(*target.Type).Auth(target.ID)
    177  - if err != nil {
    178  - *target.Status = types.AUTH_ERROR
    179  - cp.svc.Update(target.ID, target)
    180  - c.JSON(http.StatusBadRequest, errorMsgInfo(err.Error()))
    181  - return
    182  - }
    183  - // 自动同步函数
    184  - err = sdk.GetSDK(*target.Type).SyncFC(target.ID)
    185  - if err != nil {
    186  - *target.Status = types.SYNC_ERROR
    187  - cp.svc.Update(target.ID, target)
    188  - c.JSON(http.StatusBadRequest, errorMsgInfo(err.Error()))
    189  - return
    190  - }
    191  - 
    192  - // 更新完的
    193  - target = cp.svc.GetById(target.ID).(*models.CloudProvider)
    194  - *target.Status = types.SUCCESS
    195  - 
    196  - cp.svc.Update(target.ID, target)
    197  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(target, &models.CloudProviderApi{}, target.Extra())))
    198  -}
    199  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/config.go
    1  -package control
    2  - 
    3  -import (
    4  - "net/http"
    5  - 
    6  - "github.com/gin-gonic/gin"
    7  - 
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    10  -)
    11  - 
    12  -type SysConfigController struct {
    13  - svc service.ApiService
    14  -}
    15  - 
    16  -func (sc SysConfigController) ListSystemConfigs(c *gin.Context) {
    17  - page, size := getPageSize(c)
    18  - 
    19  - var obj = sc.svc.List(page, size, false).([]*models.SystemConfig)
    20  - 
    21  - c.JSON(http.StatusOK, successMsg(1, models.ToSystemConfigApi(obj)))
    22  -}
    23  - 
    24  -func (sc SysConfigController) UpdateSystemConfig(c *gin.Context) {
    25  - var obj models.SystemConfigApi
    26  - if err := c.ShouldBindJSON(&obj); err != nil {
    27  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    28  - return
    29  - }
    30  - // model 转换
    31  - target := obj.ToModel()
    32  - sc.svc.Update(0, target)
    33  - c.JSON(http.StatusOK, successMsg(1, obj))
    34  -}
    35  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/control.go
    1  -package control
    2  - 
    3  -import (
    4  - "net/http"
    5  - "strconv"
    6  - 
    7  - "github.com/gin-gonic/gin"
    8  - 
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    10  -)
    11  - 
    12  -var (
    13  - StatisticC = StatisticController{}
    14  - AuthC = AuthController{
    15  - service.GetService("auth"),
    16  - }
    17  - ProxyC = ProxyController{
    18  - service.GetService("proxy"),
    19  - service.GetService("tunnel"),
    20  - }
    21  - TunnelC = TunnelController{
    22  - service.GetService("tunnel"),
    23  - service.GetService("provider"),
    24  - }
    25  - ProviderC = CloudProviderController{
    26  - service.GetService("provider"),
    27  - }
    28  - SysConfigC = SysConfigController{
    29  - service.GetService("config"),
    30  - }
    31  -)
    32  - 
    33  -// PageNotFound 404页面
    34  -func PageNotFound(c *gin.Context) {
    35  - c.JSON(http.StatusNotFound, errorMsg(10404))
    36  -}
    37  - 
    38  -// 通用获取页面信息
    39  -func getPageSize(c *gin.Context) (int, int) {
    40  - defaultPageSize := 10
    41  - defaultPageNum := 0
    42  - 
    43  - pageStr := c.Query("page")
    44  - sizeStr := c.Query("size")
    45  - 
    46  - page, errPage := strconv.Atoi(pageStr)
    47  - if errPage != nil {
    48  - page = defaultPageNum
    49  - }
    50  - 
    51  - size, errSize := strconv.Atoi(sizeStr)
    52  - if errSize != nil {
    53  - size = defaultPageSize
    54  - }
    55  - return page, size
    56  -}
    57  - 
    58  -// 通用获取 path 信息
    59  -func getPathId(c *gin.Context) (int, error) {
    60  - return strconv.Atoi(c.Param("id"))
    61  -}
    62  - 
    63  -// 通用 正常响应
    64  -func successMsg(total int64, data interface{}) gin.H {
    65  - return gin.H{
    66  - "success": true,
    67  - "total": total,
    68  - "data": data,
    69  - }
    70  -}
    71  - 
    72  -var errorCodeMaps = map[int]string{
    73  - 10000: "请求结构错误",
    74  - 10001: "请求数据重复",
    75  - 10002: "请求数据不存在",
    76  - 10003: "请求数据字段缺失",
    77  - 10004: "请求数据异常",
    78  - 
    79  - 10010: "认证失败",
    80  - 10011: "需要认证",
    81  - 10012: "权限不足",
    82  - 10013: "Limit限制",
    83  - 
    84  - 10404: "页面不存在",
    85  -}
    86  - 
    87  -// 通用 错误响应
    88  -func errorMsg(code int) gin.H {
    89  - 
    90  - if msg, ok := errorCodeMaps[code]; ok {
    91  - return gin.H{
    92  - "success": false,
    93  - "code": code,
    94  - "msg": msg,
    95  - }
    96  - }
    97  - 
    98  - return gin.H{
    99  - "type": "error",
    100  - "code": code,
    101  - "msg": "unknown error",
    102  - }
    103  -}
    104  - 
    105  -func errorMsgInfo(m string) gin.H {
    106  - 
    107  - return gin.H{
    108  - "success": false,
    109  - "code": 99999,
    110  - "msg": m,
    111  - }
    112  -}
    113  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/jwt.go
    1  -package control
    2  - 
    3  -import (
    4  - "net/http"
    5  - "time"
    6  - 
    7  - "github.com/gin-gonic/gin"
    8  - "github.com/golang-jwt/jwt"
    9  - 
    10  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    11  - "github.com/DVKunion/SeaMoon/pkg/tools"
    12  -)
    13  - 
    14  -var secret = []byte(tools.GenerateRandomString(64))
    15  - 
    16  -func JWTAuth(user string, t types.AuthType) (string, error) {
    17  - // 生成 token
    18  - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
    19  - "user": user,
    20  - "type": t,
    21  - "exp": time.Now().Add(time.Hour * 72).Unix(),
    22  - })
    23  - 
    24  - return token.SignedString(secret)
    25  -}
    26  - 
    27  -func JWTAuthMiddleware(debug bool) gin.HandlerFunc {
    28  - return func(c *gin.Context) {
    29  - // debug 模式跳过认证
    30  - if debug {
    31  - c.Next()
    32  - return
    33  - }
    34  - // 这里简化了JWT验证逻辑,实际使用时应更复杂
    35  - tokenString := c.GetHeader("Authorization")
    36  - 
    37  - if tokenString == "" {
    38  - c.JSON(http.StatusUnauthorized, errorMsg(10011))
    39  - c.Abort()
    40  - return
    41  - }
    42  - 
    43  - // 验证token是否有效
    44  - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    45  - return secret, nil
    46  - })
    47  - 
    48  - if err != nil {
    49  - c.JSON(http.StatusForbidden, errorMsg(10010))
    50  - c.Abort()
    51  - return
    52  - }
    53  - 
    54  - if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
    55  - if cast, ok := claims["type"].(float64); ok && types.AuthType(cast) == types.Admin {
    56  - c.Next()
    57  - return
    58  - }
    59  - }
    60  - 
    61  - c.JSON(http.StatusForbidden, errorMsg(10012))
    62  - c.Abort()
    63  - return
    64  - }
    65  -}
    66  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/proxy.go
    1  -package control
    2  - 
    3  -import (
    4  - "net/http"
    5  - "strconv"
    6  - 
    7  - "github.com/gin-gonic/gin"
    8  - 
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    10  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    12  - "github.com/DVKunion/SeaMoon/cmd/client/signal"
    13  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    14  -)
    15  - 
    16  -type ProxyController struct {
    17  - svc service.ApiService
    18  - tsvc service.ApiService
    19  -}
    20  - 
    21  -func (pc ProxyController) ListProxies(c *gin.Context) {
    22  - var res = make([]*models.ProxyApi, 0)
    23  - var data []models.Proxy
    24  - var ok bool
    25  - var count int64
    26  - id, err := getPathId(c)
    27  - page, size := getPageSize(c)
    28  - if err != nil {
    29  - count = pc.svc.Count()
    30  - if count < 0 {
    31  - c.JSON(http.StatusOK, successMsg(count, res))
    32  - return
    33  - }
    34  - data, ok = pc.svc.List(page, size, true).([]models.Proxy)
    35  - } else {
    36  - count = pc.svc.Count(service.Condition{
    37  - Key: "ID",
    38  - Value: strconv.Itoa(id),
    39  - })
    40  - if count < 0 {
    41  - c.JSON(http.StatusOK, successMsg(count, res))
    42  - return
    43  - }
    44  - data, ok = pc.svc.List(page, size, true, service.Condition{
    45  - Key: "ID",
    46  - Value: strconv.Itoa(id),
    47  - }).([]models.Proxy)
    48  - }
    49  - if !ok {
    50  - c.JSON(http.StatusBadRequest, errorMsg(10004))
    51  - }
    52  - // 处理 API
    53  - for _, d := range data {
    54  - api := models.ToApi(d, &models.ProxyApi{})
    55  - res = append(res, api.(*models.ProxyApi))
    56  - }
    57  - 
    58  - c.JSON(http.StatusOK, successMsg(count, res))
    59  - return
    60  -}
    61  - 
    62  -func (pc ProxyController) GetProxy(c *gin.Context) {
    63  - id, err := getPathId(c)
    64  - if err != nil {
    65  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    66  - return
    67  - }
    68  - proxy := pc.svc.GetById(uint(id)).(models.Proxy)
    69  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(proxy, &models.ProxyApi{})))
    70  -}
    71  - 
    72  -func (pc ProxyController) CreateProxy(c *gin.Context) {
    73  - var obj *models.ProxyCreateApi
    74  - var proxy *models.Proxy
    75  - if err := c.ShouldBindJSON(&obj); err != nil {
    76  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    77  - return
    78  - }
    79  - // 先查询一下是否存在
    80  - if exist := service.Exist(pc.svc, service.Condition{
    81  - Key: "NAME",
    82  - Value: obj.Name,
    83  - }, service.Condition{
    84  - Key: "tunnel_id",
    85  - Value: obj.TunnelId,
    86  - }); exist {
    87  - c.JSON(http.StatusBadRequest, errorMsg(10001))
    88  - return
    89  - }
    90  - 
    91  - // 判断是从账户还是从函数
    92  - if obj.TunnelId != 0 {
    93  - // 去查询队列
    94  - tun := pc.tsvc.GetById(obj.TunnelId).(*models.Tunnel)
    95  - if tun != nil && tun.ID != 0 {
    96  - // 说明没问题,继续
    97  - target := &models.Proxy{}
    98  - // 转换成对应的结构
    99  - models.ToModel(obj, target)
    100  - // 填充 null 字段
    101  - models.AutoFull(target)
    102  - proxy = pc.svc.Create(target).(*models.Proxy)
    103  - 
    104  - tun.Proxies = append(tun.Proxies, *proxy)
    105  - pc.tsvc.Update(tun.ID, tun)
    106  - }
    107  - }
    108  - 
    109  - // 判断是否从账户来的,账户来的需要先创建 tunnel
    110  - if obj.TunnelCreateApi != nil {
    111  - // 说明没问题,继续
    112  - target := &models.Proxy{}
    113  - // 转换成对应的结构
    114  - models.ToModel(obj, target)
    115  - // 填充 null 字段
    116  - models.AutoFull(target)
    117  - proxy = pc.svc.Create(target).(*models.Proxy)
    118  - // 创建 tunnel
    119  - tun, err := TunnelC.createTunnel(obj.TunnelCreateApi)
    120  - if err != nil {
    121  - *proxy.Status = types.ERROR
    122  - pc.tsvc.Update(target.ID, target)
    123  - c.JSON(http.StatusBadRequest, errorMsgInfo(err.Error()))
    124  - return
    125  - }
    126  - // 再加入 proxy
    127  - tun.Proxies = append(tun.Proxies, *proxy)
    128  - *tun.Status = tunnel.ACTIVE
    129  - pc.tsvc.Update(tun.ID, tun)
    130  - }
    131  - 
    132  - if proxy == nil {
    133  - c.JSON(http.StatusBadRequest, errorMsg(10002))
    134  - return
    135  - }
    136  - 
    137  - // 发送至队列
    138  - signal.Signal().SendStartProxy(proxy.ID, proxy.Addr())
    139  - 
    140  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(proxy, &models.ProxyApi{})))
    141  - return
    142  -}
    143  - 
    144  -func (pc ProxyController) UpdateProxy(c *gin.Context) {
    145  - var obj *models.ProxyCreateApi
    146  - if err := c.ShouldBindJSON(&obj); err != nil {
    147  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    148  - return
    149  - }
    150  - id, err := getPathId(c)
    151  - if err != nil {
    152  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    153  - return
    154  - }
    155  - data := pc.svc.GetById(uint(id)).(*models.Proxy)
    156  - target := &models.Proxy{}
    157  - // 转换成对应的结构
    158  - models.ToModel(obj, target)
    159  - // 说明服务状态发生了改变
    160  - if *target.Status != *data.Status {
    161  - switch *target.Status {
    162  - case types.ACTIVE:
    163  - signal.Signal().SendStartProxy(data.ID, data.Addr())
    164  - case types.INACTIVE:
    165  - signal.Signal().SendStopProxy(data.ID, data.Addr())
    166  - }
    167  - }
    168  - target = pc.svc.Update(uint(id), target).(*models.Proxy)
    169  - 
    170  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(target, &models.ProxyApi{})))
    171  -}
    172  - 
    173  -func (pc ProxyController) DeleteProxy(c *gin.Context) {
    174  - id, err := getPathId(c)
    175  - if err != nil {
    176  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    177  - return
    178  - }
    179  - 
    180  - obj := pc.svc.GetById(uint(id))
    181  - 
    182  - if obj == nil {
    183  - c.JSON(http.StatusBadRequest, errorMsg(100002))
    184  - return
    185  - }
    186  - 
    187  - pc.svc.Delete(uint(id))
    188  - c.JSON(http.StatusOK, successMsg(1, nil))
    189  -}
    190  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/statistic.go
    1  -package control
    2  - 
    3  -import (
    4  - "github.com/gin-gonic/gin"
    5  -)
    6  - 
    7  -type StatisticController struct {
    8  -}
    9  - 
    10  -func (sc StatisticController) Get(c *gin.Context) {
    11  - // 目前数据结构对统计不太友好,放到下一期做大盘吧
    12  -}
    13  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/control/tunnel.go
    1  -package control
    2  - 
    3  -import (
    4  - "errors"
    5  - "net/http"
    6  - "reflect"
    7  - "strconv"
    8  - 
    9  - "github.com/gin-gonic/gin"
    10  - 
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    12  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    13  - "github.com/DVKunion/SeaMoon/cmd/client/sdk"
    14  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    15  -)
    16  - 
    17  -type TunnelController struct {
    18  - svc service.ApiService
    19  - ksvc service.ApiService
    20  -}
    21  - 
    22  -func (tc TunnelController) ListTunnels(c *gin.Context) {
    23  - var res = make([]interface{}, 0)
    24  - var data []models.Tunnel
    25  - var ok bool
    26  - var count int64
    27  - id, err := getPathId(c)
    28  - page, size := getPageSize(c)
    29  - if err != nil {
    30  - count = tc.svc.Count()
    31  - if count < 0 {
    32  - c.JSON(http.StatusOK, successMsg(count, res))
    33  - return
    34  - }
    35  - data, ok = tc.svc.List(page, size, true).([]models.Tunnel)
    36  - } else {
    37  - count = tc.svc.Count(service.Condition{
    38  - Key: "ID",
    39  - Value: strconv.Itoa(id),
    40  - })
    41  - if count < 0 {
    42  - c.JSON(http.StatusOK, successMsg(count, res))
    43  - return
    44  - }
    45  - data, ok = tc.svc.List(page, size, true, service.Condition{
    46  - Key: "ID",
    47  - Value: strconv.Itoa(id),
    48  - }).([]models.Tunnel)
    49  - }
    50  - if !ok {
    51  - c.JSON(http.StatusBadRequest, errorMsg(10004))
    52  - }
    53  - // 处理 API
    54  - for _, d := range data {
    55  - prd := tc.ksvc.GetById(d.CloudProviderId).(*models.CloudProvider)
    56  - api := models.ToApi(d, &models.TunnelApi{}, func(api interface{}) {
    57  - ref := reflect.ValueOf(api).Elem()
    58  - field := ref.FieldByName("CloudProviderType")
    59  - if field.CanSet() {
    60  - field.Set(reflect.ValueOf(prd.Type))
    61  - }
    62  - field = ref.FieldByName("CloudProviderRegion")
    63  - if field.CanSet() {
    64  - field.Set(reflect.ValueOf(prd.Region))
    65  - }
    66  - })
    67  - res = append(res, api.(*models.TunnelApi))
    68  - }
    69  - c.JSON(http.StatusOK, successMsg(count, res))
    70  - return
    71  -}
    72  - 
    73  -func (tc TunnelController) GetTunnel(c *gin.Context) {
    74  - id, err := getPathId(c)
    75  - if err != nil {
    76  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    77  - return
    78  - }
    79  - c.JSON(http.StatusOK, successMsg(1, tc.svc.GetById(uint(id))))
    80  -}
    81  - 
    82  -func (tc TunnelController) CreateTunnel(c *gin.Context) {
    83  - var obj models.TunnelCreateApi
    84  - if err := c.ShouldBindJSON(&obj); err != nil {
    85  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    86  - return
    87  - }
    88  - // 先查询一下是否存在
    89  - if exist := service.Exist(tc.svc, service.Condition{
    90  - Key: "NAME",
    91  - Value: obj.Name,
    92  - }, service.Condition{
    93  - Key: "cloud_provider_id",
    94  - Value: obj.CloudProviderId,
    95  - }); exist {
    96  - c.JSON(http.StatusBadRequest, errorMsg(10001))
    97  - return
    98  - }
    99  - 
    100  - target, err := tc.createTunnel(&obj)
    101  - if err != nil {
    102  - c.JSON(http.StatusBadRequest, errorMsgInfo(err.Error()))
    103  - return
    104  - }
    105  - 
    106  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(target, &models.TunnelApi{})))
    107  -}
    108  - 
    109  -func (tc TunnelController) UpdateTunnel(c *gin.Context) {
    110  - var obj *models.TunnelCreateApi
    111  - if err := c.ShouldBindJSON(&obj); err != nil {
    112  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    113  - return
    114  - }
    115  - id, err := getPathId(c)
    116  - if err != nil {
    117  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    118  - return
    119  - }
    120  - 
    121  - target := &models.Tunnel{}
    122  - // 转换成对应的结构
    123  - models.ToModel(obj, target)
    124  - target = tc.svc.Update(uint(id), target).(*models.Tunnel)
    125  - 
    126  - c.JSON(http.StatusOK, successMsg(1, models.ToApi(target, &models.TunnelApi{})))
    127  -}
    128  - 
    129  -func (tc TunnelController) DeleteTunnel(c *gin.Context) {
    130  - id, err := getPathId(c)
    131  - if err != nil {
    132  - c.JSON(http.StatusBadRequest, errorMsg(10000))
    133  - return
    134  - }
    135  - 
    136  - obj := tc.svc.GetById(uint(id))
    137  - 
    138  - if obj == nil {
    139  - c.JSON(http.StatusBadRequest, errorMsg(100002))
    140  - return
    141  - }
    142  - 
    143  - tc.svc.Delete(uint(id))
    144  - c.JSON(http.StatusOK, successMsg(0, nil))
    145  -}
    146  - 
    147  -func (tc TunnelController) createTunnel(tun *models.TunnelCreateApi) (*models.Tunnel, error) {
    148  - target := &models.Tunnel{}
    149  - 
    150  - // 检查账户provider是否正确
    151  - prv := tc.ksvc.GetById(tun.CloudProviderId).(*models.CloudProvider)
    152  - if prv == nil || prv.ID == 0 {
    153  - return target, errors.New("provider 数据不存在")
    154  - }
    155  - if *prv.MaxLimit != 0 && *prv.MaxLimit < len(prv.Tunnels)+1 {
    156  - return target, errors.New("超出最大 limit 限制")
    157  - }
    158  - 
    159  - // 转换成对应的结构
    160  - models.ToModel(tun, target)
    161  - // 填充默认值
    162  - models.AutoFull(target)
    163  - target.CloudProviderId = 0
    164  - target = tc.svc.Create(target).(*models.Tunnel)
    165  - 
    166  - // 添加到 provider 中去
    167  - prv.Tunnels = append(prv.Tunnels, *target)
    168  - tc.ksvc.Update(prv.ID, prv)
    169  - 
    170  - err := sdk.GetSDK(*prv.Type).Deploy(prv.ID, target)
    171  - if err != nil {
    172  - // 部署失败了,更新状态
    173  - *target.Status = tunnel.ERROR
    174  - tc.svc.Update(target.ID, target)
    175  - return target, err
    176  - }
    177  - return target, nil
    178  -}
    179  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/database/sqlite3.go
    1  -package database
    2  - 
    3  -import (
    4  - "log/slog"
    5  - "os"
    6  - 
    7  - "github.com/glebarez/sqlite"
    8  - "gorm.io/gorm"
    9  - "gorm.io/gorm/logger"
    10  - 
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    12  -)
    13  - 
    14  -const dbPath string = ".seamoon.db"
    15  - 
    16  -var (
    17  - globalDB *gorm.DB
    18  - migrateFunc []func()
    19  -)
    20  - 
    21  -func Init() {
    22  - gormConfig := gorm.Config{
    23  - Logger: logger.Default.LogMode(logger.Silent),
    24  - DisableForeignKeyConstraintWhenMigrating: true,
    25  - }
    26  - 
    27  - var err error
    28  - 
    29  - if _, exist := os.Stat(dbPath); os.IsNotExist(exist) {
    30  - defer func() {
    31  - slog.Info("初始化数据库......")
    32  - for _, m := range models.ModelList {
    33  - // 初始化表
    34  - globalDB.AutoMigrate(m)
    35  - }
    36  - // 写表
    37  - for _, fn := range migrateFunc {
    38  - fn()
    39  - }
    40  - }()
    41  - }
    42  - 
    43  - globalDB, err = gorm.Open(sqlite.Open(dbPath), &gormConfig)
    44  - if err != nil {
    45  - panic(err)
    46  - }
    47  -}
    48  - 
    49  -func GetConn() *gorm.DB {
    50  - return globalDB
    51  -}
    52  - 
    53  -// QueryPage 公共查询所有数据的方法
    54  -func QueryPage(page, size int) *gorm.DB {
    55  - if page < 0 {
    56  - page = 0
    57  - }
    58  - if size <= 0 {
    59  - size = 10
    60  - }
    61  - return globalDB.Offset(page * size).Limit(size)
    62  -}
    63  - 
    64  -func RegisterMigrate(f func()) {
    65  - migrateFunc = append(migrateFunc, f)
    66  -}
    67  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/models/auth.go
    1  -package models
    2  - 
    3  -import (
    4  - "gorm.io/gorm"
    5  - 
    6  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    7  -)
    8  - 
    9  -var DefaultAuth = []Auth{
    10  - {
    11  - Type: types.Admin,
    12  - Username: "seamoon",
    13  - Password: "2575a6f37310dd27e884a0305a2dd210",
    14  - },
    15  -}
    16  - 
    17  -type Auth struct {
    18  - gorm.Model
    19  - 
    20  - Type types.AuthType // 认证类型,用于判断该认证信息适用于啥的
    21  - Username string `json:"username"`
    22  - Password string `json:"password"`
    23  -}
    24  - 
    25  -type CloudAuth struct {
    26  - // 阿里需要 ID
    27  - AccessId string `json:"access_id" gorm:"not null"`
    28  - // 普通云厂商使用的认证
    29  - AccessKey string `json:"access_key" gorm:"not null"`
    30  - AccessSecret string `json:"access_secret" gorm:"not null"`
    31  - 
    32  - // 接口类型认证信息
    33  - Token string `json:"token" gorm:"not null"`
    34  - 
    35  - // Sealos 认证信息
    36  - KubeConfig string `json:"kube_config" gorm:"not null"`
    37  -}
    38  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/models/cloud.go
    1  -package models
    2  - 
    3  -import (
    4  - "reflect"
    5  - "time"
    6  - 
    7  - "gorm.io/gorm"
    8  - 
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    10  -)
    11  - 
    12  -type CloudProvider struct {
    13  - gorm.Model
    14  - 
    15  - // 元信息
    16  - Name *string `gorm:"not null"`
    17  - Desc *string `gorm:"not null"`
    18  - Region *string `gorm:"not null"`
    19  - Type *types.CloudType `gorm:"not null"`
    20  - 
    21  - // 账户信息
    22  - Amount *float64 `gorm:"not null"`
    23  - Cost *float64 `gorm:"not null"`
    24  - Status *types.CloudStatus `gorm:"not null"`
    25  - MaxLimit *int `gorm:"not null"`
    26  - 
    27  - CloudAuth *CloudAuth `gorm:"embedded"`
    28  - 
    29  - // 连表
    30  - Tunnels []Tunnel `gorm:"foreignKey:CloudProviderId;references:ID"`
    31  -}
    32  - 
    33  -// CloudProviderApi api 不展示敏感的账户数据
    34  -type CloudProviderApi struct {
    35  - ID uint `json:"id"`
    36  - CreatedAt time.Time `json:"created_at"`
    37  - UpdatedAt time.Time `json:"updated_at"`
    38  - 
    39  - Name *string `json:"name"`
    40  - Desc *string `json:"desc"`
    41  - Type *types.CloudType `json:"type"`
    42  - Region *string `json:"region"`
    43  - 
    44  - // 账户信息
    45  - Amount *float64 `json:"amount"`
    46  - Cost *float64 `json:"cost"`
    47  - Status *types.CloudStatus `json:"status"`
    48  - Count *int `json:"count"`
    49  - MaxLimit *int `json:"max_limit"`
    50  -}
    51  - 
    52  -// CloudProviderCreateApi api 用于创建时接受数据的模型
    53  -type CloudProviderCreateApi struct {
    54  - Name *string `json:"name"`
    55  - Region *string `json:"region"`
    56  - Desc *string `json:"desc"`
    57  - Status *types.CloudStatus `json:"status"`
    58  - Type *types.CloudType `json:"type"`
    59  - 
    60  - // 认证信息
    61  - CloudAuth *CloudAuth `json:"cloud_auth"`
    62  -}
    63  - 
    64  -func (p CloudProvider) Extra() func(api interface{}) {
    65  - return func(api interface{}) {
    66  - ref := reflect.ValueOf(api).Elem()
    67  - field := ref.FieldByName("Count")
    68  - if field.CanSet() {
    69  - a := len(p.Tunnels)
    70  - field.Set(reflect.ValueOf(&a))
    71  - }
    72  - }
    73  -}
    74  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/models/config.go
    1  -package models
    2  - 
    3  -import (
    4  - "gorm.io/gorm"
    5  - 
    6  - "github.com/DVKunion/SeaMoon/pkg/consts"
    7  -)
    8  - 
    9  -var DefaultSysConfig = []SystemConfig{
    10  - {
    11  - Key: "control_addr",
    12  - Value: "0.0.0.0",
    13  - },
    14  - {
    15  - Key: "control_port",
    16  - Value: "7778",
    17  - },
    18  - {
    19  - Key: "control_log",
    20  - Value: "seamoon-web.log",
    21  - },
    22  - {
    23  - Key: "version",
    24  - Value: consts.Version,
    25  - },
    26  -}
    27  - 
    28  -// SystemConfig 系统标准配置表
    29  -type SystemConfig struct {
    30  - gorm.Model
    31  - 
    32  - Key string
    33  - Value string
    34  -}
    35  - 
    36  -// SystemConfigApi 对外暴露接口
    37  -type SystemConfigApi struct {
    38  - // 为了 web 方便, 直接转化成对应的 key 了
    39  - ControlAddr string `json:"control_addr"`
    40  - ControlPort string `json:"control_port"`
    41  - ControlLog string `json:"control_log"`
    42  - 
    43  - Version string `json:"version"`
    44  -}
    45  - 
    46  -// ToModel SysConfig 比较特殊,存储时候是一个 KEY-VALUE 模式,
    47  -// 因此让他自己重新实现一下 ToModel
    48  -func (p *SystemConfigApi) ToModel() []SystemConfig {
    49  - // 由于目前东西比较少,懒得写反射了;后续如果也有这种 KV 存储转换的需求,可以抽到 models 公共方法中
    50  - var res = make([]SystemConfig, 0)
    51  - res = append(res, SystemConfig{
    52  - Key: "control_addr",
    53  - Value: p.ControlAddr,
    54  - })
    55  - res = append(res, SystemConfig{
    56  - Key: "control_port",
    57  - Value: p.ControlPort,
    58  - })
    59  - res = append(res, SystemConfig{
    60  - Key: "control_log",
    61  - Value: p.ControlLog,
    62  - })
    63  - res = append(res, SystemConfig{
    64  - Key: "version",
    65  - Value: p.Version,
    66  - })
    67  - 
    68  - return res
    69  -}
    70  - 
    71  -func ToSystemConfigApi(sc []*SystemConfig) SystemConfigApi {
    72  - var res = SystemConfigApi{}
    73  - for _, s := range sc {
    74  - switch s.Key {
    75  - case "control_addr":
    76  - res.ControlAddr = s.Value
    77  - case "control_port":
    78  - res.ControlPort = s.Value
    79  - case "control_log":
    80  - res.ControlLog = s.Value
    81  - case "version":
    82  - res.Version = s.Value
    83  - }
    84  - }
    85  - return res
    86  -}
    87  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/models/proxy.go
    1  -package models
    2  - 
    3  -import (
    4  - "strings"
    5  - "time"
    6  - 
    7  - "gorm.io/gorm"
    8  - 
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    10  - "github.com/DVKunion/SeaMoon/pkg/transfer"
    11  -)
    12  - 
    13  -type Proxy struct {
    14  - gorm.Model
    15  - 
    16  - TunnelID uint
    17  - Name *string
    18  - Type *transfer.Type
    19  - Status *types.ProxyStatus
    20  - Conn *int
    21  - Speed *float64
    22  - Lag *int
    23  - InBound *int64
    24  - OutBound *int64
    25  - ListenAddr *string
    26  - ListenPort *string
    27  -}
    28  - 
    29  -type ProxyApi struct {
    30  - ID uint `json:"id"`
    31  - CreatedAt time.Time `json:"created_at"`
    32  - UpdatedAt time.Time `json:"updated_at"`
    33  - Name *string `json:"name"`
    34  - Type *transfer.Type `json:"type"`
    35  - Status *types.ProxyStatus `json:"status"`
    36  - Conn *int `json:"conn"`
    37  - Speed *float64 `json:"speed"`
    38  - Lag *int `json:"lag"`
    39  - InBound *int64 `json:"in_bound"`
    40  - OutBound *int64 `json:"out_bound"`
    41  - ListenAddr *string `json:"listen_address"`
    42  - ListenPort *string `json:"listen_port"`
    43  -}
    44  - 
    45  -type ProxyCreateApi struct {
    46  - Name *string `json:"name"`
    47  - Type *transfer.Type `json:"type"`
    48  - ListenAddr *string `json:"listen_address"`
    49  - ListenPort *string `json:"listen_port"`
    50  - Status *types.ProxyStatus `json:"status"`
    51  - TunnelId uint `json:"tunnel_id"`
    52  - TunnelCreateApi *TunnelCreateApi `json:"tunnel_create_api"`
    53  -}
    54  - 
    55  -func (p Proxy) Addr() string {
    56  - return strings.Join([]string{*p.ListenAddr, *p.ListenPort}, ":")
    57  -}
    58  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/models/tunnel.go
    1  -package models
    2  - 
    3  -import (
    4  - "time"
    5  - 
    6  - "gorm.io/gorm"
    7  - 
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    9  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    10  -)
    11  - 
    12  -// Tunnel 表示着实际部署的一个函数节点
    13  -type Tunnel struct {
    14  - gorm.Model
    15  - 
    16  - CloudProviderId uint
    17  - 
    18  - Name *string // 隧道名称,建议英文
    19  - Addr *string // 服务地址
    20  - Port *string // 服务端口
    21  - Type *tunnel.Type // 隧道协议类型
    22  - Status *tunnel.Status // 隧道状态
    23  - 
    24  - TunnelConfig *TunnelConfig `gorm:"embedded"`
    25  - // 连表查询
    26  - Proxies []Proxy `gorm:"foreignKey:TunnelID;references:ID"`
    27  -}
    28  - 
    29  -func (t *Tunnel) GetAddr() string {
    30  - switch *t.Type {
    31  - case tunnel.WST:
    32  - if t.TunnelConfig.TLS {
    33  - return "wss://" + *t.Addr
    34  - }
    35  - return "ws://" + *t.Addr
    36  - case tunnel.GRT:
    37  - if t.TunnelConfig.TLS {
    38  - return "grpcs://" + *t.Addr
    39  - }
    40  - return "grpc://" + *t.Addr
    41  - }
    42  - return ""
    43  -}
    44  - 
    45  -type TunnelConfig struct {
    46  - // 函数配置
    47  - CPU float32 `json:"cpu"` // CPU 资源
    48  - Memory int32 `json:"memory"` // 内存资源
    49  - Instance int32 `json:"instance"` // 最大实例处理数
    50  - TunnelAuthType types.AuthType `json:"tunnel_auth_type"` // 函数认证方式
    51  - 
    52  - TLS bool `json:"tls"` // 是否开启 TLS 传输, 开启后自动使用 wss 协议
    53  - Tor bool `json:"tor"` // 是否开启 Tor 转发
    54  -}
    55  - 
    56  -type TunnelApi struct {
    57  - CloudProviderId uint `json:"cloud_provider_id"`
    58  - CloudProviderRegion *string `json:"cloud_provider_region"`
    59  - CloudProviderType *types.CloudType `json:"cloud_provider_type"`
    60  - 
    61  - ID uint `json:"id"`
    62  - CreatedAt time.Time `json:"created_at"`
    63  - UpdatedAt time.Time `json:"updated_at"`
    64  - 
    65  - Name *string `json:"name"`
    66  - Addr *string `json:"address"`
    67  - Port *string `json:"port"`
    68  - Type *tunnel.Type `json:"type"`
    69  - Status *tunnel.Status `json:"status"`
    70  - 
    71  - TunnelConfig *TunnelConfig `json:"tunnel_config"`
    72  -}
    73  - 
    74  -type TunnelCreateApi struct {
    75  - CloudProviderId uint `json:"cloud_provider_id"`
    76  - Name *string `json:"name"`
    77  - Port *string `json:"port"`
    78  - Type *tunnel.Type `json:"type"`
    79  - Status *tunnel.Status `json:"status"`
    80  - 
    81  - TunnelConfig *TunnelConfig `json:"tunnel_config"`
    82  -}
    83  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/route.go
    1  -package api
    2  - 
    3  -import (
    4  - "net/http"
    5  - 
    6  - "github.com/gin-gonic/gin"
    7  - 
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/control"
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    10  -)
    11  - 
    12  -func init() {
    13  - database.Init()
    14  -}
    15  - 
    16  -func Register(router *gin.Engine, debug bool) {
    17  - // pprof
    18  - if debug {
    19  - router.GET("/debug/pprof/*any", gin.WrapH(http.DefaultServeMux))
    20  - }
    21  - // statistic
    22  - router.GET("/api/statistic", control.JWTAuthMiddleware(debug), control.StatisticC.Get)
    23  - // user
    24  - router.POST("/api/user/login", control.AuthC.Login)
    25  - router.PUT("/api/user/passwd", control.JWTAuthMiddleware(debug), control.AuthC.Passwd)
    26  - // proxy
    27  - router.GET("/api/proxy", control.JWTAuthMiddleware(debug), control.ProxyC.ListProxies)
    28  - router.GET("/api/proxy/:id", control.JWTAuthMiddleware(debug), control.ProxyC.ListProxies)
    29  - router.POST("/api/proxy", control.JWTAuthMiddleware(debug), control.ProxyC.CreateProxy)
    30  - router.PUT("/api/proxy/:id", control.JWTAuthMiddleware(debug), control.ProxyC.UpdateProxy)
    31  - router.DELETE("/api/proxy/:id", control.JWTAuthMiddleware(debug), control.ProxyC.DeleteProxy)
    32  - // tunnel
    33  - router.GET("/api/tunnel", control.JWTAuthMiddleware(debug), control.TunnelC.ListTunnels)
    34  - router.GET("/api/tunnel/:id", control.JWTAuthMiddleware(debug), control.TunnelC.ListTunnels)
    35  - router.POST("/api/tunnel", control.JWTAuthMiddleware(debug), control.TunnelC.CreateTunnel)
    36  - router.PUT("/api/tunnel/:id", control.JWTAuthMiddleware(debug), control.TunnelC.UpdateTunnel)
    37  - router.DELETE("/api/tunnel/:id", control.JWTAuthMiddleware(debug), control.TunnelC.DeleteTunnel)
    38  - // cloud provider
    39  - router.GET("/api/provider", control.JWTAuthMiddleware(debug), control.ProviderC.ListCloudProviders)
    40  - router.GET("/api/provider/active", control.JWTAuthMiddleware(debug), control.ProviderC.ListActiveCloudProviders)
    41  - router.GET("/api/provider/:id", control.JWTAuthMiddleware(debug), control.ProviderC.ListCloudProviders)
    42  - router.POST("/api/provider", control.JWTAuthMiddleware(debug), control.ProviderC.CreateCloudProvider)
    43  - router.PUT("/api/provider/sync/:id", control.JWTAuthMiddleware(debug), control.ProviderC.SyncCloudProvider)
    44  - router.PUT("/api/provider/:id", control.JWTAuthMiddleware(debug), control.ProviderC.UpdateCloudProvider)
    45  - router.DELETE("/api/provider/:id", control.JWTAuthMiddleware(debug), control.ProviderC.DeleteCloudProvider)
    46  - // system config
    47  - router.GET("/api/config", control.JWTAuthMiddleware(debug), control.SysConfigC.ListSystemConfigs)
    48  - router.PUT("/api/config/", control.JWTAuthMiddleware(debug), control.SysConfigC.UpdateSystemConfig)
    49  -}
    50  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/auth.go
    1  -package service
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    6  -)
    7  - 
    8  -type AuthService struct {
    9  -}
    10  - 
    11  -func (a AuthService) Count(cond ...Condition) int64 {
    12  - var res int64 = 0
    13  - conn := database.GetConn()
    14  - for _, cs := range cond {
    15  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    16  - }
    17  - conn.Model(&models.Auth{}).Count(&res)
    18  - return res
    19  -}
    20  - 
    21  -func (a AuthService) List(page int, size int, preload bool, cond ...Condition) interface{} {
    22  - var data = make([]models.Auth, 0)
    23  - conn := database.QueryPage(page, size)
    24  - for _, cs := range cond {
    25  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    26  - }
    27  - conn.Find(&data)
    28  - return data
    29  -}
    30  - 
    31  -func (a AuthService) GetById(id uint) interface{} {
    32  - var data = models.Auth{}
    33  - database.GetConn().Limit(1).Where("ID = ?", id).Find(&data)
    34  - return &data
    35  -}
    36  - 
    37  -func (a AuthService) Create(obj interface{}) interface{} {
    38  - database.GetConn().Create(obj.(*models.Auth))
    39  - return obj
    40  -}
    41  - 
    42  -func (a AuthService) Update(id uint, obj interface{}) interface{} {
    43  - obj.(*models.Auth).ID = id
    44  - database.GetConn().Updates(obj.(*models.Auth))
    45  - return a.GetById(id)
    46  -}
    47  - 
    48  -func (a AuthService) Delete(id uint) {
    49  - database.GetConn().Delete(&models.Auth{}, id)
    50  -}
    51  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/cloud.go
    1  -package service
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    6  -)
    7  - 
    8  -type CloudProviderService struct {
    9  -}
    10  - 
    11  -func (c CloudProviderService) Count(cond ...Condition) int64 {
    12  - var res int64 = 0
    13  - conn := database.GetConn()
    14  - for _, cs := range cond {
    15  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    16  - }
    17  - conn.Model(&models.CloudProvider{}).Count(&res)
    18  - return res
    19  -}
    20  - 
    21  -func (c CloudProviderService) List(page int, size int, preload bool, cond ...Condition) interface{} {
    22  - var data = make([]models.CloudProvider, 0)
    23  - conn := database.QueryPage(page, size)
    24  - if preload {
    25  - conn = conn.Preload("Tunnels.Proxies")
    26  - }
    27  - for _, cs := range cond {
    28  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    29  - }
    30  - conn.Find(&data)
    31  - return data
    32  -}
    33  - 
    34  -func (c CloudProviderService) GetById(id uint) interface{} {
    35  - var data = models.CloudProvider{}
    36  - //database.GetConn().Unscoped().Limit(1).Where("ID = ?", id).Find(&data)
    37  - database.GetConn().Limit(1).Where("ID = ?", id).Find(&data)
    38  - return &data
    39  -}
    40  - 
    41  -func (c CloudProviderService) Create(obj interface{}) interface{} {
    42  - database.GetConn().Create(obj.(*models.CloudProvider))
    43  - return obj
    44  -}
    45  - 
    46  -func (c CloudProviderService) Update(id uint, obj interface{}) interface{} {
    47  - obj.(*models.CloudProvider).ID = id
    48  - database.GetConn().Updates(obj.(*models.CloudProvider))
    49  - return c.GetById(id)
    50  -}
    51  - 
    52  -func (c CloudProviderService) Delete(id uint) {
    53  - database.GetConn().Delete(&models.CloudProvider{}, id)
    54  -}
    55  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/config.go
    1  -package service
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    6  -)
    7  - 
    8  -type SystemConfigService struct {
    9  -}
    10  - 
    11  -func (s SystemConfigService) Count(cond ...Condition) int64 {
    12  - var res int64 = 0
    13  - conn := database.GetConn()
    14  - for _, cs := range cond {
    15  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    16  - }
    17  - conn.Model(&models.SystemConfig{}).Count(&res)
    18  - return res
    19  -}
    20  - 
    21  -func (s SystemConfigService) List(page, size int, preload bool, cond ...Condition) interface{} {
    22  - var data = make([]*models.SystemConfig, 0)
    23  - conn := database.QueryPage(page, size)
    24  - for _, cs := range cond {
    25  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    26  - }
    27  - conn.Find(&data)
    28  - return data
    29  -}
    30  - 
    31  -func (s SystemConfigService) GetById(id uint) interface{} {
    32  - var data = models.SystemConfig{}
    33  - database.GetConn().Limit(1).Where("ID = ?", id).Find(&data)
    34  - return &data
    35  -}
    36  - 
    37  -func (s SystemConfigService) GetByName(name string) *models.SystemConfig {
    38  - var data = models.SystemConfig{}
    39  - database.GetConn().Limit(1).Where("KEY = ?", name).Find(&data)
    40  - return &data
    41  -}
    42  - 
    43  -func (s SystemConfigService) Create(obj interface{}) interface{} {
    44  - database.GetConn().Create(obj.(*models.SystemConfig))
    45  - return obj
    46  -}
    47  - 
    48  -func (s SystemConfigService) Update(id uint, obj interface{}) interface{} {
    49  - for _, sys := range obj.([]models.SystemConfig) {
    50  - if sys.Key == "version" || sys.Value == "" {
    51  - continue
    52  - }
    53  - // api 传过来的不知道 id 的,从 key 去查吧
    54  - target := s.GetByName(sys.Key)
    55  - target.Value = sys.Value
    56  - database.GetConn().Updates(target)
    57  - }
    58  - 
    59  - return nil
    60  -}
    61  - 
    62  -func (s SystemConfigService) Delete(id uint) {
    63  - // 系统配置禁止删除
    64  - return
    65  -}
    66  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/proxy.go
    1  -package service
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    6  -)
    7  - 
    8  -type ProxyService struct {
    9  -}
    10  - 
    11  -func (p ProxyService) Count(cond ...Condition) int64 {
    12  - var res int64 = 0
    13  - conn := database.GetConn()
    14  - for _, cs := range cond {
    15  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    16  - }
    17  - conn.Model(&models.Proxy{}).Count(&res)
    18  - return res
    19  -}
    20  - 
    21  -func (p ProxyService) List(page, size int, preload bool, cond ...Condition) interface{} {
    22  - var data = make([]models.Proxy, 0)
    23  - conn := database.QueryPage(page, size)
    24  - for _, cs := range cond {
    25  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    26  - }
    27  - conn.Find(&data)
    28  - return data
    29  -}
    30  - 
    31  -func (p ProxyService) GetById(id uint) interface{} {
    32  - var data = models.Proxy{}
    33  - database.GetConn().Limit(1).Where("ID = ?", id).Find(&data)
    34  - return &data
    35  -}
    36  - 
    37  -func (p ProxyService) Create(obj interface{}) interface{} {
    38  - database.GetConn().Create(obj.(*models.Proxy))
    39  - return obj
    40  -}
    41  - 
    42  -func (p ProxyService) Update(id uint, obj interface{}) interface{} {
    43  - obj.(*models.Proxy).ID = id
    44  - database.GetConn().Updates(obj.(*models.Proxy))
    45  - return p.GetById(id)
    46  -}
    47  - 
    48  -func (p ProxyService) Delete(id uint) {
    49  - database.GetConn().Delete(&models.Proxy{}, id)
    50  -}
    51  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/service.go
    1  -package service
    2  - 
    3  -import (
    4  - "log/slog"
    5  - "reflect"
    6  - 
    7  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    9  -)
    10  - 
    11  -var serviceFactory = map[string]ApiService{}
    12  - 
    13  -type Condition struct {
    14  - Key string
    15  - Value interface{}
    16  -}
    17  - 
    18  -type ApiService interface {
    19  - Count(cond ...Condition) int64
    20  - List(page, size int, preload bool, cond ...Condition) interface{}
    21  - GetById(id uint) interface{}
    22  - Create(obj interface{}) interface{}
    23  - Update(id uint, obj interface{}) interface{}
    24  - Delete(id uint)
    25  -}
    26  - 
    27  -func GetService(t string) ApiService {
    28  - return serviceFactory[t]
    29  -}
    30  - 
    31  -func Exist(svc ApiService, cond ...Condition) bool {
    32  - s := svc.List(0, 1, false, cond...)
    33  - 
    34  - // 重复名称的账户不允许创建
    35  - if reflect.TypeOf(s).Kind() == reflect.Slice && reflect.ValueOf(s).Len() > 0 {
    36  - return true
    37  - }
    38  - 
    39  - return false
    40  -}
    41  - 
    42  -func init() {
    43  - serviceFactory["proxy"] = ProxyService{}
    44  - serviceFactory["provider"] = CloudProviderService{}
    45  - serviceFactory["config"] = SystemConfigService{}
    46  - serviceFactory["auth"] = AuthService{}
    47  - serviceFactory["tunnel"] = TunnelService{}
    48  - 
    49  - // 注册初始化相关信息
    50  - database.RegisterMigrate(func() {
    51  - slog.Info("未查询到本地数据,初始化默认配置......")
    52  - for _, conf := range models.DefaultSysConfig {
    53  - serviceFactory["config"].Create(&conf)
    54  - }
    55  - slog.Info("未查询到本地数据,初始化默认账户......")
    56  - for _, auth := range models.DefaultAuth {
    57  - serviceFactory["auth"].Create(&auth)
    58  - }
    59  - })
    60  -}
    61  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/service/tunnel.go
    1  -package service
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/database"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    6  -)
    7  - 
    8  -type TunnelService struct {
    9  -}
    10  - 
    11  -func (t TunnelService) Count(cond ...Condition) int64 {
    12  - var res int64 = 0
    13  - conn := database.GetConn()
    14  - for _, cs := range cond {
    15  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    16  - }
    17  - conn.Model(&models.Tunnel{}).Count(&res)
    18  - return res
    19  -}
    20  - 
    21  -func (t TunnelService) List(page int, size int, preload bool, cond ...Condition) interface{} {
    22  - var data = make([]models.Tunnel, 0)
    23  - conn := database.QueryPage(page, size)
    24  - if preload {
    25  - conn = conn.Preload("Proxies")
    26  - }
    27  - for _, cs := range cond {
    28  - conn = conn.Where(cs.Key+" = ?", cs.Value)
    29  - }
    30  - conn.Find(&data)
    31  - return data
    32  -}
    33  - 
    34  -func (t TunnelService) GetById(id uint) interface{} {
    35  - var data = models.Tunnel{}
    36  - database.GetConn().Limit(1).Where("ID = ?", id).Find(&data)
    37  - return &data
    38  -}
    39  - 
    40  -func (t TunnelService) Create(obj interface{}) interface{} {
    41  - database.GetConn().Create(obj.(*models.Tunnel))
    42  - return obj
    43  -}
    44  - 
    45  -func (t TunnelService) Update(id uint, obj interface{}) interface{} {
    46  - obj.(*models.Tunnel).ID = id
    47  - database.GetConn().Updates(obj.(*models.Tunnel))
    48  - return t.GetById(id)
    49  -}
    50  - 
    51  -func (t TunnelService) Delete(id uint) {
    52  - database.GetConn().Delete(&models.Tunnel{}, id)
    53  -}
    54  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/types/auth.go
    1  -package types
    2  - 
    3  -type AuthType int8
    4  - 
    5  -const (
    6  - Empty AuthType = iota + 1 // 无认证
    7  - Admin // 后台账户
    8  - Basic // HTTP Basic 认证
    9  - Bearer // HTTP Bearer 认证
    10  - 
    11  - Signature // FC Signature 认证, 这类认证好处在于认证失败 403 不计次数
    12  - Jwt // FC Jwt 认证。 需要 jwks
    13  - Paris // SCF 网管密钥对认证
    14  -)
    15  - 
    16  -func TransAuthType(t string) AuthType {
    17  - switch t {
    18  - case "anonymous", "NONE":
    19  - return Empty
    20  - case "function":
    21  - return Signature
    22  - case "jwt":
    23  - return Jwt
    24  - }
    25  - return Empty
    26  -}
    27  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/types/cloud.go
    1  -package types
    2  - 
    3  -type CloudType int8
    4  - 
    5  -const (
    6  - ALiYun CloudType = iota + 1
    7  - TencentYun
    8  - HuaweiYun
    9  - BaiduYun
    10  - Sealos
    11  -)
    12  - 
    13  -type CloudStatus int8
    14  - 
    15  -const (
    16  - CREATE CloudStatus = iota + 1
    17  - SUCCESS
    18  - FAILED
    19  - FORBIDDEN
    20  - AUTH_ERROR
    21  - SYNC_ERROR
    22  -)
    23  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/types/proxy.go
    1  -package types
    2  - 
    3  -type ProxyStatus int8
    4  - 
    5  -const (
    6  - INITIALIZING ProxyStatus = iota + 1
    7  - ACTIVE
    8  - INACTIVE
    9  - ERROR
    10  - WAITING
    11  -)
    12  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/client.go
    skipped 11 lines
    12 12   
    13 13   "github.com/gin-gonic/gin"
    14 14   
    15  - "github.com/DVKunion/SeaMoon/cmd/client/api"
    16  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    17  - "github.com/DVKunion/SeaMoon/cmd/client/signal"
     15 + "github.com/DVKunion/SeaMoon/cmd/client/route"
    18 16   "github.com/DVKunion/SeaMoon/cmd/client/static"
    19  - "github.com/DVKunion/SeaMoon/pkg/consts"
    20  - "github.com/DVKunion/SeaMoon/pkg/xlog"
     17 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     18 + "github.com/DVKunion/SeaMoon/pkg/signal"
     19 + "github.com/DVKunion/SeaMoon/pkg/system/consts"
     20 + "github.com/DVKunion/SeaMoon/pkg/system/xlog"
    21 21  )
    22 22   
    23 23  func Serve(ctx context.Context, debug bool) {
    24  - go signal.Signal().Run(ctx)
     24 + // 控制总线,用于管控服务相关
     25 + go signal.Signal().Daemon(ctx)
    25 26   // Restful API 服务
    26  - runApi(debug)
     27 + runApi(ctx, debug)
    27 28  }
    28 29   
    29  -func runApi(debug bool) {
    30  - logPath := service.GetService("config").(service.SystemConfigService).GetByName("control_log").Value
    31  - addr := service.GetService("config").(service.SystemConfigService).GetByName("control_addr").Value
    32  - port := service.GetService("config").(service.SystemConfigService).GetByName("control_port").Value
     30 +func runApi(ctx context.Context, debug bool) {
     31 + logPath, err := service.SVC.GetConfigByName(ctx, "control_log")
     32 + addr, err := service.SVC.GetConfigByName(ctx, "control_addr")
     33 + port, err := service.SVC.GetConfigByName(ctx, "control_port")
    33 34   
    34  - xlog.Info("API", xlog.CONTROLLER_START, "addr", addr, "port", port)
     35 + xlog.Info(xlog.ApiServerStart, "addr", addr.Value, "port", port.Value)
    35 36   
    36 37   if consts.Version != "dev" || !debug {
    37 38   gin.SetMode(gin.ReleaseMode)
    38 39   }
    39 40   
    40  - webLogger, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
     41 + webLogger, err := os.OpenFile(logPath.Value, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
    41 42   if err != nil {
    42 43   gin.DefaultWriter = io.MultiWriter(os.Stdout)
    43 44   } else {
    skipped 2 lines
    46 47   
    47 48   server := gin.Default()
    48 49   
    49  - api.Register(server, debug)
     50 + route.Register(server, debug)
    50 51   
    51 52   subFS, err := fs.Sub(static.WebViews, "dist")
    52 53   
    skipped 5 lines
    58 59   c.FileFromFS(c.Request.URL.Path, http.FS(subFS))
    59 60   })
    60 61   
    61  - if err := server.Run(strings.Join([]string{addr, port}, ":")); err != http.ErrServerClosed {
     62 + if err := server.Run(strings.Join([]string{addr.Value, port.Value}, ":")); err != http.ErrServerClosed {
    62 63   slog.Error("client running error", "err", err)
    63 64   }
    64 65  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/listener/listen.go
    1  -package listener
    2  - 
    3  -import (
    4  - "context"
    5  - "errors"
    6  - "log/slog"
    7  - "net"
    8  - "sync"
    9  - 
    10  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    11  - db_service "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    12  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    13  - "github.com/DVKunion/SeaMoon/pkg/network"
    14  - "github.com/DVKunion/SeaMoon/pkg/service"
    15  - "github.com/DVKunion/SeaMoon/pkg/xlog"
    16  -)
    17  - 
    18  -func Listen(ctx context.Context, server net.Listener, p uint) {
    19  - var pro *models.Proxy
    20  - var tun *models.Tunnel
    21  - 
    22  - // 应用级别事务锁
    23  - var m = &sync.Mutex{}
    24  - 
    25  - dbProxy := db_service.GetService("proxy")
    26  - dbTunnel := db_service.GetService("tunnel")
    27  - 
    28  - objP := dbProxy.GetById(p)
    29  - if v, ok := objP.(*models.Proxy); ok {
    30  - pro = v
    31  - } else {
    32  - *pro.Status = types.ERROR
    33  - dbProxy.Update(pro.ID, pro)
    34  - slog.Error("proxy error")
    35  - return
    36  - }
    37  - objT := dbTunnel.GetById(pro.TunnelID)
    38  - if v, ok := objT.(*models.Tunnel); ok {
    39  - tun = v
    40  - } else {
    41  - *pro.Status = types.ERROR
    42  - dbProxy.Update(pro.ID, pro)
    43  - slog.Error("tunnel error")
    44  - return
    45  - }
    46  - *pro.Status = types.ACTIVE
    47  - dbProxy.Update(pro.ID, pro)
    48  - for {
    49  - conn, err := server.Accept()
    50  - if err != nil {
    51  - if errors.Is(err, net.ErrClosed) {
    52  - // 说明是 server 被外部 close 掉了,导致了此处的 accept 报错
    53  - // 正常现象,return 即可。
    54  - return
    55  - } else {
    56  - // 除此之外,都为异常。为了保证服务正常不出现 panic 和空指针,跳过该 conn
    57  - xlog.Error("SERVE", xlog.ACCEPT_ERROR, "err", err)
    58  - continue
    59  - }
    60  - }
    61  - // 说明接到了一个conn, 更新
    62  - count(dbProxy, pro.ID, 1, m)
    63  - if srv, ok := service.Factory.Load(*tun.Type); ok {
    64  - destConn, err := srv.(service.Service).Conn(ctx, *pro.Type,
    65  - service.WithAddr(tun.GetAddr()), service.WithTorFlag(tun.TunnelConfig.Tor))
    66  - if err != nil {
    67  - slog.Error(xlog.CONNECT_RMOET_ERROR, "err", err)
    68  - count(dbProxy, pro.ID, -1, m)
    69  - continue
    70  - }
    71  - go func() {
    72  - in, out, err := network.Transport(conn, destConn)
    73  - if err != nil {
    74  - slog.Error(xlog.CONNECT_TRANS_ERROR, "err", err)
    75  - }
    76  - count(dbProxy, pro.ID, -1, m, in, out)
    77  - }()
    78  - }
    79  - }
    80  -}
    81  - 
    82  -func count(svc db_service.ApiService, id uint, cnt int, m *sync.Mutex, args ...int64) {
    83  - // 查询 -> 原有基础上 +1/-1 -> 更新 是一个完整的事务
    84  - // 只有这一整个操作完成后,才应该进行下一个操作。
    85  - // 这里丑陋的用了一个 mutex 来实现这个问题,正常应该通过 orm 事务来操作。
    86  - m.Lock()
    87  - proxy := svc.GetById(id).(*models.Proxy)
    88  - *proxy.Conn = *proxy.Conn + cnt
    89  - if len(args) > 0 {
    90  - *proxy.InBound = *proxy.InBound + args[0]
    91  - *proxy.OutBound = *proxy.OutBound + args[1]
    92  - }
    93  - svc.Update(id, proxy)
    94  - m.Unlock()
    95  -}
    96  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/route/route.go
     1 +package route
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/api/controller/middleware"
     9 + api_v1 "github.com/DVKunion/SeaMoon/pkg/api/controller/v1"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/database/drivers"
     11 +)
     12 + 
     13 +func init() {
     14 + drivers.Init()
     15 +}
     16 + 
     17 +func Register(router *gin.Engine, debug bool) {
     18 + var middles = make([]gin.HandlerFunc, 0)
     19 + 
     20 + if debug {
     21 + router.GET("/debug/pprof/*any", gin.WrapH(http.DefaultServeMux))
     22 + } else {
     23 + middles = append(middles, middleware.JWTAuthMiddleware)
     24 + }
     25 + 
     26 + registerV1(router, middles)
     27 +}
     28 + 
     29 +func registerV1(router *gin.Engine, middles []gin.HandlerFunc) {
     30 + v1 := router.Group("/api/v1")
     31 + // user
     32 + v1.POST("/user/login", api_v1.Login)
     33 + v1.PUT("/user/passwd", append(middles, api_v1.Passwd)...)
     34 + 
     35 + // proxy
     36 + v1.GET("/proxy", append(middles, api_v1.ListProxies)...)
     37 + v1.GET("/proxy/:id", append(middles, api_v1.GetProxyById)...)
     38 + v1.GET("/proxy/speed/:id", append(middles, api_v1.SpeedRateProxy)...)
     39 + v1.POST("/proxy", append(middles, api_v1.CreateProxy)...)
     40 + v1.PUT("/proxy/:id", append(middles, api_v1.UpdateProxy)...)
     41 + v1.DELETE("/proxy/:id", append(middles, api_v1.DeleteProxy)...)
     42 + 
     43 + // tunnel
     44 + v1.GET("/tunnel", append(middles, api_v1.ListTunnels)...)
     45 + v1.GET("/tunnel/:id", append(middles, api_v1.GetTunnelById)...)
     46 + v1.POST("/tunnel", append(middles, api_v1.CreateTunnel)...)
     47 + v1.PUT("/tunnel/:id", append(middles, api_v1.UpdateTunnel)...)
     48 + v1.DELETE("/tunnel/:id", append(middles, api_v1.DeleteTunnel)...)
     49 + 
     50 + // cloud provider
     51 + v1.GET("/provider", append(middles, api_v1.ListProviders)...)
     52 + v1.GET("/provider/active", append(middles, api_v1.ListActiveProviders)...)
     53 + v1.GET("/provider/:id", append(middles, api_v1.GetProviderById)...)
     54 + v1.POST("/provider", append(middles, api_v1.CreateProvider)...)
     55 + v1.PUT("/provider/sync/:id", append(middles, api_v1.SyncProvider)...)
     56 + v1.PUT("/provider/:id", append(middles, api_v1.UpdateProvider)...)
     57 + v1.DELETE("/provider/:id", append(middles, api_v1.DeleteProvider)...)
     58 + 
     59 + // config
     60 + v1.GET("/config", append(middles, api_v1.ListConfigs)...)
     61 + v1.PUT("/config", append(middles, api_v1.UpdateConfig)...)
     62 +}
     63 + 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/aliyun/aliyun.go
    1  -package aliyun
    2  - 
    3  -import (
    4  - "encoding/json"
    5  - "errors"
    6  - "fmt"
    7  - "net/http"
    8  - "strconv"
    9  - "strings"
    10  - 
    11  - bss "github.com/alibabacloud-go/bssopenapi-20171214/v3/client"
    12  - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
    13  - util "github.com/alibabacloud-go/tea-utils/v2/service"
    14  - "github.com/alibabacloud-go/tea/tea"
    15  - "github.com/aliyun/fc-go-sdk"
    16  - 
    17  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    18  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    19  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    20  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    21  - "github.com/DVKunion/SeaMoon/pkg/xlog"
    22  -)
    23  - 
    24  -var (
    25  - // 阿里云 在 fc 上层还有一套 service 的概念,为了方便管理,这里硬编码了 service 的内容。
    26  - serviceName = "seamoon"
    27  - serviceDesc = "seamoon service"
    28  -)
    29  - 
    30  -// SDK FC
    31  -type SDK struct {
    32  -}
    33  - 
    34  -type Resp struct {
    35  - StatusCode int `json:"statusCode"`
    36  - Headers map[string]interface{} `json:"headers"`
    37  - Body struct {
    38  - Code string `json:"Code"`
    39  - Message string `json:"Message"`
    40  - RequestId string `json:"RequestId"`
    41  - Success bool `json:"Success"`
    42  - Data map[string]interface{} `json:"Data"`
    43  - } `json:"body"`
    44  -}
    45  - 
    46  -func (a *SDK) Auth(providerId uint) error {
    47  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    48  - config := &openapi.Config{
    49  - // 必填,您的 AccessKey ID
    50  - AccessKeyId: &provider.CloudAuth.AccessKey,
    51  - // 必填,您的 AccessKey Secret
    52  - AccessKeySecret: &provider.CloudAuth.AccessSecret,
    53  - }
    54  - // todo: seems ALiYunBillingMap is not right here
    55  - config.Endpoint = tea.String("business.aliyuncs.com")
    56  - client, err := bss.NewClient(config)
    57  - if err != nil {
    58  - return err
    59  - }
    60  - params := &openapi.Params{
    61  - // 接口名称
    62  - Action: tea.String("QueryAccountBalance"),
    63  - // 接口版本
    64  - Version: tea.String("2017-12-14"),
    65  - // 接口协议
    66  - Protocol: tea.String("HTTPS"),
    67  - // 接口 HTTP 方法
    68  - Method: tea.String("POST"),
    69  - AuthType: tea.String("AK"),
    70  - Style: tea.String("RPC"),
    71  - // 接口 PATH
    72  - Pathname: tea.String("/"),
    73  - // 接口请求体内容格式
    74  - ReqBodyType: tea.String("json"),
    75  - // 接口响应体内容格式
    76  - BodyType: tea.String("json"),
    77  - }
    78  - // runtime options
    79  - runtime := &util.RuntimeOptions{}
    80  - request := &openapi.OpenApiRequest{}
    81  - // 复制代码运行请自行打印 API 的返回值
    82  - // 返回值为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
    83  - res, err := client.CallApi(params, request, runtime)
    84  - if err != nil {
    85  - return err
    86  - }
    87  - bs, err := json.Marshal(res)
    88  - if err != nil {
    89  - return err
    90  - }
    91  - var r Resp
    92  - err = json.Unmarshal(bs, &r)
    93  - if err != nil {
    94  - return err
    95  - }
    96  - if r.StatusCode != 200 || r.Body.Code != "200" {
    97  - return errors.New(r.Body.Message)
    98  - }
    99  - amount, err := strconv.ParseFloat(strings.Replace(r.Body.Data["AvailableAmount"].(string), ",", "", -1), 64)
    100  - if err != nil {
    101  - return err
    102  - }
    103  - *provider.Amount = amount
    104  - 
    105  - // todo: 查询总花费
    106  - service.GetService("provider").Update(provider.ID, provider)
    107  - return nil
    108  -}
    109  - 
    110  -func (a *SDK) Deploy(providerId uint, tun *models.Tunnel) error {
    111  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    112  - // 原生的库是真tm的难用,
    113  - client, err := fc.NewClient(
    114  - fmt.Sprintf("%s.%s.fc.aliyuncs.com", provider.CloudAuth.AccessId, *provider.Region),
    115  - "2016-08-15", provider.CloudAuth.AccessKey, provider.CloudAuth.AccessSecret)
    116  - if err != nil {
    117  - return err
    118  - }
    119  - // 先尝试是否已经存在了 svc
    120  - _, err = client.GetService(fc.NewGetServiceInput(serviceName))
    121  - if err != nil {
    122  - err := err.(*fc.ServiceError)
    123  - if err.HTTPStatus == http.StatusNotFound {
    124  - // 说明 service 空了,先创建svc
    125  - _, err := client.CreateService(fc.NewCreateServiceInput().
    126  - WithServiceName(serviceName).
    127  - WithDescription(serviceDesc))
    128  - if err != nil {
    129  - return err
    130  - }
    131  - } else {
    132  - return err
    133  - }
    134  - }
    135  - 
    136  - p, err := strconv.Atoi(*tun.Port)
    137  - funcName := *tun.Name
    138  - // 有了服务了,现在来创建函数
    139  - respC, err := client.CreateFunction(fc.NewCreateFunctionInput(serviceName).
    140  - WithFunctionName(funcName).
    141  - WithDescription(string(*tun.Type)).
    142  - WithRuntime("custom-container").
    143  - WithCPU(tun.TunnelConfig.CPU).
    144  - WithMemorySize(tun.TunnelConfig.Memory).
    145  - WithHandler("main").
    146  - WithDisk(512).
    147  - WithInstanceConcurrency(tun.TunnelConfig.Instance).
    148  - WithCAPort(int32(p)).
    149  - WithInstanceType("e1"). // 性能实例
    150  - WithTimeout(300).
    151  - WithCustomContainerConfig(fc.NewCustomContainerConfig().
    152  - WithImage("registry.cn-hongkong.aliyuncs.com/seamoon/seamoon:dev").
    153  - WithCommand("[\"./seamoon\"]").
    154  - WithArgs("[\"server\"]")))
    155  - if err != nil {
    156  - return err
    157  - }
    158  - fmt.Println(respC)
    159  - // 有了函数了,接下来创建 trigger
    160  - respT, err := client.CreateTrigger(fc.NewCreateTriggerInput(serviceName, funcName).
    161  - WithTriggerType("http").
    162  - WithTriggerName(string(*tun.Type)).
    163  - WithTriggerConfig(fc.TriggerConfig{
    164  - Methods: []string{"GET", "POST"},
    165  - AuthType: "anonymous",
    166  - DisableURLInternet: false,
    167  - }))
    168  - if err != nil {
    169  - return err
    170  - }
    171  - fmt.Println(respT)
    172  - // 创建成功了, 查一下
    173  - respTS, err := client.GetTrigger(fc.NewGetTriggerInput(serviceName, funcName, string(*tun.Type)))
    174  - if err != nil {
    175  - return err
    176  - }
    177  - 
    178  - *tun.Addr = strings.Replace(respTS.UrlInternet, "https://", "", -1)
    179  - *tun.Status = tunnel.ACTIVE
    180  - // 更新 tunnel
    181  - service.GetService("tunnel").Update(tun.ID, tun)
    182  - return nil
    183  -}
    184  - 
    185  -func (a *SDK) Destroy(providerId uint, tun *models.Tunnel) error {
    186  - return nil
    187  -}
    188  - 
    189  -func (a *SDK) SyncFC(providerId uint) error {
    190  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    191  - client, err := fc.NewClient(
    192  - fmt.Sprintf("%s.%s.fc.aliyuncs.com", provider.CloudAuth.AccessId, *provider.Region),
    193  - "2016-08-15", provider.CloudAuth.AccessKey, provider.CloudAuth.AccessSecret)
    194  - if err != nil {
    195  - return err
    196  - }
    197  - // 先同步函数
    198  - respC, err := client.ListFunctions(fc.NewListFunctionsInput(serviceName))
    199  - if err != nil {
    200  - e, ok := err.(*fc.ServiceError)
    201  - if ok && e.HTTPStatus == http.StatusNotFound {
    202  - // 说明没有 service,甭同步了
    203  - return nil
    204  - } else {
    205  - return err
    206  - }
    207  - }
    208  - for _, c := range respC.Functions {
    209  - // 判断下存不存在吧,不然每次同步都会整出来一堆
    210  - if exist := service.Exist(service.GetService("tunnel"), service.Condition{
    211  - Key: "NAME",
    212  - Value: *c.FunctionName,
    213  - }, service.Condition{
    214  - Key: "cloud_provider_id",
    215  - Value: provider.ID,
    216  - }); exist {
    217  - continue
    218  - }
    219  - // 还得检查下 Type, 现在临时塞到了desc中了
    220  - if *c.Description == "" {
    221  - xlog.Warn("sdk", "发现了不正确的隧道", "provider_id", provider.ID,
    222  - "fc_name", *c.FunctionName, "fc_type", *c.Description,
    223  - )
    224  - continue
    225  - }
    226  - 
    227  - var tun = models.Tunnel{
    228  - CloudProviderId: provider.ID,
    229  - Name: c.FunctionName,
    230  - 
    231  - TunnelConfig: &models.TunnelConfig{
    232  - CPU: *c.CPU,
    233  - Memory: *c.MemorySize,
    234  - Instance: *c.InstanceConcurrency,
    235  - 
    236  - // todo: 这里太糙了
    237  - TLS: true, // 默认同步过来都打开
    238  - Tor: func() bool {
    239  - // 如果是 开启 Tor 的隧道,需要有环境变量
    240  - return len(c.EnvironmentVariables) > 0
    241  - }(),
    242  - },
    243  - }
    244  - // 自动填充防止空指针
    245  - models.AutoFull(&tun)
    246  - *tun.Type = tunnel.TranType(*c.Description)
    247  - *tun.Port = strconv.Itoa(int(*c.CAPort))
    248  - *tun.Status = tunnel.ACTIVE
    249  - // 再同步触发器来填充隧道的地址
    250  - respT, err := client.ListTriggers(fc.NewListTriggersInput(serviceName, *c.FunctionName))
    251  - if err == nil {
    252  - for _, t := range respT.Triggers {
    253  - if *t.TriggerType == "http" {
    254  - // todo: 这里太糙了
    255  - *tun.Addr = strings.Replace(t.UrlInternet, "https://", "", -1)
    256  - tun.TunnelConfig.TunnelAuthType = types.TransAuthType(t.TriggerConfig.AuthType)
    257  - }
    258  - }
    259  - } else {
    260  - // todo: 打印一下失败的的日志
    261  - }
    262  - // 最后更新一下
    263  - service.GetService("tunnel").Create(&tun)
    264  - }
    265  - 
    266  - return nil
    267  -}
    268  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/aws.go
    1  -package sdk
    2  - 
    3  -// todo
    4  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/baidu.go
    1  -package sdk
    2  - 
    3  -// todo
    4  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/google.go
    1  -package sdk
    2  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/hwyun.go
    1  -package sdk
    2  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/sdk.go
    1  -package sdk
    2  - 
    3  -import (
    4  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    5  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    6  - "github.com/DVKunion/SeaMoon/cmd/client/sdk/aliyun"
    7  - "github.com/DVKunion/SeaMoon/cmd/client/sdk/sealos"
    8  - "github.com/DVKunion/SeaMoon/cmd/client/sdk/tencent"
    9  -)
    10  - 
    11  -type CloudSDK interface {
    12  - // Auth 判断是否认证信息有效,并尝试增添最低的权限角色。
    13  - Auth(providerId uint) error
    14  - // Deploy 部署隧道函数
    15  - Deploy(providerId uint, tun *models.Tunnel) error
    16  - // Destroy 删除隧道函数
    17  - Destroy(providerId uint, tun *models.Tunnel) error
    18  - // SyncFC 同步函数
    19  - SyncFC(providerId uint) error
    20  - 
    21  - // UpdateVersion 一键更新: 用本地的版本号请求远端服务更新至
    22  - // UpdateVersion(auth models.CloudAuth) error
    23  -}
    24  - 
    25  -var cloudFactory = map[types.CloudType]CloudSDK{}
    26  - 
    27  -func GetSDK(t types.CloudType) CloudSDK {
    28  - return cloudFactory[t]
    29  -}
    30  - 
    31  -func init() {
    32  - cloudFactory[types.ALiYun] = &aliyun.SDK{}
    33  - cloudFactory[types.TencentYun] = &tencent.SDK{}
    34  - cloudFactory[types.Sealos] = &sealos.SDK{}
    35  -}
    36  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/sealos/maps.go
    1  -package sealos
    2  - 
    3  -var RegionMap = map[string]string{
    4  - "internal": "cloud.sealos.run",
    5  - "external": "cloud.sealos.io",
    6  -}
    7  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/sealos/sealos.go
    1  -package sealos
    2  - 
    3  -import (
    4  - "context"
    5  - "encoding/json"
    6  - "errors"
    7  - "fmt"
    8  - "io"
    9  - "log/slog"
    10  - "net/http"
    11  - "net/url"
    12  - "strconv"
    13  - "strings"
    14  - "time"
    15  - 
    16  - appsv1 "k8s.io/api/apps/v1"
    17  - corev1 "k8s.io/api/core/v1"
    18  - networkingv1 "k8s.io/api/networking/v1"
    19  - "k8s.io/apimachinery/pkg/api/resource"
    20  - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  - "k8s.io/apimachinery/pkg/util/intstr"
    22  - "k8s.io/client-go/kubernetes"
    23  - "k8s.io/client-go/tools/clientcmd"
    24  - 
    25  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    26  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    27  - "github.com/DVKunion/SeaMoon/pkg/consts"
    28  - "github.com/DVKunion/SeaMoon/pkg/tools"
    29  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    30  -)
    31  - 
    32  -type SDK struct {
    33  -}
    34  - 
    35  -var (
    36  - num int32 = 1
    37  - prefix = networkingv1.PathTypePrefix
    38  - fl = false
    39  -)
    40  - 
    41  -type Amount struct {
    42  - Code int `json:"code"`
    43  - Message string `json:"message"`
    44  - Data struct {
    45  - ActivityBonus int `json:"activityBonus"`
    46  - Balance int `json:"balance"`
    47  - DeductionBalance int `json:"deductionBalance"`
    48  - EncryptBalance string `json:"encryptBalance"`
    49  - EncryptDeductionBalance string `json:"encryptDeductionBalance"`
    50  - } `json:"data"`
    51  -}
    52  - 
    53  -func (s *SDK) Auth(providerId uint) error {
    54  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    55  - amountUrl := fmt.Sprintf("https://costcenter.%s/api/account/getAmount", RegionMap[*provider.Region])
    56  - 
    57  - req, err := http.NewRequest("GET", amountUrl, nil)
    58  - if err != nil {
    59  - return err
    60  - }
    61  - 
    62  - req.Header.Add("Authorization", url.PathEscape(provider.CloudAuth.KubeConfig))
    63  - client := &http.Client{
    64  - Timeout: 30 * time.Second,
    65  - }
    66  - 
    67  - resp, err := client.Do(req)
    68  - if err != nil {
    69  - return err
    70  - }
    71  - 
    72  - defer resp.Body.Close()
    73  - 
    74  - if resp.StatusCode != 200 {
    75  - return errors.New("error request : " + resp.Status)
    76  - }
    77  - 
    78  - body, err := io.ReadAll(resp.Body)
    79  - if err != nil {
    80  - return err
    81  - }
    82  - 
    83  - var sa = Amount{}
    84  - err = json.Unmarshal(body, &sa)
    85  - if err != nil {
    86  - return err
    87  - }
    88  - 
    89  - *provider.Amount = float64(sa.Data.Balance-sa.Data.DeductionBalance) / 1000000
    90  - *provider.Cost = float64(sa.Data.DeductionBalance) / 1000000
    91  - 
    92  - service.GetService("provider").Update(provider.ID, provider)
    93  - 
    94  - return nil
    95  -}
    96  - 
    97  -func (s *SDK) Billing(providerId uint, tunnel models.Tunnel) error {
    98  - // 详细计算某个隧道花费数据
    99  - //url := fmt.Sprintf("https://costcenter.%s/api/billing", SealosRegionMap[provider.Region])
    100  - return nil
    101  -}
    102  - 
    103  -func (s *SDK) Deploy(providerId uint, tun *models.Tunnel) error {
    104  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    105  - // sealos 部署十分简单,直接调用 k8s client-go 即可。
    106  - ctx := context.TODO()
    107  - 
    108  - ns, clientSet, err := parseKubeConfig(provider.CloudAuth.KubeConfig)
    109  - 
    110  - if err != nil {
    111  - return err
    112  - }
    113  - 
    114  - svcName := "seamoon-" + *tun.Name + "-" + string(*tun.Type)
    115  - imgName := "dvkunion/seamoon:" + consts.Version
    116  - hostName := tools.GenerateRandomLetterString(12)
    117  - port, err := strconv.Atoi(*tun.Port)
    118  - if err != nil {
    119  - return err
    120  - }
    121  - // 需要先创建 deployment 负载
    122  - deployment := &appsv1.Deployment{
    123  - ObjectMeta: metav1.ObjectMeta{
    124  - Name: svcName,
    125  - Annotations: map[string]string{
    126  - "originImageName": imgName,
    127  - "deploy.cloud.sealos.io/minReplicas": "1",
    128  - "deploy.cloud.sealos.io/maxReplicas": "1",
    129  - "deploy.cloud.sealos.io/resize": "0Gi",
    130  - },
    131  - Labels: map[string]string{
    132  - "cloud.sealos.io/app-deploy-manager": svcName,
    133  - "app": svcName,
    134  - },
    135  - },
    136  - Spec: appsv1.DeploymentSpec{
    137  - Replicas: &num,
    138  - RevisionHistoryLimit: &num,
    139  - Selector: &metav1.LabelSelector{
    140  - MatchLabels: map[string]string{
    141  - "app": svcName,
    142  - },
    143  - },
    144  - Template: corev1.PodTemplateSpec{
    145  - ObjectMeta: metav1.ObjectMeta{
    146  - Labels: map[string]string{
    147  - "app": svcName,
    148  - },
    149  - },
    150  - Spec: corev1.PodSpec{
    151  - AutomountServiceAccountToken: &fl,
    152  - Containers: []corev1.Container{
    153  - {
    154  - Name: svcName,
    155  - Image: imgName,
    156  - Env: func() []corev1.EnvVar {
    157  - var env = make([]corev1.EnvVar, 0)
    158  - if tun.TunnelConfig.Tor {
    159  - // 需要增加环境变量
    160  - env = append(env, corev1.EnvVar{
    161  - Name: "SEAMOON_TOR",
    162  - Value: "true",
    163  - })
    164  - }
    165  - return env
    166  - }(),
    167  - Resources: corev1.ResourceRequirements{
    168  - Requests: map[corev1.ResourceName]resource.Quantity{
    169  - corev1.ResourceCPU: func() resource.Quantity {
    170  - if tun.TunnelConfig.CPU < 0.1 {
    171  - return resource.MustParse("10m")
    172  - }
    173  - return resource.MustParse(strconv.Itoa(int(tun.TunnelConfig.CPU*100)) + "m")
    174  - }(),
    175  - corev1.ResourceMemory: func() resource.Quantity {
    176  - if tun.TunnelConfig.Memory < 64 {
    177  - return resource.MustParse("6Mi")
    178  - }
    179  - return resource.MustParse(strconv.Itoa(int(tun.TunnelConfig.Memory/10)) + "Mi")
    180  - }(),
    181  - },
    182  - Limits: map[corev1.ResourceName]resource.Quantity{
    183  - corev1.ResourceCPU: func() resource.Quantity {
    184  - if tun.TunnelConfig.CPU < 0.1 {
    185  - return resource.MustParse("100m")
    186  - }
    187  - return resource.MustParse(strconv.Itoa(int(tun.TunnelConfig.CPU*1000)) + "m")
    188  - }(),
    189  - corev1.ResourceMemory: func() resource.Quantity {
    190  - if tun.TunnelConfig.Memory < 64 {
    191  - return resource.MustParse("64Mi")
    192  - }
    193  - return resource.MustParse(strconv.Itoa(int(tun.TunnelConfig.Memory)) + "Mi")
    194  - }(),
    195  - },
    196  - },
    197  - Command: []string{"/app/seamoon"},
    198  - Args: func() []string {
    199  - switch *tun.Type {
    200  - case tunnel.WST:
    201  - return []string{"server", "-p", "9000", "-t", "websocket"}
    202  - case tunnel.GRT:
    203  - return []string{"server", "-p", "8089", "-t", "grpc"}
    204  - }
    205  - return []string{}
    206  - }(),
    207  - Ports: []corev1.ContainerPort{
    208  - {
    209  - Name: "seamoon-http",
    210  - Protocol: corev1.ProtocolTCP,
    211  - ContainerPort: int32(port),
    212  - },
    213  - },
    214  - ImagePullPolicy: corev1.PullAlways,
    215  - },
    216  - },
    217  - },
    218  - },
    219  - },
    220  - }
    221  - 
    222  - // 使用客户端创建Deployment
    223  - _, err = clientSet.AppsV1().Deployments(ns).Create(ctx, deployment, metav1.CreateOptions{})
    224  - if err != nil {
    225  - return err
    226  - }
    227  - fmt.Println("Deployment创建成功!")
    228  - // 然后是创建 service 和 ingress
    229  - svc := &corev1.Service{
    230  - ObjectMeta: metav1.ObjectMeta{
    231  - Name: svcName,
    232  - Labels: map[string]string{
    233  - "cloud.sealos.io/app-deploy-manager": svcName,
    234  - },
    235  - },
    236  - Spec: corev1.ServiceSpec{
    237  - Selector: map[string]string{
    238  - "app": svcName,
    239  - },
    240  - Ports: []corev1.ServicePort{
    241  - {
    242  - Port: int32(port),
    243  - TargetPort: intstr.FromInt32(int32(port)),
    244  - },
    245  - },
    246  - },
    247  - }
    248  - _, err = clientSet.CoreV1().Services(ns).Create(ctx, svc, metav1.CreateOptions{})
    249  - if err != nil {
    250  - return err
    251  - }
    252  - fmt.Println("Service创建成功!")
    253  - // ingress
    254  - ingress := &networkingv1.Ingress{
    255  - ObjectMeta: metav1.ObjectMeta{
    256  - Name: svcName,
    257  - Labels: map[string]string{
    258  - "cloud.sealos.io/app-deploy-manager": svcName,
    259  - "cloud.sealos.io/app-deploy-manager-domain": hostName,
    260  - },
    261  - Annotations: map[string]string{
    262  - "kubernetes.io/ingress.class": "nginx",
    263  - "nginx.ingress.kubernetes.io/proxy-body-size": "32m",
    264  - "nginx.ingress.kubernetes.io/ssl-redirect": "false",
    265  - "nginx.ingress.kubernetes.io/backend-protocol": func() string {
    266  - switch *tun.Type {
    267  - case tunnel.WST:
    268  - return "WS"
    269  - case tunnel.GRT:
    270  - return "GRPC"
    271  - }
    272  - return "HTTP"
    273  - }(),
    274  - "nginx.ingress.kubernetes.io/proxy-send-timeout": "3600",
    275  - "nginx.ingress.kubernetes.io/proxy-read-timeout": "3600",
    276  - },
    277  - },
    278  - Spec: networkingv1.IngressSpec{
    279  - Rules: []networkingv1.IngressRule{
    280  - {
    281  - Host: fmt.Sprintf("%s.%s", hostName, RegionMap[*provider.Region]),
    282  - IngressRuleValue: networkingv1.IngressRuleValue{
    283  - HTTP: &networkingv1.HTTPIngressRuleValue{
    284  - Paths: []networkingv1.HTTPIngressPath{
    285  - {
    286  - Path: "/",
    287  - PathType: &prefix,
    288  - Backend: networkingv1.IngressBackend{
    289  - Service: &networkingv1.IngressServiceBackend{
    290  - Name: svcName,
    291  - Port: networkingv1.ServiceBackendPort{
    292  - Number: 9000,
    293  - },
    294  - },
    295  - },
    296  - },
    297  - },
    298  - },
    299  - },
    300  - },
    301  - },
    302  - TLS: []networkingv1.IngressTLS{
    303  - {
    304  - Hosts: []string{fmt.Sprintf("%s.%s", hostName, RegionMap[*provider.Region])},
    305  - SecretName: "wildcard-cloud-sealos-io-cert",
    306  - },
    307  - },
    308  - },
    309  - }
    310  - _, err = clientSet.NetworkingV1().Ingresses(ns).Create(ctx, ingress, metav1.CreateOptions{})
    311  - if err != nil {
    312  - return err
    313  - }
    314  - fmt.Println("Ingress创建成功!")
    315  - *tun.Status = tunnel.ACTIVE
    316  - *tun.Addr = fmt.Sprintf("%s.%s", hostName, RegionMap[*provider.Region])
    317  - service.GetService("tunnel").Update(tun.ID, tun)
    318  - return nil
    319  -}
    320  - 
    321  -func (s *SDK) Destroy(providerId uint, tun *models.Tunnel) error {
    322  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    323  - ctx := context.TODO()
    324  - 
    325  - ns, clientSet, err := parseKubeConfig(provider.CloudAuth.KubeConfig)
    326  - 
    327  - if err != nil {
    328  - return err
    329  - }
    330  - 
    331  - svcName := "seamoon-" + *tun.Name + "-" + string(*tun.Type)
    332  - if err := clientSet.AppsV1().Deployments(ns).Delete(ctx, svcName, metav1.DeleteOptions{}); err != nil {
    333  - return err
    334  - }
    335  - slog.Info("成功删除")
    336  - if err := clientSet.CoreV1().Services(ns).Delete(ctx, svcName, metav1.DeleteOptions{}); err != nil {
    337  - return err
    338  - }
    339  - slog.Info("成功删除")
    340  - if err := clientSet.NetworkingV1().Ingresses(ns).Delete(ctx, svcName, metav1.DeleteOptions{}); err != nil {
    341  - return err
    342  - }
    343  - slog.Info("成功删除")
    344  - 
    345  - // 删除数据
    346  - return nil
    347  -}
    348  - 
    349  -func (s *SDK) SyncFC(providerId uint) error {
    350  - provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    351  - tunList := make([]models.Tunnel, 0)
    352  - ctx := context.TODO()
    353  - 
    354  - ns, clientSet, err := parseKubeConfig(provider.CloudAuth.KubeConfig)
    355  - 
    356  - if err != nil {
    357  - return err
    358  - }
    359  - 
    360  - svcs, err := clientSet.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{})
    361  - if err != nil {
    362  - return err
    363  - }
    364  - 
    365  - ingresses, err := clientSet.NetworkingV1().Ingresses(ns).List(ctx, metav1.ListOptions{})
    366  - if err != nil {
    367  - return err
    368  - }
    369  - 
    370  - for _, svc := range svcs.Items {
    371  - if strings.HasPrefix(svc.Name, "seamoon-") {
    372  - // 说明是我们的服务,继续获取对应的 label 来查找 ingress
    373  - var tun = models.Tunnel{}
    374  - *tun.Name = strings.Split(svc.Name, "-")[1]
    375  - *tun.Port = strconv.Itoa(int(svc.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort))
    376  - *tun.Type = func() tunnel.Type {
    377  - if strings.HasSuffix(svc.Name, "websocket") {
    378  - return tunnel.WST
    379  - }
    380  - if strings.HasSuffix(svc.Name, "grpc") {
    381  - return tunnel.GRT
    382  - }
    383  - return tunnel.NULL
    384  - }()
    385  - for _, ingress := range ingresses.Items {
    386  - if ingress.Name == svc.Name {
    387  - *tun.Addr = ingress.Spec.Rules[0].Host
    388  - }
    389  - }
    390  - t := service.GetService("tunnel").Create(&tun).(*models.Tunnel)
    391  - tunList = append(tunList, *t)
    392  - }
    393  - }
    394  - if len(tunList) > 0 {
    395  - provider.Tunnels = append(provider.Tunnels, tunList...)
    396  - }
    397  - 
    398  - service.GetService("provider").Update(provider.ID, provider)
    399  - return nil
    400  -}
    401  - 
    402  -func parseKubeConfig(kc string) (string, *kubernetes.Clientset, error) {
    403  - bs, err := url.PathUnescape(kc)
    404  - if err != nil {
    405  - return "", nil, err
    406  - }
    407  - ac, err := clientcmd.Load([]byte(bs))
    408  - if err != nil {
    409  - return "", nil, err
    410  - }
    411  - 
    412  - var ns = ""
    413  - for _, ctx := range ac.Contexts {
    414  - ns = ctx.Namespace
    415  - }
    416  - 
    417  - if ns == "" {
    418  - return ns, nil, errors.New("认证信息错误,未发现命名空间")
    419  - }
    420  - 
    421  - config, err := clientcmd.RESTConfigFromKubeConfig([]byte(bs))
    422  - 
    423  - if err != nil {
    424  - return ns, nil, err
    425  - }
    426  - client, err := kubernetes.NewForConfig(config)
    427  - if err != nil {
    428  - return ns, nil, err
    429  - }
    430  - return ns, client, nil
    431  -}
    432  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/tencent/tencent.go
    1  -package tencent
    2  - 
    3  -import (
    4  - "errors"
    5  - "strconv"
    6  - "strings"
    7  - 
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    9  - "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    10  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    11  - "github.com/DVKunion/SeaMoon/pkg/tools"
    12  - "github.com/DVKunion/SeaMoon/pkg/tunnel"
    13  -)
    14  - 
    15  -var (
    16  - // 腾讯云 在 fc 上层还有一套 namespace 的概念,为了方便管理,这里硬编码了 namespace 的内容。
    17  - serviceName = "seamoon"
    18  - serviceDesc = "seamoon service"
    19  -)
    20  - 
    21  -type SDK struct {
    22  -}
    23  - 
    24  -func (t *SDK) Auth(providerId uint) error {
    25  - svc := service.GetService("provider")
    26  - provider, ok := svc.GetById(providerId).(*models.CloudProvider)
    27  - if !ok {
    28  - return errors.New("can not found provider")
    29  - }
    30  - err := t.auth(provider)
    31  - if err != nil {
    32  - return err
    33  - }
    34  - amount, err := t.billing(provider)
    35  - if err != nil {
    36  - return err
    37  - }
    38  - provider.Amount = &amount
    39  - svc.Update(provider.ID, provider)
    40  - return nil
    41  -}
    42  - 
    43  -func (t *SDK) Deploy(providerId uint, tun *models.Tunnel) error {
    44  - provider, ok := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    45  - if !ok {
    46  - return errors.New("can not found provider")
    47  - }
    48  - addr, err := t.deploy(provider, tun)
    49  - if err != nil {
    50  - *tun.Status = tunnel.ERROR
    51  - service.GetService("tunnel").Update(tun.ID, tun)
    52  - return err
    53  - }
    54  - *tun.Addr = strings.Replace(addr, "https://", "", -1)
    55  - *tun.Status = tunnel.ERROR
    56  - service.GetService("tunnel").Update(tun.ID, tun)
    57  - return nil
    58  -}
    59  - 
    60  -func (t *SDK) Destroy(providerId uint, tun *models.Tunnel) error {
    61  - return nil
    62  -}
    63  - 
    64  -func (t *SDK) SyncFC(providerId uint) error {
    65  - svc := service.GetService("provider")
    66  - provider, ok := svc.GetById(providerId).(*models.CloudProvider)
    67  - if !ok {
    68  - return errors.New("can not found provider")
    69  - }
    70  - fcList, err := t.sync(provider)
    71  - if err != nil {
    72  - return err
    73  - }
    74  - for _, fc := range fcList {
    75  - fcNameList := strings.Split(*fc.detail.FunctionName, "-")
    76  - fcName := fcNameList[0]
    77  - if len(fcNameList) > 3 {
    78  - fcName = fcNameList[2]
    79  - }
    80  - var tun = models.Tunnel{
    81  - CloudProviderId: provider.ID,
    82  - Name: &fcName,
    83  - TunnelConfig: &models.TunnelConfig{
    84  - CPU: 0,
    85  - Memory: tools.PtrInt32(fc.detail.MemorySize),
    86  - Instance: 1, // 这个玩意tmd怎么也找不到,同步过来的就算他1好了。
    87  - 
    88  - TLS: true, // 默认同步过来都打开
    89  - Tor: func() bool {
    90  - if fc.detail.Environment != nil {
    91  - // 如果是 开启 Tor 的隧道,需要有环境变量
    92  - return len(fc.detail.Environment.Variables) > 0
    93  - }
    94  - return false
    95  - }(),
    96  - },
    97  - }
    98  - // 自动填充防止空指针
    99  - models.AutoFull(&tun)
    100  - *tun.Type = tunnel.TranType(*fc.detail.Description)
    101  - *tun.Port = strconv.Itoa(int(*fc.detail.ImageConfig.ImagePort))
    102  - *tun.Status = tunnel.ACTIVE
    103  - *tun.Addr = fc.addr
    104  - tun.TunnelConfig.TunnelAuthType = types.TransAuthType(fc.auth)
    105  - 
    106  - service.GetService("tunnel").Create(&tun)
    107  - }
    108  - return nil
    109  -}
    110  - 
  • ■ ■ ■ ■ ■ ■
    cmd/client/signal/signal.go
    1  -package signal
    2  - 
    3  -import (
    4  - "context"
    5  - "log/slog"
    6  - "net"
    7  - 
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/types"
    9  - "github.com/DVKunion/SeaMoon/cmd/client/listener"
    10  - "github.com/DVKunion/SeaMoon/pkg/xlog"
    11  -)
    12  - 
    13  -// SignalBus 用于控制所有服务类型的启动
    14  -type SignalBus struct {
    15  - canceler map[uint]context.CancelFunc
    16  - listener map[uint]net.Listener
    17  - 
    18  - proxyChannel chan *ProxySignal
    19  -}
    20  - 
    21  -type ProxySignal struct {
    22  - ProxyId uint
    23  - Addr string
    24  - Next types.ProxyStatus
    25  -}
    26  - 
    27  -var signalBus = &SignalBus{
    28  - canceler: make(map[uint]context.CancelFunc, 0),
    29  - listener: make(map[uint]net.Listener, 0),
    30  - proxyChannel: make(chan *ProxySignal, 1>>8),
    31  -}
    32  - 
    33  -func Signal() *SignalBus {
    34  - return signalBus
    35  -}
    36  - 
    37  -// Run 监听逻辑
    38  -func (sb *SignalBus) Run(ctx context.Context) {
    39  - for {
    40  - select {
    41  - case t := <-sb.proxyChannel:
    42  - switch t.Next {
    43  - case types.ACTIVE:
    44  - sigCtx, cancel := context.WithCancel(ctx)
    45  - server, err := net.Listen("tcp", t.Addr)
    46  - if err != nil {
    47  - slog.Error(xlog.LISTEN_ERROR, "id", t.ProxyId, "addr", t.Addr, "err", err)
    48  - } else {
    49  - slog.Info(xlog.LISTEN_START, "id", t.ProxyId, "addr", t.Addr)
    50  - go listener.Listen(sigCtx, server, t.ProxyId)
    51  - sb.canceler[t.ProxyId] = cancel
    52  - sb.listener[t.ProxyId] = server
    53  - }
    54  - case types.INACTIVE:
    55  - if cancel, ok := sb.canceler[t.ProxyId]; ok {
    56  - // 先调一下 cancel
    57  - cancel()
    58  - if ln, exist := sb.listener[t.ProxyId]; exist {
    59  - // 尝试着去停一下 ln, 防止泄漏
    60  - err := ln.Close()
    61  - if err != nil {
    62  - // 错了就错了吧,说明 ctx 挂了一般 gorouting 也跟着挂了
    63  - slog.Error(xlog.LISTEN_STOP_ERROR, "id", t.ProxyId, "addr", t.Addr, "err", err)
    64  - }
    65  - }
    66  - }
    67  - slog.Info(xlog.LISTEN_STOP, "id", t.ProxyId, "addr", t.Addr)
    68  - }
    69  - }
    70  - }
    71  -}
    72  - 
    73  -func (sb *SignalBus) SendStartProxy(p uint, addr string) {
    74  - sb.proxyChannel <- &ProxySignal{
    75  - ProxyId: p,
    76  - Addr: addr,
    77  - Next: types.ACTIVE,
    78  - }
    79  -}
    80  - 
    81  -func (sb *SignalBus) SendStopProxy(p uint, addr string) {
    82  - sb.proxyChannel <- &ProxySignal{
    83  - ProxyId: p,
    84  - Addr: addr,
    85  - Next: types.INACTIVE,
    86  - }
    87  -}
    88  - 
  • ■ ■ ■ ■ ■
    cmd/main.go
    skipped 7 lines
    8 8   
    9 9   "github.com/DVKunion/SeaMoon/cmd/client"
    10 10   "github.com/DVKunion/SeaMoon/cmd/server"
    11  - "github.com/DVKunion/SeaMoon/pkg/consts"
     11 + "github.com/DVKunion/SeaMoon/pkg/api/database/drivers"
     12 + "github.com/DVKunion/SeaMoon/pkg/system/consts"
    12 13  )
    13 14   
    14 15  var (
    skipped 16 lines
    31 32   Use: "proxy",
    32 33   Short: "SeaMoon proxy mod",
    33 34   Run: Proxy,
     35 + }
     36 + 
     37 + generateCommand = &cobra.Command{
     38 + Use: "generate",
     39 + Short: "SeaMoon generate devs code",
     40 + RunE: drivers.Drive().Generate,
    34 41   }
    35 42   
    36 43   versionCommand = &cobra.Command{
    skipped 33 lines
    70 77   rootCommand.AddCommand(versionCommand)
    71 78   rootCommand.AddCommand(proxyCommand)
    72 79   rootCommand.AddCommand(serverCommand)
     80 + rootCommand.AddCommand(generateCommand)
    73 81  }
    74 82   
    75 83  func main() {
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    cmd/server/options.go
    1 1  package server
    2 2   
    3  -import "github.com/DVKunion/SeaMoon/pkg/tunnel"
     3 +import (
     4 + "github.com/DVKunion/SeaMoon/pkg/api/enum"
     5 +)
    4 6   
    5 7  type Options struct {
    6  - host string // 监听地址
    7  - port string // 监听端口
    8  - proto tunnel.Type // 监听协议
     8 + host string // 监听地址
     9 + port string // 监听端口
     10 + proto enum.TunnelType // 监听协议
    9 11   
    10 12   mtcp bool //
    11 13  }
    skipped 16 lines
    28 30   
    29 31  func WithProto(t string) Option {
    30 32   return func(o *Options) (err error) {
    31  - tt := tunnel.TranType(t)
    32  - if tt == tunnel.NULL {
     33 + tt := enum.TransTunnelType(t)
     34 + if tt == enum.TunnelTypeNULL {
    33 35   // todo
    34 36   }
    35 37   o.proto = tt
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    go.mod
    skipped 11 lines
    12 12   github.com/glebarez/sqlite v1.10.0
    13 13   github.com/golang-jwt/jwt v3.2.2+incompatible
    14 14   github.com/gorilla/websocket v1.5.1
     15 + github.com/pkg/errors v0.9.1
     16 + github.com/showwin/speedtest-go v1.6.10
    15 17   github.com/spf13/cobra v1.8.0
    16 18   github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866
    17 19   github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866
    skipped 2 lines
    20 22   github.com/tg123/go-htpasswd v1.2.0
    21 23   google.golang.org/grpc v1.37.0
    22 24   google.golang.org/protobuf v1.31.0
     25 + gorm.io/gen v0.3.25
    23 26   gorm.io/gorm v1.25.5
     27 + gorm.io/plugin/dbresolver v1.5.0
    24 28   k8s.io/api v0.29.2
    25 29   k8s.io/apimachinery v0.29.2
    26 30   k8s.io/client-go v0.29.2
    skipped 24 lines
    51 55   github.com/go-playground/locales v0.14.1 // indirect
    52 56   github.com/go-playground/universal-translator v0.18.1 // indirect
    53 57   github.com/go-playground/validator/v10 v10.14.0 // indirect
     58 + github.com/go-sql-driver/mysql v1.7.0 // indirect
    54 59   github.com/goccy/go-json v0.10.2 // indirect
    55 60   github.com/gogo/protobuf v1.3.2 // indirect
    56 61   github.com/golang/protobuf v1.5.3 // indirect
    skipped 22 lines
    79 84   github.com/ugorji/go/codec v1.2.11 // indirect
    80 85   golang.org/x/arch v0.3.0 // indirect
    81 86   golang.org/x/crypto v0.18.0 // indirect
     87 + golang.org/x/mod v0.14.0 // indirect
    82 88   golang.org/x/net v0.20.0 // indirect
    83 89   golang.org/x/oauth2 v0.10.0 // indirect
    84 90   golang.org/x/sys v0.16.0 // indirect
    85 91   golang.org/x/term v0.16.0 // indirect
    86 92   golang.org/x/text v0.14.0 // indirect
    87 93   golang.org/x/time v0.3.0 // indirect
     94 + golang.org/x/tools v0.16.1 // indirect
    88 95   google.golang.org/appengine v1.6.7 // indirect
    89 96   google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
    90 97   gopkg.in/inf.v0 v0.9.1 // indirect
    skipped 1 lines
    92 99   gopkg.in/resty.v1 v1.11.0 // indirect
    93 100   gopkg.in/yaml.v2 v2.4.0 // indirect
    94 101   gopkg.in/yaml.v3 v3.0.1 // indirect
     102 + gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect
     103 + gorm.io/driver/mysql v1.5.2 // indirect
     104 + gorm.io/hints v1.1.0 // indirect
    95 105   k8s.io/klog/v2 v2.110.1 // indirect
    96 106   k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
    97 107   k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    go.sum
    skipped 80 lines
    81 81  github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
    82 82  github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
    83 83  github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
     84 +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
     85 +github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
     86 +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
    84 87  github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
    85 88  github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
    86 89  github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
    skipped 2 lines
    89 92  github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
    90 93  github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
    91 94  github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
     95 +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
     96 +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
     97 +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
     98 +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
    92 99  github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
    93 100  github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
    94 101  github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
    skipped 38 lines
    133 140  github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
    134 141  github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
    135 142  github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
     143 +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
     144 +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
     145 +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
     146 +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
     147 +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
     148 +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
     149 +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
     150 +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
     151 +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
     152 +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
     153 +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
     154 +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
     155 +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
     156 +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
     157 +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
     158 +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
    136 159  github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
    137 160  github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
     161 +github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
     162 +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
    138 163  github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
    139 164  github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
    140 165  github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
    skipped 21 lines
    162 187  github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
    163 188  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
    164 189  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
     190 +github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
     191 +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
     192 +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
     193 +github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE=
     194 +github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ=
    165 195  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
    166 196  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
    167 197  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
    skipped 10 lines
    178 208  github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
    179 209  github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
    180 210  github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
     211 +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
     212 +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
    181 213  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
    182 214  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
    183 215  github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
    skipped 3 lines
    187 219  github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
    188 220  github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
    189 221  github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
     222 +github.com/showwin/speedtest-go v1.6.10 h1:dPxr1gVOu30KvMNl2L8UZD937Ge7zsZW0JulzYpyP48=
     223 +github.com/showwin/speedtest-go v1.6.10/go.mod h1:uLgdWCNarXxlYsL2E5TOZpCIwpgSWnEANZp7gfHXHu0=
    190 224  github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
    191 225  github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
    192 226  github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
    skipped 58 lines
    251 285  golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
    252 286  golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
    253 287  golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
     288 +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
     289 +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
    254 290  golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
    255 291  golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
    256 292  golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
    skipped 24 lines
    281 317  golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
    282 318  golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
    283 319  golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
     320 +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
     321 +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
    284 322  golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
    285 323  golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
    286 324  golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
    skipped 91 lines
    378 416  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
    379 417  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
    380 418  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
     419 +gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c h1:jWdr7cHgl8c/ua5vYbR2WhSp+NQmzhsj0xoY3foTzW8=
     420 +gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c/go.mod h1:SH2K9R+2RMjuX1CkCONrPwoe9JzVv2hkQvEu4bXGojE=
     421 +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
     422 +gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
     423 +gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
     424 +gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc=
     425 +gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg=
     426 +gorm.io/driver/sqlite v1.1.6/go.mod h1:W8LmC/6UvVbHKah0+QOC7Ja66EaZXHwUTjgXY8YNWX8=
     427 +gorm.io/driver/sqlite v1.4.3 h1:HBBcZSDnWi5BW3B3rwvVTc510KGkBkexlOg0QrmLUuU=
     428 +gorm.io/driver/sqlite v1.4.3/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
     429 +gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0=
     430 +gorm.io/driver/sqlserver v1.4.1/go.mod h1:DJ4P+MeZbc5rvY58PnmN1Lnyvb5gw5NPzGshHDnJLig=
     431 +gorm.io/gen v0.3.25 h1:uT/1YfvcnYUdike4XPYyi89FEnVHZF115GUXQm2Sfug=
     432 +gorm.io/gen v0.3.25/go.mod h1:p+t0iCKjaPz+pKRxcx63nXdRgnrah/QD2l92747ihyA=
     433 +gorm.io/gorm v1.21.15/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
     434 +gorm.io/gorm v1.22.2/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
     435 +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
     436 +gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
     437 +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
    381 438  gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
    382 439  gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
     440 +gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw=
     441 +gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y=
     442 +gorm.io/plugin/dbresolver v1.5.0 h1:XVHLxh775eP0CqVh3vcfJtYqja3uFl5Wr3cKlY8jgDY=
     443 +gorm.io/plugin/dbresolver v1.5.0/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0=
    383 444  honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
    384 445  honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
    385 446  k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A=
    skipped 27 lines
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/middleware/jwt.go
     1 +package middleware
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + "github.com/golang-jwt/jwt"
     8 + 
     9 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/enum"
     11 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     12 + "github.com/DVKunion/SeaMoon/pkg/tools"
     13 +)
     14 + 
     15 +func JWTAuthMiddleware(c *gin.Context) {
     16 + // 这里简化了JWT验证逻辑,实际使用时应更复杂
     17 + tokenString := c.GetHeader("Authorization")
     18 + 
     19 + if tokenString == "" {
     20 + servant.ErrorMsg(c, http.StatusUnauthorized, errors.ApiError(errors.ApiParamsRequire))
     21 + c.Abort()
     22 + return
     23 + }
     24 + 
     25 + // 验证token是否有效
     26 + token, err := tools.JWTParse(tokenString)
     27 + 
     28 + if err != nil {
     29 + // 认证失败
     30 + servant.ErrorMsg(c, http.StatusForbidden, errors.ApiError(errors.ApiAuthError, err))
     31 + c.Abort()
     32 + return
     33 + }
     34 + 
     35 + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
     36 + // 校验通过
     37 + if cast, ok := claims["type"].(float64); ok && enum.AuthType(cast) == enum.AuthAdmin {
     38 + c.Next()
     39 + return
     40 + }
     41 + }
     42 + 
     43 + // 校验不通过
     44 + servant.ErrorMsg(c, http.StatusForbidden, errors.ApiError(errors.ApiAuthLimit, err))
     45 + c.Abort()
     46 + return
     47 +}
     48 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/servant/params.go
     1 +package servant
     2 + 
     3 +import (
     4 + "strconv"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 +)
     8 + 
     9 +// GetPageSize 通用获取页面信息
     10 +func GetPageSize(c *gin.Context) (int, int) {
     11 + defaultPageSize := 10
     12 + defaultPageNum := 0
     13 + 
     14 + pageStr := c.Query("page")
     15 + sizeStr := c.Query("size")
     16 + 
     17 + page, errPage := strconv.Atoi(pageStr)
     18 + if errPage != nil {
     19 + page = defaultPageNum
     20 + }
     21 + 
     22 + size, errSize := strconv.Atoi(sizeStr)
     23 + if errSize != nil {
     24 + size = defaultPageSize
     25 + }
     26 + return page, size
     27 +}
     28 + 
     29 +// GetPathId 通用获取 path 信息
     30 +func GetPathId(c *gin.Context) (int, error) {
     31 + return strconv.Atoi(c.Param("id"))
     32 +}
     33 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/servant/response.go
     1 +package servant
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     9 +)
     10 + 
     11 +// SuccessMsg 通用正常响应
     12 +func SuccessMsg(c *gin.Context, total int64, data interface{}) {
     13 + c.JSON(http.StatusOK, gin.H{
     14 + "success": true,
     15 + "total": total,
     16 + "data": data,
     17 + })
     18 + return
     19 +}
     20 + 
     21 +// ErrorMsg 通用错误响应
     22 +func ErrorMsg(c *gin.Context, code int, err error) {
     23 + if err == nil {
     24 + err = errors.ApiError(errors.ApiCommonError)
     25 + }
     26 + c.JSON(code, gin.H{
     27 + "success": false,
     28 + "code": code,
     29 + "msg": err.Error(),
     30 + })
     31 +}
     32 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/v1/auth.go
     1 +package v1
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     9 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     11 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     12 +)
     13 + 
     14 +func Login(c *gin.Context) {
     15 + var obj *models.AuthApi
     16 + if err := c.ShouldBindJSON(&obj); err != nil {
     17 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     18 + return
     19 + }
     20 + 
     21 + if token, err := service.SVC.Login(c, obj); err != nil {
     22 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     23 + } else {
     24 + servant.SuccessMsg(c, 1, token)
     25 + }
     26 +}
     27 + 
     28 +func Passwd(c *gin.Context) {
     29 + var obj *models.AuthApi
     30 + if err := c.ShouldBindJSON(&obj); err != nil {
     31 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     32 + return
     33 + }
     34 + 
     35 + if err := service.SVC.UpdatePassword(c, obj); err != nil {
     36 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     37 + } else {
     38 + servant.SuccessMsg(c, 1, "更新成功")
     39 + }
     40 +}
     41 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/v1/config.go
     1 +package v1
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     9 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     11 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     12 +)
     13 + 
     14 +func ListConfigs(c *gin.Context) {
     15 + p, s := servant.GetPageSize(c)
     16 + if config, err := service.SVC.ListConfigs(c, p, s); err != nil {
     17 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     18 + } else {
     19 + servant.SuccessMsg(c, 1, config.ToApi())
     20 + }
     21 +}
     22 + 
     23 +func UpdateConfig(c *gin.Context) {
     24 + var obj models.ConfigApi
     25 + if err := c.ShouldBindJSON(&obj); err != nil {
     26 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     27 + return
     28 + }
     29 + if err := service.SVC.UpdateConfig(c, obj.ToModel()); err != nil {
     30 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     31 + } else {
     32 + servant.SuccessMsg(c, 1, nil)
     33 + }
     34 +}
     35 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/v1/provider.go
     1 +package v1
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     9 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     11 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     12 +)
     13 + 
     14 +func ListProviders(c *gin.Context) {
     15 + total, err := service.SVC.TotalProviders(c)
     16 + if err != nil {
     17 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     18 + return
     19 + }
     20 + 
     21 + p, s := servant.GetPageSize(c)
     22 + if res, err := service.SVC.ListProviders(c, p, s); err != nil {
     23 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     24 + } else {
     25 + servant.SuccessMsg(c, total, res.ToApi())
     26 + }
     27 +}
     28 + 
     29 +func GetProviderById(c *gin.Context) {
     30 + id, err := servant.GetPathId(c)
     31 + if err != nil {
     32 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     33 + return
     34 + }
     35 + if res, err := service.SVC.GetProviderById(c, uint(id)); err != nil {
     36 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     37 + } else {
     38 + servant.SuccessMsg(c, 1, res.ToApi())
     39 + }
     40 +}
     41 + 
     42 +func ListActiveProviders(c *gin.Context) {
     43 + total, err := service.SVC.TotalProviders(c)
     44 + if err != nil {
     45 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     46 + return
     47 + }
     48 + 
     49 + if res, err := service.SVC.ListActiveProviders(c); err != nil {
     50 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     51 + } else {
     52 + servant.SuccessMsg(c, total, res.ToApi())
     53 + }
     54 +}
     55 + 
     56 +func CreateProvider(c *gin.Context) {
     57 + var obj models.ProviderCreateApi
     58 + if err := c.ShouldBindJSON(&obj); err != nil {
     59 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     60 + return
     61 + }
     62 + 
     63 + if service.SVC.ExistProvider(c, obj.Name) {
     64 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsExist, nil))
     65 + return
     66 + }
     67 + 
     68 + if res, err := service.SVC.CreateProvider(c, obj.ToModel()); err != nil {
     69 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     70 + } else {
     71 + servant.SuccessMsg(c, 1, res.ToApi())
     72 + }
     73 +}
     74 + 
     75 +func UpdateProvider(c *gin.Context) {
     76 + var obj *models.ProviderCreateApi
     77 + if err := c.ShouldBindJSON(&obj); err != nil {
     78 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     79 + return
     80 + }
     81 + 
     82 + id, err := servant.GetPathId(c)
     83 + if err != nil {
     84 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     85 + return
     86 + }
     87 + 
     88 + obj.ID = uint(id)
     89 + 
     90 + if res, err := service.SVC.UpdateProvider(c, obj.ToModel()); err != nil {
     91 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     92 + } else {
     93 + servant.SuccessMsg(c, 1, res.ToApi())
     94 + }
     95 +}
     96 + 
     97 +func DeleteProvider(c *gin.Context) {
     98 + id, err := servant.GetPathId(c)
     99 + if err != nil {
     100 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     101 + return
     102 + }
     103 + 
     104 + if err = service.SVC.DeleteProvider(c, uint(id)); err != nil {
     105 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     106 + } else {
     107 + servant.SuccessMsg(c, 1, nil)
     108 + }
     109 +}
     110 + 
     111 +func SyncProvider(c *gin.Context) {
     112 + id, err := servant.GetPathId(c)
     113 + if err != nil {
     114 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     115 + return
     116 + }
     117 + if err = service.SVC.SyncProvider(c, uint(id)); err != nil {
     118 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     119 + } else {
     120 + servant.SuccessMsg(c, 1, nil)
     121 + }
     122 +}
     123 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/v1/proxy.go
     1 +package v1
     2 + 
     3 +import (
     4 + "net/http"
     5 + 
     6 + "github.com/gin-gonic/gin"
     7 + 
     8 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     9 + "github.com/DVKunion/SeaMoon/pkg/api/enum"
     10 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     11 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     12 + "github.com/DVKunion/SeaMoon/pkg/signal"
     13 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     14 +)
     15 + 
     16 +func ListProxies(c *gin.Context) {
     17 + total, err := service.SVC.TotalProxies(c)
     18 + if err != nil {
     19 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     20 + return
     21 + }
     22 + 
     23 + p, s := servant.GetPageSize(c)
     24 + if res, err := service.SVC.ListProxies(c, p, s); err != nil {
     25 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     26 + } else {
     27 + servant.SuccessMsg(c, total, res.ToApi())
     28 + }
     29 +}
     30 + 
     31 +func GetProxyById(c *gin.Context) {
     32 + id, err := servant.GetPathId(c)
     33 + if err != nil {
     34 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     35 + return
     36 + }
     37 + if res, err := service.SVC.GetProxyById(c, uint(id)); err != nil {
     38 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     39 + } else {
     40 + servant.SuccessMsg(c, 1, res.ToApi())
     41 + }
     42 +}
     43 + 
     44 +func CreateProxy(c *gin.Context) {
     45 + var obj models.ProxyCreateApi
     46 + if err := c.ShouldBindJSON(&obj); err != nil {
     47 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     48 + return
     49 + }
     50 + 
     51 + if service.SVC.ExistProvider(c, obj.Name) {
     52 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsExist, nil))
     53 + return
     54 + }
     55 + 
     56 + // 判断是否从账户来的,账户来的需要先创建 tunnel
     57 + if obj.TunnelCreateApi != nil {
     58 + if tun, err := service.SVC.CreateTunnel(c, obj.TunnelCreateApi.ToModel()); err != nil {
     59 + *obj.Status = enum.ProxyStatusError
     60 + *obj.StatusMessage = err.Error()
     61 + } else {
     62 + // todo: 发送部署请求
     63 + obj.TunnelId = tun.ID
     64 + }
     65 + }
     66 + 
     67 + if res, err := service.SVC.CreateProxy(c, obj.ToModel()); err != nil {
     68 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     69 + return
     70 + } else {
     71 + // 发送启动通知
     72 + signal.Signal().SendProxySignal(res.ID, *res.Status)
     73 + servant.SuccessMsg(c, 1, res.ToApi())
     74 + }
     75 +}
     76 + 
     77 +func UpdateProxy(c *gin.Context) {
     78 + var obj *models.ProxyCreateApi
     79 + if err := c.ShouldBindJSON(&obj); err != nil {
     80 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     81 + return
     82 + }
     83 + id, err := servant.GetPathId(c)
     84 + if err != nil {
     85 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     86 + return
     87 + }
     88 + 
     89 + // 朝着队列发送控制信号
     90 + signal.Signal().SendProxySignal(obj.ID, *obj.Status)
     91 + 
     92 + if res, err := service.SVC.UpdateProxy(c, uint(id), obj.ToModel()); err != nil {
     93 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     94 + } else {
     95 + servant.SuccessMsg(c, 1, res.ToApi())
     96 + }
     97 +}
     98 + 
     99 +func DeleteProxy(c *gin.Context) {
     100 + id, err := servant.GetPathId(c)
     101 + if err != nil {
     102 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     103 + return
     104 + }
     105 + 
     106 + if err = service.SVC.DeleteProxy(c, uint(id)); err != nil {
     107 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     108 + } else {
     109 + servant.SuccessMsg(c, 1, nil)
     110 + }
     111 +}
     112 + 
     113 +func SpeedRateProxy(c *gin.Context) {
     114 + id, err := servant.GetPathId(c)
     115 + if err != nil {
     116 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     117 + return
     118 + }
     119 + 
     120 + // todo 全量测速
     121 + if proxy, err := service.SVC.GetProxyById(c, uint(id)); err != nil || *proxy.Status != enum.ProxyStatusActive {
     122 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     123 + } else {
     124 + signal.Signal().SendProxySignal(proxy.ID, enum.ProxyStatusSpeeding)
     125 + if err := service.SVC.UpdateProxyStatus(c, proxy.ID, enum.ProxyStatusSpeeding, ""); err != nil {
     126 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     127 + }
     128 + // 发送测速信号
     129 + servant.SuccessMsg(c, 1, proxy.ToApi())
     130 + }
     131 +}
     132 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/controller/v1/tunnel.go
     1 +package v1
     2 + 
     3 +import (
     4 + "context"
     5 + "net/http"
     6 + "reflect"
     7 + 
     8 + "github.com/gin-gonic/gin"
     9 + 
     10 + "github.com/DVKunion/SeaMoon/pkg/api/controller/servant"
     11 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     12 + "github.com/DVKunion/SeaMoon/pkg/api/service"
     13 + "github.com/DVKunion/SeaMoon/pkg/system/errors"
     14 +)
     15 + 
     16 +func ListTunnels(c *gin.Context) {
     17 + total, err := service.SVC.TotalTunnels(c)
     18 + if err != nil {
     19 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     20 + return
     21 + }
     22 + 
     23 + p, s := servant.GetPageSize(c)
     24 + if res, err := service.SVC.ListTunnels(c, p, s); err != nil {
     25 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     26 + } else {
     27 + servant.SuccessMsg(c, total, res.ToApi(extra()))
     28 + }
     29 +}
     30 + 
     31 +func GetTunnelById(c *gin.Context) {
     32 + id, err := servant.GetPathId(c)
     33 + if err != nil {
     34 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     35 + return
     36 + }
     37 + if res, err := service.SVC.GetTunnelById(c, uint(id)); err != nil {
     38 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     39 + } else {
     40 + servant.SuccessMsg(c, 1, res.ToApi(extra()))
     41 + }
     42 +}
     43 + 
     44 +func CreateTunnel(c *gin.Context) {
     45 + var obj models.TunnelCreateApi
     46 + if err := c.ShouldBindJSON(&obj); err != nil {
     47 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     48 + return
     49 + }
     50 + 
     51 + if service.SVC.ExistTunnel(c, obj.Name, nil) {
     52 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsExist, nil))
     53 + return
     54 + }
     55 + 
     56 + if res, err := service.SVC.CreateTunnel(c, obj.ToModel()); err != nil {
     57 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     58 + } else {
     59 + servant.SuccessMsg(c, 1, res.ToApi(extra()))
     60 + }
     61 +}
     62 + 
     63 +func UpdateTunnel(c *gin.Context) {
     64 + var obj *models.TunnelCreateApi
     65 + if err := c.ShouldBindJSON(&obj); err != nil {
     66 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     67 + return
     68 + }
     69 + 
     70 + id, err := servant.GetPathId(c)
     71 + if err != nil {
     72 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     73 + return
     74 + }
     75 + 
     76 + obj.ID = uint(id)
     77 + 
     78 + if res, err := service.SVC.UpdateTunnel(c, obj.ToModel()); err != nil {
     79 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     80 + } else {
     81 + servant.SuccessMsg(c, 1, res.ToApi(extra()))
     82 + }
     83 +}
     84 + 
     85 +func DeleteTunnel(c *gin.Context) {
     86 + id, err := servant.GetPathId(c)
     87 + if err != nil {
     88 + servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(errors.ApiParamsError, err))
     89 + return
     90 + }
     91 + 
     92 + if err = service.SVC.DeleteTunnel(c, uint(id)); err != nil {
     93 + servant.ErrorMsg(c, http.StatusInternalServerError, errors.ApiError(errors.ApiServiceError, err))
     94 + } else {
     95 + servant.SuccessMsg(c, 1, nil)
     96 + }
     97 +}
     98 + 
     99 +func extra() func(api interface{}) {
     100 + return func(api interface{}) {
     101 + ref := reflect.ValueOf(api).Elem()
     102 + idField := ref.FieldByName("ProviderId")
     103 + prv, err := service.SVC.GetProviderById(context.Background(), uint(idField.Uint()))
     104 + if err != nil {
     105 + // todo: deal with this error
     106 + return
     107 + }
     108 + field := ref.FieldByName("ProviderType")
     109 + if field.CanSet() {
     110 + field.Set(reflect.ValueOf(prv.Type))
     111 + }
     112 + }
     113 +}
     114 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/database/dao/auths.gen.go
     1 +// Code generated by gorm.io/gen. DO NOT EDIT.
     2 +// Code generated by gorm.io/gen. DO NOT EDIT.
     3 +// Code generated by gorm.io/gen. DO NOT EDIT.
     4 + 
     5 +package dao
     6 + 
     7 +import (
     8 + "context"
     9 + 
     10 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     11 + "gorm.io/gorm"
     12 + "gorm.io/gorm/clause"
     13 + "gorm.io/gorm/schema"
     14 + 
     15 + "gorm.io/gen"
     16 + "gorm.io/gen/field"
     17 + 
     18 + "gorm.io/plugin/dbresolver"
     19 +)
     20 + 
     21 +func newAuth(db *gorm.DB, opts ...gen.DOOption) auth {
     22 + _auth := auth{}
     23 + 
     24 + _auth.authDo.UseDB(db, opts...)
     25 + _auth.authDo.UseModel(&models.Auth{})
     26 + 
     27 + tableName := _auth.authDo.TableName()
     28 + _auth.ALL = field.NewAsterisk(tableName)
     29 + _auth.ID = field.NewUint(tableName, "id")
     30 + _auth.CreatedAt = field.NewTime(tableName, "created_at")
     31 + _auth.UpdatedAt = field.NewTime(tableName, "updated_at")
     32 + _auth.DeletedAt = field.NewField(tableName, "deleted_at")
     33 + _auth.Type = field.NewInt8(tableName, "type")
     34 + _auth.Username = field.NewString(tableName, "username")
     35 + _auth.Password = field.NewString(tableName, "password")
     36 + _auth.LastLogin = field.NewString(tableName, "last_login")
     37 + _auth.LastAddr = field.NewString(tableName, "last_addr")
     38 + 
     39 + _auth.fillFieldMap()
     40 + 
     41 + return _auth
     42 +}
     43 + 
     44 +type auth struct {
     45 + authDo authDo
     46 + 
     47 + ALL field.Asterisk
     48 + ID field.Uint
     49 + CreatedAt field.Time
     50 + UpdatedAt field.Time
     51 + DeletedAt field.Field
     52 + Type field.Int8
     53 + Username field.String
     54 + Password field.String
     55 + LastLogin field.String
     56 + LastAddr field.String
     57 + 
     58 + fieldMap map[string]field.Expr
     59 +}
     60 + 
     61 +func (a auth) Table(newTableName string) *auth {
     62 + a.authDo.UseTable(newTableName)
     63 + return a.updateTableName(newTableName)
     64 +}
     65 + 
     66 +func (a auth) As(alias string) *auth {
     67 + a.authDo.DO = *(a.authDo.As(alias).(*gen.DO))
     68 + return a.updateTableName(alias)
     69 +}
     70 + 
     71 +func (a *auth) updateTableName(table string) *auth {
     72 + a.ALL = field.NewAsterisk(table)
     73 + a.ID = field.NewUint(table, "id")
     74 + a.CreatedAt = field.NewTime(table, "created_at")
     75 + a.UpdatedAt = field.NewTime(table, "updated_at")
     76 + a.DeletedAt = field.NewField(table, "deleted_at")
     77 + a.Type = field.NewInt8(table, "type")
     78 + a.Username = field.NewString(table, "username")
     79 + a.Password = field.NewString(table, "password")
     80 + a.LastLogin = field.NewString(table, "last_login")
     81 + a.LastAddr = field.NewString(table, "last_addr")
     82 + 
     83 + a.fillFieldMap()
     84 + 
     85 + return a
     86 +}
     87 + 
     88 +func (a *auth) WithContext(ctx context.Context) IAuthDo { return a.authDo.WithContext(ctx) }
     89 + 
     90 +func (a auth) TableName() string { return a.authDo.TableName() }
     91 + 
     92 +func (a auth) Alias() string { return a.authDo.Alias() }
     93 + 
     94 +func (a auth) Columns(cols ...field.Expr) gen.Columns { return a.authDo.Columns(cols...) }
     95 + 
     96 +func (a *auth) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
     97 + _f, ok := a.fieldMap[fieldName]
     98 + if !ok || _f == nil {
     99 + return nil, false
     100 + }
     101 + _oe, ok := _f.(field.OrderExpr)
     102 + return _oe, ok
     103 +}
     104 + 
     105 +func (a *auth) fillFieldMap() {
     106 + a.fieldMap = make(map[string]field.Expr, 9)
     107 + a.fieldMap["id"] = a.ID
     108 + a.fieldMap["created_at"] = a.CreatedAt
     109 + a.fieldMap["updated_at"] = a.UpdatedAt
     110 + a.fieldMap["deleted_at"] = a.DeletedAt
     111 + a.fieldMap["type"] = a.Type
     112 + a.fieldMap["username"] = a.Username
     113 + a.fieldMap["password"] = a.Password
     114 + a.fieldMap["last_login"] = a.LastLogin
     115 + a.fieldMap["last_addr"] = a.LastAddr
     116 +}
     117 + 
     118 +func (a auth) clone(db *gorm.DB) auth {
     119 + a.authDo.ReplaceConnPool(db.Statement.ConnPool)
     120 + return a
     121 +}
     122 + 
     123 +func (a auth) replaceDB(db *gorm.DB) auth {
     124 + a.authDo.ReplaceDB(db)
     125 + return a
     126 +}
     127 + 
     128 +type authDo struct{ gen.DO }
     129 + 
     130 +type IAuthDo interface {
     131 + gen.SubQuery
     132 + Debug() IAuthDo
     133 + WithContext(ctx context.Context) IAuthDo
     134 + WithResult(fc func(tx gen.Dao)) gen.ResultInfo
     135 + ReplaceDB(db *gorm.DB)
     136 + ReadDB() IAuthDo
     137 + WriteDB() IAuthDo
     138 + As(alias string) gen.Dao
     139 + Session(config *gorm.Session) IAuthDo
     140 + Columns(cols ...field.Expr) gen.Columns
     141 + Clauses(conds ...clause.Expression) IAuthDo
     142 + Not(conds ...gen.Condition) IAuthDo
     143 + Or(conds ...gen.Condition) IAuthDo
     144 + Select(conds ...field.Expr) IAuthDo
     145 + Where(conds ...gen.Condition) IAuthDo
     146 + Order(conds ...field.Expr) IAuthDo
     147 + Distinct(cols ...field.Expr) IAuthDo
     148 + Omit(cols ...field.Expr) IAuthDo
     149 + Join(table schema.Tabler, on ...field.Expr) IAuthDo
     150 + LeftJoin(table schema.Tabler, on ...field.Expr) IAuthDo
     151 + RightJoin(table schema.Tabler, on ...field.Expr) IAuthDo
     152 + Group(cols ...field.Expr) IAuthDo
     153 + Having(conds ...gen.Condition) IAuthDo
     154 + Limit(limit int) IAuthDo
     155 + Offset(offset int) IAuthDo
     156 + Count() (count int64, err error)
     157 + Scopes(funcs ...func(gen.Dao) gen.Dao) IAuthDo
     158 + Unscoped() IAuthDo
     159 + Create(values ...*models.Auth) error
     160 + CreateInBatches(values []*models.Auth, batchSize int) error
     161 + Save(values ...*models.Auth) error
     162 + First() (*models.Auth, error)
     163 + Take() (*models.Auth, error)
     164 + Last() (*models.Auth, error)
     165 + Find() ([]*models.Auth, error)
     166 + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Auth, err error)
     167 + FindInBatches(result *[]*models.Auth, batchSize int, fc func(tx gen.Dao, batch int) error) error
     168 + Pluck(column field.Expr, dest interface{}) error
     169 + Delete(...*models.Auth) (info gen.ResultInfo, err error)
     170 + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
     171 + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
     172 + Updates(value interface{}) (info gen.ResultInfo, err error)
     173 + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
     174 + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
     175 + UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
     176 + UpdateFrom(q gen.SubQuery) gen.Dao
     177 + Attrs(attrs ...field.AssignExpr) IAuthDo
     178 + Assign(attrs ...field.AssignExpr) IAuthDo
     179 + Joins(fields ...field.RelationField) IAuthDo
     180 + Preload(fields ...field.RelationField) IAuthDo
     181 + FirstOrInit() (*models.Auth, error)
     182 + FirstOrCreate() (*models.Auth, error)
     183 + FindByPage(offset int, limit int) (result []*models.Auth, count int64, err error)
     184 + ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
     185 + Scan(result interface{}) (err error)
     186 + Returning(value interface{}, columns ...string) IAuthDo
     187 + UnderlyingDB() *gorm.DB
     188 + schema.Tabler
     189 +}
     190 + 
     191 +func (a authDo) Debug() IAuthDo {
     192 + return a.withDO(a.DO.Debug())
     193 +}
     194 + 
     195 +func (a authDo) WithContext(ctx context.Context) IAuthDo {
     196 + return a.withDO(a.DO.WithContext(ctx))
     197 +}
     198 + 
     199 +func (a authDo) ReadDB() IAuthDo {
     200 + return a.Clauses(dbresolver.Read)
     201 +}
     202 + 
     203 +func (a authDo) WriteDB() IAuthDo {
     204 + return a.Clauses(dbresolver.Write)
     205 +}
     206 + 
     207 +func (a authDo) Session(config *gorm.Session) IAuthDo {
     208 + return a.withDO(a.DO.Session(config))
     209 +}
     210 + 
     211 +func (a authDo) Clauses(conds ...clause.Expression) IAuthDo {
     212 + return a.withDO(a.DO.Clauses(conds...))
     213 +}
     214 + 
     215 +func (a authDo) Returning(value interface{}, columns ...string) IAuthDo {
     216 + return a.withDO(a.DO.Returning(value, columns...))
     217 +}
     218 + 
     219 +func (a authDo) Not(conds ...gen.Condition) IAuthDo {
     220 + return a.withDO(a.DO.Not(conds...))
     221 +}
     222 + 
     223 +func (a authDo) Or(conds ...gen.Condition) IAuthDo {
     224 + return a.withDO(a.DO.Or(conds...))
     225 +}
     226 + 
     227 +func (a authDo) Select(conds ...field.Expr) IAuthDo {
     228 + return a.withDO(a.DO.Select(conds...))
     229 +}
     230 + 
     231 +func (a authDo) Where(conds ...gen.Condition) IAuthDo {
     232 + return a.withDO(a.DO.Where(conds...))
     233 +}
     234 + 
     235 +func (a authDo) Order(conds ...field.Expr) IAuthDo {
     236 + return a.withDO(a.DO.Order(conds...))
     237 +}
     238 + 
     239 +func (a authDo) Distinct(cols ...field.Expr) IAuthDo {
     240 + return a.withDO(a.DO.Distinct(cols...))
     241 +}
     242 + 
     243 +func (a authDo) Omit(cols ...field.Expr) IAuthDo {
     244 + return a.withDO(a.DO.Omit(cols...))
     245 +}
     246 + 
     247 +func (a authDo) Join(table schema.Tabler, on ...field.Expr) IAuthDo {
     248 + return a.withDO(a.DO.Join(table, on...))
     249 +}
     250 + 
     251 +func (a authDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAuthDo {
     252 + return a.withDO(a.DO.LeftJoin(table, on...))
     253 +}
     254 + 
     255 +func (a authDo) RightJoin(table schema.Tabler, on ...field.Expr) IAuthDo {
     256 + return a.withDO(a.DO.RightJoin(table, on...))
     257 +}
     258 + 
     259 +func (a authDo) Group(cols ...field.Expr) IAuthDo {
     260 + return a.withDO(a.DO.Group(cols...))
     261 +}
     262 + 
     263 +func (a authDo) Having(conds ...gen.Condition) IAuthDo {
     264 + return a.withDO(a.DO.Having(conds...))
     265 +}
     266 + 
     267 +func (a authDo) Limit(limit int) IAuthDo {
     268 + return a.withDO(a.DO.Limit(limit))
     269 +}
     270 + 
     271 +func (a authDo) Offset(offset int) IAuthDo {
     272 + return a.withDO(a.DO.Offset(offset))
     273 +}
     274 + 
     275 +func (a authDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAuthDo {
     276 + return a.withDO(a.DO.Scopes(funcs...))
     277 +}
     278 + 
     279 +func (a authDo) Unscoped() IAuthDo {
     280 + return a.withDO(a.DO.Unscoped())
     281 +}
     282 + 
     283 +func (a authDo) Create(values ...*models.Auth) error {
     284 + if len(values) == 0 {
     285 + return nil
     286 + }
     287 + return a.DO.Create(values)
     288 +}
     289 + 
     290 +func (a authDo) CreateInBatches(values []*models.Auth, batchSize int) error {
     291 + return a.DO.CreateInBatches(values, batchSize)
     292 +}
     293 + 
     294 +// Save : !!! underlying implementation is different with GORM
     295 +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
     296 +func (a authDo) Save(values ...*models.Auth) error {
     297 + if len(values) == 0 {
     298 + return nil
     299 + }
     300 + return a.DO.Save(values)
     301 +}
     302 + 
     303 +func (a authDo) First() (*models.Auth, error) {
     304 + if result, err := a.DO.First(); err != nil {
     305 + return nil, err
     306 + } else {
     307 + return result.(*models.Auth), nil
     308 + }
     309 +}
     310 + 
     311 +func (a authDo) Take() (*models.Auth, error) {
     312 + if result, err := a.DO.Take(); err != nil {
     313 + return nil, err
     314 + } else {
     315 + return result.(*models.Auth), nil
     316 + }
     317 +}
     318 + 
     319 +func (a authDo) Last() (*models.Auth, error) {
     320 + if result, err := a.DO.Last(); err != nil {
     321 + return nil, err
     322 + } else {
     323 + return result.(*models.Auth), nil
     324 + }
     325 +}
     326 + 
     327 +func (a authDo) Find() ([]*models.Auth, error) {
     328 + result, err := a.DO.Find()
     329 + return result.([]*models.Auth), err
     330 +}
     331 + 
     332 +func (a authDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Auth, err error) {
     333 + buf := make([]*models.Auth, 0, batchSize)
     334 + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
     335 + defer func() { results = append(results, buf...) }()
     336 + return fc(tx, batch)
     337 + })
     338 + return results, err
     339 +}
     340 + 
     341 +func (a authDo) FindInBatches(result *[]*models.Auth, batchSize int, fc func(tx gen.Dao, batch int) error) error {
     342 + return a.DO.FindInBatches(result, batchSize, fc)
     343 +}
     344 + 
     345 +func (a authDo) Attrs(attrs ...field.AssignExpr) IAuthDo {
     346 + return a.withDO(a.DO.Attrs(attrs...))
     347 +}
     348 + 
     349 +func (a authDo) Assign(attrs ...field.AssignExpr) IAuthDo {
     350 + return a.withDO(a.DO.Assign(attrs...))
     351 +}
     352 + 
     353 +func (a authDo) Joins(fields ...field.RelationField) IAuthDo {
     354 + for _, _f := range fields {
     355 + a = *a.withDO(a.DO.Joins(_f))
     356 + }
     357 + return &a
     358 +}
     359 + 
     360 +func (a authDo) Preload(fields ...field.RelationField) IAuthDo {
     361 + for _, _f := range fields {
     362 + a = *a.withDO(a.DO.Preload(_f))
     363 + }
     364 + return &a
     365 +}
     366 + 
     367 +func (a authDo) FirstOrInit() (*models.Auth, error) {
     368 + if result, err := a.DO.FirstOrInit(); err != nil {
     369 + return nil, err
     370 + } else {
     371 + return result.(*models.Auth), nil
     372 + }
     373 +}
     374 + 
     375 +func (a authDo) FirstOrCreate() (*models.Auth, error) {
     376 + if result, err := a.DO.FirstOrCreate(); err != nil {
     377 + return nil, err
     378 + } else {
     379 + return result.(*models.Auth), nil
     380 + }
     381 +}
     382 + 
     383 +func (a authDo) FindByPage(offset int, limit int) (result []*models.Auth, count int64, err error) {
     384 + result, err = a.Offset(offset).Limit(limit).Find()
     385 + if err != nil {
     386 + return
     387 + }
     388 + 
     389 + if size := len(result); 0 < limit && 0 < size && size < limit {
     390 + count = int64(size + offset)
     391 + return
     392 + }
     393 + 
     394 + count, err = a.Offset(-1).Limit(-1).Count()
     395 + return
     396 +}
     397 + 
     398 +func (a authDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
     399 + count, err = a.Count()
     400 + if err != nil {
     401 + return
     402 + }
     403 + 
     404 + err = a.Offset(offset).Limit(limit).Scan(result)
     405 + return
     406 +}
     407 + 
     408 +func (a authDo) Scan(result interface{}) (err error) {
     409 + return a.DO.Scan(result)
     410 +}
     411 + 
     412 +func (a authDo) Delete(models ...*models.Auth) (result gen.ResultInfo, err error) {
     413 + return a.DO.Delete(models)
     414 +}
     415 + 
     416 +func (a *authDo) withDO(do gen.Dao) *authDo {
     417 + a.DO = *do.(*gen.DO)
     418 + return a
     419 +}
     420 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/database/dao/configs.gen.go
     1 +// Code generated by gorm.io/gen. DO NOT EDIT.
     2 +// Code generated by gorm.io/gen. DO NOT EDIT.
     3 +// Code generated by gorm.io/gen. DO NOT EDIT.
     4 + 
     5 +package dao
     6 + 
     7 +import (
     8 + "context"
     9 + 
     10 + "github.com/DVKunion/SeaMoon/pkg/api/models"
     11 + "gorm.io/gorm"
     12 + "gorm.io/gorm/clause"
     13 + "gorm.io/gorm/schema"
     14 + 
     15 + "gorm.io/gen"
     16 + "gorm.io/gen/field"
     17 + 
     18 + "gorm.io/plugin/dbresolver"
     19 +)
     20 + 
     21 +func newConfig(db *gorm.DB, opts ...gen.DOOption) config {
     22 + _config := config{}
     23 + 
     24 + _config.configDo.UseDB(db, opts...)
     25 + _config.configDo.UseModel(&models.Config{})
     26 + 
     27 + tableName := _config.configDo.TableName()
     28 + _config.ALL = field.NewAsterisk(tableName)
     29 + _config.ID = field.NewUint(tableName, "id")
     30 + _config.CreatedAt = field.NewTime(tableName, "created_at")
     31 + _config.UpdatedAt = field.NewTime(tableName, "updated_at")
     32 + _config.DeletedAt = field.NewField(tableName, "deleted_at")
     33 + _config.Key = field.NewString(tableName, "key")
     34 + _config.Value = field.NewString(tableName, "value")
     35 + 
     36 + _config.fillFieldMap()
     37 + 
     38 + return _config
     39 +}
     40 + 
     41 +type config struct {
     42 + configDo configDo
     43 + 
     44 + ALL field.Asterisk
     45 + ID field.Uint
     46 + CreatedAt field.Time
     47 + UpdatedAt field.Time
     48 + DeletedAt field.Field
     49 + Key field.String
     50 + Value field.String
     51 + 
     52 + fieldMap map[string]field.Expr
     53 +}
     54 + 
     55 +func (c config) Table(newTableName string) *config {
     56 + c.configDo.UseTable(newTableName)
     57 + return c.updateTableName(newTableName)
     58 +}
     59 + 
     60 +func (c config) As(alias string) *config {
     61 + c.configDo.DO = *(c.configDo.As(alias).(*gen.DO))
     62 + return c.updateTableName(alias)
     63 +}
     64 + 
     65 +func (c *config) updateTableName(table string) *config {
     66 + c.ALL = field.NewAsterisk(table)
     67 + c.ID = field.NewUint(table, "id")
     68 + c.CreatedAt = field.NewTime(table, "created_at")
     69 + c.UpdatedAt = field.NewTime(table, "updated_at")
     70 + c.DeletedAt = field.NewField(table, "deleted_at")
     71 + c.Key = field.NewString(table, "key")
     72 + c.Value = field.NewString(table, "value")
     73 + 
     74 + c.fillFieldMap()
     75 + 
     76 + return c
     77 +}
     78 + 
     79 +func (c *config) WithContext(ctx context.Context) IConfigDo { return c.configDo.WithContext(ctx) }
     80 + 
     81 +func (c config) TableName() string { return c.configDo.TableName() }
     82 + 
     83 +func (c config) Alias() string { return c.configDo.Alias() }
     84 + 
     85 +func (c config) Columns(cols ...field.Expr) gen.Columns { return c.configDo.Columns(cols...) }
     86 + 
     87 +func (c *config) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
     88 + _f, ok := c.fieldMap[fieldName]
     89 + if !ok || _f == nil {
     90 + return nil, false
     91 + }
     92 + _oe, ok := _f.(field.OrderExpr)
     93 + return _oe, ok
     94 +}
     95 + 
     96 +func (c *config) fillFieldMap() {
     97 + c.fieldMap = make(map[string]field.Expr, 6)
     98 + c.fieldMap["id"] = c.ID
     99 + c.fieldMap["created_at"] = c.CreatedAt
     100 + c.fieldMap["updated_at"] = c.UpdatedAt
     101 + c.fieldMap["deleted_at"] = c.DeletedAt
     102 + c.fieldMap["key"] = c.Key
     103 + c.fieldMap["value"] = c.Value
     104 +}
     105 + 
     106 +func (c config) clone(db *gorm.DB) config {
     107 + c.configDo.ReplaceConnPool(db.Statement.ConnPool)
     108 + return c
     109 +}
     110 + 
     111 +func (c config) replaceDB(db *gorm.DB) config {
     112 + c.configDo.ReplaceDB(db)
     113 + return c
     114 +}
     115 + 
     116 +type configDo struct{ gen.DO }
     117 + 
     118 +type IConfigDo interface {
     119 + gen.SubQuery
     120 + Debug() IConfigDo
     121 + WithContext(ctx context.Context) IConfigDo
     122 + WithResult(fc func(tx gen.Dao)) gen.ResultInfo
     123 + ReplaceDB(db *gorm.DB)
     124 + ReadDB() IConfigDo
     125 + WriteDB() IConfigDo
     126 + As(alias string) gen.Dao
     127 + Session(config *gorm.Session) IConfigDo
     128 + Columns(cols ...field.Expr) gen.Columns
     129 + Clauses(conds ...clause.Expression) IConfigDo
     130 + Not(conds ...gen.Condition) IConfigDo
     131 + Or(conds ...gen.Condition) IConfigDo
     132 + Select(conds ...field.Expr) IConfigDo
     133 + Where(conds ...gen.Condition) IConfigDo
     134 + Order(conds ...field.Expr) IConfigDo
     135 + Distinct(cols ...field.Expr) IConfigDo
     136 + Omit(cols ...field.Expr) IConfigDo
     137 + Join(table schema.Tabler, on ...field.Expr) IConfigDo
     138 + LeftJoin(table schema.Tabler, on ...field.Expr) IConfigDo
     139 + RightJoin(table schema.Tabler, on ...field.Expr) IConfigDo
     140 + Group(cols ...field.Expr) IConfigDo
     141 + Having(conds ...gen.Condition) IConfigDo
     142 + Limit(limit int) IConfigDo
     143 + Offset(offset int) IConfigDo
     144 + Count() (count int64, err error)
     145 + Scopes(funcs ...func(gen.Dao) gen.Dao) IConfigDo
     146 + Unscoped() IConfigDo
     147 + Create(values ...*models.Config) error
     148 + CreateInBatches(values []*models.Config, batchSize int) error
     149 + Save(values ...*models.Config) error
     150 + First() (*models.Config, error)
     151 + Take() (*models.Config, error)
     152 + Last() (*models.Config, error)
     153 + Find() ([]*models.Config, error)
     154 + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Config, err error)
     155 + FindInBatches(result *[]*models.Config, batchSize int, fc func(tx gen.Dao, batch int) error) error
     156 + Pluck(column field.Expr, dest interface{}) error
     157 + Delete(...*models.Config) (info gen.ResultInfo, err error)
     158 + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
     159 + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
     160 + Updates(value interface{}) (info gen.ResultInfo, err error)
     161 + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
     162 + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
     163 + UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
     164 + UpdateFrom(q gen.SubQuery) gen.Dao
     165 + Attrs(attrs ...field.AssignExpr) IConfigDo
     166 + Assign(attrs ...field.AssignExpr) IConfigDo
     167 + Joins(fields ...field.RelationField) IConfigDo
     168 + Preload(fields ...field.RelationField) IConfigDo
     169 + FirstOrInit() (*models.Config, error)
     170 + FirstOrCreate() (*models.Config, error)
     171 + FindByPage(offset int, limit int) (result []*models.Config, count int64, err error)
     172 + ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
     173 + Scan(result interface{}) (err error)
     174 + Returning(value interface{}, columns ...string) IConfigDo
     175 + UnderlyingDB() *gorm.DB
     176 + schema.Tabler
     177 +}
     178 + 
     179 +func (c configDo) Debug() IConfigDo {
     180 + return c.withDO(c.DO.Debug())
     181 +}
     182 + 
     183 +func (c configDo) WithContext(ctx context.Context) IConfigDo {
     184 + return c.withDO(c.DO.WithContext(ctx))
     185 +}
     186 + 
     187 +func (c configDo) ReadDB() IConfigDo {
     188 + return c.Clauses(dbresolver.Read)
     189 +}
     190 + 
     191 +func (c configDo) WriteDB() IConfigDo {
     192 + return c.Clauses(dbresolver.Write)
     193 +}
     194 + 
     195 +func (c configDo) Session(config *gorm.Session) IConfigDo {
     196 + return c.withDO(c.DO.Session(config))
     197 +}
     198 + 
     199 +func (c configDo) Clauses(conds ...clause.Expression) IConfigDo {
     200 + return c.withDO(c.DO.Clauses(conds...))
     201 +}
     202 + 
     203 +func (c configDo) Returning(value interface{}, columns ...string) IConfigDo {
     204 + return c.withDO(c.DO.Returning(value, columns...))
     205 +}
     206 + 
     207 +func (c configDo) Not(conds ...gen.Condition) IConfigDo {
     208 + return c.withDO(c.DO.Not(conds...))
     209 +}
     210 + 
     211 +func (c configDo) Or(conds ...gen.Condition) IConfigDo {
     212 + return c.withDO(c.DO.Or(conds...))
     213 +}
     214 + 
     215 +func (c configDo) Select(conds ...field.Expr) IConfigDo {
     216 + return c.withDO(c.DO.Select(conds...))
     217 +}
     218 + 
     219 +func (c configDo) Where(conds ...gen.Condition) IConfigDo {
     220 + return c.withDO(c.DO.Where(conds...))
     221 +}
     222 + 
     223 +func (c configDo) Order(conds ...field.Expr) IConfigDo {
     224 + return c.withDO(c.DO.Order(conds...))
     225 +}
     226 + 
     227 +func (c configDo) Distinct(cols ...field.Expr) IConfigDo {
     228 + return c.withDO(c.DO.Distinct(cols...))
     229 +}
     230 + 
     231 +func (c configDo) Omit(cols ...field.Expr) IConfigDo {
     232 + return c.withDO(c.DO.Omit(cols...))
     233 +}
     234 + 
     235 +func (c configDo) Join(table schema.Tabler, on ...field.Expr) IConfigDo {
     236 + return c.withDO(c.DO.Join(table, on...))
     237 +}
     238 + 
     239 +func (c configDo) LeftJoin(table schema.Tabler, on ...field.Expr) IConfigDo {
     240 + return c.withDO(c.DO.LeftJoin(table, on...))
     241 +}
     242 + 
     243 +func (c configDo) RightJoin(table schema.Tabler, on ...field.Expr) IConfigDo {
     244 + return c.withDO(c.DO.RightJoin(table, on...))
     245 +}
     246 + 
     247 +func (c configDo) Group(cols ...field.Expr) IConfigDo {
     248 + return c.withDO(c.DO.Group(cols...))
     249 +}
     250 + 
     251 +func (c configDo) Having(conds ...gen.Condition) IConfigDo {
     252 + return c.withDO(c.DO.Having(conds...))
     253 +}
     254 + 
     255 +func (c configDo) Limit(limit int) IConfigDo {
     256 + return c.withDO(c.DO.Limit(limit))
     257 +}
     258 + 
     259 +func (c configDo) Offset(offset int) IConfigDo {
     260 + return c.withDO(c.DO.Offset(offset))
     261 +}
     262 + 
     263 +func (c configDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IConfigDo {
     264 + return c.withDO(c.DO.Scopes(funcs...))
     265 +}
     266 + 
     267 +func (c configDo) Unscoped() IConfigDo {
     268 + return c.withDO(c.DO.Unscoped())
     269 +}
     270 + 
     271 +func (c configDo) Create(values ...*models.Config) error {
     272 + if len(values) == 0 {
     273 + return nil
     274 + }
     275 + return c.DO.Create(values)
     276 +}
     277 + 
     278 +func (c configDo) CreateInBatches(values []*models.Config, batchSize int) error {
     279 + return c.DO.CreateInBatches(values, batchSize)
     280 +}
     281 + 
     282 +// Save : !!! underlying implementation is different with GORM
     283 +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
     284 +func (c configDo) Save(values ...*models.Config) error {
     285 + if len(values) == 0 {
     286 + return nil
     287 + }
     288 + return c.DO.Save(values)
     289 +}
     290 + 
     291 +func (c configDo) First() (*models.Config, error) {
     292 + if result, err := c.DO.First(); err != nil {
     293 + return nil, err
     294 + } else {
     295 + return result.(*models.Config), nil
     296 + }
     297 +}
     298 + 
     299 +func (c configDo) Take() (*models.Config, error) {
     300 + if result, err := c.DO.Take(); err != nil {
     301 + return nil, err
     302 + } else {
     303 + return result.(*models.Config), nil
     304 + }
     305 +}
     306 + 
     307 +func (c configDo) Last() (*models.Config, error) {
     308 + if result, err := c.DO.Last(); err != nil {
     309 + return nil, err
     310 + } else {
     311 + return result.(*models.Config), nil
     312 + }
     313 +}
     314 + 
     315 +func (c configDo) Find() ([]*models.Config, error) {
     316 + result, err := c.DO.Find()
     317 + return result.([]*models.Config), err
     318 +}
     319 + 
     320 +func (c configDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Config, err error) {
     321 + buf := make([]*models.Config, 0, batchSize)
     322 + err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
     323 + defer func() { results = append(results, buf...) }()
     324 + return fc(tx, batch)
     325 + })
     326 + return results, err
     327 +}
     328 + 
     329 +func (c configDo) FindInBatches(result *[]*models.Config, batchSize int, fc func(tx gen.Dao, batch int) error) error {
     330 + return c.DO.FindInBatches(result, batchSize, fc)
     331 +}
     332 + 
     333 +func (c configDo) Attrs(attrs ...field.AssignExpr) IConfigDo {
     334 + return c.withDO(c.DO.Attrs(attrs...))
     335 +}
     336 + 
     337 +func (c configDo) Assign(attrs ...field.AssignExpr) IConfigDo {
     338 + return c.withDO(c.DO.Assign(attrs...))
     339 +}
     340 + 
     341 +func (c configDo) Joins(fields ...field.RelationField) IConfigDo {
     342 + for _, _f := range fields {
     343 + c = *c.withDO(c.DO.Joins(_f))
     344 + }
     345 + return &c
     346 +}
     347 + 
     348 +func (c configDo) Preload(fields ...field.RelationField) IConfigDo {
     349 + for _, _f := range fields {
     350 + c = *c.withDO(c.DO.Preload(_f))
     351 + }
     352 + return &c
     353 +}
     354 + 
     355 +func (c configDo) FirstOrInit() (*models.Config, error) {
     356 + if result, err := c.DO.FirstOrInit(); err != nil {
     357 + return nil, err
     358 + } else {
     359 + return result.(*models.Config), nil
     360 + }
     361 +}
     362 + 
     363 +func (c configDo) FirstOrCreate() (*models.Config, error) {
     364 + if result, err := c.DO.FirstOrCreate(); err != nil {
     365 + return nil, err
     366 + } else {
     367 + return result.(*models.Config), nil
     368 + }
     369 +}
     370 + 
     371 +func (c configDo) FindByPage(offset int, limit int) (result []*models.Config, count int64, err error) {
     372 + result, err = c.Offset(offset).Limit(limit).Find()
     373 + if err != nil {
     374 + return
     375 + }
     376 + 
     377 + if size := len(result); 0 < limit && 0 < size && size < limit {
     378 + count = int64(size + offset)
     379 + return
     380 + }
     381 + 
     382 + count, err = c.Offset(-1).Limit(-1).Count()
     383 + return
     384 +}
     385 + 
     386 +func (c configDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
     387 + count, err = c.Count()
     388 + if err != nil {
     389 + return
     390 + }
     391 + 
     392 + err = c.Offset(offset).Limit(limit).Scan(result)
     393 + return
     394 +}
     395 + 
     396 +func (c configDo) Scan(result interface{}) (err error) {
     397 + return c.DO.Scan(result)
     398 +}
     399 + 
     400 +func (c configDo) Delete(models ...*models.Config) (result gen.ResultInfo, err error) {
     401 + return c.DO.Delete(models)
     402 +}
     403 + 
     404 +func (c *configDo) withDO(do gen.Dao) *configDo {
     405 + c.DO = *do.(*gen.DO)
     406 + return c
     407 +}
     408 + 
  • ■ ■ ■ ■ ■ ■
    pkg/api/database/dao/gen.go
     1 +// Code generated by gorm.io/gen. DO NOT EDIT.
     2 +// Code generated by gorm.io/gen. DO NOT EDIT.
     3 +// Code generated by gorm.io/gen. DO NOT EDIT.
     4 + 
     5 +package dao
     6 + 
     7 +import (
     8 + "context"
     9 + "database/sql"
     10 + 
     11 + "gorm.io/gorm"
     12 + 
     13 + "gorm.io/gen"
     14 + 
     15 + "gorm.io/plugin/dbresolver"
     16 +)
     17 + 
     18 +var (
     19 + Q = new(Query)
     20 + Auth *auth
     21 + Config *config
     22 + Provider *provider
     23 + Proxy *proxy
     24 + Tunnel *tunnel
     25 +)
     26 + 
     27 +func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
     28 + *Q = *Use(db, opts...)
     29 + Auth = &Q.Auth
     30 + Config = &Q.Config
     31 + Provider = &Q.Provider
     32 + Proxy = &Q.Proxy
     33 + Tunnel = &Q.Tunnel
     34 +}
     35 + 
     36 +func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
     37 + return &Query{
     38 + db: db,
     39 + Auth: newAuth(db, opts...),
     40 + Config: newConfig(db, opts...),
     41 + Provider: newProvider(db, opts...),
     42 + Proxy: newProxy(db, opts...),
     43 + Tunnel: newTunnel(db, opts...),
     44 + }
     45 +}
     46 + 
     47 +type Query struct {
     48 + db *gorm.DB
     49 + 
     50 + Auth auth
     51 + Config config
     52 + Provider provider
     53 + Proxy proxy
     54 + Tunnel tunnel
     55 +}
     56 + 
     57 +func (q *Query) Available() bool { return q.db != nil }
     58 + 
     59 +func (q *Query) clone(db *gorm.DB) *Query {
     60 + return &Query{
     61 + db: db,
     62 + Auth: q.Auth.clone(db),
     63 + Config: q.Config.clone(db),
     64 + Provider: q.Provider.clone(db),
     65 + Proxy: q.Proxy.clone(db),
     66 + Tunnel: q.Tunnel.clone(db),
     67 + }
     68 +}
     69 + 
     70 +func (q *Query) ReadDB() *Query {
     71 + return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
     72 +}
     73 + 
     74 +func (q *Query) WriteDB() *Query {
     75 + return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
     76 +}
     77 + 
     78 +func (q *Query) ReplaceDB(db *gorm.DB) *Query {
     79 + return &Query{
     80 + db: db,
     81 + Auth: q.Auth.replaceDB(db),
     82 + Config: q.Config.replaceDB(db),
     83 + Provider: q.Provider.replaceDB(db),
     84 + Proxy: q.Proxy.replaceDB(db),
     85 + Tunnel: q.Tunnel.replaceDB(db),
     86 + }
     87 +}
     88 + 
     89 +type queryCtx struct {
     90 + Auth IAuthDo
     91 + Config IConfigDo
     92 + Provider IProviderDo
     93 + Proxy IProxyDo
     94 + Tunnel ITunnelDo
     95 +}
     96 + 
     97 +func (q *Query) WithContext(ctx context.Context) *queryCtx {
     98 + return &queryCtx{
     99 + Auth: q.Auth.WithContext(ctx),
     100 + Config: q.Config.WithContext(ctx),
     101 + Provider: q.Provider.WithContext(ctx),
     102 + Proxy: q.Proxy.WithContext(ctx),
     103 + Tunnel: q.Tunnel.WithContext(ctx),
     104 + }
     105 +}
     106 + 
     107 +func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
     108 + return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
     109 +}
     110 + 
     111 +func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
     112 + tx := q.db.Begin(opts...)
     113 + return &QueryTx{Query: q.clone(tx), Error: tx.Error}
     114 +}
     115 + 
     116 +type QueryTx struct {
     117 + *Query
     118 + Error error
     119 +}
     120 + 
     121 +func (q *QueryTx) Commit() error {
     122 + return q.db.Commit().Error
     123 +}
     124 + 
     125 +func (q *QueryTx) Rollback() error {
     126 + return q.db.Rollback().Error
     127 +}
     128 + 
     129 +func (q *QueryTx) SavePoint(name string) error {
     130 + return q.db.SavePoint(name).Error
     131 +}
     132 + 
     133 +func (q *QueryTx) RollbackTo(name string) error {
     134 + return q.db.RollbackTo(name).Error
     135 +}
     136 + 
Please wait...
Page is in error, reload to recover