mm_os 4.3.7 → 5.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.
Files changed (231) hide show
  1. package/README.md +102 -504
  2. package/index.js +26 -19
  3. package/lib/os.js +536 -0
  4. package/package.json +60 -84
  5. package/LICENSE +0 -21
  6. package/README_EN.md +0 -505
  7. package/adapter/adapter.js +0 -484
  8. package/adapter/custom_persistence.js +0 -661
  9. package/adapter/mqtt.js +0 -254
  10. package/adapter/socket.js +0 -244
  11. package/adapter/web.js +0 -92
  12. package/adapter/websocket.js +0 -43
  13. package/ai.js +0 -130
  14. package/com/api/README.md +0 -3
  15. package/com/api/com.json +0 -5
  16. package/com/api/config.tpl.json +0 -41
  17. package/com/api/drive.js +0 -732
  18. package/com/api/index.js +0 -201
  19. package/com/api/oauth.js +0 -200
  20. package/com/api/script.tpl.js +0 -32
  21. package/com/cmd/README.md +0 -11
  22. package/com/cmd/com.json +0 -5
  23. package/com/cmd/config.tpl.json +0 -48
  24. package/com/cmd/drive.js +0 -176
  25. package/com/cmd/index.js +0 -287
  26. package/com/cmd/job/config.json +0 -66
  27. package/com/cmd/job/index.js +0 -241
  28. package/com/cmd/job/test.js +0 -188
  29. package/com/cmd/msg.json +0 -48
  30. package/com/cmd/script.tpl.js +0 -12
  31. package/com/db/README.md +0 -3
  32. package/com/db/com.json +0 -5
  33. package/com/db/drive.js +0 -2206
  34. package/com/db/index.js +0 -241
  35. package/com/event/README.md +0 -4
  36. package/com/event/com.json +0 -5
  37. package/com/event/config.tpl.json +0 -20
  38. package/com/event/drive.js +0 -61
  39. package/com/event/index.js +0 -438
  40. package/com/event/script.tpl.js +0 -23
  41. package/com/mqtt/README.md +0 -47
  42. package/com/mqtt/com.json +0 -5
  43. package/com/mqtt/config.tpl.json +0 -42
  44. package/com/mqtt/drive.js +0 -704
  45. package/com/mqtt/index.js +0 -1052
  46. package/com/mqtt/index.test.js +0 -503
  47. package/com/mqtt/script.tpl.js +0 -719
  48. package/com/nav/README.md +0 -2
  49. package/com/nav/com.json +0 -5
  50. package/com/nav/config.tpl.json +0 -84
  51. package/com/nav/drive.js +0 -702
  52. package/com/nav/index.js +0 -228
  53. package/com/nav/tpl/admin_pc/page_channel.vue +0 -305
  54. package/com/nav/tpl/admin_pc/page_config.vue +0 -280
  55. package/com/nav/tpl/admin_pc/page_config_form.vue +0 -194
  56. package/com/nav/tpl/admin_pc/page_default.vue +0 -247
  57. package/com/nav/tpl/admin_pc/page_form.vue +0 -180
  58. package/com/nav/tpl/admin_pc/page_lang.vue +0 -264
  59. package/com/nav/tpl/admin_pc/page_nav.vue +0 -321
  60. package/com/nav/tpl/admin_pc/page_table.vue +0 -296
  61. package/com/nav/tpl/admin_pc/page_type.vue +0 -321
  62. package/com/nav/tpl/admin_pc/page_view.vue +0 -124
  63. package/com/nav/tpl/dev_pc/page_channel.vue +0 -253
  64. package/com/nav/tpl/dev_pc/page_config.vue +0 -253
  65. package/com/nav/tpl/dev_pc/page_default.vue +0 -247
  66. package/com/nav/tpl/dev_pc/page_form.vue +0 -162
  67. package/com/nav/tpl/dev_pc/page_nav.vue +0 -253
  68. package/com/nav/tpl/dev_pc/page_table.vue +0 -247
  69. package/com/nav/tpl/dev_pc/page_type.vue +0 -313
  70. package/com/nav/tpl/home_pc/page_channel.vue +0 -234
  71. package/com/nav/tpl/home_pc/page_default.vue +0 -234
  72. package/com/nav/tpl/home_pc/page_form.vue +0 -137
  73. package/com/nav/tpl/home_pc/page_list.vue +0 -234
  74. package/com/nav/tpl/home_pc/page_nav.vue +0 -221
  75. package/com/nav/tpl/home_pc/page_type.vue +0 -234
  76. package/com/nav/tpl/home_pc/page_view.vue +0 -125
  77. package/com/nav/tpl/home_phone/page_channel.vue +0 -234
  78. package/com/nav/tpl/home_phone/page_default.vue +0 -234
  79. package/com/nav/tpl/home_phone/page_form.vue +0 -137
  80. package/com/nav/tpl/home_phone/page_list.vue +0 -234
  81. package/com/nav/tpl/home_phone/page_nav.vue +0 -237
  82. package/com/nav/tpl/home_phone/page_type.vue +0 -234
  83. package/com/nav/tpl/home_phone/page_view.vue +0 -125
  84. package/com/nav/viewmodel.js +0 -446
  85. package/com/param/README.md +0 -2
  86. package/com/param/com.json +0 -5
  87. package/com/param/config.tpl.json +0 -136
  88. package/com/param/drive.js +0 -502
  89. package/com/param/index.js +0 -158
  90. package/com/param/script.tpl.js +0 -12
  91. package/com/pendant/README.md +0 -3
  92. package/com/pendant/com.json +0 -5
  93. package/com/pendant/config.tpl.json +0 -32
  94. package/com/pendant/drive.js +0 -204
  95. package/com/pendant/index.js +0 -467
  96. package/com/pendant/pendant.html +0 -16
  97. package/com/pendant/script.tpl.js +0 -18
  98. package/com/socket/README.md +0 -47
  99. package/com/socket/com.json +0 -5
  100. package/com/socket/config.tpl.json +0 -12
  101. package/com/socket/drive.js +0 -679
  102. package/com/socket/index.js +0 -402
  103. package/com/socket/script.tpl.js +0 -41
  104. package/com/sql/README.md +0 -3
  105. package/com/sql/com.json +0 -5
  106. package/com/sql/config.tpl.json +0 -74
  107. package/com/sql/drive.js +0 -1328
  108. package/com/sql/index.js +0 -152
  109. package/com/sql/script.tpl.js +0 -47
  110. package/com/static/README.md +0 -2
  111. package/com/static/com.json +0 -5
  112. package/com/static/config.tpl.json +0 -24
  113. package/com/static/drive.js +0 -194
  114. package/com/static/index.js +0 -237
  115. package/com/static/script.tpl.js +0 -28
  116. package/com/task/README.md +0 -3
  117. package/com/task/com.json +0 -5
  118. package/com/task/config.tpl.json +0 -24
  119. package/com/task/drive.js +0 -428
  120. package/com/task/index.js +0 -159
  121. package/com/task/script.tpl.js +0 -40
  122. package/com/template/com.json +0 -5
  123. package/com/template/config.tpl.json +0 -16
  124. package/com/template/drive.js +0 -81
  125. package/com/template/index.js +0 -141
  126. package/com.js +0 -237
  127. package/common/README.md +0 -2
  128. package/common/middleware/web_after/index.js +0 -26
  129. package/common/middleware/web_after/middleware.json +0 -9
  130. package/common/middleware/web_base/index.js +0 -113
  131. package/common/middleware/web_base/middleware.json +0 -19
  132. package/common/middleware/web_before/index.js +0 -33
  133. package/common/middleware/web_before/middleware.json +0 -9
  134. package/common/middleware/web_cors/index.js +0 -87
  135. package/common/middleware/web_cors/middleware.json +0 -24
  136. package/common/middleware/web_error/index.js +0 -131
  137. package/common/middleware/web_error/middleware.json +0 -19
  138. package/common/middleware/web_ip/index.js +0 -15
  139. package/common/middleware/web_ip/middleware.json +0 -14
  140. package/common/middleware/web_logger/index.js +0 -156
  141. package/common/middleware/web_logger/middleware.json +0 -14
  142. package/common/middleware/web_main/index.js +0 -26
  143. package/common/middleware/web_main/middleware.json +0 -9
  144. package/common/middleware/web_static/index.js +0 -73
  145. package/common/middleware/web_static/middleware.json +0 -54
  146. package/common/middleware/web_waf/index.js +0 -395
  147. package/common/middleware/web_waf/middleware.json +0 -13
  148. package/core/app/config.tpl.json +0 -67
  149. package/core/app/index.js +0 -711
  150. package/core/app/script.tpl.js +0 -52
  151. package/core/channel/index.js +0 -899
  152. package/core/channel/matcher.js +0 -585
  153. package/core/com/config.tpl.json +0 -16
  154. package/core/com/index.js +0 -77
  155. package/core/com/script.tpl.js +0 -5
  156. package/core/component/component.js +0 -42
  157. package/core/component/config.tpl.json +0 -63
  158. package/core/component/index.js +0 -273
  159. package/core/component/script.tpl.js +0 -19
  160. package/core/controller/config.tpl.json +0 -14
  161. package/core/controller/index.js +0 -371
  162. package/core/controller/script.tpl.js +0 -27
  163. package/core/factory/config.tpl.json +0 -14
  164. package/core/factory/entity.js +0 -275
  165. package/core/factory/index.js +0 -241
  166. package/core/factory/script.tpl.js +0 -16
  167. package/core/game/bat/index.js +0 -137
  168. package/core/game/bat/world.js +0 -622
  169. package/core/game/config.tpl.json +0 -16
  170. package/core/game/entity_admin.js +0 -230
  171. package/core/game/index.js +0 -186
  172. package/core/handler/config.tpl.json +0 -22
  173. package/core/handler/index.js +0 -181
  174. package/core/handler/script.tpl.js +0 -23
  175. package/core/logic/config.tpl.json +0 -14
  176. package/core/logic/index.js +0 -59
  177. package/core/logic/script.tpl.js +0 -19
  178. package/core/middleware/config.tpl.json +0 -16
  179. package/core/middleware/index.js +0 -117
  180. package/core/middleware/script.tpl.js +0 -37
  181. package/core/mod/config.tpl.json +0 -22
  182. package/core/mod/index.js +0 -136
  183. package/core/mod/script.tpl.js +0 -34
  184. package/core/model/config.tpl.json +0 -219
  185. package/core/model/index.js +0 -272
  186. package/core/model/model.js +0 -27
  187. package/core/model/script.tpl.js +0 -20
  188. package/core/notifier/config.tpl.json +0 -14
  189. package/core/notifier/index.js +0 -77
  190. package/core/notifier/script.tpl.js +0 -20
  191. package/core/plugin/config.tpl.json +0 -36
  192. package/core/plugin/index.js +0 -267
  193. package/core/plugin/script.tpl.js +0 -51
  194. package/core/pusher/config.tpl.json +0 -14
  195. package/core/pusher/index.js +0 -158
  196. package/core/pusher/script.tpl.js +0 -20
  197. package/core/room/bat/index.js +0 -170
  198. package/core/room/bat/room.js +0 -524
  199. package/core/room/config.tpl.json +0 -20
  200. package/core/room/index.js +0 -249
  201. package/core/room/room.js +0 -61
  202. package/core/scene/config.tpl.json +0 -14
  203. package/core/scene/index.js +0 -467
  204. package/core/scene/loop.js +0 -1306
  205. package/core/scene/map.js +0 -28
  206. package/core/scene/script.tpl.js +0 -22
  207. package/core/sender/config.tpl.json +0 -14
  208. package/core/sender/index.js +0 -79
  209. package/core/sender/script.tpl.js +0 -20
  210. package/core/service/config.tpl.json +0 -14
  211. package/core/service/index.js +0 -100
  212. package/core/service/script.tpl.js +0 -25
  213. package/core/store/config.tpl.json +0 -26
  214. package/core/store/index.js +0 -1794
  215. package/core/store/script.tpl.js +0 -22
  216. package/core/system/config.tpl.json +0 -18
  217. package/core/system/index.js +0 -312
  218. package/core/system/script.tpl.js +0 -77
  219. package/core/view/config.tpl.json +0 -14
  220. package/core/view/index.js +0 -91
  221. package/core/view/script.tpl.js +0 -20
  222. package/core/zone/bat/index.js +0 -744
  223. package/core/zone/config.tpl.json +0 -54
  224. package/core/zone/index.js +0 -655
  225. package/core/zone/script.tpl.js +0 -10
  226. package/core/zone/zone_bat.js +0 -136
  227. package/core//345/237/272/347/261/273/346/250/241/345/235/227/346/270/205/345/215/225.md +0 -24
  228. package/os.js +0 -53
  229. package/server.js +0 -602
  230. package/ulits/id_gen.js +0 -134
  231. package/ulits/word.js +0 -206
