wip: alpha version
This commit is contained in:
26
internal/database/cache.go
Normal file
26
internal/database/cache.go
Normal file
@ -0,0 +1,26 @@
|
||||
package database
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type encoded_value interface {
|
||||
MarshalBinary() ([]byte, error)
|
||||
}
|
||||
|
||||
type decoded_value interface {
|
||||
UnmarshalBinary(bs []byte) error
|
||||
}
|
||||
|
||||
func handleValue(value any) ([]byte, error) {
|
||||
var (
|
||||
bs []byte
|
||||
err error
|
||||
)
|
||||
|
||||
if imp, ok := value.(encoded_value); ok {
|
||||
bs, err = imp.MarshalBinary()
|
||||
} else {
|
||||
bs, err = json.Marshal(value)
|
||||
}
|
||||
|
||||
return bs, err
|
||||
}
|
63
internal/database/cache_memory.go
Normal file
63
internal/database/cache_memory.go
Normal file
@ -0,0 +1,63 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"gitea.com/taozitaozi/gredis"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ Caches = (*_mem)(nil)
|
||||
|
||||
type _mem struct {
|
||||
client *gredis.Gredis
|
||||
}
|
||||
|
||||
func (m *_mem) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
v, err := m.client.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bs, ok := v.([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid value type=%T", v)
|
||||
}
|
||||
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (m *_mem) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
v, err := m.client.GetEx(key, duration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bs, ok := v.([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid value type=%T", v)
|
||||
}
|
||||
|
||||
return bs, nil
|
||||
}
|
||||
|
||||
func (m *_mem) Set(ctx context.Context, key string, value any) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.client.Set(key, bs)
|
||||
}
|
||||
|
||||
func (m *_mem) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.client.SetEx(key, bs, duration)
|
||||
}
|
||||
|
||||
func (m *_mem) Del(ctx context.Context, keys ...string) error {
|
||||
m.client.Delete(keys...)
|
||||
return nil
|
||||
}
|
54
internal/database/cache_redis.go
Normal file
54
internal/database/cache_redis.go
Normal file
@ -0,0 +1,54 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"time"
|
||||
)
|
||||
|
||||
type _redis struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func (r *_redis) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
result, err := r.client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error) {
|
||||
result, err := r.client.GetEx(ctx, key, duration).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []byte(result), nil
|
||||
}
|
||||
|
||||
func (r *_redis) Set(ctx context.Context, key string, value any) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.client.Set(ctx, key, bs, redis.KeepTTL).Result()
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *_redis) SetEx(ctx context.Context, key string, value any, duration time.Duration) error {
|
||||
bs, err := handleValue(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = r.client.SetEX(ctx, key, bs, duration).Result()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *_redis) Del(ctx context.Context, keys ...string) error {
|
||||
return r.client.Del(ctx, keys...).Err()
|
||||
}
|
6
internal/database/client.go
Normal file
6
internal/database/client.go
Normal file
@ -0,0 +1,6 @@
|
||||
package database
|
||||
|
||||
var (
|
||||
DB Store
|
||||
Cache Caches
|
||||
)
|
89
internal/database/init.go
Normal file
89
internal/database/init.go
Normal file
@ -0,0 +1,89 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gitea.com/taozitaozi/gredis"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/loveuer/nfflow/internal/opt"
|
||||
"github.com/loveuer/nfflow/internal/util"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func MustInitClient() {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
// todo: 可以实现自己的 "Store" sql_db, like sqlite, postgresql
|
||||
if DB, err = initSql(); err != nil {
|
||||
panic(fmt.Errorf("database.MustInitClient: init sql err=%v", err))
|
||||
}
|
||||
|
||||
// todo: 可以实现自己的 "Caches" 缓存, like redis
|
||||
if Cache, err = initCacher(); err != nil {
|
||||
panic(fmt.Errorf("database.MustInitCache: init cache err=%v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func initSql() (Store, error) {
|
||||
var (
|
||||
err error
|
||||
client *gorm.DB
|
||||
)
|
||||
|
||||
switch opt.Cfg.Database.Type {
|
||||
case "postgresql":
|
||||
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai",
|
||||
opt.Cfg.Database.Host, opt.Cfg.Database.Username, opt.Cfg.Database.Password, opt.Cfg.Database.DB, opt.Cfg.Database.Port)
|
||||
if client, err = gorm.Open(postgres.Open(dsn)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "mysql":
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
opt.Cfg.Database.Username, opt.Cfg.Database.Password, opt.Cfg.Database.Host, opt.Cfg.Database.Port, opt.Cfg.Database.DB)
|
||||
if client, err = gorm.Open(mysql.Open(dsn)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case "sqlite":
|
||||
if client, err = gorm.Open(sqlite.Open(opt.Cfg.Database.Path)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupportted databsae type=%s", opt.Cfg.Database.Type)
|
||||
}
|
||||
|
||||
return &_db{client: client}, nil
|
||||
}
|
||||
|
||||
func initCacher() (Caches, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
switch opt.Cfg.Cache.Type {
|
||||
case "redis":
|
||||
var rc *redis.Client
|
||||
rc = redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", opt.Cfg.Cache.Host, opt.Cfg.Cache.Port),
|
||||
Username: opt.Cfg.Cache.Username,
|
||||
Password: opt.Cfg.Cache.Password,
|
||||
})
|
||||
|
||||
if err = rc.Ping(util.Timeout(5)).Err(); err != nil {
|
||||
return nil, fmt.Errorf("redis ping err=%v", err)
|
||||
}
|
||||
|
||||
return &_redis{client: rc}, nil
|
||||
case "memory":
|
||||
var mc *gredis.Gredis
|
||||
mc = gredis.NewGredis(-1)
|
||||
|
||||
return &_mem{client: mc}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupportted cache type=%s", opt.Cfg.Cache.Type)
|
||||
}
|
||||
|
||||
}
|
21
internal/database/interface.go
Normal file
21
internal/database/interface.go
Normal file
@ -0,0 +1,21 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Caches interface {
|
||||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
GetEx(ctx context.Context, key string, duration time.Duration) ([]byte, error)
|
||||
// Set value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
Set(ctx context.Context, key string, value any) error
|
||||
// SetEx value 会被序列化, 优先使用 MarshalBinary 方法, 没有则执行 json.Marshal
|
||||
SetEx(ctx context.Context, key string, value any, duration time.Duration) error
|
||||
Del(ctx context.Context, keys ...string) error
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
Session(ctx context.Context) *gorm.DB
|
||||
}
|
20
internal/database/sql.go
Normal file
20
internal/database/sql.go
Normal file
@ -0,0 +1,20 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/loveuer/nfflow/internal/opt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type _db struct {
|
||||
client *gorm.DB
|
||||
}
|
||||
|
||||
func (d *_db) Session(ctx context.Context) *gorm.DB {
|
||||
s := d.client.Session(&gorm.Session{})
|
||||
if opt.Debug > 0 || opt.DBDebug {
|
||||
s = s.Debug()
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
Reference in New Issue
Block a user