first commit

main
NoahLan 1 year ago
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,81 @@
syntax = "v1"
info(
title: "Base Api"
desc: "API basic"
author: "NorthLan"
email: "lan6995@gmail.com"
version: "v1.0"
)
// Pagination | 分页模型
// swagger:model Pagination
// swagger:allOf
type Pagination {
// Page Size | 每页大小
//
// Minimum: 0
// Maximum: 9999
// Required: false
// Example: 10
Size uint64 `json:"size,optional" form:"size,optional" validate:"number,max=9999"`
// Current Page | 当前页
//
// Minimum: 1
// Maximum: 100000
// Required: false
// Example: 1
Current uint64 `json:"current,optional" form:"current,optional" validate:"number,max=100000"`
// Total Number | 数据总数
//
// Required: false
Total uint64 `json:"total,optional" form:"total,optional" validate:"number"`
}
// TimeInfo | 时间结构
// swagger:model TimeInfo
type TimeInfo {
// Create Time | 创建时间
CreatedAt string `json:"createdAt,optional"`
// Update Time | 更新时间
UpdatedAt string `json:"updatedAt,optional"`
}
// Basic ID Request | 基础ID结构
type IDReq {
// Id | 序号
Id uint64 `json:"id,string,optional" form:"id,string,optional"`
}
// Basic ID request (path) | 基础ID结构地址参数
type IDPathReq {
// ID | 序号
//
// In: path
Id uint64 `json:"id,optional,string" path:"id,optional,string"`
}
// Basic ID List request | 基础ID列表结构用于Post
// swagger:model IDsReq
type IDsReq {
// 主键列表
Ids []uint64 `json:"ids,optional" form:"ids,optional"`
}
// The base ID response data | 基础ID信息
type BaseIDInfo {
// Id | 序号
Id uint64 `json:"id,string,optional"`
TimeInfo
}
@server(
group: base
prefix: /api/base
)
service {{.name}} {
// Initialize database | 初始化数据库
@handler initDatabase
get /initDatabase
}

@ -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,40 @@
package dberrorhandler
import (
"git.noahlan.cn/noahlan/ntool/nlog"
"git.noahlan.cn/noahlan/ntool-biz/core/nstatus"
"git.noahlan.cn/noahlan/ntool-biz/core/nstatus/msg"
// api
"git.noahlan.cn/noahlan/ntool-biz/core/nstatus/code"
"{{.package}}/ent"
)
// HandleEntErr returns errors dealing with default functions.
func HandleEntErr(logger logx.Logger, err error, detail any) error {
logger := nlog.WithCallerSkip(1)
if err != nil {
switch {
case ent.IsNotFound(err):
// 未找到数据实体
logger.Errorw(err.Error(), nlog.Field("detail", detail))
return nstatus.NewBizErr(code.StatusNotFound, msg.ObjectNotFound)
case ent.IsConstraintError(err):
// 创建/更新时,发生约束错误
logger.Errorw(err.Error(), nlog.Field("detail", detail))
return nstatus.NewBizErr(code.StatusConflict, msg.ConstraintError)
case ent.IsValidationError(err):
// 数据类型错误,验证错误
logger.Errorw(err.Error(), nlog.Field("detail", detail))
return nstatus.NewBizErr(code.StatusBadRequest, msg.ValidationError)
case ent.IsNotSingular(err):
// 查询时发生非单一实体错误通常是因为记录中存在多个实体查询单个实体时未添加Limit
logger.Errorw(err.Error(), nlog.Field("detail", detail))
return nstatus.NewBizErr(code.StatusBadRequest, msg.NotSingularError)
default:
logger.Errorw("database error", nlog.Field("err", err.Error()), nlog.Field("detail", detail))
return nstatus.NewGrpcInternalErr(msg.DatabaseError)
}
}
return err
}

@ -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…
Cancel
Save