天天看點

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

說在前面

pomelo: 它是網易開源的一套基于Node.js的遊戲服務端架構,詳情請戳這裡關于pomelo的種種這裡不詳細說。點選連結檢視詳情。但是由于pomelo是js項目,使用起來的時候并不是很爽,是以就有了ts的引入。

typescript: TypeScript是一種由微軟開發的自由和開源的程式設計語言。它是JavaScript的一個超集,而且本質上向這個語言添加了可選的靜态類型和基于類的面向對象程式設計。換而言之,TypeScript是在JavaScript的基礎上添加了文法糖,使其在使用的過程中完成了文法和類型的檢測,同時達到更便利的代碼提示。本質上typeScript在運作前是需要通過tsc編譯成Javascript,然後運作。是以TS的最大便利是在使用的過程,而本質還是JS。對于TS的更多相關資訊,自行腦補。

vscode: Visual Studio Code (簡稱 VS Code / VSC) 是一款免費開源的現代化輕量級代碼編輯器,支援幾乎所有主流的開發語言的文法高亮、智能代碼補全、自定義熱鍵、括号比對、代碼片段、代碼對比 Diff、GIT 等特性,支援插件擴充,并針對網頁開發和雲端應用開發做了優化。軟體跨平台支援 Win、Mac 以及 Linux。VSC中文網,用過的都知道它的好~~~

是以前面說了這麼多,其實就是在講,想這麼幹的往下看。

流程

環境安裝

  1. Node.js
  2. vscode
  3. pomelo
  4. typescript
  5. 安裝VSCode擴充插件:ESLint, TSLint.

建立一個Pomelo項目

  1. 建立一個檔案夾
  2. 進入該檔案夾
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
          
    $ pomelo init
    
    The default admin user is:
    
      username: admin
      password: admin
    
    You can configure admin users by editing adminUser.json later.
    
    Please select underly connector, 1 for websocket(native socket), 2 for socket.io, 3 for wss, 4 for socket.io(wss), 5 for udp, 6 for mqtt: [1]
    
    
    $ 1
    
        create : E:pomelotestnpm-install.bat
        create : E:pomelotestnpm-install.sh
        create : E:pomelotestweb-server
        create : E:pomelotestshared
    #... 省略部分輸出
        create : E:pomeloTestweb-serverpublicjsliblocalboot
        create : E:pomeloTestweb-serverpublicjsliblocalbootcomponent.json
        create : E:pomeloTestweb-serverpublicjsliblocalbootindex.js
          
  3. windows使用者執行項目檔案夾下的 “npm-install.bat”, shell 使用者執行檔案夾下的 “npm-install.sh” 進行依賴安裝,初始化pomelo項目.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
      
E:pomelotest>npm-install.bat
npm info it worked if it ends with ok
npm info using [email protected]
npm info using [email protected]
#... 省略部分輸出

npm notice created a lockfile as package-lock.json. You should commit this file.
npm info lifecycle undefined~postshrinkwrap: undefined
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
npm WARN [email protected] No license field.
#... 省略部分輸出
added 29 packages in 3.713s
npm info lifecycle undefined~postshrinkwrap: undefined
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
npm WARN [email protected] No license field.

added 312 packages in 29.82s
npm info ok

E:pomelotestgame-server>
      

至此pomelo項目建立成功。

接下來測試一下項目是否正确可行。

  1. 試運作pomelo項目

    a. 進入到項目目錄下的game-server檔案夾執行app.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
          
    $ cd game-server
    $ node app
    
    [2018-06-20 22:05:45.215] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibapplication.js] application inited: "master-server-1"
    [2018-06-20 22:05:45.325] [INFO] pomelo-admin - [MqttServer] [MqttServer] listen on 3005
    [2018-06-20 22:05:45.328] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibmasterstarter.js] Executing D:Program Filesnodejsnode.exe E:pomeloTestgame-serverapp,env=development,id=connector-server-1,host=127.0.0.1,port=3150,clientHost=127.0.0.1,clientPort=3010,frontend=true,serverType=connector locally
    [2018-06-20 22:05:45.332] [INFO] pomelo-admin - [ConsoleService] try to connect master: "master", "127.0.0.1", 3005
    [2018-06-20 22:05:45.372] [DEBUG] pomelo - [E:pomeloTestgame-servernode_modulespomelolibmodulesmasterwatcher.js] masterwatcher receive add server 
    #... 省略部分輸出
    [2018-06-20 22:05:45.715] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibmasterwatchdog.js] all servers startup in 485 ms
          

