Projects STRLCPY SeaMoon Commits 7620c14b
🤬
  • ■ ■ ■ ■
    cmd/client/api/control/proxy.go
    skipped 7 lines
    8 8   
    9 9   "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    10 10   "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    11  - "github.com/DVKunion/SeaMoon/cmd/client/api/signal"
    12 11   "github.com/DVKunion/SeaMoon/cmd/client/api/types"
     12 + "github.com/DVKunion/SeaMoon/cmd/client/signal"
    13 13   "github.com/DVKunion/SeaMoon/pkg/tunnel"
    14 14  )
    15 15   
    skipped 175 lines
  • ■ ■ ■ ■ ■
    cmd/client/api/models/tunnel.go
    skipped 17 lines
    18 18   Name *string // 隧道名称,建议英文
    19 19   Addr *string // 服务地址
    20 20   Port *string // 服务端口
    21  - Cost *float32 // 累计花费
    22 21   Type *tunnel.Type // 隧道协议类型
    23 22   Status *tunnel.Status // 隧道状态
    24 23   
    skipped 60 lines
  • ■ ■ ■ ■ ■
    cmd/client/api/types/auth.go
    skipped 9 lines
    10 10   
    11 11   Signature // FC Signature 认证, 这类认证好处在于认证失败 403 不计次数
    12 12   Jwt // FC Jwt 认证。 需要 jwks
     13 + Paris // SCF 网管密钥对认证
    13 14  )
    14 15   
    15 16  func TransAuthType(t string) AuthType {
    16 17   switch t {
    17  - case "anonymous":
     18 + case "anonymous", "NONE":
    18 19   return Empty
    19 20   case "function":
    20 21   return Signature
    skipped 6 lines
  • ■ ■ ■ ■
    cmd/client/client.go
    skipped 13 lines
    14 14   
    15 15   "github.com/DVKunion/SeaMoon/cmd/client/api"
    16 16   "github.com/DVKunion/SeaMoon/cmd/client/api/service"
    17  - "github.com/DVKunion/SeaMoon/cmd/client/api/signal"
     17 + "github.com/DVKunion/SeaMoon/cmd/client/signal"
    18 18   "github.com/DVKunion/SeaMoon/cmd/client/static"
    19 19   "github.com/DVKunion/SeaMoon/pkg/consts"
    20 20   "github.com/DVKunion/SeaMoon/pkg/xlog"
    skipped 45 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/api/listener/listen.go cmd/client/listener/listen.go
    skipped 64 lines
    65 65   service.WithAddr(tun.GetAddr()), service.WithTorFlag(tun.TunnelConfig.Tor))
    66 66   if err != nil {
    67 67   slog.Error(xlog.CONNECT_RMOET_ERROR, "err", err)
    68  - // 说明远程连接失败了,直接把当前的这个 conn 关掉,然后数量 -1
    69  - //_ = conn.Close()
    70 68   count(dbProxy, pro.ID, -1, m)
    71 69   continue
    72 70   }
    skipped 26 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/aliyun.go cmd/client/sdk/aliyun/aliyun.go
    1  -package sdk
     1 +package aliyun
    2 2   
    3 3  import (
    4 4   "encoding/json"
    skipped 17 lines
    22 22  )
    23 23   
    24 24  var (
    25  - // 阿里云在 fc 上层还有一套 service 的概念,为了方便管理,这里硬编码了 service 的内容。
     25 + // 阿里云 在 fc 上层还有一套 service 的概念,为了方便管理,这里硬编码了 service 的内容。
    26 26   serviceName = "seamoon"
    27 27   serviceDesc = "seamoon service"
    28 28  )
    29 29   
    30  -type ALiYunSDK struct {
     30 +// SDK FC
     31 +type SDK struct {
    31 32  }
    32 33   
    33 34  type Resp struct {
    skipped 8 lines
    42 43   } `json:"body"`
    43 44  }
    44 45   
    45  -func (a *ALiYunSDK) Auth(providerId uint) error {
     46 +func (a *SDK) Auth(providerId uint) error {
    46 47   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    47 48   config := &openapi.Config{
    48 49   // 必填,您的 AccessKey ID
    skipped 57 lines
    106 107   return nil
    107 108  }
    108 109   
    109  -func (a *ALiYunSDK) Deploy(providerId uint, tun *models.Tunnel) error {
     110 +func (a *SDK) Deploy(providerId uint, tun *models.Tunnel) error {
    110 111   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    111 112   // 原生的库是真tm的难用,
    112 113   client, err := fc.NewClient(
    skipped 68 lines
    181 182   return nil
    182 183  }
    183 184   
    184  -func (a *ALiYunSDK) Destroy(providerId uint, tun *models.Tunnel) error {
     185 +func (a *SDK) Destroy(providerId uint, tun *models.Tunnel) error {
    185 186   return nil
    186 187  }
    187 188   
    188  -func (a *ALiYunSDK) SyncFC(providerId uint) error {
     189 +func (a *SDK) SyncFC(providerId uint) error {
    189 190   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    190 191   client, err := fc.NewClient(
    191 192   fmt.Sprintf("%s.%s.fc.aliyuncs.com", provider.CloudAuth.AccessId, *provider.Region),
    skipped 76 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/aws.go
    1 1  package sdk
    2 2   
     3 +// todo
     4 + 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/baidu.go
    1 1  package sdk
    2 2   
     3 +// todo
     4 + 
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/sdk.go
    skipped 2 lines
    3 3  import (
    4 4   "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    5 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"
    6 9  )
    7 10   
    8 11  type CloudSDK interface {
    9  - // Auth 判断是否存在权限动作, 并获取账户钱包信息
     12 + // Auth 判断是否认证信息有效,并尝试增添最低的权限角色。
    10 13   Auth(providerId uint) error
    11 14   // Deploy 部署隧道函数
    12 15   Deploy(providerId uint, tun *models.Tunnel) error
    skipped 2 lines
    15 18   // SyncFC 同步函数
    16 19   SyncFC(providerId uint) error
    17 20   
    18  - // Billing(provider models.CloudProvider, tunnel models.Tunnel) error
    19  - 
    20 21   // UpdateVersion 一键更新: 用本地的版本号请求远端服务更新至
    21 22   // UpdateVersion(auth models.CloudAuth) error
    22 23  }
    skipped 5 lines
    28 29  }
    29 30   
    30 31  func init() {
    31  - cloudFactory[types.ALiYun] = &ALiYunSDK{}
    32  - cloudFactory[types.Sealos] = &SealosSDK{}
     32 + cloudFactory[types.ALiYun] = &aliyun.SDK{}
     33 + cloudFactory[types.TencentYun] = &tencent.SDK{}
     34 + cloudFactory[types.Sealos] = &sealos.SDK{}
    33 35  }
    34 36   
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/sealos.go cmd/client/sdk/sealos/sealos.go
    1  -package sdk
     1 +package sealos
    2 2   
    3 3  import (
    4 4   "context"
    skipped 19 lines
    24 24   
    25 25   "github.com/DVKunion/SeaMoon/cmd/client/api/models"
    26 26   "github.com/DVKunion/SeaMoon/cmd/client/api/service"
     27 + "github.com/DVKunion/SeaMoon/cmd/client/sdk"
    27 28   "github.com/DVKunion/SeaMoon/pkg/consts"
    28 29   "github.com/DVKunion/SeaMoon/pkg/tools"
    29 30   "github.com/DVKunion/SeaMoon/pkg/tunnel"
    30 31  )
    31 32   
    32  -type SealosSDK struct {
     33 +type SDK struct {
    33 34  }
    34 35   
    35 36  var (
    skipped 2 lines
    38 39   fl = false
    39 40  )
    40 41   
    41  -type SealosAmount struct {
     42 +type Amount struct {
    42 43   Code int `json:"code"`
    43 44   Message string `json:"message"`
    44 45   Data struct {
    skipped 5 lines
    50 51   } `json:"data"`
    51 52  }
    52 53   
    53  -func (s SealosSDK) Auth(providerId uint) error {
     54 +func (s *SDK) Auth(providerId uint) error {
    54 55   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    55  - amountUrl := fmt.Sprintf("https://costcenter.%s/api/account/getAmount", SealosRegionMap[*provider.Region])
     56 + amountUrl := fmt.Sprintf("https://costcenter.%s/api/account/getAmount", sdk.SealosRegionMap[*provider.Region])
    56 57   
    57 58   req, err := http.NewRequest("GET", amountUrl, nil)
    58 59   if err != nil {
    skipped 21 lines
    80 81   return err
    81 82   }
    82 83   
    83  - var sa = SealosAmount{}
     84 + var sa = Amount{}
    84 85   err = json.Unmarshal(body, &sa)
    85 86   if err != nil {
    86 87   return err
    skipped 7 lines
    94 95   return nil
    95 96  }
    96 97   
    97  -func (s SealosSDK) Billing(providerId uint, tunnel models.Tunnel) error {
     98 +func (s *SDK) Billing(providerId uint, tunnel models.Tunnel) error {
    98 99   // 详细计算某个隧道花费数据
    99 100   //url := fmt.Sprintf("https://costcenter.%s/api/billing", SealosRegionMap[provider.Region])
    100 101   return nil
    101 102  }
    102 103   
    103  -func (s SealosSDK) Deploy(providerId uint, tun *models.Tunnel) error {
     104 +func (s *SDK) Deploy(providerId uint, tun *models.Tunnel) error {
    104 105   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    105 106   // sealos 部署十分简单,直接调用 k8s client-go 即可。
    106 107   ctx := context.TODO()
    skipped 171 lines
    278 279   Spec: networkingv1.IngressSpec{
    279 280   Rules: []networkingv1.IngressRule{
    280 281   {
    281  - Host: fmt.Sprintf("%s.%s", hostName, SealosRegionMap[*provider.Region]),
     282 + Host: fmt.Sprintf("%s.%s", hostName, sdk.SealosRegionMap[*provider.Region]),
    282 283   IngressRuleValue: networkingv1.IngressRuleValue{
    283 284   HTTP: &networkingv1.HTTPIngressRuleValue{
    284 285   Paths: []networkingv1.HTTPIngressPath{
    skipped 16 lines
    301 302   },
    302 303   TLS: []networkingv1.IngressTLS{
    303 304   {
    304  - Hosts: []string{fmt.Sprintf("%s.%s", hostName, SealosRegionMap[*provider.Region])},
     305 + Hosts: []string{fmt.Sprintf("%s.%s", hostName, sdk.SealosRegionMap[*provider.Region])},
    305 306   SecretName: "wildcard-cloud-sealos-io-cert",
    306 307   },
    307 308   },
    skipped 5 lines
    313 314   }
    314 315   fmt.Println("Ingress创建成功!")
    315 316   *tun.Status = tunnel.ACTIVE
    316  - *tun.Addr = fmt.Sprintf("%s.%s", hostName, SealosRegionMap[*provider.Region])
     317 + *tun.Addr = fmt.Sprintf("%s.%s", hostName, sdk.SealosRegionMap[*provider.Region])
    317 318   service.GetService("tunnel").Update(tun.ID, tun)
    318 319   return nil
    319 320  }
    320 321   
    321  -func (s SealosSDK) Destroy(providerId uint, tun *models.Tunnel) error {
     322 +func (s *SDK) Destroy(providerId uint, tun *models.Tunnel) error {
    322 323   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    323 324   ctx := context.TODO()
    324 325   
    skipped 21 lines
    346 347   return nil
    347 348  }
    348 349   
    349  -func (s SealosSDK) SyncFC(providerId uint) error {
     350 +func (s *SDK) SyncFC(providerId uint) error {
    350 351   provider := service.GetService("provider").GetById(providerId).(*models.CloudProvider)
    351 352   tunList := make([]models.Tunnel, 0)
    352 353   ctx := context.TODO()
    skipped 21 lines
    374 375   *tun.Name = strings.Split(svc.Name, "-")[1]
    375 376   *tun.Port = strconv.Itoa(int(svc.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort))
    376 377   *tun.Type = func() tunnel.Type {
    377  - if strings.HasSuffix(svc.Name, "websocket-tunnel") {
     378 + if strings.HasSuffix(svc.Name, "websocket") {
    378 379   return tunnel.WST
    379 380   }
    380  - if strings.HasSuffix(svc.Name, "grpc-tunnel") {
     381 + if strings.HasSuffix(svc.Name, "grpc") {
    381 382   return tunnel.GRT
    382 383   }
    383 384   return tunnel.NULL
    skipped 49 lines
  • ■ ■ ■ ■ ■ ■
    cmd/client/sdk/tencent/sdk.go
     1 +package tencent
     2 + 
     3 +import (
     4 + "encoding/json"
     5 + "errors"
     6 + "strconv"
     7 + "strings"
     8 + "time"
     9 + 
     10 + billing "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing/v20180709"
     11 + cam "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam/v20190116"
     12 + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
     13 + fcError "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
     14 + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
     15 + scf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf/v20180416"
     16 + 
     17 + "github.com/DVKunion/SeaMoon/cmd/client/api/models"
     18 + "github.com/DVKunion/SeaMoon/cmd/client/api/types"
     19 + "github.com/DVKunion/SeaMoon/pkg/consts"
     20 + "github.com/DVKunion/SeaMoon/pkg/xlog"
     21 +)
     22 + 
     23 +const (
     24 + BillEndPoint = "billing.tencentcloudapi.com"
     25 + SCFEndPoint = "scf.tencentcloudapi.com"
     26 + CAMEndPoint = "cam.tencentcloudapi.com"
     27 +)
     28 + 
     29 +type triggerDesc struct {
     30 + Api triggerDescApi `json:"api"`
     31 + Service triggerDescService `json:"service"`
     32 + Release struct {
     33 + EnvironmentName string `json:"environmentName"`
     34 + } `json:"release"`
     35 +}
     36 + 
     37 +type triggerDescApi struct {
     38 + AuthRequired string `json:"authRequired"`
     39 + AuthType string `json:"authType"`
     40 + RequestConfig struct {
     41 + Method string `json:"method"`
     42 + Path string `json:"path"`
     43 + } `json:"requestConfig"`
     44 + IsIntegratedResponse string `json:"isIntegratedResponse"`
     45 + IsBase64Encoded string `json:"isBase64Encoded"`
     46 +}
     47 + 
     48 +type triggerDescService struct {
     49 + ServiceName string `json:"serviceName"`
     50 + ServiceType string `json:"serviceType"`
     51 + SubDomain string `json:"subDomain"`
     52 + Tags []string `json:"tags"`
     53 +}
     54 + 
     55 +type triggerResp struct {
     56 + Service struct {
     57 + SubDomain string `json:"subDomain"`
     58 + } `json:"service"`
     59 +}
     60 + 
     61 +type fcInfo struct {
     62 + detail *scf.GetFunctionResponseParams
     63 + addr string
     64 + auth string
     65 +}
     66 + 
     67 +func (t *SDK) auth(provider *models.CloudProvider) error {
     68 + credential := common.NewCredential(
     69 + provider.CloudAuth.AccessKey,
     70 + provider.CloudAuth.AccessSecret,
     71 + )
     72 + 
     73 + cpf := profile.NewClientProfile()
     74 + // 需要授权: SCF、 API GateWay
     75 + cpf.HttpProfile.Endpoint = "cam.tencentcloudapi.com"
     76 + roleClient, _ := cam.NewClient(credential, "ap-guangzhou", cpf)
     77 + 
     78 + apiGateWayPolicy := "{\"version\":\"2.0\",\"statement\":[{\"action\":\"name/sts:AssumeRole\",\"effect\":\"allow\",\"principal\":{\"service\":\"apigateway.qcloud.com\"}}]}"
     79 + fcPolicy := "{\"version\":\"2.0\",\"statement\":[{\"action\":\"name/sts:AssumeRole\",\"effect\":\"allow\",\"principal\":{\"service\":\"scf.qcloud.com\"}}]}"
     80 + 
     81 + roleRequest := cam.NewCreateRoleRequest()
     82 + roleRequest.RoleName = common.StringPtr("ApiGateWay_QCSRole")
     83 + roleRequest.PolicyDocument = common.StringPtr(apiGateWayPolicy)
     84 + roleRequest.Description = common.StringPtr("API 网关(API Gateway)对您的腾讯云资源进行访问操作,含上传日志、获取日志游标、下载日志、获取日志主题信息等。")
     85 + 
     86 + _, err := roleClient.CreateRole(roleRequest)
     87 + if err != nil {
     88 + if err, ok := err.(*fcError.TencentCloudSDKError); !ok || err.Code != "InvalidParameter.RoleNameInUse" ||
     89 + err.Message != "role name in use" {
     90 + return err
     91 + }
     92 + }
     93 + 
     94 + attachRolePolicyRequest := cam.NewAttachRolePolicyRequest()
     95 + attachRolePolicyRequest.PolicyName = common.StringPtr("QcloudAccessForAPIGatewayRoleInSCFTrigger")
     96 + attachRolePolicyRequest.AttachRoleName = roleRequest.RoleName
     97 + 
     98 + _, err = roleClient.AttachRolePolicy(attachRolePolicyRequest)
     99 + if err != nil {
     100 + return err
     101 + }
     102 + 
     103 + roleRequest = cam.NewCreateRoleRequest()
     104 + roleRequest.RoleName = common.StringPtr("SCF_QcsRole")
     105 + roleRequest.PolicyDocument = common.StringPtr(fcPolicy)
     106 + roleRequest.Description = common.StringPtr("云函数(SCF)操作权限含创建对象存储(COS)触发器,拉取代码包等;含创建API网关(API Gateway)触发器等;含消创建息队列(CMQ)触发器等;含投递日志服务(CLS)日志等。")
     107 + 
     108 + _, err = roleClient.CreateRole(roleRequest)
     109 + if err != nil {
     110 + if err, ok := err.(*fcError.TencentCloudSDKError); !ok || err.Code != "InvalidParameter.RoleNameInUse" ||
     111 + err.Message != "role name in use" {
     112 + return err
     113 + }
     114 + }
     115 + 
     116 + attachRolePolicyRequest = cam.NewAttachRolePolicyRequest()
     117 + attachRolePolicyRequest.PolicyName = common.StringPtr("QcloudAccessForScfRole")
     118 + attachRolePolicyRequest.AttachRoleName = roleRequest.RoleName
     119 + 
     120 + _, err = roleClient.AttachRolePolicy(attachRolePolicyRequest)
     121 + if err != nil {
     122 + return err
     123 + }
     124 + 
     125 + return nil
     126 +}
     127 + 
     128 +func (t *SDK) billing(provider *models.CloudProvider) (float64, error) {
     129 + credential := common.NewCredential(
     130 + provider.CloudAuth.AccessKey,
     131 + provider.CloudAuth.AccessSecret,
     132 + )
     133 + 
     134 + cpf := profile.NewClientProfile()
     135 + cpf.HttpProfile.Endpoint = BillEndPoint
     136 + 
     137 + client, err := billing.NewClient(credential, "", cpf)
     138 + 
     139 + if err != nil {
     140 + return 0, err
     141 + }
     142 + 
     143 + // 构造请求
     144 + request := billing.NewDescribeAccountBalanceRequest()
     145 + 
     146 + // 发送请求
     147 + response, err := client.DescribeAccountBalance(request)
     148 + 
     149 + if err != nil {
     150 + return 0, err
     151 + }
     152 + 
     153 + balance := *response.Response.Balance
     154 + 
     155 + return float64(balance) / 100, nil
     156 +}
     157 + 
     158 +func (t *SDK) deploy(provider *models.CloudProvider, tun *models.Tunnel) (string, error) {
     159 + credential := common.NewCredential(
     160 + provider.CloudAuth.AccessKey,
     161 + provider.CloudAuth.AccessSecret,
     162 + )
     163 + 
     164 + cpf := profile.NewClientProfile()
     165 + cpf.HttpProfile.Endpoint = SCFEndPoint
     166 + 
     167 + // 创建 SFC 客户端
     168 + client, err := scf.NewClient(credential, *provider.Region, cpf)
     169 + 
     170 + if err != nil {
     171 + return "", err
     172 + }
     173 + 
     174 + // SCF 需要一个 namespace
     175 + // 同阿里云一样,这里硬编码一个 code
     176 + nsRequest := scf.NewCreateNamespaceRequest()
     177 + 
     178 + nsRequest.Namespace = common.StringPtr(serviceName)
     179 + nsRequest.Description = common.StringPtr(serviceDesc)
     180 + _, err = client.CreateNamespace(nsRequest)
     181 + if err != nil {
     182 + // 如果错误是 ns 存在,则忽略。
     183 + if err, ok := err.(*fcError.TencentCloudSDKError); !ok || err.Code != scf.RESOURCEINUSE_NAMESPACE {
     184 + return "", err
     185 + }
     186 + }
     187 + 
     188 + // 创建函数
     189 + request := scf.NewCreateFunctionRequest()
     190 + 
     191 + // 查询的时候只能用模糊匹配,sb, 得用个不会模糊的前缀区分
     192 + fcName := "a" + strconv.Itoa(int(tun.CreatedAt.Unix())) + "-" + *tun.Name
     193 + 
     194 + request.Namespace = common.StringPtr(serviceName)
     195 + request.FunctionName = common.StringPtr(fcName)
     196 + request.Description = common.StringPtr(string(*tun.Type))
     197 + request.Type = common.StringPtr("HTTP")
     198 + // 腾讯云没有 cpu 大小设置选项
     199 + request.MemorySize = common.Int64Ptr(int64(tun.TunnelConfig.Memory))
     200 + // 需要记得打开 ws 支持
     201 + request.ProtocolType = common.StringPtr("WS")
     202 + request.ProtocolParams = &scf.ProtocolParams{
     203 + WSParams: &scf.WSParams{
     204 + IdleTimeOut: common.Uint64Ptr(60),
     205 + },
     206 + }
     207 + request.Timeout = common.Int64Ptr(600)
     208 + 
     209 + port, err := strconv.Atoi(*tun.Port)
     210 + if err != nil {
     211 + return "", err
     212 + }
     213 + 
     214 + request.AutoCreateClsTopic = common.StringPtr("FALSE")
     215 + 
     216 + request.Code = &scf.Code{
     217 + ImageConfig: &scf.ImageConfig{
     218 + ImageType: common.StringPtr("personal"),
     219 + ImageUri: common.StringPtr("hkccr.ccs.tencentyun.com/seamoon/seamoon:" + consts.Version),
     220 + Command: common.StringPtr("/app/seamoon"),
     221 + Args: common.StringPtr("server -p " + *tun.Port + " -t " + string(*tun.Type)),
     222 + ImagePort: common.Int64Ptr(int64(port)),
     223 + },
     224 + }
     225 + 
     226 + if tun.TunnelConfig.Tor {
     227 + request.Environment = &scf.Environment{
     228 + Variables: []*scf.Variable{
     229 + {
     230 + Key: common.StringPtr("SEAMOON_TOR"),
     231 + Value: common.StringPtr("true"),
     232 + },
     233 + },
     234 + }
     235 + }
     236 + 
     237 + request.PublicNetConfig = &scf.PublicNetConfigIn{
     238 + PublicNetStatus: common.StringPtr("ENABLE"),
     239 + EipConfig: &scf.EipConfigIn{
     240 + EipStatus: common.StringPtr("DISABLE"),
     241 + },
     242 + }
     243 + 
     244 + request.InstanceConcurrencyConfig = &scf.InstanceConcurrencyConfig{
     245 + DynamicEnabled: common.StringPtr("FALSE"),
     246 + MaxConcurrency: common.Uint64Ptr(uint64(tun.TunnelConfig.Instance)),
     247 + }
     248 + 
     249 + _, err = client.CreateFunction(request)
     250 + if err != nil {
     251 + if err, ok := err.(*fcError.TencentCloudSDKError); !ok || err.Code != scf.RESOURCEINUSE_FUNCTION {
     252 + return "", err
     253 + }
     254 + }
     255 + 
     256 + // 查询等待状态正常
     257 + // 尝试查询20次,每次等待1秒
     258 + cnt := 0
     259 + for cnt < 20 {
     260 + eRequest := scf.NewListFunctionsRequest()
     261 + eRequest.Namespace = common.StringPtr(serviceName)
     262 + eRequest.SearchKey = common.StringPtr(fcName)
     263 + 
     264 + fc, err := client.ListFunctions(eRequest)
     265 + if err != nil {
     266 + return "", err
     267 + }
     268 + if *fc.Response.TotalCount != 1 {
     269 + return "", errors.New("查询到多余的函数")
     270 + }
     271 + xlog.Info("SDK", "正在等待函数创建成功...", "status", *fc.Response.Functions[0].Status, "cnt", cnt)
     272 + switch *fc.Response.Functions[0].Status {
     273 + case "Active":
     274 + cnt = 21
     275 + case "Creating":
     276 + time.Sleep(1 * time.Second)
     277 + cnt++
     278 + continue
     279 + default:
     280 + return "", errors.New(*fc.Response.Functions[0].StatusDesc)
     281 + }
     282 + }
     283 + 
     284 + // 尝试创建触发器
     285 + r := scf.NewCreateTriggerRequest()
     286 + r.TriggerName = common.StringPtr("apigw")
     287 + r.FunctionName = common.StringPtr(fcName)
     288 + r.Type = common.StringPtr("apigw")
     289 + 
     290 + config, err := json.Marshal(&triggerDesc{
     291 + Api: triggerDescApi{
     292 + AuthRequired: func() string {
     293 + if tun.TunnelConfig.TunnelAuthType == types.Paris {
     294 + return "TRUE"
     295 + }
     296 + return "FALSE"
     297 + }(),
     298 + RequestConfig: struct {
     299 + Method string `json:"method"`
     300 + Path string `json:"path"`
     301 + }{Method: "GET", Path: "/"},
     302 + IsIntegratedResponse: "FALSE",
     303 + IsBase64Encoded: "FALSE",
     304 + },
     305 + Service: triggerDescService{
     306 + ServiceName: "SCF_API_SERVICE",
     307 + ServiceType: "BASIC",
     308 + },
     309 + Release: struct {
     310 + EnvironmentName string `json:"environmentName"`
     311 + }{EnvironmentName: "release"},
     312 + })
     313 + 
     314 + // 触发器配置参数叫做 desc...
     315 + r.TriggerDesc = common.StringPtr(string(config))
     316 + r.Namespace = common.StringPtr(serviceName)
     317 + 
     318 + response, err := client.CreateTrigger(r)
     319 + if err != nil {
     320 + return "", err
     321 + }
     322 + 
     323 + extractor := &triggerResp{}
     324 + desc := *response.Response.TriggerInfo.TriggerDesc
     325 + if err := json.Unmarshal([]byte(desc), extractor); err != nil {
     326 + return "", err
     327 + }
     328 + 
     329 + return extractor.Service.SubDomain, nil
     330 +}
     331 + 
     332 +func (t *SDK) sync(provider *models.CloudProvider) ([]fcInfo, error) {
     333 + credential := common.NewCredential(
     334 + provider.CloudAuth.AccessKey,
     335 + provider.CloudAuth.AccessSecret,
     336 + )
     337 + 
     338 + cpf := profile.NewClientProfile()
     339 + cpf.HttpProfile.Endpoint = SCFEndPoint
     340 + 
     341 + // 创建 SFC 客户端
     342 + client, err := scf.NewClient(credential, *provider.Region, cpf)
     343 + 
     344 + if err != nil {
     345 + return nil, err
     346 + }
     347 + 
     348 + request := scf.NewListFunctionsRequest()
     349 + request.Namespace = common.StringPtr(serviceName)
     350 + request.Limit = common.Int64Ptr(999999)
     351 + fcList, err := client.ListFunctions(request)
     352 + if err != nil {
     353 + return nil, err
     354 + }
     355 + var res = make([]fcInfo, 0)
     356 + // list 不够详细,需要继续处理
     357 + for _, fc := range fcList.Response.Functions {
     358 + target := fcInfo{}
     359 + req := scf.NewGetFunctionRequest()
     360 + req.FunctionName = fc.FunctionName
     361 + req.Namespace = fc.Namespace
     362 + fcd, err := client.GetFunction(req)
     363 + if err != nil {
     364 + xlog.Error("SDK", "get function detail error", "name", *fc.FunctionName, "err", err)
     365 + continue
     366 + } else {
     367 + target.detail = fcd.Response
     368 + // 解析触发器
     369 + trigger := fcd.Response.Triggers
     370 + if len(trigger) < 1 {
     371 + xlog.Error("SDK", "get function triggers error", "name", *fc.FunctionName, "err", err)
     372 + } else {
     373 + var tri triggerDesc
     374 + err := json.Unmarshal([]byte(*trigger[0].TriggerDesc), &tri)
     375 + if err != nil {
     376 + xlog.Error("SDK", "get function triggers json error", "name", *fc.FunctionName, "err", err)
     377 + }
     378 + target.addr = strings.Replace(tri.Service.SubDomain, "https://", "", -1)
     379 + target.auth = tri.Api.AuthType
     380 + }
     381 + }
     382 + 
     383 + res = append(res, target)
     384 + }
     385 + return res, nil
     386 +}
     387 + 
  • ■ ■ ■ ■ ■ ■
    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/sdk/tencent.go
    1  -package sdk
    2  - 
  • ■ ■ ■ ■
    cmd/client/api/signal/signal.go cmd/client/signal/signal.go
    skipped 4 lines
    5 5   "log/slog"
    6 6   "net"
    7 7   
    8  - "github.com/DVKunion/SeaMoon/cmd/client/api/listener"
    9 8   "github.com/DVKunion/SeaMoon/cmd/client/api/types"
     9 + "github.com/DVKunion/SeaMoon/cmd/client/listener"
    10 10   "github.com/DVKunion/SeaMoon/pkg/xlog"
    11 11  )
    12 12   
    skipped 76 lines
  • ■ ■ ■ ■ ■ ■
    go.mod
    skipped 12 lines
    13 13   github.com/golang-jwt/jwt v3.2.2+incompatible
    14 14   github.com/gorilla/websocket v1.5.1
    15 15   github.com/spf13/cobra v1.8.0
     16 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866
     17 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866
     18 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.866
     19 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.866
    16 20   github.com/tg123/go-htpasswd v1.2.0
    17 21   google.golang.org/grpc v1.37.0
    18 22   google.golang.org/protobuf v1.31.0
    skipped 86 lines
  • ■ ■ ■ ■ ■ ■
    go.sum
    skipped 209 lines
    210 210  github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
    211 211  github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
    212 212  github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
     213 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866 h1:GB1M0t/+jiJET18SBH8ZS9cRax/s7G6R5DD8djGVV54=
     214 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866/go.mod h1:q3z5hNxMu2l9uXR7S8oHQMzlu/Be0GtXaML8dOWG77Y=
     215 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866 h1:xTBIyd52OUpCDgtsujz7+kiUyz/AP/LweYhS2WoV8AM=
     216 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866/go.mod h1:QbPLSDQeimGYIxI0JSjnhOWJzJWy14T4rfD4tO+DRdE=
     217 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.866 h1:qVui3jFr+antCKDYJOIVoNcNYwOVairHkWHKROztuac=
     218 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.866/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
     219 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.866 h1:LIMZ2+Cob57pryoNjPckpC5QSveSRkCPy8T8aYY35bg=
     220 +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.866/go.mod h1:UXHY/ZxZm9E62mEDacQ8Izc8vR+BtBSLjBbLtuH287o=
    213 221  github.com/tg123/go-htpasswd v1.2.0 h1:UKp34m9H467/xklxUxU15wKRru7fwXoTojtxg25ITF0=
    214 222  github.com/tg123/go-htpasswd v1.2.0/go.mod h1:h7IzlfpvIWnVJhNZ0nQ9HaFxHb7pn5uFJYLlEUJa2sM=
    215 223  github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
    skipped 189 lines
  • ■ ■ ■ ■ ■ ■
    pkg/tools/ptr.go
     1 +package tools
     2 + 
     3 +func IntPtr(v int) *int {
     4 + return &v
     5 +}
     6 + 
     7 +func Int32Ptr(v int32) *int32 {
     8 + return &v
     9 +}
     10 + 
     11 +func Int64Ptr(v int64) *int64 {
     12 + return &v
     13 +}
     14 + 
     15 +func UintPtr(v uint) *uint {
     16 + return &v
     17 +}
     18 + 
     19 +func Uint64Ptr(v uint64) *uint64 {
     20 + return &v
     21 +}
     22 + 
     23 +func Float64Ptr(v float64) *float64 {
     24 + return &v
     25 +}
     26 + 
     27 +func BoolPtr(v bool) *bool {
     28 + return &v
     29 +}
     30 + 
     31 +func StringPtr(v string) *string {
     32 + return &v
     33 +}
     34 + 
     35 +func StringValues(ptrs []*string) []string {
     36 + values := make([]string, len(ptrs))
     37 + for i := 0; i < len(ptrs); i++ {
     38 + if ptrs[i] != nil {
     39 + values[i] = *ptrs[i]
     40 + }
     41 + }
     42 + return values
     43 +}
     44 + 
     45 +func IntPtrs(vals []int) []*int {
     46 + ptrs := make([]*int, len(vals))
     47 + for i := 0; i < len(vals); i++ {
     48 + ptrs[i] = &vals[i]
     49 + }
     50 + return ptrs
     51 +}
     52 + 
     53 +func Int64Ptrs(vals []int64) []*int64 {
     54 + ptrs := make([]*int64, len(vals))
     55 + for i := 0; i < len(vals); i++ {
     56 + ptrs[i] = &vals[i]
     57 + }
     58 + return ptrs
     59 +}
     60 + 
     61 +func UintPtrs(vals []uint) []*uint {
     62 + ptrs := make([]*uint, len(vals))
     63 + for i := 0; i < len(vals); i++ {
     64 + ptrs[i] = &vals[i]
     65 + }
     66 + return ptrs
     67 +}
     68 + 
     69 +func Uint64Ptrs(vals []uint64) []*uint64 {
     70 + ptrs := make([]*uint64, len(vals))
     71 + for i := 0; i < len(vals); i++ {
     72 + ptrs[i] = &vals[i]
     73 + }
     74 + return ptrs
     75 +}
     76 + 
     77 +func Float64Ptrs(vals []float64) []*float64 {
     78 + ptrs := make([]*float64, len(vals))
     79 + for i := 0; i < len(vals); i++ {
     80 + ptrs[i] = &vals[i]
     81 + }
     82 + return ptrs
     83 +}
     84 + 
     85 +func BoolPtrs(vals []bool) []*bool {
     86 + ptrs := make([]*bool, len(vals))
     87 + for i := 0; i < len(vals); i++ {
     88 + ptrs[i] = &vals[i]
     89 + }
     90 + return ptrs
     91 +}
     92 + 
     93 +func StringPtrs(vals []string) []*string {
     94 + ptrs := make([]*string, len(vals))
     95 + for i := 0; i < len(vals); i++ {
     96 + ptrs[i] = &vals[i]
     97 + }
     98 + return ptrs
     99 +}
     100 + 
     101 +func PtrInt32(v interface{}) int32 {
     102 + if v != nil {
     103 + switch cast := v.(type) {
     104 + case *int:
     105 + return int32(*cast)
     106 + case *int32:
     107 + return *cast
     108 + case *int64:
     109 + return int32(*cast)
     110 + }
     111 + }
     112 + return 0
     113 +}
     114 + 
  • ■ ■ ■ ■ ■ ■
    pkg/tunnel/tunnel.go
    skipped 23 lines
    24 24   
    25 25  const (
    26 26   NULL = "unknown"
    27  - WST = "websocket-tunnel"
    28  - GRT = "grpc-tunnel"
     27 + WST = "websocket"
     28 + GRT = "grpc"
    29 29  )
    30 30   
    31 31  var tpMaps = map[Type]string{
    skipped 24 lines
Please wait...
Page is in error, reload to recover