diff --git a/.github/workflows/latest.workflow.yml b/.github/workflows/latest.workflow.yml index 3ee1de8..c040962 100644 --- a/.github/workflows/latest.workflow.yml +++ b/.github/workflows/latest.workflow.yml @@ -11,6 +11,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: npm setup uses: actions/setup-node@v4 with: @@ -43,8 +45,13 @@ jobs: build-docker: runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v3 with: @@ -53,6 +60,7 @@ jobs: - name: Build and push uses: docker/build-push-action@v3 with: + context: . file: ./Dockerfile.standalone push: true platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/tag.workflow.yml b/.github/workflows/tag.workflow.yml index d6418b2..a891621 100644 --- a/.github/workflows/tag.workflow.yml +++ b/.github/workflows/tag.workflow.yml @@ -12,6 +12,8 @@ jobs: id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: npm setup uses: actions/setup-node@v4 with: @@ -44,8 +46,18 @@ jobs: build-docker: runs-on: ubuntu-latest steps: + - name: Get version + id: get_version + run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//} + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get git tag history + run: git fetch -a + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v3 with: @@ -54,6 +66,7 @@ jobs: - name: Build and push uses: docker/build-push-action@v3 with: + context: . file: ./Dockerfile.standalone push: true platforms: linux/amd64,linux/arm64 diff --git a/Dockerfile.standalone b/Dockerfile.standalone index fdabe5d..619e36c 100644 --- a/Dockerfile.standalone +++ b/Dockerfile.standalone @@ -1,9 +1,9 @@ # Stage 1: Building frontend FROM node:20-alpine AS frontend WORKDIR /app/www -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories +# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories RUN apk update --no-cache && apk add --no-cache tzdata git openssh -RUN npm config set registry https://registry.npmmirror.com +# RUN npm config set registry https://registry.npmmirror.com COPY www/package*.json . RUN corepack enable && corepack prepare pnpm@latest-9 --activate && pnpm install @@ -27,19 +27,20 @@ RUN ls && mkdir -p ../cmd/frpp && pnpm build # Stage 2: Building binary FROM golang:1.22-alpine AS builder WORKDIR /app -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories -RUN apk update --no-cache && apk add --no-cache tzdata git +# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories +RUN apk update --no-cache && apk add --no-cache tzdata git bash COPY go.mod go.sum ./ -RUN CGO_ENABLED=0 GOPROXY=https://goproxy.cn,https://proxy.golang.org,direct go mod download +# RUN CGO_ENABLED=0 GOPROXY=https://goproxy.cn,https://proxy.golang.org,direct go mod download +RUN CGO_ENABLED=0 go mod download COPY . . RUN rm -rf /app/cmd/frpp/out COPY --from=frontend /app/www/out ./cmd/frpp/out -RUN CGO_ENABLED=0 GOPROXY=https://goproxy.cn,https://proxy.golang.org,direct go build -ldflags="-s -w" -o frp-panel cmd/frpp/*.go +RUN ./build.sh --current --skip-frontend # Stage 3: Build image FROM alpine:latest WORKDIR /app -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories +# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories RUN apk update --no-cache && apk add --no-cache tzdata git && mkdir -p /data COPY --from=builder /app/frp-panel . @@ -48,6 +49,6 @@ EXPOSE 9000 # rpc port EXPOSE 9001 -ENV DB_DSN /data/data.db +ENV DB_DSN=/data/data.db ENTRYPOINT ["/app/frp-panel"] CMD ["master"] \ No newline at end of file diff --git a/README.md b/README.md index 48de693..f753787 100644 --- a/README.md +++ b/README.md @@ -37,20 +37,21 @@ frp-panel 可选 docker 和直接运行模式部署,直接部署请到 release - master ```bash -docker run -d -p 9000:9000 \ # API控制台端口 - -p 9001:9001 \ # rpc端口 - -p 7000:7000 \ # frps 端口 - -p 20000-20050:20000-20050 \ # 给frps预留的端口 +# 推荐 +docker run -d \ + --network=host \ --restart=unless-stopped \ - -v /opt/frp-panel:/data \ # 数据存储位置 + -v /opt/frp-panel:/data \ -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 -e MASTER_RPC_HOST=0.0.0.0 \ # 这里要改成你服务器的外部IP vaalacat/frp-panel # 或者 -docker run -d \ - --network=host \ +docker run -d -p 9000:9000 \ # API控制台端口 + -p 9001:9001 \ # rpc端口 + -p 7000:7000 \ # frps 端口 + -p 20000-20050:20000-20050 \ # 给frps预留的端口 --restart=unless-stopped \ - -v /opt/frp-panel:/data \ + -v /opt/frp-panel:/data \ # 数据存储位置 -e APP_GLOBAL_SECRET=your_secret \ # Master的secret注意不要泄漏,客户端和服务端的是通过Master生成的 -e MASTER_RPC_HOST=0.0.0.0 \ # 这里要改成你服务器的外部IP vaalacat/frp-panel @@ -80,19 +81,19 @@ docker run -d \ 注意修改 IP -```powershell +```bash APP_GLOBAL_SECRET=your_secret MASTER_RPC_HOST=0.0.0.0 frp-panel master ``` - client -```powershell +```bash frp-panel client -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # 在master WebUI复制的参数 ``` - server -```powershell +```bash frp-panel server -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # 在master WebUI复制的参数 ``` @@ -100,14 +101,14 @@ frp-panel server -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # 在下载的可执行文件同名文件夹下创建一个 `.env` 文件(注意不要有后缀名),然后输入以下内容保存后运行对应命令,注意,client 和 server 的对应参数需要在 web 页面复制 -- master: `frp-panel-amd64.exe master` - ``` APP_GLOBAL_SECRET=your_secret MASTER_RPC_HOST=IP DB_DSN=data.db ``` +- master: `frp-panel-amd64.exe master` + client 和 server 要使用在 master WebUI 复制的参数 - client: `frp-panel-amd64.exe client -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # 在master WebUI复制的参数` @@ -124,7 +125,7 @@ client 和 server 要使用在 master WebUI 复制的参数 ### 服务管理 -如果您使用的是面板自带的安装脚本,对于 Linux 使用 systemd 控制,对于 Windows 使用 nssm 控制 +如果您使用的是面板自带的安装脚本,对于 Linux 使用 systemd 控制,对于 Windows 使用 本程序 控制 Linux 安装后使用示例: @@ -136,10 +137,42 @@ systemctl start frpp Windows 安装后使用示例: ``` -C:/frpp/nssm.exe stop frpp -C:/frpp/nssm.exe remove frpp +C:/frpp/frpp.exe start +C:/frpp/frpp.exe stop +C:/frpp/frpp.exe uninstall ``` +### 配置说明 + +| 类型 | 环境变量名 | 默认值 | 描述 | +|--------|-------------------------------------|--------------------|----------------------------------------------------------------| +| string | `APP_SECRET` | - | 应用密钥,用于客户端和服务器的和Master的通信加密 | +| string | `APP_GLOBAL_SECRET` | `frp-panel` | 全局密钥,用于管理生成密钥,需妥善保管 | +| int | `APP_COOKIE_AGE` | `86400` | Cookie 的有效期(秒),默认值为 1 天 | +| string | `APP_COOKIE_NAME` | `frp-panel-cookie` | Cookie 名称 | +| string | `APP_COOKIE_PATH` | `/` | Cookie 路径 | +| string | `APP_COOKIE_DOMAIN` | - | Cookie 域 | +| bool | `APP_COOKIE_SECURE` | `false` | Cookie 是否安全 | +| bool | `APP_COOKIE_HTTP_ONLY` | `true` | Cookie 是否仅限 HTTP | +| bool | `APP_ENABLE_REGISTER` | `false` | 是否启用注册,仅允许第一个管理员注册 | +| int | `MASTER_API_PORT` | `9000` | 主节点 API 端口 | +| string | `MASTER_API_HOST` | - | 主节点域名,可以在反向代理和CDN后 | +| string | `MASTER_API_SCHEME` | `http` | 主节点 API 协议(注意,这里不影响主机行为,设置为https只是为了方便复制客户端启动命令,HTTPS需要自行反向代理)| +| int | `MASTER_CACHE_SIZE` | `10` | 缓存大小(MB) | +| string | `MASTER_RPC_HOST` | `127.0.0.1` | Master节点公共 IP 或域名 | +| int | `MASTER_RPC_PORT` | `9001` | Master节点 RPC 端口 | +| bool | `MASTER_COMPATIBLE_MODE` | `false` | 兼容模式,用于官方 frp 客户端 | +| string | `MASTER_INTERNAL_FRP_SERVER_HOST` | - | Master内置 frps 服务器主机,用于客户端连接 | +| int | `MASTER_INTERNAL_FRP_SERVER_PORT` | `9002` | Master内置 frps 服务器端口,用于客户端连接 | +| string | `MASTER_INTERNAL_FRP_AUTH_SERVER_HOST` | `127.0.0.1` | Master内置 frps 认证服务器主机 | +| int | `MASTER_INTERNAL_FRP_AUTH_SERVER_PORT` | `8999` | Master内置 frps 认证服务器端口 | +| string | `MASTER_INTERNAL_FRP_AUTH_SERVER_PATH` | `/auth` | Master内置 frps 认证服务器路径 | +| int | `SERVER_API_PORT` | `8999` | 服务器 API 端口 | +| string | `DB_TYPE` | `sqlite3` | 数据库类型,如 mysql postgres 或 sqlite3 等 | +| string | `DB_DSN` | `data.db` | 数据库 DSN,默认使用sqlite3,数据默认存储在可执行文件同目录下,对于 sqlite 是路径,其他数据库为 DSN,参见 [MySQL DSN](https://github.com/go-sql-driver/mysql#dsn-data-source-name) | +| string | `CLIENT_ID` | - | 客户端 ID | +| string | `CLIENT_SECRET` | - | 客户端密钥 | + ## 项目开发指南 ### 平台架构设计 diff --git a/README_en.md b/README_en.md index fd91fe6..8faaee3 100644 --- a/README_en.md +++ b/README_en.md @@ -33,20 +33,23 @@ Note⚠️: The startup commands for client and server may change as the project - master ```bash -docker run -d -p 9000:9000 \ # API control console port - -p 9001:9001 \ # rpc port - -p 7000:7000 \ # frps port - -p 20000-20050:20000-20050 \ # Reserved ports for frps +# recommended +docker run -d \ + --network=host \ --restart=unless-stopped \ - -v /opt/frp-panel:/data \ # Data storage location + -v /opt/frp-panel:/data \ -e APP_GLOBAL_SECRET=your_secret \ # Master's secret, be careful not to leak it, the client and server secrets are generated by the Master -e MASTER_RPC_HOST=0.0.0.0 \ # Change this to your server's external IP vaalacat/frp-panel + # or -docker run -d \ - --network=host \ + +docker run -d -p 9000:9000 \ # API control console port + -p 9001:9001 \ # rpc port + -p 7000:7000 \ # frps port + -p 20000-20050:20000-20050 \ # Reserved ports for frps --restart=unless-stopped \ - -v /opt/frp-panel:/data \ + -v /opt/frp-panel:/data \ # Data storage location -e APP_GLOBAL_SECRET=your_secret \ # Master's secret, be careful not to leak it, the client and server secrets are generated by the Master -e MASTER_RPC_HOST=0.0.0.0 \ # Change this to your server's external IP vaalacat/frp-panel @@ -76,19 +79,19 @@ docker run -d \ Note: Modify the IP -```powershell +```bash APP_GLOBAL_SECRET=your_secret MASTER_RPC_HOST=0.0.0.0 frp-panel master ``` - client -```powershell +```bash frp-panel client -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # Copy the parameters from the master WebUI ``` - server -```powershell +```bash frp-panel server -s xxxx -i xxxx -a xxxx -r 127.0.0.1 -c 9001 -p 9000 -e http # Copy the parameters from the master WebUI ``` @@ -120,7 +123,7 @@ The program will read the contents of the following files in order as the config ### Service Management -If you are using the installation script provided by the panel, systemd is used for Linux control, and nssm is used for Windows control. +If you are using the installation script provided by the panel, systemd is used for Linux control, and frpp.exe is used for Windows control. Examples of using Linux after installation: @@ -132,8 +135,9 @@ systemctl start frpp Examples of using Windows after installation: ``` -C:/frpp/nssm.exe stop frpp -C:/frpp/nssm.exe remove frpp +C:/frpp/frpp.exe start +C:/frpp/frpp.exe stop +C:/frpp/frpp.exe uninstall ``` ## Project Development Guide diff --git a/biz/client/pty_connect.go b/biz/client/pty_connect.go new file mode 100644 index 0000000..fb7e996 --- /dev/null +++ b/biz/client/pty_connect.go @@ -0,0 +1,18 @@ +package client + +import ( + "context" + + "github.com/VaalaCat/frp-panel/biz/common" + "github.com/VaalaCat/frp-panel/conf" + "github.com/VaalaCat/frp-panel/pb" +) + +func StartPTYConnect(c context.Context, req *pb.CommonRequest) (*pb.CommonResponse, error) { + return common.StartPTYConnect(c, req, &pb.PTYClientMessage{Base: &pb.PTYClientMessage_ClientBase{ + ClientBase: &pb.ClientBase{ + ClientId: conf.Get().Client.ID, + ClientSecret: conf.Get().Client.Secret, + }, + }}) +} diff --git a/biz/client/rpc_handler.go b/biz/client/rpc_handler.go index 9da9efe..9faa5eb 100644 --- a/biz/client/rpc_handler.go +++ b/biz/client/rpc_handler.go @@ -6,8 +6,11 @@ import ( "runtime/debug" "github.com/VaalaCat/frp-panel/common" + + "github.com/VaalaCat/frp-panel/conf" "github.com/VaalaCat/frp-panel/logger" "github.com/VaalaCat/frp-panel/pb" + "google.golang.org/protobuf/proto" ) func HandleServerMessage(req *pb.ServerMessage) *pb.ClientMessage { @@ -31,10 +34,13 @@ func HandleServerMessage(req *pb.ServerMessage) *pb.ClientMessage { return common.WrapperServerMsg(req, StartSteamLogHandler) case pb.Event_EVENT_STOP_STREAM_LOG: return common.WrapperServerMsg(req, StopSteamLogHandler) + case pb.Event_EVENT_START_PTY_CONNECT: + return common.WrapperServerMsg(req, StartPTYConnect) case pb.Event_EVENT_PING: + rawData, _ := proto.Marshal(conf.GetVersion().ToProto()) return &pb.ClientMessage{ Event: pb.Event_EVENT_PONG, - Data: []byte("pong"), + Data: rawData, } default: } diff --git a/biz/common/pty.go b/biz/common/pty.go new file mode 100644 index 0000000..8134847 --- /dev/null +++ b/biz/common/pty.go @@ -0,0 +1,153 @@ +package common + +import ( + "context" + "fmt" + + "github.com/VaalaCat/frp-panel/logger" + "github.com/VaalaCat/frp-panel/pb" + "github.com/VaalaCat/frp-panel/services/rpcclient" + "github.com/VaalaCat/frp-panel/utils/pty" + "github.com/google/uuid" + "github.com/samber/lo" + "github.com/sourcegraph/conc" +) + +func StartPTYConnect(c context.Context, req *pb.CommonRequest, initMsg *pb.PTYClientMessage) (*pb.CommonResponse, error) { + conn, err := rpcclient.GetClientRPCSerivce().GetCli().PTYConnect(c) + if err != nil { + logger.Logger(c).WithError(err).Infof("rpc connect master error") + return nil, err + } + + sessionID := uuid.New().String() + initMsg.SessionId = sessionID + + if err := conn.Send(initMsg); err != nil { + logger.Logger(c).WithError(err).Infof("send server base error") + return nil, err + } + + ack, err := conn.Recv() + if err != nil { + logger.Logger(c).WithError(err).Infof("recv ack error") + return nil, err + } + + if ack.GetData() != "ok" { + logger.Logger(c).Infof("ack error") + return nil, fmt.Errorf("ack error") + } + + go func() { + HandlePTY(c, conn, sessionID) + }() + + return &pb.CommonResponse{Data: &sessionID}, nil +} + +func HandlePTY(c context.Context, conn pb.Master_PTYConnectClient, sessionID string) { + connectionErrorLimit := 10 + maxBufferSizeBytes := 4096 + + ptyInstace, err := pty.Start() + if err != nil { + msg := fmt.Sprintf("failed to start tty: %s", err) + logger.Logger(c).WithError(err).Warn(msg) + conn.Send(&pb.PTYClientMessage{Data: &msg, SessionId: sessionID}) + return + } + + defer func() { + logger.Logger(c).Info("gracefully stopping spawned tty...") + if err := ptyInstace.Close(); err != nil { + logger.Logger(c).Warnf("failed to kill process: %s", err) + } + if err := conn.CloseSend(); err != nil { + logger.Logger(c).Warnf("failed to close webscoket connection: %s", err) + } + }() + + var connectionClosed bool + var wg conc.WaitGroup + + // tty >> master + wg.Go(func() { + errorCounter := 0 + for { + if errorCounter > connectionErrorLimit { + break + } + buffer := make([]byte, maxBufferSizeBytes) + readLength, err := ptyInstace.Read(buffer) + if err != nil { + logger.Logger(c).Warnf("failed to read from tty: %s", err) + if err := conn.Send(&pb.PTYClientMessage{Data: lo.ToPtr("bye!"), SessionId: sessionID}); err != nil { + logger.Logger(c).Warnf("failed to send termination message from tty to master: %s", err) + } + if err := conn.CloseSend(); err != nil { + logger.Logger(c).Warnf("failed to close grpc stream connection: %s", err) + } + return + } + str := string(buffer[:readLength]) + if err := conn.Send(&pb.PTYClientMessage{Data: lo.ToPtr(str), SessionId: sessionID}); err != nil { + logger.Logger(c).Warnf("failed to send %v bytes from tty to master", readLength) + errorCounter++ + continue + } + logger.Logger(c).Tracef("sent message of size %v bytes from tty to master", readLength) + errorCounter = 0 + } + }) + + // tty << master + wg.Go(func() { + for { + // data processing + msg, err := conn.Recv() + if err != nil { + if !connectionClosed { + logger.Logger(c).Warnf("failed to get next reader: %s", err) + } + if err := conn.CloseSend(); err != nil { + logger.Logger(c).Warnf("failed to close grpc stream connection: %s", err) + } + return + } + if msg.GetDone() { + if err := conn.CloseSend(); err != nil { + logger.Logger(c).Warnf("failed to close grpc stream connection: %s", err) + } + logger.Logger(c).Info("gracefully stopping spawned tty...") + if err := ptyInstace.Close(); err != nil { + logger.Logger(c).Warnf("failed to kill process: %s", err) + } + logger.Logger(c).Info("recv server msg done, closing conn...") + return + } + data := msg.GetData() + + // handle resizing + if msg.Height != nil && msg.Width != nil { + logger.Logger(c).Infof("resizing tty to use %+v rows and %+v columns...", *msg.Height, *msg.Width) + if err := ptyInstace.Setsize(uint32(*msg.Width), uint32(*msg.Height)); err != nil { + logger.Logger(c).Warnf("failed to resize tty, error: %s", err) + } + continue + } + + // write to tty + bytesWritten, err := ptyInstace.Write([]byte(data)) + if err != nil { + logger.Logger(c).Warn(fmt.Sprintf("failed to write %v bytes to tty: %s", len(data), err)) + continue + } + logger.Logger(c).Tracef("%v bytes written to tty...", bytesWritten) + } + }) + + wg.Wait() + logger.Logger(c).Info("closing conn...") + connectionClosed = true +} diff --git a/biz/master/handler.go b/biz/master/handler.go index c68ce06..1a3e879 100644 --- a/biz/master/handler.go +++ b/biz/master/handler.go @@ -8,6 +8,7 @@ import ( "github.com/VaalaCat/frp-panel/biz/master/platform" "github.com/VaalaCat/frp-panel/biz/master/proxy" "github.com/VaalaCat/frp-panel/biz/master/server" + "github.com/VaalaCat/frp-panel/biz/master/shell" "github.com/VaalaCat/frp-panel/biz/master/streamlog" "github.com/VaalaCat/frp-panel/biz/master/user" "github.com/VaalaCat/frp-panel/common" @@ -76,6 +77,7 @@ func ConfigureRouter(router *gin.Engine) { proxyRouter.POST("/get_by_cid", common.Wrapper(proxy.GetProxyByCID)) proxyRouter.POST("/get_by_sid", common.Wrapper(proxy.GetProxyBySID)) } - v1.GET("/log", streamlog.GetLogHander) + v1.GET("/pty/:clientID", middleware.JWTAuth, middleware.AuthCtx, shell.PTYHandler) + v1.GET("/log", middleware.JWTAuth, middleware.AuthCtx, streamlog.GetLogHander) } } diff --git a/biz/master/platform/get_clients_status.go b/biz/master/platform/get_clients_status.go index d4a103b..b838419 100644 --- a/biz/master/platform/get_clients_status.go +++ b/biz/master/platform/get_clients_status.go @@ -8,6 +8,8 @@ import ( "github.com/VaalaCat/frp-panel/logger" "github.com/VaalaCat/frp-panel/pb" "github.com/VaalaCat/frp-panel/rpc" + "github.com/samber/lo" + "google.golang.org/protobuf/proto" ) func GetClientsStatus(c context.Context, req *pb.GetClientsStatusRequest) (*pb.GetClientsStatusResponse, error) { @@ -24,7 +26,8 @@ func GetClientsStatus(c context.Context, req *pb.GetClientsStatusRequest) (*pb.G ) for _, clientID := range clientIDs { - conn := rpc.GetClientsManager().Get(clientID) + mgr := rpc.GetClientsManager() + conn := mgr.Get(clientID) if conn == nil { resps[clientID] = &pb.ClientStatus{ ClientType: req.GetClientType(), @@ -48,11 +51,22 @@ func GetClientsStatus(c context.Context, req *pb.GetClientsStatusRequest) (*pb.G } continue } + + clientVersion := &pb.ClientVersion{} + proto.Unmarshal(tresp.GetData(), clientVersion) + connectTime, ok := mgr.ConnectTime(clientID) + if !ok { + connectTime = endTime + } + resps[clientID] = &pb.ClientStatus{ - ClientType: req.GetClientType(), - ClientId: clientID, - Status: pb.ClientStatus_STATUS_ONLINE, - Ping: int32(pingTime), + ClientType: req.GetClientType(), + ClientId: clientID, + Status: pb.ClientStatus_STATUS_ONLINE, + Ping: int32(pingTime), + Version: clientVersion, + Addr: lo.ToPtr(mgr.ClientAddr(clientID)), + ConnectTime: lo.ToPtr(int32(endTime.Sub(connectTime).Seconds())), } } diff --git a/biz/master/shell/handler.go b/biz/master/shell/handler.go new file mode 100644 index 0000000..a759457 --- /dev/null +++ b/biz/master/shell/handler.go @@ -0,0 +1,236 @@ +package shell + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + "time" + + "github.com/VaalaCat/frp-panel/common" + "github.com/VaalaCat/frp-panel/logger" + "github.com/VaalaCat/frp-panel/pb" + "github.com/VaalaCat/frp-panel/rpc" + "github.com/fatedier/golib/log" + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "github.com/samber/lo" + "github.com/sourcegraph/conc" + "google.golang.org/protobuf/proto" +) + +func PTYHandler(c *gin.Context) { + connectionErrorLimit := 10 + keepalivePingTimeout := 10 * time.Second + + upgrader := getUpgrader(c) + webConn, err := upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + logger.Logger(c).WithError(err).Infof("websocket connect error") + c.JSON(http.StatusBadRequest, common.Err("websocket connect error")) + return + } + + clientID := c.Param("clientID") + if len(clientID) == 0 { + logger.Logger(c).Errorf("invalid client id") + webConn.Close() + return + } + + var ( + initHeight = c.Query("height") + initWidth = c.Query("width") + initWidthInt = 0 + initHeightInt = 0 + ) + + if initHeight != "" { + initHeightInt, err = strconv.Atoi(initHeight) + if err != nil { + logger.Logger(c).WithError(err).Infof("invalid height") + webConn.Close() + return + } + } + + if initWidth != "" { + initWidthInt, err = strconv.Atoi(initWidth) + if err != nil { + logger.Logger(c).WithError(err).Infof("invalid width") + webConn.Close() + return + } + } + + cliMsg, err := rpc.CallClient(c, clientID, pb.Event_EVENT_START_PTY_CONNECT, &pb.CommonRequest{}) + if err != nil { + logger.Logger(c).WithError(err).Errorf("start pty connect error") + webConn.Close() + return + } + + commonResp := &pb.CommonResponse{} + if err := proto.Unmarshal(cliMsg.GetData(), commonResp); err != nil { + logger.Logger(c).WithError(err).Errorf("cannot unmarshal") + webConn.Close() + return + } + + sessionID := string(commonResp.GetData()) + + cliConn, ok := Mgr().Load(sessionID) + if !ok { + logger.Logger(c).Errorf("cannot get client, session id: [%s]", sessionID) + c.JSON(http.StatusInternalServerError, common.Err("cannot get client")) + return + } + + cliConn.Send(&pb.PTYServerMessage{ + Height: lo.ToPtr(int32(initHeightInt)), + Width: lo.ToPtr(int32(initWidthInt)), + }) + + defer func() { + logger.Logger(c).Info("gracefully stopping spawned tty...") + if err := cliConn.Send(&pb.PTYServerMessage{Data: lo.ToPtr("bye!"), Done: true}); err != nil { + logger.Logger(c).Warnf("failed to send close message: %s", err) + } + + Mgr().SetSessionDone(sessionID) + if err := webConn.Close(); err != nil { + logger.Logger(c).Warnf("failed to close webscoket connection: %s", err) + } + }() + + var connectionClosed bool + var wg conc.WaitGroup + + // this is a keep-alive loop that ensures connection does not hang-up itself + lastPongTime := time.Now() + webConn.SetPongHandler(func(msg string) error { + lastPongTime = time.Now() + return nil + }) + + wg.Go(func() { + defer func() { + if err := cliConn.Send(&pb.PTYServerMessage{Data: lo.ToPtr("bye!"), Done: true}); err != nil { + logger.Logger(c).Warnf("failed to send close message: %s", err) + } + + Mgr().SetSessionDone(sessionID) + if err := webConn.Close(); err != nil { + logger.Logger(c).Warnf("failed to close webscoket connection: %s", err) + } + }() + for { + if err := webConn.WriteMessage(websocket.PingMessage, []byte("keepalive")); err != nil { + logger.Logger(c).Warn("failed to write ping message") + return + } + time.Sleep(keepalivePingTimeout / 2) + if time.Now().Sub(lastPongTime) > keepalivePingTimeout { + logger.Logger(c).Warn("failed to get response from ping, triggering disconnect now...") + return + } + logger.Logger(c).Debug("received response from ping successfully") + } + }) + + // client >> xterm.js + wg.Go(func() { + errorCounter := 0 + for { + // consider the connection closed/errored out so that the socket handler + // can be terminated - this frees up memory so the service doesn't get + // overloaded + if errorCounter > connectionErrorLimit { + break + } + cliMsg, err := cliConn.Recv() + if err != nil { + logger.Logger(c).Warnf("failed to read from client sender: %s", err) + if err := webConn.WriteMessage(websocket.TextMessage, []byte("bye!")); err != nil { + logger.Logger(c).Warnf("failed to send termination message from client sender to xterm.js: %s", err) + } + if err := cliConn.Send(&pb.PTYServerMessage{Data: lo.ToPtr("bye!"), Done: true}); err != nil { + logger.Logger(c).Warnf("failed to send termination message from client sender to client: %s", err) + } + if err := webConn.Close(); err != nil { + logger.Logger(c).Warnf("failed to close webscoket connection: %s", err) + } + return + } + + readLength := len(cliMsg.GetData()) + + if err := webConn.WriteMessage(websocket.BinaryMessage, []byte(cliMsg.GetData())); err != nil { + logger.Logger(c).Warnf("failed to send %v bytes from client sender to xterm.js", readLength) + errorCounter++ + continue + } + logger.Logger(c).Tracef("sent message of size %v bytes from client sender to xterm.js", readLength) + errorCounter = 0 + } + }) + + // client << xterm.js + wg.Go(func() { + for { + // data processing + messageType, data, err := webConn.ReadMessage() + if err != nil { + if !connectionClosed { + logger.Logger(c).Warnf("failed to get next reader: %s", err) + } + if err := cliConn.Send(&pb.PTYServerMessage{Data: lo.ToPtr("bye!"), Done: true}); err != nil { + logger.Logger(c).Warnf("failed to send termination message from xterm.js to client: %s", err) + } + if err := webConn.Close(); err != nil { + logger.Logger(c).Warnf("failed to close webscoket connection: %s", err) + } + return + } + payload := struct { + Data *string `json:"data,omitempty"` + Height *uint16 `json:"height,omitempty"` + Width *uint16 `json:"width,omitempty"` + }{} + json.Unmarshal(data, &payload) + + msg := &pb.PTYServerMessage{} + if payload.Data != nil { + msg.Data = lo.ToPtr(*payload.Data) + } + if payload.Height != nil { + msg.Height = lo.ToPtr(int32(*payload.Height)) + } + if payload.Width != nil { + msg.Width = lo.ToPtr(int32(*payload.Width)) + } + + err = cliConn.Send(msg) + if err != nil { + logger.Logger(c).Warn(fmt.Sprintf("failed to write bytes to tty: %s", err)) + continue + } + logger.Logger(c).Tracef("messageType [%v] bytes written to tty...", messageType) + } + }) + + wg.Wait() + log.Info("closing conn...") + connectionClosed = true +} + +func getUpgrader(c *gin.Context) websocket.Upgrader { + return websocket.Upgrader{ + // cross origin domain + CheckOrigin: func(r *http.Request) bool { + return true + }, + // 处理 Sec-WebSocket-Protocol Header + Subprotocols: []string{c.GetHeader("Sec-WebSocket-Protocol")}, + } +} diff --git a/biz/master/shell/mgr.go b/biz/master/shell/mgr.go new file mode 100644 index 0000000..cf61367 --- /dev/null +++ b/biz/master/shell/mgr.go @@ -0,0 +1,50 @@ +package shell + +import ( + "github.com/VaalaCat/frp-panel/pb" + "github.com/VaalaCat/frp-panel/utils" +) + +type PTYMgr struct { + *utils.SyncMap[string, pb.Master_PTYConnectServer] // sessionID + doneMap *utils.SyncMap[string, chan bool] // sessionID +} + +var ( + mgr *PTYMgr +) + +func (m *PTYMgr) IsSessionDone(sessionID string) bool { + ch, ok := m.doneMap.Load(sessionID) + if !ok { + return true + } + return <-ch +} + +func (m *PTYMgr) SetSessionDone(sessionID string) { + ch, ok := m.doneMap.Load(sessionID) + if !ok { + return + } + ch <- true +} + +func (m *PTYMgr) Add(sessionID string, conn pb.Master_PTYConnectServer) { + m.Store(sessionID, conn) + m.doneMap.Store(sessionID, make(chan bool)) +} + +func NewPTYMgr() *PTYMgr { + return &PTYMgr{ + SyncMap: &utils.SyncMap[string, pb.Master_PTYConnectServer]{}, + doneMap: &utils.SyncMap[string, chan bool]{}, + } +} + +func Mgr() *PTYMgr { + if mgr == nil { + mgr = NewPTYMgr() + } + return mgr +} diff --git a/biz/master/shell/recv_mgr.go b/biz/master/shell/recv_mgr.go new file mode 100644 index 0000000..af8990c --- /dev/null +++ b/biz/master/shell/recv_mgr.go @@ -0,0 +1,51 @@ +package shell + +import ( + "fmt" + "io" + + "github.com/VaalaCat/frp-panel/biz/master/client" + "github.com/VaalaCat/frp-panel/biz/master/server" + "github.com/VaalaCat/frp-panel/logger" + "github.com/VaalaCat/frp-panel/pb" + "github.com/samber/lo" +) + +func PTYConnect(sender pb.Master_PTYConnectServer) error { + msg, err := sender.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + clientID := "" + + if msg.GetClientBase() != nil { + _, err = client.ValidateClientRequest(msg.GetClientBase()) + clientID = msg.GetClientBase().GetClientId() + } + if msg.GetServerBase() != nil { + _, err = server.ValidateServerRequest(msg.GetServerBase()) + clientID = msg.GetServerBase().GetServerId() + } + if err != nil { + return err + } + + if len(clientID) == 0 { + return fmt.Errorf("invalid client connect") + } + + logger.Logger(sender.Context()).Infof("start pty connect, client id: [%s], session id: [%s]", clientID, msg.GetSessionId()) + + Mgr().Add(msg.GetSessionId(), sender) + + if err := sender.Send(&pb.PTYServerMessage{Data: lo.ToPtr("ok")}); err != nil { + return err + } + + Mgr().IsSessionDone(msg.GetSessionId()) + return nil +} diff --git a/biz/server/pty_connect.go b/biz/server/pty_connect.go new file mode 100644 index 0000000..338351e --- /dev/null +++ b/biz/server/pty_connect.go @@ -0,0 +1,18 @@ +package server + +import ( + "context" + + "github.com/VaalaCat/frp-panel/biz/common" + "github.com/VaalaCat/frp-panel/conf" + "github.com/VaalaCat/frp-panel/pb" +) + +func StartPTYConnect(c context.Context, req *pb.CommonRequest) (*pb.CommonResponse, error) { + return common.StartPTYConnect(c, req, &pb.PTYClientMessage{Base: &pb.PTYClientMessage_ServerBase{ + ServerBase: &pb.ServerBase{ + ServerId: conf.Get().Client.ID, + ServerSecret: conf.Get().Client.Secret, + }, + }}) +} diff --git a/biz/server/rpc_handler.go b/biz/server/rpc_handler.go index 050f794..a619939 100644 --- a/biz/server/rpc_handler.go +++ b/biz/server/rpc_handler.go @@ -6,8 +6,10 @@ import ( "runtime/debug" "github.com/VaalaCat/frp-panel/common" + "github.com/VaalaCat/frp-panel/conf" "github.com/VaalaCat/frp-panel/logger" "github.com/VaalaCat/frp-panel/pb" + "google.golang.org/protobuf/proto" ) func HandleServerMessage(req *pb.ServerMessage) *pb.ClientMessage { @@ -29,10 +31,13 @@ func HandleServerMessage(req *pb.ServerMessage) *pb.ClientMessage { return common.WrapperServerMsg(req, StartSteamLogHandler) case pb.Event_EVENT_STOP_STREAM_LOG: return common.WrapperServerMsg(req, StopSteamLogHandler) + case pb.Event_EVENT_START_PTY_CONNECT: + return common.WrapperServerMsg(req, StartPTYConnect) case pb.Event_EVENT_PING: + rawData, _ := proto.Marshal(conf.GetVersion().ToProto()) return &pb.ClientMessage{ Event: pb.Event_EVENT_PONG, - Data: []byte("pong"), + Data: rawData, } default: } diff --git a/build.sh b/build.sh index 30afa03..808de7b 100755 --- a/build.sh +++ b/build.sh @@ -1,30 +1,156 @@ #!/usr/bin/env /bin/bash -bash ./codegen.sh -mkdir -p dist -rm -rf dist/* -cd www && pnpm install --no-frozen-lockfile && pnpm build && cd .. -echo "Building frp-panel full windows binaries..." -CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o dist/frp-panel-amd64.exe cmd/frpp/*.go -CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o dist/frp-panel-arm64.exe cmd/frpp/*.go -echo "Building frp-panel full linux binaries..." -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/frp-panel-linux-amd64 cmd/frpp/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o dist/frp-panel-linux-arm64 cmd/frpp/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -o dist/frp-panel-linux-armv7l cmd/frpp/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -o dist/frp-panel-linux-armv6l cmd/frpp/*.go -echo "Building frp-panel full darwin binaries..." -CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o dist/frp-panel-darwin-amd64 cmd/frpp/*.go -CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o dist/frp-panel-darwin-arm64 cmd/frpp/*.go - -echo "Building frp-panel client only windows binaries..." -CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o dist/frp-panel-client-amd64.exe cmd/frppc/*.go -CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -o dist/frp-panel-client-arm64.exe cmd/frppc/*.go -echo "Building frp-panel client only linux binaries..." -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/frp-panel-client-linux-amd64 cmd/frppc/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o dist/frp-panel-client-linux-arm64 cmd/frppc/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build -o dist/frp-panel-client-linux-armv7l cmd/frppc/*.go -CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build -o dist/frp-panel-client-linux-armv6l cmd/frppc/*.go -echo "Building frp-panel client only darwin binaries..." -CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o dist/frp-panel-client-darwin-amd64 cmd/frppc/*.go -CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o dist/frp-panel-client-darwin-arm64 cmd/frppc/*.go + +# Function to print usage +usage() { + echo "Usage: $0 [--platform ] [--bintype ] [--arch ]" + echo "Platforms: windows, linux, darwin, all" + echo "Binary Types: full, client, all" + echo "Architectures: amd64, arm64, arm, all" + echo "Example: $0 --platform linux --bintype full --arch amd64" + exit 1 +} + +# Default values +PLATFORM="all" +BINTYPE="all" +ARCH="all" + +# build variables +BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" +GIT_COMMIT="$(git rev-parse HEAD)" +VERSION="$(git describe --tags --abbrev=0 | tr -d '\n')" + +# Parse arguments +while [[ "$#" -gt 0 ]]; do + case $1 in + --platform) PLATFORM="$2"; shift ;; + --bintype) BINTYPE="$2"; shift ;; + --arch) ARCH="$2"; shift ;; + --skip-frontend) SKIP_FRONTEND=true ;; + --current) CURRENT=true ;; + *) usage ;; + esac + shift +done + +if [[ "$CURRENT" == "true" ]]; then + PLATFORM=$(uname -s | tr '[:upper:]' '[:lower:]') + ARCH=$(uname -m) + if [[ "$ARCH" == "x86_64" ]]; then + ARCH="amd64" + fi + if [[ "$ARCH" == "aarch64" ]]; then + ARCH="arm64" + fi + BINTYPE="full" +fi + +echo "Building for platform: $PLATFORM, binary type: $BINTYPE, architecture: $ARCH" +echo "Build Date: $BUILD_DATE" +echo "Git Commit: $GIT_COMMIT" +echo "Version: $VERSION" + +BUILD_LD_FLAGS="-X 'github.com/VaalaCat/frp-panel/conf.buildDate=${BUILD_DATE}' -X 'github.com/VaalaCat/frp-panel/conf.gitCommit=${GIT_COMMIT}' -X 'github.com/VaalaCat/frp-panel/conf.gitVersion=${VERSION}'" + +if [[ "$SKIP_FRONTEND" == "true" ]]; then + echo "Skipping frontend build" +else + echo "Building frontend" + # Prepare build environment + mkdir -p dist + rm -rf dist/* + + # Build frontend + cd www && pnpm install --no-frozen-lockfile && pnpm build && cd .. +fi + +# Build function +build_binary() { + local platform=$1 + local arch=$2 + local bintype=$3 + local output_name="" + local source_path="" + + # Determine output name and source path + if [[ "$bintype" == "full" ]]; then + source_path="cmd/frpp/*.go" + output_name="frp-panel" + elif [[ "$bintype" == "client" ]]; then + source_path="cmd/frppc/*.go" + output_name="frp-panel-client" + else + echo "Invalid binary type" + return 1 + fi + + # Set executable extension for Windows + local exe_ext="" + if [[ "$platform" == "windows" ]]; then + exe_ext=".exe" + fi + + # Special handling for ARM architectures + local goarch="$arch" + local goarm="" + if [[ "$arch" == "arm" ]]; then + goarch="arm" + if [[ "$platform" == "linux" ]]; then + # Build for ARMv7 and ARMv6 + for arm_version in 7 6; do + local arm_output="${output_name}-${platform}-armv${arm_version}l${exe_ext}" + CGO_ENABLED=0 GOOS="$platform" GOARCH="$goarch" GOARM="$arm_version" \ + go build -o "dist/${arm_output}" -ldflags "$BUILD_LD_FLAGS" $source_path + done + return 0 + fi + fi + + # Standard build + local output="${output_name}-${platform}-${arch}${exe_ext}" + CGO_ENABLED=0 GOOS="$platform" GOARCH="$goarch" \ + go build -o "dist/${output}" -ldflags "$BUILD_LD_FLAGS" $source_path +} + +# Platforms array +PLATFORMS=() +if [[ "$PLATFORM" == "all" ]]; then + PLATFORMS=("windows" "linux" "darwin") +else + PLATFORMS=("$PLATFORM") +fi + +# Architectures array +ARCHS=() +if [[ "$ARCH" == "all" ]]; then + ARCHS=("amd64" "arm64" "arm") +else + ARCHS=("$ARCH") +fi + +# Binary types array +BINTYPES=() +if [[ "$BINTYPE" == "all" ]]; then + BINTYPES=("full" "client") +else + BINTYPES=("$BINTYPE") +fi + +# Build matrix +for platform in "${PLATFORMS[@]}"; do + for arch in "${ARCHS[@]}"; do + for bintype in "${BINTYPES[@]}"; do + echo "Building $bintype binary for $platform-$arch" + if [[ "$platform" == "darwin" && "$arch" == "arm" ]]; then continue; fi + if [[ "$platform" == "windows" && "$arch" == "arm" ]]; then continue; fi + build_binary "$platform" "$arch" "$bintype" + done + done +done + +# Move to current directory if current enabled +if [[ "$CURRENT" == "true" ]]; then + mv dist/frp* ./frp-panel +fi echo "Build Done!" \ No newline at end of file diff --git a/cmd/frpp/cmd.go b/cmd/frpp/cmd.go index 57d2337..1dcf414 100644 --- a/cmd/frpp/cmd.go +++ b/cmd/frpp/cmd.go @@ -2,9 +2,11 @@ package main import ( "context" + "fmt" "github.com/VaalaCat/frp-panel/conf" "github.com/VaalaCat/frp-panel/logger" + "github.com/VaalaCat/frp-panel/utils" "github.com/spf13/cobra" ) @@ -30,50 +32,130 @@ func initCommand() { Use: "client [-s client secret] [-i client id] [-a app secret] [-r rpc host] [-c rpc port] [-p api port]", Short: "run managed frpc", Run: func(cmd *cobra.Command, args []string) { - patchConfig(rpcHost, appSecret, - clientID, clientSecret, - apiScheme, rpcPort, apiPort) - runClient() + run := func() { + patchConfig(rpcHost, appSecret, + clientID, clientSecret, + apiScheme, rpcPort, apiPort) + runClient() + } + if srv, err := utils.CreateSystemService(args, run); err != nil { + run() + } else { + srv.Run() + } }, } serverCmd = &cobra.Command{ Use: "server [-s client secret] [-i client id] [-a app secret] [-r rpc host] [-c rpc port] [-p api port]", Short: "run managed frps", Run: func(cmd *cobra.Command, args []string) { - patchConfig(rpcHost, appSecret, - clientID, clientSecret, - apiScheme, rpcPort, apiPort) - runServer() + run := func() { + patchConfig(rpcHost, appSecret, + clientID, clientSecret, + apiScheme, rpcPort, apiPort) + runServer() + } + if srv, err := utils.CreateSystemService(args, run); err != nil { + run() + } else { + srv.Run() + } }, } masterCmd = &cobra.Command{ Use: "master", Short: "run frp-panel manager", Run: func(cmd *cobra.Command, args []string) { - runMaster() + if srv, err := utils.CreateSystemService(args, runMaster); err != nil { + runMaster() + } else { + srv.Run() + } }, } rootCmd = &cobra.Command{ Use: "frp-panel", Short: "frp-panel is a frp panel QwQ", } - rootCmd.AddCommand(clientCmd, serverCmd, masterCmd) + + installServiceCmd := &cobra.Command{ + Use: "install", + Short: "install frp-panel as service", + DisableFlagParsing: true, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + utils.ControlSystemService(args, "install", func() {}) + }, + } + + uninstallServiceCmd := &cobra.Command{ + Use: "uninstall", + Short: "uninstall frp-panel service", + DisableFlagParsing: true, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + utils.ControlSystemService(args, "uninstall", func() {}) + }, + } + + startServiceCmd := &cobra.Command{ + Use: "start", + Short: "start frp-panel service", + DisableFlagParsing: true, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + utils.ControlSystemService(args, "start", func() {}) + }, + } + + stopServiceCmd := &cobra.Command{ + Use: "stop", + Short: "stop frp-panel service", + DisableFlagParsing: true, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + utils.ControlSystemService(args, "stop", func() {}) + }, + } + + restartServiceCmd := &cobra.Command{ + Use: "restart", + Short: "restart frp-panel service", + DisableFlagParsing: true, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + utils.ControlSystemService(args, "restart", func() {}) + }, + } + + versionCmd := &cobra.Command{ + Use: "version", + Short: "Print the version info of frp-panel", + Long: `All software has versions. This is frp-panel's`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(conf.GetVersion().String()) + }, + } + + rootCmd.AddCommand(clientCmd, serverCmd, masterCmd, versionCmd, + installServiceCmd, uninstallServiceCmd, + startServiceCmd, stopServiceCmd, restartServiceCmd) clientCmd.Flags().StringVarP(&clientSecret, "secret", "s", "", "client secret") serverCmd.Flags().StringVarP(&clientSecret, "secret", "s", "", "client secret") clientCmd.Flags().StringVarP(&clientID, "id", "i", "", "client id") serverCmd.Flags().StringVarP(&clientID, "id", "i", "", "client id") - clientCmd.Flags().StringVarP(&rpcHost, "rpc", "r", "", "rpc host") - serverCmd.Flags().StringVarP(&rpcHost, "rpc", "r", "", "rpc host") + clientCmd.Flags().StringVarP(&rpcHost, "rpc", "r", "", "rpc host, canbe ip or domain") + serverCmd.Flags().StringVarP(&rpcHost, "rpc", "r", "", "rpc host, canbe ip or domain") clientCmd.Flags().StringVarP(&appSecret, "app", "a", "", "app secret") serverCmd.Flags().StringVarP(&appSecret, "app", "a", "", "app secret") - clientCmd.Flags().IntVarP(&rpcPort, "rpc-port", "c", 0, "rpc port") - serverCmd.Flags().IntVarP(&rpcPort, "rpc-port", "c", 0, "rpc port") - clientCmd.Flags().IntVarP(&apiPort, "api-port", "p", 0, "api port") - serverCmd.Flags().IntVarP(&apiPort, "api-port", "p", 0, "api port") + clientCmd.Flags().IntVarP(&rpcPort, "rpc-port", "c", 0, "rpc port, master rpc port, scheme is grpc") + serverCmd.Flags().IntVarP(&rpcPort, "rpc-port", "c", 0, "rpc port, master rpc port, scheme is grpc") + clientCmd.Flags().IntVarP(&apiPort, "api-port", "p", 0, "api port, master api port, scheme is http/https") + serverCmd.Flags().IntVarP(&apiPort, "api-port", "p", 0, "api port, master api port, scheme is http/https") - clientCmd.Flags().StringVarP(&apiScheme, "api-scheme", "e", "", "api scheme") - serverCmd.Flags().StringVarP(&apiScheme, "api-scheme", "e", "", "api scheme") + clientCmd.Flags().StringVarP(&apiScheme, "api-scheme", "e", "", "api scheme, master api scheme, scheme is http/https") + serverCmd.Flags().StringVarP(&apiScheme, "api-scheme", "e", "", "api scheme, master api scheme, scheme is http/https") } func initLogger() { diff --git a/cmd/frpp/main.go b/cmd/frpp/main.go index 3c3c299..e4773e8 100644 --- a/cmd/frpp/main.go +++ b/cmd/frpp/main.go @@ -3,9 +3,12 @@ package main import ( "github.com/VaalaCat/frp-panel/conf" "github.com/VaalaCat/frp-panel/rpc" + "github.com/spf13/cobra" ) func main() { + cobra.MousetrapHelpText = "" + initLogger() initCommand() conf.InitConfig() diff --git a/conf/settings.go b/conf/settings.go index 9eca56b..558a28f 100644 --- a/conf/settings.go +++ b/conf/settings.go @@ -54,6 +54,7 @@ type Config struct { var ( config *Config ClientCred credentials.TransportCredentials + Version string ) func Get() *Config { @@ -79,11 +80,9 @@ func InitConfig() { break } if i == len(envFiles)-1 { - logger.Logger(ctx).Errorf("cannot load env file: %s, error: %v", envFile, err) useEnvFile = false break } - logger.Logger(ctx).Infof("cannot load env file: %s, error: %v, try next", envFile, err) } if !useEnvFile { diff --git a/conf/version.go b/conf/version.go new file mode 100644 index 0000000..be83bb8 --- /dev/null +++ b/conf/version.go @@ -0,0 +1,61 @@ +package conf + +import ( + "bytes" + "fmt" + "html/template" + "runtime" + + "github.com/VaalaCat/frp-panel/pb" +) + +var ( + gitVersion = "dev-build" + gitCommit = "" + buildDate = "1970-01-01T00:00:00Z" +) + +type VersionInfo struct { + GitVersion string `json:"gitVersion" yaml:"gitVersion"` + GitCommit string `json:"gitCommit" yaml:"gitCommit"` + BuildDate string `json:"buildDate" yaml:"buildDate"` + GoVersion string `json:"goVersion" yaml:"goVersion"` + Compiler string `json:"compiler" yaml:"compiler"` + Platform string `json:"platform" yaml:"platform"` +} + +func (v *VersionInfo) String() string { + tempStr := "BinVersion: {{.GitVersion}}\nGitCommit: {{.GitCommit}}\nBuildDate: {{.BuildDate}}\nGoVersion: {{.GoVersion}}\nCompiler: {{.Compiler}}\nPlatform: {{.Platform}}" + temp, err := template.New("version").Parse(tempStr) + if err != nil { + return "" + } + var result bytes.Buffer + err = temp.Execute(&result, v) + if err != nil { + return "" + } + return result.String() +} + +func (v *VersionInfo) ToProto() *pb.ClientVersion { + return &pb.ClientVersion{ + GitVersion: v.GitVersion, + GitCommit: v.GitCommit, + BuildDate: v.BuildDate, + GoVersion: v.GoVersion, + Compiler: v.Compiler, + Platform: v.Platform, + } +} + +func GetVersion() *VersionInfo { + return &VersionInfo{ + GitVersion: gitVersion, + GitCommit: gitCommit, + BuildDate: buildDate, + GoVersion: runtime.Version(), + Compiler: runtime.Compiler, + Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), + } +} diff --git a/go.mod b/go.mod index 9eb80f4..44f8033 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module github.com/VaalaCat/frp-panel go 1.22.1 require ( + github.com/UserExistsError/conpty v0.1.4 github.com/coocood/freecache v1.2.4 + github.com/creack/pty v1.1.24 github.com/fatedier/frp v0.61.0 github.com/fatedier/golib v0.5.0 github.com/gin-contrib/static v0.0.1 @@ -12,10 +14,14 @@ require ( github.com/go-co-op/gocron/v2 v2.1.2 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.3 + github.com/iamacarpet/go-winpty v1.0.4 github.com/ilyakaznacheev/cleanenv v1.5.0 github.com/imroc/req/v3 v3.42.3 github.com/joho/godotenv v1.5.1 + github.com/kardianos/service v1.2.2 github.com/samber/lo v1.39.0 + github.com/shirou/gopsutil/v4 v4.24.11 github.com/sirupsen/logrus v1.9.3 github.com/sourcegraph/conc v0.3.0 github.com/spf13/cobra v1.8.0 @@ -41,10 +47,12 @@ require ( github.com/coreos/go-oidc/v3 v3.10.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/ebitengine/purego v0.8.1 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect @@ -69,6 +77,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/reedsolomon v1.12.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -82,6 +91,7 @@ require ( github.com/pires/go-proxyproto v0.7.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_golang v1.19.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect @@ -95,9 +105,12 @@ require ( github.com/templexxx/cpu v0.1.1 // indirect github.com/templexxx/xorsimd v0.4.3 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/xtaci/kcp-go/v5 v5.6.13 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.9.0 // indirect @@ -107,7 +120,7 @@ require ( 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/sys v0.26.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect diff --git a/go.sum b/go.sum index c1860b6..ce7e99e 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/UserExistsError/conpty v0.1.4 h1:+3FhJhiqhyEJa+K5qaK3/w6w+sN3Nh9O9VbJyBS02to= +github.com/UserExistsError/conpty v0.1.4/go.mod h1:PDglKIkX3O/2xVk0MV9a6bCWxRmPVfxqZoTG/5sSd9I= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -30,17 +32,19 @@ github.com/coocood/freecache v1.2.4/go.mod h1:RBUWa/Cy+OHdfTGFEhEuE1pMCMX51Ncizj github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE= +github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatedier/frp v0.58.1 h1:g9X0KTXxgINBvMLpWUI3VrMjNjB5qgTEexqFT2mgLXc= -github.com/fatedier/frp v0.58.1/go.mod h1:8lwoMcR+f8Shnx7lFWhN0JLhGspl8j0Tt/3cRiRVHgc= github.com/fatedier/frp v0.61.0 h1:+OuBLMtfsd3bHTd+uiYUKaz2h5Xv8JJnKfHD2FLwjOU= github.com/fatedier/frp v0.61.0/go.mod h1:slbDpYP9l8y6p3buVKGniAzbmxL3Fr+IdEJ3chRaA8Q= github.com/fatedier/golib v0.5.0 h1:hNcH7hgfIFqVWbP+YojCCAj4eO94pPf4dEF8lmq2jWs= @@ -64,6 +68,8 @@ github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWq github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= 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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -101,6 +107,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a 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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -110,6 +117,8 @@ 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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +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/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -117,6 +126,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/iamacarpet/go-winpty v1.0.4 h1:r42xaLLRZcUqjX6vHZeHos2haACfWkooOJTnFdogBfI= +github.com/iamacarpet/go-winpty v1.0.4/go.mod h1:50yLtqN2hFb5sYO5Qm2LegB166oAEw/PZYRn+FPWj0Q= github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4= github.com/ilyakaznacheev/cleanenv v1.5.0/go.mod h1:a5aDzaJrLCQZsazHol1w8InnDcOX0OColm64SlIi6gk= github.com/imroc/req/v3 v3.42.3 h1:ryPG2AiwouutAopwPxKpWKyxgvO8fB3hts4JXlh3PaE= @@ -140,6 +151,8 @@ github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= +github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -154,6 +167,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -186,6 +201,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -207,11 +224,12 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -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/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/shirou/gopsutil/v4 v4.24.11 h1:WaU9xqGFKvFfsUv94SXcUPD7rCkU0vr/asVdQOBZNj8= +github.com/shirou/gopsutil/v4 v4.24.11/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= @@ -236,29 +254,29 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl 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/templexxx/cpu v0.1.0 h1:wVM+WIJP2nYaxVxqgHPD4wGA2aJ9rvrQRV8CvFzNb40= -github.com/templexxx/cpu v0.1.0/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= github.com/templexxx/cpu v0.1.1 h1:isxHaxBXpYFWnk2DReuKkigaZyrjs2+9ypIdGP4h+HI= github.com/templexxx/cpu v0.1.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk= -github.com/templexxx/xorsimd v0.4.2 h1:ocZZ+Nvu65LGHmCLZ7OoCtg8Fx8jnHKK37SjvngUoVI= -github.com/templexxx/xorsimd v0.4.2/go.mod h1:HgwaPoDREdi6OnULpSfxhzaiiSUY4Fi3JPn1wpt28NI= github.com/templexxx/xorsimd v0.4.3 h1:9AQTFHd7Bhk3dIT7Al2XeBX5DWOvsUPZCuhyAtNbHjU= github.com/templexxx/xorsimd v0.4.3/go.mod h1:oZQcD6RFDisW2Am58dSAGwwL6rHjbzrlu25VDqfWkQg= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 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/xtaci/kcp-go/v5 v5.6.8 h1:jlI/0jAyjoOjT/SaGB58s4bQMJiNS41A2RKzR6TMWeI= -github.com/xtaci/kcp-go/v5 v5.6.8/go.mod h1:oE9j2NVqAkuKO5o8ByKGch3vgVX3BNf8zqP8JiGq0bM= github.com/xtaci/kcp-go/v5 v5.6.13 h1:FEjtz9+D4p8t2x4WjciGt/jsIuhlWjjgPCCWjrVR4Hk= github.com/xtaci/kcp-go/v5 v5.6.13/go.mod h1:75S1AKYYzNUSXIv30h+jPKJYZUwqpfvLshu63nCNSOM= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -316,9 +334,12 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -328,8 +349,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= diff --git a/idl/api_master.proto b/idl/api_master.proto index 42cf2a4..c4cd200 100644 --- a/idl/api_master.proto +++ b/idl/api_master.proto @@ -15,6 +15,18 @@ message ClientStatus { string client_id = 2; Status status = 3; int32 ping = 4; // 单位为毫秒 + optional ClientVersion version = 5; + optional string addr = 6; + optional int32 connect_time = 7; // 连接建立的时间 +} + +message ClientVersion { + string GitVersion = 1; + string GitCommit = 2; + string BuildDate = 3; + string GoVersion = 4; + string Compiler = 5; + string Platform = 6; } message GetClientsStatusRequest { diff --git a/idl/common.proto b/idl/common.proto index 0cf68e3..4d1dd3e 100644 --- a/idl/common.proto +++ b/idl/common.proto @@ -24,10 +24,13 @@ message Status { string message = 2; } -message CommonRequest {} +message CommonRequest { + optional string data = 1; +} message CommonResponse { optional Status status = 1; + optional string data = 2; } message Client { diff --git a/idl/rpc_master.proto b/idl/rpc_master.proto index 3e7ed80..681c88a 100644 --- a/idl/rpc_master.proto +++ b/idl/rpc_master.proto @@ -22,6 +22,7 @@ enum Event { EVENT_START_FRPS = 14; EVENT_START_STREAM_LOG = 15; EVENT_STOP_STREAM_LOG = 16; + EVENT_START_PTY_CONNECT = 17; } message ServerBase { @@ -103,6 +104,23 @@ message PushStreamLogResp { bool ok = 2; } +message PTYClientMessage { + optional string data = 1; + string session_id = 2; + bool done = 3; + oneof Base { + ServerBase server_base = 254; + ClientBase client_base = 255; + } +} + +message PTYServerMessage { + optional string data = 1; + optional int32 height = 2; + optional int32 width = 3; + bool done = 4; +} + service Master { rpc ServerSend(stream ClientMessage) returns(stream ServerMessage); rpc PullClientConfig(PullClientConfigReq) returns(PullClientConfigResp); @@ -111,4 +129,5 @@ service Master { rpc PushProxyInfo(PushProxyInfoReq) returns(PushProxyInfoResp); rpc PushClientStreamLog(stream PushClientStreamLogReq) returns(PushStreamLogResp); rpc PushServerStreamLog(stream PushServerStreamLogReq) returns(PushStreamLogResp); + rpc PTYConnect(stream PTYClientMessage) returns(stream PTYServerMessage); } diff --git a/install.ps1 b/install.ps1 index c1015b7..0c58556 100644 --- a/install.ps1 +++ b/install.ps1 @@ -4,7 +4,6 @@ if($PSVersionTable.PSVersion.Major -lt 5){ exit } $clientrepo = "VaalaCat/frp-panel" -$nssmrepo = "nezhahq/nssm-backup" # x86 or x64 if ([System.Environment]::Is64BitOperatingSystem) { $file = "frp-panel-amd64.exe" @@ -14,12 +13,11 @@ else { exit } $clientreleases = "https://api.github.com/repos/$clientrepo/releases" -$nssmreleases = "https://api.github.com/repos/$nssmrepo/releases" #重复运行自动更新 if (Test-Path "C:\frpp") { Write-Host "frp panel client already exists, delete and reinstall" -BackgroundColor DarkGreen -ForegroundColor White - C:/frpp/nssm.exe stop frpp - C:/frpp/nssm.exe remove frpp + C:/frpp/frpp.exe stop + C:/frpp/frpp.exe uninstall Remove-Item "C:\frpp" -Recurse } @@ -27,39 +25,21 @@ if (Test-Path "C:\frpp") { Write-Host "Determining latest frp panel client release" -BackgroundColor DarkGreen -ForegroundColor White [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $agenttag = (Invoke-WebRequest -Uri $clientreleases -UseBasicParsing | ConvertFrom-Json)[0].tag_name -$nssmtag = (Invoke-WebRequest -Uri $nssmreleases -UseBasicParsing | ConvertFrom-Json)[0].tag_name #Region判断 $ipapi= Invoke-RestMethod -Uri "https://api.myip.com/" -UserAgent "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1" $region=$ipapi.cc echo $ipapi if($region -ne "CN"){ $download = "https://github.com/$clientrepo/releases/download/$agenttag/$file" -$nssmdownload="https://github.com/$nssmrepo/releases/download/$nssmtag/nssm.zip" Write-Host "Location:$region,connect directly!" -BackgroundColor DarkRed -ForegroundColor Green }else{ $download = "https://dn-dao-github-mirror.daocloud.io/$clientrepo/releases/download/$agenttag/$file" -$nssmdownload="https://dn-dao-github-mirror.daocloud.io/$nssmrepo/releases/download/$nssmtag/nssm.zip" Write-Host "Location:CN,use mirror address" -BackgroundColor DarkRed -ForegroundColor Green } echo $download -echo $nssmdownload -Invoke-WebRequest $nssmdownload -OutFile "C:\nssm.zip" Invoke-WebRequest $download -OutFile "C:\frpp.exe" -#使用nssm安装服务 - -#解压 -Expand-Archive "C:\nssm.zip" -DestinationPath "C:\temp" -Force -if (!(Test-Path "C:\frpp")) { New-Item -Path "C:\frpp" -type directory } - -#整理文件 Move-Item -Path "C:\frpp.exe" -Destination "C:\frpp\frpp.exe" -Move-Item -Path "C:\temp\nssm-2.24\win64\nssm.exe" -Destination "C:\frpp\nssm.exe" - -#清理垃圾 -Remove-Item "C:\nssm.zip" Remove-Item "C:\temp" -Recurse -#安装部分 -C:\frpp\nssm.exe install frpp C:\frpp\frpp.exe $args -C:\frpp\nssm.exe start frpp -#enjoy +C:\frpp\frpp.exe install $args +C:\frpp\frpp.exe start Write-Host "Enjoy It!" -BackgroundColor DarkGreen -ForegroundColor Red \ No newline at end of file diff --git a/install.sh b/install.sh index 52af09e..cdf3ccd 100755 --- a/install.sh +++ b/install.sh @@ -45,8 +45,6 @@ esac chmod +x frp-panel -sudo mv frp-panel /usr/local/bin/frp-panel - get_start_params() { read -p "请输入启动参数:" params echo "$params" @@ -58,21 +56,7 @@ else start_params=$(get_start_params) fi -sudo tee /lib/systemd/system/frpp.service << EOF -[Unit] -Description=frp-panel -After=network.target - -[Service] -Type=simple -Restart=always -RestartSec=5 -StartLimitInterval=0 -ExecStart=/usr/local/bin/frp-panel $start_params - -[Install] -WantedBy=multi-user.target -EOF +sudo ./frp-panel install $start_params sudo systemctl daemon-reload diff --git a/pb/api_master.pb.go b/pb/api_master.pb.go index 2fa8546..fbcd0c8 100644 --- a/pb/api_master.pb.go +++ b/pb/api_master.pb.go @@ -77,10 +77,13 @@ type ClientStatus struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ClientType ClientType `protobuf:"varint,1,opt,name=client_type,json=clientType,proto3,enum=common.ClientType" json:"client_type,omitempty"` - ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - Status ClientStatus_Status `protobuf:"varint,3,opt,name=status,proto3,enum=api_master.ClientStatus_Status" json:"status,omitempty"` - Ping int32 `protobuf:"varint,4,opt,name=ping,proto3" json:"ping,omitempty"` // 单位为毫秒 + ClientType ClientType `protobuf:"varint,1,opt,name=client_type,json=clientType,proto3,enum=common.ClientType" json:"client_type,omitempty"` + ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + Status ClientStatus_Status `protobuf:"varint,3,opt,name=status,proto3,enum=api_master.ClientStatus_Status" json:"status,omitempty"` + Ping int32 `protobuf:"varint,4,opt,name=ping,proto3" json:"ping,omitempty"` // 单位为毫秒 + Version *ClientVersion `protobuf:"bytes,5,opt,name=version,proto3,oneof" json:"version,omitempty"` + Addr *string `protobuf:"bytes,6,opt,name=addr,proto3,oneof" json:"addr,omitempty"` + ConnectTime *int32 `protobuf:"varint,7,opt,name=connect_time,json=connectTime,proto3,oneof" json:"connect_time,omitempty"` // 连接建立的时间 } func (x *ClientStatus) Reset() { @@ -141,6 +144,112 @@ func (x *ClientStatus) GetPing() int32 { return 0 } +func (x *ClientStatus) GetVersion() *ClientVersion { + if x != nil { + return x.Version + } + return nil +} + +func (x *ClientStatus) GetAddr() string { + if x != nil && x.Addr != nil { + return *x.Addr + } + return "" +} + +func (x *ClientStatus) GetConnectTime() int32 { + if x != nil && x.ConnectTime != nil { + return *x.ConnectTime + } + return 0 +} + +type ClientVersion struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GitVersion string `protobuf:"bytes,1,opt,name=GitVersion,proto3" json:"GitVersion,omitempty"` + GitCommit string `protobuf:"bytes,2,opt,name=GitCommit,proto3" json:"GitCommit,omitempty"` + BuildDate string `protobuf:"bytes,3,opt,name=BuildDate,proto3" json:"BuildDate,omitempty"` + GoVersion string `protobuf:"bytes,4,opt,name=GoVersion,proto3" json:"GoVersion,omitempty"` + Compiler string `protobuf:"bytes,5,opt,name=Compiler,proto3" json:"Compiler,omitempty"` + Platform string `protobuf:"bytes,6,opt,name=Platform,proto3" json:"Platform,omitempty"` +} + +func (x *ClientVersion) Reset() { + *x = ClientVersion{} + mi := &file_api_master_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ClientVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClientVersion) ProtoMessage() {} + +func (x *ClientVersion) ProtoReflect() protoreflect.Message { + mi := &file_api_master_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClientVersion.ProtoReflect.Descriptor instead. +func (*ClientVersion) Descriptor() ([]byte, []int) { + return file_api_master_proto_rawDescGZIP(), []int{1} +} + +func (x *ClientVersion) GetGitVersion() string { + if x != nil { + return x.GitVersion + } + return "" +} + +func (x *ClientVersion) GetGitCommit() string { + if x != nil { + return x.GitCommit + } + return "" +} + +func (x *ClientVersion) GetBuildDate() string { + if x != nil { + return x.BuildDate + } + return "" +} + +func (x *ClientVersion) GetGoVersion() string { + if x != nil { + return x.GoVersion + } + return "" +} + +func (x *ClientVersion) GetCompiler() string { + if x != nil { + return x.Compiler + } + return "" +} + +func (x *ClientVersion) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + type GetClientsStatusRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -152,7 +261,7 @@ type GetClientsStatusRequest struct { func (x *GetClientsStatusRequest) Reset() { *x = GetClientsStatusRequest{} - mi := &file_api_master_proto_msgTypes[1] + mi := &file_api_master_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -164,7 +273,7 @@ func (x *GetClientsStatusRequest) String() string { func (*GetClientsStatusRequest) ProtoMessage() {} func (x *GetClientsStatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_master_proto_msgTypes[1] + mi := &file_api_master_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -177,7 +286,7 @@ func (x *GetClientsStatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetClientsStatusRequest.ProtoReflect.Descriptor instead. func (*GetClientsStatusRequest) Descriptor() ([]byte, []int) { - return file_api_master_proto_rawDescGZIP(), []int{1} + return file_api_master_proto_rawDescGZIP(), []int{2} } func (x *GetClientsStatusRequest) GetClientType() ClientType { @@ -205,7 +314,7 @@ type GetClientsStatusResponse struct { func (x *GetClientsStatusResponse) Reset() { *x = GetClientsStatusResponse{} - mi := &file_api_master_proto_msgTypes[2] + mi := &file_api_master_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -217,7 +326,7 @@ func (x *GetClientsStatusResponse) String() string { func (*GetClientsStatusResponse) ProtoMessage() {} func (x *GetClientsStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_master_proto_msgTypes[2] + mi := &file_api_master_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -230,7 +339,7 @@ func (x *GetClientsStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetClientsStatusResponse.ProtoReflect.Descriptor instead. func (*GetClientsStatusResponse) Descriptor() ([]byte, []int) { - return file_api_master_proto_rawDescGZIP(), []int{2} + return file_api_master_proto_rawDescGZIP(), []int{3} } func (x *GetClientsStatusResponse) GetStatus() *Status { @@ -259,7 +368,7 @@ type GetClientCertRequest struct { func (x *GetClientCertRequest) Reset() { *x = GetClientCertRequest{} - mi := &file_api_master_proto_msgTypes[3] + mi := &file_api_master_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -271,7 +380,7 @@ func (x *GetClientCertRequest) String() string { func (*GetClientCertRequest) ProtoMessage() {} func (x *GetClientCertRequest) ProtoReflect() protoreflect.Message { - mi := &file_api_master_proto_msgTypes[3] + mi := &file_api_master_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -284,7 +393,7 @@ func (x *GetClientCertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetClientCertRequest.ProtoReflect.Descriptor instead. func (*GetClientCertRequest) Descriptor() ([]byte, []int) { - return file_api_master_proto_rawDescGZIP(), []int{3} + return file_api_master_proto_rawDescGZIP(), []int{4} } func (x *GetClientCertRequest) GetClientType() ClientType { @@ -319,7 +428,7 @@ type GetClientCertResponse struct { func (x *GetClientCertResponse) Reset() { *x = GetClientCertResponse{} - mi := &file_api_master_proto_msgTypes[4] + mi := &file_api_master_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -331,7 +440,7 @@ func (x *GetClientCertResponse) String() string { func (*GetClientCertResponse) ProtoMessage() {} func (x *GetClientCertResponse) ProtoReflect() protoreflect.Message { - mi := &file_api_master_proto_msgTypes[4] + mi := &file_api_master_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -344,7 +453,7 @@ func (x *GetClientCertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetClientCertResponse.ProtoReflect.Descriptor instead. func (*GetClientCertResponse) Descriptor() ([]byte, []int) { - return file_api_master_proto_rawDescGZIP(), []int{4} + return file_api_master_proto_rawDescGZIP(), []int{5} } func (x *GetClientCertResponse) GetStatus() *Status { @@ -366,7 +475,7 @@ var File_api_master_proto protoreflect.FileDescriptor var file_api_master_proto_rawDesc = []byte{ 0x0a, 0x10, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x1a, 0x0c, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x88, 0x02, 0x0a, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa9, 0x03, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x33, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6c, 0x69, 0x65, @@ -377,52 +486,74 @@ var file_api_master_proto_rawDesc = []byte{ 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x22, 0x59, 0x0a, 0x06, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, - 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, - 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x4c, - 0x49, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x22, 0x6d, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x33, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0xf5, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, - 0x12, 0x4b, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x31, 0x2e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x47, - 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x54, 0x0a, - 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, - 0x2e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x8d, - 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x61, 0x64, 0x64, 0x72, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x61, 0x64, 0x64, 0x72, 0x88, 0x01, 0x01, 0x12, + 0x26, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x22, 0x59, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, + 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4e, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, + 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x46, 0x46, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x02, + 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, + 0x10, 0x03, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x07, + 0x0a, 0x05, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x22, 0xc1, 0x01, 0x0a, 0x0d, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x69, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x47, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x47, 0x69, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x47, + 0x69, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x44, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x47, 0x6f, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x47, 0x6f, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x6d, 0x0a, 0x17, + 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x63, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x04, 0x63, 0x65, 0x72, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x73, 0x22, 0xf5, 0x01, 0x0a, 0x18, + 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x88, 0x01, 0x01, 0x12, 0x4b, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, + 0x74, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x73, 0x1a, 0x54, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x5f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x8d, 0x01, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x0b, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x23, + 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x22, 0x63, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x65, 0x72, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x63, 0x65, 0x72, 0x74, 0x42, 0x09, 0x0a, + 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, + 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -438,32 +569,34 @@ func file_api_master_proto_rawDescGZIP() []byte { } var file_api_master_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_api_master_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_api_master_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_api_master_proto_goTypes = []any{ (ClientStatus_Status)(0), // 0: api_master.ClientStatus.Status (*ClientStatus)(nil), // 1: api_master.ClientStatus - (*GetClientsStatusRequest)(nil), // 2: api_master.GetClientsStatusRequest - (*GetClientsStatusResponse)(nil), // 3: api_master.GetClientsStatusResponse - (*GetClientCertRequest)(nil), // 4: api_master.GetClientCertRequest - (*GetClientCertResponse)(nil), // 5: api_master.GetClientCertResponse - nil, // 6: api_master.GetClientsStatusResponse.ClientsEntry - (ClientType)(0), // 7: common.ClientType - (*Status)(nil), // 8: common.Status + (*ClientVersion)(nil), // 2: api_master.ClientVersion + (*GetClientsStatusRequest)(nil), // 3: api_master.GetClientsStatusRequest + (*GetClientsStatusResponse)(nil), // 4: api_master.GetClientsStatusResponse + (*GetClientCertRequest)(nil), // 5: api_master.GetClientCertRequest + (*GetClientCertResponse)(nil), // 6: api_master.GetClientCertResponse + nil, // 7: api_master.GetClientsStatusResponse.ClientsEntry + (ClientType)(0), // 8: common.ClientType + (*Status)(nil), // 9: common.Status } var file_api_master_proto_depIdxs = []int32{ - 7, // 0: api_master.ClientStatus.client_type:type_name -> common.ClientType + 8, // 0: api_master.ClientStatus.client_type:type_name -> common.ClientType 0, // 1: api_master.ClientStatus.status:type_name -> api_master.ClientStatus.Status - 7, // 2: api_master.GetClientsStatusRequest.client_type:type_name -> common.ClientType - 8, // 3: api_master.GetClientsStatusResponse.status:type_name -> common.Status - 6, // 4: api_master.GetClientsStatusResponse.clients:type_name -> api_master.GetClientsStatusResponse.ClientsEntry - 7, // 5: api_master.GetClientCertRequest.client_type:type_name -> common.ClientType - 8, // 6: api_master.GetClientCertResponse.status:type_name -> common.Status - 1, // 7: api_master.GetClientsStatusResponse.ClientsEntry.value:type_name -> api_master.ClientStatus - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 2, // 2: api_master.ClientStatus.version:type_name -> api_master.ClientVersion + 8, // 3: api_master.GetClientsStatusRequest.client_type:type_name -> common.ClientType + 9, // 4: api_master.GetClientsStatusResponse.status:type_name -> common.Status + 7, // 5: api_master.GetClientsStatusResponse.clients:type_name -> api_master.GetClientsStatusResponse.ClientsEntry + 8, // 6: api_master.GetClientCertRequest.client_type:type_name -> common.ClientType + 9, // 7: api_master.GetClientCertResponse.status:type_name -> common.Status + 1, // 8: api_master.GetClientsStatusResponse.ClientsEntry.value:type_name -> api_master.ClientStatus + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_api_master_proto_init() } @@ -472,15 +605,16 @@ func file_api_master_proto_init() { return } file_common_proto_init() - file_api_master_proto_msgTypes[2].OneofWrappers = []any{} - file_api_master_proto_msgTypes[4].OneofWrappers = []any{} + file_api_master_proto_msgTypes[0].OneofWrappers = []any{} + file_api_master_proto_msgTypes[3].OneofWrappers = []any{} + file_api_master_proto_msgTypes[5].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_master_proto_rawDesc, NumEnums: 1, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/pb/common.pb.go b/pb/common.pb.go index 5ad99c0..c7f3552 100644 --- a/pb/common.pb.go +++ b/pb/common.pb.go @@ -187,6 +187,8 @@ type CommonRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Data *string `protobuf:"bytes,1,opt,name=data,proto3,oneof" json:"data,omitempty"` } func (x *CommonRequest) Reset() { @@ -219,12 +221,20 @@ func (*CommonRequest) Descriptor() ([]byte, []int) { return file_common_proto_rawDescGZIP(), []int{1} } +func (x *CommonRequest) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + type CommonResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Status *Status `protobuf:"bytes,1,opt,name=status,proto3,oneof" json:"status,omitempty"` + Data *string `protobuf:"bytes,2,opt,name=data,proto3,oneof" json:"data,omitempty"` } func (x *CommonResponse) Reset() { @@ -264,6 +274,13 @@ func (x *CommonResponse) GetStatus() *Status { return nil } +func (x *CommonResponse) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + type Client struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -645,112 +662,116 @@ var file_common_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x48, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, - 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x06, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, - 0x74, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x73, 0x74, 0x6f, 0x70, 0x70, 0x65, - 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, 0x05, 0x52, 0x07, 0x73, 0x74, 0x6f, 0x70, 0x70, - 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x42, 0x09, 0x0a, 0x07, - 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0c, - 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x42, 0x0a, 0x0a, 0x08, - 0x5f, 0x73, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x22, 0xbb, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x88, 0x01, 0x01, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x02, 0x52, 0x02, 0x69, 0x70, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, - 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, 0x42, 0x09, 0x0a, - 0x07, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x70, 0x42, - 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0xd5, 0x02, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x1b, 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x48, - 0x00, 0x52, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, - 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, - 0x52, 0x08, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, - 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x02, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x19, - 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, - 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x06, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, - 0x19, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, - 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x52, 0x61, - 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x07, 0x52, 0x0b, 0x52, 0x61, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x88, 0x01, - 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x42, 0x0b, 0x0a, 0x09, - 0x5f, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x55, 0x73, - 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x45, 0x6d, 0x61, 0x69, 0x6c, - 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, - 0x52, 0x6f, 0x6c, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0e, - 0x0a, 0x0c, 0x5f, 0x52, 0x61, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x84, - 0x04, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x20, - 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x48, 0x02, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, - 0x12, 0x20, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x88, - 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, - 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x48, 0x04, 0x52, 0x0e, - 0x74, 0x6f, 0x64, 0x61, 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x49, 0x6e, 0x88, 0x01, - 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, - 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x48, 0x05, 0x52, 0x0f, - 0x74, 0x6f, 0x64, 0x61, 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x88, - 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x72, - 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x48, 0x06, - 0x52, 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, - 0x49, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x08, 0x20, 0x01, - 0x28, 0x03, 0x48, 0x07, 0x52, 0x11, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x72, 0x61, - 0x66, 0x66, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x66, 0x69, - 0x72, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x08, - 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x88, 0x01, 0x01, 0x42, 0x07, - 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x0c, - 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x42, 0x13, 0x0a, 0x11, - 0x5f, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, - 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, - 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x69, 0x73, 0x74, - 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x42, 0x16, - 0x0a, 0x14, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, - 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, - 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x2a, 0xbc, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x43, 0x6f, - 0x64, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, - 0x11, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, - 0x53, 0x53, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, - 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x1c, 0x0a, - 0x18, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x41, 0x4c, 0x52, 0x45, 0x41, - 0x44, 0x59, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x52, - 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, - 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x45, 0x53, 0x50, - 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, - 0x45, 0x44, 0x10, 0x06, 0x2a, 0x55, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x14, 0x0a, 0x10, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, - 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x02, 0x42, 0x07, 0x5a, 0x05, 0x2e, - 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x31, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, + 0x61, 0x74, 0x61, 0x22, 0x6a, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, + 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x01, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, + 0xfa, 0x01, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, + 0x1b, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x01, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x08, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x73, 0x74, + 0x6f, 0x70, 0x70, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x48, 0x05, 0x52, 0x07, 0x73, + 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, 0x64, + 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x73, 0x74, 0x6f, 0x70, 0x70, 0x65, 0x64, 0x22, 0xbb, 0x01, 0x0a, + 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x69, 0x64, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, + 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x88, 0x01, 0x01, 0x12, 0x13, 0x0a, 0x02, 0x69, 0x70, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x02, 0x69, 0x70, 0x88, 0x01, 0x01, 0x12, 0x1b, + 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, + 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x88, 0x01, 0x01, 0x12, 0x1d, 0x0a, 0x07, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, 0x07, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x69, + 0x64, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x05, 0x0a, 0x03, + 0x5f, 0x69, 0x70, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x0a, + 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0xd5, 0x02, 0x0a, 0x04, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x88, 0x01, 0x01, + 0x12, 0x1f, 0x0a, 0x08, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x08, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x88, 0x01, + 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x88, + 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x03, 0x52, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, + 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x04, 0x52, + 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x52, 0x6f, + 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x05, 0x52, 0x04, 0x52, 0x6f, 0x6c, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x06, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x25, + 0x0a, 0x0b, 0x52, 0x61, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x07, 0x52, 0x0b, 0x52, 0x61, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x42, 0x0b, 0x0a, + 0x09, 0x5f, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, + 0x07, 0x0a, 0x05, 0x5f, 0x52, 0x6f, 0x6c, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x52, 0x61, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x22, 0x84, 0x04, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, + 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, + 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, + 0x48, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, + 0x49, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, + 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, + 0x48, 0x05, 0x52, 0x0f, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, + 0x4f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x31, 0x0a, 0x12, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x06, 0x52, 0x10, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x49, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x33, 0x0a, 0x13, 0x68, 0x69, 0x73, + 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x48, 0x07, 0x52, 0x11, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x4f, 0x75, 0x74, 0x88, 0x01, 0x01, 0x12, 0x22, + 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x48, 0x08, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x88, + 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x5f, 0x69, 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x74, 0x6f, 0x64, 0x61, 0x79, 0x5f, + 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, + 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, + 0x69, 0x6e, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, + 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x6f, 0x75, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x2a, 0xbc, 0x01, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, + 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x53, + 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x53, 0x50, + 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, + 0x02, 0x12, 0x1c, 0x0a, 0x18, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x41, + 0x4c, 0x52, 0x45, 0x41, 0x44, 0x59, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x53, 0x10, 0x03, 0x12, + 0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x49, 0x4e, 0x56, + 0x41, 0x4c, 0x49, 0x44, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, + 0x4f, 0x44, 0x45, 0x5f, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x10, 0x05, 0x12, 0x1a, 0x0a, 0x16, + 0x52, 0x45, 0x53, 0x50, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, + 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x06, 0x2a, 0x55, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x43, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x4c, 0x49, + 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x02, 0x42, + 0x07, 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -793,6 +814,7 @@ func file_common_proto_init() { if File_common_proto != nil { return } + file_common_proto_msgTypes[1].OneofWrappers = []any{} file_common_proto_msgTypes[2].OneofWrappers = []any{} file_common_proto_msgTypes[3].OneofWrappers = []any{} file_common_proto_msgTypes[4].OneofWrappers = []any{} diff --git a/pb/rpc_master.pb.go b/pb/rpc_master.pb.go index b31a39e..fd85e30 100644 --- a/pb/rpc_master.pb.go +++ b/pb/rpc_master.pb.go @@ -23,23 +23,24 @@ const ( type Event int32 const ( - Event_EVENT_UNSPECIFIED Event = 0 - Event_EVENT_REGISTER_CLIENT Event = 1 - Event_EVENT_REGISTER_SERVER Event = 2 - Event_EVENT_ERROR Event = 3 - Event_EVENT_DATA Event = 4 - Event_EVENT_UPDATE_FRPC Event = 5 - Event_EVENT_REMOVE_FRPC Event = 6 - Event_EVENT_UPDATE_FRPS Event = 7 - Event_EVENT_REMOVE_FRPS Event = 8 - Event_EVENT_PING Event = 9 - Event_EVENT_PONG Event = 10 - Event_EVENT_STOP_FRPC Event = 11 - Event_EVENT_START_FRPC Event = 12 - Event_EVENT_STOP_FRPS Event = 13 - Event_EVENT_START_FRPS Event = 14 - Event_EVENT_START_STREAM_LOG Event = 15 - Event_EVENT_STOP_STREAM_LOG Event = 16 + Event_EVENT_UNSPECIFIED Event = 0 + Event_EVENT_REGISTER_CLIENT Event = 1 + Event_EVENT_REGISTER_SERVER Event = 2 + Event_EVENT_ERROR Event = 3 + Event_EVENT_DATA Event = 4 + Event_EVENT_UPDATE_FRPC Event = 5 + Event_EVENT_REMOVE_FRPC Event = 6 + Event_EVENT_UPDATE_FRPS Event = 7 + Event_EVENT_REMOVE_FRPS Event = 8 + Event_EVENT_PING Event = 9 + Event_EVENT_PONG Event = 10 + Event_EVENT_STOP_FRPC Event = 11 + Event_EVENT_START_FRPC Event = 12 + Event_EVENT_STOP_FRPS Event = 13 + Event_EVENT_START_FRPS Event = 14 + Event_EVENT_START_STREAM_LOG Event = 15 + Event_EVENT_STOP_STREAM_LOG Event = 16 + Event_EVENT_START_PTY_CONNECT Event = 17 ) // Enum value maps for Event. @@ -62,25 +63,27 @@ var ( 14: "EVENT_START_FRPS", 15: "EVENT_START_STREAM_LOG", 16: "EVENT_STOP_STREAM_LOG", + 17: "EVENT_START_PTY_CONNECT", } Event_value = map[string]int32{ - "EVENT_UNSPECIFIED": 0, - "EVENT_REGISTER_CLIENT": 1, - "EVENT_REGISTER_SERVER": 2, - "EVENT_ERROR": 3, - "EVENT_DATA": 4, - "EVENT_UPDATE_FRPC": 5, - "EVENT_REMOVE_FRPC": 6, - "EVENT_UPDATE_FRPS": 7, - "EVENT_REMOVE_FRPS": 8, - "EVENT_PING": 9, - "EVENT_PONG": 10, - "EVENT_STOP_FRPC": 11, - "EVENT_START_FRPC": 12, - "EVENT_STOP_FRPS": 13, - "EVENT_START_FRPS": 14, - "EVENT_START_STREAM_LOG": 15, - "EVENT_STOP_STREAM_LOG": 16, + "EVENT_UNSPECIFIED": 0, + "EVENT_REGISTER_CLIENT": 1, + "EVENT_REGISTER_SERVER": 2, + "EVENT_ERROR": 3, + "EVENT_DATA": 4, + "EVENT_UPDATE_FRPC": 5, + "EVENT_REMOVE_FRPC": 6, + "EVENT_UPDATE_FRPS": 7, + "EVENT_REMOVE_FRPS": 8, + "EVENT_PING": 9, + "EVENT_PONG": 10, + "EVENT_STOP_FRPC": 11, + "EVENT_START_FRPC": 12, + "EVENT_STOP_FRPS": 13, + "EVENT_START_FRPS": 14, + "EVENT_START_STREAM_LOG": 15, + "EVENT_STOP_STREAM_LOG": 16, + "EVENT_START_PTY_CONNECT": 17, } ) @@ -930,6 +933,178 @@ func (x *PushStreamLogResp) GetOk() bool { return false } +type PTYClientMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data *string `protobuf:"bytes,1,opt,name=data,proto3,oneof" json:"data,omitempty"` + SessionId string `protobuf:"bytes,2,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + Done bool `protobuf:"varint,3,opt,name=done,proto3" json:"done,omitempty"` + // Types that are assignable to Base: + // + // *PTYClientMessage_ServerBase + // *PTYClientMessage_ClientBase + Base isPTYClientMessage_Base `protobuf_oneof:"Base"` +} + +func (x *PTYClientMessage) Reset() { + *x = PTYClientMessage{} + mi := &file_rpc_master_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PTYClientMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PTYClientMessage) ProtoMessage() {} + +func (x *PTYClientMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_master_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PTYClientMessage.ProtoReflect.Descriptor instead. +func (*PTYClientMessage) Descriptor() ([]byte, []int) { + return file_rpc_master_proto_rawDescGZIP(), []int{15} +} + +func (x *PTYClientMessage) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + +func (x *PTYClientMessage) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +func (x *PTYClientMessage) GetDone() bool { + if x != nil { + return x.Done + } + return false +} + +func (m *PTYClientMessage) GetBase() isPTYClientMessage_Base { + if m != nil { + return m.Base + } + return nil +} + +func (x *PTYClientMessage) GetServerBase() *ServerBase { + if x, ok := x.GetBase().(*PTYClientMessage_ServerBase); ok { + return x.ServerBase + } + return nil +} + +func (x *PTYClientMessage) GetClientBase() *ClientBase { + if x, ok := x.GetBase().(*PTYClientMessage_ClientBase); ok { + return x.ClientBase + } + return nil +} + +type isPTYClientMessage_Base interface { + isPTYClientMessage_Base() +} + +type PTYClientMessage_ServerBase struct { + ServerBase *ServerBase `protobuf:"bytes,254,opt,name=server_base,json=serverBase,proto3,oneof"` +} + +type PTYClientMessage_ClientBase struct { + ClientBase *ClientBase `protobuf:"bytes,255,opt,name=client_base,json=clientBase,proto3,oneof"` +} + +func (*PTYClientMessage_ServerBase) isPTYClientMessage_Base() {} + +func (*PTYClientMessage_ClientBase) isPTYClientMessage_Base() {} + +type PTYServerMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data *string `protobuf:"bytes,1,opt,name=data,proto3,oneof" json:"data,omitempty"` + Height *int32 `protobuf:"varint,2,opt,name=height,proto3,oneof" json:"height,omitempty"` + Width *int32 `protobuf:"varint,3,opt,name=width,proto3,oneof" json:"width,omitempty"` + Done bool `protobuf:"varint,4,opt,name=done,proto3" json:"done,omitempty"` +} + +func (x *PTYServerMessage) Reset() { + *x = PTYServerMessage{} + mi := &file_rpc_master_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PTYServerMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PTYServerMessage) ProtoMessage() {} + +func (x *PTYServerMessage) ProtoReflect() protoreflect.Message { + mi := &file_rpc_master_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PTYServerMessage.ProtoReflect.Descriptor instead. +func (*PTYServerMessage) Descriptor() ([]byte, []int) { + return file_rpc_master_proto_rawDescGZIP(), []int{16} +} + +func (x *PTYServerMessage) GetData() string { + if x != nil && x.Data != nil { + return *x.Data + } + return "" +} + +func (x *PTYServerMessage) GetHeight() int32 { + if x != nil && x.Height != nil { + return *x.Height + } + return 0 +} + +func (x *PTYServerMessage) GetWidth() int32 { + if x != nil && x.Width != nil { + return *x.Width + } + return 0 +} + +func (x *PTYServerMessage) GetDone() bool { + if x != nil { + return x.Done + } + return false +} + var File_rpc_master_proto protoreflect.FileDescriptor var file_rpc_master_proto_rawDesc = []byte{ @@ -1022,65 +1197,95 @@ var file_rpc_master_proto_rawDesc = []byte{ 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x02, 0x6f, 0x6b, 0x2a, 0xfe, 0x02, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x15, 0x0a, - 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, - 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, - 0x19, 0x0a, 0x15, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, - 0x52, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x56, - 0x45, 0x4e, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x45, - 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x45, - 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x43, - 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, - 0x56, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x43, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, - 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x07, - 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, - 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x50, 0x4f, 0x4e, 0x47, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x46, 0x52, 0x50, 0x43, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x46, 0x52, 0x50, 0x43, - 0x10, 0x0c, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, - 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x56, 0x45, 0x4e, 0x54, - 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x0e, 0x12, 0x1a, 0x0a, - 0x16, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, - 0x45, 0x41, 0x4d, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x0f, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x56, 0x45, - 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4c, - 0x4f, 0x47, 0x10, 0x10, 0x32, 0x91, 0x04, 0x0a, 0x06, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, - 0x3e, 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x15, 0x2e, - 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x1a, 0x15, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, - 0x4d, 0x0a, 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, - 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, - 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, - 0x0a, 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, 0x6c, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, - 0x1c, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x3b, 0x0a, - 0x08, 0x46, 0x52, 0x50, 0x43, 0x41, 0x75, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x73, 0x74, - 0x65, 0x72, 0x2e, 0x46, 0x52, 0x50, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x46, 0x52, 0x50, 0x41, 0x75, - 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x50, 0x75, - 0x73, 0x68, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, - 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, - 0x75, 0x73, 0x68, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, - 0x12, 0x52, 0x0a, 0x13, 0x50, 0x75, 0x73, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x50, 0x75, 0x73, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, - 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, - 0x73, 0x70, 0x28, 0x01, 0x12, 0x52, 0x0a, 0x13, 0x50, 0x75, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6d, 0x61, - 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, - 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x28, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x02, 0x6f, 0x6b, 0x22, 0xdf, 0x01, 0x0a, 0x10, 0x50, 0x54, 0x59, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x88, 0x01, + 0x01, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, + 0x64, 0x6f, 0x6e, 0x65, 0x12, 0x36, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x62, + 0x61, 0x73, 0x65, 0x18, 0xfe, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x73, + 0x74, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x61, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0b, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x18, 0xff, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x42, 0x61, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x42, 0x61, 0x73, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x42, 0x61, 0x73, 0x65, 0x42, 0x07, 0x0a, 0x05, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x22, 0x95, 0x01, 0x0a, 0x10, 0x50, 0x54, 0x59, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x88, 0x01, 0x01, + 0x12, 0x19, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, + 0x02, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x6f, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x42, + 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x68, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2a, 0x9b, 0x03, + 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, + 0x0a, 0x15, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, + 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x5f, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x44, + 0x41, 0x54, 0x41, 0x10, 0x04, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, + 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x43, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, + 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x46, 0x52, 0x50, + 0x43, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x45, 0x56, + 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, + 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x10, + 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x4f, 0x4e, 0x47, 0x10, + 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x5f, + 0x46, 0x52, 0x50, 0x43, 0x10, 0x0b, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, + 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x46, 0x52, 0x50, 0x43, 0x10, 0x0c, 0x12, 0x13, 0x0a, 0x0f, + 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, + 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x5f, 0x46, 0x52, 0x50, 0x53, 0x10, 0x0e, 0x12, 0x1a, 0x0a, 0x16, 0x45, 0x56, 0x45, 0x4e, 0x54, + 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4c, 0x4f, + 0x47, 0x10, 0x0f, 0x12, 0x19, 0x0a, 0x15, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, + 0x50, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x10, 0x12, 0x1b, + 0x0a, 0x17, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x50, 0x54, + 0x59, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x11, 0x32, 0xd7, 0x04, 0x0a, 0x06, + 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x53, 0x65, 0x6e, 0x64, 0x12, 0x15, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x15, 0x2e, 0x6d, 0x61, + 0x73, 0x74, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x73, + 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x4d, 0x0a, 0x10, 0x50, 0x75, 0x6c, 0x6c, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x61, 0x73, 0x74, + 0x65, 0x72, 0x2e, 0x50, 0x75, 0x6c, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1c, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, + 0x50, 0x75, 0x6c, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x3b, 0x0a, 0x08, 0x46, 0x52, 0x50, 0x43, 0x41, 0x75, 0x74, 0x68, + 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x46, 0x52, 0x50, 0x41, 0x75, 0x74, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, + 0x72, 0x2e, 0x46, 0x52, 0x50, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x18, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x12, 0x52, 0x0a, 0x13, 0x50, 0x75, 0x73, 0x68, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x12, 0x1e, + 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x19, + 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x28, 0x01, 0x12, 0x52, 0x0a, 0x13, 0x50, + 0x75, 0x73, 0x68, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, + 0x6f, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, + 0x65, 0x71, 0x1a, 0x19, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x28, 0x01, 0x12, + 0x44, 0x0a, 0x0a, 0x50, 0x54, 0x59, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x18, 0x2e, + 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x50, 0x54, 0x59, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x2e, 0x50, 0x54, 0x59, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1096,7 +1301,7 @@ func file_rpc_master_proto_rawDescGZIP() []byte { } var file_rpc_master_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_rpc_master_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_rpc_master_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_rpc_master_proto_goTypes = []any{ (Event)(0), // 0: master.Event (*ServerBase)(nil), // 1: master.ServerBase @@ -1114,47 +1319,53 @@ var file_rpc_master_proto_goTypes = []any{ (*PushServerStreamLogReq)(nil), // 13: master.PushServerStreamLogReq (*PushClientStreamLogReq)(nil), // 14: master.PushClientStreamLogReq (*PushStreamLogResp)(nil), // 15: master.PushStreamLogResp - (*Status)(nil), // 16: common.Status - (*Client)(nil), // 17: common.Client - (*Server)(nil), // 18: common.Server - (*ProxyInfo)(nil), // 19: common.ProxyInfo + (*PTYClientMessage)(nil), // 16: master.PTYClientMessage + (*PTYServerMessage)(nil), // 17: master.PTYServerMessage + (*Status)(nil), // 18: common.Status + (*Client)(nil), // 19: common.Client + (*Server)(nil), // 20: common.Server + (*ProxyInfo)(nil), // 21: common.ProxyInfo } var file_rpc_master_proto_depIdxs = []int32{ 0, // 0: master.ServerMessage.event:type_name -> master.Event 0, // 1: master.ClientMessage.event:type_name -> master.Event 2, // 2: master.PullClientConfigReq.base:type_name -> master.ClientBase - 16, // 3: master.PullClientConfigResp.status:type_name -> common.Status - 17, // 4: master.PullClientConfigResp.client:type_name -> common.Client + 18, // 3: master.PullClientConfigResp.status:type_name -> common.Status + 19, // 4: master.PullClientConfigResp.client:type_name -> common.Client 1, // 5: master.PullServerConfigReq.base:type_name -> master.ServerBase - 16, // 6: master.PullServerConfigResp.status:type_name -> common.Status - 18, // 7: master.PullServerConfigResp.server:type_name -> common.Server + 18, // 6: master.PullServerConfigResp.status:type_name -> common.Status + 20, // 7: master.PullServerConfigResp.server:type_name -> common.Server 1, // 8: master.FRPAuthRequest.base:type_name -> master.ServerBase - 16, // 9: master.FRPAuthResponse.status:type_name -> common.Status + 18, // 9: master.FRPAuthResponse.status:type_name -> common.Status 1, // 10: master.PushProxyInfoReq.base:type_name -> master.ServerBase - 19, // 11: master.PushProxyInfoReq.proxy_infos:type_name -> common.ProxyInfo - 16, // 12: master.PushProxyInfoResp.status:type_name -> common.Status + 21, // 11: master.PushProxyInfoReq.proxy_infos:type_name -> common.ProxyInfo + 18, // 12: master.PushProxyInfoResp.status:type_name -> common.Status 1, // 13: master.PushServerStreamLogReq.base:type_name -> master.ServerBase 2, // 14: master.PushClientStreamLogReq.base:type_name -> master.ClientBase - 16, // 15: master.PushStreamLogResp.status:type_name -> common.Status - 4, // 16: master.Master.ServerSend:input_type -> master.ClientMessage - 5, // 17: master.Master.PullClientConfig:input_type -> master.PullClientConfigReq - 7, // 18: master.Master.PullServerConfig:input_type -> master.PullServerConfigReq - 9, // 19: master.Master.FRPCAuth:input_type -> master.FRPAuthRequest - 11, // 20: master.Master.PushProxyInfo:input_type -> master.PushProxyInfoReq - 14, // 21: master.Master.PushClientStreamLog:input_type -> master.PushClientStreamLogReq - 13, // 22: master.Master.PushServerStreamLog:input_type -> master.PushServerStreamLogReq - 3, // 23: master.Master.ServerSend:output_type -> master.ServerMessage - 6, // 24: master.Master.PullClientConfig:output_type -> master.PullClientConfigResp - 8, // 25: master.Master.PullServerConfig:output_type -> master.PullServerConfigResp - 10, // 26: master.Master.FRPCAuth:output_type -> master.FRPAuthResponse - 12, // 27: master.Master.PushProxyInfo:output_type -> master.PushProxyInfoResp - 15, // 28: master.Master.PushClientStreamLog:output_type -> master.PushStreamLogResp - 15, // 29: master.Master.PushServerStreamLog:output_type -> master.PushStreamLogResp - 23, // [23:30] is the sub-list for method output_type - 16, // [16:23] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 18, // 15: master.PushStreamLogResp.status:type_name -> common.Status + 1, // 16: master.PTYClientMessage.server_base:type_name -> master.ServerBase + 2, // 17: master.PTYClientMessage.client_base:type_name -> master.ClientBase + 4, // 18: master.Master.ServerSend:input_type -> master.ClientMessage + 5, // 19: master.Master.PullClientConfig:input_type -> master.PullClientConfigReq + 7, // 20: master.Master.PullServerConfig:input_type -> master.PullServerConfigReq + 9, // 21: master.Master.FRPCAuth:input_type -> master.FRPAuthRequest + 11, // 22: master.Master.PushProxyInfo:input_type -> master.PushProxyInfoReq + 14, // 23: master.Master.PushClientStreamLog:input_type -> master.PushClientStreamLogReq + 13, // 24: master.Master.PushServerStreamLog:input_type -> master.PushServerStreamLogReq + 16, // 25: master.Master.PTYConnect:input_type -> master.PTYClientMessage + 3, // 26: master.Master.ServerSend:output_type -> master.ServerMessage + 6, // 27: master.Master.PullClientConfig:output_type -> master.PullClientConfigResp + 8, // 28: master.Master.PullServerConfig:output_type -> master.PullServerConfigResp + 10, // 29: master.Master.FRPCAuth:output_type -> master.FRPAuthResponse + 12, // 30: master.Master.PushProxyInfo:output_type -> master.PushProxyInfoResp + 15, // 31: master.Master.PushClientStreamLog:output_type -> master.PushStreamLogResp + 15, // 32: master.Master.PushServerStreamLog:output_type -> master.PushStreamLogResp + 17, // 33: master.Master.PTYConnect:output_type -> master.PTYServerMessage + 26, // [26:34] is the sub-list for method output_type + 18, // [18:26] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name } func init() { file_rpc_master_proto_init() } @@ -1163,13 +1374,18 @@ func file_rpc_master_proto_init() { return } file_common_proto_init() + file_rpc_master_proto_msgTypes[15].OneofWrappers = []any{ + (*PTYClientMessage_ServerBase)(nil), + (*PTYClientMessage_ClientBase)(nil), + } + file_rpc_master_proto_msgTypes[16].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_master_proto_rawDesc, NumEnums: 1, - NumMessages: 15, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/pb/rpc_master_grpc.pb.go b/pb/rpc_master_grpc.pb.go index 1d68d3d..386b308 100644 --- a/pb/rpc_master_grpc.pb.go +++ b/pb/rpc_master_grpc.pb.go @@ -26,6 +26,7 @@ const ( Master_PushProxyInfo_FullMethodName = "/master.Master/PushProxyInfo" Master_PushClientStreamLog_FullMethodName = "/master.Master/PushClientStreamLog" Master_PushServerStreamLog_FullMethodName = "/master.Master/PushServerStreamLog" + Master_PTYConnect_FullMethodName = "/master.Master/PTYConnect" ) // MasterClient is the client API for Master service. @@ -39,6 +40,7 @@ type MasterClient interface { PushProxyInfo(ctx context.Context, in *PushProxyInfoReq, opts ...grpc.CallOption) (*PushProxyInfoResp, error) PushClientStreamLog(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PushClientStreamLogReq, PushStreamLogResp], error) PushServerStreamLog(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[PushServerStreamLogReq, PushStreamLogResp], error) + PTYConnect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[PTYClientMessage, PTYServerMessage], error) } type masterClient struct { @@ -128,6 +130,19 @@ func (c *masterClient) PushServerStreamLog(ctx context.Context, opts ...grpc.Cal // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type Master_PushServerStreamLogClient = grpc.ClientStreamingClient[PushServerStreamLogReq, PushStreamLogResp] +func (c *masterClient) PTYConnect(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[PTYClientMessage, PTYServerMessage], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &Master_ServiceDesc.Streams[3], Master_PTYConnect_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[PTYClientMessage, PTYServerMessage]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Master_PTYConnectClient = grpc.BidiStreamingClient[PTYClientMessage, PTYServerMessage] + // MasterServer is the server API for Master service. // All implementations must embed UnimplementedMasterServer // for forward compatibility. @@ -139,6 +154,7 @@ type MasterServer interface { PushProxyInfo(context.Context, *PushProxyInfoReq) (*PushProxyInfoResp, error) PushClientStreamLog(grpc.ClientStreamingServer[PushClientStreamLogReq, PushStreamLogResp]) error PushServerStreamLog(grpc.ClientStreamingServer[PushServerStreamLogReq, PushStreamLogResp]) error + PTYConnect(grpc.BidiStreamingServer[PTYClientMessage, PTYServerMessage]) error mustEmbedUnimplementedMasterServer() } @@ -170,6 +186,9 @@ func (UnimplementedMasterServer) PushClientStreamLog(grpc.ClientStreamingServer[ func (UnimplementedMasterServer) PushServerStreamLog(grpc.ClientStreamingServer[PushServerStreamLogReq, PushStreamLogResp]) error { return status.Errorf(codes.Unimplemented, "method PushServerStreamLog not implemented") } +func (UnimplementedMasterServer) PTYConnect(grpc.BidiStreamingServer[PTYClientMessage, PTYServerMessage]) error { + return status.Errorf(codes.Unimplemented, "method PTYConnect not implemented") +} func (UnimplementedMasterServer) mustEmbedUnimplementedMasterServer() {} func (UnimplementedMasterServer) testEmbeddedByValue() {} @@ -284,6 +303,13 @@ func _Master_PushServerStreamLog_Handler(srv interface{}, stream grpc.ServerStre // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type Master_PushServerStreamLogServer = grpc.ClientStreamingServer[PushServerStreamLogReq, PushStreamLogResp] +func _Master_PTYConnect_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(MasterServer).PTYConnect(&grpc.GenericServerStream[PTYClientMessage, PTYServerMessage]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type Master_PTYConnectServer = grpc.BidiStreamingServer[PTYClientMessage, PTYServerMessage] + // Master_ServiceDesc is the grpc.ServiceDesc for Master service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -325,6 +351,12 @@ var Master_ServiceDesc = grpc.ServiceDesc{ Handler: _Master_PushServerStreamLog_Handler, ClientStreams: true, }, + { + StreamName: "PTYConnect", + Handler: _Master_PTYConnect_Handler, + ServerStreams: true, + ClientStreams: true, + }, }, Metadata: "rpc_master.proto", } diff --git a/rpc/client_manager.go b/rpc/client_manager.go index 2da12f8..d873cc7 100644 --- a/rpc/client_manager.go +++ b/rpc/client_manager.go @@ -1,15 +1,19 @@ package rpc import ( - "sync" + "time" "github.com/VaalaCat/frp-panel/pb" + "github.com/VaalaCat/frp-panel/utils" + "google.golang.org/grpc/peer" ) type ClientsManager interface { Get(cliID string) *Connector Set(cliID, clientType string, sender pb.Master_ServerSendServer) Remove(cliID string) + ClientAddr(cliID string) string + ConnectTime(cliID string) (time.Time, bool) } type Connector struct { @@ -19,7 +23,8 @@ type Connector struct { } type ClientsManagerImpl struct { - senders *sync.Map + senders *utils.SyncMap[string, *Connector] + connectTime *utils.SyncMap[string, time.Time] } // Get implements ClientsManager. @@ -28,13 +33,7 @@ func (c *ClientsManagerImpl) Get(cliID string) *Connector { if !ok { return nil } - - cli, ok := cliAny.(*Connector) - if !ok { - return nil - } - - return cli + return cliAny } // Set implements ClientsManager. @@ -44,10 +43,32 @@ func (c *ClientsManagerImpl) Set(cliID, clientType string, sender pb.Master_Serv Conn: sender, CliType: clientType, }) + c.connectTime.Store(cliID, time.Now()) } func (c *ClientsManagerImpl) Remove(cliID string) { c.senders.Delete(cliID) + c.connectTime.Delete(cliID) +} + +func (c *ClientsManagerImpl) ClientAddr(cliID string) string { + connector := c.Get(cliID) + if connector == nil { + return "" + } + p, ok := peer.FromContext(connector.Conn.Context()) + if !ok || p == nil { + return "" + } + return p.Addr.String() +} + +func (c *ClientsManagerImpl) ConnectTime(cliID string) (time.Time, bool) { + t, ok := c.connectTime.Load(cliID) + if !ok { + return time.Time{}, false + } + return t, true } var ( @@ -56,7 +77,8 @@ var ( func NewClientsManager() *ClientsManagerImpl { return &ClientsManagerImpl{ - senders: &sync.Map{}, + senders: &utils.SyncMap[string, *Connector]{}, + connectTime: &utils.SyncMap[string, time.Time]{}, } } diff --git a/services/master/grpc_server.go b/services/master/grpc_server.go index 44aa41f..d4533e1 100644 --- a/services/master/grpc_server.go +++ b/services/master/grpc_server.go @@ -8,6 +8,7 @@ import ( "github.com/VaalaCat/frp-panel/biz/master/client" masterserver "github.com/VaalaCat/frp-panel/biz/master/server" + "github.com/VaalaCat/frp-panel/biz/master/shell" "github.com/VaalaCat/frp-panel/biz/master/streamlog" "github.com/VaalaCat/frp-panel/common" "github.com/VaalaCat/frp-panel/conf" @@ -63,7 +64,6 @@ func (*server) FRPCAuth(ctx context.Context, req *pb.FRPAuthRequest) (*pb.FRPAut // ServerSend implements pb.MasterServer. func (s *server) ServerSend(sender pb.Master_ServerSendServer) error { ctx := context.Background() - logger.Logger(ctx).Infof("server get a client connected") var done chan bool for { @@ -154,3 +154,7 @@ func (s *server) PushClientStreamLog(sender pb.Master_PushClientStreamLogServer) func (s *server) PushServerStreamLog(sender pb.Master_PushServerStreamLogServer) error { return streamlog.PushServerStreamLog(sender) } + +func (s *server) PTYConnect(sender pb.Master_PTYConnectServer) error { + return shell.PTYConnect(sender) +} diff --git a/utils/pty/interface.go b/utils/pty/interface.go new file mode 100644 index 0000000..3711efb --- /dev/null +++ b/utils/pty/interface.go @@ -0,0 +1,9 @@ +package pty + +type PTYInterface interface { + Write(p []byte) (n int, err error) + Read(p []byte) (n int, err error) + Getsize() (uint16, uint16, error) + Setsize(cols, rows uint32) error + Close() error +} diff --git a/utils/pty/pty_other.go b/utils/pty/pty_other.go new file mode 100644 index 0000000..f150872 --- /dev/null +++ b/utils/pty/pty_other.go @@ -0,0 +1,83 @@ +//go:build !windows + +package pty + +import ( + "errors" + "os" + "os/exec" + "syscall" + + opty "github.com/creack/pty" +) + +var _ PTYInterface = (*Pty)(nil) + +var defaultShells = []string{"fish", "zsh", "bash", "sh"} + +type Pty struct { + tty *os.File + cmd *exec.Cmd +} + +func DownloadDependency() error { + return nil +} + +func Start() (PTYInterface, error) { + var shellPath string + for i := 0; i < len(defaultShells); i++ { + shellPath, _ = exec.LookPath(defaultShells[i]) + if shellPath != "" { + break + } + } + if shellPath == "" { + return nil, errors.New("none of the default shells was found") + } + cmd := exec.Command(shellPath) + cmd.Env = append(os.Environ(), "TERM=xterm") + tty, err := opty.Start(cmd) + return &Pty{tty: tty, cmd: cmd}, err +} + +func (pty *Pty) Write(p []byte) (n int, err error) { + return pty.tty.Write(p) +} + +func (pty *Pty) Read(p []byte) (n int, err error) { + return pty.tty.Read(p) +} + +func (pty *Pty) Getsize() (uint16, uint16, error) { + ws, err := opty.GetsizeFull(pty.tty) + if err != nil { + return 0, 0, err + } + return ws.Cols, ws.Rows, nil +} + +func (pty *Pty) Setsize(cols, rows uint32) error { + return opty.Setsize(pty.tty, &opty.Winsize{ + Cols: uint16(cols), + Rows: uint16(rows), + }) +} + +func (pty *Pty) killChildProcess(c *exec.Cmd) error { + pgid, err := syscall.Getpgid(c.Process.Pid) + if err != nil { + // Fall-back on error. Kill the main process only. + c.Process.Kill() + } + // Kill the whole process group. + syscall.Kill(-pgid, syscall.SIGKILL) // SIGKILL 直接杀掉 SIGTERM 发送信号,等待进程自己退出 + return c.Wait() +} + +func (pty *Pty) Close() error { + if err := pty.tty.Close(); err != nil { + return err + } + return pty.killChildProcess(pty.cmd) +} diff --git a/utils/pty/pty_windows_amd64.go b/utils/pty/pty_windows_amd64.go new file mode 100644 index 0000000..c2bf39a --- /dev/null +++ b/utils/pty/pty_windows_amd64.go @@ -0,0 +1,120 @@ +//go:build windows && !arm64 + +package pty + +import ( + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + + "github.com/UserExistsError/conpty" + "github.com/iamacarpet/go-winpty" + "github.com/shirou/gopsutil/v4/host" +) + +var _ PTYInterface = (*winPTY)(nil) +var _ PTYInterface = (*conPty)(nil) + +var isWin10 = IsWindows10() + +type winPTY struct { + tty *winpty.WinPTY +} + +type conPty struct { + tty *conpty.ConPty +} + +func IsWindows10() bool { + hi, err := host.Info() + if err != nil { + return false + } + + re := regexp.MustCompile(`Build (\d+(\.\d+)?)`) + match := re.FindStringSubmatch(hi.KernelVersion) + if len(match) > 1 { + versionStr := match[1] + + version, err := strconv.ParseFloat(versionStr, 64) + if err != nil { + return false + } + + return version >= 17763 + } + return false +} + +func getExecutableFilePath() (string, error) { + ex, err := os.Executable() + if err != nil { + return "", err + } + return filepath.Dir(ex), nil +} + +func Start() (PTYInterface, error) { + shellPath, err := exec.LookPath("powershell.exe") + if err != nil || shellPath == "" { + shellPath = "cmd.exe" + } + path, err := getExecutableFilePath() + if err != nil { + return nil, err + } + if !isWin10 { + tty, err := winpty.OpenDefault(path, shellPath) + return &winPTY{tty: tty}, err + } + tty, err := conpty.Start(shellPath, conpty.ConPtyWorkDir(path)) + return &conPty{tty: tty}, err +} + +func (w *winPTY) Write(p []byte) (n int, err error) { + return w.tty.StdIn.Write(p) +} + +func (w *winPTY) Read(p []byte) (n int, err error) { + return w.tty.StdOut.Read(p) +} + +func (w *winPTY) Getsize() (uint16, uint16, error) { + return 80, 40, nil +} + +func (w *winPTY) Setsize(cols, rows uint32) error { + w.tty.SetSize(cols, rows) + return nil +} + +func (w *winPTY) Close() error { + w.tty.Close() + return nil +} + +func (c *conPty) Write(p []byte) (n int, err error) { + return c.tty.Write(p) +} + +func (c *conPty) Read(p []byte) (n int, err error) { + return c.tty.Read(p) +} + +func (c *conPty) Getsize() (uint16, uint16, error) { + return 80, 40, nil +} + +func (c *conPty) Setsize(cols, rows uint32) error { + c.tty.Resize(int(cols), int(rows)) + return nil +} + +func (c *conPty) Close() error { + if err := c.tty.Close(); err != nil { + return err + } + return nil +} diff --git a/utils/pty/pty_windows_arm64.go b/utils/pty/pty_windows_arm64.go new file mode 100644 index 0000000..8562f85 --- /dev/null +++ b/utils/pty/pty_windows_arm64.go @@ -0,0 +1,65 @@ +//go:build windows && arm64 + +package pty + +import ( + "os" + "os/exec" + "path/filepath" + + "github.com/UserExistsError/conpty" +) + +var _ PTYInterface = (*Pty)(nil) + +type Pty struct { + tty *conpty.ConPty +} + +func DownloadDependency() error { + return nil +} + +func getExecutableFilePath() (string, error) { + ex, err := os.Executable() + if err != nil { + return "", err + } + return filepath.Dir(ex), nil +} + +func Start() (PTYInterface, error) { + shellPath, err := exec.LookPath("powershell.exe") + if err != nil || shellPath == "" { + shellPath = "cmd.exe" + } + path, err := getExecutableFilePath() + if err != nil { + return nil, err + } + tty, err := conpty.Start(shellPath, conpty.ConPtyWorkDir(path)) + return &Pty{tty: tty}, err +} + +func (pty *Pty) Write(p []byte) (n int, err error) { + return pty.tty.Write(p) +} + +func (pty *Pty) Read(p []byte) (n int, err error) { + return pty.tty.Read(p) +} + +func (pty *Pty) Getsize() (uint16, uint16, error) { + return 80, 40, nil +} + +func (pty *Pty) Setsize(cols, rows uint32) error { + return pty.tty.Resize(int(cols), int(rows)) +} + +func (pty *Pty) Close() error { + if err := pty.tty.Close(); err != nil { + return err + } + return nil +} diff --git a/utils/system_service.go b/utils/system_service.go new file mode 100644 index 0000000..af83e2d --- /dev/null +++ b/utils/system_service.go @@ -0,0 +1,109 @@ +package utils + +import ( + "fmt" + "io" + "os" + "path" + "path/filepath" + + "github.com/kardianos/service" + "github.com/sirupsen/logrus" +) + +type SystemService struct { + run func() + service.Service +} + +func (ss *SystemService) Start(s service.Service) error { + go ss.iRun() + return nil +} + +func (ss *SystemService) Stop(s service.Service) error { return nil } + +func (ss *SystemService) iRun() { + defer func() { + if service.Interactive() { + ss.Stop(ss.Service) + } else { + ss.Service.Stop() + } + }() + ss.run() +} + +func CreateSystemService(args []string, run func()) (service.Service, error) { + currentPath, err := os.Executable() + if err != nil { + return nil, fmt.Errorf("get current path failed, err: %v", err) + } + + svcConfig := &service.Config{ + Name: "frpp", + DisplayName: "frp-panel", + Description: "this is frp-panel service, developed by [VaalaCat] - https://github.com/VaalaCat/frp-panel", + Arguments: args, + WorkingDirectory: path.Dir(currentPath), + } + + ss := &SystemService{ + run: run, + } + + s, err := service.New(ss, svcConfig) + if err != nil { + return nil, fmt.Errorf("service New failed, err: %v", err) + } + return s, nil +} + +func ControlSystemService(args []string, action string, run func()) error { + logrus.Info("try to ", action, " service, args:", args) + s, err := CreateSystemService(args, run) + if err != nil { + logrus.WithError(err).Error("create service controller failed") + return err + } + + if err := service.Control(s, action); err != nil { + logrus.WithError(err).Errorf("controller %v service failed", action) + return err + } + logrus.Infof("controller %v service success", action) + return nil +} + +func InstallToSystemPath(installPath string) error { + currentPath, err := os.Executable() + if err != nil { + return err + } + + targetPath := path.Join(installPath, filepath.Base(currentPath)) + + src, err := os.Open(currentPath) + if err != nil { + return err + } + defer src.Close() + + dst, err := os.Create(targetPath) + if err != nil { + return err + } + defer dst.Close() + + _, err = io.Copy(dst, src) + if err != nil { + return err + } + + err = os.Chmod(targetPath, 0755) + if err != nil { + return err + } + + return nil +} diff --git a/www/api/http.ts b/www/api/http.ts index 58da775..8dc617b 100644 --- a/www/api/http.ts +++ b/www/api/http.ts @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_TOKEN_KEY, SET_TOKEN_HEADER, X_CLIENT_REQUEST_ID } from '@/lib/consts' +import { SET_TOKEN_HEADER, X_CLIENT_REQUEST_ID } from '@/lib/consts' import { $token } from '@/store/user' import axios from 'axios' import { v4 as uuidv4 } from 'uuid' @@ -6,10 +6,9 @@ import { v4 as uuidv4 } from 'uuid' const instance = axios.create({}) instance.interceptors.request.use((request) => { - let token = 'Bearer ' + localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY) + let token = 'Bearer ' + $token.get() if (token) { request.headers.Authorization = token - $token.set(token) } request.headers[X_CLIENT_REQUEST_ID] = uuidv4() return request @@ -17,7 +16,6 @@ instance.interceptors.request.use((request) => { instance.interceptors.response.use((response) => { if (response.headers?.[SET_TOKEN_HEADER]) { - localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, response.headers[SET_TOKEN_HEADER]) $token.set(response.headers[SET_TOKEN_HEADER]) } if (response.data.code != 200) { diff --git a/www/components/app-sidebar.tsx b/www/components/app-sidebar.tsx index 25e48bb..50bf6d1 100644 --- a/www/components/app-sidebar.tsx +++ b/www/components/app-sidebar.tsx @@ -1,13 +1,11 @@ import * as React from "react" import { - MessagesSquare, SquareTerminal, ServerCogIcon, ServerIcon, MonitorSmartphoneIcon, MonitorCogIcon, ChartNetworkIcon, - icons, Scroll, } from "lucide-react" @@ -22,11 +20,13 @@ import { SidebarMenuButton, SidebarRail, } from "@/components/ui/sidebar" -import { $userInfo } from "@/store/user" +import { $platformInfo, $userInfo } from "@/store/user" import { useStore } from "@nanostores/react" import { TbBuildingTunnel } from "react-icons/tb" import { RegisterAndLogin } from "./header" import { useRouter } from "next/navigation" +import { useQuery } from "@tanstack/react-query" +import { getPlatformInfo } from "@/api/platform" const data = { teams: [ @@ -68,7 +68,12 @@ const data = { title: "实时日志", url: "/streamlog", icon: Scroll, - } + }, + { + title: "控制台", + url: "/console", + icon: SquareTerminal, + }, ] } @@ -80,6 +85,15 @@ export interface AppSidebarProps extends React.ComponentProps { export function AppSidebar({ ...props }: AppSidebarProps) { const router = useRouter() const userInfo = useStore($userInfo) + const { data: platformInfo } = useQuery({ + queryKey: ['platformInfo'], + queryFn: getPlatformInfo, + }) + + React.useEffect(() => { + $platformInfo.set(platformInfo) + }, [platformInfo]) + return ( diff --git a/www/components/base/client_detail.tsx b/www/components/base/client_detail.tsx new file mode 100644 index 0000000..7cdf703 --- /dev/null +++ b/www/components/base/client_detail.tsx @@ -0,0 +1,43 @@ +import { Popover, PopoverTrigger } from "@radix-ui/react-popover" +import { Badge } from "../ui/badge" +import { ClientStatus } from "@/lib/pb/api_master" +import { PopoverContent } from "../ui/popover" + +export const ClientDetail = ({ clientStatus }: { clientStatus: ClientStatus }) => { + return ( + + + + {clientStatus.version?.gitVersion} + + + +