看到 all servers startup in 485 ms 了沒有,說明伺服器啟動成功了。

b. 有伺服器肯定會有前端,前端就是項目根目錄下的web-server檔案夾,了解一下。進入到web-server檔案夾,啟動前端服務。

建立一個控制台

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      
$ cd web-server
$ node app

Warning: express.createServer() is deprecated, express
applications no longer inherit from http.Server,
please use:

  var express = require("express");
  var app = express();

connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Web server has started.
Please log on http://127.0.0.1:3001/index.html
      

其中的警告是說:’express.createServer()’ 方法已經廢棄,請使用下面的‘ var express = require(“express”); var app = express();’這是因為項目的模闆比較舊沒有進行更新,而新版本的express已經廢棄了該方法,但是目前還不影響使用,先不管它。

好了,前端也跑起來了,輸傳入連結接測試:http://127.0.0.1:3001/index.html

看到下圖:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

表示前端啟動成功了。

點選”Test Game Server”按鈕,測試後端。

看到下圖:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

表示服務端也啟動成功。

如果出現啟動失敗請檢視輸出,自行百度解決,一般是由于子產品沒有安裝完整,或者端口被占用的問題。如果又要請留言。

然後開始第二階段,項目改造,接入TS。

改造項目為TypeScript

  1. 用VSCode打開 game-server 項目
  2. 在game-server目錄下建立一個app_types檔案夾。
  3. 在檔案夾内添加ts配置檔案“tsconfig.json”, 檔案内容如下。
1
2
3
4
5
6
7
8
9
10
11
      
{
  "compilerOptions": {
    "module": "commonjs",
    "lib": [ "dom", "es6", "es2015.promise" ],
    "target": "es6",
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "outDir": "../app",
    "sourceMap": true,
  },
}
      

解釋下ts的這個配置:

“compilerOptions”: 編譯選項

“module”: 指定生成哪個子產品系統代碼: “None”, “CommonJS”, “AMD”, “System”, “UMD”, “ES6”或 “ES2015”。

“lib”: 編譯過程中需要引入的庫檔案的清單。 可能的值為: “ ES5 “,” ES6 “,” ES2015 “,” ES7 “,” ES2016 “,” ES2017” 等;

“target”: 指定ECMAScript目标版本 “ES3”(預設), “ES5”, “ES6”/ “ES2015”, “ES2016”, “ES2017”或 “ESNext”。

“experimentalDecorators”: 啟用實驗性的ES裝飾器。(這裡可以不加)

“skipLibCheck”: 忽略所有的聲明檔案( *.d.ts)的類型檢查。

“outDir”: 重定向輸出目錄。

“sourceMap”:生成相應的 .map檔案。

其他的配置的詳情請戳這裡

  1. 修改代碼

    我們可以先看下原來app中的代碼結構:

    –|app

    –|servers

    --|connector
        --|handler
            --entryHandler.js
               
    這個結構是不可以亂改的,至于為啥請戳上面pomelo官網翻閱文檔。

我們需要做的是,當我們寫好ts的代碼之後,編譯之後的ts代碼需要輸出到app目錄下,并且保證servers下的目錄和pomelo的要求一直。當pomelo啟動,讀取伺服器配置”config/server.json”時,能找到對應的js代碼來啟動服務。

我們可以看一下server.json中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
      
{
  "development":{
    "connector": [
    {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true}
    ]
  },
  "production":{
    "connector": [
    {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true}
    ]
  }
}
      

