package modules import ( "fmt" "go_dreamfactory/comm" "go_dreamfactory/lego/core" "go_dreamfactory/lego/core/cbase" "go_dreamfactory/lego/sys/log" "go_dreamfactory/lego/sys/mgo" "go_dreamfactory/lego/sys/redis" "go_dreamfactory/sys/cache" "go_dreamfactory/sys/db" "reflect" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "google.golang.org/protobuf/proto" ) /* 基础组件 缓存组件 读写缓存数据 DB组件也封装进来 */ type Model_Comp struct { cbase.ModuleCompBase Redis redis.ISys DB mgo.ISys TableName string //redis key前缀 } const ( DB_ModelTable core.SqlTable = "model_log" ) //组件初始化接口 func (this *Model_Comp) Init(service core.IService, module core.IModule, comp core.IModuleComp, options core.IModuleOptions) (err error) { this.ModuleCompBase.Init(service, module, comp, options) this.Redis = cache.Redis() this.DB = db.Mgo() return } func (this *Model_Comp) Start() (err error) { err = this.ModuleCompBase.Start() return } func (this *Model_Comp) ukey(uid string) string { return fmt.Sprintf("%s:%s", this.TableName, uid) } func (this *Model_Comp) InsertModelLogs(table string, uID string, target interface{}) (err error) { data := &comm.Autogenerated{ ID: primitive.NewObjectID().Hex(), UID: uID, Act: string(comm.LogHandleType_Insert), } data.D = append(data.D, table) // D[0] data.D = append(data.D, target) // D[1] _, err = this.DB.InsertOne(DB_ModelTable, data) if err != nil { log.Errorf("insert model db err %v", err) } return err } func (this *Model_Comp) DeleteModelLogs(table string, uID string, where interface{}) (err error) { data := &comm.Autogenerated{ ID: primitive.NewObjectID().Hex(), UID: uID, Act: string(comm.LogHandleType_Delete), } data.D = append(data.D, table) // D[0] data.D = append(data.D, where) // D[1] _, err = this.DB.InsertOne(DB_ModelTable, data) if err != nil { log.Errorf("insert model db err %v", err) } return err } func (this *Model_Comp) UpdateModelLogs(table string, uID string, where bson.M, target interface{}) (err error) { data := &comm.Autogenerated{ ID: primitive.NewObjectID().Hex(), UID: uID, Act: string(comm.LogHandleType_Update), } data.D = append(data.D, table) // D[0] data.D = append(data.D, where) // D[1] data.D = append(data.D, target) // D[2] _, err = this.DB.InsertOne(DB_ModelTable, data) if err != nil { log.Errorf("insert model db err %v", err) } return err } //设置缓存JSON格式数据 //data 值允许protobuf格式的对象 // attrs 操作可选项目 eg.传入WithDisabledMgoLog() 表示关闭日志,否则开启;WithND() 传入表示插入操作,不传表示更新,前提不能传入传入WithDisabledMgoLog() func (this *Model_Comp) SetObj(uid string, data proto.Message, attrs ...*cache.OperationAttr) error { err := this.Redis.Set(this.ukey(uid), data, 0) if err != nil { log.Errorf("set err:%v", err) return err } return this.logOpt(uid, data, attrs...) } //缓存多个字段的数据 data参数 允许map或protobuf //eg.map[string]*TestData{"li_1": {Name: "liwei2dao", Agr: 56}, "li_2": {Name: "liwei3dao", Agr: 78}} //or &TestData{Name: "liwei1dao", Agr: 12, Sub: &TestAny{SubName: "test", Age: 20}} // attrs 操作可选项目 eg.传入WithDisabledMgoLog() 表示关闭日志,否则开启;WithND() 传入表示插入操作,不传表示更新,前提不能传入传入WithDisabledMgoLog() //如果更新数据,uid作为where条件之一,如果检索结果不能确定唯一,此时data 必需是map[string]interface{}类型,必需包含_id 字段 func (this *Model_Comp) SetHM(uid string, data interface{}, attrs ...*cache.OperationAttr) error { err := this.Redis.HMSet(this.ukey(uid), data) if err != nil { log.Errorf("SetHM err: %v", err) return err } return this.logOpt(uid, data, attrs...) } //缓存一个字段的数据 //如果更新数据,uid作为where条件之一,如果检索结果不能确定唯一,此时data 必需是map[string]interface{}类型,必需包含_id 字段 func (this *Model_Comp) SetH(uid string, field string, data interface{}, attrs ...*cache.OperationAttr) error { err := this.Redis.HSet(this.ukey(uid), field, data) if err != nil { log.Errorf("SetH err %v", err) return err } return this.logOpt(uid, data, attrs...) } //获取缓存JSON数据 func (this *Model_Comp) GetObj(uid string, v proto.Message) error { err := this.Redis.Get(this.ukey(uid), v) if err != nil { if err == redis.RedisNil { //query from mgo err = this.DB.FindOne(core.SqlTable(this.TableName), bson.M{"_id": uid}).Decode(v) if err != nil { //no record if err == mongo.ErrNoDocuments { _, err = this.DB.InsertOne(core.SqlTable(this.TableName), v) if err != nil { log.Errorf("insert err: %v", err) return err } //set cache return this.SetObj(uid, v, cache.WithND()) } } } else { log.Errorf("get cache err: %v", err) } } return err } //获取对象所有字段数据 //data类型map或protobuf func (this *Model_Comp) GetHM(uid string, data interface{}) error { ok, err := this.Redis.ExistsKey(this.ukey(uid)) if err != nil { log.Errorf("key no exist %v", this.ukey(uid)) return err } if ok { return this.Redis.HGetAll(this.ukey(uid), data) } else { filter := bson.M{"uid": uid} c, err2 := this.DB.Find(core.SqlTable(this.TableName), filter) if err2 != nil { log.Errorf("GetHM-find err:%v", err) return err } err2 = c.Decode(data) if err2 != nil { log.Errorf("GetHM-find decode err:%v", err) return err } //update cache without mgolog return this.SetHM(this.ukey(uid), data, cache.WithDisabledMgoLog()) } } //获取字段数据 缓存存储的数据为hashmap时 func (this *Model_Comp) GetH(uid string, field string, v interface{}) error { return this.Redis.HGet(this.ukey(uid), field, v) } //删除一条数据 func (this *Model_Comp) DelH(uid string) error { err := this.Redis.HDel(this.ukey(uid)) if err != nil { log.Errorf("del err:%v", err) return err } return this.DeleteModelLogs(this.TableName, uid, bson.M{"uid": uid}) } //删除缓存字段 func (this *Model_Comp) DelHF(uid string, fields ...string) error { err := this.Redis.HDel(this.ukey(uid), fields...) if err != nil { log.Errorf("DelHF err: %v", err) return err } //get new data after delete data := make(map[string]interface{}) err = this.Redis.HGetAll(this.ukey(uid), data) if err != nil { log.Errorf("DelHF-HGetAll err: %v", err) return err } //cache with mgolog return this.SetHM(this.ukey(uid), data) } //日志操作可选项 func (this *Model_Comp) logOpt(uid string, data interface{}, attrs ...*cache.OperationAttr) error { ret := cache.OperationAttrs(attrs).Find(cache.ATTR_MGOLOG).Unwrap_Or(nil) if ret == nil { //启用mgolog ir := cache.OperationAttrs(attrs).Find(cache.ATTR_INSERT).Unwrap_Or(nil) if ir == nil { //updte opt where := bson.M{"uid": uid} if reflect.ValueOf(data).Kind() == reflect.Map { if m, ok := data.(map[string]interface{}); ok { where["_id"] = m["_id"] } else { return fmt.Errorf("have %v,but want map[string]interface{}", data) } } return this.UpdateModelLogs(this.TableName, uid, where, data) } else { //insert opt return this.InsertModelLogs(this.TableName, uid, data) } } return nil }