func initNodeData() { if memConfNodes[conf.ClientAddr] == nil { bs, _ := json.Marshal(memConfDataVersion) node := &models.Node{ URL: conf.ClientAddr, NodeURL: conf.NodeAddr, Type: conf.NodeType, DataVersion: memConfDataVersion, DataVersionStr: string(bs), CreatedUTC: utils.GetNowSecond(), } if err := models.InsertRow(nil, node); err != nil { log.Panicf("Failed to init node data: %s", err.Error()) } memConfNodes[conf.ClientAddr] = node } node := memConfNodes[conf.ClientAddr] if node.Type != conf.NodeType { node.Type = conf.NodeType if err := models.UpdateDBModel(nil, node); err != nil { log.Panicf("Failed to update node data: %s", err.Error()) } } }
func updateApp(app *models.App, newDataVersion *models.DataVersion, ms *models.Session) (*models.App, error) { var s *models.Session if ms != nil { s = ms } else { s = models.NewSession() defer s.Close() if err := s.Begin(); err != nil { s.Rollback() return nil, err } } node := *memConfNodes[conf.ClientAddr] oldApp := memConfApps[app.Key] if newDataVersion == nil { newDataVersion = genNewDataVersion(memConfDataVersion) } if err := updateNodeDataVersion(s, &node, newDataVersion); err != nil { if ms == nil { s.Rollback() } return nil, err } if oldApp == nil { if err := models.InsertRow(s, app); err != nil { if ms == nil { s.Rollback() } return nil, err } } else { if err := models.UpdateDBModel(s, app); err != nil { if ms == nil { s.Rollback() } return nil, err } } if ms == nil { if err := s.Commit(); err != nil { s.Rollback() return nil, err } updateMemConf(app, newDataVersion, &node) } return app, nil }
func updateWebHook(hook *models.WebHook, newDataVersion *models.DataVersion) (*models.WebHook, error) { s := models.NewSession() defer s.Close() if err := s.Begin(); err != nil { s.Rollback() return nil, err } node := *memConfNodes[conf.ClientAddr] oldHookIdx := -1 var hooks []*models.WebHook if hook.Scope == models.WEBHOOK_SCOPE_GLOBAL { hooks = memConfGlobalWebHooks } else if hook.Scope == models.WEBHOOK_SCOPE_APP { hooks = memConfAppWebHooks[hook.AppKey] } for idx, oldHook := range hooks { if hook.Key == oldHook.Key { oldHookIdx = idx break } } if newDataVersion == nil { newDataVersion = genNewDataVersion(memConfDataVersion) } if err := updateNodeDataVersion(s, &node, newDataVersion); err != nil { s.Rollback() return nil, err } if oldHookIdx == -1 { if err := models.InsertRow(s, hook); err != nil { s.Rollback() return nil, err } } else { if err := models.UpdateDBModel(s, hook); err != nil { s.Rollback() return nil, err } } if err := s.Commit(); err != nil { s.Rollback() return nil, err } updateMemConf(hook, newDataVersion, &node, oldHookIdx) return hook, nil }
func updateUser(user *models.User, newDataVersion *models.DataVersion) (*models.User, error) { s := models.NewSession() defer s.Close() if err := s.Begin(); err != nil { s.Rollback() return nil, err } node := *memConfNodes[conf.ClientAddr] oldUser := memConfUsers[user.Key] if newDataVersion == nil { newDataVersion = genNewDataVersion(memConfDataVersion) } if err := updateNodeDataVersion(s, &node, newDataVersion); err != nil { s.Rollback() return nil, err } if oldUser == nil { if err := models.InsertRow(s, user); err != nil { s.Rollback() return nil, err } } else { if err := models.UpdateDBModel(s, user); err != nil { s.Rollback() return nil, err } } if err := s.Commit(); err != nil { s.Rollback() return nil, err } updateMemConf(user, newDataVersion, &node) return user, nil }
func handleSlaveCheckMaster(c *gin.Context, data string) { if !conf.IsMasterNode() { Error(c, BAD_REQUEST, "invalid req type for slave node: "+NODE_REQUEST_TYPE_CHECKMASTER) return } node := &models.Node{} if err := json.Unmarshal([]byte(data), node); err != nil { Error(c, BAD_REQUEST, "bad req body format") return } confWriteMux.Lock() defer confWriteMux.Unlock() oldNode := memConfNodes[node.URL] node.LastCheckUTC = utils.GetNowSecond() if oldNode == nil { if err := models.InsertRow(nil, node); err != nil { Error(c, SERVER_ERROR, err.Error()) return } } else { if err := models.UpdateDBModel(nil, node); err != nil { Error(c, SERVER_ERROR, err.Error()) return } } memConfMux.Lock() memConfNodes[node.URL] = node bs, _ := json.Marshal(memConfDataVersion) memConfMux.Unlock() go masterSyncNodeToSlave(node) Success(c, string(bs)) }
func updateConfig(config *models.Config, userKey string, newDataVersion *models.DataVersion, ms *models.Session) (*models.Config, error) { var s *models.Session if ms != nil { s = ms } else { s = models.NewSession() defer s.Close() if err := s.Begin(); err != nil { s.Rollback() return nil, err } } isSysConf := isSysConfType(config.AppKey) node := *memConfNodes[conf.ClientAddr] oldConfig := memConfRawConfigs[config.Key] app, err := models.GetAppByKey(s, config.AppKey) if err != nil { return nil, err } if newDataVersion == nil { newDataVersion = genNewDataVersion(memConfDataVersion) } if err := updateNodeDataVersion(s, &node, newDataVersion); err != nil { if ms == nil { s.Rollback() } return nil, err } var configHistory *models.ConfigUpdateHistory if oldConfig == nil { configHistory = &models.ConfigUpdateHistory{ Id: utils.GenerateKey(), ConfigKey: config.Key, K: config.K, OldV: "", OldVType: "", NewV: config.V, NewVType: config.VType, Kind: models.CONFIG_UPDATE_KIND_NEW, UserKey: userKey, CreatedUTC: utils.GetNowSecond(), } if err := models.InsertRow(s, configHistory); err != nil { if ms == nil { s.Rollback() } return nil, err } config.LastUpdateId = configHistory.Id if err := models.InsertRow(s, config); err != nil { if ms == nil { s.Rollback() } return nil, err } if !isSysConf { app.KeyCount++ app.LastUpdateUTC = configHistory.CreatedUTC app.LastUpdateId = configHistory.Id app.UpdateTimes++ } } else { kind := models.CONFIG_UPDATE_KIND_UPDATE if config.Status != oldConfig.Status { if config.Status == models.CONF_STATUS_ACTIVE { kind = models.CONFIG_UPDATE_KIND_RECOVER } else { kind = models.CONFIG_UPDATE_KIND_HIDE } } configHistory = &models.ConfigUpdateHistory{ Id: utils.GenerateKey(), ConfigKey: config.Key, K: config.K, OldV: oldConfig.V, OldVType: oldConfig.VType, NewV: config.V, NewVType: config.VType, Kind: kind, UserKey: userKey, CreatedUTC: utils.GetNowSecond(), } if err := models.InsertRow(s, configHistory); err != nil { if ms == nil { s.Rollback() } return nil, err } config.UpdateTimes++ config.LastUpdateId = configHistory.Id if err := models.UpdateDBModel(s, config); err != nil { if ms == nil { s.Rollback() } return nil, err } if !isSysConf { app.LastUpdateUTC = configHistory.CreatedUTC app.LastUpdateId = configHistory.Id app.UpdateTimes++ } } var toUpdateApps []*models.App if !isSysConf { newDataSign := utils.GenerateKey() app.DataSign = newDataSign if err := models.UpdateDBModel(s, app); err != nil { if ms == nil { s.Rollback() } return nil, err } if app.Type == models.APP_TYPE_TEMPLATE { for _, _app := range memConfApps { if _app.Key == config.AppKey { continue } for _, _config := range memConfAppConfigs[_app.Key] { if _config.VType == models.CONF_V_TYPE_TEMPLATE && _config.V == config.AppKey { // this app has a config refer to this template app toUpdateApps = append(toUpdateApps, _app) break } } } } for _, app := range toUpdateApps { _app := *app _app.DataSign = newDataSign if err := models.UpdateDBModel(s, &_app); err != nil { if ms == nil { s.Rollback() } return nil, err } } } if ms == nil { if err := s.Commit(); err != nil { s.Rollback() return nil, err } if !isSysConf { go TriggerWebHooks(configHistory, app) } else { go TriggerWebHooks(configHistory, &models.App{Key: config.Key, Name: config.Key}) } updateMemConf(config, newDataVersion, &node, toUpdateApps) } return config, nil }
func recordClientQueryParam() { doEverTask(func() { for { i := <-clientQueryParamCh cdata := i.(*ClientData) if cdata.Lang != "" && !memConfClientLang[cdata.Lang] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: "", Symbol: GLISP_SYMBOL_TYPE_LANG, Value: cdata.Lang}) if err == nil { memConfClientMux.Lock() memConfClientLang[cdata.Lang] = true memConfClientMux.Unlock() } } if cdata.OSType != "" && !memConfClientOSType[cdata.OSType] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: "", Symbol: GLISP_SYMBOL_TYPE_OS_TYPE, Value: cdata.OSType}) if err == nil { memConfClientMux.Lock() memConfClientOSType[cdata.OSType] = true memConfClientMux.Unlock() } } if cdata.OSVersion != "" && !memConfClientOSV[cdata.OSVersion] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: "", Symbol: GLISP_SYMBOL_TYPE_OS_VERSION, Value: cdata.OSVersion}) if err == nil { memConfClientMux.Lock() memConfClientOSV[cdata.OSVersion] = true memConfClientMux.Unlock() } } if cdata.TimeZone != "" && !memConfClientTimezone[cdata.TimeZone] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: "", Symbol: GLISP_SYMBOL_TYPE_TIMEZONE, Value: cdata.TimeZone}) if err == nil { memConfClientMux.Lock() memConfClientTimezone[cdata.TimeZone] = true memConfClientMux.Unlock() } } if cdata.NetWork != "" && !memConfClientNetwork[cdata.NetWork] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: "", Symbol: GLISP_SYMBOL_TYPE_NETWORK, Value: cdata.NetWork}) if err == nil { memConfClientMux.Lock() memConfClientNetwork[cdata.NetWork] = true memConfClientMux.Unlock() } } if _, ok := memConfClientAppVersion[cdata.AppKey]; !ok { memConfClientMux.Lock() memConfClientAppVersion[cdata.AppKey] = map[string]bool{} memConfClientMux.Unlock() } if cdata.AppVersion != "" && !memConfClientAppVersion[cdata.AppKey][cdata.AppVersion] { err := models.InsertRow( nil, &models.ClientReqeustData{AppKey: cdata.AppKey, Symbol: GLISP_SYMBOL_TYPE_APP_VERSION, Value: cdata.AppVersion}) if err == nil { memConfClientMux.Lock() memConfClientAppVersion[cdata.AppKey][cdata.AppVersion] = true memConfClientMux.Unlock() } } } }) }
func handleSlaveSyncUpdateData(c *gin.Context, data string) { if conf.IsMasterNode() { Error(c, BAD_REQUEST, "invalid req type for master node: "+NODE_REQUEST_TYPE_SYNCSLAVE) return } syncData := &syncDataT{} err := json.Unmarshal([]byte(data), syncData) if err != nil { Error(c, BAD_REQUEST, "bad req body format") return } confWriteMux.Lock() defer confWriteMux.Unlock() if syncData.Kind != NODE_REQUEST_SYNC_TYPE_NODE { if memConfDataVersion.Version+1 != syncData.DataVersion.Version { Error(c, DATA_VERSION_ERROR, "slave node data version [%d] error for master data version [%d]", memConfDataVersion.Version, syncData.DataVersion.Version) return } if memConfDataVersion.Sign != syncData.DataVersion.OldSign { Error(c, DATA_VERSION_ERROR, "slave node's data sign [%s] not equal master node's old data sign [%s]", memConfDataVersion.Sign, syncData.DataVersion.OldSign) return } } switch syncData.Kind { case NODE_REQUEST_SYNC_TYPE_USER: user := &models.User{} if err = json.Unmarshal([]byte(syncData.Data), user); err != nil { Error(c, BAD_REQUEST, "bad data format for user model") return } if _, err = updateUser(user, syncData.DataVersion); err != nil { Error(c, SERVER_ERROR, err.Error()) return } case NODE_REQUEST_SYNC_TYPE_APP: app := &models.App{} if err = json.Unmarshal([]byte(syncData.Data), app); err != nil { Error(c, BAD_REQUEST, "bad data format for app model") return } if _, err = updateApp(app, syncData.DataVersion, nil); err != nil { Error(c, SERVER_ERROR, err.Error()) return } case NODE_REQUEST_SYNC_TYPE_WEBHOOK: hook := &models.WebHook{} if err = json.Unmarshal([]byte(syncData.Data), hook); err != nil { Error(c, BAD_REQUEST, "bad data format for webHook model") return } if _, err = updateWebHook(hook, syncData.DataVersion); err != nil { Error(c, SERVER_ERROR, err.Error()) return } case NODE_REQUEST_SYNC_TYPE_CONFIG: config := &models.Config{} if err = json.Unmarshal([]byte(syncData.Data), config); err != nil { Error(c, BAD_REQUEST, "bad data format for user model") return } if _, err = updateConfig(config, syncData.OpUserKey, syncData.DataVersion, nil); err != nil { Error(c, SERVER_ERROR, err.Error()) return } case NODE_REQUEST_SYNC_TYPE_NODE: node := &models.Node{} if err = json.Unmarshal([]byte(syncData.Data), node); err != nil { Error(c, BAD_REQUEST, "bad data format for node model") return } if memConfNodes[node.URL] == nil { if err := models.InsertRow(nil, node); err != nil { Error(c, SERVER_ERROR, err.Error()) return } } else { if err := models.UpdateDBModel(nil, node); err != nil { Error(c, SERVER_ERROR, err.Error()) return } } memConfMux.Lock() memConfNodes[node.URL] = node memConfMux.Unlock() Success(c, nil) return case NODE_REQUEST_SYNC_TYPE_CLONE: data := &cloneData{} if err := json.Unmarshal([]byte(syncData.Data), data); err != nil { Error(c, BAD_REQUEST, "bad data format for clone app") return } if err := cloneConfigs(data.App, data.Configs, syncData.OpUserKey); err != nil { Error(c, SERVER_ERROR, err.Error()) return } default: Error(c, BAD_REQUEST, "unknown node data sync type: "+syncData.Kind) return } masterNode := getMasterNode() masterNode.DataVersion = syncData.DataVersion bs, _ := json.Marshal(syncData.DataVersion) masterNode.DataVersionStr = string(bs) if err = models.UpdateDBModel(nil, &masterNode); err != nil { memConfMux.Lock() memConfNodes[masterNode.URL] = &masterNode memConfMux.Unlock() } Success(c, nil) }