From 107149892c517ca07b9c02ba12e42ef8313c0ed9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Mar 2023 00:32:36 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20=E6=94=B9=E8=BF=9B=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=B7=E5=BC=8F=20(#625)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- plugin/steam/listenter.go | 268 ++++++++++++++++---------------- plugin/steam/steam.go | 316 +++++++++++++++++++------------------- plugin/steam/store.go | 234 ++++++++++++++-------------- 3 files changed, 409 insertions(+), 409 deletions(-) diff --git a/plugin/steam/listenter.go b/plugin/steam/listenter.go index 4e76f597..9cf2ca34 100644 --- a/plugin/steam/listenter.go +++ b/plugin/steam/listenter.go @@ -1,134 +1,134 @@ -package steam - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/FloatTech/floatbox/binary" - "github.com/FloatTech/floatbox/web" - ctrl "github.com/FloatTech/zbpctrl" - "github.com/tidwall/gjson" - zero "github.com/wdvxdr1123/ZeroBot" - "github.com/wdvxdr1123/ZeroBot/message" -) - -// ----------------------- 远程调用 ---------------------- -const ( - URL = "https://api.steampowered.com/" // steam API 调用地址 - StatusURL = "ISteamUser/GetPlayerSummaries/v2/?key=%+v&steamids=%+v" // 根据用户steamID获取用户状态 - steamapikeygid = 3 -) - -var apiKey string - -func init() { - engine.OnRegex(`^steam绑定\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { - apiKey = ctx.State["regex_matched"].([]string)[1] - m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - _ = m.Manager.Response(steamapikeygid) - err := m.Manager.SetExtra(steamapikeygid, apiKey) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: 保存apikey失败!")) - return - } - ctx.SendChain(message.Text("保存apikey成功!")) - }) - engine.OnFullMatch("查看apikey", zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { - ctx.SendChain(message.Text("apikey为: ", apiKey)) - }) - engine.OnFullMatch("拉取steam订阅", getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { - su := zero.BotConfig.SuperUsers[0] - // 获取所有处于监听状态的用户信息 - infos, err := database.findAll() - if err != nil { - // 挂了就给管理员发消息 - ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err)) - return - } - if len(infos) == 0 { - return - } - // 收集这波用户的streamId,然后查当前的状态,并建立信息映射表 - streamIds := make([]string, len(infos)) - localPlayerMap := make(map[int64]*player) - for i, info := range infos { - streamIds[i] = strconv.FormatInt(info.SteamID, 10) - localPlayerMap[info.SteamID] = info - } - // 将所有用户状态查一遍 - playerStatus, err := getPlayerStatus(streamIds...) - if err != nil { - // 出错就发消息 - ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err)) - return - } - // 遍历返回的信息做对比,假如信息有变化则发消息 - now := time.Now() - msg := make(message.Message, 0, len(playerStatus)) - for _, playerInfo := range playerStatus { - msg = msg[:0] - localInfo := localPlayerMap[playerInfo.SteamID] - // 排除不需要处理的情况 - if localInfo.GameID == 0 && playerInfo.GameID == 0 { - continue - } - // 打开游戏 - if localInfo.GameID == 0 && playerInfo.GameID != 0 { - msg = append(msg, message.Text(playerInfo.PersonaName, "正在玩", playerInfo.GameExtraInfo)) - localInfo.LastUpdate = now.Unix() - } - // 更换游戏 - if localInfo.GameID != 0 && playerInfo.GameID != localInfo.GameID && playerInfo.GameID != 0 { - msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 丢下了", localInfo.GameExtraInfo, ", 转头去玩", playerInfo.GameExtraInfo)) - localInfo.LastUpdate = now.Unix() - } - // 关闭游戏 - if playerInfo.GameID != localInfo.GameID && playerInfo.GameID == 0 { - msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 关掉了", localInfo.GameExtraInfo)) - localInfo.LastUpdate = 0 - } - if len(msg) != 0 { - groups := strings.Split(localInfo.Target, ",") - for _, groupString := range groups { - group, err := strconv.ParseInt(groupString, 10, 64) - if err != nil { - ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nOTHER: SteamID ", localInfo.SteamID)) - continue - } - ctx.SendGroupMessage(group, msg) - } - } - // 更新数据 - localInfo.GameID = playerInfo.GameID - localInfo.GameExtraInfo = playerInfo.GameExtraInfo - if err = database.update(localInfo); err != nil { - ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据失败\nOTHER: SteamID ", localInfo.SteamID)) - } - } - }) -} - -// getPlayerStatus 获取用户状态 -func getPlayerStatus(streamIds ...string) ([]*player, error) { - players := make([]*player, 0) - // 拼接请求地址 - url := fmt.Sprintf(URL+StatusURL, apiKey, strings.Join(streamIds, ",")) - // 拉取并解析数据 - data, err := web.GetData(url) - if err != nil { - return players, err - } - dataStr := binary.BytesToString(data) - index := gjson.Get(dataStr, "response.players.#").Uint() - for i := uint64(0); i < index; i++ { - players = append(players, &player{ - SteamID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.steamid", i)).Int(), - PersonaName: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.personaname", i)).String(), - GameID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameid", i)).Int(), - GameExtraInfo: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameextrainfo", i)).String(), - }) - } - return players, nil -} +package steam + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/FloatTech/floatbox/binary" + "github.com/FloatTech/floatbox/web" + ctrl "github.com/FloatTech/zbpctrl" + "github.com/tidwall/gjson" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +// ----------------------- 远程调用 ---------------------- +const ( + URL = "https://api.steampowered.com/" // steam API 调用地址 + StatusURL = "ISteamUser/GetPlayerSummaries/v2/?key=%+v&steamids=%+v" // 根据用户steamID获取用户状态 + steamapikeygid = 3 +) + +var apiKey string + +func init() { + engine.OnRegex(`^steam绑定\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) { + apiKey = ctx.State["regex_matched"].([]string)[1] + m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + _ = m.Manager.Response(steamapikeygid) + err := m.Manager.SetExtra(steamapikeygid, apiKey) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: 保存apikey失败!")) + return + } + ctx.SendChain(message.Text("保存apikey成功!")) + }) + engine.OnFullMatch("查看apikey", zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { + ctx.SendChain(message.Text("apikey为: ", apiKey)) + }) + engine.OnFullMatch("拉取steam订阅", getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { + su := zero.BotConfig.SuperUsers[0] + // 获取所有处于监听状态的用户信息 + infos, err := database.findAll() + if err != nil { + // 挂了就给管理员发消息 + ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err)) + return + } + if len(infos) == 0 { + return + } + // 收集这波用户的streamId,然后查当前的状态,并建立信息映射表 + streamIds := make([]string, len(infos)) + localPlayerMap := make(map[int64]*player) + for i, info := range infos { + streamIds[i] = strconv.FormatInt(info.SteamID, 10) + localPlayerMap[info.SteamID] = info + } + // 将所有用户状态查一遍 + playerStatus, err := getPlayerStatus(streamIds...) + if err != nil { + // 出错就发消息 + ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err)) + return + } + // 遍历返回的信息做对比,假如信息有变化则发消息 + now := time.Now() + msg := make(message.Message, 0, len(playerStatus)) + for _, playerInfo := range playerStatus { + msg = msg[:0] + localInfo := localPlayerMap[playerInfo.SteamID] + // 排除不需要处理的情况 + if localInfo.GameID == 0 && playerInfo.GameID == 0 { + continue + } + // 打开游戏 + if localInfo.GameID == 0 && playerInfo.GameID != 0 { + msg = append(msg, message.Text(playerInfo.PersonaName, "正在玩", playerInfo.GameExtraInfo)) + localInfo.LastUpdate = now.Unix() + } + // 更换游戏 + if localInfo.GameID != 0 && playerInfo.GameID != localInfo.GameID && playerInfo.GameID != 0 { + msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 丢下了", localInfo.GameExtraInfo, ", 转头去玩", playerInfo.GameExtraInfo)) + localInfo.LastUpdate = now.Unix() + } + // 关闭游戏 + if playerInfo.GameID != localInfo.GameID && playerInfo.GameID == 0 { + msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 关掉了", localInfo.GameExtraInfo)) + localInfo.LastUpdate = 0 + } + if len(msg) != 0 { + groups := strings.Split(localInfo.Target, ",") + for _, groupString := range groups { + group, err := strconv.ParseInt(groupString, 10, 64) + if err != nil { + ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nOTHER: SteamID ", localInfo.SteamID)) + continue + } + ctx.SendGroupMessage(group, msg) + } + } + // 更新数据 + localInfo.GameID = playerInfo.GameID + localInfo.GameExtraInfo = playerInfo.GameExtraInfo + if err = database.update(localInfo); err != nil { + ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据失败\nOTHER: SteamID ", localInfo.SteamID)) + } + } + }) +} + +// getPlayerStatus 获取用户状态 +func getPlayerStatus(streamIds ...string) ([]*player, error) { + players := make([]*player, 0) + // 拼接请求地址 + url := fmt.Sprintf(URL+StatusURL, apiKey, strings.Join(streamIds, ",")) + // 拉取并解析数据 + data, err := web.GetData(url) + if err != nil { + return players, err + } + dataStr := binary.BytesToString(data) + index := gjson.Get(dataStr, "response.players.#").Uint() + for i := uint64(0); i < index; i++ { + players = append(players, &player{ + SteamID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.steamid", i)).Int(), + PersonaName: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.personaname", i)).String(), + GameID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameid", i)).Int(), + GameExtraInfo: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameextrainfo", i)).String(), + }) + } + return players, nil +} diff --git a/plugin/steam/steam.go b/plugin/steam/steam.go index ac9f3f11..925dc90a 100644 --- a/plugin/steam/steam.go +++ b/plugin/steam/steam.go @@ -1,158 +1,158 @@ -// Package steam 获取steam用户状态 -package steam - -import ( - "strconv" - "strings" - "time" - - "github.com/FloatTech/floatbox/binary" - "github.com/FloatTech/floatbox/math" - ctrl "github.com/FloatTech/zbpctrl" - "github.com/FloatTech/zbputils/control" - "github.com/FloatTech/zbputils/ctxext" - "github.com/FloatTech/zbputils/img/text" - zero "github.com/wdvxdr1123/ZeroBot" - "github.com/wdvxdr1123/ZeroBot/message" -) - -var ( - engine = control.Register("steam", &ctrl.Options[*zero.Ctx]{ - DisableOnDefault: false, - Brief: "steam相关插件", - Help: "- steam添加订阅 xxxxxxx (可输入需要绑定的 steamid)\n" + - "- steam删除订阅 xxxxxxx (删除你创建的对于 steamid 的绑定)\n" + - "- steam查询订阅 (查询本群内所有的绑定对象)\n" + - "-----------------------\n" + - "- steam绑定 api key xxxxxxx (密钥在steam网站申请, 申请地址: https://steamcommunity.com/dev/registerkey)\n" + - "- 查看apikey (查询已经绑定的密钥)\n" + - "- 拉取steam订阅 (使用插件定时任务开始)\n" + - "-----------------------\n" + - "Tips: steamID在用户资料页的链接上面, 形如7656119820673xxxx\n" + - "需要先私聊绑定apikey, 订阅用户之后使用job插件设置定时, 例: \n" + - "记录在\"@every 1m\"触发的指令\n" + - "拉取steam订阅", - PrivateDataFolder: "steam", - }).ApplySingle(ctxext.DefaultSingle) -) - -func init() { - // 创建绑定流程 - engine.OnRegex(`^steam添加订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { - steamidstr := ctx.State["regex_matched"].([]string)[1] - steamID := math.Str2Int64(steamidstr) - // 获取用户状态 - playerStatus, err := getPlayerStatus(steamidstr) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败, 获取用户信息错误")) - return - } - if len(playerStatus) == 0 { - ctx.SendChain(message.Text("[steam] ERROR: 需要添加的用户不存在, 请检查id或url")) - return - } - playerData := playerStatus[0] - // 判断用户是否已经初始化:若未初始化,通过用户的steamID获取当前状态并初始化;若已经初始化则更新用户信息 - info, err := database.find(steamID) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败,数据库错误")) - return - } - // 处理数据 - groupID := strconv.FormatInt(ctx.Event.GroupID, 10) - if info.Target == "" { - info = player{ - SteamID: steamID, - PersonaName: playerData.PersonaName, - Target: groupID, - GameID: playerData.GameID, - GameExtraInfo: playerData.GameExtraInfo, - LastUpdate: time.Now().Unix(), - } - } else if !strings.Contains(info.Target, groupID) { - info.Target = strings.Join([]string{info.Target, groupID}, ",") - } - // 更新数据库 - if err = database.update(&info); err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据库失败")) - return - } - ctx.SendChain(message.Text("添加成功")) - }) - // 删除绑定流程 - engine.OnRegex(`^steam删除订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { - steamID := math.Str2Int64(ctx.State["regex_matched"].([]string)[1]) - groupID := strconv.FormatInt(ctx.Event.GroupID, 10) - // 判断是否已经绑定该steamID,若已绑定就将群列表从推送群列表钟去除 - info, err := database.findWithGroupID(steamID, groupID) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) - return - } - if info.SteamID == 0 { - ctx.SendChain(message.Text("[steam] ERROR: 所需要删除的用户不存在。")) - return - } - // 从绑定列表中剔除需要删除的对象 - targets := strings.Split(info.Target, ",") - newTargets := make([]string, 0) - for _, target := range targets { - if target == groupID { - continue - } - newTargets = append(newTargets, target) - } - if len(newTargets) == 0 { - if err = database.del(steamID); err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) - return - } - } else { - info.Target = strings.Join(newTargets, ",") - if err = database.update(&info); err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) - return - } - } - ctx.SendChain(message.Text("删除成功")) - }) - // 查询当前群绑定信息 - engine.OnFullMatch("steam查询订阅", zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { - // 获取群信息 - groupID := strconv.FormatInt(ctx.Event.GroupID, 10) - // 获取所有绑定信息 - infos, err := database.findAll() - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 查询订阅失败, 数据库错误")) - return - } - if len(infos) == 0 { - ctx.SendChain(message.Text("[steam] ERROR: 还未订阅过用户关系!")) - return - } - // 遍历所有信息,如果包含该群就收集对应的steamID - var sb strings.Builder - head := " 查询steam订阅成功, 该群订阅的用户有: \n" - sb.WriteString(head) - for _, info := range infos { - if strings.Contains(info.Target, groupID) { - sb.WriteString(" ") - sb.WriteString(info.PersonaName) - sb.WriteString(":") - sb.WriteString(strconv.FormatInt(info.SteamID, 10)) - sb.WriteString("\n") - } - } - if sb.String() == head { - ctx.SendChain(message.Text("查询成功,该群暂时还没有被绑定的用户!")) - return - } - // 组装并返回结果 - data, err := text.RenderToBase64(sb.String(), text.FontFile, 400, 18) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err)) - return - } - ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))) - }) -} +// Package steam 获取steam用户状态 +package steam + +import ( + "strconv" + "strings" + "time" + + "github.com/FloatTech/floatbox/binary" + "github.com/FloatTech/floatbox/math" + ctrl "github.com/FloatTech/zbpctrl" + "github.com/FloatTech/zbputils/control" + "github.com/FloatTech/zbputils/ctxext" + "github.com/FloatTech/zbputils/img/text" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +var ( + engine = control.Register("steam", &ctrl.Options[*zero.Ctx]{ + DisableOnDefault: false, + Brief: "steam相关插件", + Help: "- steam添加订阅 xxxxxxx (可输入需要绑定的 steamid)\n" + + "- steam删除订阅 xxxxxxx (删除你创建的对于 steamid 的绑定)\n" + + "- steam查询订阅 (查询本群内所有的绑定对象)\n" + + "-----------------------\n" + + "- steam绑定 api key xxxxxxx (密钥在steam网站申请, 申请地址: https://steamcommunity.com/dev/registerkey)\n" + + "- 查看apikey (查询已经绑定的密钥)\n" + + "- 拉取steam订阅 (使用插件定时任务开始)\n" + + "-----------------------\n" + + "Tips: steamID在用户资料页的链接上面, 形如7656119820673xxxx\n" + + "需要先私聊绑定apikey, 订阅用户之后使用job插件设置定时, 例: \n" + + "记录在\"@every 1m\"触发的指令\n" + + "拉取steam订阅", + PrivateDataFolder: "steam", + }).ApplySingle(ctxext.DefaultSingle) +) + +func init() { + // 创建绑定流程 + engine.OnRegex(`^steam添加订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { + steamidstr := ctx.State["regex_matched"].([]string)[1] + steamID := math.Str2Int64(steamidstr) + // 获取用户状态 + playerStatus, err := getPlayerStatus(steamidstr) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败, 获取用户信息错误")) + return + } + if len(playerStatus) == 0 { + ctx.SendChain(message.Text("[steam] ERROR: 需要添加的用户不存在, 请检查id或url")) + return + } + playerData := playerStatus[0] + // 判断用户是否已经初始化:若未初始化,通过用户的steamID获取当前状态并初始化;若已经初始化则更新用户信息 + info, err := database.find(steamID) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败,数据库错误")) + return + } + // 处理数据 + groupID := strconv.FormatInt(ctx.Event.GroupID, 10) + if info.Target == "" { + info = player{ + SteamID: steamID, + PersonaName: playerData.PersonaName, + Target: groupID, + GameID: playerData.GameID, + GameExtraInfo: playerData.GameExtraInfo, + LastUpdate: time.Now().Unix(), + } + } else if !strings.Contains(info.Target, groupID) { + info.Target = strings.Join([]string{info.Target, groupID}, ",") + } + // 更新数据库 + if err = database.update(&info); err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据库失败")) + return + } + ctx.SendChain(message.Text("添加成功")) + }) + // 删除绑定流程 + engine.OnRegex(`^steam删除订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { + steamID := math.Str2Int64(ctx.State["regex_matched"].([]string)[1]) + groupID := strconv.FormatInt(ctx.Event.GroupID, 10) + // 判断是否已经绑定该steamID,若已绑定就将群列表从推送群列表钟去除 + info, err := database.findWithGroupID(steamID, groupID) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) + return + } + if info.SteamID == 0 { + ctx.SendChain(message.Text("[steam] ERROR: 所需要删除的用户不存在。")) + return + } + // 从绑定列表中剔除需要删除的对象 + targets := strings.Split(info.Target, ",") + newTargets := make([]string, 0) + for _, target := range targets { + if target == groupID { + continue + } + newTargets = append(newTargets, target) + } + if len(newTargets) == 0 { + if err = database.del(steamID); err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) + return + } + } else { + info.Target = strings.Join(newTargets, ",") + if err = database.update(&info); err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误")) + return + } + } + ctx.SendChain(message.Text("删除成功")) + }) + // 查询当前群绑定信息 + engine.OnFullMatch("steam查询订阅", zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) { + // 获取群信息 + groupID := strconv.FormatInt(ctx.Event.GroupID, 10) + // 获取所有绑定信息 + infos, err := database.findAll() + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 查询订阅失败, 数据库错误")) + return + } + if len(infos) == 0 { + ctx.SendChain(message.Text("[steam] ERROR: 还未订阅过用户关系!")) + return + } + // 遍历所有信息,如果包含该群就收集对应的steamID + var sb strings.Builder + head := " 查询steam订阅成功, 该群订阅的用户有: \n" + sb.WriteString(head) + for _, info := range infos { + if strings.Contains(info.Target, groupID) { + sb.WriteString(" ") + sb.WriteString(info.PersonaName) + sb.WriteString(":") + sb.WriteString(strconv.FormatInt(info.SteamID, 10)) + sb.WriteString("\n") + } + } + if sb.String() == head { + ctx.SendChain(message.Text("查询成功,该群暂时还没有被绑定的用户!")) + return + } + // 组装并返回结果 + data, err := text.RenderToBase64(sb.String(), text.FontFile, 400, 18) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err)) + return + } + ctx.SendChain(message.Image("base64://" + binary.BytesToString(data))) + }) +} diff --git a/plugin/steam/store.go b/plugin/steam/store.go index b175fb21..16c93444 100644 --- a/plugin/steam/store.go +++ b/plugin/steam/store.go @@ -1,117 +1,117 @@ -package steam - -import ( - "strconv" - "sync" - "time" - - fcext "github.com/FloatTech/floatbox/ctxext" - sql "github.com/FloatTech/sqlite" - ctrl "github.com/FloatTech/zbpctrl" - zero "github.com/wdvxdr1123/ZeroBot" - "github.com/wdvxdr1123/ZeroBot/message" -) - -var ( - database streamDB - // 开启并检查数据库链接 - getDB = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { - database.db.DBPath = engine.DataFolder() + "steam.db" - err := database.db.Open(time.Hour * 24) - if err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err)) - return false - } - if err = database.db.Create(TableListenPlayer, &player{}); err != nil { - ctx.SendChain(message.Text("[steam] ERROR: ", err)) - return false - } - // 校验密钥是否初始化 - m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) - _ = m.Manager.Response(steamapikeygid) - _ = m.Manager.GetExtra(steamapikeygid, &apiKey) - if apiKey == "" { - ctx.SendChain(message.Text("ERROR: 未设置steam apikey")) - return false - } - return true - }) -) - -// streamDB 继承方法的存储结构 -type streamDB struct { - sync.RWMutex - db sql.Sqlite -} - -const ( - // TableListenPlayer 存储查询用户信息 - TableListenPlayer = "listen_player" -) - -// player 用户状态存储结构体 -type player struct { - SteamID int64 `json:"steam_id"` // 绑定用户标识ID - PersonaName string `json:"persona_name"` // 用户昵称 - Target string `json:"target"` // 信息推送群组 - GameID int64 `json:"game_id"` // 游戏ID - GameExtraInfo string `json:"game_extra_info"` // 游戏信息 - LastUpdate int64 `json:"last_update"` // 更新时间 -} - -// update 如果主键不存在则插入一条新的数据,如果主键存在直接复写 -func (sql *streamDB) update(dbInfo *player) error { - sql.Lock() - defer sql.Unlock() - return sql.db.Insert(TableListenPlayer, dbInfo) -} - -// find 根据主键查信息 -func (sql *streamDB) find(steamID int64) (dbInfo player, err error) { - sql.Lock() - defer sql.Unlock() - condition := "where steam_id = " + strconv.FormatInt(steamID, 10) - if !sql.db.CanFind(TableListenPlayer, condition) { - return player{}, nil // 规避没有该用户数据的报错 - } - err = sql.db.Find(TableListenPlayer, &dbInfo, condition) - return -} - -// findWithGroupID 根据用户steamID和groupID查询信息 -func (sql *streamDB) findWithGroupID(steamID int64, groupID string) (dbInfo player, err error) { - sql.Lock() - defer sql.Unlock() - condition := "where steam_id = " + strconv.FormatInt(steamID, 10) + " AND target LIKE '%" + groupID + "%'" - if !sql.db.CanFind(TableListenPlayer, condition) { - return player{}, nil // 规避没有该用户数据的报错 - } - err = sql.db.Find(TableListenPlayer, &dbInfo, condition) - return -} - -// findAll 查询所有库信息 -func (sql *streamDB) findAll() (dbInfos []*player, err error) { - sql.Lock() - defer sql.Unlock() - var info player - num, err := sql.db.Count(TableListenPlayer) - if err != nil || num == 0 { - return - } - dbInfos = make([]*player, 0, num) - err = sql.db.FindFor(TableListenPlayer, &info, "", func() error { - if info.SteamID != 0 { - dbInfos = append(dbInfos, &info) - } - return nil - }) - return -} - -// del 删除指定数据 -func (sql *streamDB) del(steamID int64) error { - sql.Lock() - defer sql.Unlock() - return sql.db.Del(TableListenPlayer, "where steam_id = "+strconv.FormatInt(steamID, 10)) -} +package steam + +import ( + "strconv" + "sync" + "time" + + fcext "github.com/FloatTech/floatbox/ctxext" + sql "github.com/FloatTech/sqlite" + ctrl "github.com/FloatTech/zbpctrl" + zero "github.com/wdvxdr1123/ZeroBot" + "github.com/wdvxdr1123/ZeroBot/message" +) + +var ( + database streamDB + // 开启并检查数据库链接 + getDB = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool { + database.db.DBPath = engine.DataFolder() + "steam.db" + err := database.db.Open(time.Hour * 24) + if err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err)) + return false + } + if err = database.db.Create(TableListenPlayer, &player{}); err != nil { + ctx.SendChain(message.Text("[steam] ERROR: ", err)) + return false + } + // 校验密钥是否初始化 + m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]) + _ = m.Manager.Response(steamapikeygid) + _ = m.Manager.GetExtra(steamapikeygid, &apiKey) + if apiKey == "" { + ctx.SendChain(message.Text("ERROR: 未设置steam apikey")) + return false + } + return true + }) +) + +// streamDB 继承方法的存储结构 +type streamDB struct { + sync.RWMutex + db sql.Sqlite +} + +const ( + // TableListenPlayer 存储查询用户信息 + TableListenPlayer = "listen_player" +) + +// player 用户状态存储结构体 +type player struct { + SteamID int64 `json:"steam_id"` // 绑定用户标识ID + PersonaName string `json:"persona_name"` // 用户昵称 + Target string `json:"target"` // 信息推送群组 + GameID int64 `json:"game_id"` // 游戏ID + GameExtraInfo string `json:"game_extra_info"` // 游戏信息 + LastUpdate int64 `json:"last_update"` // 更新时间 +} + +// update 如果主键不存在则插入一条新的数据,如果主键存在直接复写 +func (sql *streamDB) update(dbInfo *player) error { + sql.Lock() + defer sql.Unlock() + return sql.db.Insert(TableListenPlayer, dbInfo) +} + +// find 根据主键查信息 +func (sql *streamDB) find(steamID int64) (dbInfo player, err error) { + sql.Lock() + defer sql.Unlock() + condition := "where steam_id = " + strconv.FormatInt(steamID, 10) + if !sql.db.CanFind(TableListenPlayer, condition) { + return player{}, nil // 规避没有该用户数据的报错 + } + err = sql.db.Find(TableListenPlayer, &dbInfo, condition) + return +} + +// findWithGroupID 根据用户steamID和groupID查询信息 +func (sql *streamDB) findWithGroupID(steamID int64, groupID string) (dbInfo player, err error) { + sql.Lock() + defer sql.Unlock() + condition := "where steam_id = " + strconv.FormatInt(steamID, 10) + " AND target LIKE '%" + groupID + "%'" + if !sql.db.CanFind(TableListenPlayer, condition) { + return player{}, nil // 规避没有该用户数据的报错 + } + err = sql.db.Find(TableListenPlayer, &dbInfo, condition) + return +} + +// findAll 查询所有库信息 +func (sql *streamDB) findAll() (dbInfos []*player, err error) { + sql.Lock() + defer sql.Unlock() + var info player + num, err := sql.db.Count(TableListenPlayer) + if err != nil || num == 0 { + return + } + dbInfos = make([]*player, 0, num) + err = sql.db.FindFor(TableListenPlayer, &info, "", func() error { + if info.SteamID != 0 { + dbInfos = append(dbInfos, &info) + } + return nil + }) + return +} + +// del 删除指定数据 +func (sql *streamDB) del(steamID int64) error { + sql.Lock() + defer sql.Unlock() + return sql.db.Del(TableListenPlayer, "where steam_id = "+strconv.FormatInt(steamID, 10)) +}