master 82350787426f cached
15 files
11.8 KB
3.8k tokens
5 symbols
1 requests
Download .txt
Repository: tencentyun/wafer-node-server-demo
Branch: master
Commit: 82350787426f
Files: 15
Total size: 11.8 KB

Directory structure:
gitextract_c013j9pl/

├── .gitignore
├── LICENSE
├── README.md
├── app.js
├── business/
│   └── chat-tunnel-handler.js
├── config.js
├── globals.js
├── package.json
├── process.json
├── routes/
│   ├── index.js
│   ├── login.js
│   ├── tunnel.js
│   ├── user.js
│   └── welcome.js
└── setup-qcloud-sdk.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules/
npm-debug.log
sftp-config.json

================================================
FILE: LICENSE
================================================
LICENSE - "MIT License"

Copyright (c) 2016 by Tencent Cloud

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README.md
================================================
# Wafer 服务端 Demo - Node.js

本项目是 [腾讯云微信小程序服务端 SDK - Node.js](https://github.com/tencentyun/wafer-node-server-sdk) 的使用示例。示例需要和 [微信小程序客户端示例](https://github.com/tencentyun/wafer-client-demo) 配合一起使用。

## 运行示例

按照[小程序创建资源配置指引](https://github.com/tencentyun/weapp-doc)进行操作,可以得到运行本示例所需的资源和服务,其中包括已部署好的示例代码及自动下发的 SDK 配置文件 `/etc/qcloud/sdk.config`。

- 示例代码部署目录:`/data/release/node-weapp-demo`
- 运行示例的 Node 版本:`v4.6.0`
- Node 进程管理工具:`pm2`

## 项目结构

```
Demo
├── README.md
├── app.js
├── business
│   └── chat-tunnel-handler.js
├── config.js
├── globals.js
├── package.json
├── process.json
├── routes
│   ├── index.js
│   ├── welcome.js
│   ├── login.js
│   ├── user.js
│   └── tunnel.js
└── setup-qcloud-sdk.js
```

其中,`app.js` 是 启动文件,`config.js` 配置了启动服务监听的端口号,`process.json` 是运行本示例 的 `pm2` 配置文件。

`setup-qcloud-sdk.js` 用于初始化 SDK 配置,配置从文件 `/etc/qcloud/sdk.config` 中读取。 配置文件包含如下配置项:

```json
{
    "serverHost": "业务服务器的主机名",
    "authServerUrl": "鉴权服务器地址",
    "tunnelServerUrl": "信道服务器地址",
    "tunnelSignatureKey": "和信道服务器通信的签名密钥"
}
```

`routes/` 目录包含了示例用到的4个路由,路由和处理文件映射关系如下:

```
// 首页指引
/ => routes/welcome.js

// 登录
/login => routes/login.js

// 获取微信用户信息
/user => routes/user.js

// 处理信道请求
/tunnel => routes/tunnel.js
```

`business/chat-tunnel-handler.js` 是业务处理信道请求的示例代码。

## 如何在demo基础上进行开发
进入目录 `/data/release/node-weapp-demo`,将写好的代码上传到routes目录下

重启服务:  pm2 restart all


## 更新 SDK 版本

进入目录 `/data/release/node-weapp-demo`,然后先后执行命令 `npm update`、`pm2 restart process.json` 即可。


================================================
FILE: app.js
================================================
'use strict';

require('./globals');
require('./setup-qcloud-sdk');

const http = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const config = require('./config');

const app = express();

app.set('query parser', 'simple');
app.set('case sensitive routing', true);
app.set('jsonp callback name', 'callback');
app.set('strict routing', true);
app.set('trust proxy', true);

app.disable('x-powered-by');

// 记录请求日志
app.use(morgan('tiny'));

// parse `application/x-www-form-urlencoded`
app.use(bodyParser.urlencoded({ extended: true }));

// parse `application/json`
app.use(bodyParser.json());

app.use('/', require('./routes'));

// 打印异常日志
process.on('uncaughtException', error => {
    console.log(error);
});

// 启动server
http.createServer(app).listen(config.port, () => {
    console.log('Express server listening on port: %s', config.port);
});


================================================
FILE: business/chat-tunnel-handler.js
================================================
'use strict';

const TunnelService = require('qcloud-weapp-server-sdk').TunnelService;

/**
 * 调用 TunnelService.broadcast() 进行广播
 * @param  {String} type    消息类型
 * @param  {String} content 消息内容
 */
const $broadcast = (type, content) => {
    TunnelService.broadcast(connectedTunnelIds, type, content)
        .then(result => {
            let invalidTunnelIds = result.data && result.data.invalidTunnelIds || [];

            if (invalidTunnelIds.length) {
                debug('检测到无效的信道 IDs =>', invalidTunnelIds);

                // 从`userMap`和`connectedTunnelIds`中将无效的信道记录移除
                invalidTunnelIds.forEach(tunnelId => {
                    delete userMap[tunnelId];

                    let index = connectedTunnelIds.indexOf(tunnelId);
                    if (~index) {
                        connectedTunnelIds.splice(index, 1);
                    }
                });
            }
        });
};

/**
 * 调用 TunnelService.closeTunnel() 关闭信道
 * @param  {String} tunnelId 信道ID
 */
const $close = (tunnelId) => {
    TunnelService.closeTunnel(tunnelId);
};

// 保存 WebSocket 信道对应的用户
// 在实际的业务中,应该使用数据库进行存储跟踪,这里作为示例只是演示其作用
let userMap = {};

// 保存 当前已连接的 WebSocket 信道ID列表
let connectedTunnelIds = [];

/**
 * 实现 WebSocket 信道处理器
 * 本示例配合客户端 Demo 实现一个简单的聊天室功能
 */
class ChatTunnelHandler {
    /**
     * 实现 onRequest 方法
     * 在客户端请求 WebSocket 信道连接之后,
     * 会调用 onRequest 方法,此时可以把信道 ID 和用户信息关联起来
     */
    onRequest(tunnelId, userInfo) {
        debug(`${this.constructor.name} [onRequest] =>`, { tunnelId, userInfo });

        if (typeof userInfo === 'object') {
            // 保存 信道ID => 用户信息 的映射
            userMap[tunnelId] = userInfo;
        }
    }

    /**
     * 实现 onConnect 方法
     * 在客户端成功连接 WebSocket 信道服务之后会调用该方法,
     * 此时通知所有其它在线的用户当前总人数以及刚加入的用户是谁
     */
    onConnect(tunnelId) {
        debug(`${this.constructor.name} [onConnect] =>`, { tunnelId });

        if (tunnelId in userMap) {
            connectedTunnelIds.push(tunnelId);

            $broadcast('people', {
                'total': connectedTunnelIds.length,
                'enter': userMap[tunnelId],
            });
        } else {
            debug(`Unknown tunnelId(${tunnelId}) was connectd, close it`);
            $close(tunnelId);
        }
    }

    /**
     * 实现 onMessage 方法
     * 客户端推送消息到 WebSocket 信道服务器上后,会调用该方法,此时可以处理信道的消息。
     * 在本示例,我们处理 `speak` 类型的消息,该消息表示有用户发言。
     * 我们把这个发言的信息广播到所有在线的 WebSocket 信道上
     */
    onMessage(tunnelId, type, content) {
        debug(`${this.constructor.name} [onMessage] =>`, { tunnelId, type, content });

        switch (type) {
        case 'speak':
            if (tunnelId in userMap) {
                $broadcast('speak', {
                    'who': userMap[tunnelId],
                    'word': content.word,
                });
            } else {
                $close(tunnelId);
            }
            break;

        default:
            // ...
            break;
        }
    }

    /**
     * 实现 onClose 方法
     * 客户端关闭 WebSocket 信道或者被信道服务器判断为已断开后,
     * 会调用该方法,此时可以进行清理及通知操作
     */
    onClose(tunnelId) {
        debug(`${this.constructor.name} [onClose] =>`, { tunnelId });

        if (!(tunnelId in userMap)) {
            debug(`${this.constructor.name} [onClose][Invalid TunnelId]=>`, tunnelId);
            $close(tunnelId);
            return;
        }

        const leaveUser = userMap[tunnelId];
        delete userMap[tunnelId];

        const index = connectedTunnelIds.indexOf(tunnelId);
        if (~index) {
            connectedTunnelIds.splice(index, 1);
        }

        // 聊天室没有人了(即无信道ID)不再需要广播消息
        if (connectedTunnelIds.length > 0) {
            $broadcast('people', {
                'total': connectedTunnelIds.length,
                'leave': leaveUser,
            });
        }
    }
}

module.exports = ChatTunnelHandler;

================================================
FILE: config.js
================================================
'use strict';

module.exports = {
    /**
     * Node 服务器启动端口,如果是自行搭建,请保证负载均衡上的代理地址指向这个端口
     */
    port: '5757',
};


================================================
FILE: globals.js
================================================
global.debug = (() => {
    const log = console.log.bind(console);

    return function () {
        log('========================================');
        log.apply(null, Array.from(arguments).map(item => {
            return (typeof item === 'object'
                ? JSON.stringify(item, null, 2)
                : item);
        }));
        log('========================================\n');
    };
})();

================================================
FILE: package.json
================================================
{
  "name": "wafer-node-server-demo",
  "version": "1.0.0",
  "description": "Wafer 服务端 Demo - Node.js",
  "main": "index.js",
  "scripts": {
    "start": "pm2 start process.json"
  },
  "keywords": [],
  "author": "CFETeam",
  "license": "MIT",
  "dependencies": {
    "body-parser": "^1.15.2",
    "express": "^4.14.0",
    "lodash": "^4.16.1",
    "morgan": "^1.7.0",
    "qcloud-weapp-server-sdk": "latest"
  }
}


================================================
FILE: process.json
================================================
{
    "name": "weapp",
    "script": "app.js",
    "cwd": "./",
    "exec_mode": "fork",
    "watch": true,
    "env": {
        "NODE_ENV": "production",
        "DEBUG_SDK": "yes"
    }
}

================================================
FILE: routes/index.js
================================================
'use strict';

const express = require('express');
const router = express.Router();

router.get('/', require('./welcome'));
router.get('/login', require('./login'));
router.get('/user', require('./user'));
router.all('/tunnel', require('./tunnel'));

module.exports = router;

================================================
FILE: routes/login.js
================================================
'use strict';

const LoginService = require('qcloud-weapp-server-sdk').LoginService;

module.exports = (req, res) => {
    LoginService.create(req, res).login();
};

================================================
FILE: routes/tunnel.js
================================================
'use strict';

const TunnelService = require('qcloud-weapp-server-sdk').TunnelService;
const ChatTunnelHandler = require('../business/chat-tunnel-handler');

module.exports = (req, res) => {
    let handler = new ChatTunnelHandler();
    TunnelService.create(req, res).handle(handler, {
        'checkLogin': true,
    });
};

================================================
FILE: routes/user.js
================================================
'use strict';

const LoginService = require('qcloud-weapp-server-sdk').LoginService;

module.exports = (req, res) => {
    const loginService = LoginService.create(req, res);

    loginService.check()
        .then(data => {
            res.json({
                'code': 0,
                'message': 'ok',
                'data': {
                    'userInfo': data.userInfo,
                },
            });
        });
};

================================================
FILE: routes/welcome.js
================================================
const html =
`<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>腾讯云微信小程序服务器 Demo - Node.js</title>
    <style type="text/css">

    ::selection { background-color: #327F2D; color: white; }
    ::-moz-selection { background-color: #327F2D; color: white; }

    body {
        background-color: #fff;
        margin: 40px;
        font: 13px/20px normal Helvetica, Arial, sans-serif;
        color: #4F5155;
    }

    a {
        color: #003399;
        background-color: transparent;
        font-weight: normal;
        text-decoration: none;
    }

    h1 {
        color: #444;
        background-color: transparent;
        border-bottom: 1px solid #D0D0D0;
        font-size: 19px;
        font-weight: normal;
        margin: 0 0 14px 0;
        padding: 14px 0;
    }

    #container {
        margin: 10px;
        padding: 10px 20px;
        border: 1px solid #D0D0D0;
        box-shadow: 0 0 8px #D0D0D0;
    }
    </style>
</head>
<body>
    <div id="container">
        <h1>腾讯云微信小程序服务端 Demo - Node.js</h1>
        <p>会话管理服务</p>
        <ul>
            <li><a href="/login">登录服务</a></li>
            <li><a href="/user">检查登录</a></li>
        </ul>
        <p>信道服务</p>
        <ul>
            <li><a href="/tunnel">获得信道地址</a></li>
        </ul>
    </div>
</body>
</html>
`;

module.exports = (req, res) => {
    res.send(html);
};

================================================
FILE: setup-qcloud-sdk.js
================================================
const os = require('os');
const fs = require('fs');
const qcloud = require('qcloud-weapp-server-sdk');

const sdkConfig = (() => {
    // Windows
    if (os.type().toLowerCase().startsWith('windows')) {
        return 'C:\\qcloud\\sdk.config';
    }

    // Linux
    return '/etc/qcloud/sdk.config';
})();

try {
    const stats = fs.statSync(sdkConfig);

    if (!stats.isFile()) {
        throw new Error('File not exists.');
    }
} catch (e) {
    debug(`SDK 配置文件(${sdkConfig})不存在`);
    process.exit(1);
}

const config = (() => {
    try {
        const content = fs.readFileSync(sdkConfig, 'utf8');
        return JSON.parse(content);
    } catch (e) {
        debug(`SDK 配置文件(${sdkConfig})内容不合法`);
        process.exit(1);
    }
})();

qcloud.config({
    ServerHost: config.serverHost,
    AuthServerUrl: config.authServerUrl,
    TunnelServerUrl: config.tunnelServerUrl,
    TunnelSignatureKey: config.tunnelSignatureKey,
});

// 网络请求超时时长(单位:毫秒)
qcloud.config.setNetworkTimeout(config.networkTimeout);

debug('[当前 SDK 使用配置] =>', config);
Download .txt
gitextract_c013j9pl/

├── .gitignore
├── LICENSE
├── README.md
├── app.js
├── business/
│   └── chat-tunnel-handler.js
├── config.js
├── globals.js
├── package.json
├── process.json
├── routes/
│   ├── index.js
│   ├── login.js
│   ├── tunnel.js
│   ├── user.js
│   └── welcome.js
└── setup-qcloud-sdk.js
Download .txt
SYMBOL INDEX (5 symbols across 1 files)

FILE: business/chat-tunnel-handler.js
  class ChatTunnelHandler (line 50) | class ChatTunnelHandler {
    method onRequest (line 56) | onRequest(tunnelId, userInfo) {
    method onConnect (line 70) | onConnect(tunnelId) {
    method onMessage (line 92) | onMessage(tunnelId, type, content) {
    method onClose (line 118) | onClose(tunnelId) {
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
  {
    "path": ".gitignore",
    "chars": 44,
    "preview": "node_modules/\nnpm-debug.log\nsftp-config.json"
  },
  {
    "path": "LICENSE",
    "chars": 1084,
    "preview": "LICENSE - \"MIT License\"\n\nCopyright (c) 2016 by Tencent Cloud\n\nPermission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "README.md",
    "chars": 1475,
    "preview": "# Wafer 服务端 Demo - Node.js\n\n本项目是 [腾讯云微信小程序服务端 SDK - Node.js](https://github.com/tencentyun/wafer-node-server-sdk) 的使用示例。"
  },
  {
    "path": "app.js",
    "chars": 933,
    "preview": "'use strict';\n\nrequire('./globals');\nrequire('./setup-qcloud-sdk');\n\nconst http = require('http');\nconst express = requi"
  },
  {
    "path": "business/chat-tunnel-handler.js",
    "chars": 3841,
    "preview": "'use strict';\n\nconst TunnelService = require('qcloud-weapp-server-sdk').TunnelService;\n\n/**\n * 调用 TunnelService.broadcas"
  },
  {
    "path": "config.js",
    "chars": 119,
    "preview": "'use strict';\n\nmodule.exports = {\n    /**\n     * Node 服务器启动端口,如果是自行搭建,请保证负载均衡上的代理地址指向这个端口\n     */\n    port: '5757',\n};\n"
  },
  {
    "path": "globals.js",
    "chars": 412,
    "preview": "global.debug = (() => {\n    const log = console.log.bind(console);\n\n    return function () {\n        log('=============="
  },
  {
    "path": "package.json",
    "chars": 417,
    "preview": "{\n  \"name\": \"wafer-node-server-demo\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Wafer 服务端 Demo - Node.js\",\n  \"main\": \"inde"
  },
  {
    "path": "process.json",
    "chars": 189,
    "preview": "{\n    \"name\": \"weapp\",\n    \"script\": \"app.js\",\n    \"cwd\": \"./\",\n    \"exec_mode\": \"fork\",\n    \"watch\": true,\n    \"env\": {"
  },
  {
    "path": "routes/index.js",
    "chars": 275,
    "preview": "'use strict';\n\nconst express = require('express');\nconst router = express.Router();\n\nrouter.get('/', require('./welcome'"
  },
  {
    "path": "routes/login.js",
    "chars": 164,
    "preview": "'use strict';\n\nconst LoginService = require('qcloud-weapp-server-sdk').LoginService;\n\nmodule.exports = (req, res) => {\n "
  },
  {
    "path": "routes/tunnel.js",
    "chars": 325,
    "preview": "'use strict';\n\nconst TunnelService = require('qcloud-weapp-server-sdk').TunnelService;\nconst ChatTunnelHandler = require"
  },
  {
    "path": "routes/user.js",
    "chars": 430,
    "preview": "'use strict';\n\nconst LoginService = require('qcloud-weapp-server-sdk').LoginService;\n\nmodule.exports = (req, res) => {\n "
  },
  {
    "path": "routes/welcome.js",
    "chars": 1361,
    "preview": "const html =\n`<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title>腾讯云微信小程序服务器 Demo - Node.js</title>\n   "
  },
  {
    "path": "setup-qcloud-sdk.js",
    "chars": 1049,
    "preview": "const os = require('os');\nconst fs = require('fs');\nconst qcloud = require('qcloud-weapp-server-sdk');\n\nconst sdkConfig "
  }
]

About this extraction

This page contains the full source code of the tencentyun/wafer-node-server-demo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (11.8 KB), approximately 3.8k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!