{"id":22213957,"url":"https://github.com/xmlking/toolkit","last_synced_at":"2025-07-27T12:31:51.100Z","repository":{"id":38000832,"uuid":"277557598","full_name":"xmlking/toolkit","owner":"xmlking","description":"gRPC, CloudEvents toolkit","archived":false,"fork":false,"pushed_at":"2023-08-08T00:52:13.000Z","size":928,"stargazers_count":4,"open_issues_count":27,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-06-21T20:12:14.812Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/xmlking.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["xmlking"],"open_collective":"xmlking"}},"created_at":"2020-07-06T14:01:42.000Z","updated_at":"2024-01-11T08:11:22.000Z","dependencies_parsed_at":"2024-06-19T11:24:02.301Z","dependency_job_id":"290355db-fd89-4dd6-9c73-6e01759729aa","html_url":"https://github.com/xmlking/toolkit","commit_stats":null,"previous_names":[],"tags_count":146,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmlking%2Ftoolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmlking%2Ftoolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmlking%2Ftoolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xmlking%2Ftoolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xmlking","download_url":"https://codeload.github.com/xmlking/toolkit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227802821,"owners_count":17822113,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-12-02T21:12:43.629Z","updated_at":"2024-12-02T21:12:44.284Z","avatar_url":"https://github.com/xmlking.png","language":"Go","readme":"# toolkit\n\n## Features\n\n- [x] Config\n- [x] Logging\n- [x] Broker\n- [x] Errors\n- [x] Server\n- [x] Middleware\n- [x] Telemetry\n- [ ] Auth\n- [ ] Cache\n- [ ] Crypto\n\n## Usage\n\n\u003cdetails\u003e\n  \u003csummary\u003eUsage Example\u003c/summary\u003e\n\n```go\nfunc main() {\n    serviceName := constants.PLAY_SERVICE\n    cfg := config.GetConfig()\n    efs := config.GetFileSystem()\n    \n    appCtx, stop := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGTERM, syscall.SIGINT, os.Interrupt)\n    defer stop()\n    \n    g, ctx := errgroup.WithContext(appCtx)\n    \n    // Register kuberesolver to grpc.\n    // This line should be before calling registry.NewContainer(cfg)\n    if config.IsProduction() {\n    kuberesolver.RegisterInCluster()\n    }\n    \n    if cfg.Features.Tracing.Enabled {\n    closeFn := tracing.InitTracing(ctx, cfg.Features.Tracing)\n    defer closeFn()\n    }\n    \n    if cfg.Features.Metrics.Enabled {\n    closeFn := metrics.InitMetrics(ctx, cfg.Features.Metrics)\n    defer closeFn()\n    }\n    \n    var unaryInterceptors = []grpc.UnaryServerInterceptor{grpc_validator.UnaryServerInterceptor()}\n    var streamInterceptors = []grpc.StreamServerInterceptor{grpc_validator.StreamServerInterceptor()}\n    \n    if cfg.Features.Tracing.Enabled {\n    unaryInterceptors = append(unaryInterceptors, otelgrpc.UnaryServerInterceptor())\n    streamInterceptors = append(streamInterceptors, otelgrpc.StreamServerInterceptor())\n    }\n    if cfg.Features.Rpclog.Enabled {\n    // keep it last in the interceptor chain\n    unaryInterceptors = append(unaryInterceptors, rpclog.UnaryServerInterceptor())\n    }\n    \n    // ServerOption\n    grpcOps := []grpc.ServerOption{\n    grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)),\n    grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(streamInterceptors...)),\n    }\n    \n    if cfg.Features.TLS.Enabled {\n    tlsConf, err := tls.NewTLSConfig(efs, cfg.Features.TLS.CertFile, cfg.Features.TLS.KeyFile, cfg.Features.TLS.CaFile, cfg.Features.TLS.ServerName, cfg.Features.TLS.Password)\n    if err != nil {\n    log.Fatal().Err(err).Msg(\"failed to create cert\")\n    }\n    serverCert := credentials.NewTLS(tlsConf)\n    grpcOps = append(grpcOps, grpc.Creds(serverCert))\n    }\n    \n    listener, err := endpoint.GetListener(cfg.Services.Play.Endpoint)\n    if err != nil {\n    log.Fatal().Stack().Err(err).Msg(\"error creating listener\")\n    }\n    srv := server.NewServer(appCtx, server.ServerName(serviceName), server.WithListener(listener), server.WithServerOptions(grpcOps...))\n    \n    gSrv := srv.Server()\n    \n    greeterHandler := handler.NewGreeterHandler()\n    // attach the Greeter service to the server\n    greeterv1.RegisterGreeterServiceServer(gSrv, greeterHandler)\n    \n    // Start broker/gRPC daemon services\n    log.Info().Msg(config.GetBuildInfo())\n    log.Info().Msgf(\"Server(%s) starting at: %s, secure: %t, pid: %d\", serviceName, listener.Addr(), cfg.Features.TLS.Enabled, os.Getpid())\n    \n    g.Go(func() error {\n    return srv.Start()\n    })\n    \n    go func() {\n    if err := g.Wait(); err != nil {\n    log.Fatal().Stack().Err(err).Msgf(\"Unexpected error for service: %s\", cfg.Services.Emailer.Endpoint)\n    }\n    log.Info().Msg(\"Goodbye.....\")\n    os.Exit(0)\n    }()\n    \n    // Listen for the interrupt signal.\n    \u003c-appCtx.Done()\n    \n    // notify user of shutdown\n    switch ctx.Err() {\n    case context.DeadlineExceeded:\n    log.Info().Str(\"cause\", \"timeout\").Msg(\"Shutting down gracefully, press Ctrl+C again to force\")\n    case context.Canceled:\n    log.Info().Str(\"cause\", \"interrupt\").Msg(\"Shutting down gracefully, press Ctrl+C again to force\")\n    }\n    \n    // Restore default behavior on the interrupt signal.\n    stop()\n    \n    // Perform application shutdown with a maximum timeout of 1 minute.\n    timeoutCtx, cancel := context.WithTimeout(context.Background(), constants.DefaultShutdownTimeout)\n    defer cancel()\n    \n    // force termination after shutdown timeout\n    \u003c-timeoutCtx.Done()\n    log.Error().Msg(\"Shutdown grace period elapsed. force exit\")\n    // force stop any daemon services here:\n    srv.Stop()\n    os.Exit(1)\n    }\n```\n\n\u003c/details\u003e\n\n## Infra\n\n### PubSub\n\nSource the script needed for next steps\n\n```bash\n. ./scripts/pubsub_functions.sh\n```\n\n#### Start PubSub\n\nStart emulator via gcloud cli\n\n```bash\ngcps\n```\n\nAs alternative, you can also start emulator via docker\n\n```bash\ndocker-compose up pub-sub-emulator\n```\n\n#### Setup PubSub\n\n```bash\ngcpg\n# or \ngcpg tooklit\n# or \ngcpg tooklit dev\n```\n\n#### Tail logs\n\n```bash\n# when using gcloud cli to start emulator\ngcpl\n```\n\n#### Stop PubSub\n\n```bash\n# when using gcloud cli to start emulator\ngcpk\n# or if you are using docker-compose\ndocker-compose up down\n```\n\n## Development\n\n### Maintenance\n\nupdate outdated Go dependencies interactively\n\n```shell\ngo-mod-upgrade\n# then commit the changes. \n```\n\n### Build\n\n```bash\ntask mod:sync\ntask go:lint\ntask go:format\n```\n\n### Test\n\n```bash\n#task go:test\ngo test -v $(go list -f '{{.Dir}}/...' -m | xargs)\n```\n\n### Release\n\nReplace **vx.y.z** with version you try to tag. e.g., **v0.2.5**\n\n1. Start release\n\n    ```shell\n    git switch main\n    task mod:outdated\n    task mod:update\n    # then upgrade recommended versions in each go.mod files\n    ```\n\n2. Update files\n\n    Update  all **go.mod** files that have reference to `github.com/xmlking/toolkit v0.2.5` -\u003e `github.com/xmlking/toolkit vx.y.z`. e.g., \n\n    ```\n    broker/cloudevents/go.mod\n    examples/publish/go.mod\n    examples/subscribe/go.mod\n    ```\n\n3. Update deps\n\n    ```shell\n    go work sync\n    task mod:sync\n    task mod:verify\n    git add .\n    git commit -m \"build(deps): update deps\"\n    ```\n\n4. Finish release\n\n    ```shell\n    cog bump --auto --dry-run \n    cog bump --auto\n    ```\n\n5. Push tags for all modules\n\n    ```shell\n    git switch main\n    task mod:release TAG=vx.y.z\n    git pull --all\n    ```\n\n## 🔗 Credits\n\n- https://github.com/infobloxopen/atlas-app-toolkit/tree/master/server\n- https://github.com/spencer-p/moroncloudevents/tree/master\n\n## Similar Projects\n\n- [Kratos](https://go-kratos.dev/)\n    - [Kratos Docs]( https://go-kratos.dev/en/docs/)\n    - [Kratos Project Template](https://github.com/go-kratos/kratos-layout)\n- [rookie-ninja](https://github.com/rookie-ninja/rk-boot)\n    - [RK Docs](https://rkdev.info/docs/bootstrapper/concept/)\n- [connect-go](https://connect.build/) RPC framework for building gRPC-compatible and browser accessible APIs  \n- [go-zero](https://go-zero.dev/docs/introduction/)\n","funding_links":["https://github.com/sponsors/xmlking","https://opencollective.com/xmlking"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmlking%2Ftoolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxmlking%2Ftoolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxmlking%2Ftoolkit/lists"}