package service import ( "StuAcaWorksAI/dao" "StuAcaWorksAI/proto" "StuAcaWorksAI/worker" "encoding/json" "errors" "fmt" "github.com/golang-jwt/jwt" "log" "regexp" "strconv" "time" ) func CreateUser(name, password, email, gender string, age int) uint { id := dao.CreateUser(name, password, email, gender, age) if id != 0 { //添加用户信息到同步列表 err := setSyncUserDataSet("add", int(id)) if err != nil { return id } } return id } func GetUser(name, email, password string) dao.User { emailRegex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` re := regexp.MustCompile(emailRegex) var user dao.User if re.MatchString(name) { user = dao.FindUserByEmail(name) } else { user = dao.FindUserByName(name) } if user.ID != 0 && user.Password == password { return user } return dao.User{} } func ContainsUser(name, email string) bool { user := dao.FindUserByName(name) user2 := dao.FindUserByEmail(email) if user.ID != 0 || user2.ID != 0 { return true } return false } func GetUserByID(id int) []dao.User { users := dao.FindUserByID(id) for i, _ := range users { users[i].Password = "" //不返回密码 } return users } // 获取用户信息,有redis缓存 func GetUserByIDFromUserCenter(id int) dao.User { if id <= 0 { return dao.User{} } var user dao.User //先从redis获取 key := "user_info_" + strconv.Itoa(id) user_str := worker.GetRedis(key) if user_str != "" { err := json.Unmarshal([]byte(user_str), &user) if err != nil { fmt.Println("get user info , json unmarshal error:", err, "\tuser_str:", user_str) return dao.User{} } } else { user = GetUserInfoByIDFromUserCenterHttp(id) if user.ID != 0 { userJson, err := json.Marshal(user) if err != nil { fmt.Println("get user info , json marshal error:", err) return dao.User{} } success := worker.SetRedisWithExpire(key, string(userJson), time.Second*10) if !success { fmt.Println("set redis error,user json:", string(userJson)) } } } return user } type UserInfoResponse struct { Code int `json:"code"` Message string `json:"message"` Data dao.User `json:"data"` } func GetUserInfoByIDFromUserCenterHttp(id int) dao.User { var resp UserInfoResponse url := "https://uc.ljsea.top/user/info?super_id=1" tokens := worker.GetRedisSetMembers("super_permission_tokens") if len(tokens) == 0 { return resp.Data } token := tokens[0] //请求参数 req := map[string]int{ "id": id, } headers := map[string]string{ "token": token, } reqByte, _ := json.Marshal(req) err, respBytes := worker.DoPostRequestJSON(url, reqByte, headers) if err != nil { log.Println("GetUserInfoByIDFromUserCenterHttp error:", err) return resp.Data } if err2 := json.Unmarshal(respBytes, &resp); err2 != nil { log.Println("GetUserInfoByIDFromUserCenterHttp json unmarshal error:", err2) } return resp.Data } func GetUserByNameLike(name string) []dao.User { users := dao.FindUserByNameLike(name) for i, _ := range users { users[i].Password = "" } return users } // 获取默认前20个用户 func GetUsersDefault() []dao.User { users := dao.FindUsersDefault() for i, _ := range users { users[i].Password = "" } return users } func UpdateUser(user_id int, req proto.UpdateUserInfoReq) (int, error) { cur_user := dao.FindUserByID2(user_id) //fmt.Println("cur_user:", cur_user, "req:", req) if user_id == req.ID && cur_user.Role != "admin" { err := dao.UpdateUserByID3(user_id, req) //用户修改自己的信息,不能修改权限信息 //添加修改用户信息到同步列表 if err == nil { err2 := setSyncUserDataSet("update", user_id) UpdateUserCache(user_id) if err2 != nil { fmt.Println("set sync user data set error:", err2) return user_id, nil } } return user_id, err } else if cur_user.Role == "admin" { err := dao.UpdateUserByID2(req.ID, req) if err == nil { //添加修改用户信息到同步列表 err2 := setSyncUserDataSet("update", req.ID) UpdateUserCache(req.ID) if err2 != nil { fmt.Println("set sync user data set error:", err2) return req.ID, nil } } return req.ID, nil } else { return 0, nil } } func UpdateUserCache(id int) { key := "user_info_" + strconv.Itoa(id) if worker.IsContainKey(key) { user := dao.FindUserByID2(id) userJson, err := json.Marshal(user) if err != nil { fmt.Println("get user info , json marshal error:", err) } success := worker.SetRedis(key, string(userJson)) if !success { fmt.Println("set redis error,user json:", string(userJson)) } } } func DeleteUserService(id, user_id int) int { res := 0 if user_id == id { res = dao.DeleteUserByID(id) } else { user := dao.FindUserByID2(user_id) if user.Role == "admin" { res = dao.DeleteUserByID(id) } } if res != 0 { //添加删除用户信息到同步列表 err := setSyncUserDataSet("delete", id) if err != nil { return res } } return res } func UserSyncDataFromMaster() { //从接口获取数据 url := "https://" + proto.Config.MASTER_SERVER_DOMAIN + "/user/sync" tokens := worker.GetRedisSetMembers("super_permission_tokens") var req proto.SyncUserReq req.Token = tokens[0] req.Device = proto.Config.SERVER_NAME all := worker.GetRedis("user_sync_all") is_all := false //是否全量同步 if all == "" || all == "1" { is_all = true //清空数据表 err := dao.ClearAllUsers() if err != nil { fmt.Println("All ClearAllUsers error:", err) return } worker.SetRedisForever("user_sync_all", "1") req.Types = 1 } else { worker.SetRedisForever("user_sync_all", "2") req.Types = 2 } user_sync_data, err := worker.SyncDataFromMasterReq2(url, req) if err != nil { fmt.Println("UserSyncDataFromMaster error:", err) return } add_users := user_sync_data.Add update_users := user_sync_data.Update delete_users := user_sync_data.Delete //未成功操作的id var fail_ids []uint //添加用户 var add_confirm []proto.UserConfirmID for _, v := range add_users { res := dao.AddUserSync(v) if res == 0 { fail_ids = append(fail_ids, v.ID) } else { add_confirm = append(add_confirm, proto.UserConfirmID{ID: v.ID}) } } //更新用户 var update_confirm []proto.UserConfirmID for _, v := range update_users { res := dao.UpdateUserSync(v) if res == 0 { fail_ids = append(fail_ids, v.ID) } else { update_confirm = append(update_confirm, proto.UserConfirmID{ID: v.ID}) } } //删除用户 var delete_confirm []proto.UserConfirmID for _, v := range delete_users { res := dao.DeleteUserSync(v) if res == 0 { fail_ids = append(fail_ids, v.ID) } else { delete_confirm = append(delete_confirm, proto.UserConfirmID{ID: v.ID}) } } //确认同步数据 if is_all == false { var data proto.UserSyncConfirm data.Add = add_confirm data.Update = update_confirm data.Delete = delete_confirm //确认同步数据请求 var confirm_req proto.SyncUserReq confirm_req.Token = tokens[0] confirm_req.Device = proto.Config.SERVER_NAME confirm_req.Types = 3 confirm_req.Confirm = data worker.SyncDataFromMasterReq2(url, confirm_req) } else { worker.SetRedisForever("user_sync_all", "2") } } // 同步数据到主服务器-增删改数据 func GetUserSyncData(device string) dao.UserSyncResp { key := device + "_sync_user_ids" add_temp_key := device + "_sync_user_ids_add_confirm_temp" update_temp_key := device + "_sync_user_ids_update_confirm_temp" delete_temp_key := device + "_sync_user_ids_delete_confirm_temp" //需要获取暂存集合的并集,清空暂存集合,存入待确认集合 add_user_ids := worker.GetRedisSetUnion(key+"_add", add_temp_key) update_user_ids := worker.GetRedisSetUnion(key+"_update", update_temp_key) delete_user_ids := worker.GetRedisSetUnion(key+"_delete", delete_temp_key) add_users := []dao.User{} update_users := []dao.User{} delete_users := []proto.UserDelID{} for _, v := range add_user_ids { id, _ := strconv.Atoi(v) user := dao.FindUserByUserID(id) add_users = append(add_users, user) } for _, v := range update_user_ids { id, _ := strconv.Atoi(v) user := dao.FindUserByUserID(id) update_users = append(update_users, user) } for _, v := range delete_user_ids { id, _ := strconv.Atoi(v) delete_users = append(delete_users, proto.UserDelID{ID: uint(id)}) } //将id存入暂存集合,清空原集合,存入待确认集合主要保证在确认时,有新的数据加入不会在确认时漏掉 worker.SetRedisSetUnionAndStore(add_temp_key, key+"_add") worker.ClearRedisSet(key + "_add") worker.SetRedisSetUnionAndStore(update_temp_key, key+"_update") worker.ClearRedisSet(key + "_update") worker.SetRedisSetUnionAndStore(delete_temp_key, key+"_delete") worker.ClearRedisSet(key + "_delete") return dao.UserSyncResp{Add: add_users, Update: update_users, Delete: delete_users} } func setSyncUserDataSet(t string, id int) error { devices := worker.GetRedisSetMembers("sync_devices_ids") //主服务器查看从服务器的设备列表 fmt.Println("set sync user data set devices:", devices, "t:", t, "id:", id) var err error for _, device := range devices { key := device + "_sync_user_ids" if t == "add" { key_ := key + "_add" worker.SetRedisSetAdd(key_, strconv.Itoa(id)) } else if t == "update" { key_ := key + "_update" worker.SetRedisSetAdd(key_, strconv.Itoa(id)) } else if t == "delete" { key_ := key + "_delete" worker.SetRedisSetAdd(key_, strconv.Itoa(id)) } else { err = errors.New("error") } } return err } // 确认同步数据 func ConfirmSyncUserData(device string, data proto.UserSyncConfirm) error { var err error if len(data.Add) > 0 { var ids_add []string for _, v := range data.Add { ids_add = append(ids_add, strconv.Itoa(int(v.ID))) } add_key := device + "_sync_user_ids_add_confirm" isSuccess := worker.SetRedisSetAddBatchWithExpire(add_key, ids_add, time.Second*30) if !isSuccess { err = errors.New("set add confirm error") return err } ids_add_confirm_temp := device + "_sync_user_ids_add_confirm_temp" //取差集 add_diff := worker.SetRedisSetDiffAndStore(ids_add_confirm_temp, add_key) if add_diff == false { err = errors.New("add diff error") return err } } if len(data.Update) > 0 { var ids_update []string for _, v := range data.Update { ids_update = append(ids_update, strconv.Itoa(int(v.ID))) } update_key := device + "_sync_user_ids_update_confirm" isSuccess := worker.SetRedisSetAddBatchWithExpire(update_key, ids_update, time.Second*30) if !isSuccess { err = errors.New("set update confirm error") return err } ids_update_confirm_temp := device + "_sync_user_ids_update_confirm_temp" update_diff := worker.SetRedisSetDiffAndStore(ids_update_confirm_temp, update_key) if update_diff == false { err = errors.New("update diff error") return err } } if len(data.Delete) > 0 { var ids_delete []string for _, v := range data.Delete { ids_delete = append(ids_delete, strconv.Itoa(int(v.ID))) } del_key := device + "_sync_user_ids_delete_confirm" isSuccess := worker.SetRedisSetAddBatchWithExpire(del_key, ids_delete, time.Second*30) if !isSuccess { err = errors.New("set del confirm error") return err } //待确认集合暂存 ids_delete_confirm_temp := device + "_sync_user_ids_delete_confirm_temp" delete_diff := worker.SetRedisSetDiffAndStore(ids_delete_confirm_temp, del_key) if delete_diff == false { err = errors.New("delete diff error") return err } } return err } // 生成新的token,存入redis,返回信息 func CreateTokenAndSave(user dao.User) (string, error) { var tokenString string var err error key := "user_" + user.Name redis_token := worker.GetRedis(string(key)) if redis_token == "" { // 生成 JWT 令牌 token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "username": user.Name, "id": user.ID, "exp": time.Now().Add(time.Hour * 10).Unix(), // 令牌过期时间, 10小时后过期 }) tokenString, err = token.SignedString(proto.SigningKey) if err != nil { return "", err } worker.SetRedisWithExpire("user_"+user.Name, tokenString, time.Hour*10) // 将用户信息存入 worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*10) // 设置过期时间为10分钟 data := make(map[string]interface{}) data["id"] = user.ID data["username"] = user.Name data["email"] = user.Email worker.SetHash(tokenString, data) // 将用户信息存入 } else { tokenString = redis_token } // 返回令牌 return tokenString, err } func GetUserStatistics(userID int) dao.UserStatistics { return dao.UserStatisticsData(userID) } func CalculateUserTokenAndSetCache(user dao.User) (string, error) { // 生成 JWT 令牌 token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ "username": user.Name, "id": user.ID, "exp": time.Now().Add(time.Hour * 24).Unix(), // 令牌过期时间, 24小时后过期 }) tokenString, err := token.SignedString(proto.SigningKey) //设置缓存 worker.SetRedisWithExpire("user_"+user.Name, tokenString, time.Hour*24) // 将用户信息存入 worker.SetRedisWithExpire(tokenString, tokenString, time.Hour*24) // 设置过期时间为24小时 return tokenString, err } func GetUserInfoByToken(token string) (dao.User, error) { //解析token claims := jwt.MapClaims{} var user dao.User tkn, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { return proto.SigningKey, nil }) if err != nil { return user, err } if !tkn.Valid { return user, errors.New("token is invalid") } id := int(claims["id"].(float64)) user = GetUserByIDFromUserCenter(id) if user.ID == 0 { return user, errors.New("user not found") } return user, nil } // 获取用户前端配置信息 func GetUserUIConfigInfo(userID int) proto.UserUIConfigInfo { userConfig, err := dao.GetUserUIConfigInfo(userID) if err != nil { userConfig.UserID = userID //没有则插入 id, err2 := dao.CreateUserUIConfigInfo(userConfig) if err2 != nil { log.Println("InsertUserUIConfigInfo error:", err.Error()) } else { log.Println("InsertUserUIConfigInfo success, id:", id, "config:", userConfig) } } userConfig, err = dao.GetUserUIConfigInfo(userID) return userConfig } // 设置用户前端配置信息 func SetUserUIConfigInfo(userID int, config proto.UserUIConfigInfo) error { //先查询是否有该用户的配置信息 userConfig, err := dao.GetUserUIConfigInfo(userID) if err != nil { log.Println("SetUserUIConfigInfo error:", err) } config.UserID = userID if userConfig.UserID == 0 { //没有则插入 id, err2 := dao.CreateUserUIConfigInfo(config) if err2 != nil { log.Println("InsertUserUIConfigInfo error:", err.Error()) return err } else { log.Println("InsertUserUIConfigInfo success, id:", id, "config:", config) } } else { //有则更新 err3 := dao.UpdateUserUIConfigInfo(userID, config) if err3 != nil { log.Println("UpdateUserUIConfigInfo error:", err) return err } } return nil }