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  }