add
This commit is contained in:
parent
772ad415ee
commit
7200c6c99b
8
brotato/.idea/.gitignore
vendored
Normal file
8
brotato/.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
9
brotato/.idea/brotato.iml
Normal file
9
brotato/.idea/brotato.iml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
5
brotato/.idea/inspectionProfiles/Project_Default.xml
Normal file
5
brotato/.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
8
brotato/.idea/modules.xml
Normal file
8
brotato/.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/brotato.iml" filepath="$PROJECT_DIR$/.idea/brotato.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
4
brotato/.idea/vcs.xml
Normal file
4
brotato/.idea/vcs.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||||
|
</project>
|
10
brotato/go.mod
Normal file
10
brotato/go.mod
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module brotato
|
||||||
|
|
||||||
|
go 1.23.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
|
golang.org/x/crypto v0.28.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require filippo.io/edwards25519 v1.1.0 // indirect
|
6
brotato/go.sum
Normal file
6
brotato/go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||||
|
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
17
brotato/main.go
Normal file
17
brotato/main.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
var db *sql.DB
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
initweb()
|
||||||
|
//openFileDate()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TIP See GoLand help at <a href="https://www.jetbrains.com/help/go/">jetbrains.com/help/go/</a>.
|
||||||
|
// Also, you can try interactive lessons for GoLand by selecting 'Help | Learn IDE Features' from the main menu.
|
13
brotato/playerInfo.json
Normal file
13
brotato/playerInfo.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"id": 123456821,
|
||||||
|
"userName": "player137",
|
||||||
|
"url": "https://example.com/pic.png",
|
||||||
|
|
||||||
|
"openId": "119",
|
||||||
|
"parentAddress": "66666",
|
||||||
|
"language": "en",
|
||||||
|
"tg_userid":"123456828player132"
|
||||||
|
}
|
968
brotato/web.go
Normal file
968
brotato/web.go
Normal file
@ -0,0 +1,968 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
_ "github.com/go-sql-driver/mysql" // MySQL 驱动
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initweb() {
|
||||||
|
var err error
|
||||||
|
db, err = sql.Open("mysql", "root:43994399@tcp(192.168.2.19:3306)/brotato") /*******************/
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("数据库连接失败: ", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
err = db.Ping()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("数据库连接不可用: ", err)
|
||||||
|
}
|
||||||
|
log.Println("数据库连接")
|
||||||
|
|
||||||
|
// 创建 ServeMux 实例
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
// 注册 /login 路由,绑定到 loginHandler
|
||||||
|
mux.HandleFunc("/loginHandler", loginHandler) //登录与注册
|
||||||
|
//mux.HandleFunc("/getPerson", getPerson)
|
||||||
|
mux.HandleFunc("/showDailyTaskHandler", showDailyTaskHandler) //每日任务
|
||||||
|
mux.HandleFunc("/inviteeListHandler", inviteeListHandler) //返回邀请好友列表(和邀请奖励)
|
||||||
|
mux.HandleFunc("/userInfoHandler", userInfoHandler) //以openId为查询返回所有用户数据的方法(会有用的)
|
||||||
|
mux.HandleFunc("/goldCommodityHandler", goldCommodityHandler) //金币商店列表
|
||||||
|
mux.HandleFunc("/rankingListHandler", rankingListHandler) //排行榜
|
||||||
|
mux.HandleFunc("/saveHandler", saveHandler) // 注册存档路由
|
||||||
|
mux.HandleFunc("/loadHandler", loadHandler) // 注册加载路由
|
||||||
|
|
||||||
|
log.Println("服务器启动,监听端口: 8080")
|
||||||
|
|
||||||
|
//openFileDate() // 打开 json 文件并解析数据
|
||||||
|
err = http.ListenAndServe(":8080", mux) // 使用 mux 作为路由器
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("ListenAndServe: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开json文件函数
|
||||||
|
/*func openFileDate() {
|
||||||
|
// 打开 JSON 文件
|
||||||
|
jsonFile, err := os.Open("playerInfo.json")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("无法打开文件: %v", err)
|
||||||
|
}
|
||||||
|
defer jsonFile.Close()
|
||||||
|
|
||||||
|
// 读取文件的内容
|
||||||
|
byteValue, _ := ioutil.ReadAll(jsonFile)
|
||||||
|
|
||||||
|
// 解析 JSON 数据到结构体
|
||||||
|
err = json.Unmarshal(byteValue, &person)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("解析 JSON 数据失败: %v", err)
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
/*************************************************一个方法,以open Id为查询,能返回当前用户所有数据***************************************************/
|
||||||
|
// User 结构体用于存储查询结果
|
||||||
|
type User struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserName sql.NullString `json:"-"` // 允许 NULL 值
|
||||||
|
Url sql.NullString `json:"-"`
|
||||||
|
Gold int `json:"gold"`
|
||||||
|
RandCode sql.NullString `json:"-"`
|
||||||
|
OpenId string `json:"openId"`
|
||||||
|
ParentAddress sql.NullString `json:"-"`
|
||||||
|
Language sql.NullString `json:"-"`
|
||||||
|
TgUserId sql.NullString `json:"-"`
|
||||||
|
LastLoginAt sql.NullString `json:"-"`
|
||||||
|
RegisteredAt sql.NullString `json:"-"`
|
||||||
|
InviteReward int `json:"inviteReward"`
|
||||||
|
InviteCode sql.NullString `json:"-"`
|
||||||
|
NickName sql.NullString `json:"-"`
|
||||||
|
Ranks sql.NullInt64 `json:"-"`
|
||||||
|
TopScore sql.NullInt64 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONUser 结构体用于返回 JSON 数据
|
||||||
|
type JSONUser struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Gold int `json:"gold"`
|
||||||
|
RandCode string `json:"randCode"`
|
||||||
|
OpenId string `json:"openId"`
|
||||||
|
ParentAddress string `json:"parentAddress"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
TgUserId string `json:"tg_userid"`
|
||||||
|
LastLoginAt string `json:"lastLoginAt"`
|
||||||
|
RegisteredAt string `json:"registeredAt"`
|
||||||
|
InviteReward int `json:"inviteReward"`
|
||||||
|
InviteCode string `json:"inviteCode"`
|
||||||
|
NickName string `json:"nickName"`
|
||||||
|
Ranks int `json:"ranking"`
|
||||||
|
TopScore int `json:"topScore"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换函数,将 User 转换为 JSONUser,并处理 NULL 值
|
||||||
|
func (u *User) toJSONUser() JSONUser {
|
||||||
|
return JSONUser{
|
||||||
|
Id: u.Id,
|
||||||
|
UserName: nullStringToString(u.UserName),
|
||||||
|
Url: nullStringToString(u.Url),
|
||||||
|
Gold: u.Gold,
|
||||||
|
RandCode: nullStringToString(u.RandCode),
|
||||||
|
OpenId: u.OpenId,
|
||||||
|
ParentAddress: nullStringToString(u.ParentAddress),
|
||||||
|
Language: nullStringToString(u.Language),
|
||||||
|
TgUserId: nullStringToString(u.TgUserId),
|
||||||
|
LastLoginAt: nullStringToString(u.LastLoginAt),
|
||||||
|
RegisteredAt: nullStringToString(u.RegisteredAt),
|
||||||
|
InviteReward: u.InviteReward,
|
||||||
|
InviteCode: nullStringToString(u.InviteCode),
|
||||||
|
NickName: nullStringToString(u.NickName),
|
||||||
|
Ranks: nullIntToInt(u.Ranks),
|
||||||
|
TopScore: nullIntToInt(u.TopScore),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数,将 sql.NullString 转为字符串
|
||||||
|
func nullStringToString(ns sql.NullString) string {
|
||||||
|
if ns.Valid {
|
||||||
|
return ns.String
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数,将 sql.NullInt64 转为 int
|
||||||
|
func nullIntToInt(ni sql.NullInt64) int {
|
||||||
|
if ni.Valid {
|
||||||
|
return int(ni.Int64)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询并返回用户信息
|
||||||
|
func getUserInfoByOpenId(db *sql.DB, openId string) (User, error) {
|
||||||
|
var user User
|
||||||
|
|
||||||
|
query := `
|
||||||
|
SELECT id, userName, url, gold, randCode, openId, parentAddress, language, tg_userid,
|
||||||
|
lastLoginAt, registeredAt, inviteReward, inviteCode, nickName, ranks, topScore
|
||||||
|
FROM users WHERE openId = ?`
|
||||||
|
|
||||||
|
err := db.QueryRow(query, openId).Scan(
|
||||||
|
&user.Id,
|
||||||
|
&user.UserName,
|
||||||
|
&user.Url,
|
||||||
|
&user.Gold,
|
||||||
|
&user.RandCode,
|
||||||
|
&user.OpenId,
|
||||||
|
&user.ParentAddress,
|
||||||
|
&user.Language,
|
||||||
|
&user.TgUserId,
|
||||||
|
&user.LastLoginAt,
|
||||||
|
&user.RegisteredAt,
|
||||||
|
&user.InviteReward,
|
||||||
|
&user.InviteCode,
|
||||||
|
&user.NickName,
|
||||||
|
&user.Ranks,
|
||||||
|
&user.TopScore,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
// 返回自定义错误消息,指示未找到记录
|
||||||
|
return user, fmt.Errorf("用户不存在,openId: %s", openId)
|
||||||
|
} else if err != nil {
|
||||||
|
// 返回其他查询错误
|
||||||
|
return user, fmt.Errorf("查询出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理请求,返回用户信息
|
||||||
|
func userInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req struct {
|
||||||
|
OpenId string `json:"openId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error decoding request body: %v\n", err)
|
||||||
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := getUserInfoByOpenId(db, req.OpenId)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == fmt.Sprintf("用户不存在,openId: %s", req.OpenId) {
|
||||||
|
log.Printf("User not found for openId: %s\n", req.OpenId)
|
||||||
|
http.Error(w, "User not found", http.StatusNotFound)
|
||||||
|
} else {
|
||||||
|
log.Printf("Error retrieving user info: %v\n", err)
|
||||||
|
http.Error(w, "Error retrieving user info", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 JSON 格式的用户信息
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(user.toJSONUser()); err != nil {
|
||||||
|
log.Printf("Error encoding user info to JSON: %v\n", err)
|
||||||
|
http.Error(w, "Error encoding user info to JSON", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************登录与注册********************************************/
|
||||||
|
var person Person
|
||||||
|
|
||||||
|
// 定义玩家,接收所有玩家信息
|
||||||
|
type Person struct {
|
||||||
|
Id int `json:"id"` //数据库中的标识,会自增
|
||||||
|
UserName string `json:"userName"` //昵称(甲方要求每次登录刷新)
|
||||||
|
Url string `json:"url"` //头像的URL
|
||||||
|
Gold int `json:"gold"` //金币
|
||||||
|
RandCode string `json:"randCode"` //随机码,注册时生成,登录会刷新
|
||||||
|
OpenId string `json:"openId"` //openid
|
||||||
|
ParentAddress string `json:"parentAddress"` //上级地址
|
||||||
|
Language string `json:"language"` //语言(甲方要求每次登录刷新)(刷新功能未完成)
|
||||||
|
Tg_userid string `json:"tg_userid"` //tgid
|
||||||
|
InviteCode string `json:"inviteCode"` //玩家注册时生成并插入的邀请码,不会刷新
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查用户是否存在
|
||||||
|
func checkUserExists(db *sql.DB, openId string) (bool, error) {
|
||||||
|
log.Println("传入的 openId: ", openId) /**************************************************/
|
||||||
|
var exists bool
|
||||||
|
// 查询数据库中是否存在传入的 openid
|
||||||
|
query := "SELECT COUNT(*) FROM users WHERE openId = ?"
|
||||||
|
|
||||||
|
// 使用 db.QueryRow() 执行查询,查询结果存储在 exists 变量中
|
||||||
|
err := db.QueryRow(query, openId).Scan(&exists)
|
||||||
|
if err != nil {
|
||||||
|
return false, err // 如果查询出错,返回错误
|
||||||
|
}
|
||||||
|
return exists, nil // 返回查询结果,存在则为 true,不存在为 false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录或注册函数
|
||||||
|
func loginOrRegister(db *sql.DB, openid, userName, url, parentAddress, language, tg_userid string) (string, error) {
|
||||||
|
// 调用 checkUserExists() 函数,检查用户是否存在
|
||||||
|
exists, err := checkUserExists(db, openid)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error checking user exists: %v\n", err)
|
||||||
|
return "500", err // 如果查询出错,返回错误
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每次登录生成新的随机码
|
||||||
|
person.RandCode = generateRandomCode()
|
||||||
|
//甲方要求的每次登录刷新userName
|
||||||
|
person.UserName = generateRandomCode()
|
||||||
|
|
||||||
|
// 获取当前时间作为登录和注册时间
|
||||||
|
currentTime := time.Now()
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
// 如果用户已存在,更新数据库中的 RandCode 和 lastLoginAt
|
||||||
|
updateRandCode := "UPDATE users SET userName = ?,randCode = ?, lastLoginAt = ? WHERE openid = ?"
|
||||||
|
_, err := db.Exec(updateRandCode, person.UserName, person.RandCode, currentTime, openid)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error updating MySQL users")
|
||||||
|
return "500", err // 如果更新失败,返回错误
|
||||||
|
}
|
||||||
|
log.Printf("用户 %s 登录成功, 生成的新随机码: %s,生成新的userName:%s, 登录时间: %s", openid, person.RandCode, person.UserName, currentTime.Format("2006-01-02 15:04:05"))
|
||||||
|
return "200", nil
|
||||||
|
} else {
|
||||||
|
// 如果 userName, url, parentAddress, language, tg_userid 没有传入,默认设置为空字符串
|
||||||
|
if userName == "" {
|
||||||
|
userName = person.UserName
|
||||||
|
}
|
||||||
|
if url == "" {
|
||||||
|
url = ""
|
||||||
|
}
|
||||||
|
if parentAddress == "" {
|
||||||
|
parentAddress = ""
|
||||||
|
}
|
||||||
|
if language == "" {
|
||||||
|
language = ""
|
||||||
|
}
|
||||||
|
if tg_userid == "" {
|
||||||
|
tg_userid = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//玩家注册时用随机码生成一个邀请码插入数据库,这个不会改变
|
||||||
|
person.InviteCode = generateRandomCode()
|
||||||
|
// 如果用户不存在,生成新的随机码并插入相关信息,包括注册时间和登录时间
|
||||||
|
//当玩家注册时,随机生成一个邀请码插入数据库,这个不会改变
|
||||||
|
insertOpenId := "INSERT INTO users (openid, userName, url, randCode, parentAddress, language, tg_userid, registeredAt, lastLoginAt,inviteCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,?)"
|
||||||
|
_, err := db.Exec(insertOpenId, openid, userName, url, person.RandCode, parentAddress, language, tg_userid, currentTime, currentTime, person.InviteCode) // 执行插入操作
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error inserting MySQL users")
|
||||||
|
return "500", err // 如果插入出错,返回错误
|
||||||
|
}
|
||||||
|
log.Printf("用户 %s 注册成功, 生成的新随机码: %s,生成的userName:%s, 注册时间: %s,邀请码:%s", openid, person.RandCode, person.UserName, currentTime.Format("2006-01-02 15:04:05"), person.InviteCode)
|
||||||
|
return "200", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成随机码RandCode
|
||||||
|
func generateRandomCode() string {
|
||||||
|
const length = 16 // 随机码的长度
|
||||||
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
randCode := make([]byte, length)
|
||||||
|
for i := range randCode {
|
||||||
|
randCode[i] = charset[rand.Intn(len(charset))]
|
||||||
|
}
|
||||||
|
return string(randCode)
|
||||||
|
}
|
||||||
|
func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 定义用于接收 JSON 请求体的结构体
|
||||||
|
var req struct {
|
||||||
|
OpenId string `json:"openId"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
ParentAddress string `json:"parentAddress"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
TgUserId string `json:"tg_userid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 json.NewDecoder() 将请求体中的 JSON 数据解析为结构体
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 loginOrRegister() 函数,传入解析出的参数
|
||||||
|
message, err := loginOrRegister(db, req.OpenId, req.UserName, req.Url, req.ParentAddress, req.Language, req.TgUserId)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "登录或注册过程出错", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 JSON 格式的响应,包含登录或注册的结果
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{
|
||||||
|
"message": message,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ******************************************************************每日任务********************************************************************/
|
||||||
|
// 任务列表
|
||||||
|
type DailyTask struct {
|
||||||
|
TaskId int `json:"task_id"`
|
||||||
|
Reward string `json:"reward"`
|
||||||
|
IsComplete bool `json:"is_complete"`
|
||||||
|
EvenId int `json:"even_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func showDailyTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 定义用于接收 JSON 请求体的结构体
|
||||||
|
var req struct {
|
||||||
|
AskDailyTask string `json:"AskDailyTask"`
|
||||||
|
}
|
||||||
|
// 使用 json.NewDecoder() 将请求体中的 JSON 数据解析为结构体
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 showDailyTask() 函数,传入解析出的参数
|
||||||
|
tasks, err := showDailyTask(db, req.AskDailyTask)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error retrieving daily tasks", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印任务列表到服务器日志
|
||||||
|
for _, task := range tasks {
|
||||||
|
log.Printf("Task ID: %d, Reward: %s, IsComplete: %v, Event ID: %d\n",
|
||||||
|
task.TaskId, task.Reward, task.IsComplete, task.EvenId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 JSON 格式的响应,包含每日任务表
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
err = json.NewEncoder(w).Encode(tasks) // tasks 是一个切片,因此直接编码为 JSON
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Error encoding response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// 测试代码,功能与上面那个方法相同,但有更多日志打印。出现问题用它
|
||||||
|
func showDailyTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 定义用于接收 JSON 请求体的结构体
|
||||||
|
var req struct {
|
||||||
|
AskDailyTask string `json:"AskDailyTask"`
|
||||||
|
}
|
||||||
|
// 使用 json.NewDecoder() 将请求体中的 JSON 数据解析为结构体
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error decoding request body: %v\n", err) // 打印解码错误
|
||||||
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 showDailyTask() 函数,传入解析出的参数
|
||||||
|
tasks, err := showDailyTask(db, req.AskDailyTask)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error retrieving tasks: %v\n", err) // 打印任务获取错误
|
||||||
|
http.Error(w, "Error retrieving daily tasks", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印任务列表到服务器日志
|
||||||
|
for _, task := range tasks {
|
||||||
|
log.Printf("Task ID: %d, Reward: %s, IsComplete: %v, Event ID: %d\n",
|
||||||
|
task.TaskId, task.Reward, task.IsComplete, task.EvenId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 JSON 格式的响应,包含每日任务表
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
err = json.NewEncoder(w).Encode(tasks) // tasks 是一个切片,因此直接编码为 JSON
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error encoding tasks to JSON: %v\n", err) // 打印编码错误
|
||||||
|
http.Error(w, "Error encoding response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 展示任务列表
|
||||||
|
func showDailyTask(db *sql.DB, string2 string) ([]DailyTask, error) {
|
||||||
|
// 查询数据库
|
||||||
|
rows, err := db.Query("SELECT taskId, reward, isComplete, evenId FROM dailytask")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("query error: %v", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// 存储任务列表的切片
|
||||||
|
var tasks []DailyTask
|
||||||
|
|
||||||
|
// 遍历查询结果
|
||||||
|
for rows.Next() {
|
||||||
|
var task DailyTask
|
||||||
|
// 扫描每行数据到 DailyTask 结构体
|
||||||
|
err := rows.Scan(&task.TaskId, &task.Reward, &task.IsComplete, &task.EvenId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("scan error: %v", err)
|
||||||
|
}
|
||||||
|
tasks = append(tasks, task)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 rows.Next() 是否有发生错误
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("rows iteration error: %v", err)
|
||||||
|
}
|
||||||
|
// 返回任务列表
|
||||||
|
return tasks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************返回邀请好友列表(和邀请奖励)*************************************************************/
|
||||||
|
|
||||||
|
type Invitee struct {
|
||||||
|
InviteeId int `json:"invitee_id"`
|
||||||
|
InviteeName string `json:"invitee_userName"`
|
||||||
|
InviteeOpenId string `json:"invitee_open_id"`
|
||||||
|
InviteeUrl string `json:"invitee_url"`
|
||||||
|
InviteReward int `json:"invite_reward"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Inviter struct {
|
||||||
|
InviterUrl string `json:"inviter_url"`
|
||||||
|
InviterId int `json:"inviter_id"`
|
||||||
|
InviterOpenId string `json:"openId"`
|
||||||
|
InviterUserName string `json:"userName"`
|
||||||
|
InviterNickName sql.NullString `json:"nickName"` // 处理可能为 NULL 的字段
|
||||||
|
Gold int `json:"gold"`
|
||||||
|
InviteCode string `json:"invite_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个结构体,用于同时返回邀请者和被邀请者信息
|
||||||
|
type InviteeResponse struct {
|
||||||
|
Invitees []Invitee `json:"invitees"`
|
||||||
|
Inviter Inviter `json:"inviter"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// inviteeListHandler 处理 HTTP 请求,返回某个用户邀请的好友列表和邀请者信息
|
||||||
|
func inviteeListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 定义用于接收 JSON 请求体的结构体
|
||||||
|
var req struct {
|
||||||
|
OpenId string `json:"openId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 json.NewDecoder() 将请求体中的 JSON 数据解析为结构体
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&req)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error decoding request body: %v\n", err) // 打印解码错误
|
||||||
|
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 inviteeList() 函数,传入解析出的参数
|
||||||
|
invitees, err := inviteeList(db, req.OpenId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error retrieving invitee list: %v\n", err) // 打印错误日志
|
||||||
|
http.Error(w, "Error retrieving invitee list", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印邀请的好友列表信息到服务器日志
|
||||||
|
log.Println("----- 邀请的好友列表信息 -----")
|
||||||
|
for _, invitee := range invitees {
|
||||||
|
log.Printf("好友ID: %d, 用户名: %s, OpenId: %s, 头像URL: %s, 邀请奖励: %d", invitee.InviteeId, invitee.InviteeName, invitee.InviteeOpenId, invitee.InviteeUrl, invitee.InviteReward)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 inviter() 函数,传入解析出的参数
|
||||||
|
inviterList, err := inviter(db, req.OpenId)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error retrieving inviter: %v\n", err) // 打印错误日志
|
||||||
|
http.Error(w, "Error retrieving inviter", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 假设邀请者只会有一个,获取第一个邀请者
|
||||||
|
var inviter Inviter
|
||||||
|
if len(inviterList) > 0 {
|
||||||
|
inviter = inviterList[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印邀请者信息到服务器日志
|
||||||
|
log.Println("----- 邀请者信息 -----")
|
||||||
|
log.Printf("邀请者ID: %d, 用户名: %s, OpenId: %s, 称号: %s, 头像URL: %s, 金币: %d,邀请码:%s", inviter.InviterId, inviter.InviterUserName, inviter.InviterOpenId, inviter.InviterNickName.String, inviter.InviterUrl, inviter.Gold, inviter.InviteCode)
|
||||||
|
|
||||||
|
// 创建一个结构体,包含邀请者和被邀请者信息
|
||||||
|
response := InviteeResponse{
|
||||||
|
Invitees: invitees,
|
||||||
|
Inviter: inviter,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回 JSON 格式的邀请好友列表和邀请者信息
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
err = json.NewEncoder(w).Encode(response)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error encoding invitee and inviter list to JSON: %v\n", err) // 打印编码错误日志
|
||||||
|
http.Error(w, "Error encoding invitee and inviter list to JSON", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inviteeList 查询数据库,返回某个用户邀请的好友列表
|
||||||
|
func inviteeList(db *sql.DB, parentAddress string) ([]Invitee, error) {
|
||||||
|
// 查询数据库,获取邀请者的好友列表
|
||||||
|
rows, err := db.Query("SELECT url,id, userName,openId,inviteReward FROM users WHERE parentAddress = ?", parentAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("query error: %v", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// 存储好友列表的切片
|
||||||
|
var invitees []Invitee
|
||||||
|
|
||||||
|
// 遍历查询结果
|
||||||
|
for rows.Next() {
|
||||||
|
var invitee Invitee
|
||||||
|
// 扫描每行数据到 Invitee 结构体
|
||||||
|
err := rows.Scan(&invitee.InviteeUrl, &invitee.InviteeId, &invitee.InviteeName, &invitee.InviteeOpenId, &invitee.InviteReward)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("scan error: %v", err)
|
||||||
|
}
|
||||||
|
invitees = append(invitees, invitee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 rows.Next() 是否有发生错误
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("rows iteration error: %v", err)
|
||||||
|
}
|
||||||
|
// 返回好友列表
|
||||||
|
return invitees, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// inviter查询邀请者的信息
|
||||||
|
func inviter(db *sql.DB, openId string) ([]Inviter, error) {
|
||||||
|
// 查询数据库,获取邀请者的好友列表
|
||||||
|
rows, err := db.Query("SELECT url, id, openId, userName, nickName, gold,inviteCode FROM users WHERE openId = ?", openId)
|
||||||
|
if err != nil {
|
||||||
|
// 如果查询过程中发生错误,返回nil和错误信息
|
||||||
|
return nil, fmt.Errorf("查询出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rows.Close() // 确保查询结束后关闭行集
|
||||||
|
|
||||||
|
var inviters []Inviter // 定义一个Inviter切片用于存储查询结果
|
||||||
|
|
||||||
|
// 遍历查询结果
|
||||||
|
for rows.Next() {
|
||||||
|
var inviter Inviter
|
||||||
|
// 扫描每行数据到 Inviter 结构体,处理 nickName 为 sql.NullString 类型
|
||||||
|
err := rows.Scan(&inviter.InviterUrl, &inviter.InviterId, &inviter.InviterOpenId, &inviter.InviterUserName, &inviter.InviterNickName, &inviter.Gold, &inviter.InviteCode)
|
||||||
|
if err != nil {
|
||||||
|
// 如果扫描过程中出现错误,返回nil和错误信息
|
||||||
|
return nil, fmt.Errorf("扫描出错: %v", err)
|
||||||
|
}
|
||||||
|
inviters = append(inviters, inviter) // 将扫描到的用户信息追加到切片中
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 rows.Next() 是否有发生错误
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("行遍历出错: %v", err)
|
||||||
|
}
|
||||||
|
// 返回查询结果的邀请者列表
|
||||||
|
return inviters, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************金币商品页面************************************************************/
|
||||||
|
// GoldCommodity 结构体表示 goldcommodity 表的每一行
|
||||||
|
type GoldCommodity struct {
|
||||||
|
CommodityGold int `json:"commodityGold"`
|
||||||
|
Commodity string `json:"commodity"`
|
||||||
|
Price string `json:"price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getGoldCommodities 从 goldcommodity 表中查询所有数据并返回
|
||||||
|
func getGoldCommodities(db *sql.DB) ([]GoldCommodity, error) {
|
||||||
|
// 查询整个 goldcommodity 表
|
||||||
|
rows, err := db.Query("SELECT commodityGold, commodity, price FROM goldcommodity")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("查询出错: %v", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var commodities []GoldCommodity
|
||||||
|
|
||||||
|
// 遍历查询结果,将每行数据扫描到 GoldCommodity 结构体中
|
||||||
|
for rows.Next() {
|
||||||
|
var commodity GoldCommodity
|
||||||
|
err := rows.Scan(&commodity.CommodityGold, &commodity.Commodity, &commodity.Price)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("扫描出错: %v", err)
|
||||||
|
}
|
||||||
|
commodities = append(commodities, commodity)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 rows.Next() 是否有其他错误
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("行遍历出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return commodities, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// goldCommodityHandler 处理 HTTP 请求,返回 goldcommodity 表中的所有数据
|
||||||
|
func goldCommodityHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 查询 goldcommodity 表中的所有数据
|
||||||
|
commodities, err := getGoldCommodities(db)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error retrieving gold commodities: %v\n", err)
|
||||||
|
http.Error(w, "Error retrieving gold commodities", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置响应头为 JSON 格式并返回数据
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(commodities); err != nil {
|
||||||
|
log.Printf("Error encoding commodities to JSON: %v\n", err)
|
||||||
|
http.Error(w, "Error encoding commodities to JSON", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************排行榜数据*************************************************************/
|
||||||
|
// 定义 ranking 结构体
|
||||||
|
type ranking struct {
|
||||||
|
UserId int `json:"userId"`
|
||||||
|
Rank int `json:"rank"`
|
||||||
|
TopScore int `json:"topScore"`
|
||||||
|
NickName string `json:"nickName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询排行榜数据
|
||||||
|
|
||||||
|
// +++++++++++++++++++++++++++++++++++返回前三+++++++++++++++++++++++++++++++++++++/
|
||||||
|
func rankingListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 在查询排行榜数据之前,先更新排名
|
||||||
|
err := updatePlayerRankings(db)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error updating player rankings: %v\n", err)
|
||||||
|
http.Error(w, "Error updating player rankings", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 top N 排行榜数据
|
||||||
|
// 请根据您的需要修改 TopNumber 的值
|
||||||
|
// 例如,TopNumber = 100,则返回排行榜前 100 名
|
||||||
|
// 例如,TopNumber = 500,则返回排行榜前 500 名
|
||||||
|
// 注意:TopNumber 的值越大,返回的数据量越大,但也会占用更多的 CPU 和内存
|
||||||
|
// 请根据您的应用的需要和 CPU 和内存的情况来决定 TopNumber 的值
|
||||||
|
// 例如,TopNumber = 1000,但您的应用 CPU 和内存都有 8GB,可能需要 30-60 秒才能返回结果
|
||||||
|
// 例如,TopNumber = 50
|
||||||
|
TopNumber := 3 // 假设要获取前 3 名
|
||||||
|
rows, err := db.Query("SELECT id, ranks, topScore, nickName FROM playerranking ORDER BY topScore DESC LIMIT ?", TopNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error retrieving ranking list: %v\n", err)
|
||||||
|
http.Error(w, "Error retrieving ranking list", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// 定义一个 ranking 切片来存储查询结果
|
||||||
|
var rankings []ranking
|
||||||
|
|
||||||
|
// 遍历查询结果,将每行数据扫描到 ranking 结构体中
|
||||||
|
for rows.Next() {
|
||||||
|
var rank ranking
|
||||||
|
err := rows.Scan(&rank.UserId, &rank.Rank, &rank.TopScore, &rank.NickName)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error scanning ranking data: %v\n", err)
|
||||||
|
http.Error(w, "Error processing ranking data", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rankings = append(rankings, rank)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查遍历行集时是否发生错误
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
log.Printf("Error iterating over rows: %v\n", err)
|
||||||
|
http.Error(w, "Error retrieving ranking data", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置响应头为 JSON 格式并返回数据
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(rankings); err != nil {
|
||||||
|
log.Printf("Error encoding ranking list to JSON: %v\n", err)
|
||||||
|
http.Error(w, "Error encoding ranking list to JSON", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新玩家排名并同步到 users 表
|
||||||
|
func updatePlayerRankings(db *sql.DB) error {
|
||||||
|
// 1. 初始化排名变量
|
||||||
|
_, err := db.Exec("SET @ranks := 0;")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("初始化排名变量时出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 更新 playerranking 表中的 rank
|
||||||
|
updateRankSQL := `
|
||||||
|
UPDATE playerranking
|
||||||
|
SET ranks = (@ranks := @ranks + 1)
|
||||||
|
ORDER BY topScore DESC;
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = db.Exec(updateRankSQL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("更新排名时出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 将 playerranking 表中的 rank 和 topScore 同步到 users 表
|
||||||
|
syncRankTopScoreSQL := `
|
||||||
|
UPDATE users u
|
||||||
|
JOIN playerranking p ON u.id = p.id
|
||||||
|
SET u.ranks = p.ranks, u.topScore = p.topScore;
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = db.Exec(syncRankTopScoreSQL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("同步 rank 和 topScore 到 users 表时出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 将 users 表中的 nickName 同步到 playerranking 表
|
||||||
|
syncNickNameSQL := `
|
||||||
|
UPDATE playerranking p
|
||||||
|
JOIN users u ON p.id = u.id
|
||||||
|
SET p.nickName = u.nickName;
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = db.Exec(syncNickNameSQL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("同步 nickName 到 playerranking 表时出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************存档****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
前端应传来的json格式
|
||||||
|
|
||||||
|
{
|
||||||
|
"save_index": 1,
|
||||||
|
"backup_index": 0,
|
||||||
|
"major_data": {"level": 5, "progress": "50%"},
|
||||||
|
"minor_data": {"cutsceneEnded": true},
|
||||||
|
"real_time_data": {"npcSeen": true, "patchID": 123}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// SaveData 结构体定义
|
||||||
|
type SaveData struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
SaveIndex int `json:"save_index"`
|
||||||
|
BackupIndex int `json:"backup_index"`
|
||||||
|
MajorData json.RawMessage `json:"major_data"`
|
||||||
|
MinorData json.RawMessage `json:"minor_data"`
|
||||||
|
RealTimeData json.RawMessage `json:"real_time_data"`
|
||||||
|
Timestamp sql.NullTime `json:"timestamp"` // 使用 sql.NullTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存档数据到数据库
|
||||||
|
func saveToDatabase(db *sql.DB, data SaveData) error {
|
||||||
|
query := `
|
||||||
|
INSERT INTO save_data (save_index, backup_index, major_data, minor_data, real_time_data, timestamp)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
`
|
||||||
|
_, err := db.Exec(query,
|
||||||
|
data.SaveIndex,
|
||||||
|
data.BackupIndex,
|
||||||
|
data.MajorData,
|
||||||
|
data.MinorData,
|
||||||
|
data.RealTimeData,
|
||||||
|
data.Timestamp,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("保存数据到数据库时出错: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从数据库加载存档
|
||||||
|
func loadFromDatabase(db *sql.DB, saveIndex, backupIndex int) (SaveData, error) {
|
||||||
|
var data SaveData
|
||||||
|
var timestampStr string // 使用字符串接收 Timestamp 字段
|
||||||
|
|
||||||
|
query := "SELECT save_index, backup_index, major_data, minor_data, real_time_data, timestamp FROM save_data WHERE save_index = ? AND backup_index = ?"
|
||||||
|
err := db.QueryRow(query, saveIndex, backupIndex).Scan(
|
||||||
|
&data.SaveIndex,
|
||||||
|
&data.BackupIndex,
|
||||||
|
&data.MajorData,
|
||||||
|
&data.MinorData,
|
||||||
|
&data.RealTimeData,
|
||||||
|
×tampStr, // 将 timestamp 作为字符串接收
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动解析 timestampStr 为 time.Time
|
||||||
|
parsedTime, err := time.Parse("2006-01-02 15:04:05", timestampStr)
|
||||||
|
if err != nil {
|
||||||
|
return data, fmt.Errorf("解析时间戳时出错: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Timestamp = sql.NullTime{
|
||||||
|
Time: parsedTime,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存档处理函数
|
||||||
|
func saveHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("请求方法: %s, 请求路径: %s\n", r.Method, r.URL.Path) // 打印请求方法和路径
|
||||||
|
|
||||||
|
// 检查请求方法是否为 GET
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(w, "请求方法错误,仅支持 GET", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从查询参数中获取存档数据
|
||||||
|
saveIndexStr := r.URL.Query().Get("save_index")
|
||||||
|
backupIndexStr := r.URL.Query().Get("backup_index")
|
||||||
|
majorDataStr := r.URL.Query().Get("major_data")
|
||||||
|
minorDataStr := r.URL.Query().Get("minor_data")
|
||||||
|
realTimeDataStr := r.URL.Query().Get("real_time_data")
|
||||||
|
|
||||||
|
// 转换 save_index 和 backup_index 为整数
|
||||||
|
saveIndex, err := strconv.Atoi(saveIndexStr)
|
||||||
|
backupIndex, err := strconv.Atoi(backupIndexStr)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "索引参数错误", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 JSON 字符串转换为对应的结构
|
||||||
|
var majorData, minorData, realTimeData json.RawMessage
|
||||||
|
err = json.Unmarshal([]byte(majorDataStr), &majorData)
|
||||||
|
err = json.Unmarshal([]byte(minorDataStr), &minorData)
|
||||||
|
err = json.Unmarshal([]byte(realTimeDataStr), &realTimeData)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "解析 JSON 数据时出错", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建存档数据结构
|
||||||
|
data := SaveData{
|
||||||
|
SaveIndex: saveIndex,
|
||||||
|
BackupIndex: backupIndex,
|
||||||
|
MajorData: majorData,
|
||||||
|
MinorData: minorData,
|
||||||
|
RealTimeData: realTimeData,
|
||||||
|
Timestamp: sql.NullTime{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存档数据到数据库
|
||||||
|
err = saveToDatabase(db, data)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("保存存档时出错: %v", err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回成功响应
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
w.Write([]byte("存档成功"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载处理函数
|
||||||
|
func loadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("请求方法: %s, 请求路径: %s\n", r.Method, r.URL.Path) // 打印请求方法和路径
|
||||||
|
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(w, "请求方法错误,仅支持 GET", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
saveIndexStr := r.URL.Query().Get("save_index")
|
||||||
|
backupIndexStr := r.URL.Query().Get("backup_index")
|
||||||
|
if saveIndexStr == "" || backupIndexStr == "" {
|
||||||
|
http.Error(w, "缺少 save_index 或 backup_index 参数", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
saveIndex, err := strconv.Atoi(saveIndexStr)
|
||||||
|
backupIndex, err := strconv.Atoi(backupIndexStr)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "索引参数错误", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := loadFromDatabase(db, saveIndex, backupIndex)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("加载存档时出错: %v", err), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
err = json.NewEncoder(w).Encode(data)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "编码 JSON 数据时出错", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 loadHandler 中的时间格式化逻辑
|
||||||
|
func formatTimestamp(timestamp sql.NullTime) string {
|
||||||
|
if timestamp.Valid {
|
||||||
|
return timestamp.Time.Format("2006-01-02 15:04:05")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user