github.com/wfusion/gofusion@v1.1.14/lock/construct.go (about) 1 package lock 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/pkg/errors" 8 9 "github.com/wfusion/gofusion/common/di" 10 "github.com/wfusion/gofusion/common/utils" 11 "github.com/wfusion/gofusion/config" 12 "github.com/wfusion/gofusion/db" 13 "github.com/wfusion/gofusion/redis" 14 ) 15 16 var ( 17 appInstances map[string]map[string]Lockable 18 rwlock sync.RWMutex 19 ) 20 21 func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() { 22 opt := utils.ApplyOptions[config.InitOption](opts...) 23 optU := utils.ApplyOptions[useOption](opts...) 24 if opt.AppName == "" { 25 opt.AppName = optU.appName 26 } 27 for name, conf := range confs { 28 addInstance(ctx, name, conf, opt) 29 } 30 31 return func() { 32 rwlock.Lock() 33 defer rwlock.Unlock() 34 if appInstances != nil { 35 delete(appInstances, opt.AppName) 36 } 37 } 38 } 39 40 func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) { 41 rwlock.Lock() 42 defer rwlock.Unlock() 43 if appInstances == nil { 44 appInstances = make(map[string]map[string]Lockable) 45 } 46 if appInstances[opt.AppName] == nil { 47 appInstances[opt.AppName] = make(map[string]Lockable) 48 } 49 50 if _, ok := appInstances[opt.AppName][name]; ok { 51 panic(ErrDuplicatedName) 52 } 53 54 switch conf.Type { 55 case lockTypeRedisLua: 56 redis.Use(ctx, conf.Instance, redis.AppName(opt.AppName)) // check if instance exists 57 appInstances[opt.AppName][name] = newRedisLuaLocker(ctx, opt.AppName, conf.Instance) 58 case lockTypeRedisNX: 59 redis.Use(ctx, conf.Instance, redis.AppName(opt.AppName)) // check if instance exists 60 appInstances[opt.AppName][name] = newRedisNXLocker(ctx, opt.AppName, conf.Instance) 61 case lockTypeMySQL: 62 db.Use(ctx, conf.Instance, db.AppName(opt.AppName)) // check if instance exists 63 appInstances[opt.AppName][name] = newMysqlLocker(ctx, opt.AppName, conf.Instance) 64 case lockTypeMariaDB: 65 db.Use(ctx, conf.Instance, db.AppName(opt.AppName)) // check if instance exists 66 appInstances[opt.AppName][name] = newMysqlLocker(ctx, opt.AppName, conf.Instance) 67 case lockTypeMongo: 68 appInstances[opt.AppName][name] = newMongoLocker(ctx, opt.AppName, conf.Instance, conf.Scheme) 69 default: 70 panic(ErrUnsupportedLockType) 71 } 72 73 // ioc 74 if opt.DI != nil { 75 opt.DI.MustProvide(func() Lockable { return Use(name, AppName(opt.AppName)) }, di.Name(name)) 76 if _, ok := appInstances[opt.AppName][name].(ReentrantLockable); ok { 77 opt.DI.MustProvide( 78 func() ReentrantLockable { return UseReentrant(ctx, name, AppName(opt.AppName)) }, 79 di.Name(name), 80 ) 81 } 82 } 83 } 84 85 type useOption struct { 86 appName string 87 } 88 89 func AppName(name string) utils.OptionFunc[useOption] { 90 return func(o *useOption) { 91 o.appName = name 92 } 93 } 94 95 func Use(name string, opts ...utils.OptionExtender) Lockable { 96 opt := utils.ApplyOptions[useOption](opts...) 97 98 rwlock.RLock() 99 defer rwlock.RUnlock() 100 instances, ok := appInstances[opt.appName] 101 if !ok { 102 panic(errors.Errorf("locker instance not found for app: %s", opt.appName)) 103 } 104 instance, ok := instances[name] 105 if !ok { 106 panic(errors.Errorf("locker instance not found for name: %s", name)) 107 } 108 return instance 109 } 110 111 func UseReentrant(ctx context.Context, name string, opts ...utils.OptionExtender) ReentrantLockable { 112 opt := utils.ApplyOptions[useOption](opts...) 113 114 rwlock.RLock() 115 defer rwlock.RUnlock() 116 instances, ok := appInstances[opt.appName] 117 if !ok { 118 panic(errors.Errorf("reentrant locker instance not found for app: %s", opt.appName)) 119 } 120 instance, ok := instances[name] 121 if !ok { 122 panic(errors.Errorf("reentrant locker instance not found for name: %s", name)) 123 } 124 lockable, ok := instance.(ReentrantLockable) 125 if !ok { 126 panic(errors.Errorf("locker instance is not reentrantable: %s", name)) 127 } 128 129 return lockable 130 } 131 132 func init() { 133 config.AddComponent(config.ComponentLock, Construct, config.WithFlag(&flagString)) 134 }