package/core/app/index.js DELETED
@@ -1,711 +0,0 @@
1
- const compressing = require('compressing');
2
- const { Manager, Drive } = require('mm_machine');
3
- const { Plugin } = require('../plugin/index.js');
4
-
5
- /**
6
- * 应用
7
- */
8
- class App extends Drive {
9
- static config = {
10
- name: 'default',
11
- version: '1.0.0',
12
- title: '应用',
13
- description: '应用',
14
- author: 'qww',
15
- scope: 'server',
16
- dir: '',
17
- // 运行模式: 1=生产, 3=开发热重载, 根据 NODE_ENV 自动切换
18
- mode: process.env.NODE_ENV === 'production' ? 1 : 3,
19
- // // 游戏配置,非游戏模块不需要配置
20
- // 'game': {
21
- // // 游戏类型
22
- // 'type': 'card_game'
23
- // },
24
- dependencies: [],
25
- // // 压缩目录
26
- // 'zip_dir': './static/file/zip',
27
- // // 解压目录
28
- // 'unzip_dir': './static/file/unzip',
29
- // 自定义数据库 - 1 开启 0 关闭
30
- diy_sql: 0,
31
- // 自定义缓存 - 1 开启 0 关闭
32
- diy_cache: 0,
33
- // sql 配置 - 可以没有,没有则使用默认数据库
34
- sql: {
35
- // 数据库方式
36
- way: 'mysql',
37
- mysql: {
38
- // 数据库主机
39
- host: '127.0.0.1',
40
- // 数据库端口
41
- port: 3306,
42
- // 数据库用户名
43
- username: 'root',
44
- // 数据库密码
45
- password: process.env.DB_PASSWORD || '',
46
- // 数据库名称
47
- database: 'mm',
48
- },
49
- },
50
- // 缓存配置 - 可以没有,没有则使用默认缓存
51
- cache: {
52
- // 缓存方式方式
53
- way: 'redis',
54
- redis: {
55
- // 缓存主机
56
- host: '127.0.0.1',
57
- // 缓存端口
58
- port: 6379,
59
- // 缓存密码
60
- password: process.env.REDIS_PASSWORD || '',
61
- // 缓存数据库
62
- database: 0,
63
- },
64
- },
65
- };
66
- /**
67
- * 构造函数
68
- * @param {object} config 配置参数
69
- * @param {object} parent 父对象
70
- */
71
- constructor(config, parent) {
72
- super({ ...App.config, ...(config || {}) }, parent);
73
- }
74
- }
75
-
76
- /**
77
- * 预置
78
- */
79
- App.prototype._preset = function () {
80
- // 管理器集合
81
- this.manager = {};
82
-
83
- // 插件,用于功能扩展
84
- this.plugin = {};
85
-
86
- // 数据库,调用统一数据库接口,也允许重定义数据库
87
- this.sql = null;
88
- // 缓存,调用统一缓存接口,也允许重定义缓存
89
- this.cache = null;
90
- // 文件管理,调用统一文件管理接口,也允许重定义文件管理
91
- this.filer = null;
92
-
93
- /**
94
- * 获取服务器实例
95
- * @returns {object} 服务器实例对象
96
- */
97
- this.getServer = function () {
98
- return $.server;
99
- };
100
- };
101
-
102
- /**
103
- * 创建管理器实例
104
- * @param {string} name 管理器名称
105
- * @param {string} title 管理器标题
106
- * @param {Function} cls 管理器类
107
- * @returns {object} 管理器实例
108
- */
109
- App.prototype._createManager = function (name, title, cls) {
110
- let dir = this.getDir();
111
- var manager = new Manager(
112
- {
113
- name: name,
114
- title: title,
115
- filename: name + '.json',
116
- tpl_dir: `../${name}/`.fullname(__dirname),
117
- base_dir: '',
118
- dir: `./${name}`.fullname(dir),
119
- },
120
- this,
121
- this[name],
122
- cls,
123
- );
124
- this.manager[name] = manager;
125
- return manager;
126
- };
127
-
128
- /**
129
- * 初始化管理器集合
130
- * @returns {Promise<void>} 初始化完成
131
- */
132
- App.prototype._initManager = async function () {
133
- // 管理器配置列表
134
- var mgr_configs = [{ name: 'plugin', title: '插件', Module: Plugin }];
135
-
136
- // 管理器实例集合
137
- var managers = [];
138
-
139
- // 使用for循环初始化所有管理器
140
- for (var i = 0; i < mgr_configs.length; i++) {
141
- var config = mgr_configs[i];
142
- var manager = this._createManager(config.name, config.title, config.Module);
143
- managers.push(manager);
144
- }
145
-
146
- // 并行执行所有管理器的初始化操作
147
- var list = [];
148
- for (var j = 0; j < managers.length; j++) {
149
- list.push(managers[j].do('load'));
150
- }
151
-
152
- await Promise.all(list);
153
- };
154
-
155
- /**
156
- * 加载资源
157
- * @returns {Promise<void>} 加载完成
158
- */
159
- App.prototype._loadSources = async function () {
160
- await this.manager.plugin.runAll('load');
161
- };
162
-
163
- /**
164
- * 初始化资源
165
- * @returns {Promise<void>} 初始化完成
166
- */
167
- App.prototype._initSources = async function () {
168
- await this.manager.plugin.runAll(
169
- 'init',
170
- this,
171
- this.getEventer(),
172
- this.getLogger(),
173
- );
174
- };
175
-
176
- /**
177
- * 初始化核心
178
- * @param {object} server 服务器
179
- * @param {object} eventer 事件总线
180
- * @param {object} logger 日志管理器
181
- * @private
182
- */
183
- App.prototype._initCore = async function (server, eventer, logger) {
184
- if (logger) {
185
- this.setLogger(logger);
186
- }
187
- if (eventer) {
188
- this.getEventer = function () {
189
- return eventer;
190
- };
191
- }
192
- if (server) {
193
- this.getServer = function () {
194
- return server;
195
- };
196
- }
197
- // 初始化基础设施
198
- await this._initBase();
199
- // 初始化管理
200
- await this._initManager();
201
- // 加载资源
202
- await this._loadSources();
203
- // 验证依赖关系
204
- this._validateDep();
205
- };
206
-
207
- /**
208
- * 初始化基础设施
209
- * @private
210
- */
211
- App.prototype._initBase = async function () {
212
- // 初始化文件处理器
213
- this.filer = this.getServer().filer;
214
-
215
- // 初始化数据库
216
- if (this.config.diy_sql) {
217
- var cg = this.config.sql || $.config.get('sql');
218
- this.sql = sqlAdmin(this.config.name, cg);
219
- await this.sql.open();
220
- } else {
221
- this.sql = this.getServer().sql;
222
- }
223
-
224
- // 初始化缓存
225
- if (this.config.diy_cache) {
226
- var cg = this.config.cache || $.config.get('cache');
227
- this.cache = cacheAdmin(this.config.name, cg);
228
- await this.cache.connect();
229
- } else {
230
- this.cache = this.getServer().cache;
231
- }
232
- };
233
-
234
- /**
235
- * 启动资源
236
- */
237
- App.prototype._startSources = async function () {
238
- await this.manager.plugin.runAll('start');
239
- };
240
-
241
- /**
242
- * 启动核心
243
- * @private
244
- */
245
- App.prototype._startCore = async function () {
246
- // 初始化资源
247
- await this._initSources();
248
- // 启动资源
249
- await this._startSources();
250
- // 注册信号处理和全局错误处理
251
- this._signalHandle();
252
- };
253
-
254
- /**
255
- * 验证依赖关系
256
- * @private
257
- */
258
- App.prototype._validateDep = function () {
259
- var required_managers = ['plugin'];
260
-
261
- for (var name of required_managers) {
262
- if (!this.manager[name]) {
263
- throw new Error(`缺少必要的管理器: ${name}`);
264
- }
265
- }
266
- };
267
-
268
- /**
269
- * 获取压缩目录
270
- * @returns {string} 压缩目录
271
- */
272
- App.prototype.getZipDir = function () {
273
- return '/static/file/zip/'.fullname();
274
- };
275
-
276
- /**
277
- * 压缩插件
278
- * @param {string} name 插件名称
279
- * @returns {string} 打包成功返回压缩包文件地址
280
- */
281
- App.prototype.zipPlugin = async function (name) {
282
- if (!name || typeof name !== 'string') {
283
- throw new TypeError('无效的插件名称');
284
- }
285
- var plugin = this.plugin[name];
286
- if (!plugin) {
287
- throw new Error(`插件 ${name} 不存在`);
288
- }
289
- var dir = plugin.getDir();
290
- var file = ('./' + name + '.zip').fullname(this.getZipDir());
291
- return await this.zip(file, dir);
292
- };
293
-
294
- /**
295
- * 压缩目录
296
- * @param {string} file 压缩文件
297
- * @param {string} dir 要压缩的目录
298
- * @returns {string} 打包成功返回压缩包文件路径
299
- */
300
- App.prototype.zip = async function (file, dir) {
301
- var target_dir = dir || this.getZipDir();
302
- file.addDir();
303
- if (!target_dir.hasDir()) {
304
- target_dir.addDir();
305
- }
306
- // 重试压缩,避免文件在压缩过程中被修改导致 yazl 报错
307
- var max_retry = 3;
308
- for (var i = 0; i < max_retry; i++) {
309
- try {
310
- await compressing.zip.compressDir(target_dir, file);
311
- break;
312
- } catch (error) {
313
- if (
314
- i < max_retry - 1 &&
315
- error.message.includes('unexpected number of bytes')
316
- ) {
317
- // 等待后重试
318
- await new Promise((resolve) => setTimeout(resolve, 500));
319
- continue;
320
- }
321
- throw error;
322
- }
323
- }
324
- if (file.hasFile()) {
325
- return file;
326
- }
327
- return null;
328
- };
329
-
330
- /**
331
- * 解压插件
332
- * @param {object} file 插件压缩文件
333
- * @param {string} unzip_dir 要解压的目录
334
- * @returns {object} 返回解压结果
335
- */
336
- App.prototype.unzip = async function (file, unzip_dir = '/cache/unzip/') {
337
- if (!file) {
338
- throw new TypeError('无效的文件路径');
339
- }
340
- var name = file.basename().left('.');
341
- var dir = name.fullname(unzip_dir);
342
-
343
- try {
344
- // 先清理可能残留的旧解压目录,避免只读文件冲突
345
- if (dir.hasDir()) {
346
- dir.delDir();
347
- }
348
- // 确保目标目录存在
349
- dir.addDir();
350
- // 解压文件到目标目录
351
- await compressing.zip.uncompress(file, dir);
352
- // 查找目标目录
353
- var target_dir = this._findTargetDir(dir, name);
354
- // 如果找到目标目录,直接使用它作为解压结果
355
- if (target_dir) {
356
- var config_file = './plugin.json'.fullname(target_dir);
357
- if (config_file.hasFile()) {
358
- return { file, config_file, dir: target_dir, unzip_dir: dir };
359
- }
360
- }
361
- return { file, dir, unzip_dir: dir };
362
- } catch (err) {
363
- this.log('error', '插件解压失败!', err);
364
- // 清理失败的解压目录
365
- if (dir.hasDir()) {
366
- dir.delDir();
367
- }
368
- return null;
369
- }
370
- };
371
-
372
- /**
373
- * 查找目标目录
374
- * @param {string} dir 解压目录
375
- * @param {string} name 插件名称
376
- * @returns {string|null} 目标目录路径
377
- * @private
378
- */
379
- App.prototype._findTargetDir = function (dir, name) {
380
- var dir_files = $.dir.get(dir);
381
- if (!dir_files || dir_files.length === 0) {
382
- return null;
383
- }
384
- for (var i = 0; i < dir_files.length; i++) {
385
- var item = dir_files[i];
386
- if (item.hasDir()) {
387
- // 优先按名称匹配
388
- if (item.basename() === name) {
389
- var plugin_json = './plugin.json'.fullname(item);
390
- if (plugin_json.hasFile()) {
391
- return item;
392
- }
393
- }
394
- }
395
- }
396
- // 名称匹配失败时,查找任意包含 plugin.json 的子目录
397
- for (var i = 0; i < dir_files.length; i++) {
398
- var item = dir_files[i];
399
- if (item.hasDir()) {
400
- var plugin_json = './plugin.json'.fullname(item);
401
- if (plugin_json.hasFile()) {
402
- return item;
403
- }
404
- }
405
- }
406
- return null;
407
- };
408
-
409
- /**
410
- * 卸载插件
411
- * @param {string} name 插件名称
412
- * @returns {string} 返回卸载路径
413
- */
414
- App.prototype.uninstallPlugin = async function (name) {
415
- if (!name || typeof name !== 'string') {
416
- this.log('error', '卸载失败:无效的插件名称');
417
- return null;
418
- }
419
-
420
- var plugin = this.manager.plugin.get(name);
421
- if (!plugin) {
422
- this.log('error', '卸载失败:插件不存在');
423
- return null;
424
- }
425
-
426
- var dir = plugin.getDir();
427
-
428
- // 执行卸载脚本
429
- if (plugin.call) {
430
- await plugin.call('uninstall');
431
- }
432
- try {
433
- this.manager.plugin.del(name);
434
- dir.delDir();
435
- } catch (err) {
436
- this.log('error', '卸载失败:', err);
437
- return null;
438
- }
439
- };
440
-
441
- /**
442
- * 复制目录
443
- * @param {string} dir_src 原路径
444
- * @param {string} dir 新路径
445
- * @returns {object} 返回复制结果
446
- */
447
- App.prototype.copyDir = function (dir_src, dir) {
448
- return new Promise((resolve, reject) => {
449
- if (!dir_src || !dir) {
450
- this.log('error', '复制目录失败:无效的目录路径');
451
- reject(new Error('无效的目录路径'));
452
- return;
453
- }
454
-
455
- if (!dir_src.hasDir()) {
456
- this.log('error', '复制目录失败:源目录不存在');
457
- reject(new Error('源目录不存在'));
458
- return;
459
- }
460
-
461
- try {
462
- // 确保目标目录存在
463
- dir.addDir();
464
-
465
- $.dir.copy(dir_src, dir, (err) => {
466
- if (err) {
467
- this.log('error', '复制目录失败:', err);
468
- reject(err);
469
- } else {
470
- resolve({
471
- dir_src,
472
- dir,
473
- });
474
- }
475
- });
476
- } catch (err) {
477
- this.log('error', '复制目录失败:', err);
478
- reject(err);
479
- }
480
- });
481
- };
482
-
483
- /**
484
- * 解压插件
485
- * @param {object} file 插件压缩文件
486
- * @returns {object} 返回解压结果
487
- */
488
- App.prototype._unzipPlugin = async function (file) {
489
- var ret = await this.unzip(file);
490
- if (!ret) {
491
- return null;
492
- }
493
-
494
- // 直接使用解压目录作为 dir_src
495
- var dir_src = ret.dir;
496
-
497
- var config_file = './plugin.json'.fullname(dir_src);
498
-
499
- if (!config_file.hasFile()) {
500
- throw new Error('安装失败:找不到配置文件');
501
- }
502
-
503
- var config = config_file.loadJson();
504
- if (!config) {
505
- throw new Error('安装失败:配置文件无效');
506
- }
507
-
508
- var app = config.app || this.config.name;
509
- var name = config.name;
510
-
511
- if (!name) {
512
- throw new Error('安装失败:配置文件中缺少名称字段');
513
- }
514
-
515
- var dir = `/app/${app}/plugin/${name}`;
516
-
517
- await this.copyDir(dir_src, dir);
518
- ret.app = app;
519
- ret.name = name;
520
- ret.dir = dir;
521
- return ret;
522
- };
523
-
524
- /**
525
- * 安装插件
526
- * @param {object} info 插件信息
527
- * @returns {object} 返回安装结果
528
- */
529
- App.prototype._installPlugin = async function (info) {
530
- if (!info) {
531
- return null;
532
- }
533
- if (!info.config_file) {
534
- throw new Error('安装失败:找不到配置文件');
535
- }
536
-
537
- var manager = this.manager.plugin;
538
- if (info.app !== this.config.name) {
539
- var app = this.getServer().app[info.app];
540
- if (!app) {
541
- throw new Error(`安装失败:应用 ${info.app} 不存在`);
542
- }
543
- manager = app.manager.plugin;
544
- }
545
- // 只加载当前插件,而不是重载所有插件
546
- await manager.load(info.config_file);
547
-
548
- // 执行安装方法
549
- var plugin = manager.getMod(info.name);
550
- if (plugin && plugin.call) {
551
- await plugin.call('install');
552
- }
553
- return true;
554
- };
555
-
556
- /**
557
- * 安装插件
558
- * @param {string} file 插件压缩文件路径
559
- * @returns {object} 返回安装结果
560
- */
561
- App.prototype.installPlugin = async function (file) {
562
- if (!file) {
563
- throw new TypeError('无效的文件路径');
564
- }
565
-
566
- // 解压插件
567
- var info = await this._unzipPlugin(file);
568
- if (!info) {
569
- return null;
570
- }
571
- // 安装插件
572
- await this._installPlugin(info);
573
-
574
- // 清理临时目录
575
- var _this = this;
576
- this._cleanup_timer = setTimeout(() => {
577
- _this.log('info', '清理临时目录', info.unzip_dir);
578
- if (info.unzip_dir && info.unzip_dir.hasDir()) {
579
- info.unzip_dir.delDir();
580
- }
581
- }, 3000);
582
- info.zip_file = file;
583
- return info;
584
- };
585
-
586
- // 模块级单例: 每种 process 事件只注册一次, 热重载时仅切换内部引用
587
- var _app_ref = null;
588
- var _inited = false;
589
-
590
- function _initProcess() {
591
- if (_inited) return;
592
- _inited = true;
593
-
594
- process.on('SIGTERM', () => {
595
- if (_app_ref) _app_ref._onSignal('SIGTERM');
596
- });
597
- process.on('SIGINT', () => {
598
- if (_app_ref) _app_ref._onSignal('SIGINT');
599
- });
600
- process.on('uncaughtException', (err) => {
601
- if (_app_ref) {
602
- _app_ref.log('error', '未捕获异常, 进程即将退出', {
603
- message: err.message,
604
- stack: err.stack,
605
- });
606
- }
607
- process.exit(1);
608
- });
609
- process.on('unhandledRejection', (reason) => {
610
- if (_app_ref) {
611
- _app_ref.log('error', '未处理的Promise rejection', {
612
- reason: reason ? reason.message : '',
613
- stack: reason ? reason.stack : '',
614
- });
615
- }
616
- });
617
- }
618
-
619
- /**
620
- * 注册信号和错误处理, 热重载时仅更新 app 引用
621
- * @private
622
- */
623
- App.prototype._signalHandle = function () {
624
- _app_ref = this;
625
- _initProcess();
626
- };
627
-
628
- /**
629
- * 处理系统信号
630
- * @param {string} signal 信号名称
631
- * @private
632
- */
633
- App.prototype._onSignal = async function (signal) {
634
- this.log('info', `收到 ${signal} 信号, 开始优雅关闭`);
635
-
636
- try {
637
- var timeout = setTimeout(() => {
638
- this.log('warn', '优雅关闭超时, 强制退出');
639
- process.exit(1);
640
- }, 15000);
641
-
642
- await this._destroy();
643
-
644
- clearTimeout(timeout);
645
- this.log('info', '优雅关闭完成');
646
- process.exit(0);
647
- } catch (err) {
648
- this.log('error', '优雅关闭失败', err);
649
- process.exit(1);
650
- }
651
- };
652
- App.prototype._destroy = async function () {
653
- if (this._cleanup_timer) {
654
- clearTimeout(this._cleanup_timer);
655
- this._cleanup_timer = null;
656
- }
657
- if (this.config.diy_sql && this.sql && this.sql.close) {
658
- try {
659
- await this.sql.close();
660
- } catch (err) {
661
- this.log('error', '关闭数据库连接失败', err);
662
- }
663
- }
664
- if (this.config.diy_cache && this.cache && this.cache.close) {
665
- try {
666
- await this.cache.close();
667
- } catch (err) {
668
- this.log('error', '关闭缓存连接失败', err);
669
- }
670
- }
671
- };
672
-
673
- /**
674
- * 健康检查, 返回各组件状态
675
- * @returns {object} 健康状态对象
676
- */
677
- App.prototype.healthcheck = async function () {
678
- var status = {
679
- status: 'ok',
680
- uptime: process.uptime(),
681
- memory: process.memoryUsage(),
682
- timestamp: new Date().toISOString(),
683
- services: {},
684
- };
685
-
686
- // 检查数据库连接
687
- if (this.sql) {
688
- try {
689
- await this.sql.run('SELECT 1');
690
- status.services.database = 'ok';
691
- } catch {
692
- status.services.database = 'error';
693
- status.status = 'degraded';
694
- }
695
- }
696
-
697
- // 检查缓存连接
698
- if (this.cache) {
699
- try {
700
- await this.cache.ping();
701
- status.services.cache = 'ok';
702
- } catch {
703
- status.services.cache = 'error';
704
- status.status = 'degraded';
705
- }
706
- }
707
-
708
- return status;
709
- };
710
-
711
- exports.App = App;