Skip to content

Commit

Permalink
实现接口调起监听服务;多用户同时监听;监听接口支持查询状态/监听/停止;
Browse files Browse the repository at this point in the history
  • Loading branch information
cxOrz committed Aug 6, 2022
1 parent 338c99b commit 81d5714
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 41 deletions.
45 changes: 25 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ cd chaoxing-sign-cli && npm install
```

## 运行 ⚙

### 命令解释

- `npm start`:运行程序,若有签到则进行手动签到,若无则退出程序;
- `npm run serve`:启动接口服务;
- `npm run monitor`:监听模式,检测到签到将自动签上,无需人工干预;


一般情况下执行以下命令即可满足基础使用

```bash
Expand Down Expand Up @@ -74,7 +75,13 @@ npm start

以上内容介绍了最基本的用法,接下来介绍一些稍高级一些的使用方法。

### 运行接口服务
### 图形化界面

基于 React.js + Material UI 开发前端页面,其中修改了很多 MUI 附带样式,也自己手写了一些,整体设计灵感-->拟态。

访问 [这里](https://github.com/cxOrz/chaoxing-sign-ui) 查看图形化页面如何部署,使用图形化页面需要先部署接口才能正常工作。

### 接口服务

首先运行 `npm install` 或者 `yarn`,安装依赖。

Expand All @@ -92,36 +99,34 @@ npm start
|/photo|POST|uf, _d, vc3, name, aid, uid, fid, objectId|JSON|待填|
|/upload|POST|uf, _d, vc3, uid, file, ?_token|multipart/form-data|待填|
|/qrocr|POST|file|multipart/form-data|\< String \>|

### 图形化界面

基于 React.js + Material UI 开发前端页面,其中修改了很多 MUI 附带样式,也自己手写了一些,整体设计灵感-->拟态。

访问 [这里](https://github.com/cxOrz/chaoxing-sign-ui) 查看图形化页面如何部署,使用图形化页面需要先部署接口才能正常工作。
|/monitor/status|POST|phone|JSON|JSON|
|/monitor/start|POST|phone, uf, _d, vc3, uid, lv, fid|JSON|JSON|
|/monitor/stop|POST|phone|JSON|JSON|

### 最佳实践

在这里介绍部署接口的最佳方式,图形化页面的最佳实践请到其仓库查看
在这里介绍部署接口的最佳方式,图形化页面的最佳实践请到它对应的仓库查看

使用 [腾讯云开发-云函数](https://console.cloud.tencent.com/tcb/scf) 部署接口服务,步骤如下:
部署在服务器,这里以 Ubuntu 22.04 为例,步骤如下:

1. 在云函数页面,使用默认 HelloWorld 模板新建云函数,并选择最新的 Nodejs 版本
2. 下载 [tcb-serverless.zip](https://github.com/cxOrz/chaoxing-sign-cli/releases) 文件,如需配置使用 [腾讯云OCR](https://console.cloud.tencent.com/ocr/overview) 以精准解析二维码,请解压并在 `env.json` 配置腾讯云的 secretId 和 secretKey,并重新压缩。注意,请直接选中所有文件夹和文件进行压缩(确保打开压缩包显示一堆文件夹和文件,而不是一个总文件夹)。如果使用默认的二维码解析方法,可以不用修改压缩包文件,直接使用即可。
3. 点击创建好的云函数,进入**函数代码**页面,在提交方法中选择本地上传ZIP包,上传压缩包。
4. 保存,安装依赖,至此部署完成。
1. 安装 Node 环境,推荐使用 LTS 版本
2. 克隆代码,安装依赖
3. 配置项目中的 env.json 文件(可选)
4. 最后,使用 GNU Screen 或者 PM2 运行项目

部署完成后,还有一些必要的设置需要调整
还有一些事情必需知道

- 选择创建的云函数,进入函数配置页面,将**超时时间**设为 `20` 秒,在 10-30 秒的范围内较合理。
- 在云开发CloudBase-环境-访问服务中,开启HTTP访问服务。新建触发路径,选择一个域名,触发路径可写为 `/chaoxing`,在关联资源选择云函数和刚刚创建的函数,确认并等待完成。完成后即可通过触发路径,访问接口服务。
- 目前任何云函数,都无法实现监听,如果要在 UI 端使用监听功能,请部署在服务器,并且在运行接口服务之前,先运行一次 `npm run monitor` 来配置默认信息,填写完成后看到 "监听中" ,即可终止程序,信息已经写入本地。然后就可以运行 `npm run serve` 了。
- 此项目可以运行在 AWS Lambda,腾讯云函数暂时不支持,如需在 Lambda 运行,请务必在运行前修改 env.json 中的 `SERVERLESS``true`
- 如过使用腾讯文字识别,请在 env.json 中配置 secretId 和 secretKey。

至此,云函数部署完成,可通过该函数的触发路径,访问接口服务
至此,部署完成,可通过域名或服务器 IP 访问接口的默认路径 `/` ,看到欢迎页面

### 展示

演示地址:https://prod.d6afmntd8nh5y.amplifyapp.com (部署在香港,较慢,仅供演示
演示地址:https://prod.d6afmntd8nh5y.amplifyapp.com (部署在香港,较慢,功能阉割版仅供演示

![](https://636c-cloudbase-1a4211-1252446325.tcb.qcloud.la/chaoxing-sign-ui/1.png)
![](https://636c-cloudbase-1a4211-1252446325.tcb.qcloud.la/chaoxing-sign-ui/1.png?)
![](https://636c-cloudbase-1a4211-1252446325.tcb.qcloud.la/chaoxing-sign-ui/2.png)

## 贡献
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"type": "module",
"license": "MIT",
"dependencies": {
"@koa/router": "^10.1.1",
"@koa/router": "^12.0.0",
"crypto-js": "^4.1.1",
"form-data": "^4.0.0",
"koa": "^2.13.4",
Expand Down
37 changes: 31 additions & 6 deletions src/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ class Monitor {
static UNKNOWN_PREFIX_LV2_LV0 = '0800123d0a0e63782d64657623637873747564791209';
static UNKNOWN_PREFIX_LV1 = '0800123c0a0e63782d64657623637873747564791208';

// 生成登录请求数据包
generateLoginHex(IM_Params, lv) {
const timestampHex = utf8ToHex(new Date().getTime().toString());

// 兼容三种账号类型
switch (lv) {
case '1': lv = Monitor.UNKNOWN_PREFIX_LV1; break;
default: lv = Monitor.UNKNOWN_PREFIX_LV2_LV0;
Expand All @@ -41,20 +43,24 @@ class Monitor {
utf8ToHex(IM_Params.myToken) + "50005800");
}

// 生成活动请求数据包
generateGetActivityHex() {
return '080040004a2b1a29120f' + Monitor.ChatIDHex + '1a16636f6e666572656e63652e656173656d6f622e636f6d5800';
}

// 生成请求保持连接数据包
generateKeepAliveHex() {
return '080040004a3510d09580acd5a2d2a90e1a29120f' + Monitor.ChatIDHex + '1a16636f6e666572656e63652e656173656d6f622e636f6d5800';
}

}

// 提取活动数据的JSON部分
function parseActivityHexJSON(hexStr) {
hexStr = hexStr.substring(hexStr.lastIndexOf('7b22617474'), hexStr.lastIndexOf('4a02'));
return JSON.parse(hexToUtf8(hexStr));
}
// 提取聊天群组ID
function getchatIdHex(hexStr) {
return hexStr.substring(hexStr.indexOf('29120f') + 6, hexStr.indexOf('1a16636f'))
}
Expand Down Expand Up @@ -82,6 +88,8 @@ async function fetchParams() {

async function configure() {
const config = getJsonObject('configs/storage.json');
if (process.argv[2] === '--auth') return config.monitor;

let local = false;
console.log(blue('自动签到支持 [普通/手势/拍照/签到码/位置]'))
if (config.monitor.address !== "") {
Expand Down Expand Up @@ -165,8 +173,19 @@ async function Sign(name, params, config, activity) {

// 开始运行
(async () => {
// 登录,获取凭证
let params = await fetchParams();
let params = {};
// 若凭证由命令参数传来,直接赋值;否则,直接用户名密码登录获取凭证
if (process.argv[2] === '--auth') {
params.uf = process.argv[3];
params._d = process.argv[4];
params.vc3 = process.argv[5];
params._uid = process.argv[6];
params.lv = process.argv[7];
params.fid = process.argv[8];
} else {
params = await fetchParams();
if (params === 'AuthFailed') process.exit(0);
}
let IM_Params = await getIMParams(params.uf, params._d, params._uid, params.vc3);
// 配置默认签到信息
const config = await configure();
Expand All @@ -179,13 +198,17 @@ async function Sign(name, params, config, activity) {
while (true) {
await new Promise((resolve) => {
const ws = new WebSocket(Monitor.WebSocketURL);
ws.on('message', async (data) => {
let data = null;
ws.on('message', async (rawData) => {
// console.log(data.toString())
if (data.toString() == 'o') {
data = rawData.toString();
if (data === 'o') {
// 发送登录数据包
ws.send(`["${hexToBase64(loginHex)}"]`)
} else if (data.toString().charAt(0) == 'a') {
const temp = base64toHex(data.toString().split('"')[1])
} else if (data.charAt(0) === 'a') {
// 向父进程发送连接正常消息
if (process.send) process.send('success');
const temp = base64toHex(data.split('"')[1])
// 有签到活动,发送请求获取签到内容
if (temp.startsWith(Monitor.COMING_SIGN_PREFIX)) {
Monitor.ChatIDHex = getchatIdHex(temp)
Expand All @@ -209,6 +232,8 @@ async function Sign(name, params, config, activity) {
ws.terminate();
resolve();
}
} else if (data.charAt(0) === 'c') {
if (process.send) process.send('authfail');
}
})
})
Expand Down
56 changes: 56 additions & 0 deletions src/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ import { GeneralSign } from './functions/general.js';
import { PhotoSign, uploadPhoto } from './functions/photo.js';
import { QrCodeScan } from './functions/tencent/QrCodeOCR.js';
import { getJsonObject } from './utils/file.js';
import { spawn } from 'child_process';
import serverless from 'serverless-http';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const ENVJSON = getJsonObject('env.json');

const app = new Koa()
const router = new Router()
const processMap = new Map()

router.get('/', async (ctx) => {
ctx.body = `<h1 style="text-align: center">Welcome, chaoxing-sign-cli API service is running.</h1>`
Expand Down Expand Up @@ -168,6 +174,56 @@ router.post('/qrocr', async (ctx) => {
ctx.body = result
})

// 200:监听中,201:未监听,202:登录失败
router.post('/monitor/status', (ctx) => {
// 状态为正在监听
if (processMap.get(ctx.request.body.phone)) {
ctx.body = '{"code":200,"msg":"Monitoring"}';
} else {
ctx.body = '{"code":201,"msg":"Suspended"}';
}
})

router.post('/monitor/stop', (ctx) => {
const process_monitor = processMap.get(ctx.request.body.phone);
if (process_monitor !== undefined) {
process_monitor.kill('SIGKILL');
processMap.delete(ctx.request.body.phone);
}
ctx.body = '{"code":201,"msg":"Suspended"}';
})

router.post('/monitor/start', async (ctx) => {
if (processMap.get(ctx.request.body.phone) !== undefined) {
ctx.body = '{"code":200,"msg":"Already started"}';
return;
}
const process_monitor = spawn('node', ['monitor.js', '--auth',
ctx.request.body.uf, ctx.request.body._d,
ctx.request.body.vc3, ctx.request.body.uid,
ctx.request.body.lv, ctx.request.body.fid], {
cwd: __dirname,
stdio: [null, null, null, 'ipc']
});
const response = await new Promise((resolve) => {
process_monitor.on('message', (msg) => {
switch (msg) {
case 'success': {
processMap.set(ctx.request.body.phone, process_monitor);
resolve('{"code":200,"msg":"Started Successfully"}');
break;
}
case 'authfail': {
process_monitor.kill();
resolve('{"code":202,"msg":"Authencation Failed"}');
break;
}
}
});
});
ctx.body = response;
})

app.use(bodyparser())
app.use(async (ctx, next) => {
ctx.set("Access-Control-Allow-Origin", "*")
Expand Down
27 changes: 13 additions & 14 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
# yarn lockfile v1


"@koa/router@^10.1.1":
version "10.1.1"
resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78"
integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==
"@koa/router@^12.0.0":
version "12.0.0"
resolved "https://registry.yarnpkg.com/@koa/router/-/router-12.0.0.tgz#2ae7937093fd392761c0e5833c368379d4a35737"
integrity sha512-cnnxeKHXlt7XARJptflGURdJaO+ITpNkOHmQu7NHmCoRinPbyvFzce/EG/E8Zy81yQ1W9MoSdtklc3nyaDReUw==
dependencies:
debug "^4.1.1"
http-errors "^1.7.3"
http-errors "^2.0.0"
koa-compose "^4.1.0"
methods "^1.1.2"
path-to-regexp "^6.1.0"
path-to-regexp "^6.2.1"

accepts@^1.3.5:
version "1.3.8"
Expand Down Expand Up @@ -106,7 +105,7 @@ crypto-js@^4.1.1:
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==

debug@4, debug@^4.1.1, debug@^4.3.2:
debug@4, debug@^4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
Expand Down Expand Up @@ -227,7 +226,7 @@ http-assert@^1.3.0:
deep-equal "~1.0.1"
http-errors "~1.8.0"

[email protected]:
[email protected], http-errors@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
Expand All @@ -238,7 +237,7 @@ [email protected]:
statuses "2.0.1"
toidentifier "1.0.1"

http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0, http-errors@~1.8.1:
http-errors@^1.6.3, http-errors@~1.8.0, http-errors@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
Expand Down Expand Up @@ -423,10 +422,10 @@ parseurl@^1.3.2:
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==

path-to-regexp@^6.1.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
path-to-regexp@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5"
integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==

prompts@^2.4.2:
version "2.4.2"
Expand Down

0 comments on commit 81d5714

Please sign in to comment.