Compare commits

...

No commits in common. "master" and "dev" have entirely different histories.
master ... dev

40 changed files with 700 additions and 1100 deletions

1
.gitignore vendored

@ -4,4 +4,3 @@ xtest
*.db
*.sqlite
.DS_Store
etc

41
api.go

@ -1,41 +0,0 @@
package uzone
import (
"net/http"
"github.com/loveuer/uzone/pkg/api"
)
func (u *uzone) API() *api.App { return u.api.engine }
func (u *uzone) GET(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodGet, path, handlers...)
}
func (u *uzone) POST(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPost, path, handlers...)
}
func (u *uzone) PUT(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPut, path, handlers...)
}
func (u *uzone) DELETE(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodDelete, path, handlers...)
}
func (u *uzone) PATCH(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPatch, path, handlers...)
}
func (u *uzone) HEAD(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodHead, path, handlers...)
}
func (u *uzone) OPTIONS(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodOptions, path, handlers...)
}
func (u *uzone) HandleAPI(method, path string, handlers ...api.HandlerFunc) {
u.api.engine.Handle(method, path, handlers...)
}

@ -1,8 +0,0 @@
package uzone
import "context"
type Config struct {
Ctx context.Context
Debug bool
}

@ -1,35 +0,0 @@
package main
import (
"github.com/loveuer/uzone"
"github.com/loveuer/uzone/pkg/api"
"github.com/loveuer/uzone/pkg/interfaces"
)
type Record struct {
Id uint64 `json:"id" gorm:"primaryKey;column:id"`
CreatedAt int64 `json:"created_at" gorm:"column:created_at;autoCreateTime:milli"`
Name string `json:"name" gorm:"column:name"`
}
func main() {
app := uzone.New(uzone.Config{Debug: true})
app.With(uzone.InitDB("sqlite://data.db", &Record{}))
app.With(uzone.InitApi(api.New()))
app.With(uzone.InitFn(func(u interfaces.Uzone) {
u.UseLogger().Debug("[init] create init record")
u.UseDB().Create(&Record{Name: "init"})
}))
app.GET("/hello/:name", func(c *api.Ctx) error {
name := c.Param("name")
c.UseLogger().Debug("[hello] got name = %s", name)
record := &Record{Name: name}
err := c.UseDB().Create(record).Error
return c.JSON(map[string]any{"record": record, "err": err})
})
app.RunSignal()
}

7
go.mod

