func cloneConfigsFromApp(from, to, aux_info, userKey string) (*models.App, []*models.Config, error) { memConfMux.RLock() fromApp := memConfAppsByName[from] memConfMux.RUnlock() fromConfigs, err := models.GetConfigsByAppKey(nil, fromApp.Key) if err != nil { return nil, nil, err } app := &models.App{ Key: utils.GenerateKey(), Name: to, UserKey: userKey, AuxInfo: aux_info, CreatedUTC: utils.GetNowSecond(), Type: fromApp.Type, } for _, config := range fromConfigs { config.Key = utils.GenerateKey() config.CreatorKey = app.UserKey config.AppKey = app.Key config.CreatedUTC = app.CreatedUTC } if err := cloneConfigs(app, fromConfigs, userKey); err != nil { return nil, nil, err } return app, fromConfigs, nil }
func initOneConfig(userName, appName, appType, configK, configV, configVType string) (*models.User, *models.App, *models.Config, error) { user, err := updateUser(&models.User{ Name: userName, Key: utils.GenerateKey()}, nil) if err != nil { return nil, nil, nil, err } app, err := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: appName, Type: appType}, nil, nil) if err != nil { return nil, nil, nil, err } config, err := updateConfig(&models.Config{ Key: utils.GenerateKey(), AppKey: app.Key, K: configK, V: configV, VType: configVType, Status: models.CONF_STATUS_ACTIVE}, "", nil, nil) return user, app, config, err }
func TestUpdateApp(t *testing.T) { err := _clearModelData() assert.True(t, err == nil, "must correctly clear data") loadAllData() initNodeData() confWriteMux.Lock() defer confWriteMux.Unlock() user, err := updateUser(&models.User{ Name: "rahuahua", Key: utils.GenerateKey()}, nil) app, err := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "iconfreecn", Type: models.APP_TYPE_REAL}, nil, nil) app, err = updateApp(&models.App{ Key: app.Key, UserKey: user.Key, Name: "hdfreecn", Type: models.APP_TYPE_REAL, AuxInfo: "guaji"}, nil, nil) assert.True(t, err == nil, "must correctly add new app") assert.True(t, len(memConfApps) == 1, "must only one app") assert.True(t, memConfAppsByName["iconfreecn"] == nil, "old-name app must not exist") assert.True(t, memConfAppsByName["hdfreecn"].AuxInfo == "guaji", "aux_info must be updated") _clearModelData() }
func TestSearchApps(t *testing.T) { user, err := updateUser(&models.User{ Name: "rahuahua", Key: utils.GenerateKey()}, nil) _, err = updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "iconfreecn", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") _, err = updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "xianyouvideo", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") _, err = updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "hdfreecn", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") _, err = updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "phoneplay", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") apps, err := searchApps("free", 0) assert.True(t, err == nil) assert.True(t, len(apps) == 2) apps, err = searchApps("video", 0) assert.True(t, err == nil) assert.True(t, len(apps) == 1) apps, err = searchApps("phoneplay", 0) assert.True(t, err == nil) assert.True(t, len(apps) == 1) apps, err = searchApps("non-exist", 0) assert.True(t, err == nil) assert.True(t, len(apps) == 0) }
func InitUser(c *gin.Context) { confWriteMux.Lock() defer confWriteMux.Unlock() if len(memConfUsers) > 0 { Error(c, BAD_REQUEST, "users already exists") return } data := &newUserData{} if err := c.BindJSON(data); err != nil { Error(c, BAD_POST_DATA, err.Error()) return } if err := verifyNewUserData(data); err != nil { Error(c, BAD_REQUEST, err.Error()) return } key := utils.GenerateKey() user, err := newUserWithNewUserData(data, key, key) if err != nil { Error(c, SERVER_ERROR, err.Error()) return } failedNodes := syncData2SlaveIfNeed(user, key) setUserKeyCookie(c, user.Key, user.PassCode) if len(failedNodes) > 0 { Success(c, map[string]interface{}{"failed_nodes": failedNodes}) } else { Success(c, nil) } }
func genNewDataVersion(old *models.DataVersion) *models.DataVersion { return &models.DataVersion{ Version: old.Version + 1, Sign: utils.GenerateKey(), OldSign: old.Sign, } }
func NewUser(c *gin.Context) { confWriteMux.Lock() defer confWriteMux.Unlock() data := &newUserData{} if err := c.BindJSON(data); err != nil { Error(c, BAD_POST_DATA, err.Error()) return } if err := verifyNewUserData(data); err != nil { Error(c, BAD_REQUEST, err.Error()) return } user, err := newUserWithNewUserData(data, utils.GenerateKey(), getOpUserKey(c)) if err != nil { Error(c, SERVER_ERROR, err.Error()) return } failedNodes := syncData2SlaveIfNeed(user, getOpUserKey(c)) if len(failedNodes) > 0 { Success(c, map[string]interface{}{"failed_nodes": failedNodes}) } else { Success(c, nil) } }
func TestUpdateUser(t *testing.T) { err := _clearModelData() assert.True(t, err == nil, "must correctly clear data") loadAllData() initNodeData() confWriteMux.Lock() defer confWriteMux.Unlock() node1 := memConfNodes[conf.ClientAddr] userData := &newUserData{ Name: "rahuahua", PassCode: "huahua", } user, err := newUserWithNewUserData(userData, "1234567", "1234567") assert.True(t, err == nil, "must correctly add new user") node2 := memConfNodes[conf.ClientAddr] assert.True(t, node2.DataVersion.Sign != node1.DataVersion.Sign) assert.True(t, node2.DataVersion.OldSign == node1.DataVersion.Sign) assert.True(t, node2.DataVersion.Version == node1.DataVersion.Version+1) userData = &newUserData{ Name: "rahuahua2", PassCode: "huahua", } newUser, err := newUserWithNewUserData(userData, utils.GenerateKey(), user.Key) assert.True(t, err == nil, "must correctly add new user") assert.True(t, newUser.CreatorKey == user.Key && newUser.CreatedUTC >= user.CreatedUTC) node3 := memConfNodes[conf.ClientAddr] assert.True(t, node3.DataVersion.Sign != node2.DataVersion.Sign) assert.True(t, node3.DataVersion.OldSign == node2.DataVersion.Sign) assert.True(t, node3.DataVersion.Version == node2.DataVersion.Version+1) assert.True(t, node3.DataVersion.Version == node1.DataVersion.Version+2) updateData := &updateUserData{ Name: "rahuahua333", AuxInfo: "1234", } assert.True(t, verifyUpdateUserData(updateData, user.Key) == nil) oldUser := *user user, err = updateUserWithUpdateData(updateData, user.Key) assert.True(t, err == nil) assert.True(t, user.Key == oldUser.Key) assert.True(t, user.Name == "rahuahua333") badData := &updateUserData{ Name: "rahuahua2", } assert.True(t, verifyUpdateUserData(badData, user.Key) != nil) badData.Name = "12" assert.True(t, verifyUpdateUserData(badData, user.Key) != nil) _clearModelData() }
func TestNewApp(t *testing.T) { err := _clearModelData() assert.True(t, err == nil, "must correctly clear data") loadAllData() initNodeData() confWriteMux.Lock() defer confWriteMux.Unlock() user, err := updateUser(&models.User{ Name: "rahuahua", Key: utils.GenerateKey()}, nil) node1 := memConfNodes[conf.ClientAddr] app, err := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "iconfreecn", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") assert.True(t, len(memConfApps) == 1, "must only one app") assert.True(t, app.Key == memConfAppsByName["iconfreecn"].Key, "must the same app") node2 := memConfNodes[conf.ClientAddr] assert.True(t, node2.DataVersion.Sign != node1.DataVersion.Sign) assert.True(t, node2.DataVersion.OldSign == node1.DataVersion.Sign) assert.True(t, node2.DataVersion.Version == node1.DataVersion.Version+1) _, err = updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "hdfreecn", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, err == nil, "must correctly add new app") assert.True(t, len(memConfApps) == 2, "must two apps") node3 := memConfNodes[conf.ClientAddr] assert.True(t, node3.DataVersion.Sign != node2.DataVersion.Sign) assert.True(t, node3.DataVersion.OldSign == node2.DataVersion.Sign) assert.True(t, node3.DataVersion.Version == node2.DataVersion.Version+1) assert.True(t, node3.DataVersion.Version == node1.DataVersion.Version+2) _clearModelData() }
func TestDataVersion(t *testing.T) { err := _clearModelData() assert.True(t, err == nil, "must correctly clear data") loadAllData() initNodeData() assert.True(t, memConfDataVersion.Version == 0, "init data version must be 0") oldVersion := *memConfDataVersion user, err := updateUser(&models.User{ Name: "rahuahua", Key: utils.GenerateKey()}, nil) assert.True(t, memConfDataVersion.Version == 1, "data version must be 1") assert.True(t, memConfDataVersion.OldSign == oldVersion.Sign) assert.True(t, memConfDataVersion.Sign != oldVersion.Sign) oldVersion = *memConfDataVersion app, _ := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "iconfreecn", Type: models.APP_TYPE_REAL}, nil, nil) assert.True(t, memConfDataVersion.Version == 2, "data version must be 2") assert.True(t, memConfDataVersion.OldSign == oldVersion.Sign) assert.True(t, memConfDataVersion.Sign != oldVersion.Sign) oldVersion = *memConfDataVersion updateConfig(&models.Config{ Key: utils.GenerateKey(), AppKey: app.Key, K: "int_conf", V: "1", VType: models.CONF_V_TYPE_INT, Status: models.CONF_STATUS_ACTIVE}, "", nil, nil) assert.True(t, memConfDataVersion.Version == 3, "data version must be 3") assert.True(t, memConfDataVersion.OldSign == oldVersion.Sign) assert.True(t, memConfDataVersion.Sign != oldVersion.Sign) _clearModelData() }
func NewWebHook(c *gin.Context) { confWriteMux.Lock() defer confWriteMux.Unlock() var data struct { AppKey string `json:"app_key"` Scope int `json:"scope"` Target string `json:"target" binding:"required"` URL string `json:"url" binding:"required"` Status int `json:"status"` } if err := c.BindJSON(&data); err != nil { Error(c, BAD_POST_DATA, err.Error()) return } if data.Scope != models.WEBHOOK_SCOPE_GLOBAL && data.Scope != models.WEBHOOK_SCOPE_APP { Error(c, BAD_REQUEST, "unknown webHook scope: "+string(data.Scope)) return } if data.Target != models.WEBHOOK_TARGET_PUBU && data.Target != models.WEBHOOK_TARGET_SLACK { Error(c, BAD_REQUEST, "unsupported webHook target: "+data.Target) return } if data.Scope == models.WEBHOOK_SCOPE_APP && memConfApps[data.AppKey] == nil { Error(c, BAD_REQUEST, "app key not exists: "+data.AppKey) return } webHook := &models.WebHook{ Key: utils.GenerateKey(), AppKey: data.AppKey, Scope: data.Scope, Target: data.Target, URL: data.URL, Status: data.Status, } if _, err := updateWebHook(webHook, nil); err != nil { Error(c, SERVER_ERROR, err.Error()) return } failedNodes := syncData2SlaveIfNeed(webHook, getOpUserKey(c)) if len(failedNodes) > 0 { Success(c, map[string]interface{}{"failed_nodes": failedNodes}) } else { Success(c, nil) } }
func newConfigWithNewConfigData(data *newConfigData, userKey string) (*models.Config, error) { config := &models.Config{ Key: utils.GenerateKey(), AppKey: data.AppKey, K: data.K, V: data.V, VType: data.VType, CreatedUTC: utils.GetNowSecond(), CreatorKey: userKey, Des: data.Des, Status: models.CONF_STATUS_ACTIVE, } return updateConfig(config, userKey, nil, nil) }
func TestTemplateApp(t *testing.T) { err := _clearModelData() assert.True(t, err == nil, "must correctly clear data") loadAllData() initNodeData() user, _ := updateUser(&models.User{ Name: "rahuahua", Key: utils.GenerateKey()}, nil) templateApp, _ := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "template_app", Type: models.APP_TYPE_TEMPLATE}, nil, nil) templateConfig, _ := updateConfig(&models.Config{ Key: utils.GenerateKey(), AppKey: templateApp.Key, K: "template_int_conf", V: "233", VType: models.CONF_V_TYPE_INT, Status: models.CONF_STATUS_ACTIVE}, "", nil, nil) app, _ := updateApp(&models.App{ Key: utils.GenerateKey(), UserKey: user.Key, Name: "iconfreecn", Type: models.APP_TYPE_REAL}, nil, nil) updateConfig(&models.Config{ Key: utils.GenerateKey(), AppKey: app.Key, K: "int_conf", V: "1", VType: models.CONF_V_TYPE_INT, Status: models.CONF_STATUS_ACTIVE}, "", nil, nil) _, err = updateConfig(&models.Config{ Key: utils.GenerateKey(), AppKey: app.Key, K: "template_conf", V: templateApp.Key, VType: models.CONF_V_TYPE_TEMPLATE, Status: models.CONF_STATUS_ACTIVE}, "", nil, nil) assert.True(t, err == nil, "must correctly add template conf") appConfig := getAppMatchConf(app.Key, &ClientData{AppKey: app.Key}) assert.True(t, reflect.TypeOf(appConfig["template_conf"]).Kind() == reflect.Map) appOldDataSign := memConfApps[app.Key].DataSign oldTemplateDataSign := memConfApps[templateApp.Key].DataSign updateConfig(templateConfig, "", nil, nil) assert.True(t, appOldDataSign != memConfApps[app.Key].DataSign, "app's data_sign must update after update config") assert.True(t, oldTemplateDataSign != memConfApps[templateApp.Key].DataSign, "app's data_sign must update after update config") _clearModelData() }
func NewApp(c *gin.Context) { confWriteMux.Lock() defer confWriteMux.Unlock() var data struct { Name string `json:"name" binding:"required"` Type string `json:"type" binding:"required"` AuxInfo string `json:"aux_info"` } if err := c.BindJSON(&data); err != nil { Error(c, BAD_POST_DATA, err.Error()) return } if !models.IsValidAppType(data.Type) { Error(c, BAD_REQUEST, "unknown app type: "+data.Type) return } if memConfAppsByName[data.Name] != nil { Error(c, BAD_REQUEST, "appname already exists: "+data.Name) return } app := &models.App{ Key: utils.GenerateKey(), Name: data.Name, UserKey: getOpUserKey(c), Type: data.Type, AuxInfo: data.AuxInfo, CreatedUTC: utils.GetNowSecond(), } if _, err := updateApp(app, nil, nil); err != nil { Error(c, SERVER_ERROR, err.Error()) return } failedNodes := syncData2SlaveIfNeed(app, getOpUserKey(c)) if len(failedNodes) > 0 { Success(c, map[string]interface{}{"failed_nodes": failedNodes}) } else { Success(c, nil) } }
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 }