其中的 “connector” 表示服務型所在的目錄,也就是’app/servers/connector’.是以這也是為什麼需要保證app下目錄的完整性。

是以實際操作如下:

a. 在app_types目中中建立如下檔案夾結構:

–|app_types

–|servers

–|connector

–|handler

b. 在handler檔案夾中建立ts檔案:”entryHandler.ts”,填充如下代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
      
class ConnectorHandler {

    protected app;

    constructor(app) {
        this.app = app;
    }

    public entry(msg, session, next) {
        next(null, {code: 200, msg: 'game server is ok.'});
    }

    public publish(msg, session, next) {
        var result = {
            topic: 'publish',
            payload: JSON.stringify({code: 200, msg: 'publish message is ok.'})
        };
      next(null, result);
    }

    public subscribe(msg, session, next) {
        var result = {
            topic: 'subscribe',
            payload: JSON.stringify({code: 200, msg: 'subscribe message is ok.'})
        };
      next(null, result);
    }
}

export = function(app) {
    return new ConnectorHandler(app);
}
      

c.添加ts編譯任務:

在VSCode下,按下快捷鍵Ctrl+Shift+P打開任務面闆,如圖所示:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

選擇“任務配置”(tasks: configure task);

然後選擇構tsc: “建構- app_types/tsconfig.json”;

這時候會在目錄下建立一個.vscode檔案夾,檔案夾中有一個tasks.json的配置檔案。

task中的内容為下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
      
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "type": "typescript",
            "tsconfig": "app_types\tsconfig.json",
            "problemMatcher": [
                "$tsc"
            ]
        }
    ]
}
      

d. 配置完成之後,檢測一下建構結果是否如你所示,首先删除app檔案夾中所有内容;

然後建構:Ctrl+Shift+B,

在彈出的面闆中選擇建構: app_typestsconfig.json

這是後可以看到,下方的面闆中顯示如下:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

這時候檢視下app中的檔案夾,結構如下:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

這時候可以發現和我們原先設想的不一樣啊。。。按理說這個entryHandler.js應該在app/servers/connector/handler下才對。

但是折騰了好久也沒照道具體的原因和配置。但是還是有解決的方法,如果有知道的道友希望您能告知下應該這麼處理,我的解決方法是:

在app_types中建立一個檔案夾,我叫做util,然後在util中放入一個ts腳本。然後寫入一些代碼。再編譯(編譯前請删除app中的舊的檔案)。

這時候如圖所示:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

這樣就達到我們預期的效果。

我們來看一下編譯之後的js代碼和原來的js代碼的差別;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
      
// 這是編譯的代碼es6的版本
;
class  {
    constructor(app) {
        this.app = app;
    }
    entry(msg, session, next) {
        next(null, { code: 200, msg: 'game server is ok.' });
    }
    publish(msg, session, next) {
        var result = {
            topic: 'publish',
            payload: JSON.stringify({ code: 200, msg: 'publish message is ok.' })
        };
        next(null, result);
    }
    subscribe(msg, session, next) {
        var result = {
            topic: 'subscribe',
            payload: JSON.stringify({ code: 200, msg: 'subscribe message is ok.' })
        };
        next(null, result);
    }
}
module.exports = function (app) {
    return new ConnectorHandler(app);
};
//# sourceMappingURL=entryHandler.js.map
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
      
// 這是原來的代碼
module.exports = function(app) {
  return new Handler(app);
};

var Handler = function(app) {
  this.app = app;
};

Handler.prototype.entry = function(msg, session, next) {
  next(null, {code: 200, msg: 'game server is ok.'});
};

Handler.prototype.publish = function(msg, session, next) {
	var result = {
		topic: 'publish',
		payload: JSON.stringify({code: 200, msg: 'publish message is ok.'})
	};
  next(null, result);
};

Handler.prototype.subscribe = function(msg, session, next) {
	var result = {
		topic: 'subscribe',
		payload: JSON.stringify({code: 200, msg: 'subscribe message is ok.'})
	};
  next(null, result);
};
      

看起來差很多對吧,但是如果改成es5的話呢?

修改tsconfig.json内容:

1
2
3
4
5
6
7
8
9
10
11
      
{
    "compilerOptions": {
      "module": "commonjs",
      "lib": [ "dom", "es5", "es2015.promise" ],
      "target": "es5",
      "experimentalDecorators": true,
      "skipLibCheck": true,
      "outDir": "../app",
      "sourceMap": true,
    },
  }
      

然後重新編譯代碼,這是js腳本的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
      
;
var ConnectorHandler = /** @class */ (function () {
    function (app) {
        this.app = app;
    }
    ConnectorHandler.prototype.entry = function (msg, session, next) {
        next(null, { code: 200, msg: 'game server is ok.' });
    };
    ConnectorHandler.prototype.publish = function (msg, session, next) {
        var result = {
            topic: 'publish',
            payload: JSON.stringify({ code: 200, msg: 'publish message is ok.' })
        };
        next(null, result);
    };
    ConnectorHandler.prototype.subscribe = function (msg, session, next) {
        var result = {
            topic: 'subscribe',
            payload: JSON.stringify({ code: 200, msg: 'subscribe message is ok.' })
        };
        next(null, result);
    };
    return ConnectorHandler;
}());
module.exports = function (app) {
    return new ConnectorHandler(app);
};
//# sourceMappingURL=entryHandler.js.map
      

這時候發現是不是差不多了,這是因為es6引入了類的概念,不細說,自行腦補啦,反正倆種都可以運作的。

e. 測試成果的時候到了,分别跑服務端和用戶端,看看效果是不是和原來一樣。

在終端輸如

1
2
3
4
5
6
7
8
9
      
$ pomelo start
# ...
[2018-06-21 00:19:21.643] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibapplication.js] "connector-server-1" enter after start...

[2018-06-21 00:19:21.645] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibapplication.js] "connector-server-1" finish start

[2018-06-21 00:19:21.645] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibapplication.js] "connector-server-1" startup in 206 ms

[2018-06-21 00:19:21.646] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibmasterwatchdog.js] all servers startup in 513 ms
      

如果和原來一樣),說明你的改造是成功的了。這是後可以嘗試下啟動前端,在測試一下,一般是OK的。

是以接下來時調試了。

pomelo ts 版本的調試

PS: 有人說,打LOG是最好的調試~~

本教程采用遠端調試的方式。

1.首先檢視Node的調試參數:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
      
$ node -h

Usage: node [options] [ -e script | script.js | - ] [arguments]
       node inspect script.js [arguments]

Options:
  -v, --version              print Node.js version
  -e, --eval script          evaluate script
  -p, --print                evaluate script and print result
  -c, --check                syntax check script without executing
  -i, --interactive          always enter the REPL even if stdin
                             does not appear to be a terminal
  -r, --require              module to preload (option can be repeated)
  -                          script read from stdin (default; interactive mode if a tty)
  # 這個就是我們需要的調試參數(别問我怎麼知道是這個的,因為有個東西叫網絡~~)
  --inspect[=[host:]port]    activate inspector on host:port
                             (default: 127.0.0.1:9229)
  --inspect-brk[=[host:]port]
                             activate inspector on host:port
                             and break at start of user script
  --inspect-port=[host:]port
                             set host:port for inspector
  --no-deprecation           silence deprecation warnings
  --trace-deprecation        show stack traces on deprecations
  --throw-deprecation        throw an exception on deprecations
      
  1. 找到pomelo項目中的config/server.json. 内容如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
          
    {
      "development":{
        "connector": [
        {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true}
        ]
      },
      "production":{
        "connector": [
        {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true}
        ]
      }
    }
          

因為pomelo每一個伺服器都是一個程序,是以調試的時候隻能選擇其中一個進行調試。雖然比較蛋疼,但是用習慣了還是好的。

pomelo在啟動伺服器的時候會将這些參數傳遞給Node…應該是這樣的,嗯,應該是…

修改 “connector”伺服器的配置,添加調試參數:

1
      
"args": " --inspect=127.0.0.1:16772"
      

是以如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
      
{
  "development":{
    "connector": [
    {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true, "args": " --inspect=127.0.0.1:16772"}
    ]
  },
  "production":{
    "connector": [
    {"id": "connector-server-1", "host": "127.0.0.1", "port": 3150, "clientHost": "127.0.0.1", "clientPort": 3010, "frontend": true}
    ]
  }
}
      

這個表示我們隊伺服器connector開啟了遠端調試功能。

  1. 然後配置VSCode調試參數:

    如圖所示:

    pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構
    先選擇側邊欄的調試按鈕,然後選擇上方的配置按鈕,在彈出的面闆中選擇Node.js, 添加launch.json
    pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構
    修改配置如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
          
    {
        // 使用 IntelliSense 了解相關屬性。 
        // 懸停以檢視現有屬性的描述。
        // 欲了解更多資訊,請通路: https://go.microsoft.com/fwlink/?linkid=830387
        "version": "0.2.0",
        "configurations": [
            {
                "type": "node", // 調試的類型
                "name": "pomelo remote", // 名稱
                "port": 16772, // 監聽的端口(配置在server.json中的調試端口)
                "sourceMaps": true, // 開啟源映射
                "outFiles": [ // js腳本目錄
                    "${workspaceRoot}/app",
                ],
                
                "request": "attach", // 請求配置的類型,啟動或者附加,我們用的是附加
            }
        ]
    }
          

OK, 配置完成儲存,然後開始開開心心的測試一下。

  1. 測試:

    a. 啟動game-server

    1
    2
    3
    4
    5
    6
          
    $ pomelo start
    # ....
    Debugger listening on ws://127.0.0.1:16772/202b2f5e-3671-4fce-aca9-d2cdf175bc69
    For help see https://nodejs.org/en/docs/inspector
    # ...
    [2018-06-22 01:01:19.776] [INFO] pomelo - [E:pomeloTestgame-servernode_modulespomelolibmasterwatchdog.js] all servers startup in 884 ms
          

如果終端輸出

Debugger listening on ws://127.0.0.1:16772/202b2f5e-3671-4fce-aca9-d2cdf175bc69

For help see https://nodejs.org/en/docs/inspector

表示已經成功的啟動了監聽。

b. 打開前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      
Windows PowerShell
版權所有 (C) Microsoft Corporation。保留所有權利。

PS E:pomeloTestgame-server> cd ..
PS E:pomeloTest> cd .web-server
PS E:pomeloTestweb-server> node app
Warning: express.createServer() is deprecated, express
applications no longer inherit from http.Server,
please use:

  var express = require("express");
  var app = express();

connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Web server has started.
Please log on http://127.0.0.1:3001/index.html
      

c. 按F5啟動調試;

在如圖的位置添加斷點(app_types/servers/handler/entryHandler.ts)

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

啟動前端:http://127.0.0.1:3001/index.html

點選“Test Game Server”

這時候可以看到VSCode中的斷點已命中的效果:

pomelo + vscode + typescript搭建可限制可調試的遊戲服務端架構

恭喜你,說明你成功了。

注意事項

如果沒有命中斷點,請對着教程中的步驟檢查下流程,看看哪裡有不一樣的地方,或者下方留言問題。

注意一下幾個地方:

  1. tsconfig.json配置檔案中的“outDir”和launch.json中的 “outFiles”中的路徑請保持一緻。
  2. tsconfig.json配置中需要添加“sourceMap”,這是為了在生成時添加.map檔案,以至于調試的時候能通過js查找到對應的ts代碼。
  3. launch.json配置中添加“sourceMaps”和“outFiles”将調試的js腳本定位到js的生成目錄,以便于映射到對應的ts代碼。
  4. launch.json配置中的端口請和server.json配置中的端口保持一緻。

gitHub:

項目git:https://github.com/Visow/pomelo-game-server-demo

PS: 擷取完之後需要執行 “npm-install.bat”