@ -1,6 +1,6 @@
module github.com/loveuer/uzone
module github.com/loveuer/upp
go 1.20
go 1.23.4
require (
gitea.com/loveuer/gredis v1.0.0
@ -14,9 +14,7 @@ require (
github.com/loveuer/nf v0.3.1
github.com/samber/lo v1.47.0
github.com/spf13/cast v1.7.1
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.25.0
gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/mysql v1.5.7
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12
@ -40,7 +38,6 @@ require (
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.21.0 // indirect

21
go.sum

@ -6,6 +6,7 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@ -15,7 +16,9 @@ github.com/elastic/go-elasticsearch/v7 v7.17.10/go.mod h1:OJ4wdbtDNk5g503kvlHLyE
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
@ -26,7 +29,9 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@ -46,7 +51,9 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/loveuer/nf v0.3.1 h1:FTmyAC9LQF06BVGeGwrwaYfbC6MIQMqr+GoZUQQPvXU=
github.com/loveuer/nf v0.3.1/go.mod h1:aApO+2cSP0ULczkfS4OVw8zfWM3rY8gQrzc5PnVV7lY=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@ -57,8 +64,11 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@ -67,6 +77,7 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
@ -75,14 +86,11 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -92,9 +100,10 @@ golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

84
log.go

@ -1,84 +0,0 @@
package uzone
import (
"context"
"sync"
"github.com/google/uuid"
"github.com/loveuer/uzone/pkg/api"
"github.com/loveuer/uzone/pkg/log"
"go.uber.org/zap"
)
type uzone_logger struct {
ctx context.Context
caller string
sugar *zap.SugaredLogger
}
func (ul *uzone_logger) WithContext(ctx context.Context) *uzone_logger {
ul.ctx = ctx
return ul
}
// func (ul *uzone_logger) WithCaller(caller string) *uzone_logger {
// ul.caller = caller
// return ul
// }
func (ul *uzone_logger) GC() {
ul.ctx = nil
ul.caller = ""
ul.sugar = nil
log.Logger.Sync()
uzone_logger_pool.Put(ul)
}
var uzone_logger_pool = &sync.Pool{
New: func() any {
s := log.Logger.Sugar()
return &uzone_logger{sugar: s}
},
}
func (ul *uzone_logger) traceId() string {
if ul.ctx == nil {
return uuid.Must(uuid.NewV7()).String()
}
if tid, ok := ul.ctx.Value(api.TraceKey).(string); ok && tid != "" {
return tid
}
return uuid.Must(uuid.NewV7()).String()
}
func (ul *uzone_logger) Debug(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Debugf(msg, data...)
ul.GC()
}
func (ul *uzone_logger) Info(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Infof(msg, data...)
ul.GC()
}
func (ul *uzone_logger) Warn(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Warnf(msg, data...)
ul.GC()
}
func (ul *uzone_logger) Error(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Errorf(msg, data...)
ul.GC()
}
func (ul *uzone_logger) Panic(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Panicf(msg, data...)
ul.GC()
}
func (ul *uzone_logger) Fatal(msg string, data ...any) {
ul.sugar.With("trace", ul.traceId()).Fatalf(msg, data...)
ul.GC()
}

102
module.go

@ -1,102 +0,0 @@
package uzone
import (
"context"
"crypto/tls"
"log"
"github.com/loveuer/uzone/pkg/api"
"github.com/loveuer/uzone/pkg/cache"
"github.com/loveuer/uzone/pkg/db"
"github.com/loveuer/uzone/pkg/es"
"github.com/loveuer/uzone/pkg/interfaces"
)
type module func(u *uzone)
func InitDB(uri string, models ...any) module {
db, err := db.New(uri)
if err != nil {
log.Panic(err.Error())
}
if err = db.AutoMigrate(models...); err != nil {
log.Panic(err.Error())
}
return func(u *uzone) {
u.db = db
}
}
func InitCache(uri string) module {
cache, err := cache.New(uri)
if err != nil {
log.Panic(err.Error())
}
return func(u *uzone) {
u.cache = cache
}
}
func InitES(uri string) module {
client, err := es.New(context.TODO(), uri)
if err != nil {
log.Panic(err.Error())
}
return func(u *uzone) {
u.es = client
}
}
type ApiConfig struct {
Address string
TLSConfig *tls.Config
}
func InitApi(api *api.App, cfgs ...ApiConfig) module {
cfg := ApiConfig{}
if len(cfgs) > 0 {
cfg = cfgs[0]
}
if cfg.Address == "" {
cfg.Address = "localhost:8080"
}
return func(u *uzone) {
api.Uzone = u
u.api = &uzoneApi{
engine: api,
config: cfg,
}
}
}
func InitTaskChan(ch <-chan func(uzone interfaces.Uzone) error) module {
return func(u *uzone) {
if u.taskCh == nil {
u.taskCh = make([]<-chan func(u interfaces.Uzone) error, 0)
}
u.taskCh = append(u.taskCh, ch)
}
}
// sync functions
// 添加 同步执行函数
func InitFn(fns ...func(interfaces.Uzone)) module {
return func(u *uzone) {
u.initFns._sync = append(u.initFns._sync, fns...)
}
}
// async functions
// 添加 异步执行函数
func InitAsyncFn(fns ...func(interfaces.Uzone)) module {
return func(u *uzone) {
u.initFns._async = append(u.initFns._async, fns...)
}
}

@ -12,8 +12,8 @@ import (
"regexp"
"sync"
"github.com/loveuer/uzone/internal/bytesconv"
"github.com/loveuer/uzone/pkg/interfaces"
"github.com/loveuer/upp/internal/bytesconv"
"github.com/loveuer/upp/pkg/interfaces"
)
var (
@ -25,7 +25,7 @@ var (
type App struct {
RouterGroup
Uzone interfaces.Uzone
Upp interfaces.Upp
config *Config
groups []*RouterGroup
server *http.Server

@ -14,11 +14,8 @@ import (
"strings"
"sync"
"github.com/elastic/go-elasticsearch/v7"
"github.com/google/uuid"
"github.com/loveuer/uzone/internal/sse"
"github.com/loveuer/uzone/pkg/cache"
"github.com/loveuer/uzone/pkg/interfaces"
"github.com/loveuer/upp/internal/sse"
"gorm.io/gorm"
)
@ -42,20 +39,8 @@ type Ctx struct {
fullPath string
}
func (c *Ctx) UseLogger() interfaces.Logger {
return c.app.Uzone.UseLogger(c.Context())
}
func (c *Ctx) UseDB(ctx ...context.Context) *gorm.DB {
return c.app.Uzone.UseDB(ctx...)
}
func (c *Ctx) UseCache() cache.Cache {
return c.app.Uzone.UseCache()
}
func (c *Ctx) UseES() elasticsearch.Client {
return *c.app.Uzone.UseES()
func (c *Ctx) UseDB() *gorm.DB {
return c.app.Upp.UseDB()
}
func (c *Ctx) reset(w http.ResponseWriter, r *http.Request) {

@ -10,7 +10,7 @@ import (
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
"github.com/loveuer/nf/nft/resp"
"github.com/loveuer/uzone/pkg/tool"
"github.com/loveuer/upp/pkg/tool"
)
func NewRecover(enableStackTrace bool) HandlerFunc {

@ -7,7 +7,7 @@ import (
"unicode"
"unicode/utf8"
"github.com/loveuer/uzone/internal/bytesconv"
"github.com/loveuer/upp/internal/bytesconv"
)
var (

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/loveuer/uzone/internal/schema"
"github.com/loveuer/upp/internal/schema"
)
const (

3
pkg/cache/cache.go vendored

@ -19,7 +19,6 @@ type Cache interface {
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
SetEx(ctx context.Context, key string, value any, duration time.Duration) error
Del(ctx context.Context, keys ...string) error
Close() error
}
type Scanner interface {
@ -35,7 +34,7 @@ type decoded_value interface {
}
const (
Prefix = "zone:"
Prefix = "upp:"
)
var ErrorKeyNotFound = errors.New("key not found")

@ -134,11 +134,6 @@ func (l *_lru) Del(ctx context.Context, keys ...string) error {
return nil
}
func (l *_lru) Close() error {
l.client = nil
return nil
}
func newLRUCache() (Cache, error) {
client := expirable.NewLRU[string, *_lru_value](1024*1024, nil, 0)

@ -103,9 +103,3 @@ func (m *_mem) Del(ctx context.Context, keys ...string) error {
m.client.Delete(keys...)
return nil
}
func (m *_mem) Close() error {
m.client = nil
return nil
}

@ -104,7 +104,3 @@ func (r *_redis) SetEx(ctx context.Context, key string, value any, duration time
func (r *_redis) Del(ctx context.Context, keys ...string) error {
return r.client.Del(ctx, keys...).Err()
}
func (r *_redis) Close() error {
return r.client.Close()
}

2
pkg/cache/new.go vendored

@ -7,7 +7,7 @@ import (
"gitea.com/loveuer/gredis"
"github.com/go-redis/redis/v8"
"github.com/loveuer/uzone/pkg/tool"
"github.com/loveuer/upp/pkg/tool"
)
func New(uri string) (Cache, error) {

@ -6,7 +6,7 @@ import (
"strings"
"github.com/glebarez/sqlite"
"github.com/loveuer/uzone/pkg/log"
"github.com/loveuer/upp/pkg/log"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
@ -32,11 +32,11 @@ func New(uri string) (*gorm.DB, error) {
switch ins.Scheme {
case "sqlite":
path := strings.TrimPrefix(uri, ins.Scheme+"://")
log.Logger.Sugar().Debugf("db.New: type = %s, path = %s", ins.Scheme, path)
log.Debug("db.New: type = %s, path = %s", ins.Scheme, path)
tx, err = gorm.Open(sqlite.Open(path))
case "mysql", "mariadb":
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?%s", username, password, ins.Host, ins.Path, ins.RawQuery)
log.Logger.Sugar().Debugf("db.New: type = %s, dsn = %s", ins.Scheme, dsn)
log.Debug("db.New: type = %s, dsn = %s", ins.Scheme, dsn)
tx, err = gorm.Open(mysql.Open(dsn))
case "pg", "postgres", "postgresql":
opts := make([]string, 0)
@ -44,7 +44,7 @@ func New(uri string) (*gorm.DB, error) {
opts = append(opts, fmt.Sprintf("%s=%s", key, val))
}
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s %s", ins.Hostname(), username, password, ins.Path, ins.Port(), strings.Join(opts, " "))
log.Logger.Sugar().Debugf("db.New: type = %s, dsn = %s", ins.Scheme, dsn)
log.Debug("db.New: type = %s, dsn = %s", ins.Scheme, dsn)
tx, err = gorm.Open(postgres.Open(dsn))
default:
return nil, fmt.Errorf("invalid database type(uri_scheme): %s", ins.Scheme)

@ -1,77 +0,0 @@
package es
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"strings"
"time"
elastic "github.com/elastic/go-elasticsearch/v7"
"github.com/elastic/go-elasticsearch/v7/esapi"
"github.com/loveuer/uzone/pkg/tool"
"github.com/samber/lo"
)
// New elasticsearch client v7
// example:
// - uri: http://127.0.0.1:9200
// - uri: https://<username>:<password>@node1:9200,node2:9200,node3:9200
func New(ctx context.Context, uri string) (*elastic.Client, error) {
var (
err error
username string
password string
client *elastic.Client
ins *url.URL
)
if ins, err = url.Parse(uri); err != nil {
return nil, err
}
endpoints := lo.Map(
strings.Split(ins.Host, ","),
func(item string, index int) string {
return fmt.Sprintf("%s://%s", ins.Scheme, item)
},
)
if ins.User != nil {
username = ins.User.Username()
password, _ = ins.User.Password()
}
if client, err = elastic.NewClient(
elastic.Config{
Addresses: endpoints,
Username: username,
Password: password,
CACert: nil,
RetryOnStatus: []int{429},
MaxRetries: 3,
RetryBackoff: nil,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DialContext: (&net.Dialer{Timeout: 10 * time.Second}).DialContext,
},
},
); err != nil {
return nil, err
}
var res *esapi.Response
if res, err = client.Ping(client.Ping.WithContext(tool.TimeoutCtx(ctx, 5))); err != nil {
return nil, err
}
if res.StatusCode != 200 {
err = fmt.Errorf("ping client response: %s", res.String())
return nil, err
}
return client, nil
}

@ -26,7 +26,7 @@ type ApiEngine interface {
}
type ApiContext interface {
App() Uzone
App() Upp
// parse body, form, json
BodyParser(out any) error
Context() context.Context

13
pkg/interfaces/upp.go Normal file

@ -0,0 +1,13 @@
package interfaces
import (
"github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/upp/pkg/cache"
"gorm.io/gorm"
)
type Upp interface {
UseDB() *gorm.DB
UseCache() cache.Cache
UseES() *elasticsearch.Client
}

@ -1,18 +0,0 @@
package interfaces
import (
"context"
"github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/uzone/pkg/cache"
"gorm.io/gorm"
)
type Uzone interface {
Debug() bool
UseCtx() context.Context
UseDB(ctx ...context.Context) *gorm.DB
UseCache() cache.Cache
UseES() *elasticsearch.Client
UseLogger(ctxs ...context.Context) Logger
}

67
pkg/log/default.go Normal file

@ -0,0 +1,67 @@
package log
import (
"fmt"
"os"
"sync"
)
var (
nilLogger = func(prefix, timestamp, msg string, data ...any) {}
normalLogger = func(prefix, timestamp, msg string, data ...any) {
fmt.Printf(prefix+"| "+timestamp+" | "+msg+"\n", data...)
}
panicLogger = func(prefix, timestamp, msg string, data ...any) {
panic(fmt.Sprintf(prefix+"| "+timestamp+" | "+msg+"\n", data...))
}
fatalLogger = func(prefix, timestamp, msg string, data ...any) {
fmt.Printf(prefix+"| "+timestamp+" | "+msg+"\n", data...)
os.Exit(1)
}
DefaultLogger = &logger{
Mutex: sync.Mutex{},
timeFormat: "2006-01-02T15:04:05",
writer: os.Stdout,
level: LogLevelInfo,
debug: nilLogger,
info: normalLogger,
warn: normalLogger,
error: normalLogger,
panic: panicLogger,
fatal: fatalLogger,
}
)
func SetTimeFormat(format string) {
DefaultLogger.SetTimeFormat(format)
}
func SetLogLevel(level LogLevel) {
DefaultLogger.SetLogLevel(level)
}
func Debug(msg string, data ...any) {
DefaultLogger.Debug(msg, data...)
}
func Info(msg string, data ...any) {
DefaultLogger.Info(msg, data...)
}
func Warn(msg string, data ...any) {
DefaultLogger.Warn(msg, data...)
}
func Error(msg string, data ...any) {
DefaultLogger.Error(msg, data...)
}
func Panic(msg string, data ...any) {
DefaultLogger.Panic(msg, data...)
}
func Fatal(msg string, data ...any) {
DefaultLogger.Fatal(msg, data...)
}

@ -1,36 +1,115 @@
package log
import (
"github.com/fatih/color"
"io"
"sync"
"go.uber.org/zap"
"time"
)
type LogLevel uint32
const (
LogLevelDebug = iota
LogLevelInfo
LogLevelWarn
LogLevelError
LogLevelPanic
LogLevelFatal
)
type logger struct {
sync.Mutex
timeFormat string
writer io.Writer
level LogLevel
debug func(prefix, timestamp, msg string, data ...any)
info func(prefix, timestamp, msg string, data ...any)
warn func(prefix, timestamp, msg string, data ...any)
error func(prefix, timestamp, msg string, data ...any)
panic func(prefix, timestamp, msg string, data ...any)
fatal func(prefix, timestamp, msg string, data ...any)
}
var (
Logger *zap.Logger
locker = &sync.Mutex{}
red = color.New(color.FgRed)
hired = color.New(color.FgHiRed)
green = color.New(color.FgGreen)
yellow = color.New(color.FgYellow)
white = color.New(color.FgWhite)
)
func init() {
var err error
config := zap.NewProductionConfig()
Logger, err = config.Build()
if err != nil {
panic(err)
func (l *logger) SetTimeFormat(format string) {
l.Lock()
defer l.Unlock()
l.timeFormat = format
}
func (l *logger) SetLogLevel(level LogLevel) {
l.Lock()
defer l.Unlock()
if level > LogLevelDebug {
l.debug = nilLogger
} else {
l.debug = normalLogger
}
if level > LogLevelInfo {
l.info = nilLogger
} else {
l.info = normalLogger
}
if level > LogLevelWarn {
l.warn = nilLogger
} else {
l.warn = normalLogger
}
if level > LogLevelError {
l.error = nilLogger
} else {
l.error = normalLogger
}
if level > LogLevelPanic {
l.panic = nilLogger
} else {
l.panic = panicLogger
}
if level > LogLevelFatal {
l.fatal = nilLogger
} else {
l.fatal = fatalLogger
}
}
func Debug() {
var err error
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(zap.DebugLevel)
locker.Lock()
defer locker.Unlock()
Logger, err = config.Build()
if err != nil {
panic(err)
func (l *logger) Debug(msg string, data ...any) {
l.debug(white.Sprint("Debug "), time.Now().Format(l.timeFormat), msg, data...)
}
func (l *logger) Info(msg string, data ...any) {
l.info(green.Sprint("Info "), time.Now().Format(l.timeFormat), msg, data...)
}
func (l *logger) Warn(msg string, data ...any) {
l.warn(yellow.Sprint("Warn "), time.Now().Format(l.timeFormat), msg, data...)
}
func (l *logger) Error(msg string, data ...any) {
l.error(red.Sprint("Error "), time.Now().Format(l.timeFormat), msg, data...)
}
func (l *logger) Panic(msg string, data ...any) {
l.panic(hired.Sprint("Panic "), time.Now().Format(l.timeFormat), msg, data...)
}
func (l *logger) Fatal(msg string, data ...any) {
l.fatal(hired.Sprint("Fatal "), time.Now().Format(l.timeFormat), msg, data...)
}
type WroteLogger interface {
Info(msg string, data ...any)
}

21
pkg/log/new.go Normal file

@ -0,0 +1,21 @@
package log
import (
"os"
"sync"
)
func New() *logger {
return &logger{
Mutex: sync.Mutex{},
timeFormat: "2006-01-02T15:04:05",
writer: os.Stdout,
level: LogLevelInfo,
debug: nilLogger,
info: normalLogger,
warn: normalLogger,
error: normalLogger,
panic: panicLogger,
fatal: fatalLogger,
}
}

@ -1,11 +1,11 @@
package tool
import "github.com/loveuer/uzone/pkg/log"
import "github.com/loveuer/upp/pkg/log"
func Must(errs ...error) {
for _, err := range errs {
if err != nil {
log.Logger.Panic(err.Error())
log.Panic(err.Error())
}
}
}

@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"github.com/loveuer/upp/pkg/log"
"golang.org/x/crypto/pbkdf2"
)
@ -20,29 +21,26 @@ func NewPassword(password string) string {
return EncryptPassword(password, RandomString(8), int(RandomInt(50000)+100000))
}
// ComparePassword
// if password in and db are same, return nil
func ComparePassword(in, db string) error {
func ComparePassword(in, db string) bool {
strs := strings.Split(db, "$")
if len(strs) != 3 {
return fmt.Errorf("password in db invalid: %s", db)
log.Error("password in db invalid: %s", db)
return false
}
encs := strings.Split(strs[0], ":")
if len(encs) != 3 {
return fmt.Errorf("password in db invalid: %s", db)
log.Error("password in db invalid: %s", db)
return false
}
encIteration, err := strconv.Atoi(encs[2])
if err != nil {
return fmt.Errorf("password in db invalid: %s, convert iter err: %s", db, err)
log.Error("password in db invalid: %s, convert iter err: %s", db, err)
return false
}
if EncryptPassword(in, strs[1], encIteration) != db {
return fmt.Errorf("password input and db not same")
}
return nil
return EncryptPassword(in, strs[1], encIteration) == db
}
func EncryptPassword(password, salt string, iter int) string {
@ -68,6 +66,7 @@ func CheckPassword(password string) error {
for idx, pattern := range patternList {
match, err = regexp.MatchString(pattern, password)
if err != nil {
log.Warn("regex match string err, reg_str: %s, err: %v", pattern, err)
return errors.New("密码强度不够")
}

@ -8,9 +8,8 @@ import (
"reflect"
"strings"
"github.com/loveuer/uzone/pkg/log"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/loveuer/upp/pkg/log"
)
func TablePrinter(data any, writers ...io.Writer) {
@ -82,6 +81,8 @@ Start:
p := fmt.Sprintf("%s.%s", prefix, rv.Type().Field(i).Name)
field := rv.Field(i)
// log.Debug("TablePrinter: prefix: %s, field: %v", p, rv.Field(i))
if !field.CanInterface() {
return
}
@ -94,7 +95,7 @@ Start:
func TableMapPrinter(data []byte) {
m := make(map[string]any)
if err := json.Unmarshal(data, &m); err != nil {
log.Logger.Warn(err.Error())
log.Warn(err.Error())
return
}

19
pkg/tool/tools.go Normal file

@ -0,0 +1,19 @@
package tool
import "cmp"
func Min[T cmp.Ordered](a, b T) T {
if a <= b {
return a
}
return b
}
func Max[T cmp.Ordered](a, b T) T {
if a >= b {
return a
}
return b
}

@ -1,129 +0,0 @@
package uzone
import (
"fmt"
"github.com/spf13/cast"
"gopkg.in/yaml.v3"
"os"
"reflect"
"time"
"github.com/loveuer/uzone/pkg/tool"
)
type _property struct {
Debug bool `yaml:"debug" json:"debug" env:"UZONE.DEBUG"`
Listen struct {
Http string `yaml:"http" json:"http" env:"UZONE.LISTEN.HTTP"`
} `yaml:"listen" json:"listen"`
DB struct {
URI string `json:"uri" env:"UZONE.DB.URI"`
} `yaml:"db" json:"db"`
Cache struct {
URI string `json:"uri" env:"UZONE.CACHE.URI"`
} `yaml:"cache" json:"cache"`
Elasticsearch struct {
URI string `yaml:"uri" json:"uri" env:"UZONE.ELASTICSEARCH.URI"`
} `yaml:"elasticsearch" json:"elasticsearch"`
}
var property = &_property{}
func init() {
time.Local = time.FixedZone("CST", 8*3600)
var (
err error
bs []byte
configFn = func(path string) error {
if bs, err = os.ReadFile(path); err != nil {
uzone_logger_pool.Get().(*uzone_logger).Debug("[%30s] read %s err, err = %s", "init", path, err.Error())
return err
}
if err = yaml.Unmarshal(bs, property); err != nil {
uzone_logger_pool.Get().(*uzone_logger).Debug("[%30s] unmarshal %s err, err = %s", "init", path, err.Error())
return err
}
return nil
}
)
if err = configFn("etc/config.yaml"); err == nil {
goto BindEnv
}
if err = configFn("etc/config.yml"); err == nil {
goto BindEnv
}
_ = configFn("etc/config.json")
BindEnv:
_ = bindEnv(property)
if property.Debug {
tool.TablePrinter(property)
}
}
func bindEnv(data any) error {
rv := reflect.ValueOf(data)
if rv.Type().Kind() != reflect.Pointer {
return fmt.Errorf("can only bind ptr")
}
rv = rv.Elem()
return bindStruct(rv)
}
func bindStruct(rv reflect.Value) error {
if rv.Type().Kind() != reflect.Struct {
return fmt.Errorf("can only bind struct ptr")
}
for i := 0; i < rv.NumField(); i++ {
f := rv.Field(i)
if f.Type().Kind() == reflect.Pointer {
f = f.Elem()
}
if f.Type().Kind() == reflect.Struct {
return bindStruct(f)
}
if !f.CanSet() {
continue
}
tag := rv.Type().Field(i).Tag.Get("env")
if tag == "" || tag == "-" {
continue
}
bv := os.Getenv(tag)
if bv == "" {
continue
}
switch f.Type().Kind() {
case reflect.String:
f.SetString(bv)
case reflect.Bool:
f.SetBool(cast.ToBool(bv))
case reflect.Int64, reflect.Int, reflect.Uint64, reflect.Uint, reflect.Int32, reflect.Uint32, reflect.Int16, reflect.Uint16, reflect.Int8, reflect.Uint8:
f.SetInt(cast.ToInt64(bv))
case reflect.Float64, reflect.Float32:
f.SetFloat(cast.ToFloat64(bv))
default:
uzone_logger_pool.Get().(*uzone_logger).Warn("[%30s] unsupported env binding, type = %s, value = %s", "init", f.Type().Kind().String(), bv)
}
}
return nil
}

@ -1,16 +0,0 @@
package uzone
import (
"os"
"testing"
)
func Test_bindEnv(t *testing.T) {
os.Setenv("UZONE.LISTEN.HTTP", "0.0.0.0:99")
os.Setenv("UZONE.DEBUG", "true")
p := &_property{}
bindEnv(p)
t.Logf("listen.http = %s", p.Listen.Http)
t.Logf("debug = %v", p.Debug)
}

@ -1,58 +1,11 @@
# UZone
# UPP - your app
### Usage
- 1. usage present
```go
app := uzone.New()
app := upp.New()
app.With(db, es, api)
app.Run(ctx)
```
- 2. simple example
```go
package main
import (
"github.com/loveuer/uzone"
"github.com/loveuer/uzone/pkg/api"
"github.com/loveuer/uzone/pkg/interfaces"
)
type Record struct {
Id uint64 `json:"id" gorm:"primaryKey;column:id"`
CreatedAt int64 `json:"created_at" gorm:"column:created_at;autoCreateTime:milli"`
Name string `json:"name" gorm:"column:name"`
}
func main() {
app := uzone.New(uzone.Config{Debug: true})
app.With(uzone.InitDB("sqlite://data.db", &Record{}))
app.With(uzone.InitApi(api.New()))
app.With(uzone.InitFn(func(u interfaces.Uzone) {
u.UseLogger().Debug("[init] create init record")
u.UseDB().Create(&Record{Name: "init"})
}))
app.GET("/hello/:name", func(c *api.Ctx) error {
name := c.Param("name")
c.UseLogger().Debug("[hello] got name = %s", name)
record := &Record{Name: name}
err := c.UseDB().Create(record).Error
return c.JSON(map[string]any{"record": record, "err": err})
})
app.RunSignal()
}
```
### Config
> The program will load configuration files in the following order:
- `etc/config.yaml`
- `etc/config.yml`
- `config.json`
> Environment variables will take precedence and override any matching configurations found in the files above.

102
run.go

@ -1,102 +0,0 @@
package uzone
import (
"context"
"fmt"
"os/signal"
"syscall"
"github.com/loveuer/uzone/pkg/interfaces"
"github.com/loveuer/uzone/pkg/tool"
)
func (u *uzone) startAPI(ctx context.Context) {
address := property.Listen.Http
if address == "" {
address = u.api.config.Address
}
fmt.Printf("Uzone | api listen at %s\n", address)
go u.api.engine.Run(address)
go func() {
<-ctx.Done()
u.api.engine.Shutdown(tool.Timeout(2))
}()
}
func (u *uzone) startTask(ctx context.Context) {
fmt.Printf("Uzone | start task channel[%02d]", len(u.taskCh))
for _, _ch := range u.taskCh {
go func(ch <-chan func(interfaces.Uzone) error) {
var err error
for {
select {
case <-ctx.Done():
case task, ok := <-ch:
if !ok {
return
}
if err = task(u); err != nil {
u.UseLogger(ctx).Error(err.Error())
}
}
}
}(_ch)
}
}
func (u *uzone) Run(ctx context.Context) {
u.RunSignal(ctx)
}
func (u *uzone) runInitFns(ctx context.Context) {
for _, fn := range u.initFns._sync {
fn(u)
}
}
func (u *uzone) startInitFns(ctx context.Context) {
for _, fn := range u.initFns._async {
go fn(u)
}
}
func (u *uzone) RunSignal(ctxs ...context.Context) {
c := context.Background()
if len(ctxs) > 0 {
c = ctxs[0]
}
ctx, cancel := signal.NotifyContext(c, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
defer cancel()
u.ctx = ctx
print(Banner)
if len(u.initFns._sync) > 0 {
u.runInitFns(ctx)
}
if len(u.initFns._async) > 0 {
u.startInitFns(ctx)
}
if u.api != nil {
u.startAPI(ctx)
}
if len(u.taskCh) > 0 {
u.startTask(ctx)
}
<-ctx.Done()
u.UseLogger().Warn(" Upp | quit by signal...")
if u.cache != nil {
u.cache.Close()
}
<-tool.Timeout(2).Done()
}

41
upp/api.go Normal file

@ -0,0 +1,41 @@
package upp
import (
"net/http"
"github.com/loveuer/upp/pkg/api"
)
func (u *upp) API() *api.App { return u.api.engine }
func (u *upp) GET(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodGet, path, handlers...)
}
func (u *upp) POST(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPost, path, handlers...)
}
func (u *upp) PUT(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPut, path, handlers...)
}
func (u *upp) DELETE(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodDelete, path, handlers...)
}
func (u *upp) PATCH(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodPatch, path, handlers...)
}
func (u *upp) HEAD(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodHead, path, handlers...)
}
func (u *upp) OPTIONS(path string, handlers ...api.HandlerFunc) {
u.HandleAPI(http.MethodOptions, path, handlers...)
}
func (u *upp) HandleAPI(method, path string, handlers ...api.HandlerFunc) {
u.api.engine.Handle(method, path, handlers...)
}

25
upp/log.go Normal file

@ -0,0 +1,25 @@
package upp
func (u *upp) Debug(msg string, data ...any) {
u.logger.Debug(msg, data...)
}
func (u *upp) Info(msg string, data ...any) {
u.logger.Info(msg, data...)
}
func (u *upp) Warn(msg string, data ...any) {
u.logger.Warn(msg, data...)
}
func (u *upp) Error(msg string, data ...any) {
u.logger.Error(msg, data...)
}
func (u *upp) Panic(msg string, data ...any) {
u.logger.Panic(msg, data...)
}
func (u *upp) Fatal(msg string, data ...any) {
u.logger.Fatal(msg, data...)
}

80
upp/module.go Normal file

@ -0,0 +1,80 @@
package upp
import (
"crypto/tls"
"log"
"github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/upp/pkg/api"
"github.com/loveuer/upp/pkg/cache"
"github.com/loveuer/upp/pkg/db"
"gorm.io/gorm"
)
type module func(u *upp)
func InitDB(uri string, models ...any) module {
db, err := db.New(uri)
if err != nil {
log.Panic(err.Error())
}
if err = db.AutoMigrate(models...); err != nil {
log.Panic(err.Error())
}
return func(u *upp) {
u.db = db
}
}
func (u *upp) UseDB() *gorm.DB {
tx := u.db.Session(&gorm.Session{})
if u.debug {
tx = tx.Debug()
}
return tx
}
func InitCache(uri string) module {
cache, err := cache.New(uri)
if err != nil {
log.Panic(err.Error())
}
return func(u *upp) {
u.cache = cache
}
}
func (u *upp) UseCache() cache.Cache {
return u.cache
}
func (u *upp) UseES() *elasticsearch.Client {
return nil
}
type ApiConfig struct {
Address string
TLSConfig *tls.Config
}
func InitApi(api *api.App, cfgs ...ApiConfig) module {
cfg := ApiConfig{}
if len(cfgs) > 0 {
cfg = cfgs[0]
}
if cfg.Address == "" {
cfg.Address = "localhost:8080"
}
return func(u *upp) {
api.Upp = u
u.api = &uppApi{
engine: api,
config: cfg,
}
}
}

71
upp/upp.go Normal file

@ -0,0 +1,71 @@
package upp
import (
"context"
"os/signal"
"syscall"
"github.com/loveuer/upp/pkg/api"
"github.com/loveuer/upp/pkg/cache"
"github.com/loveuer/upp/pkg/interfaces"
"github.com/loveuer/upp/pkg/log"
"github.com/loveuer/upp/pkg/tool"
"gorm.io/gorm"
)
type uppApi struct {
engine *api.App
config ApiConfig
}
type upp struct {
debug bool
logger interfaces.Logger
db *gorm.DB
cache cache.Cache
api *uppApi
}
func (u *upp) With(modules ...module) {
for _, m := range modules {
m(u)
}
}
func (u *upp) Run(ctx context.Context) {
u.StartAPI(ctx)
<-ctx.Done()
}
func (u *upp) RunSignal() {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
defer cancel()
if u.api != nil {
u.StartAPI(ctx)
}
<-ctx.Done()
u.Warn(" UPP | quit by signal...")
<-tool.Timeout(2).Done()
}
func (u *upp) StartAPI(ctx context.Context) {
u.Info("UPP | run api at %s", u.api.config.Address)
go u.api.engine.Run(u.api.config.Address)
go func() {
<-ctx.Done()
u.api.engine.Shutdown(tool.Timeout(2))
}()
}
func New() *upp {
app := &upp{
logger: log.New(),
}
return app
}

58
use.go

@ -1,58 +0,0 @@
package uzone
import (
"context"
"github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/uzone/pkg/cache"
"github.com/loveuer/uzone/pkg/interfaces"
"github.com/loveuer/uzone/pkg/tool"
"gorm.io/gorm"
)
func (u *uzone) Debug() bool {
return u.debug
}
func (u *uzone) UseCtx() context.Context {
return u.ctx
}
func (u *uzone) UseDB(ctx ...context.Context) *gorm.DB {
var c context.Context
if len(ctx) > 0 {
c = ctx[0]
} else {
c = tool.Timeout(30)
}
tx := u.db.Session(&gorm.Session{
Context: c,
})
if u.Debug() {
tx = tx.Debug()
}
return tx
}
func (u *uzone) UseCache() cache.Cache {
return u.cache
}
func (u *uzone) UseES() *elasticsearch.Client {
return u.es
}
func (u *uzone) UseLogger(ctxs ...context.Context) interfaces.Logger {
logger := u.logger.Get().(*uzone_logger)
logger.ctx = u.UseCtx()
if len(ctxs) > 0 {
logger.ctx = ctxs[0]
}
return logger
}

@ -1,73 +0,0 @@
package uzone
import (
"context"
"sync"
"github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/uzone/pkg/api"
"github.com/loveuer/uzone/pkg/cache"
"github.com/loveuer/uzone/pkg/interfaces"
"github.com/loveuer/uzone/pkg/log"
"gorm.io/gorm"
)
const Banner = `
__ ______
/ / / /_ / ___ ___ ___
/ /_/ / / /_/ _ \/ _ \/ -_)
\____/ /___/\___/_//_/\__/
`
type uzoneApi struct {
engine *api.App
config ApiConfig
}
type uzone struct {
debug bool
ctx context.Context
logger *sync.Pool
db *gorm.DB
cache cache.Cache
es *elasticsearch.Client
api *uzoneApi
initFns struct {
_sync []func(interfaces.Uzone)
_async []func(interfaces.Uzone)
}
taskCh []<-chan func(interfaces.Uzone) error
}
func (u *uzone) With(modules ...module) {
for _, m := range modules {
m(u)
}
}
func New(configs ...Config) *uzone {
config := Config{}
if len(configs) > 0 {
config = configs[0]
}
app := &uzone{
logger: uzone_logger_pool,
initFns: struct {
_sync []func(interfaces.Uzone)
_async []func(interfaces.Uzone)
}{
_sync: make([]func(interfaces.Uzone), 0),
_async: make([]func(interfaces.Uzone), 0),
},
}
if config.Debug || property.Debug {
log.Debug()
app.debug = true
}
return app
}