github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/cache/documentdb.go (about) 1 // The package is migrated from beego, you can get from following link: 2 // import( 3 // "github.com/beego/beego/v2/client/cache" 4 // ) 5 // Copyright 2023. All Rights Reserved. 6 // 7 // Licensed under the Apache License, Version 2.0 (the "License"); 8 // you may not use this file except in compliance with the License. 9 // You may obtain a copy of the License at 10 // 11 // http://www.apache.org/licenses/LICENSE-2.0 12 // 13 // Unless required by applicable law or agreed to in writing, software 14 // distributed under the License is distributed on an "AS IS" BASIS, 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 // See the License for the specific language governing permissions and 17 // limitations under the License. 18 19 package cache 20 21 import ( 22 "context" 23 "encoding/json" 24 "fmt" 25 "time" 26 27 "go.mongodb.org/mongo-driver/bson" 28 "go.mongodb.org/mongo-driver/bson/primitive" 29 "go.mongodb.org/mongo-driver/mongo" 30 "go.mongodb.org/mongo-driver/mongo/options" 31 32 "github.com/mdaxf/iac/framework/berror" 33 34 "github.com/mdaxf/iac/logger" 35 36 "github.com/mdaxf/iac/com" 37 ) 38 39 // Cache DocumentDB Cache adapter. 40 type DocumentDBCache struct { 41 MongoDBClient *mongo.Client 42 MongoDBDatabase *mongo.Database 43 MongoDBCollection_TC *mongo.Collection 44 /* 45 */ 46 CollectionName string 47 iLog logger.Log 48 } 49 type Item struct { 50 Key string `bson:"key"` 51 Value interface{} `bson:"value"` 52 Expiration int32 `bson:"expiration"` 53 CreatedOn time.Time `bson:"createdon"` 54 ExpirateOn time.Time `bson:"expirateon"` 55 } 56 57 // NewMemCache creates a new documentdbcache adapter. 58 func NewDocumentDBCache() Cache { 59 return &DocumentDBCache{} 60 } 61 62 // Get get value from documentdbcache. 63 func (doc *DocumentDBCache) Get(ctx context.Context, key string) (interface{}, error) { 64 var item Item 65 doc.RemoveExpired(ctx) 66 err := doc.MongoDBDatabase.Collection(doc.CollectionName).FindOne(ctx, bson.M{"key": key}).Decode(&item) 67 if err == nil { 68 jdata := make(map[string]interface{}) 69 // fmt.Println("item", item.Value) 70 if data, ok := item.Value.(primitive.D); ok { 71 for _, element := range data { 72 jdata[element.Key] = element.Value 73 } 74 // fmt.Println("jdata", jdata) 75 return jdata, nil 76 } else { 77 return item.Value, nil 78 } 79 80 } else { 81 return nil, berror.Wrapf(err, MemCacheCurdFailed, 82 "could not read data from memcache, please check your key, network and connection. Root cause: %s", 83 err.Error()) 84 } 85 } 86 87 func (doc *DocumentDBCache) RemoveExpired(ctx context.Context) error { 88 _, err := doc.MongoDBDatabase.Collection(doc.CollectionName).DeleteMany(ctx, bson.M{"expirateon": bson.M{"$lt": time.Now()}}) 89 if err != nil { 90 return berror.Wrapf(err, MemCacheCurdFailed, 91 "could not delete expired key-value from mongodb, key: %s", err.Error()) 92 } 93 return nil 94 } 95 96 // GetMulti gets a value from a key in documentdbcache. 97 func (doc *DocumentDBCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { 98 rv := make([]interface{}, len(keys)) 99 doc.RemoveExpired(ctx) 100 var item Item 101 filter := bson.M{"key": bson.M{"$in": keys}} 102 cur, err := doc.MongoDBDatabase.Collection(doc.CollectionName).Find(ctx, filter) 103 if err != nil { 104 return rv, berror.Wrapf(err, MemCacheCurdFailed, 105 "could not read multiple key-values from memcache, "+ 106 "please check your keys, network and connection. Root cause: %s", 107 err.Error()) 108 } 109 defer cur.Close(ctx) 110 for cur.Next(ctx) { 111 err := cur.Decode(&item) 112 if err != nil { 113 return rv, berror.Wrapf(err, MemCacheCurdFailed, 114 "could not read multiple key-values from memcache, "+ 115 "please check your keys, network and connection. Root cause: %s", 116 err.Error()) 117 } 118 rv = append(rv, item.Value) 119 } 120 if err := cur.Err(); err != nil { 121 return rv, berror.Wrapf(err, MemCacheCurdFailed, 122 "could not read multiple key-values from memcache, "+ 123 "please check your keys, network and connection. Root cause: %s", 124 err.Error()) 125 } 126 return rv, nil 127 } 128 129 // Put puts a value into documentdbcache. 130 func (doc *DocumentDBCache) Put(ctx context.Context, key string, val interface{}, timeout time.Duration) error { 131 doc.RemoveExpired(ctx) 132 item := Item{Key: key, 133 Expiration: int32(timeout / time.Second), 134 Value: val, 135 CreatedOn: time.Now(), 136 ExpirateOn: time.Now().Add(timeout), 137 } 138 _, err := doc.MongoDBDatabase.Collection(doc.CollectionName).InsertOne(ctx, item) 139 if err != nil { 140 return berror.Wrapf(err, MemCacheCurdFailed, 141 "could not put key-value to memcache, key: %s", key) 142 } 143 return nil 144 } 145 146 // Delete deletes a value in documentdbcache. 147 func (doc *DocumentDBCache) Delete(ctx context.Context, key string) error { 148 _, err := doc.MongoDBDatabase.Collection(doc.CollectionName).DeleteOne(ctx, bson.M{"key": key}) 149 if err != nil { 150 return berror.Wrapf(err, MemCacheCurdFailed, 151 "could not delete key-value from memcache, key: %s", key) 152 } 153 return nil 154 } 155 156 // Incr increases counter. 157 func (doc *DocumentDBCache) Incr(ctx context.Context, key string) error { 158 return nil 159 } 160 161 // Decr decreases counter. 162 func (doc *DocumentDBCache) Decr(ctx context.Context, key string) error { 163 return nil 164 } 165 166 // IsExist checks if a value exists in documentdbcache. 167 func (doc *DocumentDBCache) IsExist(ctx context.Context, key string) (bool, error) { 168 var item Item 169 err := doc.MongoDBDatabase.Collection(doc.CollectionName).FindOne(ctx, bson.M{"key": key}).Decode(&item) 170 if err == nil { 171 return true, nil 172 } else { 173 return false, berror.Wrapf(err, MemCacheCurdFailed, 174 "could not read data from memcache, please check your key, network and connection. Root cause: %s", 175 err.Error()) 176 } 177 178 } 179 180 // ClearAll clears all cache in documentdbcache. 181 func (doc *DocumentDBCache) ClearAll(context.Context) error { 182 doc.MongoDBDatabase.Collection(doc.CollectionName).Drop(context.Background()) 183 return nil 184 } 185 186 // StartAndGC starts the documentdbcache adapter. 187 // config: must be in the format {"conn":"connection info"}. 188 // If an error occurs during connecting, an error is returned 189 func (doc *DocumentDBCache) StartAndGC(config string) error { 190 doc.iLog = logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "Cache: DocumentDB"} 191 var err error 192 193 var cf map[string]string 194 if err := json.Unmarshal([]byte(config), &cf); err != nil { 195 doc.iLog.Critical(fmt.Sprintf("could not unmarshal this config, it must be valid json stringP: %s with error %s", config, err)) 196 return berror.Wrapf(err, InvalidMemCacheCfg, 197 "could not unmarshal this config, it must be valid json stringP: %s", config) 198 } 199 200 if _, ok := cf["conn"]; !ok { 201 return berror.Errorf(InvalidMemCacheCfg, `config must contains "conn" field: %s`, config) 202 } 203 204 doc.MongoDBClient, err = mongo.NewClient(options.Client().ApplyURI(cf["conn"])) 205 206 if err != nil { 207 doc.iLog.Critical(fmt.Sprintf("failed to connect mongodb with error: %s", err)) 208 } 209 210 if com.MongoDBClients == nil { 211 com.MongoDBClients = make([]*mongo.Client, 0) 212 } 213 214 com.MongoDBClients = append(com.MongoDBClients, doc.MongoDBClient) 215 216 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 217 218 defer cancel() 219 220 err = doc.MongoDBClient.Connect(ctx) 221 222 if err != nil { 223 doc.iLog.Critical(fmt.Sprintf("failed to connect mongodb with error: %s", err)) 224 return berror.Errorf(InvalidMemCacheCfg, `cannot connec tto mondodbwith configuration: %s`, config) 225 } 226 if _, ok := cf["db"]; !ok { 227 return berror.Errorf(InvalidMemCacheCfg, `config must contains "db" field: %s`, config) 228 } 229 doc.MongoDBDatabase = doc.MongoDBClient.Database(cf["db"]) 230 if _, ok := cf["collection"]; !ok { 231 return berror.Errorf(InvalidMemCacheCfg, `config must contains "collection" field: %s`, config) 232 } 233 234 doc.CollectionName = cf["collection"] 235 doc.RemoveExpired(ctx) 236 return nil 237 } 238 239 func init() { 240 Register("documentdb", NewDocumentDBCache) 241 }