HJ_Server/src/api_s2c/user/ApiLogin.ts

297 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {ApiCall, BaseConnection} from "tsrpc";
import {FriendManage} from '../../public/friend/manage';
import {GHManage} from '../../public/gonghui/manage';
import {HeroFun} from "../../public/hero";
import {PlayerFun} from '../../public/player';
import {TaskFun} from "../../public/task";
import {defaultUserAppend, UserFun} from '../../public/user';
import {ReqLogin, ResLogin} from "../../shared/protocols/user/PtlLogin";
import {setUidProcessId} from "../../clusterUtils";
import * as crypto from 'crypto';
import {EmailFun} from "../../public/email";
import {PublicShared} from "../../shared/public/public";
import {getGud, initGud} from "../../public/gud";
//登陆排队中的conn.id
let queueLogin = [
//{call:call,binduid,binduid,conn:conn}
]
//排队间隔 ms
let delay = 1000;
setInterval(function () {
doLoginQueue();
}, delay);
//获取排队顺序
function getQueueIndex(bindUid) {
for (let i = 0; i < queueLogin.length; i++) {
if (queueLogin[i].bindUid == bindUid) {
return i;
}
}
return null;
}
//conn断开了链接取消排队
export function unQueueByConn(conn: BaseConnection) {
//从queueLogin删除指定conn
for (let i = 0; i < queueLogin.length; i++) {
if (queueLogin[i].conn == conn) {
queueLogin.splice(i, 1);
break;
}
}
}
//默认入口
export default async function (call: ApiCall<ReqLogin, ResLogin>) {
let bindUid = call.req.bindUid;
let index = getQueueIndex(bindUid);
if (index == null) {
//增加到排队队列
queueLogin.push({call: call, bindUid: bindUid, conn: call.conn});
} else {
queueLogin[index].call = call;
queueLogin[index].conn = call.conn;
}
//需要排队的时间
let needTime = delay * queueLogin.length;
//需要等待的时间
G.server.sendMsgByUid(call.uid, 'msg_s2c/LoginQueue', {
delay: needTime
})
}
//每N时间消费1个排队
async function doLoginQueue() {
let data = queueLogin.shift();
if (!data) return;
let kickDelay = await kickUser(data.call.req.bindUid, data.call.req.sid);
console.log("排队登陆中,剩余数量", queueLogin.length, "kickDelay", kickDelay);
setTimeout(async function () {
return await doLogin(data.call);
}, kickDelay);
}
function md5String(password: string): string {
const md5 = crypto.createHash('md5');
md5.update(password);
return md5.digest('hex');
}
async function kickUser(bindUid: string, sid: string) {
let delayTime = 0;
let user = await G.mongodb.collection('user').findOne({bindUid: bindUid, sid: sid}, {
projection: {
uid: 1
}
});
if (user == null) {
return delayTime;
}
let uid = user.uid;
const loginConn = G.server.uid_connections[uid];
let checkPid = await G.redis.hGet("uid2processId", uid);
if (checkPid) {
if (~~checkPid == process.pid && loginConn) {
// 本进程踢线
loginConn.sendMsg('msg_s2c/OtherLogin', loginConn.ip).then(v => {
loginConn.close('otherLogin');
});
} else {
// 跨进程踢线注意这里是异步的留200ms等原进程清理数据
G.server.sendMsgByUid(uid, 'msg_s2c/OtherLogin', '1', String(process.pid));
delayTime = 200;
}
}
return delayTime;
}
async function doLogin(call: ApiCall<ReqLogin, ResLogin>) {
//合法性检测
let sign = call.req.sign;
//本地测试时,直接用通用鉴权秘钥
if (sign != "BPtqdLH9QTVbZk7v" && sign != md5String(call.req.bindUid + "ajklsdhjhquieb")) {
return call.error("shibai");
}
// 查询账号
let user = await G.mongodb.collection('user').findOne({bindUid: call.req.bindUid, sid: call.req.sid});
let {_id, ...gud} = user ? user : await UserFun.createUser(call.conn, call.req.bindUid, call.req.sid);
// 判断账号是否被封禁
if (gud.status == 1) {
return call.error(lng.user_10);
}
await initGud(gud.uid, gud);
// 修复公会id
await fixUnionData(gud);
//记录玩家所在的进程change: 更换到处理完踢线操作在写入。
// setUidProcessId(gud.uid);
let obj = await UserFun.check(gud, call.req);
call.conn.onlineTime = G.time;
call.conn.uid = gud.uid;
call.conn.bindUid = gud.bindUid;
call.conn.gud = gud;
call.conn.lshd = {};
if (!!!user) {
await firstLoginFun(call);
firstLoginSendEmail(call)
}
G.mongodb.collection('loginLog').insertOne({
uid: gud.uid,
bindUid: gud.bindUid,
sid: gud.sid,
loginTime: G.time
})
call.succ({
gud: gud,
curTime: G.time,
openTime: G.config.openTime,
openDay: PublicShared.getOpenServerDay(),
firstLogin: !!!user,
otherData: obj
});
if (obj.todayFirstLogin) {
// gud.loginTime 在check时已近被赋值为G.time
G.emit('FIRST_LOGIN_EVERY_DAY', gud, (gud.loginTime || G.time) - 24 * 3600, G.time);
}
LoginFun(call);
}
/**新玩家首次登陆后执行 */
async function firstLoginFun(call: ApiCall<ReqLogin, ResLogin>) {
await Promise.all([
//插入探险数据
G.mongodb.collection('tanxian').insertOne({
uid: call.uid,
eventTime: G.time,
lastGuaJiTime: G.time,
useFastGuaJiNum: 0,
receivePrize: [],
resetTime: G.time
}),
// 首号奖励
await PlayerFun.sendPrize(call, G.gc.playerdata.hero),
// 自动上阵
HeroFun.setHeroPos(call),
TaskFun.generateAllTask(call),
]);
}
/**新玩家首次登陆后执行 */
function firstLoginSendEmail(call: ApiCall<ReqLogin, ResLogin>) {
let conf = G.gc.yuyuemail
if (G.time > conf.overtime || G.time < conf.opentime) return
setTimeout(() => {
EmailFun.addEmail({
uid: call.conn.uid,
type: 'system',
title: '',
content: '',
prize: conf.prize,
lngTitle: conf.title,
lngContent: conf.content
});
}, 10000)
}
/**玩家登陆后执行 */
async function LoginFun(call: ApiCall<ReqLogin, ResLogin>) {
//检测玩家头像、头像框、聊天框、模型是否过期
let modelChange = false;
const model: ResLogin['gud']['model'] = {};
const change: Partial<ResLogin['gud']> = {};
if (call.conn.gud.head.time > 0 && call.conn.gud.head.time < G.time) {
change.head = defaultUserAppend.head;
}
if (call.conn.gud.headFrame.time > 0 && call.conn.gud.headFrame.time < G.time) {
change.headFrame = defaultUserAppend.headFrame;
}
if (call.conn.gud.chatFrame.time > 0 && call.conn.gud.chatFrame.time < G.time) {
change.chatFrame = defaultUserAppend.chatFrame;
}
Object.entries(call.conn.gud.model).forEach(v => {
if (v[1].time > 0 && v[1].time < G.time) {
modelChange = true;
model[v[0]] = defaultUserAppend.model[v[0]];
} else model[v[0]] = Object.assign({}, v[1]);
});
if (modelChange) change.model = model;
Object.keys(change).length > 0 && PlayerFun.addAttr(call, change);
//上线重算战力
call.conn.refreshPower();
// ### globalDebug GHManage
if (call.conn.gud.ghLevel == 1 && await GHManage.getGH(call.conn.gud.ghId)) {
GHManage.hzsx(call.conn.gud);
}
if (!await G.redis.hGet('player:uids', call.conn.gud.uid)) {
G.redis.hSet('player:uids', call.conn.gud.uid, 1)
}
FriendManage.addNew(call.conn.gud.uid);
// 更新主线任务
TaskFun.updateMainTask(call)
// 推送当前主线任务信息,引导用
let _taskInfo = await TaskFun.getFinishByTtype(call, [2], {finish: 0});
G.server.sendMsgByUid(call.uid, 'msg_s2c/TaskChange', _taskInfo?.[2]?.[0])
// 存入当前玩家多语言信息
G.redis.rawSet(`user:lng:${call.uid}`, call.req.lng, {EX: 259200})
// 临时修补
// fixHeroShiwu(call)
}
// async function fixHeroShiwu(call: ApiCall) {
// let list = await G.mongodb.collection("hero").find({$and: [{"uid": call.uid}, {"shiwu": {$exists: true}}]}).toArray()
//
// list.map(i => {
// let list = R.values(i.shiwu).filter(i => !i._id)
// if (list.length == 0) return ''
//
// let shiwuChange = {}
// if (i.shiwu?.['1']?._id) {
// shiwuChange['1'] = i.shiwu['1']
// }
// if (i.shiwu?.['2']?._id) {
// shiwuChange['2'] = i.shiwu['2']
// }
//
// G.mongodb.collection("hero").findOneAndUpdate({_id: i._id}, {$set: {shiwu: shiwuChange}})
// })
// }
// 修复玩家退出公会 但是gud中残留公会id
async function fixUnionData(gud: ResLogin["gud"]) {
if (gud.ghId) {
let ghdata = await G.mongodb.collection("gonghui").findOne(
{_id: G.mongodb.conversionId(gud.ghId), 'players.uid': gud.uid}
)
if (!ghdata) {
gud.ghId = "";
gud.ghName = "";
gud.ghLevel = 0;
PlayerFun.changeAttr(gud.uid, {ghId: '', ghLevel: 0})
}
}
}