diff --git a/plugins/genshin/model/db/MysUserDB.js b/plugins/genshin/model/db/MysUserDB.js index fdbbdcf..a5d1f81 100644 --- a/plugins/genshin/model/db/MysUserDB.js +++ b/plugins/genshin/model/db/MysUserDB.js @@ -19,10 +19,22 @@ const COLUMNS = { // CK ck: Types.STRING, device: Types.STRING, - - gsUids: Types.STRING, - - srUids: Types.STRING + uids: { + type: Types.STRING, + get () { + let data = this.getDataValue('uids') + let ret = {} + try { + ret = JSON.parse(data) + } catch (e) { + ret = {} + } + return ret + }, + set (uids) { + this.setDataValue('uids', JSON.stringify(uids)) + } + } } class MysUserDB extends BaseModel { @@ -45,8 +57,7 @@ class MysUserDB extends BaseModel { this.ck = mys.ck this.type = mys.type this.device = mys.device - this.gsUids = (mys.gsUids || []).join(',') - this.srUids = (mys.srUids || []).join(',') + this.uids = mys.uids await db.save() } } diff --git a/plugins/genshin/model/db/UserDB.js b/plugins/genshin/model/db/UserDB.js index 283f77a..fb48ddf 100644 --- a/plugins/genshin/model/db/UserDB.js +++ b/plugins/genshin/model/db/UserDB.js @@ -1,5 +1,7 @@ import BaseModel from './BaseModel.js' import lodash from 'lodash' +import { UserGameDB } from './index.js' +import MysUtil from '../mys/MysUtil.js' const { Types } = BaseModel @@ -23,15 +25,7 @@ const COLUMNS = { // 头像 face: Types.STRING, - ltuids: Types.STRING, - - // 原神UID - gsUid: Types.STRING, - gsRegUids: Types.STRING, - - // 星铁UID - srUid: Types.STRING, - srRegUids: Types.STRING + ltuids: Types.STRING } class UserDB extends BaseModel { @@ -39,7 +33,12 @@ class UserDB extends BaseModel { // user_id id = type === 'qq' ? '' + id : type + id // DB查询 - let user = await UserDB.findByPk(id) + let user = await UserDB.findByPk(id, { + include: { + model: UserGameDB, + as: 'games' + } + }) if (!user) { user = await UserDB.build({ id, @@ -53,15 +52,29 @@ class UserDB extends BaseModel { let db = this let ltuids = [] lodash.forEach(user.mysUsers, (mys) => { - if (mys.ck) { + if (mys.ck && mys.ltuid) { ltuids.push(mys.ltuid) } }) db.ltuids = ltuids.join(',') - lodash.forEach(['gs', 'sr'], (key) => { - db[`${key}Uid`] = user[`${key}Uid`] ? user[`${key}Uid`] : user.uids[key]?.[0] || '' - db[`${key}RegUids`] = JSON.stringify(user.uidMap[key]) + let games = [] + await MysUtil.eachGame(async (key) => { + let game = user.games[key] + if (!game && (user.uid[key] || !lodash.isEmpty(user.uidMap[key]))) { + game = await db.createGame({ + game: key + }) + } + if (game) { + game.uid = user.uid[key] + game.data = user.uidMap[key] + games.push(game) + await game.save() + } }) + if (games.length > 0) { + await this.setGames(games) + } await this.save() } } diff --git a/plugins/genshin/model/db/UserGameDB.js b/plugins/genshin/model/db/UserGameDB.js new file mode 100644 index 0000000..c29797b --- /dev/null +++ b/plugins/genshin/model/db/UserGameDB.js @@ -0,0 +1,43 @@ +import BaseModel from './BaseModel.js' +import lodash from 'lodash' + +const { Types } = BaseModel + +const COLUMNS = { + // 用户ID,qq为数字 + userId: { + type: Types.STRING + }, + game: Types.STRING, + uid: Types.STRING, + data: { + type: Types.STRING, + get () { + let data = this.getDataValue('data') + let ret = {} + try { + data = JSON.parse(data) + } catch (e) { + data = [] + } + lodash.forEach(data, (ds) => { + if (ds.uid) { + ret[ds.uid] = ds + } + }) + return ret + }, + set (data) { + this.setDataValue('data', JSON.stringify(lodash.values(data))) + } + } +} + +class UserGameDB extends BaseModel { + +} + +BaseModel.initDB(UserGameDB, COLUMNS) +await UserGameDB.sync() + +export default UserGameDB \ No newline at end of file diff --git a/plugins/genshin/model/db/index.js b/plugins/genshin/model/db/index.js index b797e7b..22cd3e9 100644 --- a/plugins/genshin/model/db/index.js +++ b/plugins/genshin/model/db/index.js @@ -1,5 +1,6 @@ import UserDB from './UserDB.js' import MysUserDB from './MysUserDB.js' +import UserGameDB from './UserGameDB.js' UserDB.belongsToMany(MysUserDB, { @@ -9,4 +10,15 @@ MysUserDB.belongsToMany(UserDB, { through: 'UserLtuids' }) -export { UserDB, MysUserDB } \ No newline at end of file +UserDB.hasMany(UserGameDB, { + onDelete: 'RESTRICT', + onUpdate: 'RESTRICT', + foreignKey: 'userId', + as: 'games' +}) +UserGameDB.belongsTo(UserDB, { + foreignKey: 'userId', + as: 'games' +}) + +export { UserDB, MysUserDB, UserGameDB } \ No newline at end of file diff --git a/plugins/genshin/model/mys/DailyCache.js b/plugins/genshin/model/mys/DailyCache.js index fd7df5e..1d08564 100644 --- a/plugins/genshin/model/mys/DailyCache.js +++ b/plugins/genshin/model/mys/DailyCache.js @@ -1,5 +1,6 @@ import moment from 'moment' import BaseModel from './BaseModel.js' +import MysUtil from './MysUtil.js' const servs = ['mys', 'hoyolab'] // 超时时间不必精确,直接定24小时即可 @@ -38,7 +39,7 @@ export default class DailyCache extends BaseModel { if (!uid || game === 'config') { key = 'sys:config' } else { - game = game === 'sr' ? 'sr' : 'gs' + game = MysUtil.getGameKey(game) let serv = /^[6-9]|^hoyo|^os/i.test(uid) ? servs[1] : servs[0] key = `${game}:${serv}` } diff --git a/plugins/genshin/model/mys/MysUser.js b/plugins/genshin/model/mys/MysUser.js index a718834..83af857 100644 --- a/plugins/genshin/model/mys/MysUser.js +++ b/plugins/genshin/model/mys/MysUser.js @@ -264,7 +264,7 @@ export default class MysUser extends BaseModel { getUids (game = 'gs') { let gameKey = this.gameKey(game) - return this[`${gameKey}Uids`] || [] + return this.uids[gameKey] || [] } /** @@ -378,10 +378,10 @@ export default class MysUser extends BaseModel { this.ck = data.ck || this.ck || '' this.type = data.type || this.type || 'mys' this.device = data.device || this.device || MysUtil.getDeviceGuid() + this.uids = this.uids || {} let self = this MysUtil.eachGame((game) => { - let key = `${game}Uids` - self[key] = lodash.isString(data[key]) ? (data[key] || '').split(',') : (lodash.isArray(data[key]) ? data[key] : (self[key] || [])) + self.uids[game] = data?.uids?.[game] || self.uids[game] || [] }) } @@ -400,7 +400,7 @@ export default class MysUser extends BaseModel { uid = '' + uid if (/\d{9}/.test(uid)) { let gameKey = this.gameKey(game) - let uids = this[`${gameKey}Uids`] + let uids = this.uids[gameKey] if (!uids.includes(uid)) { uids.push(uid) } @@ -419,7 +419,7 @@ export default class MysUser extends BaseModel { } let self = this await MysUtil.eachGame(async (game) => { - let uids = self[`${game}Uids`] + let uids = self.uids[game] await this.addQueryUid(uids, game) let cache = self.getCache(game) let cacheSearchList = await cache.get(tables.del, this.ltuid, true) @@ -445,28 +445,20 @@ export default class MysUser extends BaseModel { // /** * 删除缓存, 供User解绑CK时调用 - * @param user * @returns {Promise} */ - async del (user) { - if (user && user.qq) { - let qqList = await this.cache.kGet(tables.qq, this.ltuid, true) - let newList = lodash.pull(qqList, user.qq * 1) - await this.cache.kSet(tables.qq, this.ltuid, newList) - if (newList.length > 0) { - // 如果数组还有其他元素,说明该ltuid还有其他绑定,不进行缓存删除 - return false - } - } + async del () { + // TODO 检查一ltuid多绑定的情况 // 将查询过的uid缓存起来,以备后续重新绑定时恢复 - let uids = await this.getQueryUids() - await this.servCache.set(tables.del, uids) - - // 标记ltuid为失效 - await this.servCache.zDel(tables.detail, this.ltuid) - await this.cache.zDel(tables.uid, this.ltuid) - await this.cache.kDel(tables.ck, this.ltuid) - await this.cache.kDel(tables.qq, this.ltuid) + let self = this + await MysUtil.eachGame(async (game) => { + let uids = await this.getQueryUids(game) + let cache = self.getCache(game) + await cache.set(tables.del, uids) + // 标记ltuid为失效 + await cache.zDel(tables.detail, this.ltuid) + }) + await self.db.delete() logger.mark(`[删除失效ck][ltuid:${this.ltuid}]`) } @@ -502,13 +494,13 @@ export default class MysUser extends BaseModel { // 获取当前用户已查询uid列表 async getQueryUids (game = 'gs') { - let cache = this.getCache('game') + let cache = this.getCache(game) return await cache.zList(tables.detail, this.ltuid) } // 根据uid获取查询ltuid async getQueryLtuid (uid, game = 'gs') { - let cache = this.getCache('game') + let cache = this.getCache(game) return await cache.zKey(tables.detail, uid) } @@ -518,7 +510,7 @@ export default class MysUser extends BaseModel { return false } let gameKey = this.gameKey(game) - let uids = this[`${gameKey}Uids`] + let uids = this.uids[gameKey] return uids.includes(uid + '') } } diff --git a/plugins/genshin/model/mys/MysUtil.js b/plugins/genshin/model/mys/MysUtil.js index 7c373f3..c6b6c40 100644 --- a/plugins/genshin/model/mys/MysUtil.js +++ b/plugins/genshin/model/mys/MysUtil.js @@ -1,5 +1,7 @@ import { Data } from '#miao' +const games = ['gs', 'sr'] + const MysUtil = { // 获取标准ltuid getLtuid (data) { @@ -36,7 +38,7 @@ const MysUtil = { // 循环game async eachGame (fn) { - await Data.forEach(['gs', 'sr'], fn) + await Data.forEach(games, fn) }, // 循环server diff --git a/plugins/genshin/model/mys/NoteUser.js b/plugins/genshin/model/mys/NoteUser.js index b5a7cac..b48c36a 100644 --- a/plugins/genshin/model/mys/NoteUser.js +++ b/plugins/genshin/model/mys/NoteUser.js @@ -8,6 +8,7 @@ import BaseModel from './BaseModel.js' import lodash from 'lodash' import MysUser from './MysUser.js' +import MysUtil from './MysUtil.js' import gsCfg from '../gsCfg.js' import { UserDB } from '../db/index.js' import { Data } from '#miao' @@ -24,14 +25,6 @@ export default class NoteUser extends BaseModel { return this._cacheThis() } - /** - * 获取当前用户uid - * 如果为绑定用户,优先获取ck对应uid,否则获取绑定uid - */ - get uid () { - return this.getUid() - } - /** * 当前用户是否具备CK */ @@ -105,8 +98,6 @@ export default class NoteUser extends BaseModel { let user = new NoteUser(qq) await user.initDB(db) - // 检查绑定uid (regUid) - await user.getRegUid() // 传入data则使用,否则读取 return user } @@ -143,39 +134,61 @@ export default class NoteUser extends BaseModel { } // 初始化Uid - initUids () { + initUids (mys = false) { let self = this + self.uid = {} self.uids = {} self.uidMap = {} - const { db, uids, uidMap, mysUsers } = self - lodash.forEach(['gs', 'sr'], (key) => { - // 绑定UID + self.games = {} + const { db, uids, games, uidMap, mysUsers } = self + + let gameDBs = {} + lodash.forEach(db?.games, (gameDB) => { + gameDBs[gameDB.game] = gameDB + }) + + MysUtil.eachGame((key) => { + let gameDB = gameDBs[key] uidMap[key] = {} uids[key] = [] - // 设置CK UID + games[key] = gameDB + + // 优先设置CK UID lodash.forEach(mysUsers, (mys) => { - lodash.forEach(mys[`${key}Uids`], (uid) => { + lodash.forEach(mys.uids[key] || [], (uid) => { if (uid && !uidMap[key][uid]) { uidMap[key][uid] = { uid, type: 'ck', ltuid: mys.ltuid } uids[key].push(uid) } }) }) - let regUids = db[`${key}RegUids`] || '{}' - try { - regUids = JSON.parse(regUids) - } catch (e) { - regUids = {} - } - lodash.forEach(['verify', 'reg'], (uidType) => { - lodash.forEach(regUids, (ds, uid) => { - if (uid && ds.type === uidType && !uidMap[key][uid]) { - uidMap[key][uid] = { uid, type: ds.type } - uids[key].push(uid) - } + // 存在数据库记录则进行设置 + if (gameDB) { + let regUids = gameDB.data + // 依次设置verify、reg uid数据 + lodash.forEach(['verify', 'reg'], (uidType) => { + lodash.forEach(regUids, (ds, uid) => { + if (uid && ds.type === uidType && !uidMap[key][uid]) { + uidMap[key][uid] = { uid, type: ds.type } + uids[key].push(uid) + } + }) }) - }) - self[`${key}Uid`] = self[`${key}Uid`] || db[`${key}Uid`] || uids[key]?.[0] || '' + + // 如果当前选中uid未在记录中,则补充为reg数据 + let uid = gameDB.uid + if (uid && !uidMap[key][uid]) { + uidMap[key][uid] = { uid, type: 'reg' } + uids[key].push(uid) + } + } + + // 设置选中uid + if (mys && mys.uids[key]?.[0]) { + self.uid[key] = mys.uids[key]?.[0] || self.uid[key] || '' + } else { + self.uid[key] = self.uid[key] || gameDB?.uid || uids[key]?.[0] || '' + } }) } @@ -185,12 +198,13 @@ export default class NoteUser extends BaseModel { // 获取当前UID getUid (game = 'gs') { - return this.isGs(game) ? this.gsUid : this.srUid + let gameKey = this.gameKey(game) + return this.uid[gameKey] || this.uids[gameKey][0] || '' } getSelfUid (game = 'gs') { let gameKey = this.gameKey(game) - let uids = this[`${gameKey}UidMap`].filter((v) => v.type === 'ck') + let uids = this.uidMap[gameKey].filter((v) => v.type === 'ck') if (uids.length === 0) { return false } @@ -212,7 +226,7 @@ export default class NoteUser extends BaseModel { getUidData (game = 'gs') { let gameKey = this.gameKey(game) let uid = this.getUid(game) - return this.uidMap[gameKey][uid] + return this.uidMap[gameKey]?.[uid] } // 获取当前的MysUser对象 @@ -255,7 +269,7 @@ export default class NoteUser extends BaseModel { */ async getRegUid (game = 'gs') { let gameKey = this.gameKey(game) - return this[`${gameKey}Uid`] || '' + return this.uid[gameKey] || '' } /** @@ -281,27 +295,27 @@ export default class NoteUser extends BaseModel { } if (this.uidMap[gameKey][uid]) { - if (this.isGs(game)) { - this.gsUid = uid - } else { - this.srUid = uid - } + this.uid[gameKey] = uid } + + this.initUids() } // 添加MysUser addMysUser (mysUser) { this.mysUsers[mysUser.ltuid] = mysUser - this.initUids() + this.initUids(mysUser) } // 删除当前用户绑定CK async delCk (ltuid = '', needRefreshCache = true) { - if (!this.mysUsers[ltuid]) { - return false + if (!ltuid || !this.mysUsers[ltuid]) { + return } + let mys = this.mysUsers[ltuid] delete this.mysUsers[ltuid] - this.initUids() + mys.del() + await this.initUids() } /** diff --git a/plugins/genshin/model/user.js b/plugins/genshin/model/user.js index 3d9837a..6f21b73 100644 --- a/plugins/genshin/model/user.js +++ b/plugins/genshin/model/user.js @@ -6,6 +6,7 @@ import common from '../../../lib/common/common.js' import MysInfo from './mys/mysInfo.js' import NoteUser from './mys/NoteUser.js' import MysUser from './mys/MysUser.js' +import MysUtil from './mys/MysUtil.js' import { promisify } from 'node:util' import YAML from 'yaml' import { Data } from '#miao' @@ -58,6 +59,7 @@ export default class User extends base { return } + // TODO:独立的mys数据,不走缓存ltuid let mys = await MysUser.create(param.ltuid) let data = {} data.ck = `ltoken=${param.ltoken};ltuid=${param.ltuid || param.login_uid};cookie_token=${param.cookie_token || param.cookie_token_v2}; account_id=${param.ltuid || param.login_uid};` @@ -81,9 +83,10 @@ export default class User extends base { /** 检查ck是否失效 */ let uidRet = await mys.reqMysUid() - console.log('uidRet', uidRet) if (uidRet.status !== 0) { logger.mark(`绑定cookie错误1:${this.checkMsg || 'cookie错误'}`) + // 清除mys数据 + mys._delCache() return await this.e.reply(`绑定cookie失败:${this.checkMsg || 'cookie错误'}`) } @@ -92,10 +95,8 @@ export default class User extends base { let userFullInfo = await mys.getUserFullInfo() if (userFullInfo?.data?.user_info) { let userInfo = userFullInfo?.data?.user_info - /* - this.ltuid = userInfo.uid - this.ck = `${this.ck}ltuid=${this.ltuid};` - */ + // this.ltuid = userInfo.uid + // this.ck = `${this.ck}ltuid=${this.ltuid};` } else { logger.mark(`绑定cookie错误2:${userFullInfo.message || 'cookie错误'}`) return await this.e.reply(`绑定cookie失败:${userFullInfo.message || 'cookie错误'}`) @@ -105,6 +106,7 @@ export default class User extends base { logger.mark(`${this.e.logFnc} 检查cookie正常 [ltuid:${mys.ltuid}]`) await user.addMysUser(mys) + await mys.initCache() await user.save() logger.mark(`${this.e.logFnc} 保存cookie成功 [ltuid:${mys.ltuid}]`) @@ -133,49 +135,17 @@ export default class User extends base { await this.e.reply(msg) } - /** 检查ck是否可用 */ - async checkCk (mys, param = {}) { - let res - for (let type of ['mys', 'hoyolab']) { - let roleRes = await mys.getGameRole(type) - if (roleRes?.retcode === 0) { - res = roleRes - /** 国际服的标记 */ - if (type === 'hoyolab' && typeof (param.mi18nLang) === 'string' && !/mi18nLang/.test(mys.ck)) { - mys.ck += ` mi18nLang=${param.mi18nLang};` - mys.type = 'hoyolab' - } - break - } - if (roleRes.retcode === -100) { - this.checkMsg = '该ck已失效,请重新登录获取' - } else { - this.checkMsg = roleRes.message || 'error' - } - } - - if (!res) return false - let playerList = res?.data?.list || [] - if (!playerList || playerList.length <= 0) { - this.checkMsg = '该账号尚未绑定原神或星穹角色!' - return false - } else { - playerList = playerList.filter(v => ['hk4e_cn', 'hkrpg_cn', 'hk4e_global', 'hkrpg_global'].includes(v.game_biz)) - } - - /** 米游社默认展示的角色 */ - for (let val of playerList) { - mys.addUid(val.game_uid, ['hk4e_cn', 'hk4e_global'].includes(val.game_biz) ? 'gs' : 'sr') - } - await mys.save() - return mys - } - /** 删除绑定ck */ - async delCk (uid = '') { + async delCk () { let user = await this.user() - let uids = await user.delCk() - return `绑定cookie已删除,uid:${uids.join(',')}` + // 获取当前uid + let uidData = user.getUidData(this.e) + let uidms = user.getUidList(this.e) + if (!uidData || uidData.type !== 'ck' || !uidData.ltuid) { + return `删除失败:当前的UID${uidData.uid}无CK信息` + } + let uids = await user.delCk(uidData.ltuid) + return `绑定cookie已删除}` } /** 绑定uid,若有ck的话优先使用ck-uid */ @@ -192,8 +162,8 @@ export default class User extends base { /** #uid */ async showUid () { let user = await this.user() - let msg = ['通过【#uid+序号】来切换uid'] - lodash.forEach({ genshin: '原神', star: '星穹铁道' }, (gameName, game) => { + let msg = [] + lodash.forEach({ gs: '原神', sr: '星穹铁道' }, (gameName, game) => { let uidList = user.getUidList(game) let currUid = user.getUid(game) if (uidList.length === 0) { @@ -208,7 +178,12 @@ export default class User extends base { msg.push(tmp) }) }) - await this.e.reply(msg.join('\n')) + if (msg.length > 0) { + msg.unshift('通过【#uid+序号】来切换uid') + await this.e.reply(msg.join('\n')) + } else { + await this.e.reply('尚未绑定UID,发送CK或通过【#绑定123456789】命令来绑定UID') + } } /** 切换uid */ @@ -220,7 +195,7 @@ export default class User extends base { return await this.e.reply('uid序号输入错误') } index = Number(index) - 1 - await user.setMainUid(index, game) + user.setMainUid(index, game) await user.save() return await this.showUid() } @@ -318,13 +293,16 @@ export default class User extends base { ck, device, ltuid, - star: {}, - genshin: {}, + uids: {}, type: /America Server|Europe Server|Asia Server/.test(region) ? 'hoyolab' : 'mys' } let tmp = ltuids[ltuid] - let game = region === '星穹列车' ? 'star' : 'genshin' - tmp[game][uid] = uid + let game = region === '星穹列车' ? 'sr' : 'gs' + tmp.uids[game] = tmp.uids[game] || [] + let gameUids = tmp.uids[game] + if (!gameUids.includes(uid + '')) { + gameUids.push(uid + '') + } } if (!qq) { continue @@ -334,8 +312,6 @@ export default class User extends base { let data = ltuids[ltuid] let mys = await MysUser.create(data.ltuid) if (mys) { - data.gsUids = lodash.keys(data.genshin) - data.srUids = lodash.keys(data.star) mys.setCkData(data) await mys.save() user.addMysUser(mys)