feat: bootstrap reusable GoOmni framework
This commit is contained in:
22
cmd/go-omni/scaffold/templates/README.md.tmpl
Normal file
22
cmd/go-omni/scaffold/templates/README.md.tmpl
Normal file
@@ -0,0 +1,22 @@
|
||||
# GoOmni service
|
||||
|
||||
This service was generated with `go-omni new`.
|
||||
|
||||
```sh
|
||||
go mod tidy
|
||||
go run ./cmd/server
|
||||
```
|
||||
|
||||
运行时配置从 `GO_OMNI_*` 环境变量加载,例如:
|
||||
|
||||
```sh
|
||||
GO_OMNI_ENABLE_LOGGER=true GO_OMNI_LOG_LEVEL=debug go run ./cmd/server
|
||||
```
|
||||
|
||||
`GO_OMNI_HTTP_ADDR` 可以修改监听地址。生成项目默认提供 `/health/live` 和
|
||||
`/health/ready`,日志、请求 ID 和优雅退出等基础能力由 GoOmni 统一初始化;业务依赖集中放在项目自己的 `internal/servicecontext`。
|
||||
|
||||
The generated layout keeps HTTP handlers, business services, repositories,
|
||||
models and a project-owned ServiceContext separate. Replace the memory
|
||||
repository with a database implementation when the service is ready for
|
||||
persistence, then add it to `internal/servicecontext`.
|
||||
49
cmd/go-omni/scaffold/templates/cmd-server-main.go.tmpl
Normal file
49
cmd/go-omni/scaffold/templates/cmd-server-main.go.tmpl
Normal file
@@ -0,0 +1,49 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
"git.yuntuo.hk/k2safe/go-omni/config"
|
||||
"git.yuntuo.hk/k2safe/go-omni/health"
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
"{{.Module}}/internal/handler"
|
||||
"{{.Module}}/internal/repository"
|
||||
"{{.Module}}/internal/service"
|
||||
"{{.Module}}/internal/servicecontext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
settings, err := config.LoadFromEnv("")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if strings.TrimSpace(settings.Log.Service) == "" {
|
||||
settings.Log.Service = "{{.Module}}"
|
||||
}
|
||||
logger, err := logx.New(settings.Log)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Access logs and business logs share the same configured sink.
|
||||
logx.SetDefault(logger)
|
||||
|
||||
users := repository.NewMemoryUsers()
|
||||
services := servicecontext.New(logger, users)
|
||||
userService := service.NewUsers(services)
|
||||
userHandler := handler.NewUsers(userService)
|
||||
checker, err := health.New()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
application := omni.New(omni.WithConfig(settings))
|
||||
application.OnShutdown(logger.Close)
|
||||
application.GET("/health/live", checker.LivenessHandler())
|
||||
application.GET("/health/ready", checker.ReadinessHandler())
|
||||
userHandler.RegisterRoutes(application)
|
||||
if err := application.Run(settings.Address); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
8
cmd/go-omni/scaffold/templates/go.mod.tmpl
Normal file
8
cmd/go-omni/scaffold/templates/go.mod.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
module {{.Module}}
|
||||
|
||||
go 1.22
|
||||
|
||||
require git.yuntuo.hk/k2safe/go-omni v0.0.0
|
||||
{{- if .FrameworkReplace}}
|
||||
replace git.yuntuo.hk/k2safe/go-omni => {{.FrameworkReplace}}
|
||||
{{- end}}
|
||||
31
cmd/go-omni/scaffold/templates/internal-handler-user.go.tmpl
Normal file
31
cmd/go-omni/scaffold/templates/internal-handler-user.go.tmpl
Normal file
@@ -0,0 +1,31 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
"{{.Module}}/internal/model"
|
||||
"{{.Module}}/internal/service"
|
||||
)
|
||||
|
||||
type Users struct {
|
||||
service *service.Users
|
||||
}
|
||||
|
||||
func NewUsers(service *service.Users) *Users { return &Users{service: service} }
|
||||
|
||||
func (h *Users) RegisterRoutes(application *omni.App) {
|
||||
application.POST("/users", h.Create)
|
||||
}
|
||||
|
||||
func (h *Users) Create(ctx *omni.Context) error {
|
||||
var input model.UserInput
|
||||
if err := ctx.BindJSON(&input); err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := h.service.Create(ctx.Context(), input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctx.JSON(http.StatusCreated, user)
|
||||
}
|
||||
16
cmd/go-omni/scaffold/templates/internal-model-user.go.tmpl
Normal file
16
cmd/go-omni/scaffold/templates/internal-model-user.go.tmpl
Normal file
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type UserInput struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"{{.Module}}/internal/model"
|
||||
)
|
||||
|
||||
type UserRepository interface {
|
||||
Create(context.Context, model.UserInput) (model.User, error)
|
||||
}
|
||||
|
||||
type MemoryUsers struct {
|
||||
mu sync.Mutex
|
||||
nextID int64
|
||||
users []model.User
|
||||
}
|
||||
|
||||
func NewMemoryUsers() *MemoryUsers { return &MemoryUsers{nextID: 1} }
|
||||
|
||||
func (r *MemoryUsers) Create(_ context.Context, input model.UserInput) (model.User, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
now := time.Now().UTC()
|
||||
user := model.User{ID: r.nextID, Name: input.Name, Email: input.Email, CreatedAt: now, UpdatedAt: now}
|
||||
r.nextID++
|
||||
r.users = append(r.users, user)
|
||||
return user, nil
|
||||
}
|
||||
21
cmd/go-omni/scaffold/templates/internal-service-user.go.tmpl
Normal file
21
cmd/go-omni/scaffold/templates/internal-service-user.go.tmpl
Normal file
@@ -0,0 +1,21 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"{{.Module}}/internal/model"
|
||||
"{{.Module}}/internal/servicecontext"
|
||||
)
|
||||
|
||||
type Users struct {
|
||||
context *servicecontext.Context
|
||||
}
|
||||
|
||||
func NewUsers(context *servicecontext.Context) *Users {
|
||||
return &Users{context: context}
|
||||
}
|
||||
|
||||
func (s *Users) Create(ctx context.Context, input model.UserInput) (model.User, error) {
|
||||
// Put business normalization and rules here.
|
||||
return s.context.Users.Create(ctx, input)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package servicecontext
|
||||
|
||||
import (
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
"{{.Module}}/internal/repository"
|
||||
)
|
||||
|
||||
// Context owns infrastructure dependencies shared by the service layer.
|
||||
// Add database, cache and external clients here as the project grows.
|
||||
type Context struct {
|
||||
Logger *logx.Logger
|
||||
Users repository.UserRepository
|
||||
}
|
||||
|
||||
func New(logger *logx.Logger, users repository.UserRepository) *Context {
|
||||
return &Context{Logger: logger, Users: users}
|
||||
}
|
||||
Reference in New Issue
Block a user