CentOSに基づいてWeChatアップルトサービスを構築する

ミニプログラムは間違いなく今年のインターネットの主要なホットスポットです。この実験では、HTTPS展開、セッションサービス、WebSocketサービスなど、NodeJSに基づく小さなプログラムの操作をサポートできるサービスをゼロから構築します。最後に、これらのサービスを使用して、リアルタイムのロックペーパーシザーズゲームを実装します。

タスクの概要

ドメイン名と証明書を準備する##

作業時間:20分〜40分

アップルトバックグラウンドサービスにはHTTPS経由でアクセスする必要があります。実験を開始する前に、ドメイン名と[SSL証明書](https://cloud.tencent.com/product/symantecssl?from=10680)を準備する必要があります。

ドメイン登録###

ドメイン名をまだお持ちでない場合は、[Shop on Tencent Cloud](https://dnspod.qcloud.com/?fromSource=lab)をご利用いただけます。プロセスについては、以下の動画をご覧ください。

[ ドメイン名の解決](https://cloud.tencent.com/product/cns?from=10680)###

ドメイン名を購入した後、ドメイン名を実験用クラウドホストに解決する必要があります。実験用クラウドホストのIPは次のとおりです。

< CVMIPアドレス>

Tencent Cloudで購入したドメイン名については、コンソールに解像度レコードを追加できます。プロセスについては、次のビデオを参照してください。

ドメイン名の設定が解決されてから有効になるまでしばらく時間がかかります。pingコマンドを使用して、ドメイン名が有効かどうかを確認します[?]。

ping www.yourmpdomain.com

pingコマンドによって返される情報に、設定した解決済みのIPアドレスが含まれている場合、解決は成功しています。

次のコマンドの www.yourmpdomain.comを自分の登録済みドメイン名として置き換えるように注意してください

SSL証明書を申請する###

Tencent CloudはSSL証明書の無料申請を提供しています。申請方法については、次のビデオを参照してください。

申請書の提出後、承認結果はSMSで通知されます。承認後、* SSLコンソール*から証明書ファイルをダウンロードできます。次のビデオを参照してください。

小さなプログラム開発環境を構築する##

作業時間:15分〜30分

アップルトサーバーの構築を開始する前に、クライアントアップルト開発環境を完了する必要があります。

開発者アカウントを登録する###

ミニプログラム開発者でない場合は、WeChatパブリックプラットフォームに登録してください。

https://mp.weixin.qq.com

特定の登録プロセスは、次のビデオを参照できます。

すでに登録されている場合は、[次へ]をクリックします。

ミニプログラムサーバー情報の構成###

WeChatパブリックプラットフォームにログインした後、「設定」-「開発設定」-「サーバードメイン名」-「変更」に移動します。

コードをスキャンして本人確認を完了した後、リクエストのリーガルドメイン名とソケットのリーガルドメイン名の両方に、前の手順で準備したドメインアドレスが入力されます。

設定が完了したら、[保存して送信]をクリックします。以下のビデオをクリックして、構成方法を確認できます。

サポートする小さなプログラムコード###を実行します

この実験をサポートする小さなプログラムコードを実行するには、次のリソースをダウンロードしてください。

ソースコードをダウンロードしたら、ローカルの作業ディレクトリに解凍してください。

開発ツールをダウンロードしたら、インストールして起動し、WeChatを使用してコードをスキャンしてログインしてください。

ログイン後、「ローカルミニプログラムプロジェクト」-「プロジェクトの追加」を選択し、次の設定を使用します。

入力後、「アイテムの追加」をクリックします。特定の操作は、次のビデオで見ることができます。

実験ドメインを設定する###

開発ツールの「編集」パネルで、編集する「app.js」を選択します。アップルト通信ドメイン名[?]を変更する必要があります。次の構成を参照してください。

App({
 config:{
  host:''//ここにドメイン名を入力してください},onLaunch(){
  console.log('App.onLaunch()');}});

もちろん、このステップでは、対応するビデオも記録されました。

実験のソースコードで使用されている通信ドメイン名はこの設定を使用します。スムーズな実験のために、ドメイン名を前の手順で準備したドメイン名に変更してください。

HTTPサービスの設定##

作業時間:15分〜30分

次の手順では、サーバー上でNodeとExpressを使用してHTTPサーバーを構築します。

NodeJSとNPMをインストールします###

次のコマンドを使用して、NodeJSとNPMをインストールします

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
yum install nodejs -y

インストールが完了したら、次のコマンドを使用してインストール結果をテストします

node -v

HTTPサーバーのソースコードを書く###

作業ディレクトリを作成します####

次のコマンドを使用して、サーバー上に作業ディレクトリを作成します。

mkdir -p /data/release/weapp

この作業ディレクトリを入力してください

cd /data/release/weapp

package.json ####を作成します

サンプルコード:/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の開口部を実験ステップの完了の基礎として使用します。後続の実験ステップをスムーズに進めるために、他のポート番号は使用しないでください。

HTTPサービスを実行する###

PM2をインストールします####

始める前に、[PM2]をインストールしましょう

npm install pm2 --global

PM2のインストール時間は少し長くなる場合がありますので、しばらくお待ちください[?]

Express ####をインストールします

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 /

HTTPSサービスを設定します##

作業時間:15分〜30分

WeChatアップルトでは、サーバーとの通信がHTTPSを介して行われる必要があります

Nginx ###をインストールします

CentOSでは、 yumを直接使用してNginxをインストールできます

yum install nginx -y

インストールが完了したら、 nginxコマンドを使用してNginxを起動します。

nginx

この時点で、[http:// <your domain name>](http://xn--%3C-t33er8oszphj1b/)にアクセスして、Nginxテストページを表示します[?]

アクセスできない場合は、 nginx -sreloadコマンドを再試行してNginxを再起動してください

HTTPSリバースプロキシを構成します###

外部ユーザーがサーバーにアクセスするための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が正常に開始されたかどうかをテストします

アップルでHTTPSアクセスをテストします###

サポートするアップルレットを開き、[実験1:HTTPS]をクリックし、[リクエストの送信]をクリックしてアクセス結果をテストします。

サーバーが正常に応答した場合は、「次へ」をクリックします。

ミニプログラムセッション##

作業時間:45分〜90分

アップルレットはCookieの保存と追跡をサポートしていません。サーバーは、セッションレイヤーを単独で実装する必要があります。

MongoDBをインストールします###

Yumを使用して、[MongoDB]とそのクライアントコマンドラインツールをマシンにインストールします。

yum install mongodb-server mongodb -y

インストールが終了したら、次のコマンドを使用して、インストールされているバージョンを表示できます。

mongod --version
mongo --version

MongoDBは、JSON形式の構造化ドキュメントストレージとクエリをサポートするNoSQLデータベースであり、JavaScriptをフレンドリーにサポートしています。

MongoDBを起動します###

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ユーザーを追加する###

ローカルの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接続構成です。

WebSocketサービス##

作業時間:45分〜90分

ノードモジュールのインストール###

この実験では、 wsモジュールを使用してサーバー上のWebSocketプロトコルをサポートし、以下ではNPMを使用してインストールします。

cd /data/release/weapp
npm install ws --save

WebSocketサーバーを実装する###

サンプルコード:/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

Nginxプロキシを更新します###

サンプルコード:/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

WebSocketをテストする###

サポートしている小さなプログラムを開き、「実験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モジュールをインストールする###

私たちのソースコードは、日常の管理にcoを使用しています。ゲームサービスを開始する前に、以下をインストールする必要があります。

cd /data/release/weapp
npm install co --save

テストゲームサービス###

ノードサービスを再起動します。

pm2 restart app

サポートするアップルレットを開き、「実験4-ロックペーパーシザーズゲーム」をクリックし、「開始」ボタンをクリックしてゲームを開始します。

完了した実験###

おめでとう!アップルトサービスの実験内容がすべて完了しました。すでに実行されているサービスを維持し、アップルトの調査と調査を継続することを選択できます。マシンを維持することをお勧めします。

Recommended Posts

CentOSに基づいてWeChatアップルトサービスを構築する
CentOSに基づいてWeChatアップルトサービスを構築する
dockerに基づいてElasticsearch6.2.4(centos)を構築する
CentOSに基づいてDiscuzフォーラムを構築する
centos7でk8s1.9.9をビルドする
ジェンキンスはセントスに基づいて構築されています
Centos7ビルドDNSサービス
Centos 7(仮想ホストを含む)に基づいてNginxを構築する
CentOs7.3ビルドSolrスタンドアロンサービス
CentOs7.3ビルドRabbitMQ3.6スタンドアロンサービス
CentOSでMariaDBレプリケーションを構築する
CentOs7.3ビルドZooKeeper-3.4.9スタンドアロンサービス
CentOS7に基づくZabbix3.4をインストールします
CentOs7.3ビルドSolrCloudクラスターサービス
一般的なLinux操作(centos7に基づく)
LinuxでNginx環境を構築する(CentOS)
ubuntuに基づいてDiscuzフォーラムを構築する
CentOS7に基づいてNginxリバースプロキシを構成する
CentOS7に基づいてNginxロードバランシングを構成する
CentOS7に基づいてNginxフォワードプロキシを構成する
ubuntu16.04でnfsサービスを構築する方法
CentOS7ビルドFastDFS分散ファイルシステム(オン)
CentOS7ビルドジェリットコードレビューサービスメソッド
jira7.8レポートサービスはcentos7.4システムでは利用できません
クラウドサーバーはCentOSに基づいてDiscuzフォーラムを構築します
CentOS7に基づいて自動的に起動するようにNginxを構成します
CentOS7ビルドジェンキンス
Centosビルドlnmp
Centos7ビルドpython3.8.5 + scrapy + gerapy
centos7.2でLAMP環境を構築する方法
Centosサーバーでgiteaをセットアップする方法を教える3分
CentOS7.3 64ビット、ビルドZabbix3.4
Centos7にDockerをインストールする
CentOSビルドプライベートgit
CentOS8はNTPサービスを有効にします
Centos7.4はLNMPをインストールします
Linux(centos7)ビルドgitlab
Centos7にJavaをインストールする
centos7でのXfs構成
CentOS6.7ビルドLNMP環境
CentOS6でOcservを構成する
Centos6.9ビルドrabbitmq3.6.8クラスター
CentOS7はDockerサービスをインストールします
Nodejsはcentos7にインストールされます
CentOS8にFFmpegをインストールします
Centos7.6ビルドLNMP環境
CentOS7にRabbitMQをインストールします
CentOS7はRabbitMQサービスを展開します
CentosにNode.jsをインストールします
CentOS7はsaltstackサービスを展開します
Centos7ビルドKubernetesクラスター
Mavenはcentos7にインストールします
CentOS7にMongoDBをインストールします
CentOS8にSurelogをインストールする
CentOSでHadoopを構築する
CentOS7はNFSサービスを展開します
centos7にvuepressをデプロイする
centos7へのOpenjdkのインストール
Jenkinsをcentos7にインストールします
CentOS7でRapidSVNを使用する
Centos6.8はvncサービスを展開します