This commit is contained in:
Ctrlcvs 2023-05-10 22:25:27 +08:00
commit 9794cc5094
9 changed files with 213 additions and 149 deletions

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -0,0 +1,43 @@
import BaseModel from './BaseModel.js'
import lodash from 'lodash'
const { Types } = BaseModel
const COLUMNS = {
// 用户IDqq为数字
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

View File

@ -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 }
UserDB.hasMany(UserGameDB, {
onDelete: 'RESTRICT',
onUpdate: 'RESTRICT',
foreignKey: 'userId',
as: 'games'
})
UserGameDB.belongsTo(UserDB, {
foreignKey: 'userId',
as: 'games'
})
export { UserDB, MysUserDB, UserGameDB }

View File

@ -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}`
}

View File

@ -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<boolean>}
*/
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 + '')
}
}

View File

@ -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

View File

@ -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()
}
/**

View File

@ -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)