ミニプログラムは間違いなく今年のインターネットの主要なホットスポットです。この実験では、HTTPS展開、セッションサービス、WebSocketサービスなど、NodeJSに基づく小さなプログラムの操作をサポートできるサービスをゼロから構築します。最後に、これらのサービスを使用して、リアルタイムのロックペーパーシザーズゲームを実装します。
タスクの概要
1 st
ドメイン名と証明書を準備する
時間:20分〜40分
2 nd
[小規模プログラム開発](https://cloud.tencent.com/solution/la?from=10680)環境をセットアップします
時間:15分〜30分
3 rd
HTTPサービスを構築する
時間:15分〜30分
4 th
HTTPSサービスを設定する
時間:15分〜30分
5 th
ミニプログラムセッション
時間:45分〜90分
6 th
WebSocketサービス
時間:45分〜90分
7 th
ロックペーパーシザーズゲーム
時間:45分〜90分
作業時間:20分〜40分
アップルトバックグラウンドサービスにはHTTPS経由でアクセスする必要があります。実験を開始する前に、ドメイン名と[SSL証明書](https://cloud.tencent.com/product/symantecssl?from=10680)を準備する必要があります。
ドメイン名をまだお持ちでない場合は、[Shop on Tencent Cloud](https://dnspod.qcloud.com/?fromSource=lab)をご利用いただけます。プロセスについては、以下の動画をご覧ください。
ドメイン名を購入した後、ドメイン名を実験用クラウドホストに解決する必要があります。実験用クラウドホストのIPは次のとおりです。
< CVMIPアドレス>
Tencent Cloudで購入したドメイン名については、コンソールに解像度レコードを追加できます。プロセスについては、次のビデオを参照してください。
ドメイン名の設定が解決されてから有効になるまでしばらく時間がかかります。ping
コマンドを使用して、ドメイン名が有効かどうかを確認します[?]。
ping www.yourmpdomain.com
pingコマンドによって返される情報に、設定した解決済みのIPアドレスが含まれている場合、解決は成功しています。
次のコマンドの
www.yourmpdomain.com
を自分の登録済みドメイン名として置き換えるように注意してください
Tencent CloudはSSL証明書の無料申請を提供しています。申請方法については、次のビデオを参照してください。
申請書の提出後、承認結果はSMSで通知されます。承認後、* SSLコンソール*から証明書ファイルをダウンロードできます。次のビデオを参照してください。
作業時間:15分〜30分
アップルトサーバーの構築を開始する前に、クライアントアップルト開発環境を完了する必要があります。
ミニプログラム開発者でない場合は、WeChatパブリックプラットフォームに登録してください。
https://mp.weixin.qq.com
特定の登録プロセスは、次のビデオを参照できます。
すでに登録されている場合は、[次へ]をクリックします。
WeChatパブリックプラットフォームにログインした後、「設定」-「開発設定」-「サーバードメイン名」-「変更」に移動します。
コードをスキャンして本人確認を完了した後、リクエストのリーガルドメイン名とソケットのリーガルドメイン名の両方に、前の手順で準備したドメインアドレスが入力されます。
設定が完了したら、[保存して送信]をクリックします。以下のビデオをクリックして、構成方法を確認できます。
この実験をサポートする小さなプログラムコードを実行するには、次のリソースをダウンロードしてください。
ソースコードをダウンロードしたら、ローカルの作業ディレクトリに解凍してください。
開発ツールをダウンロードしたら、インストールして起動し、WeChatを使用してコードをスキャンしてログインしてください。
ログイン後、「ローカルミニプログラムプロジェクト」-「プロジェクトの追加」を選択し、次の設定を使用します。
app.js
が含まれています)入力後、「アイテムの追加」をクリックします。特定の操作は、次のビデオで見ることができます。
開発ツールの「編集」パネルで、編集する「app.js」を選択します。アップルト通信ドメイン名[?]を変更する必要があります。次の構成を参照してください。
App({
config:{
host:''//ここにドメイン名を入力してください},onLaunch(){
console.log('App.onLaunch()');}});
もちろん、このステップでは、対応するビデオも記録されました。
実験のソースコードで使用されている通信ドメイン名はこの設定を使用します。スムーズな実験のために、ドメイン名を前の手順で準備したドメイン名に変更してください。
作業時間:15分〜30分
次の手順では、サーバー上でNodeとExpressを使用してHTTPサーバーを構築します。
次のコマンドを使用して、NodeJSとNPMをインストールします
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
yum install nodejs -y
インストールが完了したら、次のコマンドを使用してインストール結果をテストします
node -v
次のコマンドを使用して、サーバー上に作業ディレクトリを作成します。
mkdir -p /data/release/weapp
この作業ディレクトリを入力してください
cd /data/release/weapp
サンプルコード:/data/release/weapp/package.json
{" name":"weapp","version":"1.0.0"}
終了したら、 Ctrl + S
を使用してファイルを保存します
作業ディレクトリ*にapp.js *を作成し、Express.jsを使用して 8765
ポート[?]を監視します。以下のサンプルコードを参照してください。
サンプルコード:/data/release/weapp/app.js
//HTTPサーバーconstexpressの実装をサポートするためのquoteexpress=require('express');//エクスプレスインスタンスconstアプリを作成する=express();//ミドルウェアを1つだけ実装し、すべてのリクエストに出力します"Response from express"
app.use((request, response, next)=>{
response.write('Response from express');
response.end();});//リスニングポート、接続を待機constポート=8765;
app.listen(port);//サーバー起動ログを出力
console.log(`Server listening at http://127.0.0.1:${port}`);
この実験では、ポート8765の開口部を実験ステップの完了の基礎として使用します。後続の実験ステップをスムーズに進めるために、他のポート番号は使用しないでください。
始める前に、[PM2]をインストールしましょう
npm install pm2 --global
PM2のインストール時間は少し長くなる場合がありますので、しばらくお待ちください[?]
Expressモジュールはサーバーのソースコードで使用されています。次のコマンドはNPMを使用してExpressをインストールします
cd /data/release/weapp
npm install express --save
インストールが完了したら、PM2を使用してHTTPサービスを開始します
cd /data/release/weapp
pm2 start app.js
これで、HTTPサービスは[http:// <CVM IPアドレス>:8765](http://xn--%3C%20cvm%20ip%20%3E-yp49ackh32qjw5g:8765/)で実行されます。
サービスによって出力されたログを表示するには、次のコマンドを使用できます。
pm2 logs
サービスを再起動する場合は、次のコマンドを使用できます。
pm2 restart app
PM2を使用して、ノードプロセスを実行、監視、および管理します
中国のNPM倉庫のアクセス速度は理想的ではない可能性があります。速度が遅すぎる場合は、CNPMのレジストリを使用してインストールしてみてください:
npm install pm2 -g --registry = https:// r.cnpmjs.org /
作業時間:15分〜30分
WeChatアップルトでは、サーバーとの通信がHTTPSを介して行われる必要があります
CentOSでは、 yum
を直接使用してNginxをインストールできます
yum install nginx -y
インストールが完了したら、 nginx
コマンドを使用してNginxを起動します。
nginx
この時点で、[http:// <your domain name>](http://xn--%3C-t33er8oszphj1b/)にアクセスして、Nginxテストページを表示します[?]
アクセスできない場合は、
nginx -sreload
コマンドを再試行してNginxを再起動してください
外部ユーザーがサーバーにアクセスするためのWebサービスはNginxによって提供されます。Nginxは、Webサービスをローカルノードサービスに転送するようにリバースプロキシを構成する必要があります。
まず、以前にダウンロードしたSSL証明書(解凍後のNginxディレクトリのサフィックスとしてcrtとkeyを含むファイル)を左側のファイルブラウザ/ etc / nginxディレクトリにドラッグしてアップロードし、ファイルをサーバーにアップロードします。
Nginx構成ディレクトリは* / etc / nginx / conf.d にあり、このディレクトリに ssl.conf *を作成します。
サンプルコード:/etc/nginx/conf.d/ssl.conf
server {
listen 443;
server_name www.example.com; #バインディング証明書のドメイン名に変更します
# ssl構成
ssl on;
ssl_certificate 1_www.example.com_bundle.crt; #自分で取得したcrtファイルの名前を変更する
ssl_certificate_key 2_www.example.com.key; #自分で取得したキーファイルの名前を変更する
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location /{
proxy_pass http://127.0.0.1:8765;}}
Ctrl + S
を押して構成ファイルを保存し、Nginxに構成を再ロードさせて有効にします。
nginx -s reload
ブラウザでhttpsを介して解決したドメイン名にアクセスし、HTTPSが正常に開始されたかどうかをテストします
サポートするアップルレットを開き、[実験1:HTTPS]をクリックし、[リクエストの送信]をクリックしてアクセス結果をテストします。
サーバーが正常に応答した場合は、「次へ」をクリックします。
作業時間:45分〜90分
アップルレットはCookieの保存と追跡をサポートしていません。サーバーは、セッションレイヤーを単独で実装する必要があります。
Yumを使用して、[MongoDB]とそのクライアントコマンドラインツールをマシンにインストールします。
yum install mongodb-server mongodb -y
インストールが終了したら、次のコマンドを使用して、インストールされているバージョンを表示できます。
mongod --version
mongo --version
MongoDBは、JSON形式の構造化ドキュメントストレージとクエリをサポートするNoSQLデータベースであり、JavaScriptをフレンドリーにサポートしています。
MongoDBデータとログストレージ用のディレクトリを作成します。
mkdir -p /data/mongodb
mkdir -p /data/logs/mongodb
作成後、次のコマンドを使用してMongoDBを起動します。[?]
mongod --fork --dbpath /data/mongodb --logpath /data/logs/mongodb/weapp.log
次のコマンドを使用して、起動が成功したかどうかを確認できます[?]
netstat -ltp | grep 27017
MongoDBは、初めて起動するのに約1分かかる場合があります。しばらくお待ちください。
MongoDBは、デフォルトでポート27017の接続をリッスンします。次のコマンドは、現在ポート27017を占有しているプロセスを確認します。MongoDBプロセスの場合は、起動が成功したことを意味します。
ローカルのMongoDBサービスにログインします。
mongo
ログイン後、ユーザー weapp
[?]を作成します。
use weapp;
db.createUser({ user:'weapp', pwd:'weapp-dev', roles:['dbAdmin','readWrite']});
作成後、 exit
を使用してコマンドラインツールを終了します。
作成したユーザーとパスワードは、次のステップでデータベースに接続するために使用されます。別のユーザーまたはパスワードを使用する場合は、それを保持してください。
アップルレットのセッション機能を実現するには、[connect-mongo]と[wafer-node-session]をインストールする必要があります。
cd /data/release/weapp
npm install connect-mongo wafer-node-session --save
[ connect-mongo] [[https://github.com/jdesboeufs/connect-mongo](https://github.com/jdesboeufs/connect-mongo)]モジュールは、MongoDBに接続することにより、セッション用のストレージを提供します
[ ウェーハノードセッション] [[https://github.com/tencentyun/wafer-node-session](https://github.com/tencentyun/wafer-node-session)]は、TencentCloudが提供する独立したミニプログラムセッション管理ミドルウェアです。
作業ディレクトリ*に構成ファイルconfig.js *を作成して、サービス[?]で使用される構成を保存します。次の実装を参照してください(注:参照構成ファイルのYORU_APP_IDとYOUR_APP_SECRETを、申請した対応するアップルトに置き換えてくださいAppIDおよびAppSecret):
サンプルコード:/data/release/weapp/config.js
module.exports ={
serverPort:'8765',//AppletappIdおよびappSecret//httpsにアクセスしてください://mp.weixin.qq.comでAppIDとAppSecretを取得します
appId:'YORU_APP_ID',
appSecret:'YOUR_APP_SECRET',//Mongodb接続構成、実稼働環境ではより複雑なユーザー名とパスワードを使用してください
mongoHost:'127.0.0.1',
mongoPort:'27017',
mongoUser:'weapp',
mongoPass:'weapp-dev',
mongoDb:'weapp'};
サンプルコード:/data/release/weapp/app.js
//HTTPサーバーconstexpressの実装をサポートするためのquoteexpress=require('express');//ウェーハを引用-セッションはミニプログラムセッションをサポートしますconstwaferSession=require('wafer-node-session');//MongoDBをセッションストレージとして使用するconstMongoStore=require('connect-mongo')(waferSession);//構成ファイルconstconfigを導入します=require('./config');//エクスプレスインスタンスconstアプリを作成する=express();//セッションミドルウェアを追加します。ログインアドレスは/login
app.use(waferSession({
appId: config.appId,
appSecret: config.appSecret,
loginPath:'/login',
store:newMongoStore({
url:`mongodb://${config.mongoUser}:${config.mongoPass}@${config.mongoHost}:${config.mongoPort}/${config.mongoDb}`})}));//ルーティング中/私の下で、セッションに含まれるユーザー情報を出力します
app.use('/me',(request, response, next)=>{
response.json(request.session ? request.session.userInfo :{ noBody:true});if(request.session){
console.log(`Wafer session success with openId=${request.session.userInfo.openId}`);}});//未処理のリクエストをすべて出力するミドルウェアを実装する"Response from express"
app.use((request, response, next)=>{
response.write('Response from express');
response.end();});//リスニングポート、接続を待機中
app.listen(config.serverPort);//サーバー起動ログを出力
console.log(`Server listening at http://127.0.0.1:${config.serverPort}`);
ソースコードを記述したら、サービスを再起動します。
pm2 restart app
再起動後、一致するアップルトを使用してセッションテストを完了します。一致するアップルトを開きます-[実験2:会話]-[会話を取得]をクリックします。WeChatアバターが表示されている場合は、セッションが正常に取得されたことを意味します。
サービスがより複雑になると、構成を一元化して管理を容易にすることができます。たとえば、現在、保存する必要があるのは、サーバー実行ポート、アップルト構成、MongoDB接続構成です。
作業時間:45分〜90分
この実験では、 ws
モジュールを使用してサーバー上のWebSocketプロトコルをサポートし、以下ではNPMを使用してインストールします。
cd /data/release/weapp
npm install ws --save
サンプルコード:/data/release/weapp/websocket.js
//WebSocket constwsの実現をサポートするwsを導入します=require('ws');//エクスポート処理方法
exports.listen = listen;/**
* HTTPサーバーでWebSocketリクエストを処理する
* @ param {http.Server} server
* @ param {wafer.SessionMiddleware} sessionMiddleware
* /functionlisten(server, sessionMiddleware){//HTTPサーバーを使用してWebSocketサービスを作成し、pathパラメーターを使用してWebSocket constwssにアップグレードする必要があるパスを指定します=newws.Server({ server, path:'/ws'});//WebSocket接続の確立を監視する
wss.on('connection',(ws,request)=>{//WebSocketプロトコルにアップグレードするHTTP接続//WebSocketへのアップグレードのリクエストは、エクスプレスでは処理されません。//セッションsessionMiddlewareを取得するには、セッションミドルセクションを使用する必要があります(request,null,()=>{const session = request.session;if(!session){//セッションが取得されないため、WebSocket接続を強制的に切断します
ws.send(JSON.stringify(request.sessionError)||"No session avaliable");
ws.close();return;}//このログの出力を保持することで、ラボは現在のステップが完了したかどうかを確認できます。
console.log(`WebSocket client connected with openId=${session.userInfo.openId}`);serveMessage(ws, session.userInfo);});});//WebSocketサービスのリッスン中にエラーが発生しました
wss.on('error',(err)=>{
console.log(err);});}/**
* 簡単なWebSocketサービスを実行し、クライアントから送信されたすべてのメッセージに返信します
* /functionserveMessage(ws, userInfo){//クライアントからのメッセージを聞く
ws.on('message',(message)=>{
console.log(`WebSocket received: ${message}`);
ws.send(`Server: Received(${message})`);});//シャットダウンイベントをリッスンする
ws.on('close',(code, message)=>{
console.log(`WebSocket client closed (code: ${code}, message: ${message ||'none'})`);});//接続直後のセッションに対応するユーザーにhelloメッセージを送信します
ws.send(`Server:おめでとう、${userInfo.nickName}`);}
サンプルコード:/data/release/weapp/app.js
//HTTPモジュールはExpressとWebSocketconsthttpの両方をサポートします=require('http');//HTTPサーバーconstexpressの実装をサポートするためのquoteexpress=require('express');//ウェーハを引用-セッションはミニプログラムセッションをサポートしますconstwaferSession=require('wafer-node-session');//MongoDBをセッションストレージとして使用するconstMongoStore=require('connect-mongo')(waferSession);//構成ファイルconstconfigを導入します=require('./config');//constwebsocketを実装するためのWebSocketサービスを導入する=require('./websocket');//エクスプレスインスタンスconstアプリを作成する=express();//エクスプレスとWSにconstsessionMiddlewareを使用するための個別のセッションミドルウェア=waferSession({
appId: config.appId,
appSecret: config.appSecret,
loginPath:'/login',
store:newMongoStore({
url:`mongodb://${config.mongoUser}:${config.mongoPass}@${config.mongoHost}:${config.mongoPort}/${config.mongoDb}`})});
app.use(sessionMiddleware);//ルーティング中/私の下で、セッションに含まれるユーザー情報を出力します
app.use('/me',(request, response, next)=>{
response.json(request.session ? request.session.userInfo :{ noBody:true});if(request.session){
console.log(`Wafer session success with openId=${request.session.userInfo.openId}`);}});//未処理のリクエストをすべて出力するミドルウェアを実装する"Response from express"
app.use((request, response, next)=>{
response.write('Response from express');
response.end();});//Expressを直接使用してconstサーバーを監視する代わりに、HTTPサーバーを作成します= http.createServer(app);//作成したHTTPサーバーでWebSocketサービスをリッスンさせます
websocket.listen(server, sessionMiddleware);//HTTPサービスを開始します
server.listen(config.serverPort);//サーバー起動ログを出力
console.log(`Server listening at http://127.0.0.1:${config.serverPort}`);
変更が完了したら、 Ctrl + S
を押してファイルを保存し、サービスを再起動します。
pm2 restart app
サンプルコード:/etc/nginx/conf.d/ssl.conf
# WebSocket構成
map $http_upgrade $connection_upgrade {default upgrade;'' close;}
server {
listen 443;
server_name www.example.com; #バインディング証明書のドメイン名に変更します
# ssl構成
ssl on;
ssl_certificate 1_www.example.com.crt; #自分で取得したcrtファイルの名前を変更する
ssl_certificate_key 2_www.example.com.key; #自分で取得したキーファイルの名前を変更する
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# WebSocket構成
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
location /{
proxy_pass http://127.0.0.1:8765;}}
構成が完了したら、 Ctrl + S
を押して保存し、Nginxプロセスに構成を再ロードするように通知します。
nginx -s reload
サポートしている小さなプログラムを開き、「実験3:WebSocket」をクリックします。テストページに入った後、[接続]ボタンをクリックします。接続に成功したプロンプトが表示された場合は、WebSocketサービスが正常に実行されており、メッセージを送受信できることを意味します。
作業時間:45分〜90分
/ data / release / weapp / gameディレクトリを作成して、rock-paper-scissorsゲームのコードを保存します
mkdir -p /data/release/weapp/game
サンプルコード:/data/release/weapp/game/Room.js
/**
enum GameChoice {
//はさみ
Scissors = 1,
//結石
Rock = 2,
//布
Paper = 3
}
* /functionjudge(choice1, choice2){//結ぶ場合(choice1 == choice2)return0;//プレーヤー1は勝ちませんでした、プレーヤー2は勝ちます(!choice1)return1;//プレーヤー2が出てこなかった場合、プレーヤー1が勝ちます(!choice2)return-1;//すべてが終わったら、ただ戻ってください(choice1 - choice2 +3)%3==1?-1:1;}/** @type {Room[]} */const globalRoomList =[];//1部屋あたり最大2人constMAX_ROOT_MEMBER =2;//ゲーム時間、秒単位const GAME_TIME =3;let nextRoomId =0;/**部屋を表します*/
module.exports =classRoom{/**すべての部屋を取得*/staticall(){return globalRoomList.slice();}/**座席のある部屋を取得する*/staticfindRoomWithSeat(){return globalRoomList.find(x =>!x.isFull());}/**新しい部屋を作成する*/staticcreate(){const room =newRoom();
globalRoomList.unshift(room);return room;}constructor(){this.id =`room${nextRoomId++}`;this.players =[];}/**プレーヤーを追加する*/addPlayer(player){const{ uid, uname }= player.user;
console.log(`Player ${uid}(${uname}) enter ${this.id}`);this.players.push(player);if(this.isFull()){this.startGame();}}/**プレーヤーを削除する*/removePlayer(player){const{ uid, uname }= player.user;
console.log(`Player ${uid}(${uname}) leave ${this.id}`);const playerIndex =this.players.indexOf(player);if(playerIndex !=-1){this.players.splice(playerIndex,1);}if(this.players.length ===0){
console.log(`Room ${this.id} is empty now`);const roomIndex = globalRoomList.indexOf(this);if(roomIndex >-1){
globalRoomList.splice(roomIndex,1);}}}/**プレーヤーがいっぱい*/isFull(){returnthis.players.length == MAX_ROOT_MEMBER;}/**ゲームを始める*/startGame(){//このログ出力の行を保持することで、実験室は実験の完了を確認できます
console.log('game started!');//権限ポイントはこれをクリアします.players.forEach(player => player.gameData.roundScore =0);//プレーヤーユーザーとゲームデータを収集するconstプレーヤー=this.players.map(player => Object.assign({}, player.user, player.gameData));//開始するようにすべてのプレーヤーに通知します(let player ofthis.players){
player.send('start',{
gameTime: GAME_TIME,
players
});} //SetTimeout(()=>this.finishGame(), GAME_TIME *1000);}/**ゲーム終了*/finishGame(){const players =this.players;//ペアワイズ比較とスコア(let i =0; i < MAX_ROOT_MEMBER; i++){let p1 = players[i];if(!p1)break;for(let j = i +1; j < MAX_ROOT_MEMBER; j++){let p2 = players[j];const result =judge(p1.gameData.choice, p2.gameData.choice);
p1.gameData.roundScore -= result;
p2.gameData.roundScore += result;}}//連勝報酬を計算する(let player of players){const gameData = player.gameData;//勝ち点(gameData.roundScore >0){
gameData.winStreak++;
gameData.roundScore *= gameData.winStreak;}//elseifをクリア(gameData.roundScore <0){
gameData.roundScore =0;
gameData.winStreak =0;}//累積合計スコア
gameData.totalScore += gameData.roundScore;}//一定の結果= players.map(player =>{const{ uid }= player.user;const{ roundScore, totalScore, winStreak, choice }= player.gameData;return{ uid, roundScore, totalScore, winStreak, choice };});//のゲーム結果をすべてのプレーヤーに通知する(let player of players){
player.send('result',{ result });}}}
ゲーム開始、計算結果、ポイントなどのロジックを処理します。
サンプルコード:/data/release/weapp/game/Player.js
const Room =require("./Room");/**
* プレーヤーを表し、プレーヤーの一般的なゲームロジックを処理し、メッセージ処理部分には特定のプレーヤーの実装が必要です(ComputerPlayerとHumanPlayerを参照してください)。
* /
module.exports =classPlayer{constructor(user){this.id = user.uid;this.user = user;this.room =null;this.gameData ={//現在の選択(はさみ/結石/布)
choice:null,//ゲームポイント
roundScore:0,//合計点
totalScore:0,//縞
winStreak:0};}/**
* 現在のプレーヤーをオンラインにし、プレーヤーに割り当てられた部屋に非同期で戻ります
* /online(room){//プレイヤーの取り扱い'join'ニュース//プレーヤーが利用できる部屋を見つけて、これを非同期で返します.receive('join',()=>{if(this.room){this.room.removePlayer(this);}
room =this.room = room || Room.findRoomWithSeat()|| Room.create();
room.addPlayer(this);});//プレイヤーの取り扱い'choise'ニュース//プレーヤーの現在の選択を記録し、部屋の他のプレーヤーにこれを通知する必要があります.receive('choice',({ choice })=>{this.gameData.choice = choice;this.broadcast('movement',{
uid:this.user.uid,
movement:"choice"});});//プレイヤーの取り扱い'leave'ニュース//プレーヤーをオフラインにします.receive('leave',()=>this.offline);}/**
* 現在のプレーヤーをオフラインにして部屋を出る
* /offline(){if(this.room){this.room.removePlayer(this);this.room =null;}this.user =null;this.gameData =null;}/**
* 指定されたメッセージを現在のプレーヤーに送信します。これには特定のサブクラスの実装が必要です
* @ abstract
* @ param {string}メッセージメッセージタイプ
* @ param {*}データメッセージデータ
* /send(message, data){thrownewError('Not implement: AbstractPlayer.send()');}/**
* プレーヤーから送信されたメッセージの処理には、特定のサブクラスの実装が必要です
* @ abstract
* @ param {string}メッセージメッセージタイプ
* @ param {Function} handler
* /receive(message, handler){thrownewError('Not implement: AbstractPlayer.receive()');}/**
* プレーヤーがいる部屋の他のプレーヤーにメッセージを送信する
* @ param {string}メッセージメッセージタイプ
* @ param {any}データメッセージデータ
* /broadcast(message, data){if(!this.room)return;this.others().forEach(neighbor => neighbor.send(message, data));}/**
* プレーヤーがいる部屋に他のプレーヤーを配置する
* /others(){returnthis.room.players.filter(player => player !=this);}}
ゲームに参加し、パンチを選択し、他のプレーヤーに通知するプレーヤーのロジックを処理します
人間のプレイヤーを実現する前に、コンピュータープレイヤーを実現するための* ComputerPlayer.js *を作成しましょう[?]
サンプルコード:/data/release/weapp/game/ComputerPlayer.js
const EventEmitter =require('events');const Player =require('./Player');let nextComputerId =0;/**
* ロボットプレーヤーの実装、EventEmitterを使用してメッセージを送受信します
* /
module.exports =classComputerPlayerextendsPlayer{constructor(){const computerId =`robot-${++nextComputerId}`;super({
uid: computerId,
uname: computerId,
uavatar:'http://www.scoutiegirl.com/wp-content/uploads/2015/06/Blue-Robot.png'});this.emitter =newEventEmitter();}/**
* プレーヤーの動作をシミュレートする
* /simulate(){this.receive('start',()=>this.play());this.receive('result',()=>this.stop());this.send('join');}/**
* ゲーム開始後、ランダム時間後のランダム選択
* /play(){this.playing =true;constrandomTime=()=> Math.floor(100+ Math.random()*2000);constrandomChoice=()=>{if(!this.playing)return;this.send("choice",{
choice: Math.floor(Math.random()*10000)%3+1});setTimeout(randomChoice,randomTime());}setTimeout(randomChoice,10);}/**
* ゲームが終わったら、ランダムな選択が続行されないようにマークを付けます
* /stop(){this.playing =false;}/**
* 現在のプレーヤーにメッセージを送信し、エミッターに直接転送します
* /send(message, data){this.emitter.emit(message, data);}/**
* 現在のエミッタからのメッセージを処理する
* /receive(message, handle){this.emitter.on(message, handle);}}
ゲームロジックをテストするとき、他の誰も一緒に参加することはできません。コンピュータプレーヤーを実現することは良い選択です。
人間のプレーヤーはWebSocketチャネルを使用してプレーヤーの入力と出力を実現します[?]。人間のプレーヤーのロジックを実現するには、* game / Tunnel.js と game / HumanPlayer.js *を追加する必要があります。次のコードを参照してください。
サンプルコード:/data/release/weapp/game/Tunnel.js
const EventEmitter =require('events');/**
* WebSocketチャネルをカプセル化します
* /
module.exports =classTunnel{constructor(ws){this.emitter =newEventEmitter();this.ws = ws;
ws.on('message', packet =>{try{//各データパケットの形式は合意されています。{ message: 'type', data: any }const{ message, data }= JSON.parse(packet);this.emitter.emit(message, data);}catch(err){
console.log('unknown packet: '+ packet);}});}on(message, handle){this.emitter.on(message, handle);}emit(message, data){this.ws.send(JSON.stringify({ message, data }));}}
サンプルコード:/data/release/weapp/game/HumanPlayer.js
const co =require('co');const Player =require('./Player');const ComputerPlayer =require('./ComputerPlayer');const Tunnel =require('./Tunnel');/**
* 人間のプレイヤーによって実現され、WebSocketチャネルを介してメッセージを送受信します
* /
module.exports =classHumanPlayerextendsPlayer{constructor(user, ws){super(user);this.ws = ws;this.tunnel =newTunnel(ws);this.send('id', user);}/**
* 人間のプレーヤーがオンラインになった後、プレーヤーをオフラインにするには、監視チャネルを閉じる必要があります
* /online(room){super.online(room);this.ws.on('close',()=>this.offline());//人間のプレイヤーはコンピュータプレイヤーにこれを要求します.receive('requestComputer',()=>{const room =this.room;while(room &&!room.isFull()){const computer =newComputerPlayer();
computer.online(room);
computer.simulate();}});}/**
* オフライン後にチャンネルを閉じる
* /offline(){super.offline();if(this.ws &&this.ws.readyState ==this.ws.OPEN){this.ws.close();}this.ws =null;this.tunnel =null;if(this.room){//部屋のコンピュータープレーヤーをクリーンアップします(let player ofthis.room.players){if(player instanceofComputerPlayer){this.room.removePlayer(player);}}this.room =null;}}/**
* WebSocketチャネルを介してプレーヤーにメッセージを送信する
* /send(message, data){this.tunnel.emit(message, data);}/**
* WebSocketチャネルからプレーヤーメッセージを受信する
* /receive(message, callback){this.tunnel.on(message, callback);}}
ヒューマンプレーヤーとコンピュータープレーヤーのロジックは同じですが、IOが異なります。ヒューマンプレーヤーは以前に実装されたWebSocketサービスを入力と出力に使用し、コンピュータープレーヤーはEventEmiterを直接使用して処理します。
ゲームの実装が完了しました。次に、* websocket.js *を編集して、サービスエントリを追加します。次のコードを参照できます。
サンプルコード:/data/release/weapp/websocket.js
//URLconsturlを解析するためのurlモジュールを紹介します=require('url');//WebSocket constwsの実現をサポートするwsを導入します=require('ws');//人間のプレーヤーを紹介するconstHumanPlayer=require('./game/HumanPlayer');//エクスポート処理方法
exports.listen = listen;/**
* HTTPサーバーでWebSocketリクエストを処理する
* @ param {http.Server} server
* @ param {wafer.SessionMiddleware} sessionMiddleware
* /functionlisten(server, sessionMiddleware){//HTTPサーバーを使用してWebSocketサービスを作成し、pathパラメーターを使用してWebSocket constwssにアップグレードする必要があるパスを指定します=newws.Server({ server });//同時にサポート/wsと/ゲームのWebSocket接続要求
wss.shouldHandle=(request)=>{const path = url.parse(request.url).pathname;
request.path = path;return['/ws','/game'].indexOf(path)>-1;};//WebSocket接続の確立を監視する
wss.on('connection',(ws, request)=>{// request:WebSocketプロトコルにアップグレードするHTTP接続//WebSocketへのアップグレードのリクエストは、エクスプレスでは処理されません。//セッションsessionMiddlewareを取得するには、セッションミドルセクションを使用する必要があります(request,null,()=>{const session = request.session;if(!session){//セッションが取得されないため、WebSocket接続を強制的に切断します
ws.send(JSON.stringify(request.sessionError)||"No session avaliable");
ws.close();return;}
console.log(`WebSocket client connected with openId=${session.userInfo.openId}`);//要求されたアドレススイッチに応じて異なる処理(request.path){case'/ws':returnserveMessage(ws, session.userInfo);case'/game':returnserveGame(ws, session.userInfo);default:return ws.close();}});});//WebSocketサービスのリッスン中にエラーが発生しました
wss.on('error',(err)=>{
console.log(err);});}/**
* 簡単なWebSocketサービスを実行し、クライアントから送信されたすべてのメッセージに返信します
* /functionserveMessage(ws, userInfo){//クライアントからのメッセージを聞く
ws.on('message',(message)=>{
console.log(`WebSocket received: ${message}`);
ws.send(`Server: Received(${message})`);});//シャットダウンイベントをリッスンする
ws.on('close',(code, message)=>{
console.log(`WebSocket client closed (code: ${code}, message: ${message ||'none'})`);});//接続直後のセッションに対応するユーザーにhelloメッセージを送信します
ws.send(`Server:おめでとう、${userInfo.nickName}`);}/**
* ゲームサービスにWebSocketを使用する
* /functionserveGame(ws, userInfo){const user ={
uid: userInfo.openId,
uname: userInfo.nickName,
uavatar: userInfo.avatarUrl
}; //コンストプレイヤー=newHumanPlayer(user, ws);//オンラインプレーヤー
player.online();}
私たちのソースコードは、日常の管理にcoを使用しています。ゲームサービスを開始する前に、以下をインストールする必要があります。
cd /data/release/weapp
npm install co --save
ノードサービスを再起動します。
pm2 restart app
サポートするアップルレットを開き、「実験4-ロックペーパーシザーズゲーム」をクリックし、「開始」ボタンをクリックしてゲームを開始します。
おめでとう!アップルトサービスの実験内容がすべて完了しました。すでに実行されているサービスを維持し、アップルトの調査と調査を継続することを選択できます。マシンを維持することをお勧めします。
Recommended Posts