监控面板 (@colyseus/monitor
)
@colyseus/monitor
是一个方便的工具,允许您查看和检查服务器生成的当前房间列表。
特性
- 列出所有活动房间
- 强制安排一个特定的房间
- 检查一个特定的房间
- 查看房间的状态
- 为客户端发送/广播消息
- 强制断开客户端连接
安装
安装模块:
npm install --save @colyseus/monitor
将它包含在你的项目中:
// ... import { monitor } from "@colyseus/monitor"; // ... app.use("/colyseus", monitor());
使用密码限制访问面板
您可以使用 express
中间件在 monitor
路由上启用身份验证,例如 express-basic-middleware
:
npm install --save express-basic-auth
使用 express-basic-auth
创建用户和密码。
import basicAuth from "express-basic-auth"; const basicAuthMiddleware = basicAuth({ // list of users and passwords users: { "admin": "admin", }, // sends WWW-Authenticate header, which will prompt the user to fill // credentials in challenge: true }); app.use("/colyseus", basicAuthMiddleware, monitor());
设置自定义房间列表列
app.use("/colyseus", basicAuthMiddleware, monitor({ columns: [ 'roomId', 'name', 'clients', { metadata: "spectators" }, // display 'spectators' from metadata 'locked', 'elapsedTime' ] }));
如果未指定,则默认的房间列表列为:['roomId', 'name', 'clients', 'maxClients', 'locked', 'elapsedTime']
。
负载测试 / 压力测试 (@colyseus/loadtest
)
当您想对服务器进行实战测试并了解它在实时环境中的性能时,@colyseus/loadtest
工具非常有用。
安装
安装 @colyseus/loadtest
模块:
npm install --save-dev @colyseus/loadtest
用法
colyseus-loadtest
命令需要一些参数才能工作:
script
: 该工具将要使用的自定义脚本--endpoint
: 你服务器端点 (默认使用ws://localhost:2567
)--room
: 您要连接的房间名称--numClients
: 您想连接到room
的客户端数量。
示例
这是一个脚本文件示例。基于每个连接客户端的房间生命周期事件,您可以实现一个 "bot"
来与 room
交互。
// script.ts import { Room, Client } from "colyseus.js"; export function requestJoinOptions (this: Client, i: number) { return { requestNumber: i }; } export function onJoin(this: Room) { console.log(this.sessionId, "joined."); this.onMessage("*", (type, message) => { console.log("onMessage:", type, message); }); } export function onLeave(this: Room) { console.log(this.sessionId, "left."); } export function onError(this: Room, err) { console.error(this.sessionId, "!! ERROR !!", err.message); } export function onStateChange(this: Room, state) { }
把 50 个客户端连接到一个 "battle"
房间
npx colyseus-loadtest script.ts --room battle --numClients 50 --endpoint ws://localhost:2567
认证 + 社交 (@colyseus/social
)
本节介绍 @colyseus/social
的配置和用法。
@colyseus/social
是一个实验性模块,提供通用后端服务,以加快您的多人游戏开发体验。该 API
公开征求建议和改进。
如果要实现自己的身份验证方法,请参见 Room » onAuth()
安装
- 下载和安装 MongoDB
- 安装
@colyseus/social
模块。
npm install @colyseus/social npm install express-jwt
Import
并expose
由@colyseus/social
提供的Express
路由。
import express from "express"; import socialRoutes from "@colyseus/social/express" const app = express(); app.use("/", socialRoutes); app.listen(8080);
const express = require("express"); const socialRoutes = require("@colyseus/social/express").default; const app = express(); app.use("/", socialRoutes); app.listen(8080);
服务器端配置
环境变量
MONGO_URI
: MongoDB 连接 URIJWT_SECRET
: 用于身份验证的安全 secret 字符串。FACEBOOK_APP_TOKEN
: Facebook App Token ("appid|appsecret"
)
服务器端 API
@colyseus/social
模块提供了 MongoDB
models 和 token
验证功能供您使用。
import { User, FriendRequest, verifyToken } from "@colyseus/social";
实现 onAuth
去检索当前用户
import { User, verifyToken } from "@colyseus/social"; class MyRoom extends Room { async onAuth(client, options) { // verify token authenticity const token = verifyToken(options.token); // query the user by its id return await User.findById(token._id); } onJoin(client, options, user) { console.log(user.username, "has joined the room!"); } }
Hooks
hooks.beforeAuthenticate
beforeAuthenticate
钩子在用户登录或注册之前被触发。
import { hooks } from "@colyseus/social"; hooks.beforeAuthenticate((provider, $setOnInsert, $set) => { // assign default metadata upon registration $setOnInsert.metadata = { coins: 100, trophies: 0 }; });
hooks.beforeUserUpdate
beforeUserUpdate
钩子在用户通过 save() 方法更新自己的信息之前被触发。
import Filter from "bad-words"; const filter = new Filter(); hooks.beforeUserUpdate((_id, fields) => { if (fields['username'] && filter.isProfane(fields['username'])) { throw new Error("no_swearing_allowed"); } })
客户端 API
登录
- Anonymous
- Email + Password
匿名
await client.auth.login();
Email + 密码
await client.auth.login({ email: "user@example.com", password: "12345" });
// // Make sure you have the Facebook SDK installed and configured first // - https://developers.facebook.com/docs/javascript/quickstart // - https://developers.facebook.com/docs/facebook-login/web // FB.login(function(response) { if (response.authResponse) { client.auth.login({ accessToken: response.authResponse.accessToken }); } }, { scope: 'public_profile,email,user_friends' });
更新用户数据
您可以从客户端修改 username
、displayName
、avatarUrl
、lang
、location
和 timezone
,然后调用 save()
方法。
client.auth.username = "Hello world!" await client.auth.save();
注销
client.auth.logout();
获取朋友列表
const friends = await client.auth.getFriends(); friends.forEach(friend => { console.log(friend.username); });
获取在线朋友列表
const friends = await client.auth.getOnlineFriends(); friends.forEach(friend => { console.log(friend.username); });
获取朋友请求的列表
const friends = await client.auth.getFriendRequests(); friends.forEach(friend => { console.log(friend.username); });
接受朋友的请求
await client.auth.acceptFriendRequest(friendId);
拒绝朋友请求
await client.auth.declineFriendRequest(friendId);
发送朋友请求
await client.auth.sendFriendRequest(friendId);
阻止用户
await client.auth.blockUser(friendId);
取消阻止用户
await client.auth.unblockUser(friendId);
调试
- Inspector (
--inspect
flag) - Debug 消息
Inspector
可以使用 Node.js
中的内置 inspector
来调试应用程序。
阅读更多关于 调试 Node.js 应用程序.
在生产环境中使用 inspector
在生产中使用 inspector 时要小心。使用内存快照和断点将直接影响用户的体验。
1. 连接到远程服务器:
ssh root@remote.example.com
2. 检查 Node 进程的 PID
ps aux | grep node
3. 将 inspector 附加到进程上
kill -usr1 PID
4. 创建一个从本地机器到远程 inspector 的 SSH tunnel
ssh -L 9229:localhost:9229 root@remote.example.com
您的生产服务器现在应该出现在 chrome://inspect
上。
Debug 消息
服务器提供了一些调试消息,您可以通过设置 DEBUG
环境变量来逐个启用这些消息。
要启用所有日志,可以使用以下命令运行服务器:
DEBUG=colyseus:* node server.js
请参阅下面所有可用的调试类别和示例输出。
colyseus:patch
记录向所有客户端广播补丁的字节数和时间间隔。
colyseus:patch "chat" (roomId: "ryWiL5rLTZ") is sending 28 bytes: +57ms
colyseus:errors
在服务器端发生意外(或内部预期)错误时记录日志。
colyseus:matchmaking
每当房间 spanwed
或 disposed
时都要记录。
colyseus:matchmaking spawning 'chat' on worker 77218 +52s colyseus:matchmaking disposing 'chat' on worker 77218 +2s
部署
- 部署在 Heroku
- 部署在 Nginx 上(推荐)
- 部署在 Apache
- 使用 greenlock-express
- Docker
Heroku
Heroku
仅用于原型设计。部署 colyseus-examples 项目:
https://heroku.com/deploy?template=https://github.com/colyseus/colyseus-examples
Nginx (推荐)
建议在生产环境中使用 pm2
和 nginx
。
PM2
在您的环境中安装 pm2
。
npm install -g pm2
然后使用它启动你的服务器:
pm2 start your-server.js
Nginx 配置
server { listen 80; server_name yourdomain.com; location / { proxy_pass http://localhost:2567; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } }
使用 SSL 配置 Nginx
建议从 LetsEncrypt 获取证书。
server { listen 80; listen 443 ssl; server_name yourdomain.com; ssl_certificate /path/to/your/cert.crt; ssl_certificate_key /path/to/your/cert.key; location / { proxy_pass http://localhost:2567; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } }
Apache
下面介绍如何使用 Apache
作为 Node.js Colyseus
应用程序的代理(Thanks tomkleine!)
安装所需的 Apache
模块:
sudo a2enmod ssl sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod proxy_html sudo a2enmod proxy_wstunnel
虚拟主机配置:
<VirtualHost *:80> ServerName servername.xyz # Redirect all requests received from port 80 to the HTTPS variant (force ssl) RewriteEngine On RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L] </VirtualHost> <VirtualHost *:443> ServerName servername.xyz # enable SSL SSLEngine On SSLCertificateFile /PATH/TO/CERT/FILE SSLCertificateKeyFile /PATH/TO/PRIVATE/KEY/FILE # # setup the proxy to forward websocket requests properly to a normal websocket # and vice versa, so there's no need to change the colyseus library or the # server for that matter) # # (note: this proxy automatically converts the secure websocket (wss) RewriteEngine On RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC,OR] RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC] RewriteRule .* ws://127.0.0.1:APP-PORT-HERE%{REQUEST_URI} [P,QSA,L] # setup the proxy to forward all https requests to http backend # (also automatic conversion from https to http and vice versa) ProxyPass "/" "http://localhost:APP-PORT-HERE/" ProxyPassReverse "/" "http://localhost:APP-PORT-HERE/" </VirtualHost>
greenlock-express
如果您希望在服务器上快速配置 SSL
,而不需要配置反向代理(reverse-proxy
),Greenlock
是一个很好的工具。
当使用 greenlock-express
时,你不应该在它背后配置任何反向代理,比如 Nginx 或 Apache。
npm install --save greenlock-express
请先遵循 greenlock-express 的 README 部分。
下面是处理开发环境(development
)和生产环境(production
)的推荐方法:
import http from "http"; import express from "express"; import { Server } from "colyseus"; function setup(app: express.Application, server: http.Server) { const gameServer = new Server({ server }); // TODO: configure `app` and `gameServer` accourding to your needs. // gameServer.define("room", YourRoom); return app; } if (process.env.NODE_ENV === "production") { require('greenlock-express') .init(function () { return { greenlock: require('./greenlock'), cluster: false }; }) .ready(function (glx) { const app = express(); // Serves on 80 and 443 // Get's SSL certificates magically! glx.serveApp(setup(app, glx.httpsServer(undefined, app))); }); } else { // development port const PORT = process.env.PORT || 2567; const app = express(); const server = http.createServer(app); setup(app, server); server.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`)); }
Docker
先决条件:
package.json
和package-lock.json
在项目中。- 设置
npm start
命令,使其启动服务器。
步骤:
Step 1 安装 Docker
Step 2 在 colyseus 项目的根目录中创建 Dockerfile
FROM node:12 ENV PORT 8080 WORKDIR /usr/src/app # A wildcard is used to ensure both package.json AND package-lock.json are copied COPY package*.json ./ RUN npm ci # run this for production # npm ci --only=production COPY . . EXPOSE 8080 CMD [ "npm", "start" ]
Step 3 在同一目录中创建 .dockerginore
文件
node_modules npm-debug.log
这将防止您的本地模块和调试日志被复制到您的 Docker 镜像中,并可能覆盖安装在镜像中的模块。
Step 4 进入 Dockerfile
所在的目录,运行以下命令构建 Docker
镜像。-t
flag 可以让你标记你的 image
,这样以后使用 docker images
命令更容易找到:
docker build -t <your username>/colyseus-server .
Step 5 你的 image
现在将由 Docker
用以下命令列出:
docker images
输出:
# Example REPOSITORY TAG ID CREATED node 12 1934b0b038d1 About a minute ago <your username>/colseus-server latest d64d3505b0d2 About a minute ago
Step 6 使用以下命令运行 Docker 镜像:
docker run -p 8080:8080 -d <your username>/colyseus-server
使用 -d
运行镜像将以 detached
模式运行容器,使容器在后台运行。-p flag
将公共端口重定向到容器内的私有端口。
Step 7 完成后,现在可以使用 localhost:8080
连接到服务器
更多信息:
- Official Node.js Docker Image
- Node.js Docker Best Practices Guide
高可用,可扩展
这个文档是一个正在进行的工作。
要将 Colyseus
扩展到多个进程或服务器,你需要有 Redis
、MongoDB
和一个动态代理(dynamic proxy
)。
Redis
下载并安装 Redis。使用 RedisPresence
:
import { Server, RedisPresence } from "colyseus"; const gameServer = new Server({ // ... presence: new RedisPresence(), });
const colyseus = require("colyseus"); const gameServer = new colyseus.Server({ // ... presence: new colyseus.RedisPresence(), });
presence
用于从一个进程到另一个进程调用房间 "seat reservation"
功能,并允许开发人员跨 rooms
利用一些数据共享功能。请参阅 Presence API。
每个 Colyseus
进程还将自己的 processId
和网络位置注册到 presence
API,稍后 dynamic proxy 服务将使用该 API
。在 graceful shutdown
期间,进程注销自己。
MongoDB
下载并安装 MongoDB。安装 mongoose
软件包:
npm install --save mongoose
使用 MongooseDriver
:
import { Server, RedisPresence } from "colyseus"; import { MongooseDriver } from "colyseus/lib/matchmaker/drivers/MongooseDriver" const gameServer = new Server({ // ... driver: new MongooseDriver(), });
const colyseus = require("colyseus"); const MongooseDriver = require("colyseus/lib/matchmaker/drivers/MongooseDriver").MongooseDriver; const gameServer = new colyseus.Server({ // ... driver: new MongooseDriver(), });
您可以将 MongoDB
连接 URI
传递给 new MongooseDriver(uri)
构造函数,或者设置 MONGO_URI
环境变量。
driver
用于存储和查询可用于 matchmaking
的 rooms
。
运行多个 Colyseus 进程
要在同一台服务器上运行多个 Colyseus
实例,需要每个实例监听不同的端口号。建议使用 3001
、3002
、3003
等端口。Colyseus 进程不应公开。只有 dynamic proxy
是。
强烈推荐使用PM2进程管理器来管理多个 Node.js
应用程序实例。
PM2 提供了一个 NODE_APP_INSTANCE
环境变量,其中包含每个进程的不同编号。使用它来定义端口号。
import { Server } from "colyseus"; // binds each instance of the server on a different port. const PORT = Number(process.env.PORT) + Number(process.env.NODE_APP_INSTANCE); const gameServer = new Server({ /* ... */ }) gameServer.listen(PORT); console.log("Listening on", PORT);
npm install -g pm2
使用以下 ecosystem.config.js
配置:
// ecosystem.config.js const os = require('os'); module.exports = { apps: [{ port : 3000, name : "colyseus", script : "lib/index.js", // your entrypoint file watch : true, // optional instances : os.cpus().length, exec_mode : 'fork', // IMPORTANT: do not use cluster mode. env: { DEBUG: "colyseus:errors", NODE_ENV: "production", } }] }
现在你已经准备好开始多个 Colyseus
进程了。
pm2 start
"PM2 和 TypeScript":建议在运行 pm2 start
之前通过 npx tsc
编译 .ts
文件。或者,你可以为 PM2
安装TypeScript
解释器(pm2 install typescript
),并设置 exec_interpreter: "ts-node"
(read more)。
动态代理
@colyseus/proxy 是一个动态代理,它会自动监听 Colyseus
进程的上下变化,允许 WebSocket
连接到创建了房间的正确进程和服务器上。
代理应该绑定到端口 80
/443
,因为它是应用程序惟一的公共端点。所有请求都必须通过代理。
npm install -g @colyseus/proxy
环境变量
配置以下环境变量以满足您的需求:
PORT
是代理将运行的端口。REDIS_URL
是你在Colyseus
进程中使用的同一个Redis
实例的路径。
运行代理
colyseus-proxy > {"name":"redbird","hostname":"Endels-MacBook-Air.local","pid":33390,"level":