diff --git "a/.github/ISSUE_TEMPLATE/bug--\347\263\273\347\273\237\345\207\272\347\216\260\345\274\202\345\270\270.md" "b/.github/ISSUE_TEMPLATE/bug--\347\263\273\347\273\237\345\207\272\347\216\260\345\274\202\345\270\270.md" index 1bc24ec..40d02e4 100644 --- "a/.github/ISSUE_TEMPLATE/bug--\347\263\273\347\273\237\345\207\272\347\216\260\345\274\202\345\270\270.md" +++ "b/.github/ISSUE_TEMPLATE/bug--\347\263\273\347\273\237\345\207\272\347\216\260\345\274\202\345\270\270.md" @@ -14,17 +14,11 @@ assignees: DVKunion **问题描述** -**如何复现** -复现步骤如下: -1. xxxxxx -2. xxxxxx -3. xxxxxx -4. xxxxxxx +**复现步骤** **预期的结果** **截图** -注意隐私信息 **其他信息** + Seamoon版本: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c5979dd..4323e1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.21 + go-version: 1.22 id: go - name: Run GoReleaser uses: goreleaser/goreleaser-action@v5 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6160eb5..6e1352d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,36 @@ # CHANGELOG + +## SeaMoon 2.1.0 + +这个版本开始,seamoon 不再追求过于底层的网络思考了。开始回归初心,接入 + 适配常用且有用的工具了。 + +网络层的架构从原本的手写协议,经过多个模块的参考和历史的一些故事,最终还是选择了 xray-core 作为了 seamoon 的网络层核心。不再花过多的时间去适配各种各样的协议和手写加解密相关、线程并发相关的东西了。 + +开发确实是一门艺术,需要深练更多的基本功才行,现阶段作者的代码能力完全不及成熟的网络工具,对 buffer 的操作和把控很容易出各种问题。 + +因此,最终还是舍弃了原始的网络层字节操作,直接引入应用级别的依赖,来解决和实现需要去做的事情。 + +不过 seamoon 的定位一开始就是:"月出于云而引于海", 所以后续将引入更多的工具类型的代码进来,更多的去实现场景和应用需求。 不再挖过于底层的东西了,收益过低且能力不足 QAQ。 + +当然,手写网络层的这段历史的版本加固了对网络协议和 tcp 的理解,对于个人而言,收益还是很大的。只是不再适合这个产品了。 + +## SeaMoon 2.0.1 + +2.0.1 主要解决腾讯云的更新问题,以及一些其他的小修复 + +## ❤️ What's New +* 🔧 fix: 修正了 ci 打包时没有带上 commit 信息的问题 +* 🔧 fix:修正了一处编译错误 +* 🔧 fix:修复腾讯云弃用 api_gw 导致的触发器失败问题 +* 📝 chore:license 更新 + +### What's Changed +* 99adf1a fix: change tecent api_gw to http sfc url (#92) +* e933b3f fix: ci && structure changes (#85) +* 6910fe3 fix: compile error (#86) + +**Full Changelog**: https://github.com/DVKunion/SeaMoon/compare/2.0.0...2.0.1 + ## SeaMoon 2.0.0 2.0.0 版本终于算是完成了一个小的里程碑,打出来第一个版本,在稳定性和使用上可能还是有一定的问题,预计在几个版本内实现fix。 diff --git a/README.md b/README.md index 01bbbab..fb86414 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Serverless 的动态实例不同的出口IP,从而获取到了干净(非威胁 | Vmess | []() | ✅ | ✅ | | Vless | []() | ✅ | ✅ | | shadowsocks | []() | ✅ | ✅ | + | **网络隧道** @@ -57,6 +58,12 @@ Serverless 的动态实例不同的出口IP,从而获取到了干净(非威胁 | grpc | []() | ✅ | | oss | []() | 🐷调研中 | + +**代理模式** ++ 正向代理 ++ 反向代理 ++ 端口转发 + **其他** + 💻 多客户端支持,clash/shadowrocket 等。 @@ -105,9 +112,3 @@ Serverless 的动态实例不同的出口IP,从而获取到了干净(非威胁 本工具仅用于学习serverless以及云原生相关技术,请勿用于其他用途。 如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。 - -## ✨ CTStack - - - -SeaMoon 现已加入 [CTStack](https://stack.chaitin.com/tool/detail?id=186) 社区 diff --git a/cmd/client/client.go b/cmd/client/client.go index 0b810f0..464835c 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -15,13 +15,20 @@ import ( "github.com/DVKunion/SeaMoon/cmd/client/static" "github.com/DVKunion/SeaMoon/pkg/api/service" "github.com/DVKunion/SeaMoon/pkg/api/signal" + "github.com/DVKunion/SeaMoon/pkg/system/errors" "github.com/DVKunion/SeaMoon/pkg/system/version" "github.com/DVKunion/SeaMoon/pkg/system/xlog" + "github.com/DVKunion/SeaMoon/plugins/xray" + "github.com/DVKunion/SeaMoon/plugins/xray/config" + + _ "github.com/xtls/xray-core/main/distro/all" ) func Serve(ctx context.Context, debug bool) { // Signal 异步服务 runSignal(ctx) + // Xray API 服务 + runXray() // Restful API 服务 runApi(ctx, debug) } @@ -38,6 +45,43 @@ func runSignal(ctx context.Context) { signal.Signal().Recover(ctx, rec.Value) } +func runXray() { + xServe, err := xray.StartServer( + // 日志 + config.WithLogs("Debug"), + // 策略 + config.WithDefaultPolicy(), + // 开启 API 控制 + config.WithApiConfig(), + // 开启默认出站:freedom + config.WithFreedomOutbound(), + // 开启 流量统计 + config.WithInboundCalculate(), + config.WithOutboundCalculate(), + ) + if err != nil { + xlog.Error("xray failed to start", "err", err.Error()) + // Configuration error. Exit with a special value to prevent systemd from restarting. + return + } + // copy + if err := xServe.Start(); err != nil { + xlog.Error("xray failed to start", "err", err.Error()) + return + } + //defer xServe.Close() + + /* + conf.FileCache = nil + conf.IPCache = nil + conf.SiteCache = nil + */ + + //// Explicitly triggering GC to remove garbage from config loading. + //runtime.GC() + //debug.FreeOSMemory() +} + func runApi(ctx context.Context, debug bool) { logPath, err := service.SVC.GetConfigByName(ctx, "control_log") addr, err := service.SVC.GetConfigByName(ctx, "control_addr") @@ -51,9 +95,9 @@ func runApi(ctx context.Context, debug bool) { webLogger, err := os.OpenFile(logPath.Value, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { - gin.DefaultWriter = io.MultiWriter(xlog.Logger()) + gin.DefaultWriter = io.MultiWriter(xlog.GetLogger()) } else { - gin.DefaultWriter = io.MultiWriter(xlog.Logger(), webLogger) + gin.DefaultWriter = io.MultiWriter(xlog.GetLogger(), webLogger) } server := gin.Default() @@ -70,7 +114,7 @@ func runApi(ctx context.Context, debug bool) { c.FileFromFS(c.Request.URL.Path, http.FS(subFS)) }) - if err := server.Run(strings.Join([]string{addr.Value, port.Value}, ":")); err != http.ErrServerClosed { + if err := server.Run(strings.Join([]string{addr.Value, port.Value}, ":")); !errors.Is(err, http.ErrServerClosed) { xlog.Error(xlog.ApiServeError, "err", err) } } diff --git a/cmd/main.go b/cmd/main.go index 00a3798..f01a984 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,6 +9,7 @@ import ( "github.com/DVKunion/SeaMoon/cmd/client" "github.com/DVKunion/SeaMoon/cmd/server" "github.com/DVKunion/SeaMoon/pkg/api/database/drivers" + "github.com/DVKunion/SeaMoon/pkg/api/service" "github.com/DVKunion/SeaMoon/pkg/system/version" ) @@ -25,7 +26,7 @@ var ( serverCommand = &cobra.Command{ Use: "server", Short: "SeaMoon server mod", - RunE: Server, + RunE: serve, } clientCommand = &cobra.Command{ @@ -36,13 +37,23 @@ var ( clientWebCommand = &cobra.Command{ Use: "web", Short: "SeaMoon client web mod", - Run: Client, + Run: webClient, + } + + clientCliCommand = &cobra.Command{ + Use: "cli", + Short: "SeaMoon client cli mod", + Run: cliClient, } generateCommand = &cobra.Command{ Use: "generate", Short: "SeaMoon generate devs code", - RunE: drivers.Drive().Generate, + RunE: func(cmd *cobra.Command, args []string) error { + service.Init() + drivers.Init() + return drivers.Drive().Generate() + }, } versionCommand = &cobra.Command{ @@ -52,28 +63,26 @@ var ( fmt.Println("SeaMoon Powered By DVK") fmt.Printf("Version: %s\n", version.Version) fmt.Printf("Commit: %s\n", version.Commit) - fmt.Printf("V2rayCoreVersion: %s\n", version.V2rayCoreVersion) + fmt.Printf("XrayVersion: %s\n", version.XrayVersion) }, } ) -func Client(cmd *cobra.Command, args []string) { +func webClient(cmd *cobra.Command, args []string) { + // 先初始化 db 服务 + service.Init() + // 初始化 db drivers.Init() client.Serve(cmd.Context(), debug) } -func Server(cmd *cobra.Command, args []string) error { - s, err := server.New( - server.WithHost("0.0.0.0"), - server.WithPort(port), - server.WithProto(proto), - ) - - if err != nil { - return err - } +// sometimes we just want a simple cli tools +func cliClient(cmd *cobra.Command, args []string) { + // todo +} - return s.Serve(cmd.Context()) +func serve(cmd *cobra.Command, args []string) error { + return server.Serve(cmd.Context(), "") } func init() { @@ -81,6 +90,7 @@ func init() { serverCommand.Flags().StringVarP(&addr, "addr", "a", "0.0.0.0", "server listen addr") serverCommand.Flags().StringVarP(&port, "port", "p", "9000", "server listen port") + serverCommand.Flags().StringVarP(&proto, "proto", "t", "websocket", "server listen proto: (websocket/grpc)") rootCommand.AddCommand(versionCommand) @@ -89,6 +99,7 @@ func init() { rootCommand.AddCommand(generateCommand) clientCommand.AddCommand(clientWebCommand) + clientCommand.AddCommand(clientCliCommand) } func main() { diff --git a/cmd/server/options.go b/cmd/server/options.go deleted file mode 100644 index 4c8742a..0000000 --- a/cmd/server/options.go +++ /dev/null @@ -1,47 +0,0 @@ -package server - -import ( - "github.com/DVKunion/SeaMoon/pkg/api/enum" -) - -type Options struct { - host string // 监听地址 - port string // 监听端口 - proto enum.TunnelType // 监听协议 - - mtcp bool // -} - -type Option func(o *Options) (err error) - -func WithHost(host string) Option { - return func(o *Options) (err error) { - o.host = host - return - } -} - -func WithPort(port string) Option { - return func(o *Options) (err error) { - o.port = port - return - } -} - -func WithProto(t string) Option { - return func(o *Options) (err error) { - tt := enum.TransTunnelType(t) - if tt == enum.TunnelTypeNULL { - // todo - } - o.proto = tt - return nil - } -} - -func WithMTcp(flag bool) Option { - return func(o *Options) (err error) { - o.mtcp = flag - return nil - } -} diff --git a/cmd/server/server.go b/cmd/server/server.go deleted file mode 100644 index 39b4d7e..0000000 --- a/cmd/server/server.go +++ /dev/null @@ -1,74 +0,0 @@ -package server - -import ( - "context" - "os" - "strings" - - "github.com/DVKunion/SeaMoon/pkg/network/basic" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel/service" - "github.com/DVKunion/SeaMoon/pkg/system/errors" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -type Server struct { - srv service.Service - opts Options -} - -func New(opts ...Option) (*Server, error) { - s := &Server{} - for _, o := range opts { - err := o(&s.opts) - if err != nil { - return s, err - } - } - // check - if srv, ok := service.Factory.Load(s.opts.proto); ok { - s.srv = srv.(service.Service) - } - - if s.srv == nil { - return s, errors.New("xxxx") - } - - return s, nil -} - -// Serve do common serve -func (s *Server) Serve(ctx context.Context) error { - network := "tcp" - - if basic.IsIPv4(s.opts.host) { - network = "tcp4" - } - - serverAddr := strings.Join(append([]string{s.opts.host, s.opts.port}), ":") - - lc := basic.ListenConfig{} - if s.opts.mtcp { - lc.SetMultipathTCP(true) - } - - ln, err := lc.Listen(ctx, network, serverAddr) - - if err != nil { - return err - } - - xlog.Info(xlog.ApiServerStart, "options", s.opts) - - var srvOpt []service.Option - - srvOpt = append(srvOpt, service.WithAddr(serverAddr)) - srvOpt = append(srvOpt, service.WithUid(os.Getenv("SM_UID"))) - srvOpt = append(srvOpt, service.WithPassword(os.Getenv("SM_SS_PASS"))) - srvOpt = append(srvOpt, service.WithCrypt(os.Getenv("SM_SS_CRYPT"))) - - if err := s.srv.Serve(ln, srvOpt...); err != nil { - xlog.Error(xlog.ServiceError, err) - return err - } - return nil -} diff --git a/cmd/server/xray.go b/cmd/server/xray.go new file mode 100644 index 0000000..57e9068 --- /dev/null +++ b/cmd/server/xray.go @@ -0,0 +1,37 @@ +package server + +import ( + "context" + "fmt" + "os" + "os/signal" + "runtime" + "runtime/debug" + "syscall" + + "github.com/DVKunion/SeaMoon/plugins/xray" +) + +// Serve do common serve +func Serve(ctx context.Context, url string) error { + server, err := xray.StartServer() + if err != nil { + fmt.Println("Failed to start:", err) + // Configuration error. Exit with a special value to prevent systemd from restarting. + os.Exit(23) + } + if err := server.Start(); err != nil { + fmt.Println("Failed to start:", err) + os.Exit(-1) + } + defer server.Close() + runtime.GC() + debug.FreeOSMemory() + + { + osSignals := make(chan os.Signal, 1) + signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) + <-osSignals + } + return nil +} diff --git a/docs/package.json b/docs/package.json index e2cbf67..285e080 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,6 @@ { - "name": "SeaMoon", - "version": "1.2.0-beta", + "name": "seamoon", + "version": "2.0.1", "main": "index.js", "license": "MIT", "repository": "https://github.com/DVKunion/SeaMoon", diff --git "a/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/00.position.md" "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/00.position.md" index de31062..41b0f05 100644 --- "a/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/00.position.md" +++ "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/00.position.md" @@ -8,6 +8,7 @@ article: false # Position ## 一些想法上的改动 + 随着版本的迭代,月海已经与我最初的雏形完全偏离 diff --git "a/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/02.refactor.md" "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/02.refactor.md" new file mode 100644 index 0000000..bb53be9 --- /dev/null +++ "b/docs/tech/00.\345\206\231\345\234\250\345\211\215\351\235\242/02.refactor.md" @@ -0,0 +1,11 @@ +--- +title: 2.0.0 版本小记 +date: 2024-04-02 17:59:12 +permalink: /tech/2.0.0/ +article: false +--- + +# 2.0.0 版本小记 + +从 1.0 到 2.0 的过程中,发生了不少好玩的事情。 + diff --git "a/docs/tech/01.\347\275\221\347\273\234/01.HTTP.md" "b/docs/tech/01.\347\275\221\347\273\234/01.HTTP.md" index 7f267f6..355c6c3 100644 --- "a/docs/tech/01.\347\275\221\347\273\234/01.HTTP.md" +++ "b/docs/tech/01.\347\275\221\347\273\234/01.HTTP.md" @@ -4,6 +4,7 @@ date: 2022-08-30 19:47:20 permalink: /tech/net/http/ article: false --- + # HTTP HTTP代理 涉及了三个问题。 @@ -58,7 +59,7 @@ HTTP代理 涉及了三个问题。 那么问题就变成了,如何信任我们的client端,参照大多proxy和burp的模式,可以通过信任根路径的证书来解决这个问题。 -可以参考这篇文章 +可以参考这篇文章 [实现基于 HTTPS 代理的中间人攻击](https://www.lyyyuna.com/2018/03/16/http-proxy-https/) @@ -75,3 +76,4 @@ HTTPS 迎刃而解。 这和现有的一些工具逻辑完全一致。 但是在测试时,很容易出现:`http redirect request` 、 js/css加载失败或直接失效的场景,这相比socks5的舒适度差了一大截。 因此,基于完美主义,后续将会重构一版底层net转发的逻辑。 + diff --git "a/docs/tech/01.\347\275\221\347\273\234/03.\345\244\232\350\267\257\345\244\215\347\224\250.md" "b/docs/tech/01.\347\275\221\347\273\234/03.\345\244\232\350\267\257\345\244\215\347\224\250.md" new file mode 100644 index 0000000..761cb55 --- /dev/null +++ "b/docs/tech/01.\347\275\221\347\273\234/03.\345\244\232\350\267\257\345\244\215\347\224\250.md" @@ -0,0 +1,7 @@ +--- +title: 多路复用 +date: 2024-01-13 +permalink: /tech/net/smux/ +article: false +--- + diff --git "a/docs/tech/01.\347\275\221\347\273\234/03.\346\234\215\345\212\241\347\251\277\351\200\217.md" "b/docs/tech/01.\347\275\221\347\273\234/03.\346\234\215\345\212\241\347\251\277\351\200\217.md" new file mode 100644 index 0000000..5036fbe --- /dev/null +++ "b/docs/tech/01.\347\275\221\347\273\234/03.\346\234\215\345\212\241\347\251\277\351\200\217.md" @@ -0,0 +1,64 @@ +--- +title: 内网穿透 +date: 2022-08-30 19:47:32 +permalink: /tech/net/forward/ +article: false +--- + +# 内网穿透、反向代理、端口转发 + +> 这个功能其实考虑了很久,我在思考:对于一些已有的功能和工具,如果能够满足需求的话,为什么要重新写一套呢? + +因此, + +## 内网穿透 + +先聊一下什么是内网穿透。 + +> 内网穿透是一种技术,它允许从互联网上的设备访问位于内网(例如家庭或企业网络)中的服务或设备。通常,内网中的设备对互联网上的其他设备不可见,因为它们是通过NAT(网络地址转换)和防火墙保护的。内网穿透技术通过在内网设备和外部服务器之间建立一个通信隧道来克服这个限制。 +> 这个通信隧道允许外部设备通过这个设立好的连接来访问内网中的服务,好像它们直接连接到互联网一样。这对于需要远程访问内部网络资源的场景特别有用,比如远程办公、家庭自动化、远程监控系统等。 +> (From ChatGPT) + +简单的总结一下就是, 对于被封闭在 NAT 后面的服务(如没有公网 IP 的家庭主机), 可以通过建立起独立的通信信道来实现远程访问内部的网络资源(如 +ssh、rdp 等服务) + +内网穿透可以通过多种方式实现, 如: + ++ 反向代理 ++ VPN,实际上也是一种内网穿透的手段。 ++ ... + +目前大部分的实现都是基于反向代理做的端口转发来实现的,后面将详细分析常见的产品实现代码。 + +## 反向代理 + +> 看到一个很好的总结: +> 正向代理中,proxy和client同属一个lan,对server透明 +> 反向代理中,proxy和server同属一个lan,对server透明 + +### 前情提要 + +抛开已有的产品实现以及之前的一些思路,现在我们的场景是:如何通过云函数来做一个内网穿透工具? + +在搭建虚拟机测试时,如果连接的网络需要 802.1x 认证,此时如果每台虚拟机都去配置这个认证的话,将会非常的麻烦(不同 os 配置不同)。 + +因此,我们在虚拟机上实现了一个简易的 NAT 转发功能:802.1x 证书认证在 pve 物理机上进行配置,然后通过 iptables 实现一条 NAT rules: 将来源于 192.168.1.1/24 (内部网络) 的流量全部转发到认证的网卡上。 + +由此,所有的虚拟机都可以通过物理机访问外部网络了,这也是常见的家庭网络基础 NAT 模式。 + +但是这样的配置也出现了一个问题:虚拟机可以出,但是无法对外提供服务,因为提供的服务 IP 都是这内部 192 网段,外部机器没有访问到这个网络的方法。 + +我常用的方式便是,通过 nginx 在物理机上部署一个反向代理,通过 stream 快速暴露内部服务;这便是反向代理的基础场景。 + +### 原理实现 + +那我们该如何实现一个 + + + +## 端口转发 + + +## 参考链接 + +> https://www.cnblogs.com/paidx0/p/13975124.html \ No newline at end of file diff --git "a/docs/tech/01.\347\275\221\347\273\234/04.V2ray.md" "b/docs/tech/01.\347\275\221\347\273\234/04.V2ray.md" new file mode 100644 index 0000000..662547a --- /dev/null +++ "b/docs/tech/01.\347\275\221\347\273\234/04.V2ray.md" @@ -0,0 +1,30 @@ +--- +title: V2ray +date: 2024-04-02 11:08:21 +permalink: /pages/8bdd3c/ +article: false +--- + +## 方案 + +1. 直接导入了 v2ray 核心裤 的 server +2. debug 打入 client.config 构造独立的client +3. 自己直接实现协议 + + +## + +```golang +func InitV2rayServer(port uint32, id, pass, crypt string, tp enum.TunnelType, tor bool, tls bool) error { + config, err := renderServerConfig(port, id, pass, crypt, tp, tor, tls) + if err != nil { + return err + } + v2ray, err = core.New(config) + if err != nil { + return err + } + return nil +} +``` + diff --git "a/docs/tech/01.\347\275\221\347\273\234/04.gost\345\210\206\346\236\220\347\240\224\347\251\266.md" "b/docs/tech/01.\347\275\221\347\273\234/04.gost\345\210\206\346\236\220\347\240\224\347\251\266.md" new file mode 100644 index 0000000..840f981 --- /dev/null +++ "b/docs/tech/01.\347\275\221\347\273\234/04.gost\345\210\206\346\236\220\347\240\224\347\251\266.md" @@ -0,0 +1,38 @@ +--- +title: gost 的研究 +date: 2022-08-30 19:47:32 +permalink: /tech/net/gost/ +article: false +--- + +# 概念理解 + +## Service + +每个服务包含一个监听器(Listener)和一个处理器(Handler)。 + +理解为入站。 + +## Node + +每个节点包含一个拨号器(Dialer)和一个连接器(Connector)。 + +## 监听器(Listener) +监听器在本地打开指定的端口,负责数据的收发及数据通道的建立和初始化工作(例如加解密,会话和数据流通道初始化等),与客户端进行直接的数据交互。 + +## 处理器(Handler) +处理器是监听器上的一个逻辑抽象层,当监听器建立好数据通道之后,客户端的实际请求数据会交给处理器进行处理,其中包括路由判断,域名解析,权限控制等处理逻辑。 + + +## 主要流程 + + accept() dial() +Listener -------------> Handler --------> Route -------> Dialer -----------> HandShake -----> Connector + | | | | + ------- service ------ --------- node ------- + +## 缺陷 ++ 有些臃肿、启动速度慢。 ++ 多余功能不太需要,如 post-up 这种带有危险 exec 行为的地方,一旦开始集成以后很容易忘记导致配置错误的 rce 注入。 ++ 认证部分在函数场景可以通过触发器来实现,比网络请求的auth更实惠好用(因为403不计费)。 ++ 没有版本控制(最开始想引用core....但是没tag,有点慌,最终还是算了) \ No newline at end of file diff --git a/go.mod b/go.mod index bb0ed0e..4955cde 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/DVKunion/SeaMoon -go 1.21 +go 1.22 require ( github.com/alibabacloud-go/bssopenapi-20171214/v3 v3.2.2 @@ -8,21 +8,22 @@ require ( github.com/alibabacloud-go/tea v1.2.1 github.com/alibabacloud-go/tea-utils/v2 v2.0.4 github.com/aliyun/fc-go-sdk v0.0.0-20230313060359-3a1b2ede1e1e + github.com/djherbis/times v1.6.0 github.com/gin-gonic/gin v1.9.1 github.com/glebarez/sqlite v1.10.0 github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 - github.com/gorilla/websocket v1.5.1 github.com/pkg/errors v0.9.1 github.com/showwin/speedtest-go v1.6.10 github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.9.0 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.866 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.866 - github.com/v2fly/v2ray-core/v5 v5.16.1 - google.golang.org/grpc v1.63.2 - google.golang.org/protobuf v1.34.0 + github.com/xtls/xray-core v1.8.21 + google.golang.org/grpc v1.65.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/gen v0.3.25 gorm.io/gorm v1.25.5 @@ -33,7 +34,7 @@ require ( ) require ( - github.com/adrg/xdg v0.4.0 // indirect + github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 // indirect github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect @@ -41,19 +42,21 @@ require ( github.com/alibabacloud-go/tea-utils v1.3.1 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/aliyun/credentials-go v1.3.1 // indirect - github.com/bufbuild/protocompile v0.10.0 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/clbanning/mxj/v2 v2.5.5 // indirect + github.com/cloudflare/circl v1.3.9 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -61,64 +64,71 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect - github.com/google/uuid v1.6.0 // indirect + github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect + github.com/gopherjs/gopherjs v0.0.0-20210420193930-a4630ec28c79 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/imdario/mergo v0.3.6 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jhump/protoreflect v1.16.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.13.0 // indirect + github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pion/transport/v2 v2.2.5 // indirect github.com/pires/go-proxyproto v0.7.0 // indirect - github.com/quic-go/quic-go v0.43.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/quic-go v0.45.1 // indirect + github.com/refraction-networking/utls v1.6.7 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect + github.com/sagernet/sing v0.4.1 // indirect + github.com/sagernet/sing-shadowsocks v0.2.7 // indirect + github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tjfoc/gmsm v1.3.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - github.com/v2fly/BrowserBridge v0.0.0-20210430233438-0570fc1d7d08 // indirect - github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848 // indirect github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect + github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect + github.com/vishvananda/netns v0.0.4 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - github.com/xtaci/smux v1.5.24 // indirect - go.starlark.net v0.0.0-20230612165344-9532f5667272 // indirect + github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect go.uber.org/mock v0.4.0 // indirect - go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/crypto v0.25.0 // indirect + golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.20.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.19.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + golang.org/x/tools v0.22.0 // indirect + golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect + golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.56.0 // indirect gopkg.in/resty.v1 v1.12.0 // indirect @@ -126,6 +136,7 @@ require ( gorm.io/datatypes v1.1.1-0.20230130040222-c43177d3cf8c // indirect gorm.io/driver/mysql v1.5.2 // indirect gorm.io/hints v1.1.0 // indirect + gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect k8s.io/klog/v2 v2.110.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect diff --git a/go.sum b/go.sum index 97edc86..66343a4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= @@ -10,18 +12,19 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DVKunion/fc-go-sdk v0.0.0-20240229064818-0899a1e1bf52 h1:RAsZRNTN5IK7osUzHL/IdgUeGPHwDG9aFTGj/HFcqzI= github.com/DVKunion/fc-go-sdk v0.0.0-20240229064818-0899a1e1bf52/go.mod h1:rYnxfOnoHRZ2QGKREUOESel1hmRe0frzF2RLpcDVtTU= +github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 h1:Wo41lDOevRJSGpevP+8Pk5bANX7fJacO2w04aqLiC5I= +github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0/go.mod h1:FVGavL/QEBQDcBpr3fAojoK17xX5k9bicBphrOpP7uM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= -github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= -github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 h1:+JkXLHME8vLJafGhOH4aoV2Iu8bR55nU6iKMVfYVLjY= -github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1/go.mod h1:nuudZmJhzWtx2212z+pkuy7B6nkBqa+xwNXZHL1j8cg= -github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= @@ -51,8 +54,9 @@ github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/xWDTE28= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= -github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= -github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -60,29 +64,24 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d h1:zsO4lp+bjv5XvPTF58Vq+qgmZEYZttJK+CWtSZhKenI= -github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d/go.mod h1:f1iKL6ZhUWvbk7PdWVmOaak10o86cqMUYEmn1CZNGEI= -github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= -github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE= +github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -96,20 +95,24 @@ github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fp github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a h1:YtdtTUN1iH97s+6PUjLnaiKSQj4oG1/EZ3N9bx6g4kU= -github.com/ebfe/bcrypt_pbkdf v0.0.0-20140212075826-3c8d2dcb253a/go.mod h1:/CZpbhAusDOobpcb9yubw46kdYjq0zRC0Wpg9a9zFQM= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= +github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= @@ -118,16 +121,15 @@ github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9g github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= -github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= -github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -146,8 +148,8 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -162,22 +164,15 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -188,27 +183,25 @@ github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvR github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs= -github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= @@ -217,12 +210,13 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20210420193930-a4630ec28c79 h1:ATVz3rDvK4xX0nHx57zYSHRVIK/+lFwln9KJr8wvuk0= github.com/gopherjs/gopherjs v0.0.0-20210420193930-a4630ec28c79/go.mod h1:Opf9rtYVq0eTyX+aRVmRO9hE8ERAozcdrBxWG9Q6mkQ= -github.com/gopherjs/websocket v0.0.0-20191103002815-9a42957e2b3a/go.mod h1:jd+zY81Fx2lC4bfw58+Rflg1srqmedQjbBUejKOjYNY= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -265,8 +259,7 @@ github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= -github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -287,13 +280,11 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/klauspost/reedsolomon v1.11.7 h1:9uaHU0slncktTEEg4+7Vl7q7XUNMBUOK4R9gnKhMjAU= -github.com/klauspost/reedsolomon v1.11.7/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -301,14 +292,15 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -319,11 +311,12 @@ github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= -github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -341,37 +334,23 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mustafaturan/bus v1.0.2 h1:2x3ErwZ0uUPwwZ5ZZoknEQprdaxr68Yl3mY8jDye1Ws= -github.com/mustafaturan/bus v1.0.2/go.mod h1:h7gfehm8TThv4Dcaa+wDQG7r7j6p74v+7ftr0Rq9i1Q= -github.com/mustafaturan/monoton v1.0.0 h1:8SCej+JiNn0lyps7V+Jzc1CRAkDR4EZPWrTupQ61YCQ= -github.com/mustafaturan/monoton v1.0.0/go.mod h1:FOnE7NV3s3EWPXb8/7+/OSdiMBbdlkV0Lz8p1dc+vy8= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= -github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= -github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw= -github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU= -github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= -github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs= github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -381,20 +360,24 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quic-go/quic-go v0.43.0 h1:sjtsTKWX0dsHpuMJvLxGqoQdtgJnbAPWY+W+5vjYW/g= -github.com/quic-go/quic-go v0.43.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= -github.com/refraction-networking/utls v1.6.5 h1:Jlfqgs/t1Uy6FHHQ8Fz9ZTrRmP/zS7d/NZw7BLahaL8= -github.com/refraction-networking/utls v1.6.5/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= +github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= +github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= +github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA= +github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= +github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -404,19 +387,45 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk= +github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= +github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= +github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/secure-io/siv-go v0.0.0-20180922214919-5ff40651e2c4 h1:zOjq+1/uLzn/Xo40stbvjIY/yehG0+mfmlsiEmc0xmQ= -github.com/secure-io/siv-go v0.0.0-20180922214919-5ff40651e2c4/go.mod h1:aI+8yClBW+1uovkHw6HM01YXnYB8vohtB9C83wzx34E= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= +github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4= +github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/showwin/speedtest-go v1.6.10 h1:dPxr1gVOu30KvMNl2L8UZD937Ge7zsZW0JulzYpyP48= github.com/showwin/speedtest-go v1.6.10/go.mod h1:uLgdWCNarXxlYsL2E5TOZpCIwpgSWnEANZp7gfHXHu0= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= @@ -424,6 +433,8 @@ github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -449,10 +460,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866 h1:GB1M0t/+jiJET18SBH8ZS9cRax/s7G6R5DD8djGVV54= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/billing v1.0.866/go.mod h1:q3z5hNxMu2l9uXR7S8oHQMzlu/Be0GtXaML8dOWG77Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cam v1.0.866 h1:xTBIyd52OUpCDgtsujz7+kiUyz/AP/LweYhS2WoV8AM= @@ -468,46 +479,47 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/v2fly/BrowserBridge v0.0.0-20210430233438-0570fc1d7d08 h1:4Yh46CVE3k/lPq6hUbEdbB1u1anRBXLewm3k+L0iOMc= -github.com/v2fly/BrowserBridge v0.0.0-20210430233438-0570fc1d7d08/go.mod h1:KAuQNm+LWQCOFqdBcUgihPzRpVXRKzGbTNhfEfRZ4wY= -github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848 h1:p1UzXK6VAutXFFQMnre66h7g1BjRKUnLv0HfmmRoz7w= -github.com/v2fly/VSign v0.0.0-20201108000810-e2adc24bf848/go.mod h1:p80Bv154ZtrGpXMN15slDCqc9UGmfBuUzheDFBYaW/M= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU= -github.com/v2fly/v2ray-core/v5 v5.16.1 h1:hIuRzCJhmRYqCA76hGiNLkAHopgbNt91L871wlJ/yUU= -github.com/v2fly/v2ray-core/v5 v5.16.1/go.mod h1:3pWIBTmNagMKpzd9/QicXq/7JZCQt716GsGZdBNmYkU= -github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI= -github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U= +github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= +github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 h1:tkMT5pTye+1NlKIXETU78NXw0fyjnaNHmJyyLyzw8+U= +github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3/go.mod h1:cAAsePK2e15YDAMJNyOpGYEWNe4sIghTY7gpz4cX/Ik= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xiaokangwang/VLite v0.0.0-20220418190619-cff95160a432 h1:I/ATawgO2RerCq9ACwL0wBB8xNXZdE3J+93MCEHReRs= -github.com/xiaokangwang/VLite v0.0.0-20220418190619-cff95160a432/go.mod h1:QN7Go2ftTVfx0aCTh9RXHV8pkpi0FtmbwQw40dy61wQ= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -github.com/xtaci/smux v1.5.15/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= -github.com/xtaci/smux v1.5.24 h1:77emW9dtnOxxOQ5ltR+8BbsX1kzcOxQ5gB+aaV9hXOY= -github.com/xtaci/smux v1.5.24/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= +github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg= +github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE= +github.com/xtls/xray-core v1.8.21 h1:cNdepud+R9PENKzXlSZsq0je4BWI6liXAuep6CD6xvk= +github.com/xtls/xray-core v1.8.21/go.mod h1:0CwyMPNA5Cs+ukPXHbYQGgne/ug0PuXOSVqBu7zyXOc= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.starlark.net v0.0.0-20230612165344-9532f5667272 h1:2/wtqS591wZyD2OsClsVBKRPEvBsQt/Js+fsCiYhwu8= -go.starlark.net v0.0.0-20230612165344-9532f5667272/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 h1:nJAwRlGWZZDOD+6wni9KVUNHMpHko/OnRwsrCYeAzPo= -go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -517,18 +529,18 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= -golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= +golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -544,17 +556,21 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -569,14 +585,16 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -592,17 +610,21 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -610,44 +632,42 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -656,7 +676,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -671,24 +690,35 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -697,28 +727,18 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= -google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -770,12 +790,13 @@ gorm.io/hints v1.1.0 h1:Lp4z3rxREufSdxn4qmkK3TLDltrM10FLTHiuqwDPvXw= gorm.io/hints v1.1.0/go.mod h1:lKQ0JjySsPBj3uslFzY3JhYDtqEwzm+G1hv8rWujB6Y= gorm.io/plugin/dbresolver v1.5.0 h1:XVHLxh775eP0CqVh3vcfJtYqja3uFl5Wr3cKlY8jgDY= gorm.io/plugin/dbresolver v1.5.0/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= -gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1 h1:qDCwdCWECGnwQSQC01Dpnp09fRHxJs9PbktotUqG+hs= -gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1/go.mod h1:8hmigyCdYtw5xJGfQDJzSH5Ju8XEIDBnpyi8+O6GRt8= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 h1:ze1vwAdliUAr68RQ5NtufWaXaOg8WUO2OACzEV+TNdE= +gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489/go.mod h1:10sU+Uh5KKNv1+2x2A0Gvzt8FjD3ASIhorV3YsauXhk= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= @@ -807,3 +828,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+s sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/pkg/api/controller/middleware/jwt.go b/pkg/api/controller/middleware/jwt.go index 1f68d3e..c6f6c06 100644 --- a/pkg/api/controller/middleware/jwt.go +++ b/pkg/api/controller/middleware/jwt.go @@ -38,7 +38,7 @@ func JWTAuthMiddleware(c *gin.Context) { if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { // 校验通过 - if cast, ok := claims["type"].(float64); ok && enum.AuthType(cast) == enum.AuthAdmin { + if cast, ok := claims["type"].(float64); ok && enum.AuthType(cast) == enum.AdminAuth { c.Next() return } diff --git a/pkg/api/controller/v1/auth.go b/pkg/api/controller/v1/auth.go index b1e2b34..458daea 100644 --- a/pkg/api/controller/v1/auth.go +++ b/pkg/api/controller/v1/auth.go @@ -13,7 +13,7 @@ import ( ) func Login(c *gin.Context) { - var obj *models.AuthApi + var obj *models.Account if err := c.ShouldBindJSON(&obj); err != nil { servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(xlog.ApiParamsError, err)) return @@ -27,7 +27,7 @@ func Login(c *gin.Context) { } func Passwd(c *gin.Context) { - var obj *models.AuthApi + var obj *models.Account if err := c.ShouldBindJSON(&obj); err != nil { servant.ErrorMsg(c, http.StatusBadRequest, errors.ApiError(xlog.ApiParamsError, err)) return diff --git a/pkg/api/database/dao/accounts.gen.go b/pkg/api/database/dao/accounts.gen.go new file mode 100644 index 0000000..8292643 --- /dev/null +++ b/pkg/api/database/dao/accounts.gen.go @@ -0,0 +1,411 @@ +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. +// Code generated by gorm.io/gen. DO NOT EDIT. + +package dao + +import ( + "context" + + "github.com/DVKunion/SeaMoon/pkg/api/models" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/schema" + + "gorm.io/gen" + "gorm.io/gen/field" + + "gorm.io/plugin/dbresolver" +) + +func newAccount(db *gorm.DB, opts ...gen.DOOption) account { + _account := account{} + + _account.accountDo.UseDB(db, opts...) + _account.accountDo.UseModel(&models.Account{}) + + tableName := _account.accountDo.TableName() + _account.ALL = field.NewAsterisk(tableName) + _account.ID = field.NewUint(tableName, "id") + _account.CreatedAt = field.NewTime(tableName, "created_at") + _account.UpdatedAt = field.NewTime(tableName, "updated_at") + _account.DeletedAt = field.NewField(tableName, "deleted_at") + _account.Type = field.NewInt8(tableName, "type") + _account.AuthType = field.NewInt8(tableName, "auth_type") + _account.Data = field.NewString(tableName, "data") + + _account.fillFieldMap() + + return _account +} + +type account struct { + accountDo accountDo + + ALL field.Asterisk + ID field.Uint + CreatedAt field.Time + UpdatedAt field.Time + DeletedAt field.Field + Type field.Int8 + AuthType field.Int8 + Data field.String + + fieldMap map[string]field.Expr +} + +func (a account) Table(newTableName string) *account { + a.accountDo.UseTable(newTableName) + return a.updateTableName(newTableName) +} + +func (a account) As(alias string) *account { + a.accountDo.DO = *(a.accountDo.As(alias).(*gen.DO)) + return a.updateTableName(alias) +} + +func (a *account) updateTableName(table string) *account { + a.ALL = field.NewAsterisk(table) + a.ID = field.NewUint(table, "id") + a.CreatedAt = field.NewTime(table, "created_at") + a.UpdatedAt = field.NewTime(table, "updated_at") + a.DeletedAt = field.NewField(table, "deleted_at") + a.Type = field.NewInt8(table, "type") + a.AuthType = field.NewInt8(table, "auth_type") + a.Data = field.NewString(table, "data") + + a.fillFieldMap() + + return a +} + +func (a *account) WithContext(ctx context.Context) IAccountDo { return a.accountDo.WithContext(ctx) } + +func (a account) TableName() string { return a.accountDo.TableName() } + +func (a account) Alias() string { return a.accountDo.Alias() } + +func (a account) Columns(cols ...field.Expr) gen.Columns { return a.accountDo.Columns(cols...) } + +func (a *account) GetFieldByName(fieldName string) (field.OrderExpr, bool) { + _f, ok := a.fieldMap[fieldName] + if !ok || _f == nil { + return nil, false + } + _oe, ok := _f.(field.OrderExpr) + return _oe, ok +} + +func (a *account) fillFieldMap() { + a.fieldMap = make(map[string]field.Expr, 7) + a.fieldMap["id"] = a.ID + a.fieldMap["created_at"] = a.CreatedAt + a.fieldMap["updated_at"] = a.UpdatedAt + a.fieldMap["deleted_at"] = a.DeletedAt + a.fieldMap["type"] = a.Type + a.fieldMap["auth_type"] = a.AuthType + a.fieldMap["data"] = a.Data +} + +func (a account) clone(db *gorm.DB) account { + a.accountDo.ReplaceConnPool(db.Statement.ConnPool) + return a +} + +func (a account) replaceDB(db *gorm.DB) account { + a.accountDo.ReplaceDB(db) + return a +} + +type accountDo struct{ gen.DO } + +type IAccountDo interface { + gen.SubQuery + Debug() IAccountDo + WithContext(ctx context.Context) IAccountDo + WithResult(fc func(tx gen.Dao)) gen.ResultInfo + ReplaceDB(db *gorm.DB) + ReadDB() IAccountDo + WriteDB() IAccountDo + As(alias string) gen.Dao + Session(config *gorm.Session) IAccountDo + Columns(cols ...field.Expr) gen.Columns + Clauses(conds ...clause.Expression) IAccountDo + Not(conds ...gen.Condition) IAccountDo + Or(conds ...gen.Condition) IAccountDo + Select(conds ...field.Expr) IAccountDo + Where(conds ...gen.Condition) IAccountDo + Order(conds ...field.Expr) IAccountDo + Distinct(cols ...field.Expr) IAccountDo + Omit(cols ...field.Expr) IAccountDo + Join(table schema.Tabler, on ...field.Expr) IAccountDo + LeftJoin(table schema.Tabler, on ...field.Expr) IAccountDo + RightJoin(table schema.Tabler, on ...field.Expr) IAccountDo + Group(cols ...field.Expr) IAccountDo + Having(conds ...gen.Condition) IAccountDo + Limit(limit int) IAccountDo + Offset(offset int) IAccountDo + Count() (count int64, err error) + Scopes(funcs ...func(gen.Dao) gen.Dao) IAccountDo + Unscoped() IAccountDo + Create(values ...*models.Account) error + CreateInBatches(values []*models.Account, batchSize int) error + Save(values ...*models.Account) error + First() (*models.Account, error) + Take() (*models.Account, error) + Last() (*models.Account, error) + Find() ([]*models.Account, error) + FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Account, err error) + FindInBatches(result *[]*models.Account, batchSize int, fc func(tx gen.Dao, batch int) error) error + Pluck(column field.Expr, dest interface{}) error + Delete(...*models.Account) (info gen.ResultInfo, err error) + Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + Updates(value interface{}) (info gen.ResultInfo, err error) + UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) + UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) + UpdateColumns(value interface{}) (info gen.ResultInfo, err error) + UpdateFrom(q gen.SubQuery) gen.Dao + Attrs(attrs ...field.AssignExpr) IAccountDo + Assign(attrs ...field.AssignExpr) IAccountDo + Joins(fields ...field.RelationField) IAccountDo + Preload(fields ...field.RelationField) IAccountDo + FirstOrInit() (*models.Account, error) + FirstOrCreate() (*models.Account, error) + FindByPage(offset int, limit int) (result []*models.Account, count int64, err error) + ScanByPage(result interface{}, offset int, limit int) (count int64, err error) + Scan(result interface{}) (err error) + Returning(value interface{}, columns ...string) IAccountDo + UnderlyingDB() *gorm.DB + schema.Tabler +} + +func (a accountDo) Debug() IAccountDo { + return a.withDO(a.DO.Debug()) +} + +func (a accountDo) WithContext(ctx context.Context) IAccountDo { + return a.withDO(a.DO.WithContext(ctx)) +} + +func (a accountDo) ReadDB() IAccountDo { + return a.Clauses(dbresolver.Read) +} + +func (a accountDo) WriteDB() IAccountDo { + return a.Clauses(dbresolver.Write) +} + +func (a accountDo) Session(config *gorm.Session) IAccountDo { + return a.withDO(a.DO.Session(config)) +} + +func (a accountDo) Clauses(conds ...clause.Expression) IAccountDo { + return a.withDO(a.DO.Clauses(conds...)) +} + +func (a accountDo) Returning(value interface{}, columns ...string) IAccountDo { + return a.withDO(a.DO.Returning(value, columns...)) +} + +func (a accountDo) Not(conds ...gen.Condition) IAccountDo { + return a.withDO(a.DO.Not(conds...)) +} + +func (a accountDo) Or(conds ...gen.Condition) IAccountDo { + return a.withDO(a.DO.Or(conds...)) +} + +func (a accountDo) Select(conds ...field.Expr) IAccountDo { + return a.withDO(a.DO.Select(conds...)) +} + +func (a accountDo) Where(conds ...gen.Condition) IAccountDo { + return a.withDO(a.DO.Where(conds...)) +} + +func (a accountDo) Order(conds ...field.Expr) IAccountDo { + return a.withDO(a.DO.Order(conds...)) +} + +func (a accountDo) Distinct(cols ...field.Expr) IAccountDo { + return a.withDO(a.DO.Distinct(cols...)) +} + +func (a accountDo) Omit(cols ...field.Expr) IAccountDo { + return a.withDO(a.DO.Omit(cols...)) +} + +func (a accountDo) Join(table schema.Tabler, on ...field.Expr) IAccountDo { + return a.withDO(a.DO.Join(table, on...)) +} + +func (a accountDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAccountDo { + return a.withDO(a.DO.LeftJoin(table, on...)) +} + +func (a accountDo) RightJoin(table schema.Tabler, on ...field.Expr) IAccountDo { + return a.withDO(a.DO.RightJoin(table, on...)) +} + +func (a accountDo) Group(cols ...field.Expr) IAccountDo { + return a.withDO(a.DO.Group(cols...)) +} + +func (a accountDo) Having(conds ...gen.Condition) IAccountDo { + return a.withDO(a.DO.Having(conds...)) +} + +func (a accountDo) Limit(limit int) IAccountDo { + return a.withDO(a.DO.Limit(limit)) +} + +func (a accountDo) Offset(offset int) IAccountDo { + return a.withDO(a.DO.Offset(offset)) +} + +func (a accountDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAccountDo { + return a.withDO(a.DO.Scopes(funcs...)) +} + +func (a accountDo) Unscoped() IAccountDo { + return a.withDO(a.DO.Unscoped()) +} + +func (a accountDo) Create(values ...*models.Account) error { + if len(values) == 0 { + return nil + } + return a.DO.Create(values) +} + +func (a accountDo) CreateInBatches(values []*models.Account, batchSize int) error { + return a.DO.CreateInBatches(values, batchSize) +} + +// Save : !!! underlying implementation is different with GORM +// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) +func (a accountDo) Save(values ...*models.Account) error { + if len(values) == 0 { + return nil + } + return a.DO.Save(values) +} + +func (a accountDo) First() (*models.Account, error) { + if result, err := a.DO.First(); err != nil { + return nil, err + } else { + return result.(*models.Account), nil + } +} + +func (a accountDo) Take() (*models.Account, error) { + if result, err := a.DO.Take(); err != nil { + return nil, err + } else { + return result.(*models.Account), nil + } +} + +func (a accountDo) Last() (*models.Account, error) { + if result, err := a.DO.Last(); err != nil { + return nil, err + } else { + return result.(*models.Account), nil + } +} + +func (a accountDo) Find() ([]*models.Account, error) { + result, err := a.DO.Find() + return result.([]*models.Account), err +} + +func (a accountDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Account, err error) { + buf := make([]*models.Account, 0, batchSize) + err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { + defer func() { results = append(results, buf...) }() + return fc(tx, batch) + }) + return results, err +} + +func (a accountDo) FindInBatches(result *[]*models.Account, batchSize int, fc func(tx gen.Dao, batch int) error) error { + return a.DO.FindInBatches(result, batchSize, fc) +} + +func (a accountDo) Attrs(attrs ...field.AssignExpr) IAccountDo { + return a.withDO(a.DO.Attrs(attrs...)) +} + +func (a accountDo) Assign(attrs ...field.AssignExpr) IAccountDo { + return a.withDO(a.DO.Assign(attrs...)) +} + +func (a accountDo) Joins(fields ...field.RelationField) IAccountDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Joins(_f)) + } + return &a +} + +func (a accountDo) Preload(fields ...field.RelationField) IAccountDo { + for _, _f := range fields { + a = *a.withDO(a.DO.Preload(_f)) + } + return &a +} + +func (a accountDo) FirstOrInit() (*models.Account, error) { + if result, err := a.DO.FirstOrInit(); err != nil { + return nil, err + } else { + return result.(*models.Account), nil + } +} + +func (a accountDo) FirstOrCreate() (*models.Account, error) { + if result, err := a.DO.FirstOrCreate(); err != nil { + return nil, err + } else { + return result.(*models.Account), nil + } +} + +func (a accountDo) FindByPage(offset int, limit int) (result []*models.Account, count int64, err error) { + result, err = a.Offset(offset).Limit(limit).Find() + if err != nil { + return + } + + if size := len(result); 0 < limit && 0 < size && size < limit { + count = int64(size + offset) + return + } + + count, err = a.Offset(-1).Limit(-1).Count() + return +} + +func (a accountDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { + count, err = a.Count() + if err != nil { + return + } + + err = a.Offset(offset).Limit(limit).Scan(result) + return +} + +func (a accountDo) Scan(result interface{}) (err error) { + return a.DO.Scan(result) +} + +func (a accountDo) Delete(models ...*models.Account) (result gen.ResultInfo, err error) { + return a.DO.Delete(models) +} + +func (a *accountDo) withDO(do gen.Dao) *accountDo { + a.DO = *do.(*gen.DO) + return a +} diff --git a/pkg/api/database/dao/auths.gen.go b/pkg/api/database/dao/auths.gen.go deleted file mode 100644 index 9ddfb66..0000000 --- a/pkg/api/database/dao/auths.gen.go +++ /dev/null @@ -1,419 +0,0 @@ -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. -// Code generated by gorm.io/gen. DO NOT EDIT. - -package dao - -import ( - "context" - - "github.com/DVKunion/SeaMoon/pkg/api/models" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "gorm.io/gorm/schema" - - "gorm.io/gen" - "gorm.io/gen/field" - - "gorm.io/plugin/dbresolver" -) - -func newAuth(db *gorm.DB, opts ...gen.DOOption) auth { - _auth := auth{} - - _auth.authDo.UseDB(db, opts...) - _auth.authDo.UseModel(&models.Auth{}) - - tableName := _auth.authDo.TableName() - _auth.ALL = field.NewAsterisk(tableName) - _auth.ID = field.NewUint(tableName, "id") - _auth.CreatedAt = field.NewTime(tableName, "created_at") - _auth.UpdatedAt = field.NewTime(tableName, "updated_at") - _auth.DeletedAt = field.NewField(tableName, "deleted_at") - _auth.Type = field.NewInt8(tableName, "type") - _auth.Username = field.NewString(tableName, "username") - _auth.Password = field.NewString(tableName, "password") - _auth.LastLogin = field.NewString(tableName, "last_login") - _auth.LastAddr = field.NewString(tableName, "last_addr") - - _auth.fillFieldMap() - - return _auth -} - -type auth struct { - authDo authDo - - ALL field.Asterisk - ID field.Uint - CreatedAt field.Time - UpdatedAt field.Time - DeletedAt field.Field - Type field.Int8 - Username field.String - Password field.String - LastLogin field.String - LastAddr field.String - - fieldMap map[string]field.Expr -} - -func (a auth) Table(newTableName string) *auth { - a.authDo.UseTable(newTableName) - return a.updateTableName(newTableName) -} - -func (a auth) As(alias string) *auth { - a.authDo.DO = *(a.authDo.As(alias).(*gen.DO)) - return a.updateTableName(alias) -} - -func (a *auth) updateTableName(table string) *auth { - a.ALL = field.NewAsterisk(table) - a.ID = field.NewUint(table, "id") - a.CreatedAt = field.NewTime(table, "created_at") - a.UpdatedAt = field.NewTime(table, "updated_at") - a.DeletedAt = field.NewField(table, "deleted_at") - a.Type = field.NewInt8(table, "type") - a.Username = field.NewString(table, "username") - a.Password = field.NewString(table, "password") - a.LastLogin = field.NewString(table, "last_login") - a.LastAddr = field.NewString(table, "last_addr") - - a.fillFieldMap() - - return a -} - -func (a *auth) WithContext(ctx context.Context) IAuthDo { return a.authDo.WithContext(ctx) } - -func (a auth) TableName() string { return a.authDo.TableName() } - -func (a auth) Alias() string { return a.authDo.Alias() } - -func (a auth) Columns(cols ...field.Expr) gen.Columns { return a.authDo.Columns(cols...) } - -func (a *auth) GetFieldByName(fieldName string) (field.OrderExpr, bool) { - _f, ok := a.fieldMap[fieldName] - if !ok || _f == nil { - return nil, false - } - _oe, ok := _f.(field.OrderExpr) - return _oe, ok -} - -func (a *auth) fillFieldMap() { - a.fieldMap = make(map[string]field.Expr, 9) - a.fieldMap["id"] = a.ID - a.fieldMap["created_at"] = a.CreatedAt - a.fieldMap["updated_at"] = a.UpdatedAt - a.fieldMap["deleted_at"] = a.DeletedAt - a.fieldMap["type"] = a.Type - a.fieldMap["username"] = a.Username - a.fieldMap["password"] = a.Password - a.fieldMap["last_login"] = a.LastLogin - a.fieldMap["last_addr"] = a.LastAddr -} - -func (a auth) clone(db *gorm.DB) auth { - a.authDo.ReplaceConnPool(db.Statement.ConnPool) - return a -} - -func (a auth) replaceDB(db *gorm.DB) auth { - a.authDo.ReplaceDB(db) - return a -} - -type authDo struct{ gen.DO } - -type IAuthDo interface { - gen.SubQuery - Debug() IAuthDo - WithContext(ctx context.Context) IAuthDo - WithResult(fc func(tx gen.Dao)) gen.ResultInfo - ReplaceDB(db *gorm.DB) - ReadDB() IAuthDo - WriteDB() IAuthDo - As(alias string) gen.Dao - Session(config *gorm.Session) IAuthDo - Columns(cols ...field.Expr) gen.Columns - Clauses(conds ...clause.Expression) IAuthDo - Not(conds ...gen.Condition) IAuthDo - Or(conds ...gen.Condition) IAuthDo - Select(conds ...field.Expr) IAuthDo - Where(conds ...gen.Condition) IAuthDo - Order(conds ...field.Expr) IAuthDo - Distinct(cols ...field.Expr) IAuthDo - Omit(cols ...field.Expr) IAuthDo - Join(table schema.Tabler, on ...field.Expr) IAuthDo - LeftJoin(table schema.Tabler, on ...field.Expr) IAuthDo - RightJoin(table schema.Tabler, on ...field.Expr) IAuthDo - Group(cols ...field.Expr) IAuthDo - Having(conds ...gen.Condition) IAuthDo - Limit(limit int) IAuthDo - Offset(offset int) IAuthDo - Count() (count int64, err error) - Scopes(funcs ...func(gen.Dao) gen.Dao) IAuthDo - Unscoped() IAuthDo - Create(values ...*models.Auth) error - CreateInBatches(values []*models.Auth, batchSize int) error - Save(values ...*models.Auth) error - First() (*models.Auth, error) - Take() (*models.Auth, error) - Last() (*models.Auth, error) - Find() ([]*models.Auth, error) - FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Auth, err error) - FindInBatches(result *[]*models.Auth, batchSize int, fc func(tx gen.Dao, batch int) error) error - Pluck(column field.Expr, dest interface{}) error - Delete(...*models.Auth) (info gen.ResultInfo, err error) - Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error) - UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) - Updates(value interface{}) (info gen.ResultInfo, err error) - UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error) - UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error) - UpdateColumns(value interface{}) (info gen.ResultInfo, err error) - UpdateFrom(q gen.SubQuery) gen.Dao - Attrs(attrs ...field.AssignExpr) IAuthDo - Assign(attrs ...field.AssignExpr) IAuthDo - Joins(fields ...field.RelationField) IAuthDo - Preload(fields ...field.RelationField) IAuthDo - FirstOrInit() (*models.Auth, error) - FirstOrCreate() (*models.Auth, error) - FindByPage(offset int, limit int) (result []*models.Auth, count int64, err error) - ScanByPage(result interface{}, offset int, limit int) (count int64, err error) - Scan(result interface{}) (err error) - Returning(value interface{}, columns ...string) IAuthDo - UnderlyingDB() *gorm.DB - schema.Tabler -} - -func (a authDo) Debug() IAuthDo { - return a.withDO(a.DO.Debug()) -} - -func (a authDo) WithContext(ctx context.Context) IAuthDo { - return a.withDO(a.DO.WithContext(ctx)) -} - -func (a authDo) ReadDB() IAuthDo { - return a.Clauses(dbresolver.Read) -} - -func (a authDo) WriteDB() IAuthDo { - return a.Clauses(dbresolver.Write) -} - -func (a authDo) Session(config *gorm.Session) IAuthDo { - return a.withDO(a.DO.Session(config)) -} - -func (a authDo) Clauses(conds ...clause.Expression) IAuthDo { - return a.withDO(a.DO.Clauses(conds...)) -} - -func (a authDo) Returning(value interface{}, columns ...string) IAuthDo { - return a.withDO(a.DO.Returning(value, columns...)) -} - -func (a authDo) Not(conds ...gen.Condition) IAuthDo { - return a.withDO(a.DO.Not(conds...)) -} - -func (a authDo) Or(conds ...gen.Condition) IAuthDo { - return a.withDO(a.DO.Or(conds...)) -} - -func (a authDo) Select(conds ...field.Expr) IAuthDo { - return a.withDO(a.DO.Select(conds...)) -} - -func (a authDo) Where(conds ...gen.Condition) IAuthDo { - return a.withDO(a.DO.Where(conds...)) -} - -func (a authDo) Order(conds ...field.Expr) IAuthDo { - return a.withDO(a.DO.Order(conds...)) -} - -func (a authDo) Distinct(cols ...field.Expr) IAuthDo { - return a.withDO(a.DO.Distinct(cols...)) -} - -func (a authDo) Omit(cols ...field.Expr) IAuthDo { - return a.withDO(a.DO.Omit(cols...)) -} - -func (a authDo) Join(table schema.Tabler, on ...field.Expr) IAuthDo { - return a.withDO(a.DO.Join(table, on...)) -} - -func (a authDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAuthDo { - return a.withDO(a.DO.LeftJoin(table, on...)) -} - -func (a authDo) RightJoin(table schema.Tabler, on ...field.Expr) IAuthDo { - return a.withDO(a.DO.RightJoin(table, on...)) -} - -func (a authDo) Group(cols ...field.Expr) IAuthDo { - return a.withDO(a.DO.Group(cols...)) -} - -func (a authDo) Having(conds ...gen.Condition) IAuthDo { - return a.withDO(a.DO.Having(conds...)) -} - -func (a authDo) Limit(limit int) IAuthDo { - return a.withDO(a.DO.Limit(limit)) -} - -func (a authDo) Offset(offset int) IAuthDo { - return a.withDO(a.DO.Offset(offset)) -} - -func (a authDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAuthDo { - return a.withDO(a.DO.Scopes(funcs...)) -} - -func (a authDo) Unscoped() IAuthDo { - return a.withDO(a.DO.Unscoped()) -} - -func (a authDo) Create(values ...*models.Auth) error { - if len(values) == 0 { - return nil - } - return a.DO.Create(values) -} - -func (a authDo) CreateInBatches(values []*models.Auth, batchSize int) error { - return a.DO.CreateInBatches(values, batchSize) -} - -// Save : !!! underlying implementation is different with GORM -// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values) -func (a authDo) Save(values ...*models.Auth) error { - if len(values) == 0 { - return nil - } - return a.DO.Save(values) -} - -func (a authDo) First() (*models.Auth, error) { - if result, err := a.DO.First(); err != nil { - return nil, err - } else { - return result.(*models.Auth), nil - } -} - -func (a authDo) Take() (*models.Auth, error) { - if result, err := a.DO.Take(); err != nil { - return nil, err - } else { - return result.(*models.Auth), nil - } -} - -func (a authDo) Last() (*models.Auth, error) { - if result, err := a.DO.Last(); err != nil { - return nil, err - } else { - return result.(*models.Auth), nil - } -} - -func (a authDo) Find() ([]*models.Auth, error) { - result, err := a.DO.Find() - return result.([]*models.Auth), err -} - -func (a authDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*models.Auth, err error) { - buf := make([]*models.Auth, 0, batchSize) - err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error { - defer func() { results = append(results, buf...) }() - return fc(tx, batch) - }) - return results, err -} - -func (a authDo) FindInBatches(result *[]*models.Auth, batchSize int, fc func(tx gen.Dao, batch int) error) error { - return a.DO.FindInBatches(result, batchSize, fc) -} - -func (a authDo) Attrs(attrs ...field.AssignExpr) IAuthDo { - return a.withDO(a.DO.Attrs(attrs...)) -} - -func (a authDo) Assign(attrs ...field.AssignExpr) IAuthDo { - return a.withDO(a.DO.Assign(attrs...)) -} - -func (a authDo) Joins(fields ...field.RelationField) IAuthDo { - for _, _f := range fields { - a = *a.withDO(a.DO.Joins(_f)) - } - return &a -} - -func (a authDo) Preload(fields ...field.RelationField) IAuthDo { - for _, _f := range fields { - a = *a.withDO(a.DO.Preload(_f)) - } - return &a -} - -func (a authDo) FirstOrInit() (*models.Auth, error) { - if result, err := a.DO.FirstOrInit(); err != nil { - return nil, err - } else { - return result.(*models.Auth), nil - } -} - -func (a authDo) FirstOrCreate() (*models.Auth, error) { - if result, err := a.DO.FirstOrCreate(); err != nil { - return nil, err - } else { - return result.(*models.Auth), nil - } -} - -func (a authDo) FindByPage(offset int, limit int) (result []*models.Auth, count int64, err error) { - result, err = a.Offset(offset).Limit(limit).Find() - if err != nil { - return - } - - if size := len(result); 0 < limit && 0 < size && size < limit { - count = int64(size + offset) - return - } - - count, err = a.Offset(-1).Limit(-1).Count() - return -} - -func (a authDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) { - count, err = a.Count() - if err != nil { - return - } - - err = a.Offset(offset).Limit(limit).Scan(result) - return -} - -func (a authDo) Scan(result interface{}) (err error) { - return a.DO.Scan(result) -} - -func (a authDo) Delete(models ...*models.Auth) (result gen.ResultInfo, err error) { - return a.DO.Delete(models) -} - -func (a *authDo) withDO(do gen.Dao) *authDo { - a.DO = *do.(*gen.DO) - return a -} diff --git a/pkg/api/database/dao/gen.go b/pkg/api/database/dao/gen.go index 0017bda..be339b7 100644 --- a/pkg/api/database/dao/gen.go +++ b/pkg/api/database/dao/gen.go @@ -17,7 +17,7 @@ import ( var ( Q = new(Query) - Auth *auth + Account *account Config *config Provider *provider Proxy *proxy @@ -26,7 +26,7 @@ var ( func SetDefault(db *gorm.DB, opts ...gen.DOOption) { *Q = *Use(db, opts...) - Auth = &Q.Auth + Account = &Q.Account Config = &Q.Config Provider = &Q.Provider Proxy = &Q.Proxy @@ -36,7 +36,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) { func Use(db *gorm.DB, opts ...gen.DOOption) *Query { return &Query{ db: db, - Auth: newAuth(db, opts...), + Account: newAccount(db, opts...), Config: newConfig(db, opts...), Provider: newProvider(db, opts...), Proxy: newProxy(db, opts...), @@ -47,7 +47,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query { type Query struct { db *gorm.DB - Auth auth + Account account Config config Provider provider Proxy proxy @@ -59,7 +59,7 @@ func (q *Query) Available() bool { return q.db != nil } func (q *Query) clone(db *gorm.DB) *Query { return &Query{ db: db, - Auth: q.Auth.clone(db), + Account: q.Account.clone(db), Config: q.Config.clone(db), Provider: q.Provider.clone(db), Proxy: q.Proxy.clone(db), @@ -78,7 +78,7 @@ func (q *Query) WriteDB() *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query { return &Query{ db: db, - Auth: q.Auth.replaceDB(db), + Account: q.Account.replaceDB(db), Config: q.Config.replaceDB(db), Provider: q.Provider.replaceDB(db), Proxy: q.Proxy.replaceDB(db), @@ -87,7 +87,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query { } type queryCtx struct { - Auth IAuthDo + Account IAccountDo Config IConfigDo Provider IProviderDo Proxy IProxyDo @@ -96,7 +96,7 @@ type queryCtx struct { func (q *Query) WithContext(ctx context.Context) *queryCtx { return &queryCtx{ - Auth: q.Auth.WithContext(ctx), + Account: q.Account.WithContext(ctx), Config: q.Config.WithContext(ctx), Provider: q.Provider.WithContext(ctx), Proxy: q.Proxy.WithContext(ctx), diff --git a/pkg/api/database/dao/tunnels.gen.go b/pkg/api/database/dao/tunnels.gen.go index 22a192c..b88457f 100644 --- a/pkg/api/database/dao/tunnels.gen.go +++ b/pkg/api/database/dao/tunnels.gen.go @@ -43,6 +43,9 @@ func newTunnel(db *gorm.DB, opts ...gen.DOOption) tunnel { _tunnel.Memory = field.NewInt32(tableName, "memory") _tunnel.Instance = field.NewInt32(tableName, "instance") _tunnel.FcAuthType = field.NewInt8(tableName, "fc_auth_type") + _tunnel.SSRCrypt = field.NewString(tableName, "ssr_crypt") + _tunnel.SSRPass = field.NewString(tableName, "ssr_pass") + _tunnel.V2rayUid = field.NewString(tableName, "v2ray_uid") _tunnel.TLS = field.NewBool(tableName, "tls") _tunnel.Tor = field.NewBool(tableName, "tor") _tunnel.Proxies = tunnelHasManyProxies{ @@ -77,6 +80,9 @@ type tunnel struct { Memory field.Int32 Instance field.Int32 FcAuthType field.Int8 + SSRCrypt field.String + SSRPass field.String + V2rayUid field.String TLS field.Bool Tor field.Bool Proxies tunnelHasManyProxies @@ -113,6 +119,9 @@ func (t *tunnel) updateTableName(table string) *tunnel { t.Memory = field.NewInt32(table, "memory") t.Instance = field.NewInt32(table, "instance") t.FcAuthType = field.NewInt8(table, "fc_auth_type") + t.SSRCrypt = field.NewString(table, "ssr_crypt") + t.SSRPass = field.NewString(table, "ssr_pass") + t.V2rayUid = field.NewString(table, "v2ray_uid") t.TLS = field.NewBool(table, "tls") t.Tor = field.NewBool(table, "tor") @@ -139,7 +148,7 @@ func (t *tunnel) GetFieldByName(fieldName string) (field.OrderExpr, bool) { } func (t *tunnel) fillFieldMap() { - t.fieldMap = make(map[string]field.Expr, 20) + t.fieldMap = make(map[string]field.Expr, 23) t.fieldMap["id"] = t.ID t.fieldMap["created_at"] = t.CreatedAt t.fieldMap["updated_at"] = t.UpdatedAt @@ -157,6 +166,9 @@ func (t *tunnel) fillFieldMap() { t.fieldMap["memory"] = t.Memory t.fieldMap["instance"] = t.Instance t.fieldMap["fc_auth_type"] = t.FcAuthType + t.fieldMap["ssr_crypt"] = t.SSRCrypt + t.fieldMap["ssr_pass"] = t.SSRPass + t.fieldMap["v2ray_uid"] = t.V2rayUid t.fieldMap["tls"] = t.TLS t.fieldMap["tor"] = t.Tor diff --git a/pkg/api/database/drivers/drivers.go b/pkg/api/database/drivers/drivers.go index 30c94a4..de9deb9 100644 --- a/pkg/api/database/drivers/drivers.go +++ b/pkg/api/database/drivers/drivers.go @@ -1,7 +1,6 @@ package drivers import ( - "github.com/spf13/cobra" "gorm.io/gorm" ) @@ -15,7 +14,7 @@ type Driver interface { Init(migrateFunc []func()) GetConn() *gorm.DB QueryPage(page, size int) *gorm.DB - Generate(cmd *cobra.Command, args []string) error + Generate() error } func Init() { diff --git a/pkg/api/database/drivers/sqlite3.go b/pkg/api/database/drivers/sqlite3.go index fbc9ad0..9940281 100644 --- a/pkg/api/database/drivers/sqlite3.go +++ b/pkg/api/database/drivers/sqlite3.go @@ -3,14 +3,16 @@ package drivers import ( "os" + "github.com/djherbis/times" "github.com/glebarez/sqlite" - "github.com/spf13/cobra" "gorm.io/gen" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/DVKunion/SeaMoon/pkg/api/database/dao" "github.com/DVKunion/SeaMoon/pkg/api/models" + "github.com/DVKunion/SeaMoon/pkg/system/keys" + "github.com/DVKunion/SeaMoon/pkg/system/tools" "github.com/DVKunion/SeaMoon/pkg/system/xlog" ) @@ -42,6 +44,14 @@ func (s *sqlite3) Init(migrateFunc []func()) { }() } + defer func() { + t, err := times.Stat(dbPath) + if err != nil || !t.HasBirthTime() { + panic(err) + } + keys.SetGlobalKey(tools.GenerateKey(t.BirthTime())) + }() + s.db, err = gorm.Open(sqlite.Open(dbPath), &gormConfig) dao.SetDefault(s.db) if err != nil { @@ -64,7 +74,7 @@ func (s *sqlite3) QueryPage(page, size int) *gorm.DB { return s.db.Offset(page * size).Limit(size) } -func (s *sqlite3) Generate(cmd *cobra.Command, args []string) error { +func (s *sqlite3) Generate() error { // Initialize the generator with configuration g := gen.NewGenerator(gen.Config{ OutPath: "pkg/api/database/dao", // output directory, default value is ./query diff --git a/pkg/api/enum/account.go b/pkg/api/enum/account.go new file mode 100644 index 0000000..82cb653 --- /dev/null +++ b/pkg/api/enum/account.go @@ -0,0 +1,48 @@ +package enum + +type AccountType int8 + +const ( + Admin AccountType = iota + 1 // 管理员 用于登陆后台的账户 + Xray + Cloud +) + +type AuthType int8 + +const ( + AdminAuth AuthType = iota + 1 +) + +const ( + // XrayAuthUserPass xray 账户类型 + XrayAuthUserPass AuthType = iota + 5 // xray http / socks 代理账户 + XrayAuthEmailPass // xray shadowsocks / trojan 代理账户 + XrayAuthIdEncrypt // xray vmess / vless 代理账户 +) + +const ( + // CloudAuthKeyMod 云账户认证类型 + CloudAuthKeyMod AuthType = iota + 10 // AK / SK 模式 + CloudAuthCert // 证书模式 +) + +const ( + // CloudFCAuthEmpty 函数认证类型 + CloudFCAuthEmpty AuthType = iota + 20 // 无认证 + CloudFCAuthSignature // FC Signature 认证, 这类认证好处在于认证失败 403 不计次数 + CloudFCAuthJwt // FC Jwt 认证。 需要 jwks + CloudFCAuthParis // SCF 网管密钥对认证 +) + +func TransCloudFCAuthType(t string) AuthType { + switch t { + case "anonymous", "NONE": + return CloudFCAuthEmpty + case "function": + return CloudFCAuthSignature + case "jwt": + return CloudFCAuthJwt + } + return CloudFCAuthEmpty +} diff --git a/pkg/api/enum/auth.go b/pkg/api/enum/auth.go deleted file mode 100644 index 0c2c087..0000000 --- a/pkg/api/enum/auth.go +++ /dev/null @@ -1,26 +0,0 @@ -package enum - -type AuthType int8 - -const ( - AuthEmpty AuthType = iota + 1 // 无认证 - AuthAdmin // 后台账户 - AuthBasic // HTTP Basic 认证 - AuthBearer // HTTP Bearer 认证 - - AuthSignature // FC Signature 认证, 这类认证好处在于认证失败 403 不计次数 - AuthJwt // FC Jwt 认证。 需要 jwks - AuthParis // SCF 网管密钥对认证 -) - -func TransAuthType(t string) AuthType { - switch t { - case "anonymous", "NONE": - return AuthEmpty - case "function": - return AuthSignature - case "jwt": - return AuthJwt - } - return AuthEmpty -} diff --git a/pkg/api/enum/proxy.go b/pkg/api/enum/proxy.go index c32a7b5..eb971ad 100644 --- a/pkg/api/enum/proxy.go +++ b/pkg/api/enum/proxy.go @@ -23,6 +23,7 @@ const ( ProxyTypeShadowSocks ProxyType = "shadowsocks" ProxyTypeVmess ProxyType = "vmess" ProxyTypeVless ProxyType = "vless" + ProxyTypeTorjan ProxyType = "torjan" ) func (t ProxyType) String() string { diff --git a/pkg/api/enum/tunnel.go b/pkg/api/enum/tunnel.go index b615b08..040da0a 100644 --- a/pkg/api/enum/tunnel.go +++ b/pkg/api/enum/tunnel.go @@ -1,14 +1,20 @@ package enum -type TunnelStatus int8 +type FunctionStatus int8 const ( - TunnelInitializing TunnelStatus = iota + 1 // 初始化 - TunnelActive // 可用 - TunnelInactive // 停用 - TunnelError // 不可用 - TunnelWaiting // 异常 - TunnelDelete // 删除 + FunctionInitializing FunctionStatus = iota + 1 // 初始化 + FunctionActive // 可用 + FunctionInactive // 停用 + FunctionError // 不可用 + FunctionWaiting // 异常 + FunctionDelete // 删除 +) + +type FunctionType int8 + +const ( + FunctionTunnel FunctionType = iota + 1 ) type TunnelType string diff --git a/pkg/api/models/abstract/auth.go b/pkg/api/models/abstract/auth.go new file mode 100644 index 0000000..cab4aa8 --- /dev/null +++ b/pkg/api/models/abstract/auth.go @@ -0,0 +1,83 @@ +package abstract + +import ( + "fmt" +) + +// Auth 抽象各类认证接口 +type Auth interface { + Identity() string +} + +type AuthList []Auth + +func (al AuthList) IsEmpty() bool { + return al == nil || len(al) == 0 +} + +type AdminAuth struct { + Username string `json:"username"` + Password string `json:"password"` + LastLogin string `json:"last_login"` + LastAddr string `json:"last_addr"` +} + +func (a AdminAuth) Identity() string { + return fmt.Sprintf("%s:%s", a.Username, a.Password) +} + +type CloudKeyAuth struct { + // 阿里需要 ID + AccessId string `json:"access_id"` + // 普通云厂商使用的认证 + AccessKey string `json:"access_key"` + AccessSecret string `json:"access_secret"` +} + +type CertsAuth struct { + // Sealos 认证信息 + KubeConfig string `json:"kube_config" gorm:"not null"` +} + +func (a CloudKeyAuth) Identity() string { + return fmt.Sprintf("%s:%s:%s", a.AccessId, a.AccessKey, a.AccessSecret) +} + +func (a CertsAuth) Identity() string { + return a.KubeConfig +} + +type UserPassAuth struct { + User string `json:"user"` + Pass string `json:"pass"` + Level *int `json:"level,omitempty"` +} + +func (a UserPassAuth) Identity() string { + return fmt.Sprintf("%s:%s", a.User, a.Pass) +} + +// EmailPassAuth for shadowsocks / trojan +type EmailPassAuth struct { + Password string `json:"password"` + Method string `json:"method,omitempty"` + Level int `json:"level"` + Email string `json:"email"` +} + +func (a EmailPassAuth) Identity() string { + return fmt.Sprintf("%s:%s:%s", a.Method, a.Email, a.Password) +} + +// IdEncryptAuth used for vmess / vless +type IdEncryptAuth struct { + Id string `json:"id"` // vmess / vless + Level int `json:"level"` + Email string `json:"email"` + Security string `json:"security,omitempty"` // vmess client needs + Flow string `json:"flow,omitempty"` +} + +func (a IdEncryptAuth) Identity() string { + return fmt.Sprintf("%s:%s:%s", a.Security, a.Email, a.Id) +} diff --git a/pkg/api/models/abstract/auth_test.go b/pkg/api/models/abstract/auth_test.go new file mode 100644 index 0000000..d8658ae --- /dev/null +++ b/pkg/api/models/abstract/auth_test.go @@ -0,0 +1,86 @@ +package abstract + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +func TestUserPassAuth(t *testing.T) { + // check single auth + a1 := &UserPassAuth{ + User: "admin", + Pass: "admin", + } + + assert.Equal(t, "{\"user\":\"admin\",\"pass\":\"admin\"}", tools.MarshalString(a1)) + + // check single auth with level nil + a2 := &UserPassAuth{ + User: "admin", + Pass: "admin", + Level: nil, + } + + assert.Equal(t, "{\"user\":\"admin\",\"pass\":\"admin\"}", tools.MarshalString(a2)) + + // check single auth with level + a3 := &UserPassAuth{ + User: "admin", + Pass: "admin", + Level: tools.IntPtr(0), + } + + assert.Equal(t, "{\"user\":\"admin\",\"pass\":\"admin\",\"level\":0}", tools.MarshalString(a3)) + + // check auth list + al1 := AuthList{} + + assert.Equal(t, "[]", tools.MarshalString(al1)) + + al2 := AuthList{a1} + assert.Equal(t, "[{\"user\":\"admin\",\"pass\":\"admin\"}]", tools.MarshalString(al2)) + + al3 := AuthList{a1, a2, a3} + assert.Equal(t, "[{\"user\":\"admin\",\"pass\":\"admin\"},{\"user\":\"admin\",\"pass\":\"admin\"},{\"user\":\"admin\",\"pass\":\"admin\",\"level\":0}]", tools.MarshalString(al3)) +} + +func TestEmailPassAuth(t *testing.T) { + // check single auth + // for shadowsocks / torjan inbound, sometimes may not have method field + a1 := &EmailPassAuth{ + Email: "admin@admin.com", + Password: "admin", + Level: 0, + } + + assert.Equal(t, "{\"password\":\"admin\",\"level\":0,\"email\":\"admin@admin.com\"}", tools.MarshalString(a1)) + + // check shadowsocks with method case + a2 := &EmailPassAuth{ + Email: "admin@admin.com", + Password: "admin", + Method: "aes-256-gcm", + Level: 0, + } + + assert.Equal(t, "{\"password\":\"admin\",\"method\":\"aes-256-gcm\",\"level\":0,\"email\":\"admin@admin.com\"}", tools.MarshalString(a2)) + + // check auth lists + al1 := &AuthList{a1} + assert.Equal(t, "[{\"password\":\"admin\",\"level\":0,\"email\":\"admin@admin.com\"}]", tools.MarshalString(al1)) + + al2 := &AuthList{a1, a2} + assert.Equal(t, "[{\"password\":\"admin\",\"level\":0,\"email\":\"admin@admin.com\"},{\"password\":\"admin\",\"method\":\"aes-256-gcm\",\"level\":0,\"email\":\"admin@admin.com\"}]", tools.MarshalString(al2)) +} + +func TestIdEncryptAuth(t *testing.T) { + a1 := IdEncryptAuth{ + Id: "1234-5678-9101-1121", + Level: 0, + Email: "admin@admin.com", + } + assert.Equal(t, "{\"id\":\"1234-5678-9101-1121\",\"level\":0,\"email\":\"admin@admin.com\"}", tools.MarshalString(a1)) +} diff --git a/pkg/api/models/abstract/func.go b/pkg/api/models/abstract/func.go new file mode 100644 index 0000000..83275ea --- /dev/null +++ b/pkg/api/models/abstract/func.go @@ -0,0 +1,16 @@ +package abstract + +type FunctionConfig interface { +} + +type TunnelConfig struct { + // 函数配置 + Region string `json:"region"` // 一个隧道只能是一个区域 + CPU float32 `json:"cpu"` // CPU 资源 + Memory int32 `json:"memory"` // 内存资源 + Instance int32 `json:"instance"` // 最大实例处理数 + SSRCrypt string `json:"ssr_crypt"` // ssr 加密方式 + SSRPass string `json:"ssr_pass"` // ssr 密码 + V2rayUid string `json:"v2ray_uid"` // v2ray_uid + TLS bool `json:"tls"` // 是否开启 TLS 传输, 开启后自动使用 wss 协议 +} diff --git a/pkg/api/models/api/account.go b/pkg/api/models/api/account.go new file mode 100644 index 0000000..778f64e --- /dev/null +++ b/pkg/api/models/api/account.go @@ -0,0 +1 @@ +package api diff --git a/pkg/api/models/tunnel.go b/pkg/api/models/api/funciton.go similarity index 70% rename from pkg/api/models/tunnel.go rename to pkg/api/models/api/funciton.go index 975417c..c0ea685 100644 --- a/pkg/api/models/tunnel.go +++ b/pkg/api/models/api/funciton.go @@ -1,52 +1,12 @@ -package models +package api import ( - "encoding/base64" "fmt" - "time" - - "gopkg.in/yaml.v3" - "gorm.io/gorm" "github.com/DVKunion/SeaMoon/pkg/api/enum" + "github.com/DVKunion/SeaMoon/pkg/api/models/external" ) -// Tunnel 表示着实际部署的一个函数节点 -type Tunnel struct { - gorm.Model - - ProviderId uint - - UniqID *string // 唯一性ID,用于 sync 同步时识别出唯一函数与隧道关系 - Name *string // 隧道名称,建议英文 - Addr *string // 服务地址 - Port *int32 // 服务端口 - Type *enum.TunnelType // 隧道协议类型 - Status *enum.TunnelStatus // 隧道状态 - StatusMessage *string // 隧道状态原因,用于展示具体的异常详情 - - Config *TunnelConfig `gorm:"embedded"` - // 连表查询 - Proxies []Proxy `gorm:"foreignKey:TunnelID;references:ID"` -} - -type TunnelList []*Tunnel - -type TunnelConfig struct { - // 函数配置 - Region string `json:"region"` // 一个隧道只能是一个区域 - CPU float32 `json:"cpu"` // CPU 资源 - Memory int32 `json:"memory"` // 内存资源 - Instance int32 `json:"instance"` // 最大实例处理数 - FcAuthType enum.AuthType `json:"fc_auth_type"` // 函数认证方式 - SSRCrypt string `json:"ssr_crypt"` // ssr 加密方式 - SSRPass string `json:"ssr_pass"` // ssr 密码 - V2rayUid string `json:"v2ray_uid"` // v2ray_uid - - TLS bool `json:"tls"` // 是否开启 TLS 传输, 开启后自动使用 wss 协议 - Tor bool `json:"tor"` // 是否开启 Tor 转发 -} - type TunnelApi struct { ProviderId uint `json:"provider_id"` ProviderType *enum.ProviderType `json:"provider_type"` @@ -56,12 +16,11 @@ type TunnelApi struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` - Name *string `json:"name"` - Addr *string `json:"address"` - Port *int32 `json:"port"` - Type *enum.TunnelType `json:"type"` - Status *enum.TunnelStatus `json:"status"` - StatusMessage *string `json:"status_message"` + Name *string `json:"name"` + Addr *string `json:"address"` + Port *int32 `json:"port"` + Type *enum.TunnelType `json:"type"` + StatusMessage *string `json:"status_message"` Config *TunnelConfig `json:"tunnel_config"` } @@ -76,8 +35,7 @@ type TunnelCreateApi struct { Status *enum.TunnelStatus `json:"status"` StatusMessage *string `json:"status_message"` Addr *string `json:"address"` - - Config *TunnelConfig `json:"tunnel_config"` + Config *TunnelConfig `json:"tunnel_config"` } type TunnelCreateApiList []*TunnelCreateApi @@ -114,7 +72,7 @@ func (tl TunnelList) ToApi(extra ...func(api interface{})) []*TunnelApi { func (tl TunnelList) ToConfig(p string) []byte { switch p { case "clash": - cc := ClashConfig{ + cc := external.ClashConfig{ MixedPort: 7890, AllowLan: false, LogLevel: "info", @@ -128,8 +86,8 @@ func (tl TunnelList) ToConfig(p string) []byte { // FakeIPFilter: []string{"*.lan"}, // Nameserver: //}, - Proxies: make([]ClashProxies, 0), - ProxyGroups: []ClashProxyGroups{ + Proxies: make([]external.ClashProxies, 0), + ProxyGroups: []external.ClashProxyGroups{ { Name: "Proxies", Type: "select", @@ -141,10 +99,10 @@ func (tl TunnelList) ToConfig(p string) []byte { Proxies: []string{"DIRECT"}, }, }, - Rules: BindingRules, + Rules: external.BindingRules, } for _, t := range tl { - cc.Proxies = append(cc.Proxies, ClashProxies{ + cc.Proxies = append(cc.Proxies, external.ClashProxies{ Name: *t.Name + "-" + t.Config.Region + "-vmess", Type: "vmess", Server: *t.Addr, diff --git a/pkg/api/models/auth.go b/pkg/api/models/auth.go deleted file mode 100644 index d2bd9d4..0000000 --- a/pkg/api/models/auth.go +++ /dev/null @@ -1,45 +0,0 @@ -package models - -import ( - "gorm.io/gorm" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" -) - -var DefaultAuth = []Auth{ - { - Type: enum.AuthAdmin, - Username: "seamoon", - Password: "2575a6f37310dd27e884a0305a2dd210", - }, -} - -type Auth struct { - gorm.Model - - Type enum.AuthType // 认证类型,用于判断该认证信息适用于啥的 - Username string `json:"username"` - Password string `json:"password"` - - LastLogin string `json:"last_login"` - LastAddr string `json:"last_addr"` -} - -type AuthApi struct { - Username string `json:"username"` - Password string `json:"password"` -} - -type CloudAuth struct { - // 阿里需要 ID - AccessId string `json:"access_id" gorm:"not null"` - // 普通云厂商使用的认证 - AccessKey string `json:"access_key" gorm:"not null"` - AccessSecret string `json:"access_secret" gorm:"not null"` - - // 接口类型认证信息 - Token string `json:"token" gorm:"not null"` - - // Sealos 认证信息 - KubeConfig string `json:"kube_config" gorm:"not null"` -} diff --git a/pkg/api/models/config.go b/pkg/api/models/config.go deleted file mode 100644 index 13228a7..0000000 --- a/pkg/api/models/config.go +++ /dev/null @@ -1,100 +0,0 @@ -package models - -import ( - "gorm.io/gorm" - - "github.com/DVKunion/SeaMoon/pkg/system/version" -) - -var DefaultConfig = []Config{ - { - Key: "control_addr", - Value: "0.0.0.0", - }, - { - Key: "control_port", - Value: "7777", - }, - { - Key: "control_log", - Value: "seamoon.log", - }, - { - Key: "auto_start", - Value: "true", - }, - { - Key: "auto_sync", - Value: "true", - }, -} - -// Config 系统标准配置表 -type Config struct { - gorm.Model - - Key string - Value string -} - -type ConfigList []*Config - -// ConfigApi 对外暴露接口 -type ConfigApi struct { - // 为了 web 方便, 直接转化成对应的 key 了 - ControlAddr string `json:"control_addr"` - ControlPort string `json:"control_port"` - ControlLog string `json:"control_log"` - AutoStart string `json:"auto_start"` - AutoSync string `json:"auto_sync"` - - Version string `json:"version"` -} - -func (c *ConfigApi) ToModel() ConfigList { - // 由于目前东西比较少,懒得写反射了;后续如果也有这种 KV 存储转换的需求,可以抽到 models 公共方法中 - var res = make([]*Config, 0) - res = append(res, &Config{ - Key: "control_addr", - Value: c.ControlAddr, - }) - res = append(res, &Config{ - Key: "control_port", - Value: c.ControlPort, - }) - res = append(res, &Config{ - Key: "control_log", - Value: c.ControlLog, - }) - res = append(res, &Config{ - Key: "auto_start", - Value: c.AutoStart, - }) - res = append(res, &Config{ - Key: "auto_sync", - Value: c.AutoSync, - }) - - return res -} - -func (cl ConfigList) ToApi() *ConfigApi { - var res = &ConfigApi{} - for _, s := range cl { - switch s.Key { - case "control_addr": - res.ControlAddr = s.Value - case "control_port": - res.ControlPort = s.Value - case "control_log": - res.ControlLog = s.Value - case "auto_start": - res.AutoStart = s.Value - case "auto_sync": - res.AutoSync = s.Value - case "version": - res.Version = version.Version - } - } - return res -} diff --git a/pkg/api/models/client.go b/pkg/api/models/external/clash.go similarity index 99% rename from pkg/api/models/client.go rename to pkg/api/models/external/clash.go index cb643d6..2012836 100644 --- a/pkg/api/models/client.go +++ b/pkg/api/models/external/clash.go @@ -1,7 +1,6 @@ -package models - -// 不同 client 结构序列化时使用 +package external +// ClashConfig 不同 client 结构序列化时使用 type ClashConfig struct { MixedPort int `yaml:"mixed-port,omitempty"` AllowLan bool `yaml:"allow-lan,omitempty"` diff --git a/pkg/api/models/model/account.go b/pkg/api/models/model/account.go new file mode 100644 index 0000000..d318a41 --- /dev/null +++ b/pkg/api/models/model/account.go @@ -0,0 +1,68 @@ +package model + +import ( + "encoding/json" + + "gorm.io/gorm" + + "github.com/DVKunion/SeaMoon/pkg/api/enum" + "github.com/DVKunion/SeaMoon/pkg/api/models/abstract" + "github.com/DVKunion/SeaMoon/pkg/system/errors" + "github.com/DVKunion/SeaMoon/pkg/system/keys" + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +// Account 表 +// 用于存放所有账户、认证相关的信息 +type Account struct { + gorm.Model + + Name string // 账户名 + Type enum.AccountType // 账户类型 + AuthType enum.AuthType // 认证类型 + Data string // 原始加密数据 + Auth abstract.Auth `gorm:"-"` +} + +// BeforeSave create / update need to transfer data to encrypt +func (a *Account) BeforeSave(*gorm.DB) (err error) { + data := tools.MarshalString(a.Auth) + if data == "" { + err = errors.New("auth save marshall error!") + return + } + a.Data, err = tools.AESEncrypt([]byte(data), keys.GetGlobalKey()) + return +} + +// AfterFind select to transfer data to plaintext +func (a *Account) AfterFind(*gorm.DB) error { + data, err := tools.AESDecrypt(a.Data, keys.GetGlobalKey()) + if err != nil { + return err + } + var b abstract.Auth + switch a.AuthType { + case enum.AdminAuth: + b = &abstract.AdminAuth{} + case enum.XrayAuthUserPass: + b = &abstract.UserPassAuth{} + case enum.XrayAuthEmailPass: + b = &abstract.EmailPassAuth{} + case enum.XrayAuthIdEncrypt: + b = &abstract.IdEncryptAuth{} + case enum.CloudAuthKeyMod: + b = &abstract.CloudKeyAuth{} + case enum.CloudAuthCert: + b = &abstract.CertsAuth{} + } + if b == nil { + return errors.New("xxxxxx") + } + err = json.Unmarshal(data, b) + if err != nil { + return err + } + a.Auth = b + return nil +} diff --git a/pkg/api/models/model/config.go b/pkg/api/models/model/config.go new file mode 100644 index 0000000..2d1ebbf --- /dev/null +++ b/pkg/api/models/model/config.go @@ -0,0 +1,38 @@ +package model + +import ( + "gorm.io/gorm" +) + +// Config 系统标准配置表 +type Config struct { + gorm.Model + + Key string + Value string +} + +// ConfigApi 对外暴露接口 +type ConfigApi map[string]string + +func (c ConfigApi) ToModel() ConfigList { + var res = make([]*Config, 0) + for k, v := range c { + cf := &Config{ + Key: k, + Value: v, + } + res = append(res, cf) + } + return res +} + +type ConfigList []*Config + +func (cl ConfigList) ToApi() ConfigApi { + var res = make(ConfigApi) + for _, s := range cl { + res[s.Key] = s.Value + } + return res +} diff --git a/pkg/api/models/model/function.go b/pkg/api/models/model/function.go new file mode 100644 index 0000000..8f431fe --- /dev/null +++ b/pkg/api/models/model/function.go @@ -0,0 +1,53 @@ +package model + +import ( + "encoding/json" + + "gorm.io/gorm" + + "github.com/DVKunion/SeaMoon/pkg/api/enum" + "github.com/DVKunion/SeaMoon/pkg/api/models/abstract" + "github.com/DVKunion/SeaMoon/pkg/system/errors" +) + +type Function struct { + gorm.Model + + ProviderId uint + UniqID *string // 唯一性ID,用于 sync 同步时识别出唯一函数与隧道关系 + Name *string // 函数名称,建议英文 + Type enum.FunctionType // 隧道协议类型 + Status enum.FunctionStatus // 函数状态 + FcAuthType enum.AuthType // 函数认证方式 + StatusMessage *string // 函数状态原因,用于展示具体的异常详情 + ConfigRaw string // 函数配置存储 + Config abstract.FunctionConfig `gorm:"-"` // 实际类型 +} + +// BeforeSave create / update need to transfer data to encrypt +func (f *Function) BeforeSave(*gorm.DB) error { + data, err := json.Marshal(f.Config) + if err != nil { + return err + } + f.ConfigRaw = string(data) + return nil +} + +// AfterFind select to transfer data to plaintext +func (f *Function) AfterFind(*gorm.DB) error { + var b abstract.FunctionConfig + switch f.Type { + case enum.FunctionTunnel: + b = &abstract.TunnelConfig{} + } + if b == nil { + return errors.New("xxxxxx") + } + err := json.Unmarshal([]byte(f.ConfigRaw), b) + if err != nil { + return err + } + f.Config = b + return nil +} diff --git a/pkg/api/models/provider.go b/pkg/api/models/model/provider.go similarity index 93% rename from pkg/api/models/provider.go rename to pkg/api/models/model/provider.go index 4f37dc3..f1c8d82 100644 --- a/pkg/api/models/provider.go +++ b/pkg/api/models/model/provider.go @@ -1,4 +1,4 @@ -package models +package model import ( "database/sql/driver" @@ -25,11 +25,10 @@ type Provider struct { StatusMessage *string `gorm:"not null"` MaxLimit *int `gorm:"not null"` - Info *ProviderInfo `gorm:"embedded"` - CloudAuth *CloudAuth `gorm:"embedded"` + Info *ProviderInfo `gorm:"embedded"` // 连表 - Tunnels []Tunnel `gorm:"foreignKey:ProviderId;references:ID"` + Tunnels []Function `gorm:"foreignKey:ProviderId;references:ID"` } type ProviderInfo struct { @@ -69,7 +68,7 @@ type ProviderCreateApi struct { Type *enum.ProviderType `json:"type"` // 认证信息 - CloudAuth *CloudAuth `json:"cloud_auth"` + CloudAuth *Account `json:"cloud_auth"` } func (pl ProviderList) ToApi() []*ProviderApi { diff --git a/pkg/api/models/proxy.go b/pkg/api/models/model/proxy.go similarity index 94% rename from pkg/api/models/proxy.go rename to pkg/api/models/model/proxy.go index bda983d..087dedd 100644 --- a/pkg/api/models/proxy.go +++ b/pkg/api/models/model/proxy.go @@ -1,7 +1,8 @@ -package models +package model import ( "fmt" + "strconv" "strings" "time" @@ -64,6 +65,11 @@ func (p Proxy) Addr() string { return strings.Join([]string{*p.ListenAddr, *p.ListenPort}, ":") } +func (p Proxy) Tag() string { + // 利用唯一性质计算 Tag + return strings.Join([]string{strconv.Itoa(int(p.ID)), *p.Name}, "-") +} + func (p Proxy) ProtoAddr() string { if *p.Type == enum.ProxyTypeAUTO || *p.Type == enum.ProxyTypeVmess || *p.Type == enum.ProxyTypeVless || *p.Type == enum.ProxyTypeShadowSocks { // 随便选好了 diff --git a/pkg/api/models/model/util.go b/pkg/api/models/model/util.go new file mode 100644 index 0000000..da3c5b1 --- /dev/null +++ b/pkg/api/models/model/util.go @@ -0,0 +1,90 @@ +package model + +import "reflect" + +// toApi 标准转化 API 方法 +func toApi(src interface{}, dst interface{}, extras ...func(api interface{})) interface{} { + copyReflect(src, dst) + // 自定义扩展 + for _, ex := range extras { + ex(dst) + } + return dst +} + +// toModel 标准转化 Model 方法 +func toModel(src interface{}, dst interface{}, full bool) interface{} { + copyReflect(src, dst) + if full { + // 实际上这里自动填充防止空指针,做了很多次的改动 + // 最终决定,只有 create 一个新对象时候是需要自动填充的, + // update 不要帮别人填充,null 就是 null + autoFull(dst) + } + return dst +} + +// full 用于填充一些字段防止数据库中出现空指针 +func autoFull(v interface{}) { + val := reflect.ValueOf(v).Elem() // 获取指向结构体的反射值对象 + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + + // 检查字段是否为指针并且为 nil + if field.Kind() == reflect.Ptr && field.IsNil() { + + fieldType := field.Type().Elem() // 获取指针指向的类型 + newField := reflect.New(fieldType) + + // 根据字段类型创建新的实例 + switch fieldType.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + newField.Elem().SetInt(0) // 设置为 0 + case reflect.Float32, reflect.Float64: + newField.Elem().SetFloat(0.0) // 设置为 0.0 + case reflect.String: + newField.Elem().SetString("") // 设置为空字符串 + // 可以根据需要添加更多类型 + default: + // todo: if find others kind in db + } + + field.Set(newField) + } + } +} + +// copyReflect 通过反射将相同的字段映射到对应的结构体中,减少重复的赋值动作 +func copyReflect(src interface{}, dst interface{}) { + srcVal := reflect.ValueOf(src) + if srcVal.Kind() == reflect.Ptr { + srcVal = srcVal.Elem() + } + + dstVal := reflect.ValueOf(dst) + if dstVal.Kind() == reflect.Ptr { + dstVal = dstVal.Elem() + } + + for i := 0; i < srcVal.NumField(); i++ { + srcField := srcVal.Field(i) + srcType := srcVal.Type().Field(i) + + // 如果字段是匿名的结构体(可能是嵌入的结构体),则递归处理 + if srcType.Anonymous && srcField.Kind() == reflect.Struct { + copyReflect(srcField.Interface(), dstVal.Addr().Interface()) + continue + } + + // 查找目标结构中相同名称的字段 + dstField := dstVal.FieldByName(srcType.Name) + if !dstField.IsValid() || !dstField.CanSet() { + continue // 目标中没有这个字段,或者该字段不能被设置 + } + + // 确保源和目标字段类型相同 + if dstField.Type() == srcField.Type() { + dstField.Set(srcField) + } + } +} diff --git a/pkg/api/models/models.go b/pkg/api/models/models.go index 191e4c8..0dd5ed9 100644 --- a/pkg/api/models/models.go +++ b/pkg/api/models/models.go @@ -1,98 +1,15 @@ package models -import "reflect" +import ( + "github.com/DVKunion/SeaMoon/pkg/api/models/model" +) func init() { - ModelList = append(ModelList, &Auth{}) - ModelList = append(ModelList, &Proxy{}) - ModelList = append(ModelList, &Tunnel{}) - ModelList = append(ModelList, &Provider{}) - ModelList = append(ModelList, &Config{}) + ModelList = append(ModelList, &model.Account{}) + ModelList = append(ModelList, &model.Proxy{}) + ModelList = append(ModelList, &model.Tunnel{}) + ModelList = append(ModelList, &model.Provider{}) + ModelList = append(ModelList, &model.Config{}) } var ModelList = make([]interface{}, 0) - -// toApi 标准转化 API 方法 -func toApi(src interface{}, dst interface{}, extras ...func(api interface{})) interface{} { - copyReflect(src, dst) - // 自定义扩展 - for _, ex := range extras { - ex(dst) - } - return dst -} - -// toModel 标准转化 Model 方法 -func toModel(src interface{}, dst interface{}, full bool) interface{} { - copyReflect(src, dst) - if full { - // 实际上这里自动填充防止空指针,做了很多次的改动 - // 最终决定,只有 create 一个新对象时候是需要自动填充的, - // update 不要帮别人填充,null 就是 null - autoFull(dst) - } - return dst -} - -// full 用于填充一些字段防止数据库中出现空指针 -func autoFull(v interface{}) { - val := reflect.ValueOf(v).Elem() // 获取指向结构体的反射值对象 - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - - // 检查字段是否为指针并且为 nil - if field.Kind() == reflect.Ptr && field.IsNil() { - - fieldType := field.Type().Elem() // 获取指针指向的类型 - newField := reflect.New(fieldType) - - // 根据字段类型创建新的实例 - switch fieldType.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - newField.Elem().SetInt(0) // 设置为 0 - case reflect.Float32, reflect.Float64: - newField.Elem().SetFloat(0.0) // 设置为 0.0 - case reflect.String: - newField.Elem().SetString("") // 设置为空字符串 - // 可以根据需要添加更多类型 - } - - field.Set(newField) - } - } -} - -// copyReflect 通过反射将相同的字段映射到对应的结构体中,减少重复的赋值动作 -func copyReflect(src interface{}, dst interface{}) { - srcVal := reflect.ValueOf(src) - if srcVal.Kind() == reflect.Ptr { - srcVal = srcVal.Elem() - } - - dstVal := reflect.ValueOf(dst) - if dstVal.Kind() == reflect.Ptr { - dstVal = dstVal.Elem() - } - - for i := 0; i < srcVal.NumField(); i++ { - srcField := srcVal.Field(i) - srcType := srcVal.Type().Field(i) - - // 如果字段是匿名的结构体(可能是嵌入的结构体),则递归处理 - if srcType.Anonymous && srcField.Kind() == reflect.Struct { - copyReflect(srcField.Interface(), dstVal.Addr().Interface()) - continue - } - - // 查找目标结构中相同名称的字段 - dstField := dstVal.FieldByName(srcType.Name) - if !dstField.IsValid() || !dstField.CanSet() { - continue // 目标中没有这个字段,或者该字段不能被设置 - } - - // 确保源和目标字段类型相同 - if dstField.Type() == srcField.Type() { - dstField.Set(srcField) - } - } -} diff --git a/pkg/api/service/account.go b/pkg/api/service/account.go new file mode 100644 index 0000000..1679b7b --- /dev/null +++ b/pkg/api/service/account.go @@ -0,0 +1,68 @@ +package service + +import ( + "context" + "errors" + + "github.com/DVKunion/SeaMoon/pkg/api/models" + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +var paramsMissingError = errors.New("missing important params") + +type account struct { +} + +func (a *account) Login(ctx context.Context, auth *models.Account) (string, error) { + //if auth.Username == "" || auth.Password == "" { + // return "", paramsMissingError + //} + + // 检查用户密码是否正确 + //hash := md5.New() + + // 写入数据到哈希实例中 + //hash.Write([]byte(auth.Password)) + + // 检查用户是否存在 + //data, err := dao.Q.Auth.WithContext(ctx).Where( + // dao.Q.Auth.Username.Eq(auth.Username), + // dao.Q.Auth.Password.Eq(strings.ToLower(hex.EncodeToString(hash.Sum(nil)))), + // dao.Q.Auth.Type.Eq(int8(enum.AuthAdmin)), + //).First() + + //if err != nil || data == nil { + // return "", err + //} + + //return tools.JWTAuth(auth.Username) + return "", nil +} + +func (a *account) CreateAuth(ctx context.Context, obj *models.Account) error { + //return dao.Q.WithContext(ctx).Create(obj) + return nil +} + +func (a *account) UpdatePassword(ctx context.Context, auth *models.Account) error { + /*if auth.Username == "" || auth.Password == "" { + return paramsMissingError + }*/ + + // 检查用户密码是否正确 + //hash := md5.New() + + // 写入数据到哈希实例中 + //hash.Write([]byte(auth.Password)) + // + //res, err := dao.Q.Auth.WithContext(ctx). + // Where(dao.Q.Auth.Username.Eq(auth.Username), dao.Q.Auth.Type.Eq(int8(enum.AuthAdmin))). + // Update(dao.Q.Auth.Password, strings.ToLower(hex.EncodeToString(hash.Sum(nil)))) + // + //if err != nil || res.Error != nil { + // return err + //} + tools.RollJWTSecret() + + return nil +} diff --git a/pkg/api/service/auth.go b/pkg/api/service/auth.go deleted file mode 100644 index 0e94358..0000000 --- a/pkg/api/service/auth.go +++ /dev/null @@ -1,71 +0,0 @@ -package service - -import ( - "context" - "crypto/md5" - "encoding/hex" - "errors" - "strings" - - "github.com/DVKunion/SeaMoon/pkg/api/database/dao" - "github.com/DVKunion/SeaMoon/pkg/api/enum" - "github.com/DVKunion/SeaMoon/pkg/api/models" - "github.com/DVKunion/SeaMoon/pkg/system/tools" -) - -var paramsMissingError = errors.New("missing important params") - -type auth struct { -} - -func (a *auth) Login(ctx context.Context, auth *models.AuthApi) (string, error) { - if auth.Username == "" || auth.Password == "" { - return "", paramsMissingError - } - - // 检查用户密码是否正确 - hash := md5.New() - - // 写入数据到哈希实例中 - hash.Write([]byte(auth.Password)) - - // 检查用户是否存在 - data, err := dao.Q.Auth.WithContext(ctx).Where( - dao.Q.Auth.Username.Eq(auth.Username), - dao.Q.Auth.Password.Eq(strings.ToLower(hex.EncodeToString(hash.Sum(nil)))), - dao.Q.Auth.Type.Eq(int8(enum.AuthAdmin)), - ).First() - - if err != nil || data == nil { - return "", err - } - - return tools.JWTAuth(auth.Username) -} - -func (a *auth) CreateAuth(ctx context.Context, obj *models.Auth) error { - return dao.Q.Auth.WithContext(ctx).Create(obj) -} - -func (a *auth) UpdatePassword(ctx context.Context, auth *models.AuthApi) error { - if auth.Username == "" || auth.Password == "" { - return paramsMissingError - } - - // 检查用户密码是否正确 - hash := md5.New() - - // 写入数据到哈希实例中 - hash.Write([]byte(auth.Password)) - - res, err := dao.Q.Auth.WithContext(ctx). - Where(dao.Q.Auth.Username.Eq(auth.Username), dao.Q.Auth.Type.Eq(int8(enum.AuthAdmin))). - Update(dao.Q.Auth.Password, strings.ToLower(hex.EncodeToString(hash.Sum(nil)))) - - if err != nil || res.Error != nil { - return err - } - tools.RollJWTSecret() - - return nil -} diff --git a/pkg/api/service/config.go b/pkg/api/service/config.go index b454d38..4efc4e1 100644 --- a/pkg/api/service/config.go +++ b/pkg/api/service/config.go @@ -5,6 +5,7 @@ import ( "github.com/DVKunion/SeaMoon/pkg/api/database/dao" "github.com/DVKunion/SeaMoon/pkg/api/models" + "github.com/DVKunion/SeaMoon/pkg/system/version" ) type config struct { @@ -12,7 +13,14 @@ type config struct { func (c *config) ListConfigs(ctx context.Context, page, size int) (models.ConfigList, error) { query := dao.Q.Config - return query.WithContext(ctx).Offset(page * size).Limit(size).Find() + data, err := query.WithContext(ctx).Offset(page * size).Limit(size).Find() + if err != nil { + return nil, err + } + data = append(data, &models.Config{Key: "version", Value: version.Version}) + data = append(data, &models.Config{Key: "commit", Value: version.Commit}) + data = append(data, &models.Config{Key: "xray", Value: version.XrayVersion}) + return data, nil } func (c *config) GetConfigByName(ctx context.Context, name string) (*models.Config, error) { diff --git a/pkg/api/service/service.go b/pkg/api/service/service.go index 1d90f14..447cfa0 100644 --- a/pkg/api/service/service.go +++ b/pkg/api/service/service.go @@ -4,39 +4,71 @@ import ( "context" "github.com/DVKunion/SeaMoon/pkg/api/database/drivers" + "github.com/DVKunion/SeaMoon/pkg/api/enum" "github.com/DVKunion/SeaMoon/pkg/api/models" + "github.com/DVKunion/SeaMoon/pkg/api/models/abstract" "github.com/DVKunion/SeaMoon/pkg/system/xlog" ) -var ( - SVC = &svc{ - &auth{}, - &config{}, - &provider{}, - &proxy{}, - &tunnel{}, - } - - // error list -) +var SVC *svc type svc struct { - *auth + *account *config *provider *proxy *tunnel } -func init() { +func Init() { + SVC = &svc{ + &account{}, + &config{}, + &provider{}, + &proxy{}, + &tunnel{}, + } drivers.RegisterMigrate(func() { xlog.Info(xlog.DatabaseConfigInit) - for _, conf := range models.DefaultConfig { + for _, conf := range defaultConfig { _ = SVC.CreateConfig(context.Background(), &conf) } xlog.Info(xlog.DatabaseUserInit) - for _, ca := range models.DefaultAuth { - _ = SVC.CreateAuth(context.Background(), &ca) + var ca = models.Account{ + Type: enum.Admin, + AuthType: enum.AdminAuth, + Auth: abstract.AdminAuth{ + Username: "seamoon", + Password: "2575a6f37310dd27e884a0305a2dd210", + }, } + _ = SVC.CreateAuth(context.Background(), &ca) }) } + +var defaultConfig = []models.Config{ + { + Key: "control_addr", + Value: "0.0.0.0", + }, + { + Key: "control_port", + Value: "7777", + }, + { + Key: "xray_api_port", + Value: "10085", + }, + { + Key: "control_log", + Value: "seamoon.log", + }, + { + Key: "auto_start", + Value: "true", + }, + { + Key: "auto_sync", + Value: "true", + }, +} diff --git a/pkg/api/signal/handler_proxy.go b/pkg/api/signal/handler_proxy.go index 8fceb6c..c8b0145 100644 --- a/pkg/api/signal/handler_proxy.go +++ b/pkg/api/signal/handler_proxy.go @@ -7,7 +7,6 @@ import ( "github.com/DVKunion/SeaMoon/pkg/api/enum" "github.com/DVKunion/SeaMoon/pkg/api/models" "github.com/DVKunion/SeaMoon/pkg/api/service" - "github.com/DVKunion/SeaMoon/pkg/network/listener" "github.com/DVKunion/SeaMoon/pkg/system/xlog" ) @@ -52,16 +51,17 @@ func (sb *Bus) proxyHandler(ctx context.Context, pys *proxySignal) { service.SVC.UpdateProxyStatus(ctx, pys.id, pys.next, "") switch pys.next { case enum.ProxyStatusActive, enum.ProxyStatusRecover: - sigCtx, cancel := context.WithCancel(ctx) - if server, err := listener.TCPListen(sigCtx, proxy); err != nil { - xlog.Error(xlog.SignalListenerError, "id", pys.id, "type", *proxy.Type, "addr", proxy.Addr(), "err", err) - service.SVC.UpdateProxyStatus(ctx, pys.id, enum.ProxyStatusError, err.Error()) - cancel() - return - } else { - sb.canceler[pys.id] = cancel - sb.listener[pys.id] = server - } + // 直接调用 xray grpc 接口 + //sigCtx, cancel := context.WithCancel(ctx) + //if server, err := listener.TCPListen(sigCtx, proxy); err != nil { + // xlog.Error(xlog.SignalListenerError, "id", pys.id, "type", *proxy.Type, "addr", proxy.Addr(), "err", err) + // service.SVC.UpdateProxyStatus(ctx, pys.id, enum.ProxyStatusError, err.Error()) + // cancel() + // return + //} else { + // sb.canceler[pys.id] = cancel + // sb.listener[pys.id] = server + //} xlog.Info(xlog.SignalStartProxy, "id", pys.id, "type", *proxy.Type, "addr", proxy.Addr()) service.SVC.UpdateProxyStatus(ctx, proxy.ID, enum.ProxyStatusActive, "") case enum.ProxyStatusInactive: @@ -80,18 +80,8 @@ func (sb *Bus) proxyHandler(ctx context.Context, pys *proxySignal) { } func (sb *Bus) stopProxy(proxy *models.Proxy) { - if cancel, ok := sb.canceler[proxy.ID]; ok { - // 先调一下 cancel - cancel() - if ln, exist := sb.listener[proxy.ID]; exist { - // 尝试着去停一下 ln, 防止泄漏 - err := ln.Close() - if err != nil { - // 错了就错了吧,说明 ctx 挂了一般 goroutines 也跟着挂了 - xlog.Error(xlog.SignalListenerError, "id", proxy.ID, "type", *proxy.Type, "addr", proxy.Addr(), "err", err) - } - } - } + // stop proxy + // xlog.Info(xlog.SignalStopProxy, "id", proxy.ID, "type", *proxy.Type, "addr", proxy.Addr()) } @@ -104,5 +94,4 @@ func (sb *Bus) deleteProxy(ctx context.Context, proxy *models.Proxy) { return } xlog.Info(xlog.SignalDeleteProxy, "id", proxy.ID, "type", *proxy.Type, "addr", proxy.Addr()) - } diff --git a/pkg/api/signal/signal.go b/pkg/api/signal/signal.go index 3334acf..b73a0cb 100644 --- a/pkg/api/signal/signal.go +++ b/pkg/api/signal/signal.go @@ -2,7 +2,6 @@ package signal import ( "context" - "net" "sync" "github.com/DVKunion/SeaMoon/pkg/api/enum" @@ -12,9 +11,6 @@ import ( // Bus 用于控制所有需要异步处理的状态转换 type Bus struct { - canceler map[uint]context.CancelFunc - listener map[uint]net.Listener - proxyChannel chan *proxySignal providerChannel chan *providerSignal tunnelChannel chan *tunnelSignal @@ -39,8 +35,6 @@ type tunnelSignal struct { } var signalBus = &Bus{ - canceler: make(map[uint]context.CancelFunc, 0), - listener: make(map[uint]net.Listener, 0), proxyChannel: make(chan *proxySignal, 1>>8), providerChannel: make(chan *providerSignal, 1>>8), tunnelChannel: make(chan *tunnelSignal, 1>>8), diff --git a/pkg/network/basic/addr.go b/pkg/network/basic/addr.go deleted file mode 100644 index 65a24c2..0000000 --- a/pkg/network/basic/addr.go +++ /dev/null @@ -1,162 +0,0 @@ -package basic - -import ( - "encoding/binary" - "net" - "strconv" - - "github.com/DVKunion/SeaMoon/pkg/system/errors" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -/* -Addr has following struct - - +------+----------+----------+ - | Type | ADDR | PORT | - +------+----------+----------+ - | 1 | Variable | 2 | - +------+----------+----------+ -*/ -type Addr struct { - Type uint8 - Host string - Port uint16 -} - -type ListenConfig struct { - net.ListenConfig -} - -func IsIPv4(address string) bool { - return address != "" && address[0] != ':' && address[0] != '[' -} - -// NewAddr creates an address object -func NewAddr(sa string) (addr *Addr, err error) { - host, sport, err := net.SplitHostPort(sa) - if err != nil { - return nil, err - } - port, err := strconv.Atoi(sport) - if err != nil { - return nil, err - } - - addr = NewAddrFromPair(host, port) - return -} - -// NewAddrFromPair creates an address object from host and port pair -func NewAddrFromPair(host string, port int) (addr *Addr) { - addr = &Addr{ - Type: AddrDomain, - Host: host, - Port: uint16(port), - } - - if ip := net.ParseIP(host); ip != nil { - if ip.To4() != nil { - addr.Type = AddrIPv4 - } else { - addr.Type = AddrIPv6 - } - } - - return -} - -// NewAddrFromAddr creates an address object -func NewAddrFromAddr(ln, conn net.Addr) (addr *Addr, err error) { - _, sport, err := net.SplitHostPort(ln.String()) - if err != nil { - return nil, err - } - host, _, err := net.SplitHostPort(conn.String()) - if err != nil { - return nil, err - } - port, err := strconv.Atoi(sport) - if err != nil { - return nil, err - } - - addr = NewAddrFromPair(host, port) - return -} - -// Decode an address from the stream -func (addr *Addr) Decode(b []byte) error { - addr.Type = b[0] - pos := 1 - switch addr.Type { - case AddrIPv4: - addr.Host = net.IP(b[pos : pos+net.IPv4len]).String() - pos += net.IPv4len - case AddrIPv6: - addr.Host = net.IP(b[pos : pos+net.IPv6len]).String() - pos += net.IPv6len - case AddrDomain: - addrlen := int(b[pos]) - pos++ - addr.Host = string(b[pos : pos+addrlen]) - pos += addrlen - default: - return errors.New(xlog.NetworkAddrTypeError) - } - - addr.Port = binary.BigEndian.Uint16(b[pos:]) - - return nil -} - -// Encode an address to the stream -func (addr *Addr) Encode(b []byte) (int, error) { - b[0] = addr.Type - pos := 1 - switch addr.Type { - case AddrIPv4: - ip4 := net.ParseIP(addr.Host).To4() - if ip4 == nil { - ip4 = net.IPv4zero.To4() - } - pos += copy(b[pos:], ip4) - case AddrDomain: - b[pos] = byte(len(addr.Host)) - pos++ - pos += copy(b[pos:], []byte(addr.Host)) - case AddrIPv6: - ip16 := net.ParseIP(addr.Host).To16() - if ip16 == nil { - ip16 = net.IPv6zero.To16() - } - pos += copy(b[pos:], ip16) - default: - b[0] = AddrIPv4 - copy(b[pos:pos+4], net.IPv4zero.To4()) - pos += 4 - } - binary.BigEndian.PutUint16(b[pos:], addr.Port) - pos += 2 - - return pos, nil -} - -// Length of the address -func (addr *Addr) Length() (n int) { - switch addr.Type { - case AddrIPv4: - n = 10 - case AddrIPv6: - n = 22 - case AddrDomain: - n = 7 + len(addr.Host) - default: - n = 10 - } - return -} - -func (addr *Addr) String() string { - return net.JoinHostPort(addr.Host, strconv.Itoa(int(addr.Port))) -} diff --git a/pkg/network/basic/auth.go b/pkg/network/basic/auth.go deleted file mode 100644 index fb8b239..0000000 --- a/pkg/network/basic/auth.go +++ /dev/null @@ -1,61 +0,0 @@ -package basic - -import ( - "crypto/subtle" - "encoding/base64" - "strings" -) - -// StrEQ returns whether s1 and s2 are equal -func StrEQ(s1, s2 string) bool { - return subtle.ConstantTimeCompare([]byte(s1), []byte(s2)) == 1 -} - -// StrInSlice return whether str in slice -func StrInSlice(str string, slice []string) bool { - for _, s := range slice { - if s == str { - return true - } - } - return false -} - -// VerifyByMap returns an verifier that verify by an username-password map -func VerifyByMap(users map[string]string) func(string, string) bool { - return func(username, password string) bool { - pw, ok := users[username] - if !ok { - return false - } - return StrEQ(pw, password) - } -} - -// VerifyByHtpasswd returns a verifier that verify by a htpasswd file -//func VerifyByHtpasswd(users string) func(string, string) bool { -// f, err := htpasswd.New(users, htpasswd.DefaultSystems, nil) -// if err != nil { -// xlog.Error("Load htpasswd file failed", "err", err) -// } -// return func(username, password string) bool { -// return f.Match(username, password) -// } -//} - -func HttpBasicAuth(auth string, verify func(string, string) bool) bool { - prefix := "Basic " - if !strings.HasPrefix(auth, prefix) { - return false - } - auth = strings.Trim(auth[len(prefix):], " ") - dc, err := base64.StdEncoding.DecodeString(auth) - if err != nil { - return false - } - groups := strings.Split(string(dc), ":") - if len(groups) != 2 { - return false - } - return verify(groups[0], groups[1]) -} diff --git a/pkg/network/basic/buffer.go b/pkg/network/basic/buffer.go deleted file mode 100644 index 69e49c2..0000000 --- a/pkg/network/basic/buffer.go +++ /dev/null @@ -1,140 +0,0 @@ -package basic - -// fork from go-gost/core - -import ( - "bufio" - "net" - "sync" -) - -type BufferedConn struct { - net.Conn - Br *bufio.Reader -} - -func (c *BufferedConn) Read(b []byte) (int, error) { - return c.Br.Read(b) -} - -func (c *BufferedConn) Peek(n int) ([]byte, error) { - return c.Br.Peek(n) -} - -var ( - pools = []struct { - size int - pool sync.Pool - }{ - { - size: 128, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 128) - return b - }, - }, - }, - { - size: 512, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 512) - return b - }, - }, - }, - { - size: 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 1024) - return b - }, - }, - }, - { - size: 2048, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 2048) - return b - }, - }, - }, - { - size: 4096, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 4096) - return b - }, - }, - }, - { - size: 8192, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 8192) - return b - }, - }, - }, - { - size: 16 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 16*1024) - return b - }, - }, - }, - { - size: 32 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 32*1024) - return b - }, - }, - }, - { - size: 64 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 64*1024) - return b - }, - }, - }, - { - size: 65 * 1024, - pool: sync.Pool{ - New: func() any { - b := make([]byte, 65*1024) - return b - }, - }, - }, - } -) - -// GetBuffer returns a buffer of specified size. -func GetBuffer(size int) []byte { - for i := range pools { - if size <= pools[i].size { - b := pools[i].pool.Get().([]byte) - return b[:size] - } - } - b := make([]byte, size) - return b -} - -func PutBuffer(b []byte) { - for i := range pools { - if cap(b) == pools[i].size { - pools[i].pool.Put(b) - } - } -} diff --git a/pkg/network/basic/socks5.go b/pkg/network/basic/socks5.go deleted file mode 100644 index cc2d0c0..0000000 --- a/pkg/network/basic/socks5.go +++ /dev/null @@ -1,596 +0,0 @@ -package basic - -// This file is modified version from https://github.com/ginuerzh/gosocks5/blob/master/socks5.go - -import ( - "bytes" - "encoding/binary" - "fmt" - "io" - "io/ioutil" - - "github.com/DVKunion/SeaMoon/pkg/system/errors" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -// Address types -const ( - AddrIPv4 uint8 = 1 - AddrDomain = 3 - AddrIPv6 = 4 -) - -// SOCKS5 Version = 5 -const ( - SOCKS5Version = 5 - SOCKS5UserPassVer = 1 -) - -// Methods -const ( - MethodNoAuth uint8 = iota - MethodGSSAPI - MethodUserPass - MethodNoAcceptable uint8 = 0xFF -) - -// SOCKS5 Commands -const ( - SOCKS5CmdConnect uint8 = iota + 1 - SOCKS5CmdBind - SOCKS5CmdUDP - SOCKS5CmdUDPOverTCP -) - -// SOCKS5 Response codes -const ( - SOCKS5RespSucceeded uint8 = iota - SOCKS5RespFailure - SOCKS5RespAllowed - SOCKS5RespNetUnreachable - SOCKS5RespHostUnreachable - SOCKS5RespConnRefused - SOCKS5RespTTLExpired - SOCKS5RespCmdUnsupported - SOCKS5RespAddrUnsupported -) - -const ( - smallSize = 576 - largeSize = 32 * 1024 -) - -/* -ReadMethods returns methods -Method selection - - +----+----------+----------+ - |VER | NMETHODS | METHODS | - +----+----------+----------+ - | 1 | 1 | 1 to 255 | - +----+----------+----------+ -*/ -func ReadMethods(r io.Reader) ([]uint8, error) { - b := GetBuffer(smallSize) - defer PutBuffer(b) - - n, err := io.ReadAtLeast(r, b, 2) - if err != nil { - return nil, err - } - - if b[0] != SOCKS5Version { - return nil, errors.New(xlog.NetworkVersionError) - } - - if b[1] == 0 { - return nil, errors.New(xlog.NetworkMethodError) - } - - length := 2 + int(b[1]) - if n < length { - if _, err := io.ReadFull(r, b[n:length]); err != nil { - return nil, err - } - } - - methods := make([]byte, int(b[1])) - copy(methods, b[2:length]) - - return methods, nil -} - -// WriteMethod send the selected method to the client -func WriteMethod(method uint8, w io.Writer) error { - _, err := w.Write([]byte{SOCKS5Version, method}) - return err -} - -// WriteMethods send method select request to the server -func WriteMethods(methods []uint8, w io.Writer) error { - b := make([]byte, 2+len(methods)) - b[0] = SOCKS5Version - b[1] = uint8(len(methods)) - copy(b[2:], methods) - - _, err := w.Write(b) - return err -} - -/* -UserPassRequest Username/Password authentication request - - +----+------+----------+------+----------+ - |VER | ULEN | UNAME | PLEN | PASSWD | - +----+------+----------+------+----------+ - | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - +----+------+----------+------+----------+ -*/ -type UserPassRequest struct { - Version byte - Username string - Password string -} - -func NewUserPassRequest(ver byte, u, p string) *UserPassRequest { - return &UserPassRequest{ - Version: ver, - Username: u, - Password: p, - } -} - -func ReadUserPassRequest(r io.Reader) (*UserPassRequest, error) { - b := GetBuffer(smallSize) - defer PutBuffer(b) - - n, err := io.ReadAtLeast(r, b, 2) - if err != nil { - return nil, err - } - - if b[0] != SOCKS5UserPassVer { - return nil, errors.New(xlog.NetworkVersionError) - } - - req := &UserPassRequest{ - Version: b[0], - } - - ulen := int(b[1]) - length := ulen + 3 - - if n < length { - if _, err := io.ReadFull(r, b[n:length]); err != nil { - return nil, err - } - n = length - } - req.Username = string(b[2 : 2+ulen]) - - plen := int(b[length-1]) - length += plen - if n < length { - if _, err := io.ReadFull(r, b[n:length]); err != nil { - return nil, err - } - } - req.Password = string(b[3+ulen : length]) - return req, nil -} - -func (req *UserPassRequest) Write(w io.Writer) error { - // b := make([]byte, 513) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - b[0] = req.Version - ulen := len(req.Username) - b[1] = byte(ulen) - length := 2 + ulen - copy(b[2:length], req.Username) - - plen := len(req.Password) - b[length] = byte(plen) - length++ - copy(b[length:length+plen], req.Password) - length += plen - - _, err := w.Write(b[:length]) - return err -} - -func (req *UserPassRequest) String() string { - return fmt.Sprintf("%d %s:%s", - req.Version, req.Username, req.Password) -} - -/* -UserPassResponse Username/Password authentication response - - +----+--------+ - |VER | STATUS | - +----+--------+ - | 1 | 1 | - +----+--------+ -*/ -type UserPassResponse struct { - Version byte - Status byte -} - -func NewUserPassResponse(ver, status byte) *UserPassResponse { - return &UserPassResponse{ - Version: ver, - Status: status, - } -} - -func ReadUserPassResponse(r io.Reader) (*UserPassResponse, error) { - // b := make([]byte, 2) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - if _, err := io.ReadFull(r, b[:2]); err != nil { - return nil, err - } - - if b[0] != SOCKS5UserPassVer { - return nil, errors.New(xlog.NetworkVersionError) - } - - res := &UserPassResponse{ - Version: b[0], - Status: b[1], - } - - return res, nil -} - -func (res *UserPassResponse) Write(w io.Writer) error { - _, err := w.Write([]byte{res.Version, res.Status}) - return err -} - -func (res *UserPassResponse) String() string { - return fmt.Sprintf("%d %d", - res.Version, res.Status) -} - -/* -SOCKS5Request represent a socks5 request -The SOCKSv5 request - - +----+-----+-------+------+----------+----------+ - |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ -*/ -type SOCKS5Request struct { - Cmd uint8 - Addr *Addr -} - -// NewSOCKS5Request creates an request object -func NewSOCKS5Request(cmd uint8, addr *Addr) *SOCKS5Request { - return &SOCKS5Request{ - Cmd: cmd, - Addr: addr, - } -} - -// ReadSOCKS5Request reads request from the stream -func ReadSOCKS5Request(r io.Reader) (*SOCKS5Request, error) { - // b := make([]byte, 262) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - n, err := io.ReadAtLeast(r, b, 5) - if err != nil { - return nil, err - } - - if b[0] != SOCKS5Version { - return nil, errors.New(xlog.NetworkVersionError) - } - - request := &SOCKS5Request{ - Cmd: b[1], - } - - atype := b[3] - length := 0 - switch atype { - case AddrIPv4: - length = 10 - case AddrIPv6: - length = 22 - case AddrDomain: - length = 7 + int(b[4]) - default: - return nil, errors.New(xlog.NetworkAddrTypeError) - } - - if n < length { - if _, err := io.ReadFull(r, b[n:length]); err != nil { - return nil, err - } - } - addr := new(Addr) - if err := addr.Decode(b[3:length]); err != nil { - return nil, err - } - request.Addr = addr - - return request, nil -} - -func (r *SOCKS5Request) Write(w io.Writer) (err error) { - //b := make([]byte, 262) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - b[0] = SOCKS5Version - b[1] = r.Cmd - b[2] = 0 //rsv - b[3] = AddrIPv4 // default - - addr := r.Addr - if addr == nil { - addr = &Addr{} - } - n, _ := addr.Encode(b[3:]) - length := 3 + n - - _, err = w.Write(b[:length]) - return -} - -func (r *SOCKS5Request) String() string { - addr := r.Addr - if addr == nil { - addr = &Addr{} - } - return fmt.Sprintf("5 %d 0 %d %s", - r.Cmd, addr.Type, addr.String()) -} - -/* -Reply is a SOCKSv5 reply - - +----+-----+-------+------+----------+----------+ - |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | - +----+-----+-------+------+----------+----------+ - | 1 | 1 | X'00' | 1 | Variable | 2 | - +----+-----+-------+------+----------+----------+ -*/ -type Reply struct { - Rep uint8 - Addr *Addr -} - -// NewReply creates a socks5 reply -func NewReply(rep uint8, addr *Addr) *Reply { - return &Reply{ - Rep: rep, - Addr: addr, - } -} - -// ReadReply reads a reply from the stream -func ReadReply(r io.Reader) (*Reply, error) { - // b := make([]byte, 262) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - n, err := io.ReadAtLeast(r, b, 5) - if err != nil { - return nil, err - } - - if b[0] != SOCKS5Version { - return nil, errors.New(xlog.NetworkVersionError) - } - - reply := &Reply{ - Rep: b[1], - } - - atype := b[3] - length := 0 - switch atype { - case AddrIPv4: - length = 10 - case AddrIPv6: - length = 22 - case AddrDomain: - length = 7 + int(b[4]) - default: - return nil, errors.New(xlog.NetworkAddrTypeError) - } - - if n < length { - if _, err := io.ReadFull(r, b[n:length]); err != nil { - return nil, err - } - } - - addr := new(Addr) - if err := addr.Decode(b[3:length]); err != nil { - return nil, err - } - reply.Addr = addr - - return reply, nil -} - -func (r *Reply) Write(w io.Writer) (err error) { - // b := make([]byte, 262) - b := GetBuffer(smallSize) - defer PutBuffer(b) - - b[0] = SOCKS5Version - b[1] = r.Rep - b[2] = 0 //rsv - b[3] = AddrIPv4 // default - length := 10 - b[4], b[5], b[6], b[7], b[8], b[9] = 0, 0, 0, 0, 0, 0 // reset address field - - if r.Addr != nil { - n, _ := r.Addr.Encode(b[3:]) - length = 3 + n - } - _, err = w.Write(b[:length]) - - return -} - -func (r *Reply) String() string { - addr := r.Addr - if addr == nil { - addr = &Addr{} - } - return fmt.Sprintf("5 %d 0 %d %s", - r.Rep, addr.Type, addr.String()) -} - -/* -UDPHeader is the header of an UDP request - - +----+------+------+----------+----------+----------+ - |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - +----+------+------+----------+----------+----------+ - | 2 | 1 | 1 | Variable | 2 | Variable | - +----+------+------+----------+----------+----------+ -*/ -type UDPHeader struct { - Rsv uint16 - Frag uint8 - Addr *Addr -} - -// NewUDPHeader creates an UDPHeader -func NewUDPHeader(rsv uint16, frag uint8, addr *Addr) *UDPHeader { - return &UDPHeader{ - Rsv: rsv, - Frag: frag, - Addr: addr, - } -} - -func (h *UDPHeader) Write(w io.Writer) error { - b := GetBuffer(smallSize) - defer PutBuffer(b) - - binary.BigEndian.PutUint16(b[:2], h.Rsv) - b[2] = h.Frag - - addr := h.Addr - if addr == nil { - addr = &Addr{} - } - length, _ := addr.Encode(b[3:]) - - _, err := w.Write(b[:3+length]) - return err -} - -func (h *UDPHeader) String() string { - return fmt.Sprintf("%d %d %d %s", - h.Rsv, h.Frag, h.Addr.Type, h.Addr.String()) -} - -// UDPDatagram represent an UDP request -type UDPDatagram struct { - Header *UDPHeader - Data []byte -} - -// NewUDPDatagram creates an UDPDatagram -func NewUDPDatagram(header *UDPHeader, data []byte) *UDPDatagram { - return &UDPDatagram{ - Header: header, - Data: data, - } -} - -// ReadUDPDatagram reads an UDPDatagram from the stream -func ReadUDPDatagram(r io.Reader) (*UDPDatagram, error) { - b := GetBuffer(largeSize) - defer PutBuffer(b) - - // when r is a streaming (such as TCP connection), we may read more than the required data, - // but we don't know how to handle it. So we use io.ReadFull to instead of io.ReadAtLeast - // to make sure that no redundant data will be discarded. - n, err := io.ReadFull(r, b[:5]) - if err != nil { - return nil, err - } - - header := &UDPHeader{ - Rsv: binary.BigEndian.Uint16(b[:2]), - Frag: b[2], - } - - atype := b[3] - hlen := 0 - switch atype { - case AddrIPv4: - hlen = 10 - case AddrIPv6: - hlen = 22 - case AddrDomain: - hlen = 7 + int(b[4]) - default: - return nil, errors.New(xlog.NetworkAddrTypeError) - } - - dlen := int(header.Rsv) - if dlen == 0 { // standard SOCKS5 UDP datagram - extra, err := ioutil.ReadAll(r) // we assume no redundant data - if err != nil { - return nil, err - } - copy(b[n:], extra) - n += len(extra) // total length - dlen = n - hlen // data length - } else { // extended feature, for UDP over TCP, using reserved field as data length - if _, err := io.ReadFull(r, b[n:hlen+dlen]); err != nil { - return nil, err - } - n = hlen + dlen - } - - header.Addr = new(Addr) - if err := header.Addr.Decode(b[3:hlen]); err != nil { - return nil, err - } - - data := make([]byte, dlen) - copy(data, b[hlen:n]) - - d := &UDPDatagram{ - Header: header, - Data: data, - } - - return d, nil -} - -func (d *UDPDatagram) Write(w io.Writer) error { - h := d.Header - if h == nil { - h = &UDPHeader{} - } - buf := bytes.Buffer{} - if err := h.Write(&buf); err != nil { - return err - } - if _, err := buf.Write(d.Data); err != nil { - return err - } - - _, err := buf.WriteTo(w) - return err -} diff --git a/pkg/network/basic/transport.go b/pkg/network/basic/transport.go deleted file mode 100644 index 03126b7..0000000 --- a/pkg/network/basic/transport.go +++ /dev/null @@ -1,75 +0,0 @@ -package basic - -import ( - "io" - "net" - "sync" - - "github.com/gorilla/websocket" -) - -const bufferSize = 64 * 1024 - -// Transport rw1 and rw2 -func Transport(src, dest net.Conn) (int64, int64, error) { - // 这是第一版本的老代码,是可以满足需求但是很丑陋 - errIn := make(chan error, 1) - errOut := make(chan error, 1) - done := make(chan error, 1<<8) - - var wg sync.WaitGroup - var mu sync.Mutex // 用于保护下面的共享变量 - - var inbound int64 = 0 - var outbound int64 = 0 - - wg.Add(2) - go func() { - defer wg.Done() - w, err := CopyBuffer(src, dest, bufferSize) - mu.Lock() - inbound += w - mu.Unlock() - errIn <- err - }() - - go func() { - defer wg.Done() - w, err := CopyBuffer(dest, src, bufferSize) - mu.Lock() - outbound += w - mu.Unlock() - errOut <- err - }() - - for { - select { - case e := <-errIn: - src.Close() - dest.Close() - done <- e - case e := <-errOut: - src.Close() - dest.Close() - done <- e - case e := <-done: - wg.Wait() - // 忽略 websocket 正常断开 - if opErr, ok := e.(*net.OpError); ok { - if closeErr, ok := opErr.Err.(*websocket.CloseError); ok { - if closeErr.Code == websocket.CloseNormalClosure || closeErr.Code == websocket.CloseAbnormalClosure { - e = nil - } - } - } - return inbound, outbound, e - } - } -} - -func CopyBuffer(dst io.Writer, src io.Reader, bufSize int) (int64, error) { - buf := GetBuffer(bufSize) - defer PutBuffer(buf) - - return io.CopyBuffer(dst, src, buf) -} diff --git a/pkg/network/listener/tcp.go b/pkg/network/listener/tcp.go deleted file mode 100644 index 95370ef..0000000 --- a/pkg/network/listener/tcp.go +++ /dev/null @@ -1,114 +0,0 @@ -package listener - -import ( - "context" - "net" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" - "github.com/DVKunion/SeaMoon/pkg/api/models" - db_service "github.com/DVKunion/SeaMoon/pkg/api/service" - "github.com/DVKunion/SeaMoon/pkg/network/basic" - "github.com/DVKunion/SeaMoon/pkg/network/transfer" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel/service" - "github.com/DVKunion/SeaMoon/pkg/system/errors" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -func TCPListen(ctx context.Context, py *models.Proxy) (net.Listener, error) { - server, err := net.Listen("tcp", py.Addr()) - if err != nil { - return nil, err - } - tun, err := db_service.SVC.GetTunnelById(ctx, py.TunnelID) - if err != nil { - return nil, err - } - switch *py.Type { - case enum.ProxyTypeAUTO, enum.ProxyTypeHTTP, enum.ProxyTypeSOCKS5: - go listen(ctx, server, py.ID, py.Type, tun) - case enum.ProxyTypeShadowSocks, enum.ProxyTypeVmess, enum.ProxyTypeVless: - go v2rayListen(ctx, server, py.ID, py.Type, tun) - } - return server, nil -} - -func listen(ctx context.Context, server net.Listener, id uint, t *enum.ProxyType, tun *models.Tunnel) { - for { - conn, err := server.Accept() - if err != nil { - if errors.Is(err, net.ErrClosed) { - // 说明是 server 被外部 close 掉了,导致了此处的 accept 报错 - // 正常现象,return 即可。 - return - } else { - // 除此之外,都为异常。为了保证服务正常不出现 panic 和空指针,跳过该 conn - xlog.Error(xlog.ListenerAcceptError, "err", err) - continue - } - } - db_service.SVC.UpdateProxyConn(ctx, id, 1) - - if srv, ok := service.Factory.Load(*tun.Type); ok { - destConn, err := srv.(service.Service).Conn(ctx, *t, - service.WithAddr(tun.GetAddr()), service.WithTorFlag(tun.Config.Tor)) - if err != nil { - xlog.Error(xlog.ListenerDailError, "err", err) - db_service.SVC.UpdateProxyConn(ctx, id, -1) - continue - } - go func() { - in, out, err := basic.Transport(conn, destConn) - if err != nil { - xlog.Error(xlog.NetworkTransportError, "err", err) - } - db_service.SVC.UpdateProxyConn(ctx, id, -1) - db_service.SVC.UpdateProxyNetworkInfo(ctx, id, in, out) - }() - go func() { - db_service.SVC.UpdateProxyNetworkLag(ctx, id, destConn.Delay()) - }() - } - } -} - -// 懒得写了,直接套一个 v2ray 的客户端去做 wrapper 原本的conn完事了 -func v2rayListen(ctx context.Context, server net.Listener, id uint, t *enum.ProxyType, tun *models.Tunnel) { - config := transfer.NewV2rayConfig( - transfer.WithClientMod(), - transfer.WithNetAddr(*tun.Addr, func() uint32 { - if tun.Config.TLS { - return 443 - } - return 80 - }()), - transfer.WithTunnelType(t.String(), *tun.Type), - transfer.WithAuthInfo(tun.Config.V2rayUid, tun.Config.SSRCrypt, tun.Config.SSRPass), - transfer.WithExtra(tun.Config.Tor, tun.Config.TLS), - ) - err := transfer.Init(config) - if err != nil { - xlog.Error(xlog.ListenerV2rayInitError, "err", err) - return - } - for { - conn, err := server.Accept() - if err != nil { - if errors.Is(err, net.ErrClosed) { - // 说明是 server 被外部 close 掉了,导致了此处的 accept 报错 - // 正常现象,return 即可。 - return - } else { - // 除此之外,都为异常。为了保证服务正常不出现 panic 和空指针,跳过该 conn - xlog.Error(xlog.ListenerAcceptError, "err", err) - continue - } - } - db_service.SVC.UpdateProxyConn(ctx, id, 1) - go func() { - defer db_service.SVC.UpdateProxyConn(ctx, id, -1) - if err := transfer.AutoTransportV2ray(conn); err != nil { - xlog.Error(xlog.ListenerV2rayTransportError, "err", err) - } - }() - } -} diff --git a/pkg/network/transfer/auto.go b/pkg/network/transfer/auto.go deleted file mode 100644 index 3ad2d7a..0000000 --- a/pkg/network/transfer/auto.go +++ /dev/null @@ -1,31 +0,0 @@ -package transfer - -import ( - "bufio" - "net" - - "github.com/DVKunion/SeaMoon/pkg/network/basic" -) - -// AutoTransport 自适应解析 http / socks -func AutoTransport(conn net.Conn) error { - br := &basic.BufferedConn{Conn: conn, Br: bufio.NewReader(conn)} - b, err := br.Peek(1) - - if err != nil || b[0] != basic.SOCKS5Version { - return HttpTransport(br) - } - - return Socks5Transport(br, true) -} - -func AutoTransportV2ray(conn net.Conn) error { - br := &basic.BufferedConn{Conn: conn, Br: bufio.NewReader(conn)} - b, err := br.Peek(1) - - if err != nil || b[0] != basic.SOCKS5Version { - return V2rayTransport(br, "http") - } - - return V2rayTransport(br, "socks5") -} diff --git a/pkg/network/transfer/http.go b/pkg/network/transfer/http.go deleted file mode 100644 index 7f277d8..0000000 --- a/pkg/network/transfer/http.go +++ /dev/null @@ -1,72 +0,0 @@ -package transfer - -import ( - "bufio" - "net" - "net/http" - - "github.com/DVKunion/SeaMoon/pkg/network/basic" -) - -type HttpTransfer struct { -} - -func UnWrapper() { - -} - -func HttpTransport(conn net.Conn) error { - // 接收客户端的连接,并从第一条消息中获取目标地址 - request, err := http.ReadRequest(bufio.NewReader(conn)) - if err != nil { - return err - } - - defer request.Body.Close() - - targetAddr := request.Host - - if targetAddr == "" || err != nil { - return err - } - - if _, port, _ := net.SplitHostPort(targetAddr); port == "" { - targetAddr = net.JoinHostPort(targetAddr, "80") - } - - // 连接到目标服务器 - destConn, err := net.Dial("tcp", targetAddr) - if err != nil { - return err - } - - defer destConn.Close() - - resp := &http.Response{ - ProtoMajor: 1, - ProtoMinor: 1, - } - if resp.Header == nil { - resp.Header = http.Header{} - } - - if request.Method == http.MethodConnect { - resp.StatusCode = http.StatusOK - resp.Status = "200 Connection established" - - if err = resp.Write(conn); err != nil { - return err - } - } else { - if err = request.Write(destConn); err != nil { - return err - } - } - - // 同时处理客户端到服务器和服务器到客户端的数据传输 - if _, _, err := basic.Transport(destConn, conn); err != nil { - return err - } - - return nil -} diff --git a/pkg/network/transfer/socks5.go b/pkg/network/transfer/socks5.go deleted file mode 100644 index 866d03a..0000000 --- a/pkg/network/transfer/socks5.go +++ /dev/null @@ -1,97 +0,0 @@ -package transfer - -import ( - "bufio" - "net" - "time" - - "github.com/DVKunion/SeaMoon/pkg/network/basic" - "github.com/DVKunion/SeaMoon/pkg/system/errors" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -func Socks5Check(conn net.Conn) (net.Conn, error) { - br := &basic.BufferedConn{Conn: conn, Br: bufio.NewReader(conn)} - b, err := br.Peek(1) - - if err != nil || b[0] != basic.SOCKS5Version { - return nil, errors.Wrap(err, xlog.ServiceProtocolNotSupportError) - } - return br, nil -} - -func Socks5Transport(conn net.Conn, check bool) error { - - var err error - if !check { - if conn, err = Socks5Check(conn); err != nil { - return err - } - } - // todo AUTH - - // select method - if _, err = basic.ReadMethods(conn); err != nil { - return errors.Wrap(err, xlog.ServiceSocks5ReadMethodError) - } - - if err = basic.WriteMethod(basic.MethodNoAuth, conn); err != nil { - return errors.Wrap(err, xlog.ServiceSocks5WriteMethodError) - } - - // read command - request, err := basic.ReadSOCKS5Request(conn) - if err != nil { - return errors.Wrap(err, xlog.ServiceSocks5ReadCmdError) - } - switch request.Cmd { - case basic.SOCKS5CmdConnect: - handleConnect(conn, request) - case basic.SOCKS5CmdBind: - // todo: support cmd bind - xlog.Debug("unexpect not support cmd bind") - handleBind(conn, request) - case basic.SOCKS5CmdUDPOverTCP: - // todo: support upd proxy - xlog.Debug("unexpect not support upd") - handleUDPOverTCP(conn, request) - } - - return nil -} - -func handleConnect(conn net.Conn, req *basic.SOCKS5Request) { - xlog.Info(xlog.ServiceSocks5ConnectServer, "src", conn.RemoteAddr(), "dest", req.Addr) - // default socks timeout : 10 - dialer := net.Dialer{Timeout: 10 * time.Second} - destConn, err := dialer.Dial("tcp", req.Addr.String()) - - if err != nil { - xlog.Error(xlog.ServiceSocks5DailError, "err", err) - return - } - - // if utils.Transport get out , then close conn of remote - defer destConn.Close() - - if err := basic.NewReply(basic.SOCKS5RespSucceeded, nil).Write(conn); err != nil { - xlog.Error(xlog.ServiceSocks5ReplyError, "err", err) - return - } - - xlog.Info(xlog.ServiceSocks5Establish, "src", conn.RemoteAddr(), "dest", req.Addr) - - if _, _, err := basic.Transport(conn, destConn); err != nil { - xlog.Error(xlog.NetworkTransportError, "err", err) - } - - xlog.Info(xlog.ServiceSocks5DisConnect, "src", conn.RemoteAddr(), "dest", req.Addr) -} - -func handleBind(conn net.Conn, req *basic.SOCKS5Request) { - // TODO -} - -func handleUDPOverTCP(conn net.Conn, req *basic.SOCKS5Request) { - // TODO -} diff --git a/pkg/network/transfer/tor.go b/pkg/network/transfer/tor.go deleted file mode 100644 index 2e0d84d..0000000 --- a/pkg/network/transfer/tor.go +++ /dev/null @@ -1,33 +0,0 @@ -package transfer - -import ( - "net" - "time" - - "github.com/DVKunion/SeaMoon/pkg/network/basic" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -const defaultTorAddr = "127.0.0.1:9050" - -func TorTransport(conn net.Conn) error { - // tor 转发非常简单,但是要求入口流量必须是一个 s5,然后直接把 s5 的口子转发给 tor 服务即可。 - dialer := net.Dialer{Timeout: 10 * time.Second} - destConn, err := dialer.Dial("tcp", defaultTorAddr) - - if err != nil { - return err - } - - defer destConn.Close() - - xlog.Info(xlog.ServiceTorConnectServer, "src", conn.RemoteAddr(), "dest", defaultTorAddr) - - if _, _, err := basic.Transport(conn, destConn); err != nil { - xlog.Error(xlog.NetworkTransportError, "err", err) - } - - xlog.Info(xlog.ServiceTorDisConnect, "src", conn.RemoteAddr(), "dest", defaultTorAddr) - - return nil -} diff --git a/pkg/network/transfer/v2ray.go b/pkg/network/transfer/v2ray.go deleted file mode 100644 index 52d8fbf..0000000 --- a/pkg/network/transfer/v2ray.go +++ /dev/null @@ -1,79 +0,0 @@ -package transfer - -import ( - "context" - - core "github.com/v2fly/v2ray-core/v5" - "github.com/v2fly/v2ray-core/v5/app/dispatcher" - pinboud "github.com/v2fly/v2ray-core/v5/app/proxyman/inbound" - "github.com/v2fly/v2ray-core/v5/common/errors" - "github.com/v2fly/v2ray-core/v5/common/net" - "github.com/v2fly/v2ray-core/v5/common/session" - "github.com/v2fly/v2ray-core/v5/features/inbound" - "github.com/v2fly/v2ray-core/v5/features/routing" - - _ "github.com/v2fly/v2ray-core/v5/app/dispatcher" - _ "github.com/v2fly/v2ray-core/v5/app/proxyman/inbound" - _ "github.com/v2fly/v2ray-core/v5/app/proxyman/outbound" - - _ "github.com/v2fly/v2ray-core/v5/proxy/freedom" - _ "github.com/v2fly/v2ray-core/v5/proxy/http" - _ "github.com/v2fly/v2ray-core/v5/proxy/shadowsocks" - _ "github.com/v2fly/v2ray-core/v5/proxy/socks" - _ "github.com/v2fly/v2ray-core/v5/proxy/vless/inbound" - _ "github.com/v2fly/v2ray-core/v5/proxy/vless/outbound" - _ "github.com/v2fly/v2ray-core/v5/proxy/vmess/inbound" - _ "github.com/v2fly/v2ray-core/v5/proxy/vmess/outbound" - - _ "github.com/v2fly/v2ray-core/v5/proxy/shadowsocks2022" - - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -func Init(cfg *v2rayConfig) error { - config, err := cfg.Build() - if err != nil { - return err - } - v2ray, err = core.New(config) - return err -} - -// V2rayTransport v2ray 相关协议支持: vmess / vless / shadowsock -func V2rayTransport(conn net.Conn, proto string) error { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - manager := v2ray.GetFeature(inbound.ManagerType()).(inbound.Manager) - handler, err := manager.GetHandler(ctx, handleTag+proto) - if err != nil { - return err - } - worker := handler.(*pinboud.AlwaysOnInboundHandler).GetInbound() - - sid := session.NewID() - ctx = session.ContextWithID(ctx, sid) - ctx = session.ContextWithInbound(ctx, &session.Inbound{ - Source: net.DestinationFromAddr(conn.RemoteAddr()), - Tag: handleTag + proto, - }) - - content := new(session.Content) - ctx = session.ContextWithContent(ctx, content) - - dispatch := v2ray.GetFeature(routing.DispatcherType()).(*dispatcher.DefaultDispatcher) - if err = worker.Process(ctx, net.Network_TCP, conn, dispatch); err != nil { - // 这个 err 在官方的代码里面也就那个样子,在 go 的携程里面没人管 - // 大概率是 context canceled 或者 io: read/write on closed pipe - // 应该也是没办法处理 当远程服务断开链接时候的通信 - // 我们就处理的简单一些好了。 - if err.(*errors.Error).Severity() > 1 { - xlog.Debug(xlog.ServiceTransportError, err) - } else { - return err - } - } - if err = conn.Close(); err != nil { - return err - } - return nil -} diff --git a/pkg/network/transfer/v2ray_config.go b/pkg/network/transfer/v2ray_config.go deleted file mode 100644 index 2e01ad3..0000000 --- a/pkg/network/transfer/v2ray_config.go +++ /dev/null @@ -1,355 +0,0 @@ -package transfer - -import ( - "encoding/json" - "fmt" - - core "github.com/v2fly/v2ray-core/v5" - "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon" - "github.com/v2fly/v2ray-core/v5/infra/conf/synthetic/log" - v4 "github.com/v2fly/v2ray-core/v5/infra/conf/v4" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" -) - -const handleTag = "seamoon-" - -var ( - v2ray *core.Instance - empty = []byte("{}") -) - -type v2rayConfig struct { - mode string - addr string // 用于出站的协议地址 - port uint32 // - - id string - pass string - crypt string - - proto string - tp enum.TunnelType - - tor bool - tls bool -} - -type ConfigOpt func(config *v2rayConfig) - -func WithServerMod() ConfigOpt { - return func(config *v2rayConfig) { - config.mode = "server" - } -} - -func WithClientMod() ConfigOpt { - return func(config *v2rayConfig) { - config.mode = "client" - } -} - -func WithNetAddr(addr string, port uint32) ConfigOpt { - return func(config *v2rayConfig) { - config.addr = addr - config.port = port - } -} - -func WithAuthInfo(id, crypt, pass string) ConfigOpt { - return func(config *v2rayConfig) { - config.id = id - config.crypt = crypt - config.pass = pass - } -} - -func WithExtra(tor, tls bool) ConfigOpt { - return func(config *v2rayConfig) { - config.tor = tor - config.tls = tls - } -} - -func WithTunnelType(proto string, tp enum.TunnelType) ConfigOpt { - return func(config *v2rayConfig) { - config.proto = proto - config.tp = tp - } -} - -func NewV2rayConfig(opts ...ConfigOpt) *v2rayConfig { - v := &v2rayConfig{} - for _, o := range opts { - o(v) - } - return v -} - -func (v v2rayConfig) Build() (*core.Config, error) { - t := &v4.Config{ - LogConfig: &log.LogConfig{ - AccessLog: "v2ray_access.log", - ErrorLog: "v2ray_error.log", - LogLevel: "ERROR", - }, - InboundConfigs: v.InboundConfig(), - OutboundConfigs: v.OutboundConfig(), - } - - return t.Build() -} - -func (v v2rayConfig) InboundConfig() []v4.InboundDetourConfig { - cs := make([]v4.InboundDetourConfig, 0) - switch v.mode { - case "server": - if v.id != "" { - cs = append(cs, v.vlessInboundConfig()) - cs = append(cs, v.vmessInboundConfig()) - } - if v.crypt != "" && v.pass != "" { - cs = append(cs, v.shadowsocksInboundConfig()) - } - case "client": - cs = append(cs, v.httpInboundConfig()) - cs = append(cs, v.socks5InboundConfig()) - } - return cs -} - -func (v v2rayConfig) OutboundConfig() []v4.OutboundDetourConfig { - cs := make([]v4.OutboundDetourConfig, 0) - switch v.mode { - case "server": - if v.tor { - cs = append(cs, v.torOutboundConfig()) - } else { - cs = append(cs, v.freedomOutboundConfig()) - } - case "client": - switch v.proto { - case "vmess": - cs = append(cs, v.vmessOutboundConfig()) - case "vless": - cs = append(cs, v.vlessOutboundConfig()) - case "shadowsocks": - cs = append(cs, v.shadowsocksOutboundConfig()) - } - } - return cs -} - -func (v v2rayConfig) StreamSetting(proto string) *v4.StreamConfig { - switch v.tp { - case enum.TunnelTypeWST: - return v.streamWebsocketSetting(proto) - case enum.TunnelTypeGRT: - return v.streamGrpcSetting(proto) - } - return nil -} - -func (v v2rayConfig) streamGrpcSetting(proto string) *v4.StreamConfig { - return nil -} - -func (v v2rayConfig) streamWebsocketSetting(proto string) *v4.StreamConfig { - return &v4.StreamConfig{ - Network: (*v4.TransportProtocol)(v.tp.ToPtr()), - Security: func() string { - if v.tls { - return "tls" - } - return "" - }(), - WSSettings: &v4.WebSocketConfig{ - Path: "/" + proto, - }, - } -} - -func (v v2rayConfig) httpInboundConfig() v4.InboundDetourConfig { - vc := []byte(`{ - "accounts": [], - "allowTransparent": false - }`) - return v4.InboundDetourConfig{ - Protocol: "http", - PortRange: &cfgcommon.PortRange{ - From: v.port, - To: v.port, - }, - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "http", - } -} - -func (v v2rayConfig) socks5InboundConfig() v4.InboundDetourConfig { - vc := []byte(`{ - "auth": "noauth", - "accounts": [], - "udp": false - }`) - return v4.InboundDetourConfig{ - Protocol: "socks", - PortRange: &cfgcommon.PortRange{ - From: v.port, - To: v.port, - }, - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "socks5", - } -} - -func (v v2rayConfig) shadowsocksOutboundConfig() v4.OutboundDetourConfig { - vc := []byte(fmt.Sprintf(`{ - "servers": [ - { - "address": "%s", - "port": %d, - "method": "%s" - "password": "%s" - } - ] -}`, v.addr, v.port, v.crypt, v.pass)) - return v4.OutboundDetourConfig{ - Protocol: "shadowsocks", - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "shadowsocks", - StreamSetting: v.StreamSetting("v-shadowsocks"), - } -} - -func (v v2rayConfig) shadowsocksInboundConfig() v4.InboundDetourConfig { - vc := []byte(fmt.Sprintf(`{ - "method": "%s", - "password": "%s", - "network": "tcp" -}`, v.crypt, v.pass)) - return v4.InboundDetourConfig{ - Protocol: "shadowsocks", - PortRange: &cfgcommon.PortRange{ - From: v.port, - To: v.port, - }, - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "shadowsocks", - StreamSetting: v.StreamSetting("v-shadowsocks"), - } -} - -func (v v2rayConfig) vmessOutboundConfig() v4.OutboundDetourConfig { - outSetting := []byte(fmt.Sprintf(`{ - "vnext": [ - { - "address": "%s", - "port": %d, - "users": [ - { - "alterId": 0, - "id": "%s", - "security": "auto" - } - ] - } - ] -}`, v.addr, v.port, v.id)) - return v4.OutboundDetourConfig{ - Protocol: "vmess", - Tag: handleTag + "vmess", - Settings: (*json.RawMessage)(&outSetting), - StreamSetting: v.StreamSetting("vmess"), - } -} - -func (v v2rayConfig) vmessInboundConfig() v4.InboundDetourConfig { - vc := []byte(fmt.Sprintf(`{ - "clients": [ - { - "id": "%s", - "alterId": 0 - } - ], - "decryption":"auto" -}`, v.id)) - return v4.InboundDetourConfig{ - Protocol: "vmess", - PortRange: &cfgcommon.PortRange{ - From: v.port, - To: v.port, - }, - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "vmess", - StreamSetting: v.StreamSetting("vmess"), - } -} - -func (v v2rayConfig) vlessOutboundConfig() v4.OutboundDetourConfig { - outSetting := []byte(fmt.Sprintf(`{ - "vnext": [ - { - "address": "%s", - "port": %d, - "users": [ - { - "alterId": 0, - "id": "%s", - "security": "auto", - "encryption": "none" - } - ] - } - ] -}`, v.addr, v.port, v.id)) - return v4.OutboundDetourConfig{ - Protocol: "vless", - Settings: (*json.RawMessage)(&outSetting), - Tag: handleTag + "vless", - StreamSetting: v.StreamSetting("vless"), - } -} - -func (v v2rayConfig) vlessInboundConfig() v4.InboundDetourConfig { - vc := []byte(fmt.Sprintf(`{ - "clients": [ - { - "id": "%s", - "alterId": 0 - } - ], - "decryption":"none" -}`, v.id)) - return v4.InboundDetourConfig{ - Protocol: "vless", - PortRange: &cfgcommon.PortRange{ - From: v.port, - To: v.port, - }, - Settings: (*json.RawMessage)(&vc), - Tag: handleTag + "vless", - StreamSetting: v.StreamSetting("vless"), - } -} - -func (v v2rayConfig) torOutboundConfig() v4.OutboundDetourConfig { - torSetting := []byte(`{ - "servers": [ - { - "address": "127.0.0.1", - "port": 9050 - } - ] - }`) - return v4.OutboundDetourConfig{ - Protocol: "socks", - Settings: (*json.RawMessage)(&torSetting), - } -} - -func (v v2rayConfig) freedomOutboundConfig() v4.OutboundDetourConfig { - return v4.OutboundDetourConfig{ - Protocol: "freedom", - Settings: (*json.RawMessage)(&empty), - } -} diff --git a/pkg/network/tunnel/grpc.go b/pkg/network/tunnel/grpc.go deleted file mode 100644 index 98fd197..0000000 --- a/pkg/network/tunnel/grpc.go +++ /dev/null @@ -1,119 +0,0 @@ -package tunnel - -import ( - "context" - "errors" - "fmt" - "net" - "time" - - "google.golang.org/grpc" - - proto2 "github.com/DVKunion/SeaMoon/pkg/network/tunnel/service/proto" -) - -type grpcConn struct { - cc grpc.Stream - - rb []byte - lAddr net.Addr - rAddr net.Addr -} - -func GRPCWrapConn(addr net.Addr, cc grpc.Stream) Tunnel { - return &grpcConn{ - cc: cc, - lAddr: addr, - rAddr: &net.TCPAddr{}, - } -} - -func (c *grpcConn) Delay() int64 { - return 0 -} - -func (c *grpcConn) Read(b []byte) (n int, err error) { - if len(c.rb) == 0 { - chunk, err := c.recv() - if err != nil { - return 0, err - } - c.rb = chunk.Body - } - - n = copy(b, c.rb) - c.rb = c.rb[n:] - return -} - -func (c *grpcConn) Write(b []byte) (n int, err error) { - chunk := &proto2.Chunk{ - Body: b, - Size: int32(len(b)), - } - - if err = c.send(chunk); err != nil { - return - } - - n = int(chunk.Size) - return -} - -func (c *grpcConn) Close() error { - switch cost := c.cc.(type) { - case proto2.Tunnel_HttpClient: - case proto2.Tunnel_Socks5Client: - return cost.CloseSend() - } - return nil -} - -func (c *grpcConn) LocalAddr() net.Addr { - return c.lAddr -} - -func (c *grpcConn) RemoteAddr() net.Addr { - return c.rAddr -} - -func (c *grpcConn) SetDeadline(t time.Time) error { - return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} -} - -func (c *grpcConn) SetReadDeadline(t time.Time) error { - return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} -} - -func (c *grpcConn) SetWriteDeadline(t time.Time) error { - return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} -} - -func (c *grpcConn) context() context.Context { - if c.cc != nil { - return c.cc.Context() - } - return context.Background() -} - -func (c *grpcConn) send(data *proto2.Chunk) error { - sender, ok := c.cc.(interface { - Send(*proto2.Chunk) error - }) - if !ok { - // todo - return fmt.Errorf("unsupported type: %T", c.cc) - } - return sender.Send(data) -} - -func (c *grpcConn) recv() (*proto2.Chunk, error) { - receiver, ok := c.cc.(interface { - Recv() (*proto2.Chunk, error) - }) - if !ok { - // todo - return nil, fmt.Errorf("unsupported type: %T", c.cc) - } - return receiver.Recv() -} diff --git a/pkg/network/tunnel/service/grpc.go b/pkg/network/tunnel/service/grpc.go deleted file mode 100644 index b9ed902..0000000 --- a/pkg/network/tunnel/service/grpc.go +++ /dev/null @@ -1,242 +0,0 @@ -package service - -import ( - "context" - "crypto/tls" - "net" - "strconv" - "strings" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/keepalive" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" - "github.com/DVKunion/SeaMoon/pkg/network/transfer" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel/service/proto" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel/service/proto/gost" - "github.com/DVKunion/SeaMoon/pkg/system/version" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -type GRPCService struct { - addr net.Addr - cc *grpc.ClientConn - server *grpc.Server - startAt time.Time - proto.UnimplementedTunnelServer - gost.UnimplementedGostTunelServer -} - -func init() { - register(enum.TunnelTypeGRT, &GRPCService{}) -} - -func (g GRPCService) Conn(ctx context.Context, t enum.ProxyType, sOpts ...Option) (tunnel.Tunnel, error) { - var cs grpc.ClientStream - var srvOpts = &Options{} - var err error - - for _, o := range sOpts { - o(srvOpts) - } - - if strings.HasPrefix(srvOpts.addr, "grpc://") { - srvOpts.addr = strings.TrimPrefix(srvOpts.addr, "grpc://") - } - - if strings.HasPrefix(srvOpts.addr, "grpcs://") { - srvOpts.addr = strings.TrimPrefix(srvOpts.addr, "grpcs://") - } - - nAddr, err := net.ResolveTCPAddr("tcp", srvOpts.addr) - if err != nil { - return nil, err - } - - if g.cc == nil { - // do connect - grpcOpts := []grpc.DialOption{ - //grpc.WithAuthority(host), - //grpc.WithConnectParams(grpc.ConnectParams{ - // Backoff: backoff.DefaultConfig, - //MinConnectTimeout: d.md.minConnectTimeout, - //}), - grpc.WithKeepaliveParams(keepalive.ClientParameters{ - Time: 10 * time.Second, // send pings every 10 seconds if there is no activity - Timeout: 3 * time.Second, // wait 1 second for ping ack before considering the c - PermitWithoutStream: false, // send pings even without active streams - }), - //grpc.FailOnNonTempDialError(true), - } - - //if !d.md.insecure { - // grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig))) - //} else { - //grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) - grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{ - InsecureSkipVerify: true, - }))) - //} - g.cc, err = grpc.DialContext(ctx, srvOpts.addr, grpcOpts...) - if err != nil { - return nil, err - } - } - - client := proto.NewTunnelClient(g.cc) - - switch t { - case enum.ProxyTypeHTTP: - cs, err = client.Http(ctx) - case enum.ProxyTypeSOCKS5: - cs, err = client.Socks5(ctx) - } - - if err != nil { - return nil, err - } - - return tunnel.GRPCWrapConn(nAddr, cs), nil - -} - -func (g GRPCService) Serve(ln net.Listener, srvOpt ...Option) error { - var srvOpts = &Options{} - for _, o := range srvOpt { - o(srvOpts) - } - var gRPCOpts []grpc.ServerOption - if srvOpts.tlsConf != nil { - gRPCOpts = append(gRPCOpts, grpc.Creds(credentials.NewTLS(srvOpts.tlsConf))) - } - - if srvOpts.keepalive != nil { - gRPCOpts = append(gRPCOpts, - grpc.KeepaliveParams(keepalive.ServerParameters{ - Time: 10 * time.Second, // send pings every 10 seconds if there is no activity - Timeout: 3 * time.Second, // wait 1 second for ping ack before considering the connection dead - MaxConnectionIdle: 30 * time.Second, - //MaxConnectionIdle: srvOpts.keepalive.MaxConnectionIdle, - //Time: srvOpts.keepalive.MaxTime, - //Timeout: srvOpts.keepalive.Timeout, - }), - grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ - //MinTime: srvOpts.keepalive.MinTime, - PermitWithoutStream: false, - }), - ) - } - - server := grpc.NewServer(gRPCOpts...) - - addr := strings.Split(ln.Addr().String(), ":") - var port = 443 // 默认端口 - if len(addr) > 1 { - if p, err := strconv.Atoi(addr[1]); err == nil { - port = p - } - } - - // init config - config := transfer.NewV2rayConfig( - transfer.WithServerMod(), - transfer.WithNetAddr("0.0.0.0", uint32(port)), - transfer.WithTunnelType("", enum.TunnelTypeWST), - transfer.WithAuthInfo(srvOpts.uid, srvOpts.crypt, srvOpts.pass), - transfer.WithExtra(srvOpts.tor, srvOpts.tlsConf != nil), - ) - - if err := transfer.Init(config); err != nil { - xlog.Error(xlog.ServiceV2rayInitError, "err", err) - } - - proto.RegisterTunnelServer(server, &g) - gost.RegisterGostTunelServer(server, &g) - - g.startAt = time.Now() - return server.Serve(ln) -} - -func (g GRPCService) Auto(server proto.Tunnel_AutoServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.AutoTransport(gt); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "socks5", "err", err) - return err - } - return nil -} - -func (g GRPCService) Http(server proto.Tunnel_HttpServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.HttpTransport(gt); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "http", "err", err) - return err - } - - return nil -} - -func (g GRPCService) Socks5(server proto.Tunnel_Socks5Server) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.Socks5Transport(gt, false); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "socks5", "err", err) - return err - } - return nil -} - -func (g GRPCService) V2RaySsr(server proto.Tunnel_V2RaySsrServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.V2rayTransport(gt, "shadowsocks"); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "v2ray-ssr", "err", err) - return err - } - return nil -} - -func (g GRPCService) V2RayVmess(server proto.Tunnel_V2RayVmessServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.V2rayTransport(gt, "vmess"); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "vmess", "err", err) - return err - } - return nil -} - -func (g GRPCService) V2RayVless(server proto.Tunnel_V2RayVlessServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.V2rayTransport(gt, "vless"); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "vless", "err", err) - return err - } - return nil -} - -// Tunnel gost grpc 适配, 实际上直接做一个 auto 协议就好了 -func (g GRPCService) Tunnel(server gost.GostTunel_TunnelServer) error { - gt := tunnel.GRPCWrapConn(g.addr, server) - - if err := transfer.AutoTransport(gt); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "socks5", "err", err) - return err - } - return nil -} - -func (g GRPCService) Health(ctx context.Context, p *proto.Ping) (*proto.Pong, error) { - return &proto.Pong{ - Status: "OK", - Time: g.startAt.Format("2006-01-02 15:04:05"), - Version: version.Version, - Commit: version.Commit, - }, nil -} diff --git a/pkg/network/tunnel/service/options.go b/pkg/network/tunnel/service/options.go deleted file mode 100644 index 06c86d5..0000000 --- a/pkg/network/tunnel/service/options.go +++ /dev/null @@ -1,84 +0,0 @@ -package service - -import ( - "crypto/tls" - "time" -) - -type Options struct { - addr string - - tor bool - pass string - uid string - crypt string - tlsConf *tls.Config - keepalive *KeepAliveOpt - buffers *BufferOpt -} - -type Option func(o *Options) - -type KeepAliveOpt struct { - MinTime time.Duration - MaxTime time.Duration - Timeout time.Duration - HandshakeTimeout time.Duration - MaxConnectionIdle time.Duration - - PermitStream bool -} - -type BufferOpt struct { - ReadBufferSize int - WriteBufferSize int - EnableCompression bool -} - -func WithAddr(addr string) Option { - return func(o *Options) { - o.addr = addr - } -} - -func WithTorFlag(tor bool) Option { - return func(o *Options) { - o.tor = tor - } -} - -func WithTLSConf(t *tls.Config) Option { - return func(o *Options) { - o.tlsConf = t - } -} - -func WithPassword(pass string) Option { - return func(o *Options) { - o.pass = pass - } -} - -func WithUid(uid string) Option { - return func(o *Options) { - o.uid = uid - } -} - -func WithCrypt(c string) Option { - return func(o *Options) { - o.crypt = c - } -} - -func WithKeepAlive(k *KeepAliveOpt) Option { - return func(o *Options) { - o.keepalive = k - } -} - -func WithBuffers(b *BufferOpt) Option { - return func(o *Options) { - o.buffers = b - } -} diff --git a/pkg/network/tunnel/service/proto/Makefile b/pkg/network/tunnel/service/proto/Makefile deleted file mode 100644 index 158da3a..0000000 --- a/pkg/network/tunnel/service/proto/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -.PHONY: all -all: generate - - -generate: - protoc --proto_path=./ --go_out=./ \ - --go_opt=Mtunnel.proto=./ \ - --go_opt=Mgost.proto=./gost \ - --go-grpc_out=./ \ - --go-grpc_opt=Mtunnel.proto=./ \ - --go-grpc_opt=Mgost.proto=./gost \ - ./*.proto diff --git a/pkg/network/tunnel/service/proto/gost.proto b/pkg/network/tunnel/service/proto/gost.proto deleted file mode 100644 index f477458..0000000 --- a/pkg/network/tunnel/service/proto/gost.proto +++ /dev/null @@ -1,10 +0,0 @@ -syntax = "proto3"; -option go_package = "github.com/go-gost/core/common/util/grpc/proto"; - -message Chunk { - bytes data = 1; -} - -service GostTunel { - rpc Tunnel (stream Chunk) returns (stream Chunk); -} \ No newline at end of file diff --git a/pkg/network/tunnel/service/proto/gost/gost.pb.go b/pkg/network/tunnel/service/proto/gost/gost.pb.go deleted file mode 100644 index 33b3022..0000000 --- a/pkg/network/tunnel/service/proto/gost/gost.pb.go +++ /dev/null @@ -1,148 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.0 -// protoc v3.3.0 -// source: gost.proto - -package gost - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Chunk struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` -} - -func (x *Chunk) Reset() { - *x = Chunk{} - if protoimpl.UnsafeEnabled { - mi := &file_gost_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Chunk) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Chunk) ProtoMessage() {} - -func (x *Chunk) ProtoReflect() protoreflect.Message { - mi := &file_gost_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Chunk.ProtoReflect.Descriptor instead. -func (*Chunk) Descriptor() ([]byte, []int) { - return file_gost_proto_rawDescGZIP(), []int{0} -} - -func (x *Chunk) GetData() []byte { - if x != nil { - return x.Data - } - return nil -} - -var File_gost_proto protoreflect.FileDescriptor - -var file_gost_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x67, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x05, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x29, 0x0a, 0x09, 0x47, 0x6f, 0x73, - 0x74, 0x54, 0x75, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x06, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, - 0x12, 0x06, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x06, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, - 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x67, 0x6f, 0x73, 0x74, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x75, 0x74, 0x69, 0x6c, 0x2f, 0x67, 0x72, 0x70, 0x63, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_gost_proto_rawDescOnce sync.Once - file_gost_proto_rawDescData = file_gost_proto_rawDesc -) - -func file_gost_proto_rawDescGZIP() []byte { - file_gost_proto_rawDescOnce.Do(func() { - file_gost_proto_rawDescData = protoimpl.X.CompressGZIP(file_gost_proto_rawDescData) - }) - return file_gost_proto_rawDescData -} - -var file_gost_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_gost_proto_goTypes = []interface{}{ - (*Chunk)(nil), // 0: Chunk -} -var file_gost_proto_depIdxs = []int32{ - 0, // 0: GostTunel.Tunnel:input_type -> Chunk - 0, // 1: GostTunel.Tunnel:output_type -> Chunk - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_gost_proto_init() } -func file_gost_proto_init() { - if File_gost_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_gost_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Chunk); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_gost_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_gost_proto_goTypes, - DependencyIndexes: file_gost_proto_depIdxs, - MessageInfos: file_gost_proto_msgTypes, - }.Build() - File_gost_proto = out.File - file_gost_proto_rawDesc = nil - file_gost_proto_goTypes = nil - file_gost_proto_depIdxs = nil -} diff --git a/pkg/network/tunnel/service/proto/gost/gost_grpc.pb.go b/pkg/network/tunnel/service/proto/gost/gost_grpc.pb.go deleted file mode 100644 index a29be37..0000000 --- a/pkg/network/tunnel/service/proto/gost/gost_grpc.pb.go +++ /dev/null @@ -1,138 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.3.0 -// source: gost.proto - -package gost - -import ( - context "context" - - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// GostTunelClient is the client API for GostTunel service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type GostTunelClient interface { - Tunnel(ctx context.Context, opts ...grpc.CallOption) (GostTunel_TunnelClient, error) -} - -type gostTunelClient struct { - cc grpc.ClientConnInterface -} - -func NewGostTunelClient(cc grpc.ClientConnInterface) GostTunelClient { - return &gostTunelClient{cc} -} - -func (c *gostTunelClient) Tunnel(ctx context.Context, opts ...grpc.CallOption) (GostTunel_TunnelClient, error) { - stream, err := c.cc.NewStream(ctx, &GostTunel_ServiceDesc.Streams[0], "/GostTunel/Tunnel", opts...) - if err != nil { - return nil, err - } - x := &gostTunelTunnelClient{stream} - return x, nil -} - -type GostTunel_TunnelClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type gostTunelTunnelClient struct { - grpc.ClientStream -} - -func (x *gostTunelTunnelClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *gostTunelTunnelClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// GostTunelServer is the server API for GostTunel service. -// All implementations must embed UnimplementedGostTunelServer -// for forward compatibility -type GostTunelServer interface { - Tunnel(GostTunel_TunnelServer) error - mustEmbedUnimplementedGostTunelServer() -} - -// UnimplementedGostTunelServer must be embedded to have forward compatible implementations. -type UnimplementedGostTunelServer struct { -} - -func (UnimplementedGostTunelServer) Tunnel(GostTunel_TunnelServer) error { - return status.Errorf(codes.Unimplemented, "method Tunnel not implemented") -} -func (UnimplementedGostTunelServer) mustEmbedUnimplementedGostTunelServer() {} - -// UnsafeGostTunelServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to GostTunelServer will -// result in compilation errors. -type UnsafeGostTunelServer interface { - mustEmbedUnimplementedGostTunelServer() -} - -func RegisterGostTunelServer(s grpc.ServiceRegistrar, srv GostTunelServer) { - s.RegisterService(&GostTunel_ServiceDesc, srv) -} - -func _GostTunel_Tunnel_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(GostTunelServer).Tunnel(&gostTunelTunnelServer{stream}) -} - -type GostTunel_TunnelServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type gostTunelTunnelServer struct { - grpc.ServerStream -} - -func (x *gostTunelTunnelServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *gostTunelTunnelServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// GostTunel_ServiceDesc is the grpc.ServiceDesc for GostTunel service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var GostTunel_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "GostTunel", - HandlerType: (*GostTunelServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "Tunnel", - Handler: _GostTunel_Tunnel_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "gost.proto", -} diff --git a/pkg/network/tunnel/service/proto/tunnel.pb.go b/pkg/network/tunnel/service/proto/tunnel.pb.go deleted file mode 100644 index e1cfd4e..0000000 --- a/pkg/network/tunnel/service/proto/tunnel.pb.go +++ /dev/null @@ -1,339 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.0 -// protoc v3.3.0 -// source: tunnel.proto - -package proto - -import ( - reflect "reflect" - sync "sync" - - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Ping struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` -} - -func (x *Ping) Reset() { - *x = Ping{} - if protoimpl.UnsafeEnabled { - mi := &file_tunnel_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Ping) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Ping) ProtoMessage() {} - -func (x *Ping) ProtoReflect() protoreflect.Message { - mi := &file_tunnel_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Ping.ProtoReflect.Descriptor instead. -func (*Ping) Descriptor() ([]byte, []int) { - return file_tunnel_proto_rawDescGZIP(), []int{0} -} - -func (x *Ping) GetVersion() string { - if x != nil { - return x.Version - } - return "" -} - -type Pong struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - Time string `protobuf:"bytes,2,opt,name=time,proto3" json:"time,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` - Commit string `protobuf:"bytes,4,opt,name=commit,proto3" json:"commit,omitempty"` -} - -func (x *Pong) Reset() { - *x = Pong{} - if protoimpl.UnsafeEnabled { - mi := &file_tunnel_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Pong) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Pong) ProtoMessage() {} - -func (x *Pong) ProtoReflect() protoreflect.Message { - mi := &file_tunnel_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Pong.ProtoReflect.Descriptor instead. -func (*Pong) Descriptor() ([]byte, []int) { - return file_tunnel_proto_rawDescGZIP(), []int{1} -} - -func (x *Pong) GetStatus() string { - if x != nil { - return x.Status - } - return "" -} - -func (x *Pong) GetTime() string { - if x != nil { - return x.Time - } - return "" -} - -func (x *Pong) GetVersion() string { - if x != nil { - return x.Version - } - return "" -} - -func (x *Pong) GetCommit() string { - if x != nil { - return x.Commit - } - return "" -} - -type Chunk struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Body []byte `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` - Size int32 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` -} - -func (x *Chunk) Reset() { - *x = Chunk{} - if protoimpl.UnsafeEnabled { - mi := &file_tunnel_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Chunk) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Chunk) ProtoMessage() {} - -func (x *Chunk) ProtoReflect() protoreflect.Message { - mi := &file_tunnel_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Chunk.ProtoReflect.Descriptor instead. -func (*Chunk) Descriptor() ([]byte, []int) { - return file_tunnel_proto_rawDescGZIP(), []int{2} -} - -func (x *Chunk) GetBody() []byte { - if x != nil { - return x.Body - } - return nil -} - -func (x *Chunk) GetSize() int32 { - if x != nil { - return x.Size - } - return 0 -} - -var File_tunnel_proto protoreflect.FileDescriptor - -var file_tunnel_proto_rawDesc = []byte{ - 0x0a, 0x0c, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, - 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x20, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x64, 0x0a, 0x04, 0x50, 0x6f, 0x6e, 0x67, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0x2f, - 0x0a, 0x05, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, - 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x32, - 0xbc, 0x02, 0x0a, 0x06, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x28, 0x0a, 0x04, 0x41, 0x75, - 0x74, 0x6f, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, 0x68, 0x75, 0x6e, - 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, - 0x28, 0x01, 0x30, 0x01, 0x12, 0x28, 0x0a, 0x04, 0x48, 0x74, 0x74, 0x70, 0x12, 0x0d, 0x2e, 0x74, - 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, - 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2a, - 0x0a, 0x06, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, - 0x6c, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, - 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x08, 0x56, 0x32, - 0x72, 0x61, 0x79, 0x53, 0x73, 0x72, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2e, 0x0a, 0x0a, 0x56, 0x32, 0x72, 0x61, - 0x79, 0x56, 0x6d, 0x65, 0x73, 0x73, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2e, 0x0a, 0x0a, 0x56, 0x32, 0x72, 0x61, - 0x79, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x28, 0x01, 0x30, 0x01, 0x12, 0x24, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x12, 0x0c, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x50, 0x69, 0x6e, 0x67, - 0x1a, 0x0c, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x50, 0x6f, 0x6e, 0x67, 0x42, 0x23, - 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x76, 0x6b, - 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x61, 0x6d, 0x6f, 0x6f, 0x6e, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_tunnel_proto_rawDescOnce sync.Once - file_tunnel_proto_rawDescData = file_tunnel_proto_rawDesc -) - -func file_tunnel_proto_rawDescGZIP() []byte { - file_tunnel_proto_rawDescOnce.Do(func() { - file_tunnel_proto_rawDescData = protoimpl.X.CompressGZIP(file_tunnel_proto_rawDescData) - }) - return file_tunnel_proto_rawDescData -} - -var file_tunnel_proto_msgTypes = make([]protoimpl.MessageInfo, 3) -var file_tunnel_proto_goTypes = []interface{}{ - (*Ping)(nil), // 0: tunnel.Ping - (*Pong)(nil), // 1: tunnel.Pong - (*Chunk)(nil), // 2: tunnel.Chunk -} -var file_tunnel_proto_depIdxs = []int32{ - 2, // 0: tunnel.Tunnel.Auto:input_type -> tunnel.Chunk - 2, // 1: tunnel.Tunnel.Http:input_type -> tunnel.Chunk - 2, // 2: tunnel.Tunnel.Socks5:input_type -> tunnel.Chunk - 2, // 3: tunnel.Tunnel.V2raySsr:input_type -> tunnel.Chunk - 2, // 4: tunnel.Tunnel.V2rayVmess:input_type -> tunnel.Chunk - 2, // 5: tunnel.Tunnel.V2rayVless:input_type -> tunnel.Chunk - 0, // 6: tunnel.Tunnel.Health:input_type -> tunnel.Ping - 2, // 7: tunnel.Tunnel.Auto:output_type -> tunnel.Chunk - 2, // 8: tunnel.Tunnel.Http:output_type -> tunnel.Chunk - 2, // 9: tunnel.Tunnel.Socks5:output_type -> tunnel.Chunk - 2, // 10: tunnel.Tunnel.V2raySsr:output_type -> tunnel.Chunk - 2, // 11: tunnel.Tunnel.V2rayVmess:output_type -> tunnel.Chunk - 2, // 12: tunnel.Tunnel.V2rayVless:output_type -> tunnel.Chunk - 1, // 13: tunnel.Tunnel.Health:output_type -> tunnel.Pong - 7, // [7:14] is the sub-list for method output_type - 0, // [0:7] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_tunnel_proto_init() } -func file_tunnel_proto_init() { - if File_tunnel_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_tunnel_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Ping); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tunnel_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Pong); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_tunnel_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Chunk); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_tunnel_proto_rawDesc, - NumEnums: 0, - NumMessages: 3, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_tunnel_proto_goTypes, - DependencyIndexes: file_tunnel_proto_depIdxs, - MessageInfos: file_tunnel_proto_msgTypes, - }.Build() - File_tunnel_proto = out.File - file_tunnel_proto_rawDesc = nil - file_tunnel_proto_goTypes = nil - file_tunnel_proto_depIdxs = nil -} diff --git a/pkg/network/tunnel/service/proto/tunnel.proto b/pkg/network/tunnel/service/proto/tunnel.proto deleted file mode 100644 index 522b6a0..0000000 --- a/pkg/network/tunnel/service/proto/tunnel.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; - -package tunnel; -option go_package = "github.com/dvkunion/seamoon/proto"; - -message Ping { - string version = 1; -} - -message Pong { - string status = 1; - string time = 2; - string version = 3; - string commit = 4; -} - -message Chunk { - bytes body = 1; - int32 size = 2; -} - -service Tunnel { - rpc Auto (stream Chunk) returns (stream Chunk); - rpc Http (stream Chunk) returns (stream Chunk); - rpc Socks5 (stream Chunk) returns (stream Chunk); - rpc V2raySsr (stream Chunk) returns (stream Chunk); - rpc V2rayVmess (stream Chunk) returns (stream Chunk); - rpc V2rayVless (stream Chunk) returns (stream Chunk); - rpc Health(Ping) returns (Pong); -} \ No newline at end of file diff --git a/pkg/network/tunnel/service/proto/tunnel_grpc.pb.go b/pkg/network/tunnel/service/proto/tunnel_grpc.pb.go deleted file mode 100644 index a140da2..0000000 --- a/pkg/network/tunnel/service/proto/tunnel_grpc.pb.go +++ /dev/null @@ -1,515 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.3.0 -// source: tunnel.proto - -package proto - -import ( - context "context" - - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// TunnelClient is the client API for Tunnel service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type TunnelClient interface { - Auto(ctx context.Context, opts ...grpc.CallOption) (Tunnel_AutoClient, error) - Http(ctx context.Context, opts ...grpc.CallOption) (Tunnel_HttpClient, error) - Socks5(ctx context.Context, opts ...grpc.CallOption) (Tunnel_Socks5Client, error) - V2RaySsr(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RaySsrClient, error) - V2RayVmess(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RayVmessClient, error) - V2RayVless(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RayVlessClient, error) - Health(ctx context.Context, in *Ping, opts ...grpc.CallOption) (*Pong, error) -} - -type tunnelClient struct { - cc grpc.ClientConnInterface -} - -func NewTunnelClient(cc grpc.ClientConnInterface) TunnelClient { - return &tunnelClient{cc} -} - -func (c *tunnelClient) Auto(ctx context.Context, opts ...grpc.CallOption) (Tunnel_AutoClient, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[0], "/tunnel.Tunnel/Auto", opts...) - if err != nil { - return nil, err - } - x := &tunnelAutoClient{stream} - return x, nil -} - -type Tunnel_AutoClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelAutoClient struct { - grpc.ClientStream -} - -func (x *tunnelAutoClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelAutoClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) Http(ctx context.Context, opts ...grpc.CallOption) (Tunnel_HttpClient, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[1], "/tunnel.Tunnel/Http", opts...) - if err != nil { - return nil, err - } - x := &tunnelHttpClient{stream} - return x, nil -} - -type Tunnel_HttpClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelHttpClient struct { - grpc.ClientStream -} - -func (x *tunnelHttpClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelHttpClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) Socks5(ctx context.Context, opts ...grpc.CallOption) (Tunnel_Socks5Client, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[2], "/tunnel.Tunnel/Socks5", opts...) - if err != nil { - return nil, err - } - x := &tunnelSocks5Client{stream} - return x, nil -} - -type Tunnel_Socks5Client interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelSocks5Client struct { - grpc.ClientStream -} - -func (x *tunnelSocks5Client) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelSocks5Client) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) V2RaySsr(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RaySsrClient, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[3], "/tunnel.Tunnel/V2raySsr", opts...) - if err != nil { - return nil, err - } - x := &tunnelV2RaySsrClient{stream} - return x, nil -} - -type Tunnel_V2RaySsrClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelV2RaySsrClient struct { - grpc.ClientStream -} - -func (x *tunnelV2RaySsrClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelV2RaySsrClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) V2RayVmess(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RayVmessClient, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[4], "/tunnel.Tunnel/V2rayVmess", opts...) - if err != nil { - return nil, err - } - x := &tunnelV2RayVmessClient{stream} - return x, nil -} - -type Tunnel_V2RayVmessClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelV2RayVmessClient struct { - grpc.ClientStream -} - -func (x *tunnelV2RayVmessClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelV2RayVmessClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) V2RayVless(ctx context.Context, opts ...grpc.CallOption) (Tunnel_V2RayVlessClient, error) { - stream, err := c.cc.NewStream(ctx, &Tunnel_ServiceDesc.Streams[5], "/tunnel.Tunnel/V2rayVless", opts...) - if err != nil { - return nil, err - } - x := &tunnelV2RayVlessClient{stream} - return x, nil -} - -type Tunnel_V2RayVlessClient interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ClientStream -} - -type tunnelV2RayVlessClient struct { - grpc.ClientStream -} - -func (x *tunnelV2RayVlessClient) Send(m *Chunk) error { - return x.ClientStream.SendMsg(m) -} - -func (x *tunnelV2RayVlessClient) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *tunnelClient) Health(ctx context.Context, in *Ping, opts ...grpc.CallOption) (*Pong, error) { - out := new(Pong) - err := c.cc.Invoke(ctx, "/tunnel.Tunnel/Health", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// TunnelServer is the server API for Tunnel service. -// All implementations must embed UnimplementedTunnelServer -// for forward compatibility -type TunnelServer interface { - Auto(Tunnel_AutoServer) error - Http(Tunnel_HttpServer) error - Socks5(Tunnel_Socks5Server) error - V2RaySsr(Tunnel_V2RaySsrServer) error - V2RayVmess(Tunnel_V2RayVmessServer) error - V2RayVless(Tunnel_V2RayVlessServer) error - Health(context.Context, *Ping) (*Pong, error) - mustEmbedUnimplementedTunnelServer() -} - -// UnimplementedTunnelServer must be embedded to have forward compatible implementations. -type UnimplementedTunnelServer struct { -} - -func (UnimplementedTunnelServer) Auto(Tunnel_AutoServer) error { - return status.Errorf(codes.Unimplemented, "method Auto not implemented") -} -func (UnimplementedTunnelServer) Http(Tunnel_HttpServer) error { - return status.Errorf(codes.Unimplemented, "method Http not implemented") -} -func (UnimplementedTunnelServer) Socks5(Tunnel_Socks5Server) error { - return status.Errorf(codes.Unimplemented, "method Socks5 not implemented") -} -func (UnimplementedTunnelServer) V2RaySsr(Tunnel_V2RaySsrServer) error { - return status.Errorf(codes.Unimplemented, "method V2RaySsr not implemented") -} -func (UnimplementedTunnelServer) V2RayVmess(Tunnel_V2RayVmessServer) error { - return status.Errorf(codes.Unimplemented, "method V2RayVmess not implemented") -} -func (UnimplementedTunnelServer) V2RayVless(Tunnel_V2RayVlessServer) error { - return status.Errorf(codes.Unimplemented, "method V2RayVless not implemented") -} -func (UnimplementedTunnelServer) Health(context.Context, *Ping) (*Pong, error) { - return nil, status.Errorf(codes.Unimplemented, "method Health not implemented") -} -func (UnimplementedTunnelServer) mustEmbedUnimplementedTunnelServer() {} - -// UnsafeTunnelServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to TunnelServer will -// result in compilation errors. -type UnsafeTunnelServer interface { - mustEmbedUnimplementedTunnelServer() -} - -func RegisterTunnelServer(s grpc.ServiceRegistrar, srv TunnelServer) { - s.RegisterService(&Tunnel_ServiceDesc, srv) -} - -func _Tunnel_Auto_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).Auto(&tunnelAutoServer{stream}) -} - -type Tunnel_AutoServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelAutoServer struct { - grpc.ServerStream -} - -func (x *tunnelAutoServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelAutoServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_Http_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).Http(&tunnelHttpServer{stream}) -} - -type Tunnel_HttpServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelHttpServer struct { - grpc.ServerStream -} - -func (x *tunnelHttpServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelHttpServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_Socks5_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).Socks5(&tunnelSocks5Server{stream}) -} - -type Tunnel_Socks5Server interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelSocks5Server struct { - grpc.ServerStream -} - -func (x *tunnelSocks5Server) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelSocks5Server) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_V2RaySsr_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).V2RaySsr(&tunnelV2RaySsrServer{stream}) -} - -type Tunnel_V2RaySsrServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelV2RaySsrServer struct { - grpc.ServerStream -} - -func (x *tunnelV2RaySsrServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelV2RaySsrServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_V2RayVmess_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).V2RayVmess(&tunnelV2RayVmessServer{stream}) -} - -type Tunnel_V2RayVmessServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelV2RayVmessServer struct { - grpc.ServerStream -} - -func (x *tunnelV2RayVmessServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelV2RayVmessServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_V2RayVless_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(TunnelServer).V2RayVless(&tunnelV2RayVlessServer{stream}) -} - -type Tunnel_V2RayVlessServer interface { - Send(*Chunk) error - Recv() (*Chunk, error) - grpc.ServerStream -} - -type tunnelV2RayVlessServer struct { - grpc.ServerStream -} - -func (x *tunnelV2RayVlessServer) Send(m *Chunk) error { - return x.ServerStream.SendMsg(m) -} - -func (x *tunnelV2RayVlessServer) Recv() (*Chunk, error) { - m := new(Chunk) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _Tunnel_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Ping) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(TunnelServer).Health(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/tunnel.Tunnel/Health", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TunnelServer).Health(ctx, req.(*Ping)) - } - return interceptor(ctx, in, info, handler) -} - -// Tunnel_ServiceDesc is the grpc.ServiceDesc for Tunnel service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Tunnel_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "tunnel.Tunnel", - HandlerType: (*TunnelServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Health", - Handler: _Tunnel_Health_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "Auto", - Handler: _Tunnel_Auto_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "Http", - Handler: _Tunnel_Http_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "Socks5", - Handler: _Tunnel_Socks5_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "V2raySsr", - Handler: _Tunnel_V2RaySsr_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "V2rayVmess", - Handler: _Tunnel_V2RayVmess_Handler, - ServerStreams: true, - ClientStreams: true, - }, - { - StreamName: "V2rayVless", - Handler: _Tunnel_V2RayVless_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "tunnel.proto", -} diff --git a/pkg/network/tunnel/service/service.go b/pkg/network/tunnel/service/service.go deleted file mode 100644 index 7e2f49c..0000000 --- a/pkg/network/tunnel/service/service.go +++ /dev/null @@ -1,21 +0,0 @@ -package service - -import ( - "context" - "net" - "sync" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel" -) - -type Service interface { - Conn(ctx context.Context, t enum.ProxyType, sOpts ...Option) (tunnel.Tunnel, error) - Serve(ln net.Listener, srvOpt ...Option) error -} - -var Factory = sync.Map{} - -func register(t enum.TunnelType, s Service) { - Factory.Store(t, s) -} diff --git a/pkg/network/tunnel/service/websocket.go b/pkg/network/tunnel/service/websocket.go deleted file mode 100644 index 999426c..0000000 --- a/pkg/network/tunnel/service/websocket.go +++ /dev/null @@ -1,213 +0,0 @@ -package service - -import ( - "context" - "crypto/tls" - "net" - "net/http" - "strconv" - "strings" - "time" - - "github.com/gorilla/websocket" - - "github.com/DVKunion/SeaMoon/pkg/api/enum" - "github.com/DVKunion/SeaMoon/pkg/network/transfer" - "github.com/DVKunion/SeaMoon/pkg/network/tunnel" - "github.com/DVKunion/SeaMoon/pkg/system/version" - "github.com/DVKunion/SeaMoon/pkg/system/xlog" -) - -const ( - defaultTimeout = 300 * time.Second - defaultReadBufferSize = 32 * 1024 -) - -type WSService struct { - startAt time.Time - upGrader *websocket.Upgrader -} - -func init() { - register(enum.TunnelTypeWST, &WSService{}) -} - -func (s *WSService) Conn(ctx context.Context, t enum.ProxyType, sOpts ...Option) (tunnel.Tunnel, error) { - // todo: useless ctx - var srvOpts = &Options{} - - for _, o := range sOpts { - o(srvOpts) - } - - wsDialer := &websocket.Dialer{ - HandshakeTimeout: defaultTimeout, - ReadBufferSize: defaultReadBufferSize, - WriteBufferSize: defaultReadBufferSize, - EnableCompression: false, - } - - if srvOpts.buffers != nil { - wsDialer.ReadBufferSize = srvOpts.buffers.ReadBufferSize - wsDialer.WriteBufferSize = srvOpts.buffers.WriteBufferSize - wsDialer.EnableCompression = srvOpts.buffers.EnableCompression - } - - var requestHeader = http.Header{} - - if srvOpts.tor { - requestHeader.Add("SM-ONION", "enable") - } - - wsConn, _, err := wsDialer.Dial(t.Path(srvOpts.addr), requestHeader) - - if err != nil { - return nil, err - } - return tunnel.WsWrapConn(wsConn), nil -} - -func (s *WSService) Serve(ln net.Listener, sOpts ...Option) error { - var srvOpts = &Options{} - - for _, o := range sOpts { - o(srvOpts) - } - - s.upGrader = &websocket.Upgrader{ - HandshakeTimeout: defaultTimeout, - ReadBufferSize: defaultReadBufferSize, - WriteBufferSize: defaultReadBufferSize, - EnableCompression: false, - CheckOrigin: func(r *http.Request) bool { return true }, - } - - if srvOpts.buffers != nil { - s.upGrader.ReadBufferSize = srvOpts.buffers.ReadBufferSize - s.upGrader.WriteBufferSize = srvOpts.buffers.WriteBufferSize - s.upGrader.EnableCompression = srvOpts.buffers.EnableCompression - } - - if srvOpts.tlsConf != nil { - ln = tls.NewListener(ln, srvOpts.tlsConf) - } - - addr := strings.Split(ln.Addr().String(), ":") - var port = 443 // 默认端口 - if len(addr) > 1 { - if p, err := strconv.Atoi(addr[1]); err == nil { - port = p - } - } - - mux := http.NewServeMux() - mux.HandleFunc("/auto", s.auto) - // websocket http proxy handler - mux.HandleFunc("/http", s.http) - - // websocket socks5 proxy handler - mux.HandleFunc("/socks5", s.socks5) - - config := transfer.NewV2rayConfig( - transfer.WithServerMod(), - transfer.WithNetAddr("0.0.0.0", uint32(port)), - transfer.WithTunnelType("", enum.TunnelTypeWST), - transfer.WithAuthInfo(srvOpts.uid, srvOpts.crypt, srvOpts.pass), - transfer.WithExtra(srvOpts.tor, srvOpts.tlsConf != nil), - ) - - if err := transfer.Init(config); err == nil { - mux.HandleFunc("/vmess", s.v2ray("vmess")) - mux.HandleFunc("/vless", s.v2ray("vless")) - mux.HandleFunc("/v-shadowsocks", s.v2ray("shadowsocks")) - } else { - xlog.Error(xlog.ServiceV2rayInitError, "err", err) - } - - s.startAt = time.Now() - // inject - mux.HandleFunc("/_health", s.health) - server := &http.Server{ - Addr: srvOpts.addr, - Handler: mux, - } - return server.Serve(ln) -} - -func (s *WSService) auto(w http.ResponseWriter, r *http.Request) { - // means use http to connector - conn, err := s.upGrader.Upgrade(w, r, nil) - if err != nil { - return - } - t := tunnel.WsWrapConn(conn) - go func() { - if err := transfer.AutoTransport(t); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "auto", "err", err) - } - }() -} - -func (s *WSService) http(w http.ResponseWriter, r *http.Request) { - // means use http to connector - conn, err := s.upGrader.Upgrade(w, r, nil) - if err != nil { - return - } - t := tunnel.WsWrapConn(conn) - go func() { - if err := transfer.HttpTransport(t); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "http", "err", err) - } - }() -} - -func (s *WSService) socks5(w http.ResponseWriter, r *http.Request) { - onion := r.Header.Get("SM-ONION") - // means use socks5 to connector - conn, err := s.upGrader.Upgrade(w, r, nil) - if err != nil { - return - } - t := tunnel.WsWrapConn(conn) - go func() { - // 检测是否存在 onion 标识,代表着是否要开启 tor 转发 - if onion != "" { - if err := transfer.TorTransport(t); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "socks5+tor", "err", err) - } - } else { - if err := transfer.Socks5Transport(t, false); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "socks5", "err", err) - } - } - }() -} - -func (s *WSService) v2ray(proto string) func(http.ResponseWriter, *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - conn, err := s.upGrader.Upgrade(w, r, nil) - if err != nil { - return - } - t := tunnel.WsWrapConn(conn) - go func() { - if err := transfer.V2rayTransport(t, proto); err != nil { - xlog.Error(xlog.ServiceTransportError, "type", "v2ray", "proto", proto, "err", err) - } - }() - } -} - -func (s *WSService) health(w http.ResponseWriter, _ *http.Request) { - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusOK) - _, err := w.Write([]byte("OK\n" + - s.startAt.Format("2006-01-02 15:04:05") + "\n" + - version.Version + "-" + version.Commit + "\n" + - "v2ray-core:" + "-" + version.V2rayCoreVersion)) - if err != nil { - xlog.Error(xlog.ServiceStatusError, "err", err) - return - } -} diff --git a/pkg/network/tunnel/tunnel.go b/pkg/network/tunnel/tunnel.go deleted file mode 100644 index 897c0e0..0000000 --- a/pkg/network/tunnel/tunnel.go +++ /dev/null @@ -1,12 +0,0 @@ -package tunnel - -import ( - "net" -) - -// Tunnel is a bridge implementation for data transmission -// tunnel 不应该解决如何处理流量信息,仅仅是一个桥梁,用于信道传输。 -type Tunnel interface { - net.Conn - Delay() int64 // 计算延迟 -} diff --git a/pkg/network/tunnel/websocket.go b/pkg/network/tunnel/websocket.go deleted file mode 100644 index c3cbeac..0000000 --- a/pkg/network/tunnel/websocket.go +++ /dev/null @@ -1,90 +0,0 @@ -package tunnel - -import ( - "sync" - "time" - - "github.com/gorilla/websocket" -) - -type websocketConn struct { - *websocket.Conn - rb []byte - mux sync.Mutex -} - -func (c *websocketConn) Delay() int64 { - - if c.Conn == nil { - return 0 - } - - // 设置一个超时时间 - const timeout = 10 * time.Second - - // 创建一个通道用于接收pong消息的回复时间 - pongReceived := make(chan time.Time, 1) // 缓冲为1,避免潜在的阻塞 - - // 设置Pong处理程序 - c.Conn.SetPongHandler(func(appData string) error { - pongReceived <- time.Now() - return nil - }) - - pingSentTime := time.Now() - if err := c.WriteMessage(websocket.PingMessage, []byte("")); err != nil { - return 0 - } - - select { - case pongTime := <-pongReceived: - res := pongTime.Sub(pingSentTime).Milliseconds() - return res - case <-time.After(timeout): - return 99999 - } -} - -func WsWrapConn(conn *websocket.Conn) Tunnel { - return &websocketConn{ - Conn: conn, - } -} - -func (c *websocketConn) Read(b []byte) (n int, err error) { - if len(c.rb) == 0 { - _, c.rb, err = c.Conn.ReadMessage() - } - n = copy(b, c.rb) - c.rb = c.rb[n:] - return -} - -func (c *websocketConn) Write(b []byte) (n int, err error) { - err = c.WriteMessage(websocket.BinaryMessage, b) - n = len(b) - return -} - -func (c *websocketConn) WriteMessage(messageType int, data []byte) error { - c.mux.Lock() - defer c.mux.Unlock() - - return c.Conn.WriteMessage(messageType, data) -} - -func (c *websocketConn) SetDeadline(t time.Time) error { - c.mux.Lock() - defer c.mux.Unlock() - - if err := c.SetReadDeadline(t); err != nil { - return err - } - return c.SetWriteDeadline(t) -} - -func (c *websocketConn) SetWriteDeadline(t time.Time) error { - c.mux.Lock() - defer c.mux.Unlock() - return c.Conn.SetWriteDeadline(t) -} diff --git a/pkg/sdk/aliyun/aliyun_sdk.go b/pkg/sdk/aliyun/aliyun_sdk.go index 85feb74..ea11425 100644 --- a/pkg/sdk/aliyun/aliyun_sdk.go +++ b/pkg/sdk/aliyun/aliyun_sdk.go @@ -252,7 +252,7 @@ func sync(ca *models.CloudAuth, regions []string) (models.TunnelCreateApiList, e for _, t := range respT.Triggers { if *t.TriggerType == "http" { *tun.Addr = strings.Replace(t.UrlInternet, "https://", "", -1) - tun.Config.FcAuthType = enum.TransAuthType(t.TriggerConfig.AuthType) + tun.Config.FcAuthType = enum.TransCloudFCAuthType(t.TriggerConfig.AuthType) } } *tun.Status = enum.TunnelActive diff --git a/pkg/sdk/sdk.go b/pkg/sdk/sdk.go index 7ded798..ff4338e 100644 --- a/pkg/sdk/sdk.go +++ b/pkg/sdk/sdk.go @@ -23,14 +23,15 @@ type CloudSDK interface { // UpdateVersion(auth models.CloudAuth) error } -var cloudFactory = map[enum.ProviderType]CloudSDK{} - func GetSDK(t enum.ProviderType) CloudSDK { - return cloudFactory[t] -} - -func init() { - cloudFactory[enum.ProvTypeALiYun] = &aliyun.SDK{} - cloudFactory[enum.ProvTypeTencentYun] = &tencent.SDK{} - cloudFactory[enum.ProvTypeSealos] = &sealos.SDK{} + switch t { + case enum.ProvTypeALiYun: + return &aliyun.SDK{} + case enum.ProvTypeTencentYun: + return &tencent.SDK{} + case enum.ProvTypeSealos: + return &sealos.SDK{} + default: + return nil + } } diff --git a/pkg/sdk/sealos/sealos.go b/pkg/sdk/sealos/sealos.go index b8f9a41..6ad8451 100644 --- a/pkg/sdk/sealos/sealos.go +++ b/pkg/sdk/sealos/sealos.go @@ -83,7 +83,7 @@ func (s *SDK) SyncFC(ca *models.CloudAuth, regions []string) (models.TunnelCreat CPU: float32(svc.Spec.Template.Spec.Containers[0].Resources.Limits.Cpu().MilliValue()) / 1000, Memory: int32(svc.Spec.Template.Spec.Containers[0].Resources.Limits.Memory().MilliValue()) / 1024 / 1024 / 1000, Instance: *svc.Spec.Replicas, - FcAuthType: enum.AuthEmpty, // sealos暂不支持认证 + FcAuthType: enum.CloudFCAuthEmpty, // sealos暂不支持认证 Tor: false, TLS: true, } diff --git a/pkg/sdk/tencent/tencent.go b/pkg/sdk/tencent/tencent.go index 2b0e16b..25fe4c6 100644 --- a/pkg/sdk/tencent/tencent.go +++ b/pkg/sdk/tencent/tencent.go @@ -89,7 +89,7 @@ func (t *SDK) SyncFC(ca *models.CloudAuth, regions []string) (models.TunnelCreat *tun.Port = int32(*fc.detail.ImageConfig.ImagePort) *tun.Status = enum.TunnelActive *tun.Addr = fc.addr - tun.Config.FcAuthType = enum.TransAuthType(fc.auth) + tun.Config.FcAuthType = enum.TransCloudFCAuthType(fc.auth) res = append(res, tun) } return res, nil diff --git a/pkg/system/keys/keys.go b/pkg/system/keys/keys.go new file mode 100644 index 0000000..df73b29 --- /dev/null +++ b/pkg/system/keys/keys.go @@ -0,0 +1,11 @@ +package keys + +var key []byte + +func SetGlobalKey(k []byte) { + key = k +} + +func GetGlobalKey() []byte { + return key +} diff --git a/pkg/system/tools/crypt.go b/pkg/system/tools/crypt.go new file mode 100644 index 0000000..457ace6 --- /dev/null +++ b/pkg/system/tools/crypt.go @@ -0,0 +1,93 @@ +package tools + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "io" + "time" + + "github.com/DVKunion/SeaMoon/pkg/system/errors" +) + +// PKCS7Padding pads the plaintext to be a multiple of the block size +func PKCS7Padding(data []byte, blockSize int) []byte { + padding := blockSize - len(data)%blockSize + padText := bytes.Repeat([]byte{byte(padding)}, padding) + return append(data, padText...) +} + +// PKCS7UnPadding unpads the plaintext +func PKCS7UnPadding(data []byte) ([]byte, error) { + length := len(data) + if length == 0 { + return nil, errors.New("invalid padding size") + } + unpadding := int(data[length-1]) + return data[:(length - unpadding)], nil +} + +// AESEncrypt encrypts the given plaintext using AES with the given key and returns the ciphertext +func AESEncrypt(plaintext, key []byte) (string, error) { + block, err := aes.NewCipher(key) + if err != nil { + return "", err + } + + blockSize := block.BlockSize() + plaintext = PKCS7Padding(plaintext, blockSize) + + ciphertext := make([]byte, blockSize+len(plaintext)) + iv := ciphertext[:blockSize] + + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "", err + } + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[blockSize:], plaintext) + + return base64.StdEncoding.EncodeToString(ciphertext), nil +} + +// AESDecrypt decrypts the given ciphertext using AES with the given key and returns the plaintext +func AESDecrypt(ciphertext string, key []byte) ([]byte, error) { + cipherData, err := base64.StdEncoding.DecodeString(ciphertext) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + blockSize := block.BlockSize() + if len(cipherData) < blockSize { + return nil, errors.New("ciphertext too short") + } + + iv := cipherData[:blockSize] + cipherData = cipherData[blockSize:] + + if len(cipherData)%blockSize != 0 { + return nil, errors.New("ciphertext is not a multiple of the block size") + } + + mode := cipher.NewCBCDecrypter(block, iv) + mode.CryptBlocks(cipherData, cipherData) + + return PKCS7UnPadding(cipherData) +} + +// GenerateKey generates a key using HMAC-SHA256 based on the provided time +func GenerateKey(t time.Time) []byte { + timeBytes := []byte(t.Format(time.DateTime)) + h := hmac.New(sha256.New, []byte("")) + h.Write(timeBytes) + return h.Sum(nil) +} diff --git a/pkg/system/tools/json.go b/pkg/system/tools/json.go new file mode 100644 index 0000000..5afd28a --- /dev/null +++ b/pkg/system/tools/json.go @@ -0,0 +1,19 @@ +package tools + +import ( + "encoding/json" + "reflect" +) + +func MarshalString(a any) string { + b, err := json.Marshal(a) + if err != nil { + switch cast := reflect.TypeOf(a); cast.Kind() { + case reflect.Array: + return "[]" + default: + return "" + } + } + return string(b) +} diff --git a/pkg/system/tools/jwt.go b/pkg/system/tools/jwt.go index 1cea6a8..4f426ba 100644 --- a/pkg/system/tools/jwt.go +++ b/pkg/system/tools/jwt.go @@ -14,7 +14,7 @@ func JWTAuth(user string) (string, error) { // 生成 token token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user": user, - "type": enum.AuthAdmin, + "type": enum.AdminAuth, "exp": time.Now().Add(time.Hour * 72).Unix(), }) diff --git a/pkg/system/tools/ptr.go b/pkg/system/tools/ptr.go index e553b2c..cc207cc 100644 --- a/pkg/system/tools/ptr.go +++ b/pkg/system/tools/ptr.go @@ -1,5 +1,7 @@ package tools +import "encoding/json" + func IntPtr(v int) *int { return &v } @@ -16,6 +18,10 @@ func UintPtr(v uint) *uint { return &v } +func Uint32Ptr(v uint32) *uint32 { + return &v +} + func Uint64Ptr(v uint64) *uint64 { return &v } @@ -98,6 +104,14 @@ func StringPtrs(vals []string) []*string { return ptrs } +func BytesPtr(vals []byte) *[]byte { + return &vals +} + +func JsonRawPtr(vals []byte) *json.RawMessage { + return (*json.RawMessage)(&vals) +} + func PtrInt32(v interface{}) int32 { if v != nil { switch cast := v.(type) { diff --git a/pkg/system/tools/random.go b/pkg/system/tools/random.go index 13fe630..aefe694 100644 --- a/pkg/system/tools/random.go +++ b/pkg/system/tools/random.go @@ -4,7 +4,7 @@ import ( "math/rand" "strings" - "github.com/v2fly/v2ray-core/v5/common/uuid" + "github.com/google/uuid" ) const randomList = "ASDFGHJKLZXCVBNMQWERTYUIOPasdfghjklzxcvbnmqwertyuiop1234567890" diff --git a/pkg/system/version/version.go b/pkg/system/version/version.go index a26fda0..b87ba58 100644 --- a/pkg/system/version/version.go +++ b/pkg/system/version/version.go @@ -1,9 +1,11 @@ package version -import core "github.com/v2fly/v2ray-core/v5" +import ( + "github.com/DVKunion/SeaMoon/plugins/xray" +) var ( - Version string = "dev" - Commit string = "" - V2rayCoreVersion string = core.Version() + Version string = "dev" + Commit string = "" + XrayVersion string = xray.GetVer() ) diff --git a/pkg/system/xlog/consts.go b/pkg/system/xlog/consts.go index 379e623..f254054 100644 --- a/pkg/system/xlog/consts.go +++ b/pkg/system/xlog/consts.go @@ -6,15 +6,6 @@ const ( ApiServerStart = "seamoon server start" ) -// SERVICE 相关日志 -const ( - ServiceSocks5ConnectServer = "service socks5 server handle connect" - ServiceSocks5Establish = "service socks5 establish connect" - ServiceSocks5DisConnect = "service socks5 disconnect" - ServiceTorConnectServer = "service tor server handle connect" - ServiceTorDisConnect = "service tor disconnect" -) - // SIGNAL 相关日志 const ( SignalStartProxy = "signal start proxy listener success" diff --git a/pkg/system/xlog/logger.go b/pkg/system/xlog/logger.go index 68ada62..715b8ab 100644 --- a/pkg/system/xlog/logger.go +++ b/pkg/system/xlog/logger.go @@ -8,11 +8,11 @@ import ( "github.com/gookit/color" ) -type logger struct { +type Logger struct { *slog.Logger } -func (l logger) Write(p []byte) (n int, err error) { +func (l Logger) Write(p []byte) (n int, err error) { s := strings.Replace(string(p), "\n", "", -1) group := "[GIN] " if strings.Contains(s, "[GIN") { @@ -34,11 +34,11 @@ func (l logger) Write(p []byte) (n int, err error) { return len(p), nil } -var defaultLog = &logger{slog.Default()} +var defaultLog = &Logger{slog.Default()} var index = "UNEXPECT" -func Logger() *logger { +func GetLogger() *Logger { return defaultLog } diff --git a/plugins/cf_worker/README.md b/plugins/cf_worker/README.md new file mode 100644 index 0000000..0f940bf --- /dev/null +++ b/plugins/cf_worker/README.md @@ -0,0 +1,4 @@ +# cf 插件收集 + +因为个人 js 无能,所以 worker 很大程度上依赖于外部开源的一些项目代码。 + diff --git a/plugins/xray/README.md b/plugins/xray/README.md new file mode 100644 index 0000000..97f0af6 --- /dev/null +++ b/plugins/xray/README.md @@ -0,0 +1,5 @@ +# Xray Package + +xray 相关外部闭包 + +保证所有的 xray 外部相关依赖在项目中只存在于该 package 中,项目内所有的调用均由 xray.go 暴露 \ No newline at end of file diff --git a/plugins/xray/config/config.go b/plugins/xray/config/config.go new file mode 100644 index 0000000..d71b809 --- /dev/null +++ b/plugins/xray/config/config.go @@ -0,0 +1,54 @@ +package config + +import ( + "github.com/xtls/xray-core/core" + "github.com/xtls/xray-core/infra/conf" + + "github.com/DVKunion/SeaMoon/plugins/xray/net" +) + +const seamoonApiTag = "seamoon-xray-api" + +var ( + empty = []byte("{}") +) + +type Config = conf.Config + +type BoundConfig struct { + Addr net.Address + Port net.Port + Tag string +} + +func Render(opts ...Options) (*core.Config, error) { + tmpl := &conf.Config{ + InboundConfigs: make([]conf.InboundDetourConfig, 0), + OutboundConfigs: make([]conf.OutboundDetourConfig, 0), + } + for _, o := range opts { + o(tmpl) + } + cf, err := tmpl.Build() + if err != nil { + return nil, err + } + return cf, nil +} + +type Options func(conf *conf.Config) + +func WithApiConfig() Options { + return func(cf *conf.Config) { + cf.API = &conf.APIConfig{ + Tag: seamoonApiTag, + Listen: "127.0.0.1:10086", + Services: []string{ + "HandlerService", + //"LoggerService", + "StatsService", + "RoutingService", + }, + } + } +} diff --git a/plugins/xray/config/inbound.go b/plugins/xray/config/inbound.go new file mode 100644 index 0000000..c41a94b --- /dev/null +++ b/plugins/xray/config/inbound.go @@ -0,0 +1,75 @@ +package config + +import ( + "fmt" + + "github.com/xtls/xray-core/infra/conf" + + "github.com/DVKunion/SeaMoon/pkg/api/models/abstract" + "github.com/DVKunion/SeaMoon/pkg/system/tools" + "github.com/DVKunion/SeaMoon/plugins/xray/net" +) + +var inboundProtoMaps = map[string]string{ + // http 默认配置了超时时间为300,0为不限制 + "http": `{"timeout": 300, "accounts": %s, "allowTransparent": false, "userLevel": 0}`, + // socks5 暂时不支持 udp + "socks": `{"auth": "%s", "accounts": %s, "udp": false, "ip": "127.0.0.1", "userLevel": 0}`, + // shadowsocks 暂时也不开 udp 和 ota, xray 实际上支持了多租户模式的socks, 本期暂时不开放 + "shadowsocks": `{"email": "%s", "method": "%s", "password": "%s", "level": 0, "ota": false, "network": "tcp"}`, + // torjan 暂时不支持 xray fallbacks 特性 + "torjan": `{"clients": %s, "fallbacks": []}`, + //"vmess": `{"clients": %s, "default": { "level": 0}, "detour": {"to": "tag_to_detour"}}`, + "vmess": `{"clients": %s, "default": {"level": 0}}`, + // vless 暂时不支持 xray fallbacks 特性, decryption 目前一直只能为空 + "vless": `{"clients": %s, "decryption": "none", "fallbacks": []}`, +} + +// WithHttpInbound http 入站配置 +func WithHttpInbound(bc *BoundConfig, auths abstract.AuthList) Options { + return withInbound("http", bc, + []byte(fmt.Sprintf(inboundProtoMaps["http"], auths.Marshal()))) +} + +// WithSocksInbound socks5 入站配置 +func WithSocksInbound(bc *BoundConfig, auths abstract.AuthList) Options { + if auths.IsEmpty() { + return withInbound("socks", bc, + []byte(fmt.Sprintf(inboundProtoMaps["socks"], "noauth", ""))) + } + return withInbound("socks", bc, + []byte(fmt.Sprintf(inboundProtoMaps["socks"], "password", auths.Marshal()))) +} + +func WithShadowSocksInbound(bc *BoundConfig, au *abstract.EmailPassAuth) Options { + return withInbound("shadowsocks", bc, + []byte(fmt.Sprintf(inboundProtoMaps["shadowsocks"], au.Email, au.Method, au.Password))) +} + +// WithTorjanInbound torjan 入站配置 +func WithTorjanInbound(bc *BoundConfig, auths abstract.AuthList) Options { + return withInbound("torjan", bc, + []byte(fmt.Sprintf(inboundProtoMaps["torjan"], auths.Marshal()))) +} + +func WithVmessInbound(bc *BoundConfig, auths abstract.AuthList) Options { + return withInbound("vmess", bc, + []byte(fmt.Sprintf(inboundProtoMaps["vmess"], auths.Marshal()))) +} + +func WithVlessInbound(bc *BoundConfig, auths abstract.AuthList) Options { + return withInbound("vless", bc, + []byte(fmt.Sprintf(inboundProtoMaps["vless"], auths.Marshal()))) +} + +func withInbound(proto string, bc *BoundConfig, settings []byte) Options { + return func(cf *conf.Config) { + cf.InboundConfigs = append(cf.InboundConfigs, conf.InboundDetourConfig{ + Protocol: proto, + Tag: bc.Tag, + ListenOn: net.A2Cfg(bc.Addr), + PortList: net.P2Cfg(bc.Port), + Settings: tools.JsonRawPtr(settings), + }) + } +} diff --git a/plugins/xray/config/logs.go b/plugins/xray/config/logs.go new file mode 100644 index 0000000..72eb4ba --- /dev/null +++ b/plugins/xray/config/logs.go @@ -0,0 +1,13 @@ +package config + +import "github.com/xtls/xray-core/infra/conf" + +func WithLogs(level string) Options { + return func(cf *conf.Config) { + cf.LogConfig = &conf.LogConfig{ + AccessLog: "", + ErrorLog: "", + LogLevel: level, + } + } +} diff --git a/plugins/xray/config/outbound.go b/plugins/xray/config/outbound.go new file mode 100644 index 0000000..9c03b82 --- /dev/null +++ b/plugins/xray/config/outbound.go @@ -0,0 +1,71 @@ +package config + +import ( + "fmt" + + "github.com/xtls/xray-core/infra/conf" + + "github.com/DVKunion/SeaMoon/pkg/api/models/abstract" + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +var outboundProtoMap = map[string]string{ + //"freedom": `{ "domainStrategy": "AsIs", "redirect": "127.0.0.1:3366", "userLevel": 0}`, + "http": `{"servers": [{"address": "%s", "port": %d, "users": %s}]}`, + "socks": `{"servers": [{"address": "%s", "port": %d, "users": %s}]}`, + "shadowsocks": `{"servers": [{"address": "%s", "port": %d, "method": %s, "password": %s, "email": "%s", "level": 0}]}`, + "torjan": `{"servers": [{"address": "%s", "port": %d, "password": "%s", "email": "%s", "level": 0}]}`, + "vmess": `{"vnext": [{"address": "%s", "port": %d, "users": %s}]}`, + "vless": `{"vnext": [{"address": "%s", "port": %d, "users": %s}]}`, +} + +// WithFreedomOutbound freedom 出站配置 +func WithFreedomOutbound() Options { + return withOutbound("freedom", "", nil, empty) +} + +// WithHttpOutbound http 出站配置 +func WithHttpOutbound(bc *BoundConfig, auths abstract.AuthList, sc *conf.StreamConfig) Options { + return withOutbound("http", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["http"], bc.Addr.String(), bc.Port, auths.Marshal()))) +} + +// WithSocksOutbound socks 出站配置 +func WithSocksOutbound(bc *BoundConfig, auths abstract.AuthList, sc *conf.StreamConfig) Options { + return withOutbound("socks", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["socks"], bc.Addr.String(), bc.Port, auths.Marshal()))) +} + +// WithShadowSocksOutbound shadowsocks 出站配置 +func WithShadowSocksOutbound(bc *BoundConfig, au abstract.EmailPassAuth, sc *conf.StreamConfig) Options { + return withOutbound("shadowsocks", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["shadowsocks"], bc.Addr.String(), bc.Port, au.Method, au.Password, au.Email))) +} + +func WithTorjanOutbound(bc *BoundConfig, au *abstract.EmailPassAuth, sc *conf.StreamConfig) Options { + return withOutbound("torjan", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["torjan"], bc.Addr.String(), bc.Port, au.Password, au.Email))) +} + +// WithVmessOutbound vmess 出站配置 +func WithVmessOutbound(bc *BoundConfig, auths abstract.AuthList, sc *conf.StreamConfig) Options { + return withOutbound("vmess", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["vmess"], bc.Addr.String(), bc.Port, auths.Marshal()))) +} + +// WithVlessOutbound vless 出站配置 +func WithVlessOutbound(bc *BoundConfig, auths abstract.AuthList, sc *conf.StreamConfig) Options { + return withOutbound("vless", bc.Tag, sc, + []byte(fmt.Sprintf(outboundProtoMap["vless"], bc.Addr.String(), bc.Port, auths.Marshal()))) +} + +func withOutbound(proto string, tag string, sc *conf.StreamConfig, settings []byte) Options { + return func(cf *conf.Config) { + cf.OutboundConfigs = append(cf.OutboundConfigs, conf.OutboundDetourConfig{ + Protocol: proto, + Tag: tag, + Settings: tools.JsonRawPtr(settings), + StreamSetting: sc, + }) + } +} diff --git a/plugins/xray/config/policy.go b/plugins/xray/config/policy.go new file mode 100644 index 0000000..2beb446 --- /dev/null +++ b/plugins/xray/config/policy.go @@ -0,0 +1,50 @@ +package config + +import ( + "github.com/xtls/xray-core/infra/conf" + + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +func WithDefaultPolicy() Options { + return func(cf *conf.Config) { + cf.Policy = &conf.PolicyConfig{ + Levels: map[uint32]*conf.Policy{ + // 0为代理策略 + 0: { + UplinkOnly: tools.Uint32Ptr(2), // 出站时,当服务端断开连接后最大中断等待时间,默认2 + DownlinkOnly: tools.Uint32Ptr(5), // 进站时,当客户端断开链接后最大中断等待时间,默认5 + // 暂时未开启用户流量统计 + StatsUserUplink: false, + StatsUserDownlink: false, + }, + // 1为管理api策略,不计入统计相关 + 1: { + StatsUserUplink: false, + StatsUserDownlink: false, + }, + }, + System: &conf.SystemPolicy{ + // 默认不开启全局流量统计 + StatsOutboundDownlink: false, + StatsOutboundUplink: false, + StatsInboundDownlink: false, + StatsInboundUplink: false, + }, + } + } +} + +func WithInboundCalculate() Options { + return func(conf *conf.Config) { + conf.Policy.System.StatsInboundUplink = true + conf.Policy.System.StatsInboundDownlink = true + } +} + +func WithOutboundCalculate() Options { + return func(conf *conf.Config) { + conf.Policy.System.StatsOutboundDownlink = true + conf.Policy.System.StatsOutboundUplink = true + } +} diff --git a/plugins/xray/config/stream.go b/plugins/xray/config/stream.go new file mode 100644 index 0000000..b9a73d1 --- /dev/null +++ b/plugins/xray/config/stream.go @@ -0,0 +1,34 @@ +package config + +import ( + "github.com/xtls/xray-core/infra/conf" + + "github.com/DVKunion/SeaMoon/pkg/system/tools" +) + +// WithWSSettings websocket stream 配置 +func WithWSSettings(tls bool, path string) *conf.StreamConfig { + return &conf.StreamConfig{ + Network: (*conf.TransportProtocol)(tools.StringPtr("websocket")), + Security: func() string { + if tls { + return "tls" + } + return "" + }(), + WSSettings: &conf.WebSocketConfig{ + Path: "/" + path, + }, + } +} + +// WithGrpcSettings grpc stream 配置 +func WithGrpcSettings(name string) *conf.StreamConfig { + return &conf.StreamConfig{ + Network: (*conf.TransportProtocol)(tools.StringPtr("grpc")), + Security: "tls", + GRPCConfig: &conf.GRPCConfig{ + ServiceName: name, + }, + } +} diff --git a/plugins/xray/net/addr.go b/plugins/xray/net/addr.go new file mode 100644 index 0000000..84043ff --- /dev/null +++ b/plugins/xray/net/addr.go @@ -0,0 +1,18 @@ +package net + +import ( + "github.com/xtls/xray-core/common/net" + "github.com/xtls/xray-core/infra/conf" +) + +type Address net.Address + +func A2Cfg(addr Address) *conf.Address { + return &conf.Address{ + Address: addr, + } +} + +func ParseAddress(addr string) Address { + return net.ParseAddress(addr) +} diff --git a/plugins/xray/net/port.go b/plugins/xray/net/port.go new file mode 100644 index 0000000..342f896 --- /dev/null +++ b/plugins/xray/net/port.go @@ -0,0 +1,33 @@ +package net + +import ( + "github.com/xtls/xray-core/common/net" + "github.com/xtls/xray-core/infra/conf" +) + +type Port *net.Port + +func PortFromInt(val uint32) Port { + p, err := net.PortFromInt(val) + if err != nil { + p = net.PortFromBytes([]byte("0")) + } + return &p +} +func PortFromString(val string) Port { + p, err := net.PortFromString(val) + if err != nil { + p = net.PortFromBytes([]byte("0")) + } + return &p +} + +func P2Cfg(p Port) *conf.PortList { + pr := net.SinglePortRange(*p) + return &conf.PortList{Range: []conf.PortRange{ + { + From: pr.From, + To: pr.To, + }, + }} +} diff --git a/plugins/xray/service/handle_service.go b/plugins/xray/service/handle_service.go new file mode 100644 index 0000000..223070c --- /dev/null +++ b/plugins/xray/service/handle_service.go @@ -0,0 +1,81 @@ +package service + +import ( + "context" + + "github.com/xtls/xray-core/app/proxyman/command" + + "github.com/DVKunion/SeaMoon/plugins/xray/config" +) + +type HandleService struct { + cc command.HandlerServiceClient +} + +func (h *HandleService) AddInbound(ctx context.Context, opts ...config.Options) error { + cf, err := config.Render(opts...) + if err != nil { + return err + } + for _, ibc := range cf.Inbound { + if _, err := h.cc.AddInbound(ctx, &command.AddInboundRequest{ + Inbound: ibc, + }); err != nil { + return err + } + } + return nil +} + +func (h *HandleService) AddOutbound(ctx context.Context, opts ...config.Options) error { + cf, err := config.Render(opts...) + if err != nil { + return err + } + for _, obc := range cf.Outbound { + if _, err := h.cc.AddOutbound(ctx, &command.AddOutboundRequest{ + Outbound: obc, + }); err != nil { + return err + } + } + return nil +} + +func (h *HandleService) AddInboundUser() { + // todo +} + +func (h *HandleService) AddOutboundUser() { + // todo +} + +func (h *HandleService) RemoveInbound(ctx context.Context, opts ...config.Options) error { + cf, err := config.Render(opts...) + if err != nil { + return err + } + for _, ibc := range cf.Inbound { + if _, err := h.cc.RemoveInbound(ctx, &command.RemoveInboundRequest{ + Tag: ibc.Tag, + }); err != nil { + return err + } + } + return nil +} + +func (h *HandleService) RemoveOutbound(ctx context.Context, opts ...config.Options) error { + cf, err := config.Render(opts...) + if err != nil { + return err + } + for _, obc := range cf.Inbound { + if _, err := h.cc.RemoveOutbound(ctx, &command.RemoveOutboundRequest{ + Tag: obc.Tag, + }); err != nil { + return err + } + } + return nil +} diff --git a/plugins/xray/service/handle_service_test.go b/plugins/xray/service/handle_service_test.go new file mode 100644 index 0000000..786a15c --- /dev/null +++ b/plugins/xray/service/handle_service_test.go @@ -0,0 +1,38 @@ +package service + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/xtls/xray-core/app/proxyman/command" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func TestAddInbound(t *testing.T) { + cc, err := grpc.NewClient(fmt.Sprintf("%s:%d", "127.0.0.1", 10086), + grpc.WithTransportCredentials( + insecure.NewCredentials(), + )) + assert.NoError(t, err) + sc := HandleService{ + cc: command.NewHandlerServiceClient(cc), + } + err = sc.AddInbound(context.Background()) + assert.NoError(t, err) +} + +func TestAddOutbound(t *testing.T) { + cc, err := grpc.NewClient(fmt.Sprintf("%s:%d", "127.0.0.1", 10086), + grpc.WithTransportCredentials( + insecure.NewCredentials(), + )) + assert.NoError(t, err) + sc := HandleService{ + cc: command.NewHandlerServiceClient(cc), + } + err = sc.AddInbound(context.Background()) + assert.NoError(t, err) +} diff --git a/plugins/xray/service/service.go b/plugins/xray/service/service.go new file mode 100644 index 0000000..8c0756a --- /dev/null +++ b/plugins/xray/service/service.go @@ -0,0 +1,19 @@ +package service + +import ( + handle "github.com/xtls/xray-core/app/proxyman/command" + states "github.com/xtls/xray-core/app/stats/command" + "google.golang.org/grpc" +) + +func NewHandleService(cc *grpc.ClientConn) HandleService { + return HandleService{ + cc: handle.NewHandlerServiceClient(cc), + } +} + +func NewStatesService(cc *grpc.ClientConn) StateService { + return StateService{ + cc: states.NewStatsServiceClient(cc), + } +} diff --git a/plugins/xray/service/state_service.go b/plugins/xray/service/state_service.go new file mode 100644 index 0000000..ba8e27c --- /dev/null +++ b/plugins/xray/service/state_service.go @@ -0,0 +1,66 @@ +package service + +import ( + "context" + "fmt" + + "github.com/xtls/xray-core/app/stats/command" +) + +type StateService struct { + cc command.StatsServiceClient +} + +// GetSysStates 获取系统状态 +func (s *StateService) GetSysStates(ctx context.Context) (*command.SysStatsResponse, error) { + return s.cc.GetSysStats(ctx, &command.SysStatsRequest{}) +} + +// GetUploadTrafficByEmail 获取用户的流量数据: 上行 +func (s *StateService) GetUploadTrafficByEmail(ctx context.Context, email string) (int64, error) { + return s.queryTraffic(ctx, fmt.Sprintf("user>>>%s>>>traffic>>>uplink", email), false) +} + +// GetDownloadTrafficByEmail 获取用户的流量数据: 下行 +func (s *StateService) GetDownloadTrafficByEmail(ctx context.Context, email string) (int64, error) { + return s.queryTraffic(ctx, fmt.Sprintf("user>>>%s>>>traffic>>>downlink", email), false) +} + +// GetUploadTrafficByTag 获取全局流量: 上行 +// bt: inbound / outbound +// tag: 对应要查询的 tag +func (s *StateService) GetUploadTrafficByTag(ctx context.Context, bt string, tag string) (int64, error) { + return s.queryTraffic(ctx, fmt.Sprintf("%s>>>%s>>>traffic>>>uplink", bt, tag), false) +} + +// GetDownloadTrafficByTag 获取全局流量: 下行 +// bt: bound_type: inbound / outbound +// tag: 对应要查询的 tag +func (s *StateService) GetDownloadTrafficByTag(ctx context.Context, bt string, tag string) (int64, error) { + return s.queryTraffic(ctx, fmt.Sprintf("%s>>>%s>>>traffic>>>downlink", bt, tag), false) +} + +// queryTraffic: 查询流量原生方法 ptn: 查询语句 reset: 是否重置 +func (s *StateService) queryTraffic(ctx context.Context, ptn string, reset bool) (int64, error) { + // 如果查无此用户或 bound 则返回-1, 默认值 -1 + var traffic int64 = -1 + resp, err := s.cc.QueryStats(ctx, &command.QueryStatsRequest{ + // 这里是查询语句,例如 “user>>>love@xray.com>>>traffic>>>uplink” 表示查询用户 email 为 love@xray.com 在所有入站中的上行流量 + Pattern: ptn, + // 是否重置流量信息(true, false),即完成查询后是否把流量统计归零 + Reset_: reset, + }) + if err != nil { + return traffic, err + } + // Get traffic data + stat := resp.GetStat() + // 判断返回 是否成功 + // 返回样例,value 值是我们需要的: [name:"inbound>>>proxy0>>>traffic>>>downlink" value:348789] + if len(stat) != 0 { + // 返回流量数据 byte + traffic = stat[0].Value + } + + return traffic, nil +} diff --git a/plugins/xray/service/state_service_test.go b/plugins/xray/service/state_service_test.go new file mode 100644 index 0000000..17fb872 --- /dev/null +++ b/plugins/xray/service/state_service_test.go @@ -0,0 +1,29 @@ +package service + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/xtls/xray-core/app/stats/command" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func TestSysState(t *testing.T) { + cc, err := grpc.NewClient(fmt.Sprintf("%s:%d", "127.0.0.1", 10086), + grpc.WithTransportCredentials( + insecure.NewCredentials(), + )) + assert.NoError(t, err) + sc := StateService{ + cc: command.NewStatsServiceClient(cc), + } + a, err := sc.GetSysStates(context.Background()) + assert.NoError(t, err) + assert.Equal(t, true, a.NumGoroutine > 0) + assert.Equal(t, true, a.NumGC > 0) + assert.Equal(t, true, a.Alloc > 0) + assert.Equal(t, true, a.TotalAlloc > 0) +} diff --git a/plugins/xray/xray.go b/plugins/xray/xray.go new file mode 100644 index 0000000..86c35d1 --- /dev/null +++ b/plugins/xray/xray.go @@ -0,0 +1,128 @@ +// Package xray +// wrapper for using in project +package xray + +import ( + "context" + "fmt" + "time" + + "github.com/xtls/xray-core/core" + "github.com/xtls/xray-core/infra/conf" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "github.com/DVKunion/SeaMoon/pkg/api/enum" + "github.com/DVKunion/SeaMoon/pkg/api/models" + "github.com/DVKunion/SeaMoon/pkg/system/errors" + "github.com/DVKunion/SeaMoon/plugins/xray/config" + "github.com/DVKunion/SeaMoon/plugins/xray/net" + "github.com/DVKunion/SeaMoon/plugins/xray/service" +) + +type Xray struct { + conn *grpc.ClientConn +} + +var versions = core.VersionStatement() + +func GetVer() string { + if len(versions) > 1 { + return versions[0] + } + return "unknown" +} + +func StartServer(opts ...config.Options) (core.Server, error) { + cfg, err := config.Render(opts...) + if err != nil { + return nil, errors.Wrap(err, "xray build error") + } + + server, err := core.New(cfg) + if err != nil { + return nil, errors.Wrap(err, "xray new error") + } + + return server, nil +} + +func (x Xray) Init() error { + if x.conn == nil { + cc, err := grpc.NewClient(fmt.Sprintf("%s:%d", "127.0.0.1", 10085), + grpc.WithTransportCredentials( + insecure.NewCredentials(), + )) + if err != nil { + return err + } + x.conn = cc + } + return nil +} + +func (x Xray) StartProxy(ctx context.Context, proxy models.Proxy, tunnel models.Tunnel) error { + if x.conn == nil { + return errors.New("need init grpc connection first") + } + handleService := service.NewHandleService(x.conn) + // 这里用一个 err chan 来处理过多的 if err 场景 + errC := make(chan error, 1) + doneC := make(chan struct{}) + // 配置出入信息 + go func() { + var sc *conf.StreamConfig + var inbound = &config.BoundConfig{ + Addr: net.ParseAddress(*proxy.ListenAddr), + Port: net.PortFromString(*proxy.ListenPort), + Tag: proxy.Tag(), + } + var outbound = &config.BoundConfig{ + Addr: net.ParseAddress(*tunnel.Addr), + Port: net.PortFromInt(uint32(*tunnel.Port)), + Tag: "", + } + switch *tunnel.Type { + case enum.TunnelTypeWST: + sc = config.WithWSSettings(tunnel.Config.TLS, *tunnel.Addr) + case enum.TunnelTypeGRT: + // todo + //sc = config.WithGrpcSettings(*proxy.Type) + } + switch *proxy.Type { + case enum.ProxyTypeHTTP: + errC <- handleService.AddInbound(ctx, config.WithHttpInbound(inbound, nil)) + case enum.ProxyTypeSOCKS5: + errC <- handleService.AddInbound(ctx, config.WithSocksInbound(inbound, nil)) + errC <- handleService.AddOutbound(ctx, config.WithSocksOutbound(outbound, nil, sc)) + case enum.ProxyTypeVmess: + errC <- handleService.AddInbound(ctx, config.WithSocksInbound(inbound, nil)) + errC <- handleService.AddOutbound(ctx, config.WithVmessOutbound(outbound, nil, sc)) + case enum.ProxyTypeVless: + errC <- handleService.AddInbound(ctx, config.WithSocksInbound(inbound, nil)) + errC <- handleService.AddOutbound(ctx, config.WithVlessOutbound(outbound, nil, sc)) + case enum.ProxyTypeShadowSocks: + errC <- handleService.AddInbound(ctx, config.WithSocksInbound(inbound, nil)) + errC <- handleService.AddOutbound(ctx, config.WithVlessOutbound(outbound, nil, sc)) + case enum.ProxyTypeTorjan: + errC <- handleService.AddInbound(ctx, config.WithSocksInbound(inbound, nil)) + errC <- handleService.AddOutbound(ctx, config.WithTorjanOutbound(outbound, nil, sc)) + default: + errC <- errors.New("un support") + } + }() + + for { + select { + case err := <-errC: + if err != nil { + return err + } + case <-doneC: + return nil + // 增加一个最大的超时时间 防止创建时候卡死了 + case <-time.After(30 * time.Second): + return errors.New("start proxy timeout") + } + } +} diff --git a/web/config/proxy.ts b/web/config/proxy.ts index 666cae1..f7ecf05 100644 --- a/web/config/proxy.ts +++ b/web/config/proxy.ts @@ -11,7 +11,7 @@ export default { // localhost:8000/api/** -> https://preview.pro.ant.design/api/** '/api/': { // 要代理的地址 - target: 'http://localhost:7778/', + target: 'http://localhost:7777/', // 配置了这个可以从 http 代理到 https // 依赖 origin 的功能可能需要这个,比如 cookie changeOrigin: true, diff --git a/web/config/routes.ts b/web/config/routes.ts index f8a8ca8..018981d 100644 --- a/web/config/routes.ts +++ b/web/config/routes.ts @@ -13,29 +13,65 @@ }, ], }, - // { - // path: '/dashboard', - // name: 'dashboard', - // icon: 'dashboard', - // component: './dashboard/', - // }, + { + path: '/dashboard', + name: 'dashboard', + icon: 'dashboard', + component: './dashboard/', + }, { path: '/service', name: 'service', icon: 'Thunderbolt', - component: './service/', + routes: [ + { + path: "/service", + component: "./service", + }, + { + name: 'network', + path: '/service/network', + component: './service/network', + }, + { + name: 'application', + path: '/service/application', + component: './service/application', + }, + { + component: './404', + }, + ], }, { path: '/function', name: 'function', icon: 'cluster', - component: './function/', + routes: [ + { + path: "/function", + component: "./function", + }, + { + name: 'network', + path: '/function/network', + component: './function/network', + }, + { + name: 'application', + path: '/function/application', + component: './function/application', + }, + { + component: './404', + }, + ], }, { - path: 'provider', - name: 'cloud', // 云账户相关配置 - icon: 'cloud', - component: './provider/', + path: 'account', + name: 'account', + icon: 'user', + component: './account/', }, { path: '/setting', @@ -45,8 +81,7 @@ }, { path: '/', - redirect: '/service', - // redirect: '/dashboard', + redirect: '/dashboard', }, { component: './404', diff --git a/web/package.json b/web/package.json index 2edc674..597edb6 100644 --- a/web/package.json +++ b/web/package.json @@ -47,12 +47,14 @@ "not ie <= 10" ], "dependencies": { + "@ant-design/charts": "^2.1.2", "@ant-design/icons": "^4.7.0", "@ant-design/pro-components": "1.1.5", "@umijs/route-utils": "^2.0.0", "antd": "^4.20.0", "classnames": "^2.3.0", "lodash": "^4.17.0", + "lodash-es": "^4.17.21", "moment": "^2.29.0", "omit.js": "^2.0.2", "rc-menu": "^9.1.0", diff --git a/web/src/app.tsx b/web/src/app.tsx index b49ffaa..e139614 100644 --- a/web/src/app.tsx +++ b/web/src/app.tsx @@ -33,8 +33,7 @@ export async function getInitialState(): Promise<{ const token = localStorage.getItem("token"); if (token !== "") { return token; - } - else { + } else { history.push(loginPath); } return ""; diff --git a/web/src/components/ServiceStatus/index.less b/web/src/components/ServiceStatus/index.less new file mode 100644 index 0000000..d9ce7b5 --- /dev/null +++ b/web/src/components/ServiceStatus/index.less @@ -0,0 +1,17 @@ +.status { + :global(.ant-statistic-title) { + font-size: 24px; + } + :global(.ant-statistic-content) { + font-size: 14px; + } +} + +.description { + :global(.ant-statistic-title) { + font-size: 12px; + } + :global(.ant-statistic-content) { + font-size: 14px; + } +} diff --git a/web/src/components/ServiceStatus/index.tsx b/web/src/components/ServiceStatus/index.tsx new file mode 100644 index 0000000..d131a70 --- /dev/null +++ b/web/src/components/ServiceStatus/index.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import {Badge, Space} from "antd"; +import type {PresetStatusColorType} from "antd/lib/_util/colors"; +import {StatisticCard} from "@ant-design/pro-components"; +import styles from "./index.less"; + +export type ServiceStatusProps = { + name: string + status: PresetStatusColorType + version: string + refers: string +}; + +export const ServiceStatus: React.FC = (props) => { + const {Statistic} = StatisticCard; + + return { + return {props.status} + }, + description: <> + { + + }}/> + + + > + }} + /> +} diff --git a/web/src/components/StepForm/ProviderSelect/index.tsx b/web/src/components/StepForm/ProviderSelect/index.tsx index eea8dad..78d0b41 100644 --- a/web/src/components/StepForm/ProviderSelect/index.tsx +++ b/web/src/components/StepForm/ProviderSelect/index.tsx @@ -1,7 +1,7 @@ import React, {useState} from "react"; import {ProFormSelect} from "@ant-design/pro-components"; -import {getActiveProvider} from "@/services/cloud/api"; -import {Space, Tag } from "antd"; +import {getActiveProvider} from "@/services/account/api"; +import {Space, Tag} from "antd"; import {CloudProvideTypeIcon, RegionEnum} from "@/enum/cloud"; export type ProviderProps = { @@ -9,60 +9,61 @@ export type ProviderProps = { }; export const ProviderSelect: React.FC = (props: ProviderProps) => { - const [cloud, setCloud] = useState>({}); + const [cloud, setCloud] = useState>({}); return <> { - const res: { key: number; label: JSX.Element; value: number; obj: Cloud.Provider; }[] = []; - const {data} = await getActiveProvider(); - data.forEach((item) => { - res.push( - { - key: item.id, - label: {CloudProvideTypeIcon[item.type]}{item.name}, - value: item.id, - obj: item - } - ) - }) - return res - }} - rules={[ - { - required: true, - message: "请选择关联云账户!", - }, - ]} - fieldProps={ - { - onSelect: (value, option) => { - setCloud(option["data-item"].obj); - props.onChange(option["data-item"].obj.type, option["data-item"].obj.regions) + name="provider_id" + label="选择关联云账户" + width={"xl"} + tooltip={"仅允许正常状态的账户"} + showSearch={true} + request={async () => { + const res: { key: number; label: JSX.Element; value: number; obj: Account.Provider; }[] = []; + const {data} = await getActiveProvider(); + data.forEach((item) => { + res.push( + { + key: item.id, + label: {CloudProvideTypeIcon[item.type]}{item.name}, + value: item.id, + obj: item } + ) + }) + return res + }} + rules={[ + { + required: true, + message: "请选择关联云账户!", + }, + ]} + fieldProps={ + { + onSelect: (value, option) => { + setCloud(option["data-item"].obj); + props.onChange(option["data-item"].obj.type, option["data-item"].obj.regions) } } - /> + } + /> {cloud.id !== undefined && cloud.id !== 0 ? <> - {cloud.info?.amount !== undefined ? 账户余额: 0 ? "volcano" : "green"}>{"¥" + cloud.info?.amount} : <>>} - {cloud.count !== undefined && cloud.max_limit !== undefined ? - 已部署函数限制: {cloud.count + " / " + (cloud.max_limit === 0 ? "∞" : cloud.max_limit)} : <>> - } + {cloud.info?.amount !== undefined ? 账户余额: 0 ? "volcano" : "green"}>{"¥" + cloud.info?.amount} : <>>} + {cloud.count !== undefined && cloud.max_limit !== undefined ? + 已部署函数限制: {cloud.count + " / " + (cloud.max_limit === 0 ? "∞" : cloud.max_limit)} + : <>> + } 允许部署区域: - - {cloud.regions?.map((region, index) => ( - {RegionEnum[region]} - ))} - > : <>> + + {cloud.regions?.map((region, index) => ( + {RegionEnum[region]} + ))} + > : <>> } - > + > } diff --git a/web/src/components/StepForm/TunnelForm/index.tsx b/web/src/components/StepForm/TunnelForm/index.tsx index 693e5e0..6f930fb 100644 --- a/web/src/components/StepForm/TunnelForm/index.tsx +++ b/web/src/components/StepForm/TunnelForm/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import {ProForm, ProFormSwitch, ProFormText, ProFormSelect} from "@ant-design/pro-components"; import {toNumber} from "lodash"; import {TunnelAuthFCTypeEnum, TunnelTypeValueEnum} from "@/enum/tunnel"; -import {CloudRegionOneSelector} from "@/pages/provider/components/AuthForm"; +import {CloudRegionOneSelector} from "@/pages/account/provider/AuthForm"; export type TunnelFormProps = { type: number diff --git a/web/src/components/StepForm/TunnelSelect/index.tsx b/web/src/components/StepForm/TunnelSelect/index.tsx index 0ace554..4397c72 100644 --- a/web/src/components/StepForm/TunnelSelect/index.tsx +++ b/web/src/components/StepForm/TunnelSelect/index.tsx @@ -26,10 +26,11 @@ export const TunnelSelect: React.FC = (props: TunnelProps) => { const res: { key: number; label: JSX.Element; value: number; obj: Serverless.Tunnel; }[] = []; const {data} = await getServerlessTunnel(0, 999999); data.forEach((item) => { - if(!props.tor || (props.tor && item.tunnel_config.tor)) { + if (!props.tor || (props.tor && item.tunnel_config.tor)) { res.push({ key: item.id, - label: {CloudProvideTypeValueEnum[item.provider_type || 0]} - {TunnelTypeValueEnum[item.type]} - {item.name}, + label: + {CloudProvideTypeValueEnum[item.provider_type || 0]} - {TunnelTypeValueEnum[item.type]} - {item.name}, value: item.id, obj: item }); diff --git a/web/src/locales/zh-CN/menu.ts b/web/src/locales/zh-CN/menu.ts index 6d34156..75cae24 100644 --- a/web/src/locales/zh-CN/menu.ts +++ b/web/src/locales/zh-CN/menu.ts @@ -1,9 +1,13 @@ export default { - 'menu.dashboard': '数据中心', + 'menu.dashboard': '系统状态', 'menu.setting': '系统配置', - 'menu.service': '服务', - 'menu.cloud': '云账户管理', - 'menu.function': '函数实例', + 'menu.service': '本地服务', + 'menu.service.network': '网络服务', + 'menu.service.application': '应用服务', + 'menu.account': '账户管理', + 'menu.function': '函数管理', + 'menu.function.network': '网络函数', + 'menu.function.application': '应用函数', 'menu.welcome': '欢迎', 'menu.more-blocks': '更多区块', 'menu.home': '首页', @@ -44,11 +48,6 @@ export default { 'menu.exception.not-find': '404', 'menu.exception.server-error': '500', 'menu.exception.trigger': '触发错误', - 'menu.account': '个人页', - 'menu.account.center': '个人中心', - 'menu.account.settings': '个人设置', - 'menu.account.trigger': '触发报错', - 'menu.account.logout': '退出登录', 'menu.editor': '图形编辑器', 'menu.editor.flow': '流程编辑器', 'menu.editor.mind': '脑图编辑器', diff --git a/web/src/pages/account/admin/Admin.tsx b/web/src/pages/account/admin/Admin.tsx new file mode 100644 index 0000000..e6427d3 --- /dev/null +++ b/web/src/pages/account/admin/Admin.tsx @@ -0,0 +1,93 @@ +import React, {useRef} from "react"; +import type {ActionType, ProColumns} from "@ant-design/pro-components"; +import {ProTable} from "@ant-design/pro-components"; +import UpdateForm from "@/pages/account/admin/UpdateForm"; +import {message} from "antd"; + +const AdminTable: React.FC = () => { + const actionRef = useRef(); + + const columns: ProColumns[] = [ + { + dataIndex: 'id', + key: 'id', + valueType: 'indexBorder', + width: 48, + }, + { + title: '账户名称', + key: 'name', + dataIndex: 'name', + copyable: true, + ellipsis: true, + }, + { + title: '账户类型', + key: 'type', + dataIndex: 'type', + }, + { + title: '最后一次登录时间', + key: 'last_time', + dataIndex: 'last_time', + valueType: 'dateTime', + responsive: ['md'], + hideInSearch: true, + disable: true, + }, + { + title: '最后一次登录地址', + key: 'last_addr', + dataIndex: 'last_addr', + }, + { + title: '其他操作', + key: 'option', + valueType: 'option', + render: () => [ + { + }}> + 禁用 + , + { + // check validator first + if (values.password === values.old_password) { + message.error("新密码与旧密码相同"); + return true; + } + if (values.password !== values.password_repeat) { + message.error("两次输入的密码不一致"); + return true; + } + // do update + return true; + }}/> + ], + }, + ] + + return <> + + columns={columns} + actionRef={actionRef} + cardBordered + rowKey="id" + headerTitle={"客户端管理账户"} + search={false} + options={false} + pagination={{ + defaultPageSize: 12, + showSizeChanger: true, + }} + dateFormatter="string" + dataSource={[{ + name: "admin", + type: "admin", + last_addr: "127.0.0.1", + last_time: "2024-08-06", + }]} + /> + > +} + +export default AdminTable diff --git a/web/src/pages/account/admin/UpdateForm.tsx b/web/src/pages/account/admin/UpdateForm.tsx new file mode 100644 index 0000000..f724ff7 --- /dev/null +++ b/web/src/pages/account/admin/UpdateForm.tsx @@ -0,0 +1,76 @@ +import {ModalForm, ProForm, ProFormText} from '@ant-design/pro-components'; +import React from 'react'; + +export type FormValueType = { + old_password: string, + password: string, + password_repeat: string, +} + +export type UpdateFormProps = { + onSubmit: (values: FormValueType) => Promise; +}; + +const UpdateForm: React.FC = (props) => { + + return ( + + width={640} + title={"修改密码"} + trigger={ + + 修改密码 + + } + autoFocusFirstInput + modalProps={{ + destroyOnClose: true, + }} + onFinish={props.onSubmit} + > + + + + + + +); +}; + +export default UpdateForm; diff --git a/web/src/pages/provider/handle.tsx b/web/src/pages/account/handle.tsx similarity index 94% rename from web/src/pages/provider/handle.tsx rename to web/src/pages/account/handle.tsx index 68e31da..b95634b 100644 --- a/web/src/pages/provider/handle.tsx +++ b/web/src/pages/account/handle.tsx @@ -1,7 +1,7 @@ import {message} from "antd"; import {toNumber} from "lodash"; -import type {FormValueType} from "@/pages/provider/components/CreateForm"; -import {createProvider, deleteProvider, syncProvider, updateProvider} from "@/services/cloud/api"; +import type {FormValueType} from "@/pages/account/provider/CreateForm"; +import {createProvider, deleteProvider, syncProvider, updateProvider} from "@/services/account/api"; export const handleCreateCloud = async (fields: FormValueType) => { const hide = message.loading('创建中......', 30); diff --git a/web/src/pages/account/index.tsx b/web/src/pages/account/index.tsx new file mode 100644 index 0000000..1f8bd32 --- /dev/null +++ b/web/src/pages/account/index.tsx @@ -0,0 +1,40 @@ +import React, {useState} from "react"; +import {PageContainer} from "@ant-design/pro-components"; +import ProviderTable from "@/pages/account/provider/Provider"; +import AdminTable from "@/pages/account/admin/Admin"; +import TunnelTable from "@/pages/account/tunnel/Tunnel"; + +const Account: React.FC = () => { + + const [currentTab, setCurrentTab] = useState("cloud_provider"); + + return { + setCurrentTab(key) + } + } + extra={""}> + { + currentTab == "admin_auth" ? : + currentTab == "proxy_auth" ? : + } + +} + +export default Account diff --git a/web/src/pages/provider/components/AuthForm.tsx b/web/src/pages/account/provider/AuthForm.tsx similarity index 100% rename from web/src/pages/provider/components/AuthForm.tsx rename to web/src/pages/account/provider/AuthForm.tsx diff --git a/web/src/pages/provider/components/CreateForm.tsx b/web/src/pages/account/provider/CreateForm.tsx similarity index 95% rename from web/src/pages/provider/components/CreateForm.tsx rename to web/src/pages/account/provider/CreateForm.tsx index 7cc037e..74ca087 100644 --- a/web/src/pages/provider/components/CreateForm.tsx +++ b/web/src/pages/account/provider/CreateForm.tsx @@ -6,7 +6,7 @@ import { import {Modal} from 'antd'; import React, {useState} from 'react'; import {CloudProvideTypeValueEnum} from "@/enum/cloud"; -import {CloudProviderAuthForm} from "@/pages/provider/components/AuthForm"; +import {CloudProviderAuthForm} from "./AuthForm"; import {toNumber} from "lodash"; export type FormValueType = { @@ -15,13 +15,13 @@ export type FormValueType = { access_secret?: string, token?: string, kube_config?: string, -} & Partial; +} & Partial; export type CreateFormProps = { onCancel: (flag?: boolean, formValue?: FormValueType) => void; onSubmit: (values: FormValueType) => Promise; createModalVisible: boolean; - values: Partial; + values: Partial; }; const CreateForm: React.FC = (props) => { diff --git a/web/src/pages/provider/components/DetailDrawer.tsx b/web/src/pages/account/provider/DetailDrawer.tsx similarity index 86% rename from web/src/pages/provider/components/DetailDrawer.tsx rename to web/src/pages/account/provider/DetailDrawer.tsx index a5b3841..b94b4ca 100644 --- a/web/src/pages/provider/components/DetailDrawer.tsx +++ b/web/src/pages/account/provider/DetailDrawer.tsx @@ -1,10 +1,10 @@ import React, {useRef, useState} from 'react'; import type {ProDescriptionsActionType} from '@ant-design/pro-components'; import {ProDescriptions} from '@ant-design/pro-components'; -import {FormValueType} from "./CreateForm"; -import {Button, Divider, Drawer, Popconfirm, Space, Tag, Tooltip, Badge} from "antd"; +import type {FormValueType} from "./CreateForm"; +import {Badge, Button, Divider, Drawer, Popconfirm, Space, Tag, Tooltip} from "antd"; import {CloudProviderStatusEnum, CloudProvideTypeValueEnum, RegionEnum} from "@/enum/cloud"; -import {AuthColumns, CloudRegionSelector} from "@/pages/provider/components/AuthForm"; +import {AuthColumns, CloudRegionSelector} from "./AuthForm"; import {SyncOutlined} from "@ant-design/icons"; export type DetailProps = { @@ -13,7 +13,7 @@ export type DetailProps = { onSync: (values: FormValueType) => Promise; onSubmit: (values: FormValueType) => Promise; detailVisible: boolean; - values: Partial; + values: Partial; }; const DetailDrawer: React.FC = (props) => { @@ -58,8 +58,8 @@ const DetailDrawer: React.FC = (props) => { column={2} actionRef={actionRef} editable={{ - onSave: async (keypath, newInfo, oriInfo) => { - props.values[keypath.toString()] = newInfo[keypath.toString()]; + onSave: async (key_path, newInfo) => { + props.values[key_path.toString()] = newInfo[key_path.toString()]; return true; }, }} @@ -76,12 +76,13 @@ const DetailDrawer: React.FC = (props) => { editable: false, dataIndex: 'status', render: (dom, entry) => { - return + return + }, }, { diff --git a/web/src/pages/provider/index.tsx b/web/src/pages/account/provider/Provider.tsx similarity index 86% rename from web/src/pages/provider/index.tsx rename to web/src/pages/account/provider/Provider.tsx index c9fa05c..928452c 100644 --- a/web/src/pages/provider/index.tsx +++ b/web/src/pages/account/provider/Provider.tsx @@ -1,22 +1,21 @@ -import React, {useRef, useState} from "react"; -import {PageContainer, ProTable, ActionType, ProColumns} from "@ant-design/pro-components"; -import {Button, Popconfirm, Badge, Tooltip} from "antd"; +import React,{useRef,useState} from "react"; +import type {ActionType, ProColumns} from "@ant-design/pro-components"; +import {ProTable} from "@ant-design/pro-components"; +import {CloudProviderStatusEnum, CloudProvideTypeEnum} from "@/enum/cloud"; +import {Badge, Popconfirm, Tooltip, Button} from "antd"; +import {handleCreateCloud, handleDeleteCloud, handleSyncCloud, handleUpdateCloud} from "@/pages/account/handle"; +import {getCloudProvider} from "@/services/account/api"; import {PlusOutlined} from "@ant-design/icons"; -import {getCloudProvider} from "@/services/cloud/api"; -import {handleCreateCloud, handleDeleteCloud, handleSyncCloud, handleUpdateCloud} from './handle'; -import {CloudProvideTypeEnum, CloudProviderStatusEnum} from "@/enum/cloud"; -import CreateForm from './components/CreateForm'; -import DetailDrawer from "./components/DetailDrawer"; - -const Provider: React.FC = () => { +import CreateForm from "./CreateForm"; +import DetailDrawer from "./DetailDrawer"; +const ProviderTable: React.FC = () => { const actionRef = useRef(); const [detailModalVisible, setDetailVisible] = useState(false); const [createModalVisible, setCreateVisible] = useState(false); - const [currentRow, setCurrentRow] = useState(); - + const [currentRow, setCurrentRow] = useState(); - const columns: ProColumns[] = [ + const columns: ProColumns[] = [ { dataIndex: 'id', key: 'id', @@ -95,7 +94,7 @@ const Provider: React.FC = () => { }}> 详情 , - { await handleDeleteCloud(record.id); @@ -106,15 +105,14 @@ const Provider: React.FC = () => { okText="确认" cancelText="取消" > - 删除 + 删除 ], }, ]; - return - + return <> + columns={columns} actionRef={actionRef} cardBordered @@ -147,7 +145,7 @@ const Provider: React.FC = () => { } type="primary" onClick={() => { setCreateVisible(true) }}> - 新增 + 新增云账户 , ]} /> @@ -205,7 +203,8 @@ const Provider: React.FC = () => { detailVisible={detailModalVisible} values={currentRow || {}} /> - + > } -export default Provider + +export default ProviderTable diff --git a/web/src/pages/account/tunnel/Tunnel.tsx b/web/src/pages/account/tunnel/Tunnel.tsx new file mode 100644 index 0000000..34704cc --- /dev/null +++ b/web/src/pages/account/tunnel/Tunnel.tsx @@ -0,0 +1,46 @@ +import React, {useRef} from "react"; +import {type ActionType, type ProColumns, ProTable} from "@ant-design/pro-components"; + +const TunnelTable: React.FC = () => { + const actionRef = useRef(); + const columns: ProColumns[] = [ + { + dataIndex: 'id', + key: 'id', + valueType: 'indexBorder', + width: 48, + }, + { + title: '账户名称', + key: 'name', + dataIndex: 'name', + copyable: true, + ellipsis: true, + }, + { + title: '账户类型', + key: 'type', + dataIndex: 'type', + copyable: true, + ellipsis: true, + }, + ] + + return <> + + columns={columns} + actionRef={actionRef} + cardBordered + rowKey="id" + headerTitle={"隧道账户"} + search={false} + options={false} + pagination={{ + defaultPageSize: 12, + showSizeChanger: true, + }} + dateFormatter="string" + />> +} + +export default TunnelTable diff --git a/web/src/pages/dashboard/index.less b/web/src/pages/dashboard/index.less index 8289ebe..38044d6 100644 --- a/web/src/pages/dashboard/index.less +++ b/web/src/pages/dashboard/index.less @@ -1,4 +1,8 @@ -.icon-large svg { - width: 3em; - height: 3em; +.status { + :global(.ant-statistic-title) { + font-size: 24px; + } + :global(.ant-statistic-content) { + font-size: 14px; + } } diff --git a/web/src/pages/dashboard/index.tsx b/web/src/pages/dashboard/index.tsx index 7ccbe9b..d6647cb 100644 --- a/web/src/pages/dashboard/index.tsx +++ b/web/src/pages/dashboard/index.tsx @@ -1,17 +1,170 @@ -import {PageContainer} from '@ant-design/pro-components'; -import React, {useState} from 'react'; -import {StatisticCard} from '@ant-design/pro-components'; +import {PageContainer, ProCard, StatisticCard} from '@ant-design/pro-components'; +import React, {useEffect, useRef, useState} from 'react'; import RcResizeObserver from 'rc-resize-observer'; -import IconFont from "@/components/IconFont"; +import {Badge, Progress} from "antd"; +import {Line} from '@ant-design/plots'; +import {ServiceStatus} from "@/components/ServiceStatus"; + +const {Divider} = StatisticCard; +const colors = [ + "#28a745", "#32ad46", "#3cb548", "#46bd49", "#51c44b", + "#5bcc4c", "#66d34d", "#70db4f", "#7ae351", "#84ea52", + "#8ff254", "#99fa55", "#a3fc57", "#adfe5b", "#b7ff5f", + "#c1ff63", "#cbff68", "#d5ff6c", "#dfff70", "#e9ff74", + "#f2f276", "#f3e671", "#f4da6d", "#f5cd69", "#f6c065", + "#f7b361", "#f8a75d", "#f99b59", "#fa8f55", "#fb8351", + "#fc774d", "#fd6b49", "#fe5f45", "#ff5341", "#ff473d", + "#ff3b39", "#ff2f35", "#ff2331", "#ff172d", "#ff0b29", + "#f8092a", "#f1082b", "#ea072d", "#e3062e", "#dc0530", + "#d50431", "#ce0333", "#c70234", "#c00136", "#dc3545" +]; + +type NetworkProps = { + values: { + time: number, + up: number, + down: number, + }[] +} + +function formatTimestamp(timestamp: number) { + const date = new Date(timestamp); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + const seconds = date.getSeconds().toString().padStart(2, '0'); + + return `${hours}:${minutes}:${seconds}`; +} + +function formatTimestampDate(timestamp: number) { + const date = new Date(timestamp); + + const year = date.getFullYear(); // 获取两位数的年份 + const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 获取月份(从0开始,所以要加1) + const day = date.getDate().toString().padStart(2, '0'); // 获取日期 + + const hours = date.getHours().toString().padStart(2, '0'); // 获取小时 + const minutes = date.getMinutes().toString().padStart(2, '0'); // 获取分钟 + const seconds = date.getSeconds().toString().padStart(2, '0'); // 获取秒数 + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} + +const Networks: React.FC = (props) => { + const config = { + height: 230, + data: { + value: props.values, + transform: [ + { + type: 'fold', + fields: ['up', 'down'], + key: 'type', + value: 'value', + }, + ], + }, + xField: (d: any) => formatTimestamp(d.time), + yField: 'value', + colorField: 'type', + legend: { + color: { + itemLabelFill: 'rgba(229, 224, 216, 0.85)' + } + }, + axis: { + x: { + // labelAutoHide: 'greedy', + labelFill: 'rgba(229, 224, 216, 0.85)' + }, + y: { + // labelAutoHide: 'greedy', + labelFill: 'rgba(229, 224, 216, 0.85)' + } + }, + } + + return ; +}; -// const {Statistic} = StatisticCard; const Index: React.FC = () => { const [responsive, setResponsive] = useState(false); + const [trafficData, setTrafficData] = useState([{time: 0, up: 0, down: 0}]); + const dataRef = useRef([{time: 0, up: 0, down: 0}]); + dataRef.current = trafficData; + + const now = new Date().getTime(); + useEffect(() => { + const interval = setInterval(() => { + const newData = { + time: new Date().getTime(), + up: Math.floor(Math.random() * 100), + down: Math.floor(Math.random() * 100), + }; + setTrafficData((prevData) => [...prevData.slice(-19), newData]); // 保持数据长度为20 + }, 2000); // 每秒更新一次数据 + + return () => clearInterval(interval); // 组件卸载时清除定时器 + }, []); + + // useEffect(() => { + // // 创建XMLHttpRequest对象 + // const xhr = new XMLHttpRequest(); + // + // // 配置请求 + // xhr.open('GET', 'http://127.0.0.1:9090/traffic', true); + // xhr.setRequestHeader('Transfer-Encoding', 'chunked'); + // + // let partialData = ''; + // + // // 监听onreadystatechange事件 + // xhr.onreadystatechange = () => { + // if (xhr.readyState === 3) { // readyState 3表示请求仍在处理中 + // partialData += xhr.responseText; + // + // // 处理响应数据,找到完整的JSON对象 + // let boundary = partialData.indexOf('}'); + // while (boundary !== -1) { + // const jsonString = partialData.slice(0, boundary + 1); + // partialData = partialData.slice(boundary + 1); + // + // try { + // const data = JSON.parse(jsonString); + // const time = Date.now(); + // const traffic = { time, ...data }; + // + // setTrafficData(prevData => { + // // 新数组包括新数据 + // const updatedData = [...prevData, traffic]; + // + // // 如果长度超过15,删除最早的数据 + // if (updatedData.length > 15) { + // updatedData.shift(); + // } + // console.log("update data: ",updatedData) + // return updatedData; + // }); + // } catch (e) { + // console.error('Error parsing JSON:', e); + // } + // + // boundary = partialData.indexOf('}'); + // } + // } + // }; + // + // // 发送请求 + // xhr.send(); + // + // // 清理函数:组件卸载时中止请求 + // return () => { + // xhr.abort(); + // }; + // }, []); return ( { setResponsive(offset.width < 596); }} > - - , - }} - /> - , - }} - /> - , - }} - /> - , - }} - /> - - + + + + + { + if (percent != undefined) { + return {percent} % + } + return {percent} % + }}/> + }/> + { + if (percent != undefined) { + return {percent} % + } + return {percent} % + }}/> + }/> + + + { + if (percent != undefined) { + return {percent} % + } + return {percent} % + }}/> + }/> + { + if (percent != undefined) { + return {percent} % + } + return {percent} % + }}/> + }/> + + + + + + + + + + + + + + + + + + + + + {/**/} + {/* ,*/} + {/* }}*/} + {/* />*/} + {/* ,*/} + {/* }}*/} + {/* />*/} + {/* ,*/} + {/* }}*/} + {/* />*/} + {/* ,*/} + {/* }}*/} + {/* />*/} + {/**/} + + { + setResponsive(offset.width < 596); + }} + > + + + + + + + + + + + + + + + + ); }; diff --git a/web/src/pages/function/application/index.tsx b/web/src/pages/function/application/index.tsx new file mode 100644 index 0000000..44c8779 --- /dev/null +++ b/web/src/pages/function/application/index.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import {PageContainer} from "@ant-design/pro-components"; + +const Application: React.FC = () => { + return +} + +export default Application diff --git a/web/src/pages/function/index.tsx b/web/src/pages/function/index.tsx index a1f60c2..4b12571 100644 --- a/web/src/pages/function/index.tsx +++ b/web/src/pages/function/index.tsx @@ -1,174 +1,11 @@ -import React, {useRef, useState} from "react"; -import {ActionType, PageContainer, ProList, StatisticCard, ProCard} from "@ant-design/pro-components"; -import {Badge, Button, Space, Tag, Tooltip} from "antd"; -import {PlusOutlined} from "@ant-design/icons"; -import IconFont from "@/components/IconFont"; -import CreateForm from "./components/CreateForm"; -import DetailDrawer from "./components/DetailDrawer"; -import {getServerlessTunnel} from "@/services/function/api"; -import {CloudProvideTypeValueEnum, RegionEnum} from "@/enum/cloud"; -import {TunnelStatusEnum, TunnelTypeValueEnum} from "@/enum/tunnel"; -import styles from "./index.less"; -import {handleCreateTunnel, handleDeleteTunnel, handleUpdateTunnel} from "@/pages/function/handle"; -import {ClashDropDown, ShadowRocketDropDown, SSrDropDown} from "@/components/Subcirber"; - -const {Statistic} = StatisticCard; - -const Tunnel: React.FC = () => { - - const actionRef = useRef(); - const [detailModalVisible, setDetailVisible] = useState(false); - const [createModalVisible, setCreateVisible] = useState(false); - const [currentRow, setCurrentRow] = useState(); +import React from "react"; +import {PageContainer} from "@ant-design/pro-components"; +const LocalService: React.FC = () => { return - - className={styles.proList} - actionRef={actionRef} - pagination={{ - defaultPageSize: 12, - showSizeChanger: true, - }} - request={async (params, sort, filter) => { - return getServerlessTunnel(params.current === undefined ? 0 : params.current - 1, params.pageSize === undefined ? 10 : params.pageSize); - }} - rowKey={"ID"} - showActions="hover" - rowSelection={{}} - grid={{gutter: 16, xs: 1, sm: 2, md: 2, lg: 2, xl: 3, xxl: 3}} - onItem={(record: Serverless.Tunnel) => { - return { - onClick: () => { - setCurrentRow(record); - setDetailVisible(true); - }, - }; - }} - toolBarRender={() => { - return [ - // , - , - , - } type="primary" - style={{marginLeft: "10px"}} - onClick={() => { - setCreateVisible(true) - }}> - 新增 - - ] - }} - metas={{ - title: { - dataIndex: 'name', - }, - subTitle: {}, - avatar: { - dataIndex: 'type', - formItemProps: { - style: { - fontSize: "150%", - } - }, - render: (_, record) => { - return TunnelTypeValueEnum[record.type] - } - }, - content: { - render: (dom, record) => { - return - - }/> - { - return {CloudProvideTypeValueEnum[record.provider_type]} - {RegionEnum[record.tunnel_config.region]} - }}/> - { - return record.address.length > 40 ? {record.address.substring(0, 39) + "..."} : record.address - }} - /> - - {record.tunnel_config.cpu} M {record.tunnel_config.memory} Mi }/> - - - } - }, - actions: { - cardActionProps: 'extra', - render: (_, record) => { - return - {record.tunnel_config.tls ? tls : <>>} - {record.tunnel_config.tor ? tor : <>>} - - } - }, - }} - headerTitle={隧道 - - Tunnel} - /> - { - const success = await handleCreateTunnel(value); - setCreateVisible(false); - if (actionRef.current) { - actionRef.current.reload(); - } - if (success) { - setCurrentRow(undefined); - } - }} - onCancel={() => { - setCreateVisible(false); - setCurrentRow(undefined); - }} - createModalVisible={createModalVisible} - values={currentRow || {}} - /> - { - const success = await handleUpdateTunnel(value) - setDetailVisible(false); - if (actionRef.current) { - actionRef.current.reload(); - } - if (success) { - setCurrentRow(undefined); - } - }} - onDelete={async (value) => { - // 检查当前状态是否为停止,如果非停止,则禁止删除。 - const success = await handleDeleteTunnel(value.id) - setDetailVisible(false); - if (success) { - setCurrentRow(undefined); - } - if (actionRef.current) { - actionRef.current.reload(); - } - }} - onCancel={() => { - setDetailVisible(false); - setCurrentRow(undefined); - }} - detailVisible={detailModalVisible} - values={currentRow || {}} - /> - + title={"函数管理"} + content={"展示和操作远端部署的函数服务"} + extra={""} /> } -export default Tunnel +export default LocalService diff --git a/web/src/pages/function/components/CreateForm.tsx b/web/src/pages/function/network/components/CreateForm.tsx similarity index 100% rename from web/src/pages/function/components/CreateForm.tsx rename to web/src/pages/function/network/components/CreateForm.tsx diff --git a/web/src/pages/function/components/DetailDrawer.tsx b/web/src/pages/function/network/components/DetailDrawer.tsx similarity index 98% rename from web/src/pages/function/components/DetailDrawer.tsx rename to web/src/pages/function/network/components/DetailDrawer.tsx index 829e594..378c6eb 100644 --- a/web/src/pages/function/components/DetailDrawer.tsx +++ b/web/src/pages/function/network/components/DetailDrawer.tsx @@ -5,9 +5,7 @@ import {Button, Divider, Drawer, Popconfirm, Space, Tooltip} from "antd"; import {TunnelAuthFCTypeEnum, TunnelStatusTag, TunnelTypeValueEnum} from "@/enum/tunnel"; import {CloudProvideTypeValueEnum, RegionEnum} from "@/enum/cloud"; import {CheckCircleTwoTone, CloseCircleTwoTone, PoweroffOutlined, SyncOutlined} from "@ant-design/icons"; -// @ts-ignore -import {CopyToClipboard} from 'react-copy-to-clipboard'; -import {FormValueType} from "./CreateForm"; +import type {FormValueType} from "./CreateForm"; export type DetailProps = { onCancel: () => void; diff --git a/web/src/pages/function/handle.tsx b/web/src/pages/function/network/handle.tsx similarity index 100% rename from web/src/pages/function/handle.tsx rename to web/src/pages/function/network/handle.tsx diff --git a/web/src/pages/function/index.less b/web/src/pages/function/network/index.less similarity index 100% rename from web/src/pages/function/index.less rename to web/src/pages/function/network/index.less diff --git a/web/src/pages/function/network/index.tsx b/web/src/pages/function/network/index.tsx new file mode 100644 index 0000000..b23b58f --- /dev/null +++ b/web/src/pages/function/network/index.tsx @@ -0,0 +1,180 @@ +import React, {useRef, useState} from "react"; +import type {ActionType} from "@ant-design/pro-components"; +import {PageContainer, ProCard, ProList, StatisticCard} from "@ant-design/pro-components"; +import {Badge, Button, Space, Tag, Tooltip} from "antd"; +import {PlusOutlined} from "@ant-design/icons"; +import IconFont from "@/components/IconFont"; +import CreateForm from "./components/CreateForm"; +import DetailDrawer from "./components/DetailDrawer"; +import {getServerlessTunnel} from "@/services/function/api"; +import {CloudProvideTypeValueEnum, RegionEnum} from "@/enum/cloud"; +import {TunnelStatusEnum, TunnelTypeValueEnum} from "@/enum/tunnel"; +import styles from "./index.less"; +import {handleCreateTunnel, handleDeleteTunnel, handleUpdateTunnel} from "@/pages/function/network/handle"; +import {ClashDropDown, ShadowRocketDropDown} from "@/components/Subcirber"; + +const {Statistic} = StatisticCard; + +const Tunnel: React.FC = () => { + + const actionRef = useRef(); + const [detailModalVisible, setDetailVisible] = useState(false); + const [createModalVisible, setCreateVisible] = useState(false); + const [currentRow, setCurrentRow] = useState(); + + return + + className={styles.proList} + actionRef={actionRef} + pagination={{ + defaultPageSize: 12, + showSizeChanger: true, + }} + request={async (params, sort, filter) => { + return getServerlessTunnel(params.current === undefined ? 0 : params.current - 1, params.pageSize === undefined ? 10 : params.pageSize); + }} + rowKey={"ID"} + showActions="hover" + rowSelection={{}} + grid={{gutter: 16, xs: 1, sm: 2, md: 2, lg: 2, xl: 3, xxl: 3}} + onItem={(record: Serverless.Tunnel) => { + return { + onClick: () => { + setCurrentRow(record); + setDetailVisible(true); + }, + }; + }} + toolBarRender={() => { + return [ + // , + , + , + } type="primary" + style={{marginLeft: "10px"}} + onClick={() => { + setCreateVisible(true) + }}> + 新增 + + ] + }} + metas={{ + title: { + dataIndex: 'name', + }, + subTitle: {}, + avatar: { + dataIndex: 'type', + formItemProps: { + style: { + fontSize: "150%", + } + }, + render: (_, record) => { + return TunnelTypeValueEnum[record.type] + } + }, + content: { + render: (dom, record) => { + return + + }/> + { + return {CloudProvideTypeValueEnum[record.provider_type]} - {RegionEnum[record.tunnel_config.region]} + }}/> + { + return record.address.length > 40 ? {record.address.substring(0, 39) + "..."} : record.address + }} + /> + + {record.tunnel_config.cpu} M {record.tunnel_config.memory} Mi }/> + + + } + }, + actions: { + cardActionProps: 'extra', + render: (_, record) => { + return + {record.tunnel_config.tls ? tls : <>>} + {record.tunnel_config.tor ? tor : <>>} + + } + }, + }} + headerTitle={正向代理} + /> + { + const success = await handleCreateTunnel(value); + setCreateVisible(false); + if (actionRef.current) { + actionRef.current.reload(); + } + if (success) { + setCurrentRow(undefined); + } + }} + onCancel={() => { + setCreateVisible(false); + setCurrentRow(undefined); + }} + createModalVisible={createModalVisible} + values={currentRow || {}} + /> + { + const success = await handleUpdateTunnel(value) + setDetailVisible(false); + if (actionRef.current) { + actionRef.current.reload(); + } + if (success) { + setCurrentRow(undefined); + } + }} + onDelete={async (value) => { + // 检查当前状态是否为停止,如果非停止,则禁止删除。 + const success = await handleDeleteTunnel(value.id) + setDetailVisible(false); + if (success) { + setCurrentRow(undefined); + } + if (actionRef.current) { + actionRef.current.reload(); + } + }} + onCancel={() => { + setDetailVisible(false); + setCurrentRow(undefined); + }} + detailVisible={detailModalVisible} + values={currentRow || {}} + /> + +} + +export default Tunnel diff --git a/web/src/pages/service/application/index.tsx b/web/src/pages/service/application/index.tsx new file mode 100644 index 0000000..0b939b5 --- /dev/null +++ b/web/src/pages/service/application/index.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import {PageContainer} from "@ant-design/pro-components"; + +const Application: React.FC = () => { + return +} + +export default Application diff --git a/web/src/pages/service/index.tsx b/web/src/pages/service/index.tsx index 8608628..ce48ec4 100644 --- a/web/src/pages/service/index.tsx +++ b/web/src/pages/service/index.tsx @@ -1,234 +1,11 @@ -import React, {useRef, useState, useEffect} from "react"; -import {Button, message, Space, Switch, Tag} from "antd"; -import {PageContainer, ActionType, ProList, StatisticCard, ProCard} from "@ant-design/pro-components"; -import IconFont from "@/components/IconFont"; -import {ProxyDynamicTagList, ProxyTypeIcon, ProxyTypeTagColor} from "@/enum/service"; -import {getServiceProxy} from "@/services/service/api"; -import {PlusOutlined} from "@ant-design/icons"; -import CreateForm from "@/pages/service/components/CreateForm"; -import DetailDrawer from "@/pages/service/components/DetailDrawer"; -import {handleCreateProxy, handleDeleteProxy, handleSpeedProxy, handleUpdateProxy} from "@/pages/service/handle"; -import {SpeedTransfer} from "@/components/SpeedTransfer"; - -const {Statistic} = StatisticCard; - -const calcThread = (n: number, o: number) => { - return n > o ? "up" : n === o ? undefined : "down" -} - -type staticProps = { - conn: number, - speed_up: number, - speed_down: number, - lag: number, - in_bound: number, - out_bound: number -} - -const Proxy: React.FC = () => { - - const actionRef = useRef(); - const [autoRoll, setAutoRoll] = useState(true); - const [showDetail, setShowDetail] = useState(false); - const [createModalVisible, handleModalVisible] = useState(false); - const [currentRow, setCurrentRow] = useState(); - const [nData, setNData] = useState>(new Map()); - const [oData, setOData] = useState>(new Map()); - - // 自动轮询器 - useEffect(() => { - if (autoRoll) { - const intervalId = setInterval(() => { - actionRef.current?.reload(); - }, 3000); // 每1秒刷新一次列表 - // 清除定时器 - return () => clearInterval(intervalId); - } - return; - }) +import React from "react"; +import {PageContainer} from "@ant-design/pro-components"; +const LocalService: React.FC = () => { return - - actionRef={actionRef} - pagination={{ - defaultPageSize: 12, - showSizeChanger: true, - }} - request={async (params, sort, filter) => { - const data = await getServiceProxy(params.current === undefined ? 0 : params.current - 1, params.pageSize === undefined ? 10 : params.pageSize) - if (data.success) { - const bData = new Map(); - data.data.forEach((item) => { - bData.set(item.id, { - conn: item.conn, - speed_up: item.speed_up, - speed_down: item.speed_down, - lag: item.lag, - in_bound: item.in_bound, - out_bound: item.out_bound, - }); - }) - // 是否是第一次: - if (oData.size === 0 && nData.size === 0) { - setOData(bData); - setNData(bData); - } - // 除此之外,先把原本新的给老的,再把刚得到的给新的。 - else { - setOData(nData); - setNData(bData); - } - } - return data; - }} - rowKey={"ID"} - showActions="hover" - rowSelection={{}} - grid={{gutter: 16, xs: 1, sm: 2, md: 2, lg: 2, xl: 3, xxl: 3}} - onItem={(record: any) => { - return { - onClick: () => { - setCurrentRow(record); - setShowDetail(true); - }, - }; - }} - toolBarRender={() => { - return [ { - setAutoRoll(!autoRoll); - }}/>, - } type="primary" - style={{marginLeft: "10px"}} - onClick={() => { - handleModalVisible(true) - }}> - 新增 - - ] - }} - metas={{ - title: { - dataIndex: 'name', - }, - subTitle: { - render: (_, record) => { - return - } - }, - avatar: { - dataIndex: 'type', - render: (_, record) => { - return ProxyTypeIcon[record.type]; - } - }, - content: { - render: (_, record) => { - const oRecord = oData.get(record.id); - return - - - - { - return SpeedTransfer({ - bytes: record.in_bound, - decimals: 2, - }); - }} trend={calcThread(record.in_bound, oRecord === undefined ? 0 : oRecord.in_bound)}/> - - - - - { - return SpeedTransfer({ - bytes: record.out_bound, - decimals: 2, - }); - }} trend={calcThread(record.out_bound, oRecord === undefined ? 0 : oRecord.out_bound)}/> - - - } - }, - actions: { - cardActionProps: 'extra', - render: (_, record) => { - return {record.type + "://" + record.listen_address + ":" + record.listen_port}; - } - }, - }} - headerTitle={代理 - Proxy} - /> - { - await handleCreateProxy(value); - handleModalVisible(false); - setCurrentRow(undefined); - if (actionRef.current) { - actionRef.current.reload(); - } - }} - onCancel={() => { - handleModalVisible(false); - setCurrentRow(undefined); - }} - createModalVisible={createModalVisible} - values={currentRow || {}} - /> - { - await handleUpdateProxy(value) - setShowDetail(false); - setCurrentRow(undefined); - if (actionRef.current) { - actionRef.current.reload(); - } - }} - onDelete={async (value) => { - // 检查当前状态是否为停止,如果非停止,则禁止删除。 - if (value.status === 2) { - message.error("当前服务状态仍在运行中,请确保服务停止后再删除"); - return; - } - await handleDeleteProxy(value) - setShowDetail(false); - setCurrentRow(undefined); - if (actionRef.current) { - actionRef.current.reload(); - } - }} - onSpeed={async (value) => { - await handleSpeedProxy(value) - setShowDetail(false); - setCurrentRow(undefined); - if (actionRef.current) { - actionRef.current.reload(); - } - }} - onCancel={() => { - setShowDetail(false); - setCurrentRow(undefined); - }} - detailVisible={showDetail} - values={currentRow || {}} - spin={autoRoll} - /> - + title={"本地服务"} + content={"运行在本地的一些服务,用于处理一些云端数据的解析客户端"} + extra={""} /> } -export default Proxy - +export default LocalService diff --git a/web/src/pages/service/components/CreateForm.tsx b/web/src/pages/service/network/components/CreateForm.tsx similarity index 100% rename from web/src/pages/service/components/CreateForm.tsx rename to web/src/pages/service/network/components/CreateForm.tsx diff --git a/web/src/pages/service/components/DetailDrawer.tsx b/web/src/pages/service/network/components/DetailDrawer.tsx similarity index 98% rename from web/src/pages/service/components/DetailDrawer.tsx rename to web/src/pages/service/network/components/DetailDrawer.tsx index d2c780f..61753fe 100644 --- a/web/src/pages/service/components/DetailDrawer.tsx +++ b/web/src/pages/service/network/components/DetailDrawer.tsx @@ -1,7 +1,7 @@ import React, {useRef} from 'react'; import type {ProDescriptionsActionType} from '@ant-design/pro-components'; import {ProDescriptions, ProFormSelect} from '@ant-design/pro-components'; -import {FormValueType} from "@/pages/service/components/CreateForm"; +import {FormValueType} from "@/pages/service/network/components/CreateForm"; import {Button, Divider, Drawer, Popconfirm, Space} from "antd"; import {PoweroffOutlined, SyncOutlined, ThunderboltTwoTone} from "@ant-design/icons"; import {ProxyDynamicTagList, ProxyTypeValueEnum} from "@/enum/service"; diff --git a/web/src/pages/service/handle.tsx b/web/src/pages/service/network/handle.tsx similarity index 95% rename from web/src/pages/service/handle.tsx rename to web/src/pages/service/network/handle.tsx index 8be65d7..a50b951 100644 --- a/web/src/pages/service/handle.tsx +++ b/web/src/pages/service/network/handle.tsx @@ -1,4 +1,4 @@ -import {FormValueType} from "@/pages/service/components/CreateForm"; +import type {FormValueType} from "@/pages/service/network/components/CreateForm"; import {message} from "antd"; import {createServiceProxy, deleteServiceProxy, speedServiceProxy, updateServiceProxy} from "@/services/service/api"; diff --git a/web/src/pages/service/network/index.tsx b/web/src/pages/service/network/index.tsx new file mode 100644 index 0000000..2a0a7fc --- /dev/null +++ b/web/src/pages/service/network/index.tsx @@ -0,0 +1,243 @@ +import React, {useRef, useState, useEffect} from "react"; +import {Button, message, Space, Switch, Tag} from "antd"; +import {PageContainer, ActionType, ProList, StatisticCard, ProCard} from "@ant-design/pro-components"; +import IconFont from "@/components/IconFont"; +import {ProxyDynamicTagList, ProxyTypeIcon, ProxyTypeTagColor} from "@/enum/service"; +import {getServiceProxy} from "@/services/service/api"; +import {PlusOutlined} from "@ant-design/icons"; +import CreateForm from "@/pages/service/network/components/CreateForm"; +import DetailDrawer from "@/pages/service/network/components/DetailDrawer"; +import {handleCreateProxy, handleDeleteProxy, handleSpeedProxy, handleUpdateProxy} from "@/pages/service/network/handle"; +import {SpeedTransfer} from "@/components/SpeedTransfer"; + +const {Statistic} = StatisticCard; + +const calcThread = (n: number, o: number) => { + return n > o ? "up" : n === o ? undefined : "down" +} + +type staticProps = { + conn: number, + speed_up: number, + speed_down: number, + lag: number, + in_bound: number, + out_bound: number +} + +const Proxy: React.FC = () => { + + const actionRef = useRef(); + const [autoRoll, setAutoRoll] = useState(true); + const [showDetail, setShowDetail] = useState(false); + const [createModalVisible, handleModalVisible] = useState(false); + const [currentRow, setCurrentRow] = useState(); + const [nData, setNData] = useState>(new Map()); + const [oData, setOData] = useState>(new Map()); + + // 自动轮询器 + useEffect(() => { + if (autoRoll) { + const intervalId = setInterval(() => { + actionRef.current?.reload(); + }, 5000); + // 清除定时器 + return () => clearInterval(intervalId); + } + return; + }) + + return + + actionRef={actionRef} + pagination={{ + defaultPageSize: 6, + showSizeChanger: true, + }} + request={async (params, sort, filter) => { + const data = await getServiceProxy(params.current === undefined ? 0 : params.current - 1, params.pageSize === undefined ? 10 : params.pageSize) + if (data.success) { + const bData = new Map(); + data.data.forEach((item) => { + bData.set(item.id, { + conn: item.conn, + speed_up: item.speed_up, + speed_down: item.speed_down, + lag: item.lag, + in_bound: item.in_bound, + out_bound: item.out_bound, + }); + }) + // 是否是第一次: + if (oData.size === 0 && nData.size === 0) { + setOData(bData); + setNData(bData); + } + // 除此之外,先把原本新的给老的,再把刚得到的给新的。 + else { + setOData(nData); + setNData(bData); + } + } + return data; + }} + rowKey={"ID"} + showActions="hover" + rowSelection={{}} + grid={{gutter: 16, xs: 1, sm: 2, md: 2, lg: 2, xl: 3, xxl: 3}} + onItem={(record: any) => { + return { + onClick: () => { + setCurrentRow(record); + setShowDetail(true); + }, + }; + }} + toolBarRender={() => { + return [ { + setAutoRoll(!autoRoll); + }}/>, + } type="primary" + style={{marginLeft: "10px"}} + onClick={() => { + handleModalVisible(true) + }}> + 新增 + + ] + }} + metas={{ + title: { + dataIndex: 'name', + }, + subTitle: { + render: (_, record) => { + return + } + }, + avatar: { + dataIndex: 'type', + render: (_, record) => { + return ProxyTypeIcon[record.type]; + } + }, + content: { + render: (_, record) => { + const oRecord = oData.get(record.id); + return + + + + { + return SpeedTransfer({ + bytes: record.in_bound, + decimals: 2, + }); + }} trend={calcThread(record.in_bound, oRecord === undefined ? 0 : oRecord.in_bound)}/> + + + + + { + return SpeedTransfer({ + bytes: record.out_bound, + decimals: 2, + }); + }} trend={calcThread(record.out_bound, oRecord === undefined ? 0 : oRecord.out_bound)}/> + + + } + }, + actions: { + cardActionProps: 'extra', + render: (_, record) => { + return {record.type + "://" + record.listen_address + ":" + record.listen_port}; + } + }, + }} + headerTitle={代理 - Proxy} + /> + { + await handleCreateProxy(value); + handleModalVisible(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + }} + onCancel={() => { + handleModalVisible(false); + setCurrentRow(undefined); + }} + createModalVisible={createModalVisible} + values={currentRow || {}} + /> + { + await handleUpdateProxy(value) + setShowDetail(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + }} + onDelete={async (value) => { + // 检查当前状态是否为停止,如果非停止,则禁止删除。 + if (value.status === 2) { + message.error("当前服务状态仍在运行中,请确保服务停止后再删除"); + return; + } + await handleDeleteProxy(value) + setShowDetail(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + }} + onSpeed={async (value) => { + await handleSpeedProxy(value) + setShowDetail(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + }} + onCancel={() => { + setShowDetail(false); + setCurrentRow(undefined); + }} + detailVisible={showDetail} + values={currentRow || {}} + spin={autoRoll} + /> + +} + +export default Proxy + diff --git a/web/src/pages/setting/index.tsx b/web/src/pages/setting/index.tsx index 4525d04..1c9f188 100644 --- a/web/src/pages/setting/index.tsx +++ b/web/src/pages/setting/index.tsx @@ -1,9 +1,8 @@ -import React, {useState, useRef} from "react"; -import {PageContainer, ProCard, ProForm, ProFormText, ProFormInstance, ProFormSwitch} from "@ant-design/pro-components"; -import {Button, message, Space, Tag} from "antd" +import React, {useRef, useState} from "react"; +import type { ProFormInstance} from "@ant-design/pro-components"; +import {PageContainer, ProCard, ProForm, ProFormSwitch, ProFormText} from "@ant-design/pro-components"; +import {Button} from "antd" import {getSysConfig} from "@/services/setting/api"; -import {GithubOutlined} from "@ant-design/icons"; -import {updatePasswd} from "@/services/user/api"; import {handleUpdateSysConfig} from "@/pages/setting/hanlder"; const Setting: React.FC = () => { @@ -12,7 +11,7 @@ const Setting: React.FC = () => { const [version, setVersion] = useState("") return 系统配置 } color="#7cd6cf">{version}} + title="系统配置" > { formRef={formRef} submitter={{ render: (props, doms) => { - return + return 保存 }, }} onFinish={async (values) => { - if (values["admin_password"] !== "" && values["admin_password"] != undefined) { - const res = await updatePasswd(values["admin_password"]); - if (res.success) { - message.success('修改密码成功', 1); - } else { - message.error(res.code + ":" + res.msg, 1) - } - } await handleUpdateSysConfig(values); values.auto_start = values.auto_start == "true"; values.auto_sync = values.auto_sync == "true"; @@ -65,7 +56,7 @@ const Setting: React.FC = () => { }} > + title={"Backend API 管理服务"}> { name="control_port" label="监听端口" tooltip={"如果你是通过 docker 启动的, 修改管理端口后,docker的端口映射也需要一起改变"} - colProps={{span: 8, offset:4}} + colProps={{span: 8, offset: 4}} placeholder={"e.g.: 7777"} /> { placeholder={"e.g.: .seamoon.log"} /> + + + { style={{display: 'flex', alignItems: 'center'}} /> - - - diff --git a/web/src/services/cloud/api.ts b/web/src/services/account/api.ts similarity index 92% rename from web/src/services/cloud/api.ts rename to web/src/services/account/api.ts index cdeb3aa..1dbda60 100644 --- a/web/src/services/cloud/api.ts +++ b/web/src/services/account/api.ts @@ -1,10 +1,10 @@ import request from '@/services/request' -import {FormValueType} from "@/pages/provider/components/CreateForm"; +import {FormValueType} from "@/pages/account/provider/CreateForm"; export async function getCloudProvider(page: number, size: number) { return request<{ success: boolean; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider?page=' + page + '&size=' + size, { method: 'GET', headers: { @@ -16,7 +16,7 @@ export async function getCloudProvider(page: number, size: number) { export async function getActiveProvider() { return request<{ success: boolean; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider/active', { method: 'GET', headers: { @@ -45,7 +45,7 @@ export async function createProvider(data: FormValueType) { success: boolean; msg?: string; code?: number; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider', { method: 'POST', headers: { @@ -91,7 +91,7 @@ export async function updateProvider(data: FormValueType) { success: boolean; msg?: string; code?: number; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider/' + data.id + "/", { method: 'PUT', headers: { @@ -106,7 +106,7 @@ export async function deleteProvider(id: number) { success: boolean; msg?: string; code?: number; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider/' + id + '/', { method: 'DELETE', headers: { @@ -120,7 +120,7 @@ export async function syncProvider(id: number) { success: boolean; msg?: string; code?: number; - data: Cloud.Provider[]; + data: Account.Provider[]; }>('/api/v1/provider/sync/' + id + '/', { method: 'PUT', headers: { diff --git a/web/src/services/cloud/types.d.ts b/web/src/services/account/types.d.ts similarity index 63% rename from web/src/services/cloud/types.d.ts rename to web/src/services/account/types.d.ts index 94fc3a3..cbfa5f6 100644 --- a/web/src/services/cloud/types.d.ts +++ b/web/src/services/account/types.d.ts @@ -1,4 +1,14 @@ -declare namespace Cloud { +declare namespace Account { + type Admin = { + name: string + type: string + last_addr: string + last_time: string + } + type Tunnel = { + name: string + type: number + } type Provider = { id: number, created_at: string,
账户余额:
已部署函数限制:
允许部署区域: