update: readme.md; feat: add flag

This commit is contained in:
loveuer 2025-01-01 21:01:05 -08:00
parent 25b36157c7
commit a9039115d8
13 changed files with 192 additions and 75 deletions

View File

@ -3,5 +3,6 @@ package upp
import "context" import "context"
type Config struct { type Config struct {
Ctx context.Context Ctx context.Context
Debug bool
} }

24
flag.go Normal file
View File

@ -0,0 +1,24 @@
package upp
import (
"flag"
"time"
)
type __flag struct {
debug bool
listen struct {
http string
}
}
var _flag = &__flag{}
func init() {
time.Local = time.FixedZone("CST", 8*3600)
flag.BoolVar(&_flag.debug, "debug", false, "debug mode")
flag.StringVar(&_flag.listen.http, "listen.http", "localhost:8080", "")
flag.Parse()
}

3
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/loveuer/nf v0.3.1 github.com/loveuer/nf v0.3.1
github.com/samber/lo v1.47.0 github.com/samber/lo v1.47.0
github.com/spf13/cast v1.7.1 github.com/spf13/cast v1.7.1
github.com/spf13/cobra v1.8.1
golang.org/x/crypto v0.25.0 golang.org/x/crypto v0.25.0
gorm.io/driver/mysql v1.5.7 gorm.io/driver/mysql v1.5.7
gorm.io/driver/postgres v1.5.11 gorm.io/driver/postgres v1.5.11
@ -27,6 +28,7 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect
@ -38,6 +40,7 @@ require (
github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.25.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect

9
go.sum
View File

@ -4,6 +4,7 @@ gitea.com/loveuer/gredis v1.0.0 h1:fbRS8YZObcp1KV1KGj8pDpIj1WrI0W8pwU9Ny/2fJys=
gitea.com/loveuer/gredis v1.0.0/go.mod h1:TQlubgDiyNTRXqASd/XIUrqPBLj9NZRR2DmV3V2ZyMY= gitea.com/loveuer/gredis v1.0.0/go.mod h1:TQlubgDiyNTRXqASd/XIUrqPBLj9NZRR2DmV3V2ZyMY=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@ -31,6 +32,8 @@ 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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
@ -67,10 +70,15 @@ 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 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -91,6 +99,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314=

1
pkg/cache/cache.go vendored
View File

@ -19,6 +19,7 @@ type Cache interface {
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal // SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
SetEx(ctx context.Context, key string, value any, duration time.Duration) error SetEx(ctx context.Context, key string, value any, duration time.Duration) error
Del(ctx context.Context, keys ...string) error Del(ctx context.Context, keys ...string) error
Close() error
} }
type Scanner interface { type Scanner interface {

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ import (
) )
type Upp interface { type Upp interface {
Debug() bool
UseCtx() context.Context UseCtx() context.Context
UseDB(ctx ...context.Context) *gorm.DB UseDB(ctx ...context.Context) *gorm.DB
UseCache() cache.Cache UseCache() cache.Cache

View File

@ -2,6 +2,7 @@
### Usage ### Usage
> usage present
```go ```go
app := upp.New() app := upp.New()
@ -9,3 +10,34 @@ app.With(db, es, api)
app.Run(ctx) app.Run(ctx)
``` ```
> simple example
```go
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 := upp.New()
app.With(upp.InitDB("sqlite://data.db", &Record{}))
app.With(upp.InitApi(api.New()))
app.GET("/hello/:name", func(c *api.Ctx) error {
name := c.Param("name")
c.UseLogger().Info("[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()
}
```
> run with flags
```sh
go run . --debug --listen.http '0.0.0.0:8080'
```

88
run.go Normal file
View File

@ -0,0 +1,88 @@
package upp
import (
"context"
"os/signal"
"syscall"
"github.com/loveuer/upp/pkg/interfaces"
"github.com/loveuer/upp/pkg/tool"
)
func (u *upp) StartAPI(ctx context.Context) {
address := _flag.listen.http
if address == "" {
address = u.api.config.Address
}
u.UseLogger().Info("UPP | run api at %s", address)
go u.api.engine.Run(address)
go func() {
<-ctx.Done()
u.api.engine.Shutdown(tool.Timeout(2))
}()
}
func (u *upp) StartTask(ctx context.Context) {
for _, _ch := range u.taskCh {
go func(ch <-chan func(interfaces.Upp) 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 *upp) Run(ctx context.Context) {
u.RunSignal(ctx)
}
func (u *upp) RunInitFns(ctx context.Context) {
for _, fn := range u.initFns {
fn(u)
}
}
func (u *upp) 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
if len(u.initFns) > 0 {
u.RunInitFns(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()
}

85
upp.go
View File

@ -2,15 +2,13 @@ package upp
import ( import (
"context" "context"
"os/signal"
"sync" "sync"
"syscall"
"github.com/elastic/go-elasticsearch/v7" "github.com/elastic/go-elasticsearch/v7"
"github.com/loveuer/upp/pkg/api" "github.com/loveuer/upp/pkg/api"
"github.com/loveuer/upp/pkg/cache" "github.com/loveuer/upp/pkg/cache"
"github.com/loveuer/upp/pkg/interfaces" "github.com/loveuer/upp/pkg/interfaces"
"github.com/loveuer/upp/pkg/tool" "github.com/loveuer/upp/pkg/log"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -37,79 +35,20 @@ func (u *upp) With(modules ...module) {
} }
} }
func (u *upp) Run(ctx context.Context) {
u.RunSignal(ctx)
}
func (u *upp) RunInitFns(ctx context.Context) {
for _, fn := range u.initFns {
fn(u)
}
}
func (u *upp) RunSignal(ctxs ...context.Context) {
c := context.Background()
if len(ctxs) > 0 {
c = ctxs[0]
}
ctx, cancel := signal.NotifyContext(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
defer cancel()
u.ctx = ctx
if len(u.initFns) > 0 {
u.RunInitFns(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...")
<-tool.Timeout(2).Done()
}
func (u *upp) StartAPI(ctx context.Context) {
u.UseLogger().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 (u *upp) StartTask(ctx context.Context) {
for _, _ch := range u.taskCh {
go func(ch <-chan func(interfaces.Upp) 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 New(configs ...Config) *upp { func New(configs ...Config) *upp {
config := Config{}
if len(configs) > 0 {
config = configs[0]
}
if config.Debug || _flag.debug {
log.SetLogLevel(log.LogLevelDebug)
}
app := &upp{ app := &upp{
logger: upp_logger_pool, logger: upp_logger_pool,
debug: config.Debug,
} }
return app return app

View File

@ -10,6 +10,10 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
func (u *upp) Debug() bool {
return u.debug
}
func (u *upp) UseCtx() context.Context { func (u *upp) UseCtx() context.Context {
return u.ctx return u.ctx
} }
@ -27,7 +31,7 @@ func (u *upp) UseDB(ctx ...context.Context) *gorm.DB {
Context: c, Context: c,
}) })
if u.debug { if u.Debug() {
tx = tx.Debug() tx = tx.Debug()
} }