feat: release managed service generation and contract diagnostics
This commit is contained in:
18
examples/managedService/internal/apierrors/catalog.go
Normal file
18
examples/managedService/internal/apierrors/catalog.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package apierrors
|
||||
|
||||
import omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
|
||||
func Catalog() omnierrors.Catalog {
|
||||
return omnierrors.Catalog{
|
||||
DefaultStatus: 400,
|
||||
Definitions: map[string]omnierrors.Definition{
|
||||
"INVALID": {Code: 400002, Message: "用户名格式不正确"},
|
||||
"TOO_LONG": {Code: 400003, Message: "{label}不能超过{max}个字符", Params: []omnierrors.Parameter{{Name: "label", Type: "string"}, {Name: "max", Type: "int"}}},
|
||||
"INTERNAL_ERROR": {Status: 500, Code: 9999, Message: "系统错误"},
|
||||
"NOT_FOUND": {Status: 404, Code: 404001, Message: "接口不存在"},
|
||||
"METHOD_NOT_ALLOWED": {Status: 405, Code: 405001, Message: "请求方法不支持"},
|
||||
"BODY_TOO_LARGE": {Status: 413, Code: 413001, Message: "请求体太大"},
|
||||
"INVALID_MULTIPART": {Status: 400, Code: 400004, Message: "上传内容不完整"},
|
||||
},
|
||||
}
|
||||
}
|
||||
69
examples/managedService/internal/config/config.go
Normal file
69
examples/managedService/internal/config/config.go
Normal file
@@ -0,0 +1,69 @@
|
||||
// Package settings owns this project's configuration; it adds no business identity model.
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/config"
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server config.Config `json:"server"`
|
||||
}
|
||||
|
||||
func Default() Config {
|
||||
server := config.Default()
|
||||
server.Address = "127.0.0.1:8080"
|
||||
server.EnableLogger = true
|
||||
server.SlowRequestThreshold = 500 * time.Millisecond
|
||||
server.Log.Service = "example.com/managed"
|
||||
server.Log.Format = "json"
|
||||
server.Log.Output = "stderr"
|
||||
return Config{Server: server}
|
||||
}
|
||||
|
||||
// Load uses defaults -> strict YAML/JSON -> nonempty environment variables.
|
||||
// Pass an empty path to use only defaults and environment.
|
||||
func Load(path string) (Config, error) {
|
||||
cfg := Default()
|
||||
var err error
|
||||
if path != "" {
|
||||
cfg, err = config.DecodeFile(path, cfg)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
}
|
||||
cfg.Server, err = config.ApplyEnv(cfg.Server, "")
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
// A stream explicitly selected by environment overrides a file profile.
|
||||
if output := strings.TrimSpace(os.Getenv("GO_OMNI_LOG_OUTPUT")); output != "" && strings.TrimSpace(os.Getenv("GO_OMNI_LOG_FILE")) == "" {
|
||||
cfg.Server.Log.File = ""
|
||||
cfg.Server.Log.Rotation = logx.RotationConfig{}
|
||||
}
|
||||
|
||||
if err = cfg.Validate(); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
func (c Config) Validate() error {
|
||||
|
||||
if err := c.Server.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Server.Log.Format != "json" && c.Server.Log.Format != "text" {
|
||||
return errors.New("log.format must be json or text")
|
||||
}
|
||||
switch strings.ToLower(c.Server.Log.Level) {
|
||||
case "debug", "info", "warn", "warning", "error":
|
||||
default:
|
||||
return errors.New("invalid log.level")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
36
examples/managedService/internal/handler/appGen.go
Normal file
36
examples/managedService/internal/handler/appGen.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
|
||||
"example.com/managed/internal/svc"
|
||||
)
|
||||
|
||||
// NewApp is generated HTTP composition. The caller owns deps and its logger.
|
||||
func NewApp(deps *svc.ServiceContext) (*omni.App, error) {
|
||||
if deps == nil || deps.Health == nil {
|
||||
return nil, fmt.Errorf("service context and health checker required")
|
||||
}
|
||||
cfg := deps.Config.Server
|
||||
for _, option := range deps.AppOptions() {
|
||||
if option != nil {
|
||||
option(&cfg)
|
||||
}
|
||||
}
|
||||
cfg.Response = newResponseTemplate("{\"body\":null,\"errorBody\":null,\"messageField\":\"msg\",\"requestIdField\":\"-\",\"codeType\":\"int32\",\"successCode\":0,\"errorCode\":9999,\"dataMode\":\"always\"}").Config()
|
||||
cfg.ResponseEncoder = nil
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app := omni.New(omni.WithConfig(cfg))
|
||||
app.Use(deps.GlobalMiddleware()...)
|
||||
if err := RegisterRoutes(app, deps); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app.GET("/openapi.json", OpenAPI)
|
||||
app.GET("/health/live", deps.Health.LivenessHandler())
|
||||
app.GET("/health/ready", deps.Health.ReadinessHandler())
|
||||
return app, nil
|
||||
}
|
||||
134
examples/managedService/internal/handler/demo/handlersGen.go
Normal file
134
examples/managedService/internal/handler/demo/handlersGen.go
Normal file
@@ -0,0 +1,134 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"example.com/managed/internal/svc"
|
||||
"example.com/managed/internal/types"
|
||||
"fmt"
|
||||
"git.yuntuo.hk/k2safe/go-omni/contract"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
)
|
||||
|
||||
type Logic interface {
|
||||
Check(ctx context.Context, req *types.CheckReq) (*types.Receipt, error)
|
||||
Other(ctx context.Context, req *types.CheckReq) (*types.Receipt, error)
|
||||
RawJSON(ctx context.Context) (*types.Receipt, error)
|
||||
Upload(ctx context.Context, body *httpx.Body) (*types.Receipt, error)
|
||||
Callback(ctx context.Context, body *httpx.Body) (*httpx.Stream, error)
|
||||
Download(ctx context.Context) (*httpx.Stream, error)
|
||||
Slow(ctx context.Context) (*types.Receipt, error)
|
||||
}
|
||||
type Handler struct {
|
||||
logic Logic
|
||||
deps *svc.ServiceContext
|
||||
}
|
||||
|
||||
func New(s Logic, deps ...*svc.ServiceContext) *Handler {
|
||||
h := &Handler{logic: s}
|
||||
if len(deps) > 0 {
|
||||
h.deps = deps[0]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
var checkRequest = contract.MustNew[types.CheckReq]()
|
||||
|
||||
func (h *Handler) Check(c *httpx.Context) error {
|
||||
var req types.CheckReq
|
||||
if err := checkRequest.Bind(c.Request(), httpx.RouteParams(c.Context()), &req); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := h.logic.Check(c.Context(), &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("Check returned a nil response")
|
||||
}
|
||||
return c.OK(resp)
|
||||
}
|
||||
|
||||
var otherRequest = contract.MustNew[types.CheckReq]()
|
||||
|
||||
func (h *Handler) Other(c *httpx.Context) error {
|
||||
var req types.CheckReq
|
||||
if err := otherRequest.Bind(c.Request(), httpx.RouteParams(c.Context()), &req); err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := h.logic.Other(c.Context(), &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("Other returned a nil response")
|
||||
}
|
||||
return c.OK(resp)
|
||||
}
|
||||
func (h *Handler) RawJSON(c *httpx.Context) error {
|
||||
resp, err := h.logic.RawJSON(c.Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("RawJSON returned a nil response")
|
||||
}
|
||||
return c.OK(resp)
|
||||
}
|
||||
func (h *Handler) Upload(c *httpx.Context) error {
|
||||
body, err := httpx.NewBody(c.Request(), "multipart")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := h.logic.Upload(c.Context(), body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("Upload returned a nil response")
|
||||
}
|
||||
if err := body.Complete(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.OK(resp)
|
||||
}
|
||||
func (h *Handler) Callback(c *httpx.Context) error {
|
||||
body, err := httpx.NewBody(c.Request(), "raw")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := h.logic.Callback(c.Context(), body)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
_ = resp.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := body.Complete(); err != nil {
|
||||
if resp != nil {
|
||||
_ = resp.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return c.WriteStream(200, "text/plain", resp)
|
||||
}
|
||||
func (h *Handler) Download(c *httpx.Context) error {
|
||||
resp, err := h.logic.Download(c.Context())
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
_ = resp.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
return c.WriteStream(200, "application/octet-stream", resp)
|
||||
}
|
||||
func (h *Handler) Slow(c *httpx.Context) error {
|
||||
resp, err := h.logic.Slow(c.Context())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp == nil {
|
||||
return fmt.Errorf("Slow returned a nil response")
|
||||
}
|
||||
return c.OK(resp)
|
||||
}
|
||||
13
examples/managedService/internal/handler/openapiGen.go
Normal file
13
examples/managedService/internal/handler/openapiGen.go
Normal file
File diff suppressed because one or more lines are too long
41
examples/managedService/internal/handler/responseGen.go
Normal file
41
examples/managedService/internal/handler/responseGen.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"git.yuntuo.hk/k2safe/go-omni/response"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var responseTemplates = map[string]response.Encoder{"": response.Default(),
|
||||
"CommonResponse": newResponseTemplate("{\"body\":null,\"errorBody\":null,\"messageField\":\"msg\",\"requestIdField\":\"-\",\"codeType\":\"int32\",\"successCode\":0,\"errorCode\":9999,\"dataMode\":\"always\"}"),
|
||||
"AlternateResponse": newResponseTemplate("{\"body\":null,\"errorBody\":null,\"messageField\":\"detail\",\"requestIdField\":\"-\",\"codeType\":\"int32\",\"successCode\":0,\"errorCode\":9999,\"dataMode\":\"always\"}"),
|
||||
}
|
||||
|
||||
func newResponseTemplate(raw string) *response.Formatter {
|
||||
var cfg response.Config
|
||||
decoder := json.NewDecoder(strings.NewReader(raw))
|
||||
decoder.UseNumber()
|
||||
if err := decoder.Decode(&cfg); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return response.MustNew(cfg)
|
||||
}
|
||||
func responseEncoder(name string, raw bool, catalogJSON string) response.Encoder {
|
||||
encoder := responseTemplates[name]
|
||||
if encoder == nil {
|
||||
panic("unknown response template")
|
||||
}
|
||||
var catalog omnierrors.Catalog
|
||||
if err := json.Unmarshal([]byte(catalogJSON), &catalog); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(catalog.Definitions) > 0 {
|
||||
encoder = response.MustWithErrors(catalog, encoder)
|
||||
}
|
||||
if raw {
|
||||
encoder = response.RawJSON(encoder)
|
||||
}
|
||||
return encoder
|
||||
}
|
||||
26
examples/managedService/internal/handler/routesGen.go
Normal file
26
examples/managedService/internal/handler/routesGen.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package handler
|
||||
|
||||
import (
|
||||
h0 "example.com/managed/internal/handler/demo"
|
||||
s0 "example.com/managed/internal/logic/demo"
|
||||
"example.com/managed/internal/svc"
|
||||
"fmt"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/openapi"
|
||||
)
|
||||
|
||||
func RegisterRoutes(router openapi.Registrar, deps *svc.ServiceContext) error {
|
||||
if router == nil || deps == nil {
|
||||
return fmt.Errorf("router and dependencies required")
|
||||
}
|
||||
h0 := h0.New(s0.New(deps), deps)
|
||||
httpx.HandleWithResponse(router, "GET", "/check", responseEncoder("CommonResponse", false, "{\"definitions\":{}}"), h0.Check)
|
||||
httpx.HandleWithResponse(router, "GET", "/other", responseEncoder("AlternateResponse", false, "{\"definitions\":{}}"), h0.Other)
|
||||
httpx.HandleWithResponse(router, "GET", "/raw", responseEncoder("CommonResponse", true, "{\"definitions\":{}}"), h0.RawJSON)
|
||||
httpx.HandleWithBodyLimit(router, "POST", "/upload", 2048, responseEncoder("CommonResponse", false, "{\"definitions\":{}}"), h0.Upload)
|
||||
httpx.HandleWithBodyLimit(router, "POST", "/callback", 64, responseEncoder("CommonResponse", false, "{\"definitions\":{}}"), h0.Callback)
|
||||
httpx.HandleWithResponse(router, "GET", "/download", responseEncoder("CommonResponse", false, "{\"definitions\":{}}"), h0.Download)
|
||||
httpx.HandleWithResponse(router, "GET", "/slow", responseEncoder("CommonResponse", false, "{\"definitions\":{}}"), h0.Slow)
|
||||
return nil
|
||||
}
|
||||
22
examples/managedService/internal/logic/demo/callback.go
Normal file
22
examples/managedService/internal/logic/demo/callback.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (l *Logic) Callback(ctx context.Context, body *httpx.Body) (*httpx.Stream, error) {
|
||||
// The route's 64-byte limit bounds this example's memory use. A real signature
|
||||
// implementation can hash body.Raw incrementally and authenticate its headers.
|
||||
data, err := io.ReadAll(body.Raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if body.Header.Get("X-Signature") != "valid" {
|
||||
return nil, omnierrors.ByCode("INVALID")
|
||||
}
|
||||
return &httpx.Stream{Content: io.NopCloser(strings.NewReader("ACK:" + string(data)))}, nil
|
||||
}
|
||||
20
examples/managedService/internal/logic/demo/check.go
Normal file
20
examples/managedService/internal/logic/demo/check.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"example.com/managed/internal/types"
|
||||
omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
)
|
||||
|
||||
func (l *Logic) Check(ctx context.Context, req *types.CheckReq) (*types.Receipt, error) {
|
||||
switch req.Kind {
|
||||
case "fixed":
|
||||
return nil, omnierrors.ByCode("INVALID")
|
||||
case "params":
|
||||
return nil, omnierrors.ByCode("TOO_LONG").WithParams(map[string]any{"label": "企业名称", "max": 100})
|
||||
case "unknown":
|
||||
return nil, omnierrors.ByCode("UNKNOWN").WithCause(errors.New("private cause"))
|
||||
}
|
||||
return &types.Receipt{Bytes: 42}, nil
|
||||
}
|
||||
12
examples/managedService/internal/logic/demo/download.go
Normal file
12
examples/managedService/internal/logic/demo/download.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (l *Logic) Download(context.Context) (*httpx.Stream, error) {
|
||||
return &httpx.Stream{Content: io.NopCloser(strings.NewReader("file-content")), Name: "example.txt"}, nil
|
||||
}
|
||||
7
examples/managedService/internal/logic/demo/logic.go
Normal file
7
examples/managedService/internal/logic/demo/logic.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package demo
|
||||
|
||||
import "example.com/managed/internal/svc"
|
||||
|
||||
type Logic struct{ deps *svc.ServiceContext }
|
||||
|
||||
func New(deps *svc.ServiceContext) *Logic { return &Logic{deps: deps} }
|
||||
10
examples/managedService/internal/logic/demo/other.go
Normal file
10
examples/managedService/internal/logic/demo/other.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"example.com/managed/internal/types"
|
||||
)
|
||||
|
||||
func (l *Logic) Other(ctx context.Context, req *types.CheckReq) (*types.Receipt, error) {
|
||||
return l.Check(ctx, req)
|
||||
}
|
||||
10
examples/managedService/internal/logic/demo/rawJSON.go
Normal file
10
examples/managedService/internal/logic/demo/rawJSON.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"example.com/managed/internal/types"
|
||||
)
|
||||
|
||||
func (l *Logic) RawJSON(context.Context) (*types.Receipt, error) {
|
||||
return &types.Receipt{Bytes: 3}, nil
|
||||
}
|
||||
16
examples/managedService/internal/logic/demo/slow.go
Normal file
16
examples/managedService/internal/logic/demo/slow.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"example.com/managed/internal/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (l *Logic) Slow(ctx context.Context) (*types.Receipt, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
return &types.Receipt{Bytes: 1}, nil
|
||||
}
|
||||
}
|
||||
31
examples/managedService/internal/logic/demo/upload.go
Normal file
31
examples/managedService/internal/logic/demo/upload.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"example.com/managed/internal/types"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"io"
|
||||
)
|
||||
|
||||
func (l *Logic) Upload(ctx context.Context, body *httpx.Body) (*types.Receipt, error) {
|
||||
var total int64
|
||||
for {
|
||||
part, err := body.Parts.NextPart()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, err := io.Copy(io.Discard, part)
|
||||
closeErr := part.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if closeErr != nil {
|
||||
return nil, closeErr
|
||||
}
|
||||
total += n
|
||||
}
|
||||
return &types.Receipt{Bytes: total}, nil
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package middleware
|
||||
|
||||
import "git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
|
||||
func Defaults() map[string]httpx.Middleware {
|
||||
return map[string]httpx.Middleware{}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Package demo owns persistence contracts for this business group.
|
||||
// Define repository interfaces and implementations here; HTTP DTOs do not
|
||||
// determine a database schema. This file is never overwritten.
|
||||
package demo
|
||||
36
examples/managedService/internal/svc/close.go
Normal file
36
examples/managedService/internal/svc/close.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package svc
|
||||
|
||||
import "errors"
|
||||
|
||||
// Close is idempotent, including startup failure and graceful shutdown.
|
||||
func (c *ServiceContext) Close() error {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
c.closeOnce.Do(func() {
|
||||
c.closeMu.Lock()
|
||||
c.closed = true
|
||||
cleanups := c.cleanups
|
||||
c.cleanups = nil
|
||||
c.closeMu.Unlock()
|
||||
for i := len(cleanups) - 1; i >= 0; i-- {
|
||||
c.closeErr = errors.Join(c.closeErr, cleanups[i]())
|
||||
}
|
||||
|
||||
})
|
||||
return c.closeErr
|
||||
}
|
||||
|
||||
// OnClose transfers a resource cleanup to this context immediately after creation.
|
||||
// Hooks run once in reverse order, also when later initialization fails.
|
||||
func (c *ServiceContext) OnClose(cleanup func() error) {
|
||||
if cleanup == nil {
|
||||
return
|
||||
}
|
||||
c.closeMu.Lock()
|
||||
defer c.closeMu.Unlock()
|
||||
if c.closed {
|
||||
panic("svc: register cleanup after Close")
|
||||
}
|
||||
c.cleanups = append(c.cleanups, cleanup)
|
||||
}
|
||||
24
examples/managedService/internal/svc/options.go
Normal file
24
examples/managedService/internal/svc/options.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"example.com/managed/internal/apierrors"
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
)
|
||||
|
||||
func (c *ServiceContext) AppOptions() []omni.Option {
|
||||
return []omni.Option{omni.WithErrors(apierrors.Catalog())}
|
||||
}
|
||||
func (c *ServiceContext) GlobalMiddleware() []httpx.Middleware {
|
||||
return []httpx.Middleware{
|
||||
func(next httpx.Handler) httpx.Handler {
|
||||
return func(c *httpx.Context) error {
|
||||
if c.Header("X-Fail") != "" {
|
||||
return omnierrors.ByCode("INVALID")
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
59
examples/managedService/internal/svc/serviceContext.go
Normal file
59
examples/managedService/internal/svc/serviceContext.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"example.com/managed/internal/config"
|
||||
"example.com/managed/internal/middleware"
|
||||
"git.yuntuo.hk/k2safe/go-omni/health"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
)
|
||||
|
||||
// Context owns infrastructure, while Logger is borrowed from main.
|
||||
// Add business repositories here; HTTP contracts do not define database tables.
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
cleanups []func() error
|
||||
Logger *logx.Logger
|
||||
Health *health.Checker
|
||||
Middlewares map[string]httpx.Middleware
|
||||
|
||||
closeMu sync.Mutex
|
||||
closed bool
|
||||
closeOnce sync.Once
|
||||
closeErr error
|
||||
}
|
||||
|
||||
// Pass the settings loaded by main. The optional form supports lightweight
|
||||
// tests without infrastructure; selected adapters still require valid config.
|
||||
func New(ctx context.Context, logger *logx.Logger, configs ...config.Config) (result *ServiceContext, err error) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if err = ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(configs) > 1 {
|
||||
return nil, errors.New("expected at most one configuration")
|
||||
}
|
||||
cfg := config.Default()
|
||||
if len(configs) == 1 {
|
||||
cfg = configs[0]
|
||||
}
|
||||
_ = cfg
|
||||
checker, err := health.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &ServiceContext{Config: cfg, Logger: logger, Health: checker, Middlewares: middleware.Defaults()}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
err = errors.Join(err, c.Close())
|
||||
}
|
||||
}()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
9
examples/managedService/internal/types/typesGen.go
Normal file
9
examples/managedService/internal/types/typesGen.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Code generated by go-omni api. DO NOT EDIT.
|
||||
package types
|
||||
|
||||
type CheckReq struct {
|
||||
Kind string `form:"kind,optional"`
|
||||
}
|
||||
type Receipt struct {
|
||||
Bytes int64 `json:"bytes"`
|
||||
}
|
||||
Reference in New Issue
Block a user