glede-init 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +125 -0
- package/copy.js +94 -0
- package/package.json +19 -0
- package/templates/default/.editorconfig +22 -0
- package/templates/default/.env +2 -0
- package/templates/default/.vscode/extensions.json +5 -0
- package/templates/default/.vscode/settings.json +7 -0
- package/templates/default/README.md +29 -0
- package/templates/default/app.ts +19 -0
- package/templates/default/components/service/entry.ts +85 -0
- package/templates/default/configs/app-config.ts +31 -0
- package/templates/default/package.json +20 -0
- package/templates/default/protos/README.md +35 -0
- package/templates/default/protos/buf.yaml +5 -0
- package/templates/default/protos/code.gen.yaml +11 -0
- package/templates/default/protos/fast-text-encoding.js +1 -0
- package/templates/default/protos/gen/buf-min/client/index.ts +87 -0
- package/templates/default/protos/gen/buf-min/server/index.ts +126 -0
- package/templates/default/protos/gen/buf-speed/client/index.ts +181 -0
- package/templates/default/protos/gen/buf-speed/server/index.ts +227 -0
- package/templates/default/protos/gen/pb/index.d.ts +293 -0
- package/templates/default/protos/gen/pb/index.js +2 -0
- package/templates/default/protos/model/client/index.proto +24 -0
- package/templates/default/protos/model/client/oneof.proto.bak +39 -0
- package/templates/default/protos/model/server/index.proto +29 -0
- package/templates/default/protos/package.json +18 -0
- package/templates/default/protos/speed.gen.yaml +10 -0
- package/templates/default/routers/common/index.ts +11 -0
- package/templates/default/tsconfig.json +39 -0
- package/templates/default/types/global.d.ts +75 -0
- package/templates/default/utils/libs/index.ts +2 -0
- package/templates/default/utils/libs/limit.ts +30 -0
- package/templates/default/utils/libs/log.ts +10 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import prompts from 'prompts';
|
|
7
|
+
import { copySync } from '../copy';
|
|
8
|
+
import { version } from '../package.json';
|
|
9
|
+
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
|
|
12
|
+
// ANSI 颜色代码
|
|
13
|
+
const colors = {
|
|
14
|
+
reset: "\x1b[0m",
|
|
15
|
+
bold: "\x1b[1m",
|
|
16
|
+
dim: "\x1b[2m",
|
|
17
|
+
underscore: "\x1b[4m",
|
|
18
|
+
blink: "\x1b[5m",
|
|
19
|
+
reverse: "\x1b[7m",
|
|
20
|
+
hidden: "\x1b[8m",
|
|
21
|
+
|
|
22
|
+
// 前景色(文本颜色)
|
|
23
|
+
black: "\x1b[30m",
|
|
24
|
+
red: "\x1b[31m",
|
|
25
|
+
green: "\x1b[32m",
|
|
26
|
+
yellow: "\x1b[33m",
|
|
27
|
+
blue: "\x1b[34m",
|
|
28
|
+
magenta: "\x1b[35m",
|
|
29
|
+
cyan: "\x1b[36m",
|
|
30
|
+
white: "\x1b[37m",
|
|
31
|
+
gray: "\x1b[90m",
|
|
32
|
+
|
|
33
|
+
// 背景色
|
|
34
|
+
bgBlack: "\x1b[40m",
|
|
35
|
+
bgRed: "\x1b[41m",
|
|
36
|
+
bgGreen: "\x1b[42m",
|
|
37
|
+
bgYellow: "\x1b[43m",
|
|
38
|
+
bgBlue: "\x1b[44m",
|
|
39
|
+
bgMagenta: "\x1b[45m",
|
|
40
|
+
bgCyan: "\x1b[46m",
|
|
41
|
+
bgWhite: "\x1b[47m"
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
async function initProject() {
|
|
45
|
+
console.log(`${colors.green} 🚀 Welcome to use GledeServer. cli version ${version}`);
|
|
46
|
+
|
|
47
|
+
// 1. 获取项目信息
|
|
48
|
+
const response = await prompts([
|
|
49
|
+
{
|
|
50
|
+
type: 'text',
|
|
51
|
+
name: 'projectName',
|
|
52
|
+
message: '请输入项目名称:',
|
|
53
|
+
initial: 'my-project',
|
|
54
|
+
validate: value => value.trim() === '' ? '项目名称不能为空' : true
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'confirm',
|
|
58
|
+
name: 'installDeps',
|
|
59
|
+
message: '是否要安装依赖?',
|
|
60
|
+
initial: true
|
|
61
|
+
}
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
if (!response.projectName) {
|
|
65
|
+
console.log(`${colors.red} ❌ 项目创建已取消`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const projectPath = path.join(process.cwd(), response.projectName);
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// 2. 创建项目目录
|
|
73
|
+
console.log(`${colors.blue} ⏳ 正在创建项目目录...`);
|
|
74
|
+
fs.mkdirSync(projectPath, { recursive: true });
|
|
75
|
+
|
|
76
|
+
// 3. 复制模板文件
|
|
77
|
+
const templatePath = path.join(__dirname, '../templates/default/.');
|
|
78
|
+
copySync(templatePath, projectPath);
|
|
79
|
+
|
|
80
|
+
// 4. 更新 package.json 中的项目名称
|
|
81
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
82
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
83
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
84
|
+
pkg.name = response.projectName.toLowerCase().replace(/\s+/g, '-');
|
|
85
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.log(`${colors.green} ✅ 项目 ${response.projectName}创建成功`);
|
|
89
|
+
|
|
90
|
+
// 5. 安装依赖
|
|
91
|
+
if (response.installDeps) {
|
|
92
|
+
console.log(`${colors.blue} ⏳ 正在安装依赖...`);
|
|
93
|
+
const installProcess = Bun.spawn(['bun', 'install'], {
|
|
94
|
+
cwd: projectPath,
|
|
95
|
+
stdout: 'inherit',
|
|
96
|
+
stderr: 'inherit'
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await installProcess.exited;
|
|
100
|
+
|
|
101
|
+
if (installProcess.exitCode === 0) {
|
|
102
|
+
console.log(`${colors.green} ✅ 依赖安装成功`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
response.installDeps = false;
|
|
106
|
+
console.log(`${colors.yellow} ⚠️ 依赖安装过程中出现错误`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 6. 显示完成信息
|
|
111
|
+
console.log(`${colors.reset}
|
|
112
|
+
${colors.bold} 🎉 Glede 服务器初始化完成!${colors.reset}
|
|
113
|
+
|
|
114
|
+
接下来可以执行:
|
|
115
|
+
${colors.cyan} cd ${response.projectName}
|
|
116
|
+
${response.installDeps ? '' : `${colors.cyan} bun install`}
|
|
117
|
+
${colors.cyan} bun dev ${colors.gray} # 启动开发服务器
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
console.error(colors.red, `❌ 项目创建失败: ${e.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
initProject().catch(console.error);
|
package/copy.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 实现 fs-extra 的 copy 功能(同步版)
|
|
6
|
+
*/
|
|
7
|
+
export function copySync(src, dest, options = {}) {
|
|
8
|
+
const {
|
|
9
|
+
preserveTimestamps = true,
|
|
10
|
+
dereference = false,
|
|
11
|
+
mode
|
|
12
|
+
} = options;
|
|
13
|
+
|
|
14
|
+
// 规范化路径并解析符号链接(如果需跟随)
|
|
15
|
+
const resolvedSrc = dereference
|
|
16
|
+
? fs.realpathSync(src)
|
|
17
|
+
: normalizeToPosixPath(src);
|
|
18
|
+
|
|
19
|
+
const stats = dereference
|
|
20
|
+
? fs.statSync(resolvedSrc)
|
|
21
|
+
: fs.lstatSync(resolvedSrc);
|
|
22
|
+
|
|
23
|
+
// 检查目标路径是否存在
|
|
24
|
+
let destExists = false;
|
|
25
|
+
try {
|
|
26
|
+
fs.accessSync(dest, fs.constants.F_OK);
|
|
27
|
+
destExists = true;
|
|
28
|
+
} catch { }
|
|
29
|
+
|
|
30
|
+
// 处理不同类型文件的复制
|
|
31
|
+
if (stats.isDirectory()) {
|
|
32
|
+
copyDirSync(resolvedSrc, dest, { preserveTimestamps, dereference, mode });
|
|
33
|
+
} else if (stats.isFile() || (stats.isSymbolicLink() && !dereference)) {
|
|
34
|
+
copyFileSync(resolvedSrc, dest, { preserveTimestamps, mode });
|
|
35
|
+
} else {
|
|
36
|
+
throw new Error(`Unsupported file type: ${resolvedSrc}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 复制单个文件(或符号链接)
|
|
41
|
+
function copyFileSync(src, dest, options) {
|
|
42
|
+
const { mode, preserveTimestamps } = options;
|
|
43
|
+
|
|
44
|
+
// 复制内容(如果是符号链接则创建新链接)
|
|
45
|
+
if (fs.lstatSync(src).isSymbolicLink()) {
|
|
46
|
+
const linkTarget = fs.readlinkSync(src);
|
|
47
|
+
fs.symlinkSync(linkTarget, dest);
|
|
48
|
+
} else {
|
|
49
|
+
fs.copyFileSync(src, dest, fs.constants.COPYFILE_FICLONE);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 保留权限
|
|
53
|
+
if (mode !== undefined) {
|
|
54
|
+
fs.chmodSync(dest, mode);
|
|
55
|
+
} else {
|
|
56
|
+
fs.chmodSync(dest, fs.statSync(src).mode);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 保留时间戳
|
|
60
|
+
if (preserveTimestamps) {
|
|
61
|
+
const { atime, mtime } = fs.statSync(src);
|
|
62
|
+
fs.utimesSync(dest, atime, mtime);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 递归复制目录
|
|
67
|
+
function copyDirSync(src, dest, options) {
|
|
68
|
+
// 创建目标目录
|
|
69
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
70
|
+
|
|
71
|
+
// 遍历源目录
|
|
72
|
+
for (const entry of fs.readdirSync(src)) {
|
|
73
|
+
const srcEntry = path.join(src, entry);
|
|
74
|
+
const destEntry = path.join(dest, entry);
|
|
75
|
+
copySync(srcEntry, destEntry, options); // 递归调用
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 保留目录权限和时间戳
|
|
79
|
+
if (options.mode !== undefined) {
|
|
80
|
+
fs.chmodSync(dest, options.mode);
|
|
81
|
+
} else {
|
|
82
|
+
fs.chmodSync(dest, fs.statSync(src).mode);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (options.preserveTimestamps) {
|
|
86
|
+
const { atime, mtime } = fs.statSync(src);
|
|
87
|
+
fs.utimesSync(dest, atime, mtime);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 工具函数:规范化路径为 POSIX 风格(跨平台一致)
|
|
92
|
+
function normalizeToPosixPath(p) {
|
|
93
|
+
return path.normalize(p).replace(/\\/g, '/');
|
|
94
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "glede-init",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"glede-server-init": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"copy.js",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"prompts": "^2.4.2"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset=utf-8
|
|
5
|
+
end_of_line=LF
|
|
6
|
+
insert_final_newline=true
|
|
7
|
+
indent_style=space
|
|
8
|
+
indent_size=2
|
|
9
|
+
max_line_length = 80
|
|
10
|
+
|
|
11
|
+
[*.{yml,yaml,json}]
|
|
12
|
+
indent_style = space
|
|
13
|
+
indent_size = 2
|
|
14
|
+
|
|
15
|
+
[*.{js,ts,vue}]
|
|
16
|
+
quote_type = single
|
|
17
|
+
|
|
18
|
+
[*.md]
|
|
19
|
+
trim_trailing_whitespace = false
|
|
20
|
+
|
|
21
|
+
[Makefile]
|
|
22
|
+
indent_style = tab
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Default Template
|
|
2
|
+
|
|
3
|
+
> [glede-server](https://gitee.com/philuo/glede-server-bun)
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
├── app.ts // 服务器启动入口
|
|
7
|
+
├── configs // 服务器配置
|
|
8
|
+
│ └── app-config.ts // 服务器配置文件 支持ts和json格式, 可配置多个用于区分运行时环境
|
|
9
|
+
├── tsconfig.json // ts编译配置
|
|
10
|
+
├── types // ts类型描述
|
|
11
|
+
│ └── global.d.ts // 全局类型描述
|
|
12
|
+
├── controllers // 数据操作对象
|
|
13
|
+
├── protos // protobuf子模块, 用于生成proto对应的编解码工具
|
|
14
|
+
├── components // 服务通用组件
|
|
15
|
+
├── utils // 服务通用工具
|
|
16
|
+
├── crons // 定时事务
|
|
17
|
+
├── logs // 日志目录
|
|
18
|
+
│ ├── running.log // 服务运行日志
|
|
19
|
+
│ └── routers.txt // 注册路由信息树状图
|
|
20
|
+
└── routers // 接口目录
|
|
21
|
+
├── api // /api开头, 用于业务接口
|
|
22
|
+
├── common // /开头, 用于通用接口
|
|
23
|
+
└── openapi // /openapi开头, 用于开放接口对接三方
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 生成proto编解码工具
|
|
27
|
+
|
|
28
|
+
- `cd protos`, 阅读[protos/README.md](./protos/README.md)
|
|
29
|
+
- 把`./protos/gen/pb/index.js` 和`./protos/gen/pb/index.d.ts` 拷贝到 `./configs/protos/` 下使用
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 业务服务器
|
|
3
|
+
* @date 2023-10-30
|
|
4
|
+
* @author Perfumere
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Server } from 'glede-server-bun';
|
|
8
|
+
import { serviceEntry, serviceMount, printServerRunning } from '@/components/service/entry';
|
|
9
|
+
|
|
10
|
+
// initialize common utils
|
|
11
|
+
serviceEntry();
|
|
12
|
+
|
|
13
|
+
Server({ conf: 'configs/app-config.ts' }, (_, address: string) => {
|
|
14
|
+
// 挂载全局工具
|
|
15
|
+
serviceMount();
|
|
16
|
+
|
|
17
|
+
// 打印启动IP:PORT
|
|
18
|
+
printServerRunning(address);
|
|
19
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 服务入口初始化
|
|
3
|
+
* @author fanchong
|
|
4
|
+
* @date 2024-05-11
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { networkInterfaces } from 'os';
|
|
8
|
+
import { logger, CatchExec } from '@/utils/libs';
|
|
9
|
+
import { GledeStaticUtil } from 'glede-server-bun';
|
|
10
|
+
|
|
11
|
+
/** 应用是否已经初始化, 单个进程内仅执行一次 */
|
|
12
|
+
let loaded = false;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 服务初始化
|
|
16
|
+
*/
|
|
17
|
+
export function serviceEntry() {
|
|
18
|
+
if (loaded) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
loaded = true;
|
|
23
|
+
|
|
24
|
+
const serverConf = require('@/configs/app-config').default || {};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 服务启动配置文件
|
|
28
|
+
*/
|
|
29
|
+
global.serverConf = serverConf;
|
|
30
|
+
/**
|
|
31
|
+
* 日志打印工具
|
|
32
|
+
*/
|
|
33
|
+
global.logger = logger;
|
|
34
|
+
/**
|
|
35
|
+
* 传入Promise为之绑定catch方法并返回,设置打印错误日志
|
|
36
|
+
*/
|
|
37
|
+
global.CatchExec = CatchExec;
|
|
38
|
+
/**
|
|
39
|
+
* res_err
|
|
40
|
+
*/
|
|
41
|
+
global.serr = {
|
|
42
|
+
params: (msg: string) => ({ code: 1, data: null, msg: String(msg) }),
|
|
43
|
+
process: (msg: string) => ({ code: 2, data: null, msg: String(msg) }),
|
|
44
|
+
ban: (msg: string) => ({ code: 3, data: null, msg: String(msg) })
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 服务启动挂载
|
|
50
|
+
*/
|
|
51
|
+
export function serviceMount() {
|
|
52
|
+
const { getRedisInstance, getPgInstance } = GledeStaticUtil;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* redis实例
|
|
56
|
+
*/
|
|
57
|
+
global.redis = getRedisInstance();
|
|
58
|
+
/**
|
|
59
|
+
* pg实例
|
|
60
|
+
*/
|
|
61
|
+
global.sql = getPgInstance();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 打印服务启动访问链接: IP:PORT
|
|
68
|
+
*/
|
|
69
|
+
export function printServerRunning(address: string) {
|
|
70
|
+
const interfaces = networkInterfaces();
|
|
71
|
+
let ip = '';
|
|
72
|
+
|
|
73
|
+
for (let devName in interfaces) {
|
|
74
|
+
const iface = interfaces[devName]!;
|
|
75
|
+
for (let i = 0; i < iface.length; i++) {
|
|
76
|
+
const alias = iface[i]!;
|
|
77
|
+
|
|
78
|
+
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
|
|
79
|
+
ip = alias.address;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('server: \x1b[32m' + address.replace('0.0.0.0', ip));
|
|
85
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 服务器配置
|
|
3
|
+
* @date 2025-04-26
|
|
4
|
+
* @author Perfumere
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
host: '0.0.0.0',
|
|
9
|
+
port: 3020,
|
|
10
|
+
// redis: {
|
|
11
|
+
// host: '0.0.0.0'
|
|
12
|
+
// },
|
|
13
|
+
// mongodb: {
|
|
14
|
+
// url: 'mongodb://localhost:27017/your-db',
|
|
15
|
+
// options: {
|
|
16
|
+
// autoIndex: true
|
|
17
|
+
// }
|
|
18
|
+
// },
|
|
19
|
+
// pg: {
|
|
20
|
+
// url: 'postgresql://postgres@localhost:5432/heartwork'
|
|
21
|
+
// },
|
|
22
|
+
token: {
|
|
23
|
+
salt: 'glede-server', // 盐应存放在数据库/环境变量中
|
|
24
|
+
period: 7200
|
|
25
|
+
},
|
|
26
|
+
sign: {
|
|
27
|
+
salt: 'glede-server', // 盐1应存放在数据库/环境变量中
|
|
28
|
+
key: 'UGhpbHVvLW1hbGxqYWRl', // 同客户端约定的key
|
|
29
|
+
period: 3600
|
|
30
|
+
}
|
|
31
|
+
} as GledeServerOpts;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "bun run --watch app.ts",
|
|
8
|
+
"start": "bun run app.ts"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"glede-server-bun": "^1.0.20"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"bun": "^1.2.10"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/bun": "^1.2.10",
|
|
18
|
+
"typescript": "^5.0.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Protos
|
|
2
|
+
|
|
3
|
+
> 使用protobuf生成`encode`和`decode`
|
|
4
|
+
|
|
5
|
+
## 生成服务端的编解码工具
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# ./protos/gen/pb/index.js 和 ./protos/gen/pb/index.d.ts
|
|
9
|
+
bun pb
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 生成客户端的编解码工具
|
|
13
|
+
|
|
14
|
+
- 支持两种模式生成, 性能模式和min模式
|
|
15
|
+
- 注意: 客户端使用时需要安装 `@protobuf-ts/@protobuf-ts/runtime`
|
|
16
|
+
- 注意: 微信小程序打包后不支持`TextEncoder/TextDecoder`,需要引入polyfill, 请复制`./protos/fast-text-encoding.js`到小程序项目中。
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// 小程序的入口文件引入polyfill
|
|
20
|
+
import '@/utils/lib/fast-text-encoding';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 性能模式, 生成的代码性能更好, 文件略大
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# ./protos/gen/buf-speed/client 和./protos/gen/buf-speed/server
|
|
27
|
+
bun buf
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### min模式, 生成的代码性能略差, 文件小, 适合小程序等客户端等场景使用
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# ./protos/gen/buf-min/client/index.ts 和./protos/gen/buf-min/server/index.ts
|
|
34
|
+
protos bun buf:min
|
|
35
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
((e)=>{function _(q){var G=0,K=Math.min(65536,q.length+1),J=new Uint16Array(K),M=[],B=0;for(;;){var C=G<q.length;if(!C||B>=K-1){var W=J.subarray(0,B),Y=W;if(M.push(String.fromCharCode.apply(null,Y)),!C)return M.join("");q=q.subarray(G),G=0,B=0}var O=q[G++];if((O&128)===0)J[B++]=O;else if((O&224)===192){var V=q[G++]&63;J[B++]=(O&31)<<6|V}else if((O&240)===224){var V=q[G++]&63,Z=q[G++]&63;J[B++]=(O&31)<<12|V<<6|Z}else if((O&248)===240){var V=q[G++]&63,Z=q[G++]&63,P=q[G++]&63,Q=(O&7)<<18|V<<12|Z<<6|P;if(Q>65535)Q-=65536,J[B++]=Q>>>10&1023|55296,Q=56320|Q&1023;J[B++]=Q}}}function H(q){var G=0,K=q.length,J=0,M=Math.max(32,K+(K>>>1)+7),B=new Uint8Array(M>>>3<<3);while(G<K){var C=q.charCodeAt(G++);if(C>=55296&&C<=56319){if(G<K){var W=q.charCodeAt(G);if((W&64512)===56320)++G,C=((C&1023)<<10)+(W&1023)+65536}if(C>=55296&&C<=56319)continue}if(J+4>B.length){M+=8,M*=1+G/q.length*2,M=M>>>3<<3;var Y=new Uint8Array(M);Y.set(B),B=Y}if((C&4294967168)===0){B[J++]=C;continue}else if((C&4294965248)===0)B[J++]=C>>>6&31|192;else if((C&4294901760)===0)B[J++]=C>>>12&15|224,B[J++]=C>>>6&63|128;else if((C&4292870144)===0)B[J++]=C>>>18&7|240,B[J++]=C>>>12&63|128,B[J++]=C>>>6&63|128;else continue;B[J++]=C&63|128}return B.slice?B.slice(0,J):B.subarray(0,J)}function $(){this.encoding="utf-8"}$.prototype.encode=function(q,G){return H(q)};var R=typeof Blob==="function"&&typeof URL==="function"&&typeof URL.createObjectURL==="function",X=["utf-8","utf8","unicode-1-1-utf-8"],N=_;if(R)N=(q)=>_(q);var z="construct 'TextDecoder'",D=`Failed to ${z}: the `;function A(q,G){q=q||"utf-8";var K=X.indexOf(q.toLowerCase())!==-1;if(!K)throw new RangeError(`${D} encoding label provided ('${q}') is invalid.`);this.encoding=q,this.fatal=!1,this.ignoreBOM=!1}A.prototype.decode=function(q,G){var K;if(q instanceof Uint8Array)K=q;else if(q.buffer instanceof ArrayBuffer)K=new Uint8Array(q.buffer);else K=new Uint8Array(q);return N(K,this.encoding)};e.TextEncoder=e.TextEncoder||$;e.TextDecoder=e.TextDecoder||A;})(globalThis);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// @generated by protobuf-ts 2.9.6 with parameter force_optimize_code_size,keep_enum_prefix,long_type_string
|
|
2
|
+
// @generated from protobuf file "client/index.proto" (package "client", syntax proto3)
|
|
3
|
+
// tslint:disable
|
|
4
|
+
import { MessageType } from "@protobuf-ts/runtime";
|
|
5
|
+
/**
|
|
6
|
+
* 客户端指令消息
|
|
7
|
+
*
|
|
8
|
+
* @generated from protobuf message client.ClientDirective
|
|
9
|
+
*/
|
|
10
|
+
export interface ClientDirective {
|
|
11
|
+
/**
|
|
12
|
+
* @generated from protobuf field: client.ClientOptEnum option = 1;
|
|
13
|
+
*/
|
|
14
|
+
option: ClientOptEnum; // 指令类型
|
|
15
|
+
/**
|
|
16
|
+
* 以下字段根据option类型选择性填充
|
|
17
|
+
*
|
|
18
|
+
* @generated from protobuf field: string ack_id = 2;
|
|
19
|
+
*/
|
|
20
|
+
ackId: string; // 用于匹配后端回执
|
|
21
|
+
/**
|
|
22
|
+
* @generated from protobuf field: string cid = 3;
|
|
23
|
+
*/
|
|
24
|
+
cid: string; // 会话记录ID(CLIENT_RELOAD/CLIENT_STOP/CLIENT_INTERACTION/CLIENT_EXPECT_ANSWER)
|
|
25
|
+
/**
|
|
26
|
+
* @generated from protobuf field: string content = 4;
|
|
27
|
+
*/
|
|
28
|
+
content: string; // 用户问题/期望答案 (CLIENT_ASK/CLIENT_EXPECT_ANSWER)
|
|
29
|
+
/**
|
|
30
|
+
* @generated from protobuf field: string task_id = 5;
|
|
31
|
+
*/
|
|
32
|
+
taskId: string; // 任务id (CLIENT_INTERACTION)
|
|
33
|
+
/**
|
|
34
|
+
* @generated from protobuf field: map<string, string> data = 6;
|
|
35
|
+
*/
|
|
36
|
+
data: {
|
|
37
|
+
[key: string]: string;
|
|
38
|
+
}; // 用户交互数据 (CLIENT_INTERACTION)
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 指令类型枚举
|
|
42
|
+
*
|
|
43
|
+
* @generated from protobuf enum client.ClientOptEnum
|
|
44
|
+
*/
|
|
45
|
+
export enum ClientOptEnum {
|
|
46
|
+
/**
|
|
47
|
+
* @generated from protobuf enum value: UNKNOWN = 0;
|
|
48
|
+
*/
|
|
49
|
+
UNKNOWN = 0,
|
|
50
|
+
/**
|
|
51
|
+
* @generated from protobuf enum value: CLIENT_ASK = 1;
|
|
52
|
+
*/
|
|
53
|
+
CLIENT_ASK = 1,
|
|
54
|
+
/**
|
|
55
|
+
* @generated from protobuf enum value: CLIENT_INTERACTION = 2;
|
|
56
|
+
*/
|
|
57
|
+
CLIENT_INTERACTION = 2,
|
|
58
|
+
/**
|
|
59
|
+
* @generated from protobuf enum value: CLIENT_RELOAD = 3;
|
|
60
|
+
*/
|
|
61
|
+
CLIENT_RELOAD = 3,
|
|
62
|
+
/**
|
|
63
|
+
* @generated from protobuf enum value: CLIENT_STOP = 4;
|
|
64
|
+
*/
|
|
65
|
+
CLIENT_STOP = 4,
|
|
66
|
+
/**
|
|
67
|
+
* @generated from protobuf enum value: CLIENT_EXPECT_ANSWER = 5;
|
|
68
|
+
*/
|
|
69
|
+
CLIENT_EXPECT_ANSWER = 5
|
|
70
|
+
}
|
|
71
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
72
|
+
class ClientDirective$Type extends MessageType<ClientDirective> {
|
|
73
|
+
constructor() {
|
|
74
|
+
super("client.ClientDirective", [
|
|
75
|
+
{ no: 1, name: "option", kind: "enum", T: () => ["client.ClientOptEnum", ClientOptEnum] },
|
|
76
|
+
{ no: 2, name: "ack_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
77
|
+
{ no: 3, name: "cid", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
78
|
+
{ no: 4, name: "content", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
79
|
+
{ no: 5, name: "task_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
|
80
|
+
{ no: 6, name: "data", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }
|
|
81
|
+
]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @generated MessageType for protobuf message client.ClientDirective
|
|
86
|
+
*/
|
|
87
|
+
export const ClientDirective = new ClientDirective$Type();
|