first commit
commit
d074e4e58b
@ -0,0 +1,4 @@
|
|||||||
|
goctls-template
|
||||||
|
---
|
||||||
|
|
||||||
|
Custom golang template repo for [goctls](https://github.com/suyuan32/goctls).
|
@ -0,0 +1,87 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casbin/casbin/v2"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
|
||||||
|
"git.noahlan.cn/noahlan/ntools-go/core/nlog"
|
||||||
|
"git.noahlan.cn/noahlan/ntools-go/zero/statusz"
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/core/nstatus"
|
||||||
|
{{if .useTrans}}
|
||||||
|
"git.noahlan.cn/noahlan/ntools-go/core/i18n"{{end}}
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthorityMiddleware struct {
|
||||||
|
Cbn *casbin.Enforcer
|
||||||
|
Rds *redis.Redis
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthorityMiddleware(cbn *casbin.Enforcer, rds *redis.Redis) *AuthorityMiddleware {
|
||||||
|
return &AuthorityMiddleware{
|
||||||
|
Cbn: cbn,
|
||||||
|
Rds: rds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *AuthorityMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
{{if .useTrans}}const transErr = true{{else}}const transErr = false{{end}}
|
||||||
|
// get the path
|
||||||
|
obj := r.URL.Path
|
||||||
|
// get the method
|
||||||
|
act := r.Method
|
||||||
|
// get the role id
|
||||||
|
roleIds := r.Context().Value("roleIds").(string)
|
||||||
|
|
||||||
|
// check jwt blacklist
|
||||||
|
jwtResult, err := m.Rds.Get("token_" + r.Header.Get("Authorization"))
|
||||||
|
if err != nil {
|
||||||
|
nlog.Errorw("redis error in jwt", nlog.Field("detail", err.Error()))
|
||||||
|
statusz.ResponseHandler(r, w, transErr, nil, nstatus.NewApiInternalErr(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if jwtResult == "1" {
|
||||||
|
nlog.Errorw("token in blacklist", nlog.Field("detail", r.Header.Get("Authorization")))
|
||||||
|
statusz.ResponseHandler(r, w, transErr, nil, nstatus.NewApiErrWithCode(http.StatusUnauthorized))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result := batchCheck(m.Cbn, roleIds, act, obj)
|
||||||
|
|
||||||
|
if result {
|
||||||
|
nlog.Infow("HTTP/HTTPS Request", nlog.Field("UUID", r.Context().Value("userId").(string)),
|
||||||
|
nlog.Field("path", obj), nlog.Field("method", act))
|
||||||
|
next(w, r)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
nlog.Errorw("the role is not permitted to access the API", nlog.Field("roleIds", roleIds),
|
||||||
|
nlog.Field("path", obj), nlog.Field("method", act))
|
||||||
|
statusz.ResponseHandler(r, w, transErr, nil, nstatus.NewApiForbiddenErr("common.permissionDeny"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func batchCheck(cbn *casbin.Enforcer, roleIds, act, obj string) bool {
|
||||||
|
var checkReq [][]any
|
||||||
|
for _, v := range strings.Split(roleIds, ",") {
|
||||||
|
checkReq = append(checkReq, []any{v, obj, act})
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := cbn.BatchEnforce(checkReq)
|
||||||
|
if err != nil {
|
||||||
|
nlog.Errorw("Casbin enforce error", nlog.Field("detail", err.Error()))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range result {
|
||||||
|
if v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
nconfig "git.noahlan.cn/noahlan/ntool-biz/core/config"
|
||||||
|
{{if .useCasbin}}
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/core/casbin"
|
||||||
|
dbconfig "git.noahlan.cn/noahlan/ntool-biz/core/orm/nent/config"{{else}}
|
||||||
|
{{if .useEnt}}
|
||||||
|
dbconfig "git.noahlan.cn/noahlan/ntool-biz/core/orm/nent/config"
|
||||||
|
{{end}}{{end}}
|
||||||
|
"github.com/zeromicro/go-zero/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
rest.RestConf
|
||||||
|
Auth nconfig.AuthConf
|
||||||
|
CROSConf nconfig.CORSConf
|
||||||
|
{{if .useCasbin}}
|
||||||
|
CasbinConf casbin.CasbinConf
|
||||||
|
DatabaseConf dbconfig.Database
|
||||||
|
RedisConf nconfig.RedisConf{{else}}
|
||||||
|
{{if .useEnt}}DatabaseConf dbconfig.Database{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{.jwtTrans}}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package svc
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{.configImport}}
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/zero/logz"
|
||||||
|
{{if .useI18n}}
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/core/i18n"{{end}}
|
||||||
|
{{if .useEnt}}
|
||||||
|
"{{.projectPackage}}/ent"{{end}}
|
||||||
|
{{if .useCasbin}}
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
"github.com/zeromicro/go-zero/rest"
|
||||||
|
"github.com/casbin/casbin/v2"{{end}}
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceContext struct {
|
||||||
|
Config {{.config}}
|
||||||
|
{{.middleware}}
|
||||||
|
{{if .useCasbin}}Casbin *casbin.Enforcer
|
||||||
|
Authority rest.Middleware{{end}}
|
||||||
|
{{if .useEnt}}
|
||||||
|
DB *ent.Client{{end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServiceContext(c {{.config}}) *ServiceContext {
|
||||||
|
// 配置nlog-logx适配器
|
||||||
|
nlog.MustSetup(logz.WrapConf(c.Log))
|
||||||
|
logx.SetWriter(logz.NewWriter())
|
||||||
|
{{if .useI18n}}
|
||||||
|
// 配置多语言
|
||||||
|
i18n.InitWithConfig(c.I18nConf)
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .useCasbin}}
|
||||||
|
rds := redis.MustNewRedis(redis.RedisConf{
|
||||||
|
Host: c.RedisConf.Addr,
|
||||||
|
Type: c.RedisConf.Type,
|
||||||
|
Pass: c.RedisConf.Password,
|
||||||
|
Tls: c.RedisConf.Tls,
|
||||||
|
})
|
||||||
|
cbn := c.CasbinConf.MustNewCasbinWithRedisWatcher(c.DatabaseConf.Type, c.DatabaseConf.GetDSN(), c.RedisConf)
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .useEnt}}
|
||||||
|
db := ent.NewClient(
|
||||||
|
ent.Log(nlog.Info), // logger
|
||||||
|
ent.Driver(c.DatabaseConf.NewNoCacheDriver()),
|
||||||
|
ent.Debug(), // debug mode
|
||||||
|
)
|
||||||
|
{{end}}
|
||||||
|
return &ServiceContext{
|
||||||
|
Config: c,
|
||||||
|
{{if .useCasbin}}
|
||||||
|
Authority: middleware.NewAuthorityMiddleware(cbn, rds).Handle,
|
||||||
|
Casbin: cbn,
|
||||||
|
{{end}}
|
||||||
|
{{if .useEnt}}DB: db,{{end}}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
Name: {{.serviceName}}.api
|
||||||
|
Host: {{.host}}
|
||||||
|
Port: {{.port}}
|
||||||
|
Timeout: 30000
|
||||||
|
|
||||||
|
Auth:
|
||||||
|
AccessSecret: # the same as core
|
||||||
|
AccessExpire: 259200
|
||||||
|
|
||||||
|
CORSConf:
|
||||||
|
Address: '*'
|
||||||
|
|
||||||
|
Log:
|
||||||
|
ServiceName: {{.serviceName}}ApiLogger
|
||||||
|
Mode: console
|
||||||
|
Path: ./logs/{{.serviceName}}/api
|
||||||
|
Encoding: plain # json or plain
|
||||||
|
Level: debug
|
||||||
|
Stat: false
|
||||||
|
Compress: false
|
||||||
|
KeepDays: 7
|
||||||
|
StackCoolDownMillis: 100
|
||||||
|
|
||||||
|
Prometheus:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Port: 4000
|
||||||
|
Path: /metrics
|
||||||
|
|
||||||
|
{{if .useCasbin}}
|
||||||
|
RedisConf:
|
||||||
|
Host: 127.0.0.1:6379
|
||||||
|
Type: node
|
||||||
|
|
||||||
|
DatabaseConf:
|
||||||
|
Type: mysql
|
||||||
|
Host: 127.0.0.1
|
||||||
|
Port: 3306
|
||||||
|
DBName: test
|
||||||
|
Username: # set your username
|
||||||
|
Password: # set your password
|
||||||
|
MaxOpenConn: 1000
|
||||||
|
SSLMode: disable
|
||||||
|
CacheTime: 5
|
||||||
|
|
||||||
|
CasbinConf:
|
||||||
|
ModelText: |
|
||||||
|
[request_definition]
|
||||||
|
r = sub, obj, act
|
||||||
|
[policy_definition]
|
||||||
|
p = sub, obj, act
|
||||||
|
[role_definition]
|
||||||
|
g = _, _
|
||||||
|
[policy_effect]
|
||||||
|
e = some(where (p.eft == allow))
|
||||||
|
[matchers]
|
||||||
|
m = r.sub == p.sub && keyMatch2(r.obj,p.obj) && r.act == p.act
|
||||||
|
|
||||||
|
{{else}}
|
||||||
|
{{if .useEnt}}
|
||||||
|
DatabaseConf:
|
||||||
|
Type: mysql
|
||||||
|
Host: 127.0.0.1
|
||||||
|
Port: 3306
|
||||||
|
DBName: simple_admin
|
||||||
|
Username: # set your username
|
||||||
|
Password: # set your password
|
||||||
|
MaxOpenConn: 100
|
||||||
|
SSLMode: disable
|
||||||
|
CacheTime: 5
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .useI18n}}
|
||||||
|
I18nConf:
|
||||||
|
Default: zh
|
||||||
|
RootPath: dal/i18n/locale
|
||||||
|
SortedParameterPrefix: p
|
||||||
|
{{end}}
|
@ -0,0 +1,32 @@
|
|||||||
|
package {{.PkgName}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/zero/statusz"
|
||||||
|
{{if .HasRequest}}"github.com/zeromicro/go-zero/rest/httpx"{{end}}
|
||||||
|
|
||||||
|
{{.ImportPackages}}
|
||||||
|
)
|
||||||
|
|
||||||
|
{{.HandlerDoc}}
|
||||||
|
|
||||||
|
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
{{if .TransErr}}const transErr = true{{else}}const transErr = false{{end}}
|
||||||
|
{{if .HasRequest}}var req types.{{.RequestType}}
|
||||||
|
if err := httpx.Parse(r, &req, true); err != nil {
|
||||||
|
statusz.ResponseHandler(r, w, transErr, nil, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
l := {{.LogicName}}.New{{.LogicType}}(r, r.Context(), svcCtx)
|
||||||
|
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
|
||||||
|
{{if .HasResp}}
|
||||||
|
statusz.ResponseHandler(r, w, transErr, resp, err)
|
||||||
|
{{else}}
|
||||||
|
statusz.ResponseHandler(r, w, transErr, nil, err)
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package {{.pkgName}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{.imports}}
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{.logic}} struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
r *http.Request
|
||||||
|
}
|
||||||
|
|
||||||
|
func New{{.logic}}(r *http.Request, ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} {
|
||||||
|
return &{{.logic}}{
|
||||||
|
r: r,
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} {
|
||||||
|
// todo: add your logic here and delete this line
|
||||||
|
|
||||||
|
{{.returnString}}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// {{.serviceName}}
|
||||||
|
//
|
||||||
|
// Description: {{.serviceName}} service
|
||||||
|
//
|
||||||
|
// Schemes: http, https
|
||||||
|
// Host: localhost:{{.port}}
|
||||||
|
// BasePath: /
|
||||||
|
// Version: 0.0.1
|
||||||
|
// SecurityDefinitions:
|
||||||
|
// Token:
|
||||||
|
// type: apiKey
|
||||||
|
// name: Authorization
|
||||||
|
// in: header
|
||||||
|
// Security:
|
||||||
|
// - Token: []
|
||||||
|
// Consumes:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// Produces:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// swagger:meta
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
{{.importPackages}}
|
||||||
|
)
|
||||||
|
|
||||||
|
var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file")
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var c config.Config
|
||||||
|
conf.MustLoad(*configFile, &c, conf.UseEnv())
|
||||||
|
|
||||||
|
server := rest.MustNewServer(c.RestConf, rest.WithCors(c.CORSConf.Address))
|
||||||
|
defer server.Stop()
|
||||||
|
|
||||||
|
ctx := svc.NewServiceContext(c)
|
||||||
|
handler.RegisterHandlers(server, ctx)
|
||||||
|
|
||||||
|
fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port)
|
||||||
|
server.Start()
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type {{.name}} struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func New{{.name}}() *{{.name}} {
|
||||||
|
return &{{.name}}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *{{.name}})Handle(next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// TODO generate middleware implement function, delete after code implementation
|
||||||
|
|
||||||
|
// Passthrough to next handler if need
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
{{.routes}} {{.jwt}}{{.signature}} {{.prefix}} {{.timeout}} {{.maxBytes}}
|
||||||
|
)
|
@ -0,0 +1,13 @@
|
|||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"{{if .hasTimeout}}
|
||||||
|
"time"{{end}}
|
||||||
|
|
||||||
|
{{.importPackages}}
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||||
|
{{.routesAdditions}}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
syntax = "v1"
|
||||||
|
|
||||||
|
info (
|
||||||
|
title: // TODO: add title
|
||||||
|
desc: // TODO: add description
|
||||||
|
author: "{{.gitUser}}"
|
||||||
|
email: "{{.gitEmail}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
type request {
|
||||||
|
// TODO: add members here and delete this comment
|
||||||
|
}
|
||||||
|
|
||||||
|
type response {
|
||||||
|
// TODO: add members here and delete this comment
|
||||||
|
}
|
||||||
|
|
||||||
|
service {{.serviceName}} {
|
||||||
|
@handler GetUser // TODO: set handler name and delete this comment
|
||||||
|
get /users/id/:userId(request) returns(response)
|
||||||
|
|
||||||
|
@handler CreateUser // TODO: set handler name and delete this comment
|
||||||
|
post /users/create(request)
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
package types{{if .containsTime}}
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
){{end}}
|
||||||
|
{{.types}}
|
@ -0,0 +1,43 @@
|
|||||||
|
FROM {{.Image}} as builder
|
||||||
|
|
||||||
|
# Define the project name | 定义项目名称
|
||||||
|
ARG PROJECT={{.ServiceName}}
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
{{if .Chinese}}
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||||
|
{{end}}{{if .HasTimezone}}
|
||||||
|
RUN apk update --no-cache && apk add --no-cache tzdata
|
||||||
|
{{end}}
|
||||||
|
RUN go env -w GO111MODULE=on \
|
||||||
|
{{if .Chinese}} && go env -w GOPROXY=https://goproxy.cn,direct \
|
||||||
|
{{end}} && go env -w CGO_ENABLED=0 \
|
||||||
|
&& go env \
|
||||||
|
&& go mod tidy \
|
||||||
|
&& go build -ldflags="-s -w" -o /build/${PROJECT}_{{.ServiceType}} ${PROJECT}.go
|
||||||
|
|
||||||
|
FROM {{.BaseImage}}
|
||||||
|
|
||||||
|
# Define the project name | 定义项目名称
|
||||||
|
ARG PROJECT={{.ServiceName}}
|
||||||
|
# Define the config file name | 定义配置文件名
|
||||||
|
ARG CONFIG_FILE={{.ServiceName}}.yaml
|
||||||
|
# Define the author | 定义作者
|
||||||
|
ARG AUTHOR="{{.Author}}"
|
||||||
|
|
||||||
|
LABEL org.opencontainers.image.authors=${AUTHOR}
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
ENV PROJECT=${PROJECT}
|
||||||
|
ENV CONFIG_FILE=${CONFIG_FILE}
|
||||||
|
{{if .HasTimezone}}
|
||||||
|
COPY --from=builder /usr/share/zoneinfo/{{.Timezone}} /usr/share/zoneinfo/{{.Timezone}}
|
||||||
|
ENV TZ={{.Timezone}}
|
||||||
|
{{end}}
|
||||||
|
COPY --from=builder /build/${PROJECT}_{{.ServiceType}} ./
|
||||||
|
COPY --from=builder /build/etc/${CONFIG_FILE} ./etc/
|
||||||
|
{{if .HasPort}}
|
||||||
|
EXPOSE {{.Port}}
|
||||||
|
{{end}}
|
||||||
|
ENTRYPOINT ./${PROJECT}_{{.ServiceType}} -f etc/${CONFIG_FILE}
|
@ -0,0 +1,18 @@
|
|||||||
|
Name: gateway-example # gateway name
|
||||||
|
Host: localhost # gateway host
|
||||||
|
Port: 8888 # gateway port
|
||||||
|
Upstreams: # upstreams
|
||||||
|
- Grpc: # grpc upstream
|
||||||
|
Target: 0.0.0.0:8080 # grpc target,the direct grpc server address,for only one node
|
||||||
|
# Endpoints: [0.0.0.0:8080,192.168.120.1:8080] # grpc endpoints, the grpc server address list, for multiple nodes
|
||||||
|
# Etcd: # etcd config, if you want to use etcd to discover the grpc server address
|
||||||
|
# Hosts: [127.0.0.1:2378,127.0.0.1:2379] # etcd hosts
|
||||||
|
# Key: greet.grpc # the discovery key
|
||||||
|
# protoset mode
|
||||||
|
ProtoSets:
|
||||||
|
- hello.pb
|
||||||
|
# Mappings can also be written in proto options
|
||||||
|
# Mappings: # routes mapping
|
||||||
|
# - Method: get
|
||||||
|
# Path: /ping
|
||||||
|
# RpcPath: hello.Hello/Ping
|
@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
|
"github.com/zeromicro/go-zero/gateway"
|
||||||
|
)
|
||||||
|
|
||||||
|
var configFile = flag.String("f", "etc/gateway.yaml", "config file")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var c gateway.GatewayConf
|
||||||
|
conf.MustLoad(*configFile, &c)
|
||||||
|
gw := gateway.MustNewServer(c)
|
||||||
|
defer gw.Stop()
|
||||||
|
gw.Start()
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}
|
||||||
|
namespace: {{.Namespace}}
|
||||||
|
labels:
|
||||||
|
app: {{.Name}}
|
||||||
|
spec:
|
||||||
|
replicas: {{.Replicas}}
|
||||||
|
revisionHistoryLimit: {{.Revisions}}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{.Name}}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{.Name}}
|
||||||
|
spec:{{if .ServiceAccount}}
|
||||||
|
serviceAccountName: {{.ServiceAccount}}{{end}}
|
||||||
|
containers:
|
||||||
|
- name: {{.Name}}
|
||||||
|
image: {{.Image}}
|
||||||
|
{{if .ImagePullPolicy}}imagePullPolicy: {{.ImagePullPolicy}}
|
||||||
|
{{end}}ports:
|
||||||
|
- containerPort: {{.Port}}
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: {{.Port}}
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: {{.Port}}
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: {{.RequestCpu}}m
|
||||||
|
memory: {{.RequestMem}}Mi
|
||||||
|
limits:
|
||||||
|
cpu: {{.LimitCpu}}m
|
||||||
|
memory: {{.LimitMem}}Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: timezone
|
||||||
|
mountPath: /etc/localtime
|
||||||
|
{{if .Secret}}imagePullSecrets:
|
||||||
|
- name: {{.Secret}}
|
||||||
|
{{end}}volumes:
|
||||||
|
- name: timezone
|
||||||
|
hostPath:
|
||||||
|
path: /usr/share/zoneinfo/Asia/Shanghai
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}-svc
|
||||||
|
namespace: {{.Namespace}}
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
{{if .UseNodePort}}- nodePort: {{.NodePort}}
|
||||||
|
port: {{.Port}}
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: {{.TargetPort}}
|
||||||
|
type: NodePort{{else}}- port: {{.Port}}
|
||||||
|
targetPort: {{.TargetPort}}{{end}}
|
||||||
|
selector:
|
||||||
|
app: {{.Name}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}
|
||||||
|
labels:
|
||||||
|
serviceMonitor: prometheus
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{.Name}}-svc
|
||||||
|
endpoints:
|
||||||
|
- port: prometheus
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}-hpa-c
|
||||||
|
namespace: {{.Namespace}}
|
||||||
|
labels:
|
||||||
|
app: {{.Name}}-hpa-c
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{.Name}}
|
||||||
|
minReplicas: {{.MinReplicas}}
|
||||||
|
maxReplicas: {{.MaxReplicas}}
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}-hpa-m
|
||||||
|
namespace: {{.Namespace}}
|
||||||
|
labels:
|
||||||
|
app: {{.Name}}-hpa-m
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: {{.Name}}
|
||||||
|
minReplicas: {{.MinReplicas}}
|
||||||
|
maxReplicas: {{.MaxReplicas}}
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: memory
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: 80
|
@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: {{.Name}}
|
||||||
|
namespace: {{.Namespace}}
|
||||||
|
spec:
|
||||||
|
successfulJobsHistoryLimit: {{.SuccessfulJobsHistoryLimit}}
|
||||||
|
schedule: "{{.Schedule}}"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:{{if .ServiceAccount}}
|
||||||
|
serviceAccountName: {{.ServiceAccount}}{{end}}
|
||||||
|
{{end}}containers:
|
||||||
|
- name: {{.Name}}
|
||||||
|
image: # todo image url
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: {{.RequestCpu}}m
|
||||||
|
memory: {{.RequestMem}}Mi
|
||||||
|
limits:
|
||||||
|
cpu: {{.LimitCpu}}m
|
||||||
|
memory: {{.LimitMem}}Mi
|
||||||
|
command:
|
||||||
|
- ./{{.ServiceName}}
|
||||||
|
- -f
|
||||||
|
- ./{{.Name}}.yaml
|
||||||
|
volumeMounts:
|
||||||
|
- name: timezone
|
||||||
|
mountPath: /etc/localtime
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: # registry secret, if no, remove this
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
volumes:
|
||||||
|
- name: timezone
|
||||||
|
hostPath:
|
||||||
|
path: /usr/share/zoneinfo/Asia/Shanghai
|
@ -0,0 +1,33 @@
|
|||||||
|
{{.head}}
|
||||||
|
|
||||||
|
package {{.filePackage}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
{{.pbPackage}}
|
||||||
|
{{if ne .pbPackage .protoGoPackage}}{{.protoGoPackage}}{{end}}
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
{{.alias}}
|
||||||
|
|
||||||
|
{{.serviceName}} interface {
|
||||||
|
{{.interface}}
|
||||||
|
}
|
||||||
|
|
||||||
|
default{{.serviceName}} struct {
|
||||||
|
cli zrpc.Client
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} {
|
||||||
|
return &default{{.serviceName}}{
|
||||||
|
cli: cli,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{.functions}}
|
@ -0,0 +1,19 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{if .isEnt}}
|
||||||
|
dbconfig "git.noahlan.cn/noahlan/ntool-biz/core/orm/nent/config"
|
||||||
|
nconfig "git.noahlan.cn/noahlan/ntool-biz/core/config"
|
||||||
|
{{end}}
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
zrpc.RpcServerConf
|
||||||
|
{{if .isEnt}}
|
||||||
|
DatabaseConf dbconfig.Database
|
||||||
|
RedisConf nconfig.RedisConf
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
package entx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
||||||
|
|
||||||
|
"{{.package}}/ent"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// WithTx uses transaction in ent.
|
||||||
|
func WithTx(ctx context.Context, client *ent.Client, fn func(tx *ent.Tx) error) error {
|
||||||
|
tx, err := client.Tx(ctx)
|
||||||
|
if err != nil {
|
||||||
|
nlog.Errorw("failed to start transaction", nlog.Field("err", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if v := recover(); v != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
panic(v)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err := fn(tx); err != nil {
|
||||||
|
if rollBackErr := tx.Rollback(); rollBackErr != nil {
|
||||||
|
err = fmt.Errorf("%w: rolling back transaction: %v", err, rollBackErr)
|
||||||
|
}
|
||||||
|
nlog.Errorw("errors occur in transaction", nlog.Field("err", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
nlog.Errorw("failed to commit transaction", nlog.Field("err", err.Error()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
Name: {{.serviceName}}.rpc
|
||||||
|
ListenOn: 0.0.0.0:{{.port}}
|
||||||
|
Timeout: 0
|
||||||
|
Mode: dev
|
||||||
|
|
||||||
|
{{if .isEnt}}
|
||||||
|
DatabaseConf:
|
||||||
|
Type: mysql
|
||||||
|
Host: 127.0.0.1
|
||||||
|
Port: 3306
|
||||||
|
DBName: test
|
||||||
|
Username: # set your username
|
||||||
|
Password: # set your password
|
||||||
|
MaxOpenConn: 1000
|
||||||
|
SSLMode: disable
|
||||||
|
CacheTime: 5
|
||||||
|
|
||||||
|
RedisConf:
|
||||||
|
Host: 127.0.0.1:6379
|
||||||
|
Type: node
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
Log:
|
||||||
|
ServiceName: {{.serviceName}}RpcLogger
|
||||||
|
Mode: console
|
||||||
|
Path: ./logs/{{.serviceName}}/rpc
|
||||||
|
Encoding: plain # json or plain
|
||||||
|
Level: debug
|
||||||
|
Stat: false
|
||||||
|
Compress: false
|
||||||
|
KeepDays: 7
|
||||||
|
StackCoolDownMillis: 100
|
||||||
|
|
||||||
|
Prometheus:
|
||||||
|
Host: 0.0.0.0
|
||||||
|
Port: 4001
|
||||||
|
Path: /metrics
|
@ -0,0 +1,6 @@
|
|||||||
|
{{if .hasComment}}{{.comment}}{{end}}
|
||||||
|
func (l *{{.logicName}}) {{.method}} ({{if .hasReq}}in {{.request}}{{if .stream}},stream {{.streamBody}}{{end}}{{else}}stream {{.streamBody}}{{end}}) ({{if .hasReply}}{{.response}},{{end}} error) {
|
||||||
|
// todo: add your logic here and delete this line
|
||||||
|
|
||||||
|
return {{if .hasReply}}&{{.responseType}}{},{{end}} nil
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package {{.packageName}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
{{.imports}}
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{.logicName}} struct {
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logicName}} {
|
||||||
|
return &{{.logicName}}{
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{.functions}}
|
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
{{.imports}}
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
|
"github.com/zeromicro/go-zero/core/service"
|
||||||
|
"github.com/zeromicro/go-zero/zrpc"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/reflection"
|
||||||
|
)
|
||||||
|
|
||||||
|
var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var c config.Config
|
||||||
|
conf.MustLoad(*configFile, &c, conf.UseEnv())
|
||||||
|
ctx := svc.NewServiceContext(c)
|
||||||
|
|
||||||
|
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||||||
|
{{range .serviceNames}} {{.Pkg}}.Register{{.Service}}Server(grpcServer, {{.ServerPkg}}.New{{.Service}}Server(ctx))
|
||||||
|
{{end}}
|
||||||
|
if c.Mode == service.DevMode || c.Mode == service.TestMode {
|
||||||
|
reflection.Register(grpcServer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer s.Stop()
|
||||||
|
|
||||||
|
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||||||
|
s.Start()
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
{{if .hasComment}}{{.comment}}{{end}}
|
||||||
|
func (s *{{.server}}Server) {{.method}} ({{if .notStream}}ctx context.Context,{{if .hasReq}} in {{.request}}{{end}}{{else}}{{if .hasReq}} in {{.request}},{{end}}stream {{.streamBody}}{{end}}) ({{if .notStream}}{{.response}},{{end}}error) {
|
||||||
|
l := {{.logicPkg}}.New{{.logicName}}({{if .notStream}}ctx,{{else}}stream.Context(),{{end}}s.svcCtx)
|
||||||
|
return l.{{.method}}({{if .hasReq}}in{{if .stream}} ,stream{{end}}{{else}}{{if .stream}}stream{{end}}{{end}})
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
{{.head}}
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{if .notStream}}"context"{{end}}
|
||||||
|
|
||||||
|
{{.imports}}
|
||||||
|
)
|
||||||
|
|
||||||
|
type {{.server}}Server struct {
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
{{.unimplementedServer}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New{{.server}}Server(svcCtx *svc.ServiceContext) *{{.server}}Server {
|
||||||
|
return &{{.server}}Server{
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{.funcs}}
|
@ -0,0 +1,48 @@
|
|||||||
|
package svc
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{.imports}}
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
"git.noahlan.cn/noahlan/ntool/nlog"
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/zero/logz"
|
||||||
|
"git.noahlan.cn/noahlan/ntool-biz/core/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceContext struct {
|
||||||
|
Config config.Config
|
||||||
|
{{if .isEnt}}
|
||||||
|
DB *ent.Client
|
||||||
|
Redis *redis.Redis
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
|
nlog.MustSetup(logz.WrapConf(c.Log))
|
||||||
|
logx.SetWriter(logz.NewWriter())
|
||||||
|
|
||||||
|
// 配置多语言
|
||||||
|
i18n.InitWithConfig(c.I18nConf)
|
||||||
|
|
||||||
|
{{if .isEnt}}
|
||||||
|
db := ent.NewClient(
|
||||||
|
ent.Log(nlog.Info), // logger
|
||||||
|
ent.Driver(c.DatabaseConf.NewNoCacheDriver()),
|
||||||
|
ent.Debug(), // debug mode
|
||||||
|
)
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
rds := redis.MustNewRedis(redis.RedisConf{
|
||||||
|
Host: c.RedisConf.Addr,
|
||||||
|
Type: c.RedisConf.Type,
|
||||||
|
Pass: c.RedisConf.Password,
|
||||||
|
Tls: c.RedisConf.Tls,
|
||||||
|
})
|
||||||
|
|
||||||
|
return &ServiceContext{
|
||||||
|
Config: c,
|
||||||
|
{{if .isEnt}}
|
||||||
|
DB: db,
|
||||||
|
Redis: rds,
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package {{.package}};
|
||||||
|
option go_package="./{{.package}}";
|
||||||
|
|
||||||
|
// Base message
|
||||||
|
message Empty {}
|
||||||
|
|
||||||
|
message IDReq {
|
||||||
|
uint64 id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IDsReq {
|
||||||
|
repeated uint64 ids = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础回执
|
||||||
|
message BaseResp {
|
||||||
|
uint32 code = 1;
|
||||||
|
string msg = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础回执带ID
|
||||||
|
message BaseIDResp {
|
||||||
|
uint64 id = 1;
|
||||||
|
uint32 code = 2;
|
||||||
|
string msg = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页参数
|
||||||
|
message Pagination {
|
||||||
|
uint64 size = 1; // 每页条目个数
|
||||||
|
uint64 total = 2; // 数据条目总数
|
||||||
|
uint64 current = 3; // 当前页码
|
||||||
|
}
|
||||||
|
|
||||||
|
// 操作类型
|
||||||
|
enum Operator {
|
||||||
|
EQ = 0; // ==
|
||||||
|
NEQ = 1; // !=
|
||||||
|
IN = 2; // in ()
|
||||||
|
NotIn = 3; // not in ()
|
||||||
|
GT = 4; // >
|
||||||
|
GTE = 5; // >=
|
||||||
|
LT = 6; // <
|
||||||
|
LTE = 7; // <=
|
||||||
|
Contains = 8; // %{}%
|
||||||
|
Prefix = 9; // {}%
|
||||||
|
Suffix = 10; // %{}
|
||||||
|
EqualFold = 11; // == with toLower
|
||||||
|
ContainsFold = 12; // %{}% with toLower
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
service {{.serviceName}} {
|
||||||
|
// group: base
|
||||||
|
rpc initDatabase (Empty) returns (BaseResp);
|
||||||
|
}
|
Loading…
Reference in New Issue