melo-sample-websocket-chat-game-server 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +45 -0
- package/LICENSE +21 -0
- package/app/servers/chat/handler/chatHandler.ts +45 -0
- package/app/servers/chat/lifecycle.ts +27 -0
- package/app/servers/chat/remote/chatRemote.ts +105 -0
- package/app/servers/connector/handler/entryHandler.ts +63 -0
- package/app/servers/connector/lifecycle.ts +27 -0
- package/app/servers/gate/handler/gateHandler.ts +41 -0
- package/app/util/dispatcher.ts +7 -0
- package/app/util/routeUtil.ts +16 -0
- package/app.ts +70 -0
- package/ci-test.js +44 -0
- package/dist/app/servers/chat/handler/chatHandler.js +45 -0
- package/dist/app/servers/chat/lifecycle.js +24 -0
- package/dist/app/servers/chat/remote/chatRemote.js +92 -0
- package/dist/app/servers/connector/handler/entryHandler.js +59 -0
- package/dist/app/servers/connector/lifecycle.js +24 -0
- package/dist/app/servers/gate/handler/gateHandler.js +44 -0
- package/dist/app/util/dispatcher.js +10 -0
- package/dist/app/util/routeUtil.js +15 -0
- package/dist/app.js +60 -0
- package/dist/config/adminServer.json +11 -0
- package/dist/config/adminUser.json +17 -0
- package/dist/config/clientProtos.json +6 -0
- package/dist/config/dictionary.json +3 -0
- package/dist/config/log4js.json +150 -0
- package/dist/config/master.json +14 -0
- package/dist/config/serverProtos.json +9 -0
- package/dist/config/servers.json +28 -0
- package/dist/preload.js +41 -0
- package/dist/robot/robot.js +84 -0
- package/package.json +34 -0
- package/preload.ts +40 -0
- package/robot/robot.ts +97 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
// 使用 IntelliSense 了解相关属性。
|
|
3
|
+
// 悬停以查看现有属性的描述。
|
|
4
|
+
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"type": "node",
|
|
9
|
+
"request": "launch",
|
|
10
|
+
"name": "LaunchMaster",
|
|
11
|
+
"program": "${workspaceFolder}\\dist\\app.js",
|
|
12
|
+
"outFiles": [
|
|
13
|
+
"${workspaceFolder}/**/*.js"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"type": "node",
|
|
18
|
+
"request": "attach",
|
|
19
|
+
"name": "Attach to Connector",
|
|
20
|
+
"address": "127.0.0.1",
|
|
21
|
+
"port": 10001,
|
|
22
|
+
"localRoot": "${workspaceFolder}",
|
|
23
|
+
"remoteRoot": "${workspaceFolder}"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"type": "node",
|
|
27
|
+
"request": "attach",
|
|
28
|
+
"name": "Attach to Chat",
|
|
29
|
+
"address": "127.0.0.1",
|
|
30
|
+
"port": 10002,
|
|
31
|
+
"localRoot": "${workspaceFolder}",
|
|
32
|
+
"remoteRoot": "${workspaceFolder}"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "node",
|
|
36
|
+
"request": "attach",
|
|
37
|
+
"name": "Attach to Gate",
|
|
38
|
+
"address": "127.0.0.1",
|
|
39
|
+
"port": 10003,
|
|
40
|
+
"localRoot": "${workspaceFolder}",
|
|
41
|
+
"remoteRoot": "${workspaceFolder}"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
]
|
|
45
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 node-melo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ChatRemote } from '../remote/chatRemote';
|
|
2
|
+
import {Application, BackendSession} from '@bigtyphoon/melo';
|
|
3
|
+
import { FrontendSession } from '@bigtyphoon/melo';
|
|
4
|
+
|
|
5
|
+
export default function(app: Application) {
|
|
6
|
+
return new ChatHandler(app);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ChatHandler {
|
|
10
|
+
constructor(private app: Application) {
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Send messages to users
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} msg message from client
|
|
17
|
+
* @param {Object} session
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
async send(msg: {content: string , target: string}, session: BackendSession) {
|
|
21
|
+
let rid = session.get('rid');
|
|
22
|
+
let username = session.uid.split('*')[0];
|
|
23
|
+
let channelService = this.app.get('channelService');
|
|
24
|
+
let param = {
|
|
25
|
+
msg: msg.content,
|
|
26
|
+
from: username,
|
|
27
|
+
target: msg.target
|
|
28
|
+
};
|
|
29
|
+
let channel = channelService.getChannel(rid, false);
|
|
30
|
+
|
|
31
|
+
// the target is all users
|
|
32
|
+
if (msg.target === '*') {
|
|
33
|
+
channel.pushMessage('onChat', param);
|
|
34
|
+
}
|
|
35
|
+
// the target is specific user
|
|
36
|
+
else {
|
|
37
|
+
let tuid = msg.target + '*' + rid;
|
|
38
|
+
let tsid = channel.getMember(tuid)['sid'];
|
|
39
|
+
channelService.pushMessageByUids('onChat', param, [{
|
|
40
|
+
uid: tuid,
|
|
41
|
+
sid: tsid
|
|
42
|
+
}]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ILifeCycle, Application } from '@bigtyphoon/melo';
|
|
2
|
+
|
|
3
|
+
export default function () {
|
|
4
|
+
return new Lifecycle();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Lifecycle implements ILifeCycle {
|
|
9
|
+
beforeStartup(app: Application, cb: () => void): void {
|
|
10
|
+
console.log(app.getServerId(), '!!!before startup');
|
|
11
|
+
cb();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
afterStartup(app: Application, cb: () => void): void {
|
|
15
|
+
console.log(app.getServerId(), '!!afterStartup');
|
|
16
|
+
cb();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
afterStartAll(app: Application): void {
|
|
20
|
+
console.log(app.getServerId(), '!!after start all');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beforeShutdown(app: Application, shutDown: () => void, cancelShutDownTimer: () => void) {
|
|
24
|
+
console.log(app.getServerId(), '!!beforeShutdown');
|
|
25
|
+
shutDown();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Application, ChannelService, RemoterClass, FrontendSession } from '@bigtyphoon/melo';
|
|
2
|
+
|
|
3
|
+
export default function (app: Application) {
|
|
4
|
+
return new ChatRemote(app);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// UserRpc的命名空间自动合并
|
|
8
|
+
declare global {
|
|
9
|
+
interface UserRpc {
|
|
10
|
+
chat: {
|
|
11
|
+
chatRemote: RemoterClass<FrontendSession, ChatRemote>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 如果有多个remote文件。需要在各自的remote文件内定义rpc的话。可以这样定义,解决定义被覆盖的问题。
|
|
17
|
+
/**
|
|
18
|
+
// UserRpc的命名空间自动合并
|
|
19
|
+
declare global {
|
|
20
|
+
interface RemoterChat {
|
|
21
|
+
chatRemote: RemoterClass<FrontendSession, ChatRemote>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface UserRpc {
|
|
25
|
+
chat: RemoterChat;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
*/
|
|
30
|
+
export class ChatRemote {
|
|
31
|
+
|
|
32
|
+
constructor(private app: Application) {
|
|
33
|
+
this.app = app;
|
|
34
|
+
this.channelService = app.get('channelService');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private channelService: ChannelService;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add user into chat channel.
|
|
41
|
+
*
|
|
42
|
+
* @param {String} uid unique id for user
|
|
43
|
+
* @param {String} sid server id
|
|
44
|
+
* @param {String} name channel name
|
|
45
|
+
* @param {boolean} flag channel parameter
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
public async add(uid: string, sid: string, name: string, flag: boolean) {
|
|
49
|
+
let channel = this.channelService.getChannel(name, flag);
|
|
50
|
+
let username = uid.split('*')[0];
|
|
51
|
+
let param = {
|
|
52
|
+
user: username
|
|
53
|
+
};
|
|
54
|
+
console.log('send on add', param);
|
|
55
|
+
channel.pushMessage('onAdd', param);
|
|
56
|
+
|
|
57
|
+
if (!!channel) {
|
|
58
|
+
channel.add(uid, sid);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return this.get(name, flag);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get user from chat channel.
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} opts parameters for request
|
|
68
|
+
* @param {String} name channel name
|
|
69
|
+
* @param {boolean} flag channel parameter
|
|
70
|
+
* @return {Array} users uids in channel
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
private get(name: string, flag: boolean) {
|
|
74
|
+
let users: string[] = [];
|
|
75
|
+
let channel = this.channelService.getChannel(name, flag);
|
|
76
|
+
if (!!channel) {
|
|
77
|
+
users = channel.getMembers();
|
|
78
|
+
}
|
|
79
|
+
for (let i = 0; i < users.length; i++) {
|
|
80
|
+
users[i] = users[i].split('*')[0];
|
|
81
|
+
}
|
|
82
|
+
return users;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Kick user out chat channel.
|
|
87
|
+
*
|
|
88
|
+
* @param {String} uid unique id for user
|
|
89
|
+
* @param {String} sid server id
|
|
90
|
+
* @param {String} name channel name
|
|
91
|
+
*
|
|
92
|
+
*/
|
|
93
|
+
public async kick(uid: string, sid: string, name: string) {
|
|
94
|
+
let channel = this.channelService.getChannel(name, false);
|
|
95
|
+
// leave channel
|
|
96
|
+
if (!!channel) {
|
|
97
|
+
channel.leave(uid, sid);
|
|
98
|
+
}
|
|
99
|
+
let username = uid.split('*')[0];
|
|
100
|
+
let param = {
|
|
101
|
+
user: username
|
|
102
|
+
};
|
|
103
|
+
channel.pushMessage('onLeave', param);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {Application} from '@bigtyphoon/melo';
|
|
2
|
+
import {FrontendSession} from '@bigtyphoon/melo';
|
|
3
|
+
|
|
4
|
+
export default function (app: Application) {
|
|
5
|
+
return new EntryHandler(app);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class EntryHandler {
|
|
9
|
+
constructor(private app: Application) {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* New client entry chat server.
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} msg request message
|
|
17
|
+
* @param {Object} session current session object
|
|
18
|
+
*/
|
|
19
|
+
async enter(msg: { rid: string, username: string }, session: FrontendSession) {
|
|
20
|
+
let self = this;
|
|
21
|
+
let rid = msg.rid;
|
|
22
|
+
let uid = msg.username + '*' + rid;
|
|
23
|
+
let sessionService = self.app.get('sessionService');
|
|
24
|
+
|
|
25
|
+
// duplicate log in
|
|
26
|
+
if (!!sessionService.getByUid(uid)) {
|
|
27
|
+
return {
|
|
28
|
+
code: 500,
|
|
29
|
+
error: true
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await session.abind(uid);
|
|
34
|
+
session.set('rid', rid);
|
|
35
|
+
session.push('rid', function (err) {
|
|
36
|
+
if (err) {
|
|
37
|
+
console.error('set rid for session service failed! error is : %j', err.stack);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
session.on('closed', this.onUserLeave.bind(this));
|
|
41
|
+
|
|
42
|
+
// put user into channel
|
|
43
|
+
let users = await self.app.rpc.chat.chatRemote.add.route(session)(uid, self.app.get('serverId'), rid, true);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
users: users
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* User log out handler
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} app current application
|
|
54
|
+
* @param {Object} session current session object
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
onUserLeave(session: FrontendSession) {
|
|
58
|
+
if (!session || !session.uid) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.app.rpc.chat.chatRemote.kick.route(session, true)(session.uid, this.app.get('serverId'), session.get('rid'));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ILifeCycle, Application } from '@bigtyphoon/melo';
|
|
2
|
+
|
|
3
|
+
export default function () {
|
|
4
|
+
return new Lifecycle();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Lifecycle implements ILifeCycle {
|
|
9
|
+
beforeStartup(app: Application, cb: () => void): void {
|
|
10
|
+
console.log(app.getServerId(), '!!!before startup');
|
|
11
|
+
cb();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
afterStartup(app: Application, cb: () => void): void {
|
|
15
|
+
console.log(app.getServerId(), '!!afterStartup');
|
|
16
|
+
cb();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
afterStartAll(app: Application): void {
|
|
20
|
+
console.log(app.getServerId(), '!!after start all');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
beforeShutdown(app: Application, shutDown: () => void, cancelShutDownTimer: () => void) {
|
|
24
|
+
console.log(app.getServerId(), '!!beforeShutdown');
|
|
25
|
+
shutDown();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { dispatch } from '../../../util/dispatcher';
|
|
2
|
+
import { Application , BackendSession} from '@bigtyphoon/melo';
|
|
3
|
+
|
|
4
|
+
export default function (app: Application) {
|
|
5
|
+
return new GateHandler(app);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class GateHandler {
|
|
9
|
+
constructor(private app: Application) {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gate handler that dispatch user to connectors.
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} msg message from client
|
|
16
|
+
* @param {Object} session
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
async queryEntry(msg: {uid: string}, session: BackendSession) {
|
|
20
|
+
let uid = msg.uid;
|
|
21
|
+
if (!uid) {
|
|
22
|
+
return {
|
|
23
|
+
code: 500
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// get all connectors
|
|
27
|
+
let connectors = this.app.getServersByType('connector');
|
|
28
|
+
if (!connectors || connectors.length === 0) {
|
|
29
|
+
return {
|
|
30
|
+
code: 500
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// select connector
|
|
34
|
+
let res = dispatch(uid, connectors);
|
|
35
|
+
return {
|
|
36
|
+
code: 200,
|
|
37
|
+
host: res.host,
|
|
38
|
+
port: res.clientPort
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
import { dispatch} from './dispatcher';
|
|
3
|
+
import { Session, Application } from '@bigtyphoon/melo';
|
|
4
|
+
|
|
5
|
+
export function chat(session: Session, msg: any, app: Application, cb: (err: Error , serverId ?: string) => void) {
|
|
6
|
+
let chatServers = app.getServersByType('chat');
|
|
7
|
+
|
|
8
|
+
if(!chatServers || chatServers.length === 0) {
|
|
9
|
+
cb(new Error('can not find chat servers.'));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let res = dispatch(session.get('rid'), chatServers);
|
|
14
|
+
|
|
15
|
+
cb(null, res.id);
|
|
16
|
+
}
|
package/app.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { melo } from '@bigtyphoon/melo';
|
|
2
|
+
import * as routeUtil from './app/util/routeUtil';
|
|
3
|
+
import { preload } from './preload';
|
|
4
|
+
import { createRobotPlugin } from '@bigtyphoon/melo-robot-plugin';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 替换全局Promise
|
|
8
|
+
* 自动解析sourcemap
|
|
9
|
+
* 捕获全局错误
|
|
10
|
+
*/
|
|
11
|
+
preload();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Init app for client.
|
|
15
|
+
*/
|
|
16
|
+
let app = melo.createApp();
|
|
17
|
+
app.set('name', 'chatofpomelo-websocket');
|
|
18
|
+
|
|
19
|
+
// app configuration
|
|
20
|
+
app.configure('production|development', 'connector', function () {
|
|
21
|
+
app.set('connectorConfig',
|
|
22
|
+
{
|
|
23
|
+
connector: melo.connectors.hybridconnector,
|
|
24
|
+
heartbeat: 3,
|
|
25
|
+
useDict: true,
|
|
26
|
+
useProtobuf: true
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
app.set('serverConfig', {
|
|
30
|
+
reloadHandlers: true,
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
app.configure('production|development', 'gate', function () {
|
|
35
|
+
app.set('connectorConfig',
|
|
36
|
+
{
|
|
37
|
+
connector: melo.connectors.hybridconnector,
|
|
38
|
+
useProtobuf: true
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// app configure
|
|
43
|
+
app.configure('production|development', function () {
|
|
44
|
+
// route configures
|
|
45
|
+
app.route('chat', routeUtil.chat);
|
|
46
|
+
|
|
47
|
+
// filter configures
|
|
48
|
+
app.filter(new melo.filters.timeout());
|
|
49
|
+
|
|
50
|
+
// 热更新 handler配置
|
|
51
|
+
// app.set('serverConfig',{
|
|
52
|
+
// reloadHandlers:true,
|
|
53
|
+
// });
|
|
54
|
+
// 热更新 remote 配置
|
|
55
|
+
// app.set('remoteConfig', {
|
|
56
|
+
// reloadRemotes: true
|
|
57
|
+
// });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.configure('development', function () {
|
|
61
|
+
// enable the system monitor modules
|
|
62
|
+
app.enable('systemMonitor');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (app.isMaster()) {
|
|
66
|
+
app.use(createRobotPlugin({ scriptFile: __dirname + '/robot/robot.js' }));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// start app
|
|
70
|
+
app.start();
|
package/ci-test.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const { spawn } = require("child_process");
|
|
2
|
+
|
|
3
|
+
console.log("!! ci-test directory:", __dirname, " cwd:", process.cwd(), " main file:", require.main.filename)
|
|
4
|
+
|
|
5
|
+
setTimeout(() => {
|
|
6
|
+
console.log("start child process timeout")
|
|
7
|
+
process.exit(-2)
|
|
8
|
+
}, 25000)
|
|
9
|
+
|
|
10
|
+
let childProcess = spawn("node", ['app.js', 'env=development'], { cwd: __dirname + "/dist" })
|
|
11
|
+
childProcess.stdout.on("data", (data) => {
|
|
12
|
+
// all servers startup in
|
|
13
|
+
let str = data.toString()
|
|
14
|
+
console.log("spawn data:", str)
|
|
15
|
+
if (str.indexOf("[master-server-1 watchdog.js] all servers startup in") >= 0) {
|
|
16
|
+
console.log("spawn -- start success")
|
|
17
|
+
// TODO: 添加 消息测试
|
|
18
|
+
// 子进程还在. ci中没什么影响
|
|
19
|
+
// 解决方法
|
|
20
|
+
// https://stackoverflow.com/a/42545818/6116888
|
|
21
|
+
// https://blog.michany.com/2020/01/13/NodeJS-ChildProcess/
|
|
22
|
+
childProcess.kill("SIGTERM")
|
|
23
|
+
process.exit(0)
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
childProcess.stderr.on("data", (data) => {
|
|
28
|
+
let str = data.toString()
|
|
29
|
+
console.log("swpan stderr:", str)
|
|
30
|
+
if (str.indexOf("Debugger listening") >= 0 ||
|
|
31
|
+
str.indexOf("Warning: Accessing non-existent") >= 0 ||
|
|
32
|
+
str.indexOf("For help") >= 0) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
// 子进程还在. ci中没什么影响
|
|
36
|
+
childProcess.kill("SIGTERM")
|
|
37
|
+
process.exit(-1)
|
|
38
|
+
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
childProcess.on("close", (v) => {
|
|
42
|
+
console.log("spwan process closed!!", v)
|
|
43
|
+
process.exit(-3)
|
|
44
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatHandler = void 0;
|
|
4
|
+
function default_1(app) {
|
|
5
|
+
return new ChatHandler(app);
|
|
6
|
+
}
|
|
7
|
+
exports.default = default_1;
|
|
8
|
+
class ChatHandler {
|
|
9
|
+
constructor(app) {
|
|
10
|
+
this.app = app;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Send messages to users
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} msg message from client
|
|
16
|
+
* @param {Object} session
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
async send(msg, session) {
|
|
20
|
+
let rid = session.get('rid');
|
|
21
|
+
let username = session.uid.split('*')[0];
|
|
22
|
+
let channelService = this.app.get('channelService');
|
|
23
|
+
let param = {
|
|
24
|
+
msg: msg.content,
|
|
25
|
+
from: username,
|
|
26
|
+
target: msg.target
|
|
27
|
+
};
|
|
28
|
+
let channel = channelService.getChannel(rid, false);
|
|
29
|
+
// the target is all users
|
|
30
|
+
if (msg.target === '*') {
|
|
31
|
+
channel.pushMessage('onChat', param);
|
|
32
|
+
}
|
|
33
|
+
// the target is specific user
|
|
34
|
+
else {
|
|
35
|
+
let tuid = msg.target + '*' + rid;
|
|
36
|
+
let tsid = channel.getMember(tuid)['sid'];
|
|
37
|
+
channelService.pushMessageByUids('onChat', param, [{
|
|
38
|
+
uid: tuid,
|
|
39
|
+
sid: tsid
|
|
40
|
+
}]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.ChatHandler = ChatHandler;
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdEhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9hcHAvc2VydmVycy9jaGF0L2hhbmRsZXIvY2hhdEhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsbUJBQXdCLEdBQWdCO0lBQ3BDLE9BQU8sSUFBSSxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDaEMsQ0FBQztBQUZELDRCQUVDO0FBRUQsTUFBYSxXQUFXO0lBQ3BCLFlBQW9CLEdBQWdCO1FBQWhCLFFBQUcsR0FBSCxHQUFHLENBQWE7SUFDcEMsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBdUMsRUFBRSxPQUF1QjtRQUN2RSxJQUFJLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLElBQUksUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3pDLElBQUksY0FBYyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDcEQsSUFBSSxLQUFLLEdBQUc7WUFDUixHQUFHLEVBQUUsR0FBRyxDQUFDLE9BQU87WUFDaEIsSUFBSSxFQUFFLFFBQVE7WUFDZCxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU07U0FDckIsQ0FBQztRQUNGLElBQUksT0FBTyxHQUFHLGNBQWMsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXBELDBCQUEwQjtRQUMxQixJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFO1lBQ3BCLE9BQU8sQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQ3hDO1FBQ0QsOEJBQThCO2FBQ3pCO1lBQ0QsSUFBSSxJQUFJLEdBQUcsR0FBRyxDQUFDLE1BQU0sR0FBRyxHQUFHLEdBQUcsR0FBRyxDQUFDO1lBQ2xDLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUMsY0FBYyxDQUFDLGlCQUFpQixDQUFDLFFBQVEsRUFBRSxLQUFLLEVBQUUsQ0FBQztvQkFDL0MsR0FBRyxFQUFFLElBQUk7b0JBQ1QsR0FBRyxFQUFFLElBQUk7aUJBQ1osQ0FBQyxDQUFDLENBQUM7U0FDUDtJQUNMLENBQUM7Q0FDSjtBQXBDRCxrQ0FvQ0MifQ==
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
function default_1() {
|
|
4
|
+
return new Lifecycle();
|
|
5
|
+
}
|
|
6
|
+
exports.default = default_1;
|
|
7
|
+
class Lifecycle {
|
|
8
|
+
beforeStartup(app, cb) {
|
|
9
|
+
console.log(app.getServerId(), '!!!before startup');
|
|
10
|
+
cb();
|
|
11
|
+
}
|
|
12
|
+
afterStartup(app, cb) {
|
|
13
|
+
console.log(app.getServerId(), '!!afterStartup');
|
|
14
|
+
cb();
|
|
15
|
+
}
|
|
16
|
+
afterStartAll(app) {
|
|
17
|
+
console.log(app.getServerId(), '!!after start all');
|
|
18
|
+
}
|
|
19
|
+
beforeShutdown(app, shutDown, cancelShutDownTimer) {
|
|
20
|
+
console.log(app.getServerId(), '!!beforeShutdown');
|
|
21
|
+
shutDown();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vYXBwL3NlcnZlcnMvY2hhdC9saWZlY3ljbGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQTtJQUNJLE9BQU8sSUFBSSxTQUFTLEVBQUUsQ0FBQztBQUMzQixDQUFDO0FBRkQsNEJBRUM7QUFHRCxNQUFNLFNBQVM7SUFDWCxhQUFhLENBQUMsR0FBZ0IsRUFBRSxFQUFjO1FBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDcEQsRUFBRSxFQUFFLENBQUM7SUFDVCxDQUFDO0lBRUQsWUFBWSxDQUFDLEdBQWdCLEVBQUUsRUFBYztRQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2pELEVBQUUsRUFBRSxDQUFDO0lBQ1QsQ0FBQztJQUVELGFBQWEsQ0FBQyxHQUFnQjtRQUMxQixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFRCxjQUFjLENBQUMsR0FBZ0IsRUFBRSxRQUFvQixFQUFFLG1CQUErQjtRQUNsRixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ25ELFFBQVEsRUFBRSxDQUFDO0lBQ2YsQ0FBQztDQUNKIn0=
|