github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/rpc_storage_handler.go (about)

     1  package gateway
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"time"
     7  
     8  	cache "github.com/pmylund/go-cache"
     9  
    10  	"github.com/TykTechnologies/tyk/rpc"
    11  
    12  	"github.com/garyburd/redigo/redis"
    13  
    14  	"github.com/TykTechnologies/tyk/config"
    15  	"github.com/TykTechnologies/tyk/storage"
    16  
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  type InboundData struct {
    21  	KeyName      string
    22  	Value        string
    23  	SessionState string
    24  	Timeout      int64
    25  	Per          int64
    26  	Expire       int64
    27  }
    28  
    29  type DefRequest struct {
    30  	OrgId string
    31  	Tags  []string
    32  }
    33  
    34  type KeysValuesPair struct {
    35  	Keys   []string
    36  	Values []string
    37  }
    38  
    39  type GroupLoginRequest struct {
    40  	UserKey string
    41  	GroupID string
    42  }
    43  
    44  type GroupKeySpaceRequest struct {
    45  	OrgID   string
    46  	GroupID string
    47  }
    48  
    49  var (
    50  	dispatcherFuncs = map[string]interface{}{
    51  		"Login": func(clientAddr, userKey string) bool {
    52  			return false
    53  		},
    54  		"LoginWithGroup": func(clientAddr string, groupData *GroupLoginRequest) bool {
    55  			return false
    56  		},
    57  		"GetKey": func(keyName string) (string, error) {
    58  			return "", nil
    59  		},
    60  		"SetKey": func(ibd *InboundData) error {
    61  			return nil
    62  		},
    63  		"GetExp": func(keyName string) (int64, error) {
    64  			return 0, nil
    65  		},
    66  		"GetKeys": func(keyName string) ([]string, error) {
    67  			return nil, nil
    68  		},
    69  		"DeleteKey": func(keyName string) (bool, error) {
    70  			return true, nil
    71  		},
    72  		"DeleteRawKey": func(keyName string) (bool, error) {
    73  			return true, nil
    74  		},
    75  		"GetKeysAndValues": func(searchString string) (*KeysValuesPair, error) {
    76  			return nil, nil
    77  		},
    78  		"GetKeysAndValuesWithFilter": func(searchString string) (*KeysValuesPair, error) {
    79  			return nil, nil
    80  		},
    81  		"DeleteKeys": func(keys []string) (bool, error) {
    82  			return true, nil
    83  		},
    84  		"Decrement": func(keyName string) error {
    85  			return nil
    86  		},
    87  		"IncrememntWithExpire": func(ibd *InboundData) (int64, error) {
    88  			return 0, nil
    89  		},
    90  		"AppendToSet": func(ibd *InboundData) error {
    91  			return nil
    92  		},
    93  		"SetRollingWindow": func(ibd *InboundData) (int, error) {
    94  			return 0, nil
    95  		},
    96  		"GetApiDefinitions": func(dr *DefRequest) (string, error) {
    97  			return "", nil
    98  		},
    99  		"GetPolicies": func(orgId string) (string, error) {
   100  			return "", nil
   101  		},
   102  		"PurgeAnalyticsData": func(data string) error {
   103  			return nil
   104  		},
   105  		"CheckReload": func(clientAddr, orgId string) (bool, error) {
   106  			return false, nil
   107  		},
   108  		"GetKeySpaceUpdate": func(clientAddr, orgId string) ([]string, error) {
   109  			return nil, nil
   110  		},
   111  		"GetGroupKeySpaceUpdate": func(clientAddr string, groupData *GroupKeySpaceRequest) ([]string, error) {
   112  			return nil, nil
   113  		},
   114  		"Ping": func() bool {
   115  			return false
   116  		},
   117  	}
   118  )
   119  
   120  // RPCStorageHandler is a storage manager that uses the redis database.
   121  type RPCStorageHandler struct {
   122  	KeyPrefix        string
   123  	HashKeys         bool
   124  	SuppressRegister bool
   125  }
   126  
   127  var RPCGlobalCache = cache.New(30*time.Second, 15*time.Second)
   128  
   129  // Connect will establish a connection to the RPC
   130  func (r *RPCStorageHandler) Connect() bool {
   131  	slaveOptions := config.Global().SlaveOptions
   132  	rpcConfig := rpc.Config{
   133  		UseSSL:                slaveOptions.UseSSL,
   134  		SSLInsecureSkipVerify: slaveOptions.SSLInsecureSkipVerify,
   135  		ConnectionString:      slaveOptions.ConnectionString,
   136  		RPCKey:                slaveOptions.RPCKey,
   137  		APIKey:                slaveOptions.APIKey,
   138  		GroupID:               slaveOptions.GroupID,
   139  		CallTimeout:           slaveOptions.CallTimeout,
   140  		PingTimeout:           slaveOptions.PingTimeout,
   141  		RPCPoolSize:           slaveOptions.RPCPoolSize,
   142  	}
   143  
   144  	return rpc.Connect(
   145  		rpcConfig,
   146  		r.SuppressRegister,
   147  		dispatcherFuncs,
   148  		func(userKey string, groupID string) interface{} {
   149  			return GroupLoginRequest{
   150  				UserKey: userKey,
   151  				GroupID: groupID,
   152  			}
   153  		},
   154  		func() {
   155  			reloadURLStructure(nil)
   156  		},
   157  		doReload,
   158  	)
   159  }
   160  
   161  func (r *RPCStorageHandler) hashKey(in string) string {
   162  	if !r.HashKeys {
   163  		// Not hashing? Return the raw key
   164  		return in
   165  	}
   166  	return storage.HashStr(in)
   167  }
   168  
   169  func (r *RPCStorageHandler) fixKey(keyName string) string {
   170  	setKeyName := r.KeyPrefix + r.hashKey(keyName)
   171  
   172  	log.Debug("Input key was: ", setKeyName)
   173  
   174  	return setKeyName
   175  }
   176  
   177  func (r *RPCStorageHandler) cleanKey(keyName string) string {
   178  	setKeyName := strings.Replace(keyName, r.KeyPrefix, "", 1)
   179  	return setKeyName
   180  }
   181  
   182  // GetKey will retrieve a key from the database
   183  func (r *RPCStorageHandler) GetKey(keyName string) (string, error) {
   184  	start := time.Now() // get current time
   185  	log.Debug("[STORE] Getting WAS: ", keyName)
   186  	log.Debug("[STORE] Getting: ", r.fixKey(keyName))
   187  
   188  	value, err := r.GetRawKey(r.fixKey(keyName))
   189  
   190  	elapsed := time.Since(start)
   191  	log.Debug("GetKey took ", elapsed)
   192  
   193  	return value, err
   194  }
   195  
   196  func (r *RPCStorageHandler) GetRawKey(keyName string) (string, error) {
   197  	// Check the cache first
   198  	if config.Global().SlaveOptions.EnableRPCCache {
   199  		log.Debug("Using cache for: ", keyName)
   200  		cachedVal, found := RPCGlobalCache.Get(keyName)
   201  		log.Debug("--> Found? ", found)
   202  		if found {
   203  			return cachedVal.(string), nil
   204  		}
   205  	}
   206  
   207  	value, err := rpc.FuncClientSingleton("GetKey", keyName)
   208  	if err != nil {
   209  		rpc.EmitErrorEventKv(
   210  			rpc.FuncClientSingletonCall,
   211  			"GetKey",
   212  			err,
   213  			map[string]string{
   214  				"keyName": keyName,
   215  			},
   216  		)
   217  		if r.IsAccessError(err) {
   218  			if rpc.Login() {
   219  				return r.GetRawKey(keyName)
   220  			}
   221  		}
   222  		log.Debug("Error trying to get value:", err)
   223  		return "", storage.ErrKeyNotFound
   224  	}
   225  	if config.Global().SlaveOptions.EnableRPCCache {
   226  		// Cache key
   227  		RPCGlobalCache.Set(keyName, value, cache.DefaultExpiration)
   228  	}
   229  	//return hash key without prefix so it doesnt get double prefixed in redis
   230  	return value.(string), nil
   231  }
   232  
   233  func (r *RPCStorageHandler) GetExp(keyName string) (int64, error) {
   234  	log.Debug("GetExp called")
   235  	value, err := rpc.FuncClientSingleton("GetExp", r.fixKey(keyName))
   236  	if err != nil {
   237  		rpc.EmitErrorEventKv(
   238  			rpc.FuncClientSingletonCall,
   239  			"GetExp",
   240  			err,
   241  			map[string]string{
   242  				"keyName":      keyName,
   243  				"fixedKeyName": r.fixKey(keyName),
   244  			},
   245  		)
   246  		if r.IsAccessError(err) {
   247  			if rpc.Login() {
   248  				return r.GetExp(keyName)
   249  			}
   250  		}
   251  		log.Error("Error trying to get TTL: ", err)
   252  		return 0, storage.ErrKeyNotFound
   253  	}
   254  	return value.(int64), nil
   255  }
   256  
   257  func (r *RPCStorageHandler) SetExp(keyName string, timeout int64) error {
   258  	log.Error("RPCStorageHandler.SetExp - Not Implemented")
   259  	return nil
   260  }
   261  
   262  // SetKey will create (or update) a key value in the store
   263  func (r *RPCStorageHandler) SetKey(keyName, session string, timeout int64) error {
   264  	start := time.Now() // get current time
   265  	ibd := InboundData{
   266  		KeyName:      r.fixKey(keyName),
   267  		SessionState: session,
   268  		Timeout:      timeout,
   269  	}
   270  
   271  	_, err := rpc.FuncClientSingleton("SetKey", ibd)
   272  	if err != nil {
   273  		rpc.EmitErrorEventKv(
   274  			rpc.FuncClientSingletonCall,
   275  			"SetKey",
   276  			err,
   277  			map[string]string{
   278  				"keyName":      keyName,
   279  				"fixedKeyName": ibd.KeyName,
   280  			},
   281  		)
   282  
   283  		if r.IsAccessError(err) {
   284  			if rpc.Login() {
   285  				return r.SetKey(keyName, session, timeout)
   286  			}
   287  		}
   288  
   289  		log.Debug("Error trying to set value:", err)
   290  		return err
   291  	}
   292  
   293  	elapsed := time.Since(start)
   294  	log.Debug("SetKey took ", elapsed)
   295  	return nil
   296  
   297  }
   298  
   299  func (r *RPCStorageHandler) SetRawKey(keyName, session string, timeout int64) error {
   300  	return nil
   301  }
   302  
   303  // Decrement will decrement a key in redis
   304  func (r *RPCStorageHandler) Decrement(keyName string) {
   305  	log.Warning("Decrement called")
   306  	_, err := rpc.FuncClientSingleton("Decrement", keyName)
   307  	if err != nil {
   308  		rpc.EmitErrorEventKv(
   309  			rpc.FuncClientSingletonCall,
   310  			"Decrement",
   311  			err,
   312  			map[string]string{
   313  				"keyName": keyName,
   314  			},
   315  		)
   316  	}
   317  	if r.IsAccessError(err) {
   318  		if rpc.Login() {
   319  			r.Decrement(keyName)
   320  			return
   321  		}
   322  	}
   323  }
   324  
   325  // IncrementWithExpire will increment a key in redis
   326  func (r *RPCStorageHandler) IncrememntWithExpire(keyName string, expire int64) int64 {
   327  
   328  	ibd := InboundData{
   329  		KeyName: keyName,
   330  		Expire:  expire,
   331  	}
   332  
   333  	val, err := rpc.FuncClientSingleton("IncrememntWithExpire", ibd)
   334  	if err != nil {
   335  		rpc.EmitErrorEventKv(
   336  			rpc.FuncClientSingletonCall,
   337  			"IncrememntWithExpire",
   338  			err,
   339  			map[string]string{
   340  				"keyName": keyName,
   341  			},
   342  		)
   343  	}
   344  	if r.IsAccessError(err) {
   345  		if rpc.Login() {
   346  			return r.IncrememntWithExpire(keyName, expire)
   347  		}
   348  	}
   349  
   350  	if val == nil {
   351  		log.Warning("RPC increment returned nil value, returning 0")
   352  		return 0
   353  	}
   354  
   355  	return val.(int64)
   356  
   357  }
   358  
   359  // GetKeys will return all keys according to the filter (filter is a prefix - e.g. tyk.keys.*)
   360  func (r *RPCStorageHandler) GetKeys(filter string) []string {
   361  	log.Error("RPCStorageHandler.GetKeys - Not Implemented")
   362  	return nil
   363  }
   364  
   365  // GetKeysAndValuesWithFilter will return all keys and their values with a filter
   366  func (r *RPCStorageHandler) GetKeysAndValuesWithFilter(filter string) map[string]string {
   367  
   368  	searchStr := r.KeyPrefix + r.hashKey(filter) + "*"
   369  	log.Debug("[STORE] Getting list by: ", searchStr)
   370  
   371  	kvPair, err := rpc.FuncClientSingleton("GetKeysAndValuesWithFilter", searchStr)
   372  	if err != nil {
   373  		rpc.EmitErrorEventKv(
   374  			rpc.FuncClientSingletonCall,
   375  			"GetKeysAndValuesWithFilter",
   376  			err,
   377  			map[string]string{
   378  				"searchStr": searchStr,
   379  			},
   380  		)
   381  
   382  		if r.IsAccessError(err) {
   383  			if rpc.Login() {
   384  				return r.GetKeysAndValuesWithFilter(filter)
   385  			}
   386  		}
   387  
   388  		return nil
   389  	}
   390  
   391  	returnValues := make(map[string]string)
   392  
   393  	for i, v := range kvPair.(*KeysValuesPair).Keys {
   394  		returnValues[r.cleanKey(v)] = kvPair.(*KeysValuesPair).Values[i]
   395  	}
   396  
   397  	return returnValues
   398  }
   399  
   400  // GetKeysAndValues will return all keys and their values - not to be used lightly
   401  func (r *RPCStorageHandler) GetKeysAndValues() map[string]string {
   402  
   403  	searchStr := r.KeyPrefix + "*"
   404  
   405  	kvPair, err := rpc.FuncClientSingleton("GetKeysAndValues", searchStr)
   406  	if err != nil {
   407  		rpc.EmitErrorEvent(rpc.FuncClientSingletonCall, "GetKeysAndValues", err)
   408  
   409  		if r.IsAccessError(err) {
   410  			if rpc.Login() {
   411  				return r.GetKeysAndValues()
   412  			}
   413  		}
   414  
   415  		return nil
   416  	}
   417  
   418  	returnValues := make(map[string]string)
   419  	for i, v := range kvPair.(*KeysValuesPair).Keys {
   420  		returnValues[r.cleanKey(v)] = kvPair.(*KeysValuesPair).Values[i]
   421  	}
   422  
   423  	return returnValues
   424  
   425  }
   426  
   427  // DeleteKey will remove a key from the database
   428  func (r *RPCStorageHandler) DeleteKey(keyName string) bool {
   429  
   430  	log.Debug("DEL Key was: ", keyName)
   431  	log.Debug("DEL Key became: ", r.fixKey(keyName))
   432  	ok, err := rpc.FuncClientSingleton("DeleteKey", r.fixKey(keyName))
   433  	if err != nil {
   434  		rpc.EmitErrorEventKv(
   435  			rpc.FuncClientSingletonCall,
   436  			"DeleteKey",
   437  			err,
   438  			map[string]string{
   439  				"keyName":      keyName,
   440  				"fixedKeyName": r.fixKey(keyName),
   441  			},
   442  		)
   443  
   444  		if r.IsAccessError(err) {
   445  			if rpc.Login() {
   446  				return r.DeleteKey(keyName)
   447  			}
   448  		}
   449  	}
   450  
   451  	return ok == true
   452  }
   453  
   454  // DeleteKey will remove a key from the database without prefixing, assumes user knows what they are doing
   455  func (r *RPCStorageHandler) DeleteRawKey(keyName string) bool {
   456  	ok, err := rpc.FuncClientSingleton("DeleteRawKey", keyName)
   457  	if err != nil {
   458  		rpc.EmitErrorEventKv(
   459  			rpc.FuncClientSingletonCall,
   460  			"DeleteRawKey",
   461  			err,
   462  			map[string]string{
   463  				"keyName": keyName,
   464  			},
   465  		)
   466  
   467  		if r.IsAccessError(err) {
   468  			if rpc.Login() {
   469  				return r.DeleteRawKey(keyName)
   470  			}
   471  		}
   472  	}
   473  
   474  	return ok == true
   475  }
   476  
   477  // DeleteKeys will remove a group of keys in bulk
   478  func (r *RPCStorageHandler) DeleteKeys(keys []string) bool {
   479  	if len(keys) > 0 {
   480  		asInterface := make([]string, len(keys))
   481  		for i, v := range keys {
   482  			asInterface[i] = r.fixKey(v)
   483  		}
   484  
   485  		log.Debug("Deleting: ", asInterface)
   486  		ok, err := rpc.FuncClientSingleton("DeleteKeys", asInterface)
   487  		if err != nil {
   488  			rpc.EmitErrorEventKv(
   489  				rpc.FuncClientSingletonCall,
   490  				"DeleteKeys",
   491  				err,
   492  				map[string]string{
   493  					"keys":        strings.Join(keys, ","),
   494  					"asInterface": strings.Join(asInterface, ","),
   495  				},
   496  			)
   497  
   498  			if r.IsAccessError(err) {
   499  				if rpc.Login() {
   500  					return r.DeleteKeys(keys)
   501  				}
   502  			}
   503  		}
   504  
   505  		return ok == true
   506  	}
   507  	log.Debug("RPCStorageHandler called DEL - Nothing to delete")
   508  	return true
   509  }
   510  
   511  // StartPubSubHandler will listen for a signal and run the callback with the message
   512  func (r *RPCStorageHandler) StartPubSubHandler(channel string, callback func(redis.Message)) error {
   513  	log.Warning("RPCStorageHandler.StartPubSubHandler - NO PUBSUB DEFINED")
   514  	return nil
   515  }
   516  
   517  func (r *RPCStorageHandler) Publish(channel, message string) error {
   518  	log.Warning("RPCStorageHandler.Publish - NO PUBSUB DEFINED")
   519  	return nil
   520  }
   521  
   522  func (r *RPCStorageHandler) GetAndDeleteSet(keyName string) []interface{} {
   523  	log.Error("RPCStorageHandler.GetAndDeleteSet - Not implemented, please disable your purger")
   524  	return nil
   525  }
   526  
   527  func (r *RPCStorageHandler) AppendToSet(keyName, value string) {
   528  	ibd := InboundData{
   529  		KeyName: keyName,
   530  		Value:   value,
   531  	}
   532  
   533  	_, err := rpc.FuncClientSingleton("AppendToSet", ibd)
   534  	if err != nil {
   535  		rpc.EmitErrorEventKv(
   536  			rpc.FuncClientSingletonCall,
   537  			"AppendToSet",
   538  			err,
   539  			map[string]string{
   540  				"keyName": keyName,
   541  			},
   542  		)
   543  	}
   544  	if r.IsAccessError(err) {
   545  		if rpc.Login() {
   546  			r.AppendToSet(keyName, value)
   547  		}
   548  	}
   549  }
   550  
   551  func (r *RPCStorageHandler) AppendToSetPipelined(key string, values []string) {
   552  	// just falls back to AppendToSet
   553  	// TODO: introduce new RPC method for pipelined operation
   554  	for _, val := range values {
   555  		r.AppendToSet(key, val)
   556  	}
   557  }
   558  
   559  // SetScrollingWindow is used in the rate limiter to handle rate limits fairly.
   560  func (r *RPCStorageHandler) SetRollingWindow(keyName string, per int64, val string, pipeline bool) (int, []interface{}) {
   561  	start := time.Now() // get current time
   562  	ibd := InboundData{
   563  		KeyName: keyName,
   564  		Per:     per,
   565  		Expire:  -1,
   566  	}
   567  
   568  	intVal, err := rpc.FuncClientSingleton("SetRollingWindow", ibd)
   569  	if err != nil {
   570  		rpc.EmitErrorEventKv(
   571  			rpc.FuncClientSingletonCall,
   572  			"SetRollingWindow",
   573  			err,
   574  			map[string]string{
   575  				"keyName": keyName,
   576  				"per":     strconv.Itoa(int(per)),
   577  			},
   578  		)
   579  
   580  		if r.IsAccessError(err) {
   581  			if rpc.Login() {
   582  				return r.SetRollingWindow(keyName, per, val, false)
   583  			}
   584  		}
   585  	}
   586  
   587  	elapsed := time.Since(start)
   588  	log.Debug("SetRollingWindow took ", elapsed)
   589  
   590  	if intVal == nil {
   591  		log.Warning("RPC Handler: SetRollingWindow() returned nil, returning 0")
   592  		return 0, nil
   593  	}
   594  
   595  	return intVal.(int), nil
   596  
   597  }
   598  
   599  func (r *RPCStorageHandler) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{}) {
   600  	log.Warning("Not Implemented!")
   601  	return 0, nil
   602  }
   603  
   604  func (r RPCStorageHandler) GetSet(keyName string) (map[string]string, error) {
   605  	log.Error("RPCStorageHandler.GetSet - Not implemented")
   606  	return nil, nil
   607  }
   608  
   609  func (r RPCStorageHandler) AddToSet(keyName, value string) {
   610  	log.Error("RPCStorageHandler.AddToSet - Not implemented")
   611  }
   612  
   613  func (r RPCStorageHandler) RemoveFromSet(keyName, value string) {
   614  	log.Error("RPCStorageHandler.RemoveFromSet - Not implemented")
   615  }
   616  
   617  func (r RPCStorageHandler) IsAccessError(err error) bool {
   618  	if err != nil {
   619  		return err.Error() == "Access Denied"
   620  	}
   621  	return false
   622  }
   623  
   624  // GetAPIDefinitions will pull API definitions from the RPC server
   625  func (r *RPCStorageHandler) GetApiDefinitions(orgId string, tags []string) string {
   626  	dr := DefRequest{
   627  		OrgId: orgId,
   628  		Tags:  tags,
   629  	}
   630  
   631  	defString, err := rpc.FuncClientSingleton("GetApiDefinitions", dr)
   632  	if err != nil {
   633  		rpc.EmitErrorEventKv(
   634  			rpc.FuncClientSingletonCall,
   635  			"GetApiDefinitions",
   636  			err,
   637  			map[string]string{
   638  				"orgId": orgId,
   639  				"tags":  strings.Join(tags, ","),
   640  			},
   641  		)
   642  
   643  		if r.IsAccessError(err) {
   644  			if rpc.Login() {
   645  				return r.GetApiDefinitions(orgId, tags)
   646  			}
   647  		}
   648  
   649  		return ""
   650  	}
   651  	log.Debug("API Definitions retrieved")
   652  
   653  	if defString == nil {
   654  		log.Warning("RPC Handler: GetApiDefinitions() returned nil, returning empty string")
   655  		return ""
   656  	}
   657  	return defString.(string)
   658  }
   659  
   660  // GetPolicies will pull Policies from the RPC server
   661  func (r *RPCStorageHandler) GetPolicies(orgId string) string {
   662  	defString, err := rpc.FuncClientSingleton("GetPolicies", orgId)
   663  	if err != nil {
   664  		rpc.EmitErrorEventKv(
   665  			rpc.FuncClientSingletonCall,
   666  			"GetPolicies",
   667  			err,
   668  			map[string]string{
   669  				"orgId": orgId,
   670  			},
   671  		)
   672  
   673  		if r.IsAccessError(err) {
   674  			if rpc.Login() {
   675  				return r.GetPolicies(orgId)
   676  			}
   677  		}
   678  
   679  		return ""
   680  	}
   681  
   682  	if defString != nil {
   683  		return defString.(string)
   684  	}
   685  	return ""
   686  }
   687  
   688  // CheckForReload will start a long poll
   689  func (r *RPCStorageHandler) CheckForReload(orgId string) {
   690  	log.Debug("[RPC STORE] Check Reload called...")
   691  	reload, err := rpc.FuncClientSingleton("CheckReload", orgId)
   692  	if err != nil {
   693  		rpc.EmitErrorEventKv(
   694  			rpc.FuncClientSingletonCall,
   695  			"CheckReload",
   696  			err,
   697  			map[string]string{
   698  				"orgId": orgId,
   699  			},
   700  		)
   701  		if r.IsAccessError(err) {
   702  			log.Warning("[RPC STORE] CheckReload: Not logged in")
   703  			if rpc.Login() {
   704  				r.CheckForReload(orgId)
   705  			}
   706  		} else if !strings.Contains(err.Error(), "Cannot obtain response during") {
   707  			log.Warning("[RPC STORE] RPC Reload Checker encountered unexpected error: ", err)
   708  		}
   709  
   710  		time.Sleep(1 * time.Second)
   711  	} else if reload == true {
   712  		// Do the reload!
   713  		log.Warning("[RPC STORE] Received Reload instruction!")
   714  		go func() {
   715  			MainNotifier.Notify(Notification{Command: NoticeGroupReload})
   716  		}()
   717  	}
   718  }
   719  
   720  func (r *RPCStorageHandler) StartRPCLoopCheck(orgId string) {
   721  	if config.Global().SlaveOptions.DisableKeySpaceSync {
   722  		return
   723  	}
   724  
   725  	log.Info("[RPC] Starting keyspace poller")
   726  
   727  	for {
   728  		r.CheckForKeyspaceChanges(orgId)
   729  		time.Sleep(10 * time.Second)
   730  	}
   731  }
   732  
   733  func (r *RPCStorageHandler) StartRPCKeepaliveWatcher() {
   734  	log.WithFields(logrus.Fields{
   735  		"prefix": "RPC Conn Mgr",
   736  	}).Info("[RPC Conn Mgr] Starting keepalive watcher...")
   737  	for {
   738  
   739  		if err := r.SetKey("0000", "0000", 10); err != nil {
   740  			log.WithError(err).WithFields(logrus.Fields{
   741  				"prefix": "RPC Conn Mgr",
   742  			}).Info("Can't connect to RPC layer")
   743  
   744  			if r.IsAccessError(err) {
   745  				if rpc.Login() {
   746  					continue
   747  				}
   748  			}
   749  
   750  			if strings.Contains(err.Error(), "Cannot obtain response during timeout") {
   751  				continue
   752  			}
   753  		}
   754  
   755  		time.Sleep(10 * time.Second)
   756  	}
   757  }
   758  
   759  // CheckForKeyspaceChanges will poll for keysace changes
   760  func (r *RPCStorageHandler) CheckForKeyspaceChanges(orgId string) {
   761  	log.Debug("Checking for keyspace changes...")
   762  
   763  	var keys interface{}
   764  	var err error
   765  	var funcName string
   766  	var req interface{}
   767  
   768  	reqData := map[string]string{}
   769  	if groupID := config.Global().SlaveOptions.GroupID; groupID == "" {
   770  		funcName = "GetKeySpaceUpdate"
   771  		req = orgId
   772  		reqData["orgId"] = orgId
   773  	} else {
   774  		funcName = "GetGroupKeySpaceUpdate"
   775  		req = GroupKeySpaceRequest{
   776  			OrgID:   orgId,
   777  			GroupID: groupID,
   778  		}
   779  		reqData["orgId"] = orgId
   780  		reqData["GroupID"] = groupID
   781  	}
   782  
   783  	keys, err = rpc.FuncClientSingleton(funcName, req)
   784  	if err != nil {
   785  		rpc.EmitErrorEventKv(
   786  			rpc.FuncClientSingletonCall,
   787  			funcName,
   788  			err,
   789  			reqData,
   790  		)
   791  		if r.IsAccessError(err) {
   792  			if rpc.Login() {
   793  				r.CheckForKeyspaceChanges(orgId)
   794  			}
   795  		}
   796  		log.Warning("Keyspace warning: ", err)
   797  		return
   798  	}
   799  
   800  	if keys == nil {
   801  		log.Info("Keys returned nil object, skipping check")
   802  		return
   803  	}
   804  
   805  	if len(keys.([]string)) > 0 {
   806  		log.Info("Keyspace changes detected, updating local cache")
   807  		go r.ProcessKeySpaceChanges(keys.([]string))
   808  	}
   809  }
   810  
   811  func getSessionAndCreate(keyName string, r *RPCStorageHandler) {
   812  	newKeyName := "apikey-" + storage.HashStr(keyName)
   813  	sessionString, err := r.GetRawKey(keyName)
   814  	if err != nil {
   815  		log.Error("Key not found in master - skipping")
   816  	} else {
   817  		handleAddKey(keyName, newKeyName[7:], sessionString, "-1")
   818  	}
   819  }
   820  
   821  func (r *RPCStorageHandler) ProcessKeySpaceChanges(keys []string) {
   822  	keysToReset := map[string]bool{}
   823  
   824  	for _, key := range keys {
   825  		splitKeys := strings.Split(key, ":")
   826  		if len(splitKeys) > 1 && splitKeys[1] == "resetQuota" {
   827  			keysToReset[splitKeys[0]] = true
   828  		}
   829  	}
   830  
   831  	for _, key := range keys {
   832  		splitKeys := strings.Split(key, ":")
   833  		_, resetQuota := keysToReset[splitKeys[0]]
   834  		if len(splitKeys) > 1 && splitKeys[1] == "hashed" {
   835  			key = splitKeys[0]
   836  			log.Info("--> removing cached (hashed) key: ", splitKeys[0])
   837  			handleDeleteHashedKey(splitKeys[0], "", resetQuota)
   838  			getSessionAndCreate(splitKeys[0], r)
   839  		} else {
   840  			log.Info("--> removing cached key: ", key)
   841  			handleDeleteKey(key, "-1", resetQuota)
   842  			getSessionAndCreate(splitKeys[0], r)
   843  		}
   844  		SessionCache.Delete(key)
   845  		RPCGlobalCache.Delete(r.KeyPrefix + key)
   846  	}
   847  	// Notify rest of gateways in cluster to flush cache
   848  	n := Notification{
   849  		Command: KeySpaceUpdateNotification,
   850  		Payload: strings.Join(keys, ","),
   851  	}
   852  	MainNotifier.Notify(n)
   853  }
   854  
   855  func (r *RPCStorageHandler) DeleteScanMatch(pattern string) bool {
   856  	log.Error("RPCStorageHandler.DeleteScanMatch - Not implemented")
   857  	return false
   858  }
   859  
   860  func (r *RPCStorageHandler) GetKeyPrefix() string {
   861  	log.Error("RPCStorageHandler.GetKeyPrefix - Not implemented")
   862  	return ""
   863  }
   864  
   865  func (r *RPCStorageHandler) AddToSortedSet(keyName, value string, score float64) {
   866  	log.Error("RPCStorageHandler.AddToSortedSet - Not implemented")
   867  }
   868  
   869  func (r *RPCStorageHandler) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error) {
   870  	log.Error("RPCStorageHandler.GetSortedSetRange - Not implemented")
   871  	return nil, nil, nil
   872  }
   873  
   874  func (r *RPCStorageHandler) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error {
   875  	log.Error("RPCStorageHandler.RemoveSortedSetRange - Not implemented")
   876  	return nil
   877  }