{"id":36894880,"url":"https://github.com/kelein/mixsamples","last_synced_at":"2026-01-12T15:41:14.286Z","repository":{"id":217990778,"uuid":"745301245","full_name":"kelein/mixsamples","owner":"kelein","description":"samples for mixgo project","archived":false,"fork":false,"pushed_at":"2024-01-19T04:02:22.000Z","size":120,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-20T00:27:18.436Z","etag":null,"topics":["api","cli","gorm","grpc","mix","mix-go","mixgo","xorm"],"latest_commit_sha":null,"homepage":"https://github.com/kelein/mixsamples","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kelein.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-19T03:18:31.000Z","updated_at":"2024-01-19T04:03:26.000Z","dependencies_parsed_at":"2024-01-19T04:28:07.351Z","dependency_job_id":"165613d3-eb4a-48b5-b22d-451d913b945a","html_url":"https://github.com/kelein/mixsamples","commit_stats":null,"previous_names":["kelein/mixsamples"],"tags_count":0,"template":false,"template_full_name":"urans/my-clean-arch","purl":"pkg:github/kelein/mixsamples","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelein%2Fmixsamples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelein%2Fmixsamples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelein%2Fmixsamples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelein%2Fmixsamples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kelein","download_url":"https://codeload.github.com/kelein/mixsamples/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kelein%2Fmixsamples/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28341282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","cli","gorm","grpc","mix","mix-go","mixgo","xorm"],"created_at":"2026-01-12T15:41:14.130Z","updated_at":"2026-01-12T15:41:14.268Z","avatar_url":"https://github.com/kelein.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## gRPC development skeleton\n\n帮助你快速搭建项目骨架，并指导你如何使用该骨架的细节。\n\n## Installation\n\n- Install\n\n~~~\ngo install -u github.com/mix-go/mixcli\n~~~\n\n- New project\n\n~~~\nmixcli new hello\n~~~\n\n~~~\n Use the arrow keys to navigate: ↓ ↑ → ←\n ? Select project type:\n     CLI\n     API\n     Web (contains the websocket)\n   ▸ gRPC\n ~~~\n\n## 编写一个 gRPC 服务、客户端\n\n首先我们使用 `mixcli` 命令创建一个项目骨架：\n\n~~~\n$ mixcli new hello\n~~~\n\n生成骨架目录结构如下：\n\n~~~\n.\n├── README.md\n├── bin\n├── commands\n├── conf\n├── config\n├── di\n├── go.mod\n├── go.sum\n├── main.go\n├── protos\n├── runtime\n└── services\n~~~\n\n`main.go` 文件：\n\n- `xcli.AddCommand` 方法传入的 `commands.Commands` 定义了全部的命令\n\n~~~go\npackage main\n\nimport (\n\t\"github.com/mix-go/xutil/xenv\"\n\t\"mixcogs/commands\"\n\t_ \"mixcogs/configor\"\n\t_ \"mixcogs/di\"\n\t_ \"mixcogs/dotenv\"\n\t\"github.com/mix-go/xcli\"\n)\n\nfunc main() {\n\txcli.SetName(\"app\").\n\t\tSetVersion(\"0.0.0-alpha\").\n\t\tSetDebug(xenv.Getenv(\"APP_DEBUG\").Bool(false))\n\txcli.AddCommand(commands.Commands...).Run()\n}\n~~~\n\n`commands/main.go` 文件：\n\n我们可以在这里自定义命令，[查看更多](https://github.com/mix-go/xcli)\n\n- 定义了 `grpc:server`、`grpc:client` 两个子命令\n- `RunI` 指定了命令执行的接口，也可以使用 `RunF` 设定一个匿名函数\n\n```go\npackage commands\n\nimport (\n\t\"github.com/mix-go/xcli\"\n)\n\nvar Commands = []*xcli.Command{\n\t{\n\t\tName:  \"grpc:server\",\n\t\tShort: \"gRPC server demo\",\n\t\tOptions: []*xcli.Option{\n\t\t\t{\n\t\t\t\tNames: []string{\"d\", \"daemon\"},\n\t\t\t\tUsage: \"Run in the background\",\n\t\t\t},\n\t\t},\n\t\tRunI: \u0026GrpcServerCommand{},\n\t},\n\t{\n\t\tName:  \"grpc:client\",\n\t\tShort: \"gRPC client demo\",\n\t\tRunI:  \u0026GrpcClientCommand{},\n\t},\n}\n```\n\n`protos/user.proto` 数据结构文件：\n\n客户端与服务器端代码中都需要使用 `.proto` 生成的 go 代码，因为双方需要使用该数据结构通讯\n\n- `.proto` 是 [gRPC](https://github.com/grpc/grpc) 通信的数据结构文件，采用 [protobuf](https://github.com/protocolbuffers/protobuf) 协议\n\n~~~\nsyntax = \"proto3\";\n\npackage go.micro.grpc.user;\noption go_package = \"./;protos\";\n\nservice User {\n    rpc Add(AddRequest) returns (AddResponse) {}\n}\n\nmessage AddRequest {\n    string Name = 1;\n}\n\nmessage AddResponse {\n    int32 error_code = 1;\n    string error_message = 2;\n    int64 user_id = 3;\n}\n~~~\n\n然后我们需要安装 gRPC 相关的编译程序：\n\n- https://www.cnblogs.com/oolo/p/11840305.html#%E5%AE%89%E8%A3%85-grpc\n\n接下来我们开始编译 `.proto` 文件：\n\n- 编译成功后会在当前目录生成 `protos/user.pb.go` 文件\n\n~~~\ncd protos\nprotoc --go_out=plugins=grpc:. user.proto\n~~~\n\n`commands/server.go` 文件：\n\n服务端代码写在 `GrpcServerCommand` 结构体的 `main` 方法中，生成的代码中已经包含了：\n\n- 监听信号停止服务\n- 可选的后台守护执行\n- `pb.RegisterUserServer` 注册了一个默认服务，用户只需要扩展自己的服务即可\n\n~~~go\npackage commands\n\nimport (\n\t\"github.com/mix-go/xutil/xenv\"\n\t\"mixcogs/di\"\n\tpb \"mixcogs/protos\"\n\t\"mixcogs/services\"\n\t\"github.com/mix-go/xcli/flag\"\n\t\"github.com/mix-go/xcli/process\"\n\t\"google.golang.org/grpc\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n)\n\nvar netListener net.Listener\n\ntype GrpcServerCommand struct {\n}\n\nfunc (t *GrpcServerCommand) Main() {\n\tif flag.Match(\"d\", \"daemon\").Bool() {\n\t\tprocess.Daemon()\n\t}\n\n\taddr := xenv.Getenv(\"GIN_ADDR\").String(\":8080\")\n\tlogger := di.Zap()\n\n\t// listen\n\tlistener, err := net.Listen(\"tcp\", addr)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tnetListener = listener\n\n\t// signal\n\tch := make(chan os.Signal)\n\tsignal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)\n\tgo func() {\n\t\t\u003c-ch\n\t\tlogger.Info(\"Server shutdown\")\n\t\tif err := listener.Close(); err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\n\t// server\n\ts := grpc.NewServer()\n\tpb.RegisterUserServer(s, \u0026services.UserService{})\n\n\t// run\n\twelcome()\n\tlogger.Infof(\"Server run %s\", addr)\n\tif err := s.Serve(listener); err != nil \u0026\u0026 !strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\tpanic(err)\n\t}\n}\n~~~\n\n`services/user.go` 文件：\n\n服务端代码中注册的 `services.UserService{}` 服务代码如下：\n\n只需要填充业务逻辑即可\n\n```go\npackage services\n\nimport (\n\t\"context\"\n\tpb \"mixcogs/protos\"\n)\n\ntype UserService struct {\n}\n\nfunc (t *UserService) Add(ctx context.Context, in *pb.AddRequest) (*pb.AddResponse, error) {\n\t// 执行数据库操作\n\t// ...\n\n\tresp := pb.AddResponse{\n\t\tErrorCode:    0,\n\t\tErrorMessage: \"\",\n\t\tUserId:       10001,\n\t}\n\treturn \u0026resp, nil\n}\n```\n\n`commands/client.go` 文件：\n\n客户端代码写在 `GrpcClientCommand` 结构体的 `main` 方法中，生成的代码中已经包含了：\n\n- 通过环境配置获取服务端连接地址\n- 设定了 `5s` 的执行超时时间\n\n~~~go\npackage commands\n\nimport (\n    \"context\"\n    \"fmt\"\n\t\"github.com/mix-go/xutil/xenv\"\n\tpb \"mixcogs/protos\"\n    \"google.golang.org/grpc\"\n    \"time\"\n)\n\ntype GrpcClientCommand struct {\n}\n\nfunc (t *GrpcClientCommand) Main() {\n    addr := xenv.Getenv(\"GIN_ADDR\").String(\":8080\")\n    ctx, _ := context.WithTimeout(context.Background(), time.Duration(5)*time.Second)\n    conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithBlock())\n    if err != nil {\n        panic(err)\n    }\n    defer func() {\n        _ = conn.Close()\n    }()\n    cli := pb.NewUserClient(conn)\n    req := pb.AddRequest{\n        Name: \"xiaoliu\",\n    }\n    resp, err := cli.Add(ctx, \u0026req)\n    if err != nil {\n        panic(err)\n    }\n    fmt.Println(fmt.Sprintf(\"Add User: %d\", resp.UserId))\n}\n~~~\n\n接下来我们编译上面的程序：\n\n- linux \u0026 macOS\n\n~~~\ngo build -o bin/go_build_main_go main.go\n~~~\n\n- win\n\n~~~\ngo build -o bin/go_build_main_go.exe main.go\n~~~\n\n首先在命令行启动 `grpc:server` 服务器：\n\n~~~\n$ bin/go_build_main_go grpc:server\n             ___\n ______ ___  _ /__ ___ _____ ______\n  / __ `__ \\/ /\\ \\/ /__  __ `/  __ \\\n / / / / / / / /\\ \\/ _  /_/ // /_/ /\n/_/ /_/ /_/_/ /_/\\_\\  \\__, / \\____/\n                     /____/\n\n\nServer      Name:      mix-grpc\nSystem      Name:      darwin\nGo          Version:   1.13.4\nListen      Addr:      :8080\ntime=2020-11-09 15:08:17.544 level=info msg=Server run :8080 file=server.go:46\n~~~\n\n然后开启一个新的终端，执行下面的客户端命令与上面的服务器通信\n\n~~~\n$ bin/go_build_main_go grpc:client\nAdd User: 10001\n~~~\n\n## 如何使用 DI 容器中的 Logger、Database、Redis 等组件\n\n项目中要使用的公共组件，都定义在 `di` 目录，框架默认生成了一些常用的组件，用户也可以定义自己的组件，[查看更多](https://github.com/mix-go/xdi)\n\n- 可以在哪里使用\n\n可以在代码的任意位置使用，但是为了可以使用到环境变量和自定义配置，通常我们在 `xcli.Command` 结构体定义的 `RunF`、`RunI` 中使用。\n\n- 使用日志，比如：[zap](https://github.com/uber-go/zap)、[logrus](https://github.com/Sirupsen/logrus)\n\n```go\nlogger := di.Zap()\nlogger.Info(\"test\")\n```\n\n- 使用数据库，比如：[gorm](https://gorm.io/)、[xorm](https://xorm.io/)\n\n```go\ndb := di.Gorm()\nuser := User{Name: \"Jinzhu\", Age: 18, Birthday: time.Now()}\nresult := db.Create(\u0026user)\nfmt.Println(result)\n```\n\n- 使用 Redis，比如：[go-redis](https://redis.uptrace.dev/)\n\n```go\nrdb := di.GoRedis()\nval, err := rdb.Get(context.Background(), \"key\").Result()\nif err != nil {\npanic(err)\n}\nfmt.Println(\"key\", val)\n```\n\n## 部署\n\n线上部署时，不需要部署源码到服务器，只需要部署编译好的二进制、配置文件等\n\n```\n├── bin\n├── conf\n├── runtime\n├── shell\n└── .env\n```\n\n修改 `shell/server.sh` 脚本中的绝对路径和参数\n\n```\nfile=/project/bin/program\ncmd=grpc:server\n```\n\n启动管理\n\n```\nsh shell/server.sh start\nsh shell/server.sh stop\nsh shell/server.sh restart\n```\n\ngRPC 通常都是内部使用，使用内网 `SLB` 代理到服务器IP或者直接使用 IP:PORT 调用\n\n## License\n\nApache License Version 2.0, http://www.apache.org/licenses/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelein%2Fmixsamples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkelein%2Fmixsamples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkelein%2Fmixsamples/lists"}