player.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. 'use strict';
  2. var request = require('request');
  3. var Jimp = require('jimp');
  4. var fs = require('fs');
  5. var quick = require('quick-pomelo');
  6. var P = quick.Promise;
  7. var _ = require('lodash');
  8. var uuid = require('node-uuid');
  9. var md5 = require('md5');
  10. var C = require('../../share/constant');
  11. var logger = quick.logger.getLogger('player', __filename);
  12. var configCommon = require('../../share/configCommon');//////TL++配置相关的公共方法
  13. var Controller = function (app) {
  14. this.app = app;
  15. this.lconfigCommon = new configCommon(this.app);
  16. };
  17. module.exports = function (app) {
  18. return new Controller(app);
  19. };
  20. var proto = Controller.prototype;
  21. var requestGet = P.promisify(request.get, {multiArgs: true});
  22. proto.convertUrlToPng = P.coroutine(function* (url, outputPath) {
  23. try {
  24. console.warn("url:",url)
  25. // 1. 使用 request 获取数据,必须 encoding: null
  26. var result = yield requestGet({
  27. url: url,
  28. encoding: null,
  29. timeout: 10000,
  30. headers: {
  31. 'User-Agent': 'Mozilla/5.0'
  32. }
  33. });
  34. // console.warn("湖南红中 游戏服务器启动",result);
  35. //console.log("result[1]:",result[1])
  36. // 重点:multiArgs: true 会返回 [response, body]
  37. // result[0] 是响应头,result[1] 才是真正的图片 Buffer
  38. var response = result[0];
  39. var body = result[1];
  40. if (!response || response.statusCode !== 200) {
  41. throw new Error('Download failed, status: ' + (response ? response.statusCode : 'unknown'));
  42. }
  43. if (!body || body.length === 0) {
  44. throw new Error('Received empty buffer');
  45. }
  46. // 2. 使用 Jimp 读取 Buffer
  47. // 如果依然报 MIME 错误,可以尝试强制指定格式 (仅限确定是 jpg/png 的情况)
  48. var image = yield Jimp.read(body);
  49. console.warn("68")
  50. // 3. 转换并输出
  51. // 老版本 Jimp 0.2.28 的 getBuffer 是回调模式,需要 promisify
  52. var pngBuffer = yield new P(function(resolve, reject) {
  53. // 显式检查 image 对象是否存在且有 getBuffer 方法
  54. console.warn("73")
  55. if (!image || typeof image.getBuffer !== 'function'){
  56. console.warn("75:",typeof image.getBuffer)
  57. //console.warn("75:", typeof image.getBuffer);
  58. return reject(new Error('Jimp 实例无效或不支持 getBuffer 方法'));
  59. }
  60. image.getBuffer(Jimp.MIME_PNG, function(err, buffer) {
  61. console.warn("80:")
  62. if (err) return reject(err);
  63. resolve(buffer);
  64. });
  65. console.log("81")
  66. });
  67. console.warn("83")
  68. if (outputPath) {
  69. console.warn("84")
  70. yield new P(function(resolve, reject) {
  71. console.warn("91:")
  72. if (typeof image.write !== 'function') {
  73. console.warn("91:")
  74. return reject(new Error('Jimp 实例不支持 write 方法'));
  75. }
  76. image.write(outputPath, function(err) {
  77. console.warn("err:",err)
  78. if (err) return reject(err);
  79. console.warn("96:")
  80. resolve();
  81. console.warn("err:",100)
  82. });
  83. });
  84. console.warn('转换并保存成功: ' + outputPath);
  85. }
  86. return pngBuffer;
  87. } catch (error) {
  88. // 增加更详细的报错日志,方便排查
  89. console.error('图片转换失败详情:', error.message);
  90. if (error.stack) console.error(error.stack);
  91. }
  92. });
  93. // 登陆
  94. proto.convertUrlToPng = function(url, outputPath, callback) {
  95. // 替换后缀为 png(仅改名字,内容还是 SVG)
  96. var pngOutputPath = outputPath.replace(/\.[^.]+$/, '.png');
  97. var https = require('https');
  98. var fs = require('fs');
  99. var request = https.get(url, function(response) {
  100. if (response.statusCode !== 200) {
  101. return callback(new Error('请求失败,状态码:' + response.statusCode));
  102. }
  103. var fileStream = fs.createWriteStream(pngOutputPath);
  104. response.pipe(fileStream);
  105. fileStream.on('finish', function() {
  106. fileStream.close(function() {
  107. // 模拟返回 Buffer(Node 4.4.7 兼容)
  108. fs.readFile(pngOutputPath, function(err, buffer) {
  109. if (err) return callback(err);
  110. callback(null, buffer); // 回调返回 Buffer,兼容原有逻辑
  111. });
  112. });
  113. });
  114. fileStream.on('error', function(err) {
  115. fs.unlink(pngOutputPath, function() {});
  116. callback(err);
  117. });
  118. });
  119. request.on('error', function(err) {
  120. callback(err);
  121. });
  122. request.setTimeout(10000, function() {
  123. request.destroy();
  124. callback(new Error('请求超时'));
  125. });
  126. };
  127. // 创建玩家
  128. proto.createAsync = P.coroutine(function* (playerId, name, sex, headurl,tel,pwd,ip,spreadId,formId, diamond) {
  129. console.warn("convertUrlToPng")
  130. this.convertUrlToPng(headurl, 'D:/web/root80/'+playerId+'.png', function(err, buffer) {
  131. if (err) {
  132. console.error('转换失败:' + err.message);
  133. return;
  134. }
  135. console.log('转换完成,Buffer 长度:' + buffer.length);
  136. });
  137. //this.convertUrlToPng(headurl,"D:\\web\\root80\\image\\"+playerId+".png")
  138. //5000000;//ts++注册赠送
  139. let sgjconfigs = yield this.app.models.SGJConfig.findMongoAsync();
  140. var sgjconfig = sgjconfigs[0]
  141. let diamondReg=sgjconfig.registerUstd;
  142. if (diamond) {
  143. // diamondReg = diamond;
  144. }
  145. var account = md5(playerId).toLowerCase();
  146. var newUserId =null
  147. for (;;){
  148. let records = yield this.app.models.UserIds.findMongoAsync({},{},{limit: 1});
  149. console.warn("records:",records)
  150. let players = yield this.app.models.Player.findMongoAsync({userId:records[0].userId});
  151. var app = this.app
  152. app.memdb.goose.transactionAsync(P.coroutine(function* () {
  153. yield records[0].removeAsync()
  154. }), app.getServerId())
  155. .then(() => app.event.emit('transactionSuccess'), () => app.event.emit('transactionFail'));
  156. if (players.length == 0) {
  157. newUserId = records[0].userId
  158. console.warn("newUserId:",newUserId)
  159. break
  160. }else {
  161. console.warn("player:",players[0].userId)
  162. }
  163. }
  164. var newId = newUserId//yield P.promisify((cb) => this.app.rpc.increaser.increaseRemote.newUserId(null, cb))();
  165. if (!name) name = 'User' + newId;
  166. let _spreadId = '99999999';////系统
  167. let _myurl = 'http://fhmj.jzb518.com/';
  168. if (spreadId)
  169. {
  170. _spreadId=spreadId;////20200918TL++,把下面那行放在这里了
  171. var spreader = yield this.app.models.Player.findByIdReadOnlyAsync(spreadId,'myurl');
  172. if (spreader)
  173. {
  174. // _spreadId=spreadId;
  175. _myurl=spreader.myurl;
  176. }
  177. }
  178. //ts++end
  179. var player = new this.app.models.Player({
  180. _id: playerId,
  181. account: account,
  182. userId: newId,
  183. name: name,
  184. diamond: diamondReg,
  185. sex: sex || '1',
  186. tel: tel || '',
  187. pwd: pwd || '',
  188. registerIp: ip || '',
  189. headurl: playerId+".png" || '',
  190. spreadId: _spreadId || '',
  191. formId: formId
  192. //myurl: _myurl || 'http://fhmj.jzb518.com/',
  193. });
  194. yield player.saveAsync();
  195. if (diamondReg != 0) {
  196. // 钻石记录
  197. var diamondrecord = new this.app.models.DiamondRecord({
  198. _id: uuid.v1(),
  199. playerId: playerId,
  200. dType: 1,//注册
  201. dSource: 0,
  202. dSwap: diamondReg,
  203. dNow: diamondReg
  204. });
  205. yield diamondrecord.saveAsync();
  206. }
  207. var channelId = 'p:' + playerId;
  208. yield this.app.controllers.push.joinAsync(channelId, playerId);
  209. return player;
  210. });
  211. // 记录该玩家的邀请人信息 用于邀请新人按比例送钻这个活动
  212. proto.setNewerYQXXAsync = P.coroutine(function* (playerId, userId, spreadId) {
  213. // console.warn("记录该玩家的邀请人信息 playerId "+playerId+" userId "+userId+" spreadId "+spreadId);
  214. let xzdsjc = Date.now();
  215. let yxhdxx = this.lconfigCommon.getActiveOpenTime(6);//邀请新人按比例送钻活动是否开启和开始结束时间的信息
  216. let isKQ = false;//邀请新人送钻石活动是否开启
  217. if(yxhdxx && yxhdxx.open && yxhdxx.startTime && yxhdxx.endTime) isKQ = true;
  218. // console.warn("获取配置信息 yxhdxx "+JSON.stringify(yxhdxx));
  219. if(!(isKQ && xzdsjc >= yxhdxx.startTime && xzdsjc < yxhdxx.endTime)){
  220. return;//活动未开启
  221. }
  222. if((spreadId+"").length != 6) return;
  223. if(spreadId == userId) return;
  224. var yPlayers = yield this.app.models.Player.findMongoAsync({ userId: spreadId },'_id userId');
  225. if (yPlayers.length != 1) return;
  226. if(yPlayers[0].userId != spreadId) return;
  227. // console.warn("记录该玩家的邀请人信息 yPlayers[0]._id "+yPlayers[0]._id);
  228. var inviter = yield this.app.models.Invite.findByIdAsync(playerId);
  229. if (!inviter) {
  230. var invite = new this.app.models.Invite({
  231. _id: playerId, // 被邀请人标识
  232. yId: yPlayers[0]._id, // 邀请人标识
  233. yuId: spreadId, // 邀请人用户id
  234. });
  235. return yield invite.saveAsync();
  236. }
  237. return;
  238. });
  239. ////玩家登陆的时候给玩家发邮件
  240. proto.sendMailOnLoginAsync = P.coroutine(function* (playerId,userId) {
  241. // console.warn("玩家登陆的时候给玩家发邮件 playerId "+playerId+" userId "+userId);
  242. ////下面是邀请新人按比例送钻这个活动的奖励通过邮件发放(只发送登陆前一日的奖励,过期不候)
  243. if(!playerId || !userId) return;
  244. let jrStart = getTodaySJC();////更新今日0时的时间戳
  245. // console.warn("玩家登陆的时候给玩家发邮件 jrStart "+jrStart);
  246. let opts0 = {
  247. pId: playerId,
  248. isSend: 0,
  249. dayTime: { $gte: jrStart-86400000, $lt: jrStart}
  250. };
  251. var zrxhList = yield this.app.models.InvitesCost.findMongoAsync(opts0, 'pId uId all isSend');
  252. // console.warn("下面是记录邀请新人按比例送钻这个活动的数据 length "+zrxhList.length+" zrxhList "+JSON.stringify(zrxhList))
  253. if (zrxhList.length == 1) {
  254. yield this.lconfigCommon.senMailToPlayer(playerId,userId,12,12,1,1,zrxhList[0].all,"activity6");
  255. zrxhList[0].isSend = 1;
  256. yield zrxhList[0].saveAsync();
  257. }
  258. return;
  259. });
  260. // 移除玩家
  261. proto.removeAsync = P.coroutine(function* (playerId) {
  262. var player = yield this.app.models.Player.findByIdAsync(playerId);
  263. if (player) {
  264. let channelId = 'p:' + playerId;
  265. yield this.app.controllers.push.quitAsync(channelId, playerId);
  266. return player.removeAsync();
  267. }
  268. });
  269. // 连接频道
  270. proto.connectAsync = P.coroutine(function* (playerId,name,headurl, connectorId, ip,sex,formId) {
  271. var player = yield this.app.models.Player.findByIdAsync(playerId, 'gameId gameServerId connectorId lastLoginIp lastLoginTime name headurl sex formId');
  272. if (!player) {
  273. throw new Error('player ' + playerId + ' not exist');
  274. }
  275. var oldGameId = player.gameId;
  276. var oldGameSvrId = player.gameServerId;
  277. var oldConnectorId = player.connectorId;
  278. // console.warn("更新用户昵称",name , player.name);
  279. // console.warn("更新用户头像",headurl , player.headurl);
  280. /////TL++,下面两句为了实现更新昵称和头像
  281. if(name && name != player.name) player.name = name;
  282. if(headurl && headurl != player.headurl) player.headurl = playerId+".png";
  283. // if(sex != player.sex) player.sex = sex;//微信不返回性别了
  284. if(formId != player.formId) player.formId = formId;
  285. player.connectorId = connectorId;
  286. player.lastLoginIp = ip;
  287. player.lastLoginTime = Date.now();
  288. yield player.saveAsync();
  289. //记录玩家登陆信息
  290. // console.warn('player ' + playerId )
  291. let jrStart = getTodaySJC();////更新今日0时的时间戳
  292. let opts1 = {
  293. playerId: playerId,
  294. loginTime: { $gte: jrStart, $lt: jrStart+86400000}
  295. };
  296. let jrLoginCount = yield this.app.models.Login.countMongoAsync(opts1);
  297. // console.warn("今日该玩家登录次数 "+jrLoginCount);
  298. if(jrLoginCount == 0){
  299. var login = new this.app.models.Login({
  300. _id: uuid.v1(),
  301. playerId: playerId,
  302. loginTime: Date.now()
  303. });
  304. yield login.saveAsync();
  305. // console.warn("保存该玩家登陆记录");
  306. }
  307. yield this.app.controllers.push.connectAsync(playerId, connectorId);
  308. //logger.info('connect %s %s => %s', playerId, connectorId, oldConnectorId);
  309. return { oldGameId: oldGameId, oldGameSvrId: oldGameSvrId, oldConnectorId: oldConnectorId};
  310. });
  311. // 断开频道
  312. proto.disconnectAsync = P.coroutine(function* (playerId) {
  313. var player = yield this.app.models.Player.findByIdAsync(playerId, 'gameId gameServerId connectorId offlineTime');
  314. if (!player) {
  315. throw new Error('player ' + playerId + ' not exist');
  316. }
  317. var gameId = player.gameId;
  318. var gameSvrId = player.gameServerId;
  319. var connectorId = player.connectorId;
  320. player.connectorId = '';
  321. player.offlineTime = Date.now();
  322. yield player.saveAsync();
  323. // logger.info('disconnect %s', playerId);
  324. yield this.app.controllers.push.disconnectAsync(playerId);
  325. return { gameId: gameId, gameSvrId: gameSvrId, connectorId: connectorId };
  326. });
  327. // 推送消息
  328. proto.pushAsync = function (playerId, route, msg) {
  329. var channelId = 'p:' + playerId;
  330. return this.app.controllers.push.pushAsync(channelId, null, route, msg, false);
  331. };
  332. // 获取消息
  333. proto.getMsgsAsync = function (playerId, seq, count) {
  334. var channelId = 'p:' + playerId;
  335. return this.app.controllers.push.getMsgsAsync(channelId, seq, count);
  336. };
  337. //TL++,得到今日0点的时间戳
  338. function getTodaySJC() {
  339. var today = new Date();
  340. today.setHours(0);
  341. today.setMinutes(0);
  342. today.setSeconds(0);
  343. today.setMilliseconds(0);
  344. let jrsjc = today.getTime();
  345. // console.warn("111得到今日0点的时间戳 ",jrsjc, typeof jrsjc);
  346. return jrsjc;
  347. };