客户端信息

+
+ 版本: + {clientStatus.version?.gitVersion} +
+
+ 编译时间: + {clientStatus.version?.buildDate} +
+
+ Go版本: + {clientStatus.version?.goVersion} +
+
+ 客户端平台: + {clientStatus.version?.platform} +
+
+ 客户端地址: + {clientStatus.addr} +
+
+ 连接时间: + {clientStatus.connectTime} +
+
+
+ ) +} \ No newline at end of file diff --git a/www/components/base/data_table.tsx b/www/components/base/data_table.tsx index 38e803a..0835a09 100644 --- a/www/components/base/data_table.tsx +++ b/www/components/base/data_table.tsx @@ -43,7 +43,7 @@ export function DataTable({ columns, filterColumnName, table }: D {table.getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => { return ( diff --git a/www/components/base/read-write-xterm.tsx b/www/components/base/read-write-xterm.tsx new file mode 100644 index 0000000..ec4ceb7 --- /dev/null +++ b/www/components/base/read-write-xterm.tsx @@ -0,0 +1,162 @@ +"use client" +import { ClientStatus } from '@/lib/pb/api_master' +import { terminalWebsocketUrl } from '@/lib/terminal' +import { FitAddon } from '@xterm/addon-fit' +import { useEffect, useState } from 'react' +import { useXTerm } from 'react-xtermjs' + +export interface TerminalComponentProps { + isLoading: boolean + clientStatus?: ClientStatus + reset: number + setStatus: (status: "loading" | "success" | "error" | undefined) => void +} + +const TerminalComponent = ({ isLoading, clientStatus, reset, setStatus }: TerminalComponentProps) => { + const { instance: terminal, ref } = useXTerm() + const fitAddon = new FitAddon() + + useEffect(() => { + if (terminal) { + terminal.reset() + } + }, [reset, ref, terminal]) + + useEffect(() => { + terminal?.loadAddon(fitAddon) + const handleResize = () => fitAddon.fit() + + fitAddon.fit() + fitAddon.fit() + window.addEventListener('resize', handleResize) + return () => { + window.removeEventListener('resize', handleResize) + } + }, [ref, terminal]) + + useEffect(() => { + if (!terminal) { + return; + } + + // The terminal should be cleared on each reconnect + // because all data is re-rendered from the backend. + terminal.clear(); + + // Focusing on connection allows users to reload the page and start + // typing immediately. + terminal.focus(); + + // Disable input while we connect. + terminal.options.disableStdin = true; + + // Show a message if we failed to find the workspace or agent. + if (isLoading) { + return; + } + + if (!clientStatus) { + terminal.writeln( + `no client found with ID, is the program started?`, + ); + setStatus("error"); + return; + } + + // Hook up terminal events to the websocket. + let websocket: WebSocket | null; + const disposers = [ + terminal.onData((data) => { + websocket?.send( + new TextEncoder().encode(JSON.stringify({ data: data })), + ); + }), + terminal.onResize((event) => { + websocket?.send( + new TextEncoder().encode( + JSON.stringify({ + height: event.rows, + width: event.cols, + }), + ), + ); + }), + ]; + + let disposed = false; + + // Open the web socket and hook it up to the terminal. + terminalWebsocketUrl( + clientStatus.clientId, + terminal.rows, + terminal.cols, + ) + .then((url) => { + if (disposed) { + return; // Unmounted while we waited for the async call. + } + websocket = new WebSocket(url); + websocket.binaryType = "arraybuffer"; + websocket.addEventListener("open", () => { + // Now that we are connected, allow user input. + terminal.options = { + disableStdin: false, + windowsMode: clientStatus.version?.platform.includes("windows"), + }; + // Send the initial size. + websocket?.send( + new TextEncoder().encode( + JSON.stringify({ + height: terminal.rows, + width: terminal.cols, + }), + ), + ); + }); + websocket.addEventListener("error", () => { + terminal.options.disableStdin = true; + terminal.writeln( + `socket errored`, + ); + setStatus("error"); + }); + websocket.addEventListener("close", () => { + terminal.options.disableStdin = true; + setStatus(undefined); + }); + websocket.addEventListener("message", (event) => { + if (typeof event.data === "string") { + // This exclusively occurs when testing. + // "jest-websocket-mock" doesn't support ArrayBuffer. + terminal.write(event.data); + } else { + terminal.write(new Uint8Array(event.data)); + } + setStatus("success"); + }); + }) + .catch((error) => { + setStatus("error"); + if (disposed) { + return; // Unmounted while we waited for the async call. + } + terminal.writeln(error.message); + }); + + return () => { + disposed = true; // Could use AbortController instead? + for (const d of disposers) { + d.dispose(); + } + websocket?.close(1000); + }; + }, [ + terminal, + isLoading, + setStatus, + ]); + + return
+} + +export default TerminalComponent \ No newline at end of file diff --git a/www/components/base/xterm.tsx b/www/components/base/readonly-xterm.tsx similarity index 92% rename from www/components/base/xterm.tsx rename to www/components/base/readonly-xterm.tsx index 72e7c20..d39e307 100644 --- a/www/components/base/xterm.tsx +++ b/www/components/base/readonly-xterm.tsx @@ -3,7 +3,7 @@ import { FitAddon } from '@xterm/addon-fit' import { useEffect, useState } from 'react' import { useXTerm } from 'react-xtermjs' -const TerminalComponent = ({ logs, reset }: { logs: string, reset: number }) => { +const LogTerminalComponent = ({ logs, reset }: { logs: string, reset: number }) => { const { instance, ref } = useXTerm() const fitAddon = new FitAddon() const [prevLogs, setPrevLogs] = useState('') @@ -57,4 +57,4 @@ const TerminalComponent = ({ logs, reset }: { logs: string, reset: number }) => return
} -export default TerminalComponent \ No newline at end of file +export default LogTerminalComponent \ No newline at end of file diff --git a/www/components/frpc/client_create_dialog.tsx b/www/components/frpc/client_create_dialog.tsx index e84e115..ddc17de 100644 --- a/www/components/frpc/client_create_dialog.tsx +++ b/www/components/frpc/client_create_dialog.tsx @@ -18,18 +18,12 @@ import { } from '@/components/ui/dialog' import { useTranslation } from 'react-i18next' -export const CreateClientDialog = () => { +export const CreateClientDialog = ({refetchTrigger}: {refetchTrigger?: (randStr: string) => void}) => { const { t } = useTranslation() const [clientID, setClientID] = useState() const newClient = useMutation({ mutationFn: initClient, }) - const dataQuery = useQuery({ - queryKey: ['listClient', { pageIndex: 0, pageSize: 10 }], - queryFn: async () => { - return await listClient({ page: 1, pageSize: 10 }) - }, - }) const { toast } = useToast() const handleNewClient = async () => { @@ -41,7 +35,7 @@ export const CreateClientDialog = () => { return } toast({ title: t('创建客户端成功') }) - dataQuery.refetch() + refetchTrigger && refetchTrigger(JSON.stringify(Math.random())) } catch (error) { toast({ title: t('创建客户端失败') }) } diff --git a/www/components/frpc/client_item.tsx b/www/components/frpc/client_item.tsx index c70b13f..99d0c6c 100644 --- a/www/components/frpc/client_item.tsx +++ b/www/components/frpc/client_item.tsx @@ -33,6 +33,9 @@ import { getClientsStatus } from '@/api/platform' import { ClientType } from '@/lib/pb/common' import { ClientStatus, ClientStatus_Status } from '@/lib/pb/api_master' import { startFrpc, stopFrpc } from '@/api/frp' +import { Badge } from '../ui/badge' +import { ClientDetail } from '../base/client_detail' +import { Input } from '../ui/input' export type ClientTableSchema = { id: string @@ -70,7 +73,7 @@ export const columns: ColumnDef[] = [ }, { accessorKey: 'info', - header: '运行信息', + header: '运行信息/版本信息', cell: ({ row }) => { const client = row.original return @@ -100,15 +103,19 @@ export const ClientID = ({ client }: { client: ClientTableSchema }) => {
{client.id}
- + +
请点击命令框全选复制
Linux安装到systemd
-
- {platformInfo === undefined ? '获取平台信息失败' : LinuxInstallCommand('client', client, platformInfo)} -
+
Windows安装到系统服务
-
- {platformInfo === undefined ? "获取平台信息失败" : WindowsInstallCommand("client", client, platformInfo)} -
+ +
) @@ -148,8 +155,13 @@ export const ClientInfo = ({ client }: { client: ClientTableSchema }) => { client.stopped ? 'text-yellow-500' : 'text-green-500') : 'text-red-500' return ( -
- {`${clientsInfo.data?.clients[client.id].ping}ms, ${trans(clientsInfo.data?.clients[client.id])}`} +
+ + {`${clientsInfo.data?.clients[client.id].ping}ms,${trans(clientsInfo.data?.clients[client.id])}`} + + {clientsInfo.data?.clients[client.id].version && + + }
) } @@ -174,7 +186,7 @@ export const ClientSecret = ({ client }: { client: ClientTableSchema }) => {
运行命令(需要点击这里自行下载文件)
-
+
{platformInfo === undefined ? '获取平台信息失败' : ExecCommandStr('client', client, platformInfo)}
@@ -191,26 +203,14 @@ export const ClientActions: React.FC = ({ client, table }) => { const { toast } = useToast() const router = useRouter() const platformInfo = useStore($platformInfo) - const fetchDataOptions = { - pageIndex: table.getState().pagination.pageIndex, - pageSize: table.getState().pagination.pageSize, - } - const dataQuery = useQuery({ - queryKey: ['listClient', fetchDataOptions], - queryFn: async () => { - return await listClient({ - page: fetchDataOptions.pageIndex + 1, - pageSize: fetchDataOptions.pageSize, - }) - }, - }) + const refetchList = () => {} const removeClient = useMutation({ mutationFn: deleteClient, onSuccess: () => { toast({ description: '删除成功' }) - dataQuery.refetch() + refetchList() }, onError: () => { toast({ description: '删除失败' }) @@ -221,7 +221,7 @@ export const ClientActions: React.FC = ({ client, table }) => { mutationFn: stopFrpc, onSuccess: () => { toast({ description: '停止成功' }) - dataQuery.refetch() + refetchList() }, onError: () => { toast({ description: '停止失败' }) @@ -232,7 +232,7 @@ export const ClientActions: React.FC = ({ client, table }) => { mutationFn: startFrpc, onSuccess: () => { toast({ description: '启动成功' }) - dataQuery.refetch() + refetchList() }, onError: () => { toast({ description: '启动失败' }) diff --git a/www/components/frps/server_create_dialog.tsx b/www/components/frps/server_create_dialog.tsx index 2b14acf..0b73afc 100644 --- a/www/components/frps/server_create_dialog.tsx +++ b/www/components/frps/server_create_dialog.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' -import { useMutation, useQuery } from '@tanstack/react-query' -import { initServer, listServer } from '@/api/server' +import { useMutation } from '@tanstack/react-query' +import { initServer } from '@/api/server' import { Label } from '@/components/ui/label' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' @@ -16,18 +16,9 @@ import { DialogTrigger, } from '@/components/ui/dialog' -export const CreateServerDialog = () => { +export const CreateServerDialog = ({refetchTrigger}: {refetchTrigger?: (randStr: string) => void}) => { const [serverID, setServerID] = useState() const [serverIP, setServerIP] = useState() - const dataQuery = useQuery({ - queryKey: ['listServer', { pageIndex: 0, pageSize: 10 }], - queryFn: async () => { - return await listServer({ - page: 1, - pageSize: 10, - }) - }, - }) const newServer = useMutation({ mutationFn: initServer, }) @@ -42,7 +33,7 @@ export const CreateServerDialog = () => { return } toast({ title: '创建服务端成功' }) - dataQuery.refetch() + refetchTrigger && refetchTrigger(JSON.stringify(Math.random())) } catch (error) { toast({ title: '创建服务端失败' }) } diff --git a/www/components/frps/server_item.tsx b/www/components/frps/server_item.tsx index 7175858..50724f0 100644 --- a/www/components/frps/server_item.tsx +++ b/www/components/frps/server_item.tsx @@ -33,6 +33,8 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover import { getClientsStatus } from '@/api/platform' import { ClientType } from '@/lib/pb/common' import { ClientStatus, ClientStatus_Status } from '@/lib/pb/api_master' +import { Badge } from '../ui/badge' +import { ClientDetail } from '../base/client_detail' export type ServerTableSchema = { id: string @@ -70,7 +72,7 @@ export const columns: ColumnDef[] = [ }, { accessorKey: 'info', - header: '运行信息', + header: '运行信息/版本信息', cell: ({ row }) => { const Server = row.original return @@ -152,8 +154,13 @@ export const ServerInfo = ({ server }: { server: ServerTableSchema }) => { clientsInfo.data?.clients[server.id]?.status === ClientStatus_Status.ONLINE ? 'text-green-500' : 'text-red-500' return ( -
- {`${clientsInfo.data?.clients[server.id].ping}ms, ${trans(clientsInfo.data?.clients[server.id])}`} +
+ + {`${clientsInfo.data?.clients[server.id].ping}ms,${trans(clientsInfo.data?.clients[server.id])}`} + + {clientsInfo.data?.clients[server.id].version && + + }
) } @@ -179,7 +186,7 @@ export const ServerSecret = ({ server }: { server: ServerTableSchema }) => {
运行命令(需要点击这里自行下载文件)
-
+
{platformInfo === undefined ? '获取平台信息失败' : ExecCommandStr('server', server, platformInfo)}
@@ -197,25 +204,13 @@ export const ServerActions: React.FC = ({ server, table }) => { const router = useRouter() const platformInfo = useStore($platformInfo) - const fetchDataOptions = { - pageIndex: table.getState().pagination.pageIndex, - pageSize: table.getState().pagination.pageSize, - } + const refetchList = () => {} - const dataQuery = useQuery({ - queryKey: ['listServer', fetchDataOptions], - queryFn: async () => { - return await listServer({ - page: fetchDataOptions.pageIndex + 1, - pageSize: fetchDataOptions.pageSize, - }) - }, - }) const removeServer = useMutation({ mutationFn: deleteServer, onSuccess: () => { toast({ description: '删除成功' }) - dataQuery.refetch() + refetchList() }, onError: () => { toast({ description: '删除失败' }) diff --git a/www/components/nav-user.tsx b/www/components/nav-user.tsx index 801a9bc..19f306e 100644 --- a/www/components/nav-user.tsx +++ b/www/components/nav-user.tsx @@ -22,8 +22,7 @@ import { import { User } from '@/lib/pb/common' import { Avatar } from "./ui/avatar" import { UserAvatar } from "./base/avatar" -import { LOCAL_STORAGE_TOKEN_KEY } from "@/lib/consts" -import { $userInfo } from "@/store/user" +import { $token, $userInfo } from "@/store/user" import { logout } from "@/api/auth" export function NavUser({ @@ -74,7 +73,7 @@ export function NavUser({
{ $userInfo.set(undefined) - localStorage.removeItem(LOCAL_STORAGE_TOKEN_KEY) + $token.set(undefined) await logout() window.location.reload() } diff --git a/www/lib/pb/api_master.ts b/www/lib/pb/api_master.ts index ad71ed9..a096249 100644 --- a/www/lib/pb/api_master.ts +++ b/www/lib/pb/api_master.ts @@ -32,6 +32,18 @@ export interface ClientStatus { * @generated from protobuf field: int32 ping = 4; */ ping: number; // 单位为毫秒 + /** + * @generated from protobuf field: optional api_master.ClientVersion version = 5; + */ + version?: ClientVersion; + /** + * @generated from protobuf field: optional string addr = 6; + */ + addr?: string; + /** + * @generated from protobuf field: optional int32 connect_time = 7; + */ + connectTime?: number; // 连接建立的时间 } /** * @generated from protobuf enum api_master.ClientStatus.Status @@ -54,6 +66,35 @@ export enum ClientStatus_Status { */ ERROR = 3 } +/** + * @generated from protobuf message api_master.ClientVersion + */ +export interface ClientVersion { + /** + * @generated from protobuf field: string GitVersion = 1 [json_name = "GitVersion"]; + */ + gitVersion: string; + /** + * @generated from protobuf field: string GitCommit = 2 [json_name = "GitCommit"]; + */ + gitCommit: string; + /** + * @generated from protobuf field: string BuildDate = 3 [json_name = "BuildDate"]; + */ + buildDate: string; + /** + * @generated from protobuf field: string GoVersion = 4 [json_name = "GoVersion"]; + */ + goVersion: string; + /** + * @generated from protobuf field: string Compiler = 5 [json_name = "Compiler"]; + */ + compiler: string; + /** + * @generated from protobuf field: string Platform = 6 [json_name = "Platform"]; + */ + platform: string; +} /** * @generated from protobuf message api_master.GetClientsStatusRequest */ @@ -119,7 +160,10 @@ class ClientStatus$Type extends MessageType { { no: 1, name: "client_type", kind: "enum", T: () => ["common.ClientType", ClientType, "CLIENT_TYPE_"] }, { no: 2, name: "client_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 3, name: "status", kind: "enum", T: () => ["api_master.ClientStatus.Status", ClientStatus_Status, "STATUS_"] }, - { no: 4, name: "ping", kind: "scalar", T: 5 /*ScalarType.INT32*/ } + { no: 4, name: "ping", kind: "scalar", T: 5 /*ScalarType.INT32*/ }, + { no: 5, name: "version", kind: "message", T: () => ClientVersion }, + { no: 6, name: "addr", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "connect_time", kind: "scalar", opt: true, T: 5 /*ScalarType.INT32*/ } ]); } create(value?: PartialMessage): ClientStatus { @@ -149,6 +193,15 @@ class ClientStatus$Type extends MessageType { case /* int32 ping */ 4: message.ping = reader.int32(); break; + case /* optional api_master.ClientVersion version */ 5: + message.version = ClientVersion.internalBinaryRead(reader, reader.uint32(), options, message.version); + break; + case /* optional string addr */ 6: + message.addr = reader.string(); + break; + case /* optional int32 connect_time */ 7: + message.connectTime = reader.int32(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -173,6 +226,15 @@ class ClientStatus$Type extends MessageType { /* int32 ping = 4; */ if (message.ping !== 0) writer.tag(4, WireType.Varint).int32(message.ping); + /* optional api_master.ClientVersion version = 5; */ + if (message.version) + ClientVersion.internalBinaryWrite(message.version, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* optional string addr = 6; */ + if (message.addr !== undefined) + writer.tag(6, WireType.LengthDelimited).string(message.addr); + /* optional int32 connect_time = 7; */ + if (message.connectTime !== undefined) + writer.tag(7, WireType.Varint).int32(message.connectTime); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -184,6 +246,93 @@ class ClientStatus$Type extends MessageType { */ export const ClientStatus = new ClientStatus$Type(); // @generated message type with reflection information, may provide speed optimized methods +class ClientVersion$Type extends MessageType { + constructor() { + super("api_master.ClientVersion", [ + { no: 1, name: "GitVersion", kind: "scalar", jsonName: "GitVersion", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "GitCommit", kind: "scalar", jsonName: "GitCommit", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "BuildDate", kind: "scalar", jsonName: "BuildDate", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "GoVersion", kind: "scalar", jsonName: "GoVersion", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "Compiler", kind: "scalar", jsonName: "Compiler", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "Platform", kind: "scalar", jsonName: "Platform", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ClientVersion { + const message = globalThis.Object.create((this.messagePrototype!)); + message.gitVersion = ""; + message.gitCommit = ""; + message.buildDate = ""; + message.goVersion = ""; + message.compiler = ""; + message.platform = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ClientVersion): ClientVersion { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string GitVersion = 1 [json_name = "GitVersion"];*/ 1: + message.gitVersion = reader.string(); + break; + case /* string GitCommit = 2 [json_name = "GitCommit"];*/ 2: + message.gitCommit = reader.string(); + break; + case /* string BuildDate = 3 [json_name = "BuildDate"];*/ 3: + message.buildDate = reader.string(); + break; + case /* string GoVersion = 4 [json_name = "GoVersion"];*/ 4: + message.goVersion = reader.string(); + break; + case /* string Compiler = 5 [json_name = "Compiler"];*/ 5: + message.compiler = reader.string(); + break; + case /* string Platform = 6 [json_name = "Platform"];*/ 6: + message.platform = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ClientVersion, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string GitVersion = 1 [json_name = "GitVersion"]; */ + if (message.gitVersion !== "") + writer.tag(1, WireType.LengthDelimited).string(message.gitVersion); + /* string GitCommit = 2 [json_name = "GitCommit"]; */ + if (message.gitCommit !== "") + writer.tag(2, WireType.LengthDelimited).string(message.gitCommit); + /* string BuildDate = 3 [json_name = "BuildDate"]; */ + if (message.buildDate !== "") + writer.tag(3, WireType.LengthDelimited).string(message.buildDate); + /* string GoVersion = 4 [json_name = "GoVersion"]; */ + if (message.goVersion !== "") + writer.tag(4, WireType.LengthDelimited).string(message.goVersion); + /* string Compiler = 5 [json_name = "Compiler"]; */ + if (message.compiler !== "") + writer.tag(5, WireType.LengthDelimited).string(message.compiler); + /* string Platform = 6 [json_name = "Platform"]; */ + if (message.platform !== "") + writer.tag(6, WireType.LengthDelimited).string(message.platform); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message api_master.ClientVersion + */ +export const ClientVersion = new ClientVersion$Type(); +// @generated message type with reflection information, may provide speed optimized methods class GetClientsStatusRequest$Type extends MessageType { constructor() { super("api_master.GetClientsStatusRequest", [ diff --git a/www/lib/pb/common.ts b/www/lib/pb/common.ts index f0d76d2..ca8eafa 100644 --- a/www/lib/pb/common.ts +++ b/www/lib/pb/common.ts @@ -27,6 +27,10 @@ export interface Status { * @generated from protobuf message common.CommonRequest */ export interface CommonRequest { + /** + * @generated from protobuf field: optional string data = 1; + */ + data?: string; } /** * @generated from protobuf message common.CommonResponse @@ -36,6 +40,10 @@ export interface CommonResponse { * @generated from protobuf field: optional common.Status status = 1; */ status?: Status; + /** + * @generated from protobuf field: optional string data = 2; + */ + data?: string; } /** * @generated from protobuf message common.Client @@ -277,7 +285,9 @@ export const Status = new Status$Type(); // @generated message type with reflection information, may provide speed optimized methods class CommonRequest$Type extends MessageType { constructor() { - super("common.CommonRequest", []); + super("common.CommonRequest", [ + { no: 1, name: "data", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); } create(value?: PartialMessage): CommonRequest { const message = globalThis.Object.create((this.messagePrototype!)); @@ -286,9 +296,28 @@ class CommonRequest$Type extends MessageType { return message; } internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CommonRequest): CommonRequest { - return target ?? this.create(); + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* optional string data */ 1: + message.data = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; } internalBinaryWrite(message: CommonRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* optional string data = 1; */ + if (message.data !== undefined) + writer.tag(1, WireType.LengthDelimited).string(message.data); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); @@ -303,7 +332,8 @@ export const CommonRequest = new CommonRequest$Type(); class CommonResponse$Type extends MessageType { constructor() { super("common.CommonResponse", [ - { no: 1, name: "status", kind: "message", T: () => Status } + { no: 1, name: "status", kind: "message", T: () => Status }, + { no: 2, name: "data", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } ]); } create(value?: PartialMessage): CommonResponse { @@ -320,6 +350,9 @@ class CommonResponse$Type extends MessageType { case /* optional common.Status status */ 1: message.status = Status.internalBinaryRead(reader, reader.uint32(), options, message.status); break; + case /* optional string data */ 2: + message.data = reader.string(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -335,6 +368,9 @@ class CommonResponse$Type extends MessageType { /* optional common.Status status = 1; */ if (message.status) Status.internalBinaryWrite(message.status, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* optional string data = 2; */ + if (message.data !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.data); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/www/lib/terminal.ts b/www/lib/terminal.ts new file mode 100644 index 0000000..268d176 --- /dev/null +++ b/www/lib/terminal.ts @@ -0,0 +1,20 @@ +export const terminalWebsocketUrl = async ( + clientID: string, + height: number, + width: number, +): Promise => { + const query = new URLSearchParams(); + query.set("height", height.toString()); + query.set("width", width.toString()); + + const url = new URL(`${location.protocol}//${location.host}`); + url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; + if (!url.pathname.endsWith("/")) { + `${url.pathname}/`; + } + url.pathname += `api/v1/pty/${clientID}`; + url.search = `?${query.toString()}`; + + url.search = `?${query.toString()}`; + return url.toString(); +}; diff --git a/www/package.json b/www/package.json index 743e370..41288a5 100644 --- a/www/package.json +++ b/www/package.json @@ -11,6 +11,7 @@ "dependencies": { "@hookform/resolvers": "^3.3.4", "@ltd/j-toml": "^1.38.0", + "@nanostores/persistent": "^0.10.2", "@nanostores/react": "^0.7.1", "@protobuf-ts/plugin": "^2.9.3", "@protobuf-ts/runtime": "^2.9.3", diff --git a/www/pages/clients.tsx b/www/pages/clients.tsx index 247c01f..69b6032 100644 --- a/www/pages/clients.tsx +++ b/www/pages/clients.tsx @@ -16,7 +16,7 @@ export default function ClientListPage() {
- +
diff --git a/www/pages/console.tsx b/www/pages/console.tsx new file mode 100644 index 0000000..1c56553 --- /dev/null +++ b/www/pages/console.tsx @@ -0,0 +1,98 @@ +import { Providers } from '@/components/providers' +import { RootLayout } from '@/components/layout' +import { Header } from '@/components/header' +import { useEffect, useState } from 'react' +import { ClientSelector } from '@/components/base/client-selector' +import { Button } from '@/components/ui/button' +import { getClientsStatus } from '@/api/platform' +import { ClientType } from '@/lib/pb/common' +import dynamic from 'next/dynamic' +import { BaseSelector } from '@/components/base/selector' +import { ServerSelector } from '@/components/base/server-selector' +import LoadingCircle from '@/components/base/status' +import { ClientStatus } from '@/lib/pb/api_master' + +const TerminalComponentProps = dynamic(() => import('@/components/base/read-write-xterm'), { + ssr: false +}) + +export default function ClientStatsPage() { + const [clientID, setClientID] = useState(undefined) + const [clear, setClear] = useState(0) + const [enabled, setEnabled] = useState(false) + const [timeoutID, setTimeoutID] = useState(null); + const [clientType, setClientType] = useState(ClientType.FRPC) + const [status, setStatus] = useState<"loading" | "success" | "error" | undefined>() + + useEffect(() => { + setClientID(undefined) + }, [clientType]) + + useEffect(() => { + setClear(Math.random()) + setStatus(undefined) + if (!clientID) { + return; + } + if (!enabled) { + return; + } + const abortController = new AbortController(); + setStatus("loading"); + + return () => { + abortController.abort("unmount"); + setEnabled(false); + }; + }, [clientID, enabled]); + + return ( + + }> +
+
+
+
+ +
+ + + + { if (value === ClientType.FRPC.toString()) { setClientType(ClientType.FRPC) } else { setClientType(ClientType.FRPS) } }} + value={clientType.toString()} + label="客户端类型" + /> +
+ {clientType === ClientType.FRPC && } + {clientType === ClientType.FRPS && } +
+ +
+
+
+
+
+ ) +} diff --git a/www/pages/servers.tsx b/www/pages/servers.tsx index 66cd1c2..29dea4a 100644 --- a/www/pages/servers.tsx +++ b/www/pages/servers.tsx @@ -16,7 +16,7 @@ export default function ServerListPage() {
- +
diff --git a/www/pages/streamlog.tsx b/www/pages/streamlog.tsx index e0569ff..d717f7f 100644 --- a/www/pages/streamlog.tsx +++ b/www/pages/streamlog.tsx @@ -12,7 +12,7 @@ import { BaseSelector } from '@/components/base/selector' import { ServerSelector } from '@/components/base/server-selector' import LoadingCircle from '@/components/base/status' -const TerminalComponent = dynamic(() => import('@/components/base/xterm'), { +const LogTerminalComponent = dynamic(() => import('@/components/base/readonly-xterm'), { ssr: false }) @@ -97,7 +97,7 @@ export default function ClientStatsPage() { {clientType === ClientType.FRPC && } {clientType === ClientType.FRPS && }
- +
diff --git a/www/pnpm-lock.yaml b/www/pnpm-lock.yaml index 1899575..0d4e160 100644 --- a/www/pnpm-lock.yaml +++ b/www/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@ltd/j-toml': specifier: ^1.38.0 version: 1.38.0 + '@nanostores/persistent': + specifier: ^0.10.2 + version: 0.10.2(nanostores@0.9.5) '@nanostores/react': specifier: ^0.7.1 version: 0.7.1(nanostores@0.9.5)(react@18.2.0) @@ -278,6 +281,12 @@ packages: '@ltd/j-toml@1.38.0': resolution: {integrity: sha512-lYtBcmvHustHQtg4X7TXUu1Xa/tbLC3p2wLvgQI+fWVySguVZJF60Snxijw5EiohumxZbR10kWYFFebh1zotiw==} + '@nanostores/persistent@0.10.2': + resolution: {integrity: sha512-BEndnLhRC+yP7gXTESepBbSj8XNl8OXK9hu4xAgKC7MWJHKXnEqJMqY47LUyHxK6vYgFnisyHmqq+vq8AUFyIg==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 + '@nanostores/react@0.7.1': resolution: {integrity: sha512-EXQg9N4MdI4eJQz/AZLIx3hxQ6BuBmV4Q55bCd5YCSgEOAW7tGTsIZxpRXxvxLXzflNvHTBvfrDNY38TlSVBkQ==} engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} @@ -2737,6 +2746,10 @@ snapshots: '@ltd/j-toml@1.38.0': {} + '@nanostores/persistent@0.10.2(nanostores@0.9.5)': + dependencies: + nanostores: 0.9.5 + '@nanostores/react@0.7.1(nanostores@0.9.5)(react@18.2.0)': dependencies: nanostores: 0.9.5 diff --git a/www/store/user.ts b/www/store/user.ts index cf8e9ce..dd22806 100644 --- a/www/store/user.ts +++ b/www/store/user.ts @@ -1,8 +1,10 @@ import { GetPlatformInfoResponse } from '@/lib/pb/api_user' import { User } from '@/lib/pb/common' import { atom } from 'nanostores' +import { persistentAtom } from '@nanostores/persistent' +import { LOCAL_STORAGE_TOKEN_KEY } from '@/lib/consts' export const $userInfo = atom() export const $statusOnline = atom(false) -export const $token = atom() +export const $token = persistentAtom(LOCAL_STORAGE_TOKEN_KEY) export const $platformInfo = atom()