github.com/cs3org/reva/v2@v2.27.7/pkg/store/store.go (about) 1 // Copyright 2018-2023 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package store 20 21 import ( 22 "context" 23 "strings" 24 "time" 25 26 "github.com/cs3org/reva/v2/pkg/store/etcd" 27 "github.com/cs3org/reva/v2/pkg/store/memory" 28 natsjs "github.com/go-micro/plugins/v4/store/nats-js" 29 natsjskv "github.com/go-micro/plugins/v4/store/nats-js-kv" 30 "github.com/go-micro/plugins/v4/store/redis" 31 redisopts "github.com/go-redis/redis/v8" 32 "github.com/nats-io/nats.go" 33 "go-micro.dev/v4/logger" 34 microstore "go-micro.dev/v4/store" 35 ) 36 37 var ocMemStore *microstore.Store 38 39 const ( 40 // TypeMemory represents memory stores 41 TypeMemory = "memory" 42 // TypeNoop represents noop stores 43 TypeNoop = "noop" 44 // TypeEtcd represents etcd stores 45 TypeEtcd = "etcd" 46 // TypeRedis represents redis stores 47 TypeRedis = "redis" 48 // TypeRedisSentinel represents redis-sentinel stores 49 TypeRedisSentinel = "redis-sentinel" 50 // TypeOCMem represents ocmem stores 51 TypeOCMem = "ocmem" 52 // TypeNatsJS represents nats-js stores 53 TypeNatsJS = "nats-js" 54 // TypeNatsJSKV represents nats-js-kv stores 55 TypeNatsJSKV = "nats-js-kv" 56 ) 57 58 // Create initializes a new store 59 func Create(opts ...microstore.Option) microstore.Store { 60 options := µstore.Options{ 61 Context: context.Background(), 62 } 63 for _, o := range opts { 64 o(options) 65 } 66 67 storeType, _ := options.Context.Value(typeContextKey{}).(string) 68 69 switch storeType { 70 case TypeNoop: 71 return microstore.NewNoopStore(opts...) 72 case TypeEtcd: 73 return etcd.NewStore(opts...) 74 case TypeRedis: 75 // FIXME redis plugin does not support redis cluster or ring -> needs upstream patch or our implementation 76 return redis.NewStore(opts...) 77 case TypeRedisSentinel: 78 redisMaster := "" 79 redisNodes := []string{} 80 for _, node := range options.Nodes { 81 parts := strings.SplitN(node, "/", 2) 82 if len(parts) != 2 { 83 return nil 84 } 85 // the first node is used to retrieve the redis master 86 redisNodes = append(redisNodes, parts[0]) 87 if redisMaster == "" { 88 redisMaster = parts[1] 89 } 90 } 91 return redis.NewStore( 92 microstore.Database(options.Database), 93 microstore.Table(options.Table), 94 microstore.Nodes(redisNodes...), 95 redis.WithRedisOptions(redisopts.UniversalOptions{ 96 MasterName: redisMaster, 97 }), 98 ) 99 case TypeOCMem: 100 if ocMemStore == nil { 101 var memStore microstore.Store 102 103 sizeNum, _ := options.Context.Value(sizeContextKey{}).(int) 104 if sizeNum <= 0 { 105 memStore = memory.NewMultiMemStore() 106 } else { 107 memStore = memory.NewMultiMemStore( 108 microstore.WithContext( 109 memory.NewContext( 110 context.Background(), 111 map[string]interface{}{ 112 "maxCap": sizeNum, 113 }, 114 )), 115 ) 116 } 117 ocMemStore = &memStore 118 } 119 return *ocMemStore 120 case TypeNatsJS: 121 ttl, _ := options.Context.Value(ttlContextKey{}).(time.Duration) 122 if mem, _ := options.Context.Value(disablePersistanceContextKey{}).(bool); mem { 123 opts = append(opts, natsjs.DefaultMemory()) 124 } 125 // TODO nats needs a DefaultTTL option as it does not support per Write TTL ... 126 // FIXME nats has restrictions on the key, we cannot use slashes AFAICT 127 // host, port, clusterid 128 natsOptions := nats.GetDefaultOptions() 129 natsOptions.Name = "TODO" // we can pass in the service name to allow identifying the client, but that requires adding a custom context option 130 if auth, ok := options.Context.Value(authenticationContextKey{}).([]string); ok && len(auth) == 2 { 131 natsOptions.User = auth[0] 132 natsOptions.Password = auth[1] 133 } 134 return natsjs.NewStore( 135 append(opts, 136 natsjs.NatsOptions(natsOptions), // always pass in properly initialized default nats options 137 natsjs.DefaultTTL(ttl))..., 138 ) // TODO test with ocis nats 139 case TypeNatsJSKV: 140 // NOTE: nats needs a DefaultTTL option as it does not support per Write TTL ... 141 ttl, _ := options.Context.Value(ttlContextKey{}).(time.Duration) 142 if mem, _ := options.Context.Value(disablePersistanceContextKey{}).(bool); mem { 143 opts = append(opts, natsjskv.DefaultMemory()) 144 } 145 146 natsOptions := nats.GetDefaultOptions() 147 natsOptions.Name = "TODO" // we can pass in the service name to allow identifying the client, but that requires adding a custom context option 148 if auth, ok := options.Context.Value(authenticationContextKey{}).([]string); ok && len(auth) == 2 { 149 natsOptions.User = auth[0] 150 natsOptions.Password = auth[1] 151 } 152 return natsjskv.NewStore( 153 append(opts, 154 natsjskv.NatsOptions(natsOptions), // always pass in properly initialized default nats options 155 natsjskv.EncodeKeys(), 156 natsjskv.DefaultTTL(ttl))..., 157 ) 158 case TypeMemory, "mem", "": // allow existing short form and use as default 159 return microstore.NewMemoryStore(opts...) 160 default: 161 // try to log an error 162 if options.Logger == nil { 163 options.Logger = logger.DefaultLogger 164 } 165 options.Logger.Logf(logger.ErrorLevel, "unknown store type: '%s', falling back to memory", storeType) 166 return microstore.NewMemoryStore(opts...) 167 } 168 }