├── .gitattributes ├── .gitignore ├── README.md ├── adapter ├── adapter_redis.go └── adapter_redis_test.go ├── go.mod └── go.sum /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=GO 2 | *.css linguist-language=GO 3 | *.html linguist-language=GO -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .hgignore.swp 3 | .project 4 | .orig 5 | .swp 6 | .idea/ 7 | .settings/ 8 | .vscode/ 9 | vendor/ 10 | composer.lock 11 | gitpush.sh 12 | pkg/ 13 | bin/ 14 | cbuild 15 | **/.DS_Store 16 | .vscode/ 17 | .example/other/ 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gcache-adapter 2 | Adapters for package gcache. 3 | 4 | ## Requirements 5 | 6 | ```shell script 7 | gf version >= v1.14.0 8 | ``` 9 | > Or using the `master` branch. 10 | 11 | 12 | 13 | ## Installation 14 | 15 | ```shell script 16 | go get -u github.com/gogf/gcache-adapter 17 | ``` 18 | 19 | ## Usage 20 | 21 | ### Import 22 | ```go 23 | import "github.com/gogf/gcache-adapter/adapter" 24 | ``` 25 | 26 | ### Normal Cache 27 | 28 | ```go 29 | cache := gcache.New() 30 | adapter := adapter.NewRedis(g.Redis()) 31 | cache.SetAdapter(adapter) 32 | ``` 33 | 34 | ### Change Database Cache From In-Memory To Redis 35 | ```go 36 | adapter := adapter.NewRedis(g.Redis()) 37 | g.DB().GetCache().SetAdapter(adapter) 38 | ``` 39 | -------------------------------------------------------------------------------- /adapter/adapter_redis.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. 2 | // 3 | // This Source Code Form is subject to the terms of the MIT License. 4 | // If a copy of the MIT was not distributed with this file, 5 | // You can obtain one at https://github.com/gogf/gf. 6 | 7 | package adapter 8 | 9 | import ( 10 | "context" 11 | "time" 12 | 13 | "github.com/gogf/gf/container/gvar" 14 | "github.com/gogf/gf/database/gredis" 15 | "github.com/gogf/gf/os/gcache" 16 | ) 17 | 18 | // Redis is the gcache adapter implements using Redis server. 19 | type Redis struct { 20 | redis *gredis.Redis 21 | } 22 | 23 | // NewRedis newAdapterMemory creates and returns a new memory cache object. 24 | func NewRedis(redis *gredis.Redis) gcache.Adapter { 25 | return &Redis{ 26 | redis: redis, 27 | } 28 | } 29 | 30 | // Set sets cache with - pair, which is expired after . 31 | // It does not expire if == 0. 32 | // It deletes the if < 0 or given is nil. 33 | func (c *Redis) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error { 34 | var err error 35 | if value == nil || duration < 0 { 36 | _, err = c.redis.Ctx(ctx).DoVar("DEL", key) 37 | } else { 38 | if duration == 0 { 39 | _, err = c.redis.Ctx(ctx).DoVar("SET", key, value) 40 | } else { 41 | _, err = c.redis.Ctx(ctx).DoVar("SETEX", key, uint64(duration.Seconds()), value) 42 | } 43 | } 44 | return err 45 | } 46 | 47 | // Update updates the value of without changing its expiration and returns the old value. 48 | // The returned value is false if the does not exist in the cache. 49 | // 50 | // It deletes the if given is nil. 51 | // It does nothing if does not exist in the cache. 52 | func (c *Redis) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) { 53 | var ( 54 | v *gvar.Var 55 | oldDuration time.Duration 56 | ) 57 | // TTL. 58 | v, err = c.redis.Ctx(ctx).DoVar("TTL", key) 59 | if err != nil { 60 | return 61 | } 62 | oldDuration = v.Duration() 63 | if oldDuration == -2 { 64 | // It does not exist. 65 | return 66 | } 67 | // Check existence. 68 | v, err = c.redis.Ctx(ctx).DoVar("GET", key) 69 | if err != nil { 70 | return 71 | } 72 | oldValue = v 73 | // DEL. 74 | if value == nil { 75 | _, err = c.redis.Ctx(ctx).DoVar("DEL", key) 76 | if err != nil { 77 | return 78 | } 79 | return 80 | } 81 | // Update the value. 82 | if oldDuration == -1 { 83 | _, err = c.redis.Ctx(ctx).DoVar("SET", key, value) 84 | } else { 85 | oldDuration *= time.Second 86 | _, err = c.redis.Ctx(ctx).DoVar("SETEX", key, uint64(oldDuration.Seconds()), value) 87 | } 88 | return oldValue, true, err 89 | } 90 | 91 | // UpdateExpire updates the expiration of and returns the old expiration duration value. 92 | // 93 | // It returns -1 if the does not exist in the cache. 94 | // It deletes the if < 0. 95 | func (c *Redis) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { 96 | var ( 97 | v *gvar.Var 98 | ) 99 | // TTL. 100 | v, err = c.redis.Ctx(ctx).DoVar("TTL", key) 101 | if err != nil { 102 | return 103 | } 104 | oldDuration = v.Duration() 105 | if oldDuration == -2 { 106 | // It does not exist. 107 | oldDuration = -1 108 | return 109 | } 110 | oldDuration *= time.Second 111 | // DEL. 112 | if duration < 0 { 113 | _, err = c.redis.Ctx(ctx).Do("DEL", key) 114 | return 115 | } 116 | // Update the expire. 117 | if duration > 0 { 118 | _, err = c.redis.Ctx(ctx).Do("EXPIRE", key, uint64(duration.Seconds())) 119 | } 120 | // No expire. 121 | if duration == 0 { 122 | v, err = c.redis.Ctx(ctx).DoVar("GET", key) 123 | if err != nil { 124 | return 125 | } 126 | _, err = c.redis.Ctx(ctx).Do("SET", key, v.Val()) 127 | } 128 | return 129 | } 130 | 131 | // GetExpire retrieves and returns the expiration of in the cache. 132 | // 133 | // It returns 0 if the does not expire. 134 | // It returns -1 if the does not exist in the cache. 135 | func (c *Redis) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) { 136 | v, err := c.redis.Ctx(ctx).DoVar("TTL", key) 137 | if err != nil { 138 | return 0, err 139 | } 140 | switch v.Int() { 141 | case -1: 142 | return 0, nil 143 | case -2: 144 | return -1, nil 145 | default: 146 | return v.Duration() * time.Second, nil 147 | } 148 | } 149 | 150 | // SetIfNotExist sets cache with - pair which is expired after 151 | // if does not exist in the cache. It returns true the dose not exist in the 152 | // cache and it sets successfully to the cache, or else it returns false. 153 | // 154 | // The parameter can be type of , but it dose nothing if its 155 | // result is nil. 156 | // 157 | // It does not expire if == 0. 158 | // It deletes the if < 0 or given is nil. 159 | func (c *Redis) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) { 160 | var err error 161 | // Execute the function and retrieve the result. 162 | if f, ok := value.(func() (interface{}, error)); ok { 163 | value, err = f() 164 | if value == nil { 165 | return false, err 166 | } 167 | } 168 | // DEL. 169 | if duration < 0 || value == nil { 170 | v, err := c.redis.Ctx(ctx).DoVar("DEL", key, value) 171 | if err != nil { 172 | return false, err 173 | } 174 | if v.Int() == 1 { 175 | return true, err 176 | } else { 177 | return false, err 178 | } 179 | } 180 | v, err := c.redis.Ctx(ctx).DoVar("SETNX", key, value) 181 | if err != nil { 182 | return false, err 183 | } 184 | if v.Int() > 0 && duration > 0 { 185 | // Set the expire. 186 | _, err := c.redis.Ctx(ctx).Do("EXPIRE", key, uint64(duration.Seconds())) 187 | if err != nil { 188 | return false, err 189 | } 190 | return true, err 191 | } 192 | return false, err 193 | } 194 | 195 | // SetIfNotExistFunc sets `key` with result of function `f` and returns true 196 | // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. 197 | // 198 | // The parameter `value` can be type of `func() interface{}`, but it does nothing if its 199 | // result is nil. 200 | // 201 | // It does not expire if `duration` == 0. 202 | // It deletes the `key` if `duration` < 0 or given `value` is nil. 203 | func (c *Redis) SetIfNotExistFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (ok bool, err error) { 204 | v, err := c.Get(ctx, key) 205 | if err != nil { 206 | return false, err 207 | } 208 | if v == nil { 209 | value, err := f() 210 | if err != nil { 211 | return false, err 212 | } 213 | if value == nil { 214 | return false, nil 215 | } 216 | return true, c.Set(ctx, key, value, duration) 217 | } else { 218 | return false, nil 219 | } 220 | } 221 | 222 | // SetIfNotExistFuncLock sets `key` with result of function `f` and returns true 223 | // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. 224 | // 225 | // It does not expire if `duration` == 0. 226 | // It deletes the `key` if `duration` < 0 or given `value` is nil. 227 | // 228 | // Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within 229 | // writing mutex lock for concurrent safety purpose. 230 | func (c *Redis) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (ok bool, err error) { 231 | return c.SetIfNotExistFunc(ctx, key, f, duration) 232 | } 233 | 234 | // Sets batch sets cache with key-value pairs by , which is expired after . 235 | // 236 | // It does not expire if == 0. 237 | // It deletes the keys of if < 0 or given is nil. 238 | func (c *Redis) Sets(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error { 239 | if len(data) == 0 { 240 | return nil 241 | } 242 | // DEL. 243 | if duration < 0 { 244 | var ( 245 | index = 0 246 | keys = make([]interface{}, len(data)) 247 | ) 248 | for k, _ := range data { 249 | keys[index] = k 250 | index += 1 251 | } 252 | _, err := c.redis.Ctx(ctx).Do("DEL", keys...) 253 | if err != nil { 254 | return err 255 | } 256 | } 257 | if duration == 0 { 258 | var ( 259 | index = 0 260 | keyValues = make([]interface{}, len(data)*2) 261 | ) 262 | for k, v := range data { 263 | keyValues[index] = k 264 | keyValues[index+1] = v 265 | index += 2 266 | } 267 | _, err := c.redis.Ctx(ctx).Do("MSET", keyValues...) 268 | if err != nil { 269 | return err 270 | } 271 | } 272 | if duration > 0 { 273 | var err error 274 | for k, v := range data { 275 | if err = c.Set(ctx, k, v, duration); err != nil { 276 | return err 277 | } 278 | } 279 | } 280 | return nil 281 | } 282 | 283 | // Get retrieves and returns the associated value of given . 284 | // It returns nil if it does not exist or its value is nil. 285 | func (c *Redis) Get(ctx context.Context, key interface{}) (*gvar.Var, error) { 286 | v, err := c.redis.Ctx(ctx).DoVar("GET", key) 287 | if err != nil { 288 | return nil, err 289 | } 290 | return v, nil 291 | } 292 | 293 | // GetOrSet retrieves and returns the value of , or sets - pair and 294 | // returns if does not exist in the cache. The key-value pair expires 295 | // after . 296 | // 297 | // It does not expire if == 0. 298 | // It deletes the if < 0 or given is nil, but it does nothing 299 | // if is a function and the function result is nil. 300 | func (c *Redis) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) { 301 | v, err := c.Get(ctx, key) 302 | if err != nil { 303 | return nil, err 304 | } 305 | if v == nil { 306 | return gvar.New(value), c.Set(ctx, key, value, duration) 307 | } else { 308 | return v, nil 309 | } 310 | } 311 | 312 | // GetOrSetFunc retrieves and returns the value of , or sets with result of 313 | // function and returns its result if does not exist in the cache. The key-value 314 | // pair expires after . 315 | // 316 | // It does not expire if == 0. 317 | // It deletes the if < 0 or given is nil, but it does nothing 318 | // if is a function and the function result is nil. 319 | func (c *Redis) GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { 320 | v, err := c.Get(ctx, key) 321 | if err != nil { 322 | return nil, err 323 | } 324 | if v == nil { 325 | value, err := f() 326 | if err != nil { 327 | return nil, err 328 | } 329 | if value == nil { 330 | return nil, nil 331 | } 332 | return gvar.New(value), c.Set(ctx, key, value, duration) 333 | } else { 334 | return v, nil 335 | } 336 | } 337 | 338 | // GetOrSetFuncLock retrieves and returns the value of , or sets with result of 339 | // function and returns its result if does not exist in the cache. The key-value 340 | // pair expires after . 341 | // 342 | // It does not expire if == 0. 343 | // It does nothing if function returns nil. 344 | // 345 | // Note that the function should be executed within writing mutex lock for concurrent 346 | // safety purpose. 347 | func (c *Redis) GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { 348 | return c.GetOrSetFunc(ctx, key, f, duration) 349 | } 350 | 351 | // Contains returns true if exists in the cache, or else returns false. 352 | func (c *Redis) Contains(ctx context.Context, key interface{}) (bool, error) { 353 | v, err := c.redis.Ctx(ctx).DoVar("EXISTS", key) 354 | if err != nil { 355 | return false, err 356 | } 357 | return v.Bool(), nil 358 | } 359 | 360 | // Remove deletes the one or more keys from cache, and returns its value. 361 | // If multiple keys are given, it returns the value of the deleted last item. 362 | func (c *Redis) Remove(ctx context.Context, keys ...interface{}) (value *gvar.Var, err error) { 363 | if len(keys) == 0 { 364 | return nil, nil 365 | } 366 | // Retrieves the last key value. 367 | if v, err := c.redis.Ctx(ctx).DoVar("GET", keys[len(keys)-1]); err != nil { 368 | return nil, err 369 | } else { 370 | value = v 371 | } 372 | // Deletes all given keys. 373 | _, err = c.redis.Ctx(ctx).DoVar("DEL", keys...) 374 | return value, err 375 | } 376 | 377 | // Data returns a copy of all key-value pairs in the cache as map type. 378 | func (c *Redis) Data(ctx context.Context) (map[interface{}]interface{}, error) { 379 | // Keys. 380 | v, err := c.redis.Ctx(ctx).DoVar("KEYS", "*") 381 | if err != nil { 382 | return nil, err 383 | } 384 | keys := v.Slice() 385 | // Values. 386 | v, err = c.redis.Ctx(ctx).DoVar("MGET", keys...) 387 | if err != nil { 388 | return nil, err 389 | } 390 | values := v.Slice() 391 | // Compose keys and values. 392 | data := make(map[interface{}]interface{}) 393 | for i := 0; i < len(keys); i++ { 394 | data[keys[i]] = values[i] 395 | } 396 | return data, nil 397 | } 398 | 399 | // Keys returns all keys in the cache as slice. 400 | func (c *Redis) Keys(ctx context.Context) ([]interface{}, error) { 401 | v, err := c.redis.Ctx(ctx).DoVar("KEYS", "*") 402 | if err != nil { 403 | return nil, err 404 | } 405 | return v.Slice(), nil 406 | } 407 | 408 | // Values returns all values in the cache as slice. 409 | func (c *Redis) Values(ctx context.Context) ([]interface{}, error) { 410 | // Keys. 411 | v, err := c.redis.Ctx(ctx).DoVar("KEYS", "*") 412 | if err != nil { 413 | return nil, err 414 | } 415 | keys := v.Slice() 416 | // Values. 417 | v, err = c.redis.Ctx(ctx).DoVar("MGET", keys...) 418 | if err != nil { 419 | return nil, err 420 | } 421 | return v.Slice(), nil 422 | } 423 | 424 | // Size returns the size of the cache. 425 | func (c *Redis) Size(ctx context.Context) (size int, err error) { 426 | v, err := c.redis.Ctx(ctx).DoVar("DBSIZE") 427 | if err != nil { 428 | return 0, err 429 | } 430 | return v.Int(), nil 431 | } 432 | 433 | // Clear clears all data of the cache. 434 | // Note that this function is sensitive and should be carefully used. 435 | func (c *Redis) Clear(ctx context.Context) error { 436 | // The "FLUSHDB" may not be available. 437 | if _, err := c.redis.Ctx(ctx).DoVar("FLUSHDB"); err != nil { 438 | keys, err := c.Keys(ctx) 439 | if err != nil { 440 | return err 441 | } 442 | _, err = c.Remove(ctx, keys...) 443 | return err 444 | } 445 | return nil 446 | } 447 | 448 | // Close closes the cache. 449 | func (c *Redis) Close(ctx context.Context) error { 450 | // It does nothing. 451 | return nil 452 | } 453 | -------------------------------------------------------------------------------- /adapter/adapter_redis_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. 2 | // 3 | // This Source Code Form is subject to the terms of the MIT License. 4 | // If a copy of the MIT was not distributed with this file, 5 | // You can obtain one at https://github.com/gogf/gf. 6 | 7 | package adapter_test 8 | 9 | import ( 10 | "context" 11 | "testing" 12 | "time" 13 | 14 | "github.com/gogf/gcache-adapter/adapter" 15 | "github.com/gogf/gf/database/gredis" 16 | "github.com/gogf/gf/os/gcache" 17 | "github.com/gogf/gf/test/gtest" 18 | ) 19 | 20 | var ( 21 | cacheRedis = gcache.New() 22 | redisConfig = &gredis.Config{ 23 | Host: "127.0.0.1", 24 | Port: 6379, 25 | Db: 1, 26 | } 27 | ctx = context.Background() 28 | ) 29 | 30 | func init() { 31 | cacheRedis.SetAdapter(adapter.NewRedis(gredis.New(redisConfig))) 32 | } 33 | 34 | func Test_Basic1(t *testing.T) { 35 | size := 10 36 | 37 | gtest.C(t, func(t *gtest.T) { 38 | for i := 0; i < size; i++ { 39 | cacheRedis.Set(ctx, i, i*10, 0) 40 | } 41 | for i := 0; i < size; i++ { 42 | v, _ := cacheRedis.Get(ctx, i) 43 | t.Assert(v, i*10) 44 | } 45 | n, _ := cacheRedis.Size(ctx) 46 | t.Assert(n, size) 47 | }) 48 | gtest.C(t, func(t *gtest.T) { 49 | data, _ := cacheRedis.Data(ctx) 50 | t.Assert(len(data), size) 51 | t.Assert(data["0"], "0") 52 | t.Assert(data["1"], "10") 53 | t.Assert(data["9"], "90") 54 | }) 55 | gtest.C(t, func(t *gtest.T) { 56 | cacheRedis.Clear(ctx) 57 | n, _ := cacheRedis.Size(ctx) 58 | t.Assert(n, 0) 59 | }) 60 | } 61 | 62 | func Test_Basic2(t *testing.T) { 63 | defer cacheRedis.Clear(ctx) 64 | size := 10 65 | gtest.C(t, func(t *gtest.T) { 66 | for i := 0; i < size; i++ { 67 | cacheRedis.Set(ctx, i, i*10, -1) 68 | } 69 | for i := 0; i < size; i++ { 70 | v, _ := cacheRedis.Get(ctx, i) 71 | t.Assert(v, nil) 72 | } 73 | n, _ := cacheRedis.Size(ctx) 74 | t.Assert(n, 0) 75 | }) 76 | } 77 | 78 | func Test_Basic3(t *testing.T) { 79 | defer cacheRedis.Clear(ctx) 80 | size := 10 81 | gtest.C(t, func(t *gtest.T) { 82 | for i := 0; i < size; i++ { 83 | cacheRedis.Set(ctx, i, i*10, time.Second) 84 | } 85 | for i := 0; i < size; i++ { 86 | v, _ := cacheRedis.Get(ctx, i) 87 | t.Assert(v, i*10) 88 | } 89 | n, _ := cacheRedis.Size(ctx) 90 | t.Assert(n, size) 91 | }) 92 | time.Sleep(time.Second * 2) 93 | gtest.C(t, func(t *gtest.T) { 94 | for i := 0; i < size; i++ { 95 | v, _ := cacheRedis.Get(ctx, i) 96 | t.Assert(v, nil) 97 | } 98 | n, _ := cacheRedis.Size(ctx) 99 | t.Assert(n, 0) 100 | }) 101 | } 102 | 103 | func TestRedis_Update(t *testing.T) { 104 | defer cacheRedis.Clear(ctx) 105 | gtest.C(t, func(t *gtest.T) { 106 | var ( 107 | key = "key" 108 | value1 = "value1" 109 | value2 = "value2" 110 | ) 111 | cacheRedis.Set(ctx, key, value1, time.Second) 112 | v, _ := cacheRedis.Get(ctx, key) 113 | t.Assert(v, value1) 114 | 115 | d, _ := cacheRedis.GetExpire(ctx, key) 116 | t.Assert(d > time.Millisecond*500, true) 117 | t.Assert(d <= time.Second, true) 118 | 119 | cacheRedis.Update(ctx, key, value2) 120 | 121 | v, _ = cacheRedis.Get(ctx, key) 122 | t.Assert(v, value2) 123 | d, _ = cacheRedis.GetExpire(ctx, key) 124 | t.Assert(d > time.Millisecond*500, true) 125 | t.Assert(d <= time.Second, true) 126 | }) 127 | } 128 | 129 | func TestRedis_UpdateExpire(t *testing.T) { 130 | defer cacheRedis.Clear(ctx) 131 | gtest.C(t, func(t *gtest.T) { 132 | var ( 133 | key = "key" 134 | value = "value" 135 | ) 136 | cacheRedis.Set(ctx, key, value, time.Second) 137 | v, _ := cacheRedis.Get(ctx, key) 138 | t.Assert(v, value) 139 | 140 | d, _ := cacheRedis.GetExpire(ctx, key) 141 | t.Assert(d > time.Millisecond*500, true) 142 | t.Assert(d <= time.Second, true) 143 | 144 | cacheRedis.UpdateExpire(ctx, key, time.Second*2) 145 | 146 | d, _ = cacheRedis.GetExpire(ctx, key) 147 | t.Assert(d > time.Second, true) 148 | t.Assert(d <= 2*time.Second, true) 149 | }) 150 | } 151 | 152 | func TestRedis_SetIfNotExist(t *testing.T) { 153 | defer cacheRedis.Clear(ctx) 154 | gtest.C(t, func(t *gtest.T) { 155 | var ( 156 | key = "key" 157 | value1 = "value1" 158 | value2 = "value2" 159 | ) 160 | cacheRedis.Set(ctx, key, value1, time.Second) 161 | v, _ := cacheRedis.Get(ctx, key) 162 | t.Assert(v, value1) 163 | 164 | r, _ := cacheRedis.SetIfNotExist(ctx, key, value2, time.Second*2) 165 | 166 | t.Assert(r, false) 167 | 168 | v, _ = cacheRedis.Get(ctx, key) 169 | t.Assert(v, value1) 170 | 171 | d, _ := cacheRedis.GetExpire(ctx, key) 172 | t.Assert(d > time.Millisecond*500, true) 173 | t.Assert(d <= time.Second, true) 174 | }) 175 | } 176 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gogf/gcache-adapter 2 | 3 | go 1.11 4 | 5 | require ( 6 | github.com/gogf/gf v1.16.7-0.20210917112656-01a3dd1eb070 7 | github.com/mattn/go-runewidth v0.0.10 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= 2 | github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 3 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4= 4 | github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= 5 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= 8 | github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 9 | github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= 10 | github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= 11 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 12 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 13 | github.com/gogf/gf v1.16.7-0.20210917112656-01a3dd1eb070 h1:m6Ks0rx/UbPG0Hr7GiCa1LxUutv/UD6ZZhv7z2QWqIQ= 14 | github.com/gogf/gf v1.16.7-0.20210917112656-01a3dd1eb070/go.mod h1:wBQx7fxaYfYXvlSeoQ6yYIsMv8ein1UxNZ1flUadhb8= 15 | github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= 16 | github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= 17 | github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= 18 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 19 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 20 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 21 | github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf h1:wIOAyJMMen0ELGiFzlmqxdcV1yGbkyHBAB6PolcNbLA= 22 | github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= 23 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 24 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 25 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 26 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 27 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 28 | github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= 29 | github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= 30 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 31 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 32 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 33 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 34 | github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= 35 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 36 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 37 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 38 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 39 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 40 | go.opentelemetry.io/otel v1.0.0-RC3 h1:kvwiyEkiUT/JaadXzVLI/R1wDO934A7r3Bs2wEe6wqA= 41 | go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ= 42 | go.opentelemetry.io/otel/oteltest v1.0.0-RC3 h1:MjaeegZTaX0Bv9uB9CrdVjOFM/8slRjReoWoV9xDCpY= 43 | go.opentelemetry.io/otel/oteltest v1.0.0-RC3/go.mod h1:xpzajI9JBRr7gX63nO6kAmImmYIAtuQblZ36Z+LfCjE= 44 | go.opentelemetry.io/otel/trace v1.0.0-RC3 h1:9F0ayEvlxv8BmNmPbU005WK7hC+7KbOazCPZjNa1yME= 45 | go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo= 46 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= 47 | golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 48 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 49 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 50 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 51 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 52 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= 53 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 54 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 55 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 56 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 57 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 58 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 59 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 60 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 61 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 62 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 63 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 64 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 65 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 66 | --------------------------------------------------------------------------------