alemonjs 2.1.16 → 2.1.18

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/README_CONFIG.md CHANGED
@@ -12,7 +12,6 @@ input: 'lib/index.js' # 应用入口文件路径,快捷参数 --input
12
12
  login: 'discord' # 登录平台标识,快捷参数 --login
13
13
  url: 'ws://127.0.0.1:17117' # CBP服务器连接地址,快捷参数 --url
14
14
  is_full_receive: false # 是否全量接收消息(用于分流处理)
15
-
16
15
  ```
17
16
 
18
17
  ### 权限管理
@@ -5,6 +5,7 @@ declare class ListNode<T> {
5
5
  }
6
6
  export declare class SinglyLinkedList<T> {
7
7
  private head;
8
+ private tail;
8
9
  private size;
9
10
  private current;
10
11
  constructor(initialValues?: T[]);
@@ -8,10 +8,12 @@ class ListNode {
8
8
  }
9
9
  class SinglyLinkedList {
10
10
  head;
11
+ tail;
11
12
  size;
12
13
  current;
13
14
  constructor(initialValues) {
14
15
  this.head = null;
16
+ this.tail = null;
15
17
  this.size = 0;
16
18
  this.current = null;
17
19
  if (initialValues) {
@@ -22,13 +24,11 @@ class SinglyLinkedList {
22
24
  const newNode = new ListNode(data);
23
25
  if (!this.head) {
24
26
  this.head = newNode;
27
+ this.tail = newNode;
25
28
  }
26
29
  else {
27
- let current = this.head;
28
- while (current.next) {
29
- current = current.next;
30
- }
31
- current.next = newNode;
30
+ this.tail.next = newNode;
31
+ this.tail = newNode;
32
32
  }
33
33
  this.size++;
34
34
  }
@@ -42,11 +42,14 @@ class SinglyLinkedList {
42
42
  return this.current;
43
43
  }
44
44
  removeCurrent() {
45
- if (!this.head) {
45
+ if (!this.head || !this.current) {
46
46
  return;
47
47
  }
48
48
  if (this.current === this.head) {
49
49
  this.head = this.head.next;
50
+ if (!this.head) {
51
+ this.tail = null;
52
+ }
50
53
  this.current = null;
51
54
  this.size--;
52
55
  return;
@@ -57,6 +60,9 @@ class SinglyLinkedList {
57
60
  }
58
61
  if (previous && this.current) {
59
62
  previous.next = this.current.next;
63
+ if (this.current === this.tail) {
64
+ this.tail = previous;
65
+ }
60
66
  this.current = null;
61
67
  this.size--;
62
68
  }
@@ -0,0 +1,4 @@
1
+ export declare const SubscribeStatus: {
2
+ active: 'active';
3
+ paused: 'paused';
4
+ };
@@ -0,0 +1,6 @@
1
+ const SubscribeStatus = {
2
+ active: 'active',
3
+ paused: 'paused'
4
+ };
5
+
6
+ export { SubscribeStatus };
@@ -1,5 +1,6 @@
1
1
  type Options = {
2
2
  main: () => any;
3
+ name?: string;
3
4
  };
4
5
  export declare const definePlatform: (options: Options) => () => any;
5
6
  export {};
@@ -1,13 +1,14 @@
1
1
  const definePlatform = (options) => {
2
+ const platformName = options.name || process.env.platform || 'unknown';
2
3
  const mainProcess = () => {
3
4
  ['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
4
5
  process?.on?.(sig, () => {
5
- logger.info?.(`[@alemonjs/qq-bot][${sig}] 收到信号,正在关闭...`);
6
+ logger.info?.(`[${platformName}][${sig}] 收到信号,正在关闭...`);
6
7
  setImmediate(() => process.exit(0));
7
8
  });
8
9
  });
9
10
  process?.on?.('exit', code => {
10
- logger.info?.(`[@alemonjs/qq-bot][exit] 进程退出,code=${code}`);
11
+ logger.info?.(`[${platformName}][exit] 进程退出,code=${code}`);
11
12
  });
12
13
  process.on('message', msg => {
13
14
  try {
@@ -1,4 +1,3 @@
1
- import { isAsyncFunction } from 'util/types';
2
1
  import 'fs';
3
2
  import 'path';
4
3
  import 'yaml';
@@ -42,20 +41,11 @@ const createCallHandler = valueEvent => {
42
41
  return;
43
42
  }
44
43
  try {
45
- if (isAsyncFunction(currents[index])) {
46
- const res = await currents[index](valueEvent, (...cns) => {
47
- isNext = true;
48
- nextEvent(...cns);
49
- });
50
- onRes(res);
51
- }
52
- else {
53
- const res = currents[index](valueEvent, (...cns) => {
54
- isNext = true;
55
- nextEvent(...cns);
56
- });
57
- onRes(res);
58
- }
44
+ const res = await currents[index](valueEvent, (...cns) => {
45
+ isNext = true;
46
+ nextEvent(...cns);
47
+ });
48
+ onRes(res);
59
49
  }
60
50
  catch (err) {
61
51
  showErrorModule(err);
@@ -1,2 +1,3 @@
1
1
  import { Next, Events, EventKeys, StoreResponseItem } from '../types';
2
+ export declare const clearModuleCache: (path?: string) => void;
2
3
  export declare const createNextStep: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, files: StoreResponseItem[], callHandler: (currents: any, nextEvent: any) => void) => Next;
@@ -3,9 +3,26 @@ import { showErrorModule } from '../core/utils.js';
3
3
  import { EventMessageText } from '../core/variable.js';
4
4
  import { ResponseMiddleware } from './store.js';
5
5
 
6
+ const moduleCache = new Map();
7
+ const clearModuleCache = (path) => {
8
+ if (path) {
9
+ moduleCache.delete(path);
10
+ }
11
+ else {
12
+ moduleCache.clear();
13
+ }
14
+ };
15
+ const loadModule = async (filePath) => {
16
+ if (moduleCache.has(filePath)) {
17
+ return moduleCache.get(filePath);
18
+ }
19
+ const mod = await import(`file://${filePath}`);
20
+ moduleCache.set(filePath, mod);
21
+ return mod;
22
+ };
6
23
  const callHandlerFile = async (valueEvent, select, file, nextStep, callback) => {
7
24
  try {
8
- const app = await import(`file://${file.path}`);
25
+ const app = await loadModule(file.path);
9
26
  if (!app?.default?.current || !app?.default?.select) {
10
27
  nextStep();
11
28
  return;
@@ -88,4 +105,4 @@ const createNextStep = (valueEvent, select, next, files, callHandler) => {
88
105
  return nextStep;
89
106
  };
90
107
 
91
- export { createNextStep };
108
+ export { clearModuleCache, createNextStep };
@@ -1,4 +1,3 @@
1
- import { isAsyncFunction } from 'util/types';
2
1
  import { EventMessageText } from '../core/variable.js';
3
2
  import 'fs';
4
3
  import 'path';
@@ -45,7 +44,7 @@ const createRouteProcessChildren = (valueEvent, select, nextCycle, callHandler)
45
44
  try {
46
45
  const currents = [];
47
46
  for (const item of currentsAndMiddleware) {
48
- const app = isAsyncFunction(item) ? await item() : item();
47
+ const app = await item();
49
48
  const selects = Array.isArray(app.select) ? app.select : [app.select];
50
49
  if (!selects.includes(select)) {
51
50
  void nextNode();
@@ -3,13 +3,13 @@ import { createCallHandler } from './event-processor-callHandler.js';
3
3
  import { createNextStep } from './event-processor-cycleFiles.js';
4
4
  import { createRouteProcessChildren } from './event-processor-cycleRoute.js';
5
5
 
6
+ const responseSingleton = new Response();
7
+ const responseRouterSingleton = new ResponseRouter();
6
8
  const expendEvent = (valueEvent, select, next) => {
7
- const res = new Response();
8
- const StoreResponse = res.value;
9
+ const StoreResponse = responseSingleton.value;
9
10
  const callHandler = createCallHandler(valueEvent);
10
11
  const nextEvent = createNextStep(valueEvent, select, next, StoreResponse, callHandler);
11
- const resRoute = new ResponseRouter();
12
- const routes = resRoute.value;
12
+ const routes = responseRouterSingleton.value;
13
13
  const callRouteHandler = createCallHandler(valueEvent);
14
14
  const processChildren = createRouteProcessChildren(valueEvent, select, nextEvent, callRouteHandler);
15
15
  void processChildren(routes, [], nextEvent);
@@ -3,13 +3,13 @@ import { createCallHandler } from './event-processor-callHandler.js';
3
3
  import { createNextStep } from './event-processor-cycleFiles.js';
4
4
  import { createRouteProcessChildren } from './event-processor-cycleRoute.js';
5
5
 
6
+ const middlewareSingleton = new Middleware();
7
+ const middlewareRouterSingleton = new MiddlewareRouter();
6
8
  const expendMiddleware = (valueEvent, select, next) => {
7
- const mw = new Middleware();
8
- const mwFiles = mw.value;
9
+ const mwFiles = middlewareSingleton.value;
9
10
  const callHandler = createCallHandler(valueEvent);
10
11
  const nextMiddleware = createNextStep(valueEvent, select, next, mwFiles, callHandler);
11
- const resRoute = new MiddlewareRouter();
12
- const routes = resRoute.value;
12
+ const routes = middlewareRouterSingleton.value;
13
13
  const callRouteHandler = createCallHandler(valueEvent);
14
14
  const processChildren = createRouteProcessChildren(valueEvent, select, nextMiddleware, callRouteHandler);
15
15
  void processChildren(routes, [], nextMiddleware);
@@ -1,5 +1,5 @@
1
1
  import { Next, Events, EventCycleEnum, EventKeys } from '../types';
2
- export declare const expendSubscribe: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, chioce: EventCycleEnum) => void;
2
+ export declare const expendSubscribe: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, choose: EventCycleEnum) => void;
3
3
  export declare const expendSubscribeCreate: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next) => void;
4
4
  export declare const expendSubscribeMount: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next) => void;
5
5
  export declare const expendSubscribeUnmount: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next) => void;
@@ -1,7 +1,8 @@
1
1
  import { SubscribeList } from './store.js';
2
+ import { SubscribeStatus } from './config.js';
2
3
 
3
- const expendSubscribe = (valueEvent, select, next, chioce) => {
4
- const subList = new SubscribeList(chioce, select);
4
+ const expendSubscribe = (valueEvent, select, next, choose) => {
5
+ const subList = new SubscribeList(choose, select);
5
6
  const nextObserver = (cn, ...cns) => {
6
7
  if (cn) {
7
8
  next(...cns);
@@ -12,45 +13,58 @@ const expendSubscribe = (valueEvent, select, next, chioce) => {
12
13
  nextObserver(true);
13
14
  return;
14
15
  }
16
+ const selects = item.data.selects;
17
+ const ID = item.data.id;
18
+ if (item.data.status === SubscribeStatus.paused) {
19
+ subList.value.removeCurrent();
20
+ nextObserver();
21
+ return;
22
+ }
15
23
  for (const key in item.data.keys) {
16
24
  if (item.data.keys[key] !== valueEvent[key]) {
17
25
  nextObserver();
18
26
  return;
19
27
  }
20
28
  }
21
- const clear = () => {
22
- const selects = item.data.selects;
23
- const ID = item.data.id;
29
+ const onActive = () => {
24
30
  for (const select of selects) {
25
- const subList = new SubscribeList(chioce, select);
26
- const remove = () => {
31
+ const subList = new SubscribeList(choose, select);
32
+ const find = () => {
27
33
  const item = subList.value.popNext();
28
- if (!item || item.data.id !== ID) {
29
- remove();
34
+ if (!item) {
35
+ return;
36
+ }
37
+ if (item.data.id !== ID) {
38
+ find();
30
39
  return;
31
40
  }
32
- subList.value.removeCurrent();
41
+ item.data.status = SubscribeStatus.active;
33
42
  };
34
- remove();
43
+ find();
35
44
  }
36
45
  };
37
- const restore = () => {
38
- const selects = item.data.selects;
46
+ const onPaused = () => {
39
47
  for (const select of selects) {
40
- const subList = new SubscribeList(chioce, select);
41
- subList.value.append(item.data);
48
+ const subList = new SubscribeList(choose, select);
49
+ const find = () => {
50
+ const item = subList.value.popNext();
51
+ if (!item) {
52
+ return;
53
+ }
54
+ if (item.data.id !== ID) {
55
+ find();
56
+ return;
57
+ }
58
+ item.data.status = SubscribeStatus.paused;
59
+ };
60
+ find();
42
61
  }
43
62
  };
44
- clear();
63
+ onPaused();
45
64
  const Continue = (cn, ...cns) => {
46
- restore();
65
+ onActive();
47
66
  if (cn) {
48
67
  nextObserver(...cns);
49
- return;
50
- }
51
- if (typeof cn === 'boolean') {
52
- clear();
53
- nextObserver(...cns);
54
68
  }
55
69
  };
56
70
  item.data.current(valueEvent, Continue);
@@ -1,7 +1,7 @@
1
1
  import { getConfigValue } from '../core/config.js';
2
- import { processorRepeatedClearTimeMin, processorRepeatedClearTimeMax, processorRepeatedEventTime, processorRepeatedUserTime, processorPepeatedClearSize } from '../core/variable.js';
2
+ import { processorRepeatedClearTimeMin, processorRepeatedClearTimeMax, processorRepeatedEventTime, processorRepeatedUserTime, processorRepeatedClearSize, processorMaxMapSize } from '../core/variable.js';
3
3
  import { expendCycle } from './event-processor-cycle.js';
4
- import { ProcessorEventAutoClearMap, ProcessorEventUserAudoClearMap } from './store.js';
4
+ import { ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap } from './store.js';
5
5
  import { createHash } from '../core/utils.js';
6
6
 
7
7
  const filter = ({ Now, store, INTERVAL }, MessageId) => {
@@ -12,6 +12,15 @@ const filter = ({ Now, store, INTERVAL }, MessageId) => {
12
12
  return true;
13
13
  }
14
14
  }
15
+ if (store.size >= processorMaxMapSize) {
16
+ cleanupStore({ Now, store, INTERVAL });
17
+ if (store.size >= processorMaxMapSize) {
18
+ const firstKey = store.keys().next().value;
19
+ if (firstKey !== undefined) {
20
+ store.delete(firstKey);
21
+ }
22
+ }
23
+ }
15
24
  store.set(MessageId, Date.now());
16
25
  };
17
26
  const cleanupStore = ({ Now, store, INTERVAL }) => {
@@ -27,12 +36,12 @@ const cleanupStoreAll = () => {
27
36
  const EVENT_INTERVAL = value?.processor?.repeated_event_time ?? processorRepeatedEventTime;
28
37
  const USER_INTERVAL = value?.processor?.repeated_user_time ?? processorRepeatedUserTime;
29
38
  cleanupStore({ Now, INTERVAL: EVENT_INTERVAL, store: ProcessorEventAutoClearMap });
30
- cleanupStore({ Now, INTERVAL: USER_INTERVAL, store: ProcessorEventUserAudoClearMap });
39
+ cleanupStore({ Now, INTERVAL: USER_INTERVAL, store: ProcessorEventUserAutoClearMap });
31
40
  };
32
41
  const callback = () => {
33
42
  cleanupStoreAll();
34
- const length = ProcessorEventAutoClearMap.size + ProcessorEventUserAudoClearMap.size;
35
- const time = length > processorPepeatedClearSize ? processorRepeatedClearTimeMin : processorRepeatedClearTimeMax;
43
+ const length = ProcessorEventAutoClearMap.size + ProcessorEventUserAutoClearMap.size;
44
+ const time = length > processorRepeatedClearSize ? processorRepeatedClearTimeMin : processorRepeatedClearTimeMax;
36
45
  setTimeout(callback, time);
37
46
  };
38
47
  setTimeout(callback, processorRepeatedClearTimeMin);
@@ -103,7 +112,7 @@ const onProcessor = (name, event, data) => {
103
112
  const USER_INTERVAL = value?.processor?.repeated_user_time ?? processorRepeatedUserTime;
104
113
  if (event['UserId']) {
105
114
  const UserId = createHash(event['UserId']);
106
- if (filter({ Now, INTERVAL: USER_INTERVAL, store: ProcessorEventUserAudoClearMap }, UserId)) {
115
+ if (filter({ Now, INTERVAL: USER_INTERVAL, store: ProcessorEventUserAutoClearMap }, UserId)) {
107
116
  return;
108
117
  }
109
118
  }
@@ -1,5 +1,6 @@
1
1
  import { ResultCode } from '../core/variable.js';
2
2
  import { SubscribeList } from './store.js';
3
+ import { SubscribeStatus } from './config.js';
3
4
 
4
5
  const useSubscribe = (event, selects) => {
5
6
  if (typeof event !== 'object') {
@@ -44,6 +45,7 @@ const useSubscribe = (event, selects) => {
44
45
  selects: curSelects,
45
46
  keys: values,
46
47
  current: callback,
48
+ status: SubscribeStatus.active,
47
49
  id: ID
48
50
  });
49
51
  }
@@ -67,15 +69,18 @@ const useSubscribe = (event, selects) => {
67
69
  const ID = value.id;
68
70
  for (const select of selects) {
69
71
  const subList = new SubscribeList(value.choose, select);
70
- const remove = () => {
72
+ const find = () => {
71
73
  const item = subList.value.popNext();
72
- if (!item || item.data.id !== ID) {
73
- remove();
74
+ if (!item) {
74
75
  return;
75
76
  }
76
- subList.value.removeCurrent();
77
+ if (item.data.id !== ID) {
78
+ find();
79
+ return;
80
+ }
81
+ item.data.status = SubscribeStatus.paused;
77
82
  };
78
- remove();
83
+ find();
79
84
  }
80
85
  };
81
86
  const subscribe = {
package/lib/app/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAudoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger } from './store.js';
1
+ export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger } from './store.js';
2
2
  export { loadModels, run } from './load_modules/load.js';
3
3
  export { loadChildren, loadChildrenFile } from './load_modules/loadChild.js';
4
4
  export { defineChildren } from './define-children.js';
@@ -40,7 +40,7 @@ const loadChildren = async (mainPath, appName) => {
40
40
  else {
41
41
  app = await moduleApp.default.callback();
42
42
  }
43
- App.pushSycle(app);
43
+ App.pushCycle(app);
44
44
  const unMounted = async (e) => {
45
45
  showErrorModule(e);
46
46
  App.un();
@@ -87,7 +87,7 @@ const loadChildren = async (mainPath, appName) => {
87
87
  for (const file of files) {
88
88
  const url = file.path.replace(mainDir, '');
89
89
  const stateKey = createEventName(url, appName);
90
- const reesponse = {
90
+ const responseItem = {
91
91
  input: mainDir,
92
92
  dir: dirname(file.path),
93
93
  path: file.path,
@@ -95,7 +95,7 @@ const loadChildren = async (mainPath, appName) => {
95
95
  stateKey,
96
96
  appName: appName
97
97
  };
98
- resData.push(reesponse);
98
+ resData.push(responseItem);
99
99
  }
100
100
  App.pushResponse(resData);
101
101
  const responseAndMiddlewareFiles = getRecursiveDirFiles(responseDir, item => fileSuffixMiddleware.test(item.name));
@@ -103,7 +103,7 @@ const loadChildren = async (mainPath, appName) => {
103
103
  for (const file of responseAndMiddlewareFiles) {
104
104
  const url = file.path.replace(mainDir, '');
105
105
  const stateKey = createEventName(url, appName);
106
- const reesponse = {
106
+ const responseItem = {
107
107
  input: mainDir,
108
108
  dir: dirname(file.path),
109
109
  path: file.path,
@@ -111,7 +111,7 @@ const loadChildren = async (mainPath, appName) => {
111
111
  stateKey,
112
112
  appName: appName
113
113
  };
114
- resAndMwData[stateKey] = reesponse;
114
+ resAndMwData[stateKey] = responseItem;
115
115
  }
116
116
  App.pushResponseMiddleware(resAndMwData);
117
117
  const mwDir = join(mainDir, 'middleware');
@@ -33,7 +33,7 @@ export declare class Middleware {
33
33
  }
34
34
  export declare class SubscribeList<T extends EventKeys> {
35
35
  #private;
36
- constructor(chioce: EventCycleEnum, select: T);
36
+ constructor(choice: EventCycleEnum, select: T);
37
37
  get value(): SinglyLinkedList<SubscribeValue>;
38
38
  }
39
39
  export declare class StateSubscribe {
@@ -58,13 +58,13 @@ export declare class ChildrenApp {
58
58
  [key: string]: StoreResponseItem;
59
59
  }): void;
60
60
  pushMiddleware(data: StoreMiddlewareItem[]): void;
61
- pushSycle(data: ChildrenCycle): void;
61
+ pushCycle(data: ChildrenCycle): void;
62
62
  on(): void;
63
63
  un(): void;
64
64
  get value(): import("..").StoreChildrenApp;
65
65
  }
66
66
  export declare const ProcessorEventAutoClearMap: Map<any, any>;
67
- export declare const ProcessorEventUserAudoClearMap: Map<any, any>;
67
+ export declare const ProcessorEventUserAutoClearMap: Map<any, any>;
68
68
  export declare const logger: any;
69
69
  export declare const core: {
70
70
  storeState: import("..").ResponseState;
package/lib/app/store.js CHANGED
@@ -178,16 +178,16 @@ class Middleware {
178
178
  }
179
179
  class SubscribeList {
180
180
  #select;
181
- #chioce;
182
- constructor(chioce, select) {
181
+ #choice;
182
+ constructor(choice, select) {
183
183
  this.#select = select;
184
- this.#chioce = chioce;
185
- if (!alemonjsCore.storeSubscribeList[this.#chioce].has(this.#select)) {
186
- alemonjsCore.storeSubscribeList[this.#chioce].set(this.#select, new SinglyLinkedList());
184
+ this.#choice = choice;
185
+ if (!alemonjsCore.storeSubscribeList[this.#choice].has(this.#select)) {
186
+ alemonjsCore.storeSubscribeList[this.#choice].set(this.#select, new SinglyLinkedList());
187
187
  }
188
188
  }
189
189
  get value() {
190
- return alemonjsCore.storeSubscribeList[this.#chioce].get(this.#select);
190
+ return alemonjsCore.storeSubscribeList[this.#choice].get(this.#select);
191
191
  }
192
192
  }
193
193
  class StateSubscribe {
@@ -269,7 +269,7 @@ class ChildrenApp {
269
269
  pushMiddleware(data) {
270
270
  this.#middleware = this.#middleware.concat(data);
271
271
  }
272
- pushSycle(data) {
272
+ pushCycle(data) {
273
273
  this.#cycle = data;
274
274
  }
275
275
  on() {
@@ -293,7 +293,7 @@ class ChildrenApp {
293
293
  }
294
294
  }
295
295
  const ProcessorEventAutoClearMap = new Map();
296
- const ProcessorEventUserAudoClearMap = new Map();
296
+ const ProcessorEventUserAutoClearMap = new Map();
297
297
  const logger = new Logger().value;
298
298
  const core = new Core().value;
299
299
  ['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
@@ -305,4 +305,4 @@ process?.on?.('exit', code => {
305
305
  logger.info?.(`[alemonjs][exit] 进程退出,code=${code}`);
306
306
  });
307
307
 
308
- export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAudoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger };
308
+ export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger };
@@ -0,0 +1,15 @@
1
+ export type WSConnectorOptions = {
2
+ url: string;
3
+ role: 'client' | 'platform';
4
+ onOpen?: () => void;
5
+ onMessage: (message: string) => void;
6
+ extraHeaders?: Record<string, string>;
7
+ globalKey: 'chatbotClient' | 'chatbotPlatform';
8
+ };
9
+ export declare const createWSConnector: (options: WSConnectorOptions) => {
10
+ heartbeatControl: {
11
+ start: () => void;
12
+ stop: () => void;
13
+ pong: () => void;
14
+ };
15
+ };
@@ -0,0 +1,77 @@
1
+ import { WebSocket } from 'ws';
2
+ import { ResultCode } from '../../core/variable.js';
3
+ import 'fs';
4
+ import 'path';
5
+ import 'yaml';
6
+ import '../../core/utils.js';
7
+ import { deviceId, DEVICE_ID_HEADER, USER_AGENT_HEADER, reconnectInterval } from '../processor/config.js';
8
+ import { useHeartbeat } from './connect.js';
9
+
10
+ const createWSConnector = (options) => {
11
+ const { url, role, onOpen, onMessage, extraHeaders = {}, globalKey } = options;
12
+ if (global[globalKey]) {
13
+ delete global[globalKey];
14
+ }
15
+ const [heartbeatControl] = useHeartbeat({
16
+ ping: () => {
17
+ global?.[globalKey]?.ping?.();
18
+ },
19
+ isConnected: () => {
20
+ return global?.[globalKey] && global?.[globalKey]?.readyState === WebSocket.OPEN;
21
+ },
22
+ terminate: () => {
23
+ try {
24
+ global?.[globalKey]?.terminate?.();
25
+ }
26
+ catch (error) {
27
+ logger.debug({
28
+ code: ResultCode.Fail,
29
+ message: '强制断开连接失败',
30
+ data: error
31
+ });
32
+ }
33
+ }
34
+ });
35
+ const start = () => {
36
+ global[globalKey] = new WebSocket(url, {
37
+ headers: {
38
+ [USER_AGENT_HEADER]: role,
39
+ [DEVICE_ID_HEADER]: deviceId,
40
+ ...extraHeaders
41
+ }
42
+ });
43
+ global[globalKey].on('open', () => {
44
+ onOpen?.();
45
+ heartbeatControl.start();
46
+ });
47
+ global[globalKey].on('pong', () => {
48
+ heartbeatControl.pong();
49
+ });
50
+ global[globalKey].on('message', (message) => {
51
+ onMessage(message.toString());
52
+ });
53
+ global[globalKey].on('close', (code) => {
54
+ heartbeatControl.stop();
55
+ logger.warn({
56
+ code: ResultCode.Fail,
57
+ message: `${role} 连接关闭,尝试重新连接...`,
58
+ data: code
59
+ });
60
+ delete global[globalKey];
61
+ setTimeout(() => {
62
+ start();
63
+ }, reconnectInterval);
64
+ });
65
+ global[globalKey].on('error', (err) => {
66
+ logger.error({
67
+ code: ResultCode.Fail,
68
+ message: `${role} 端错误`,
69
+ data: err
70
+ });
71
+ });
72
+ };
73
+ start();
74
+ return { heartbeatControl };
75
+ };
76
+
77
+ export { createWSConnector };
@@ -1,4 +1,3 @@
1
- import { WebSocket } from 'ws';
2
1
  import * as flattedJSON from 'flatted';
3
2
  import '../../app/store.js';
4
3
  import 'fs';
@@ -13,57 +12,26 @@ import '../../app/event-group.js';
13
12
  import '../../app/event-middleware.js';
14
13
  import { onProcessor } from '../../app/event-processor.js';
15
14
  import '../../app/event-response.js';
16
- import 'util/types';
17
15
  import { createResult } from '../../core/utils.js';
18
16
  import '../../app/hook-use-api.js';
19
17
  import '../../app/message-api.js';
20
18
  import '../../app/message-format.js';
21
- import { deviceId, FULL_RECEIVE_HEADER, DEVICE_ID_HEADER, USER_AGENT_HEADER, apiResolves, apiTimeouts, actionResolves, actionTimeouts, reconnectInterval } from '../processor/config.js';
22
- import { useHeartbeat } from './connect.js';
19
+ import { apiResolves, apiTimeouts, actionResolves, actionTimeouts, FULL_RECEIVE_HEADER } from '../processor/config.js';
20
+ import { createWSConnector } from './base.js';
23
21
 
24
22
  const cbpClient = (url, options = {}) => {
25
- if (global.chatbotClient) {
26
- delete global.chatbotClient;
27
- }
28
23
  const { open = () => { }, isFullReceive = true } = options;
29
- const [heartbeatControl] = useHeartbeat({
30
- ping: () => {
31
- global?.chatbotClient?.ping?.();
24
+ createWSConnector({
25
+ url,
26
+ role: 'client',
27
+ globalKey: 'chatbotClient',
28
+ extraHeaders: {
29
+ [FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
32
30
  },
33
- isConnected: () => {
34
- return global?.chatbotClient && global?.chatbotClient?.readyState === WebSocket.OPEN;
35
- },
36
- terminate: () => {
31
+ onOpen: open,
32
+ onMessage: (messageStr) => {
37
33
  try {
38
- global?.chatbotClient?.terminate?.();
39
- }
40
- catch (error) {
41
- logger.debug({
42
- code: ResultCode.Fail,
43
- message: '强制断开连接失败',
44
- data: error
45
- });
46
- }
47
- }
48
- });
49
- const start = () => {
50
- global.chatbotClient = new WebSocket(url, {
51
- headers: {
52
- [USER_AGENT_HEADER]: 'client',
53
- [DEVICE_ID_HEADER]: deviceId,
54
- [FULL_RECEIVE_HEADER]: isFullReceive ? '1' : '0'
55
- }
56
- });
57
- global.chatbotClient.on('open', () => {
58
- open();
59
- heartbeatControl.start();
60
- });
61
- global.chatbotClient.on('pong', () => {
62
- heartbeatControl.pong();
63
- });
64
- global.chatbotClient.on('message', message => {
65
- try {
66
- const parsedMessage = flattedJSON.parse(message.toString());
34
+ const parsedMessage = flattedJSON.parse(messageStr);
67
35
  if (parsedMessage?.activeId) {
68
36
  if (parsedMessage.active === 'sync') {
69
37
  const configs = parsedMessage.payload;
@@ -118,28 +86,8 @@ const cbpClient = (url, options = {}) => {
118
86
  data: error
119
87
  });
120
88
  }
121
- });
122
- global.chatbotClient.on('close', () => {
123
- heartbeatControl.stop();
124
- logger.warn({
125
- code: ResultCode.Fail,
126
- message: '连接关闭,尝试重新连接...',
127
- data: null
128
- });
129
- delete global.chatbotClient;
130
- setTimeout(() => {
131
- start();
132
- }, reconnectInterval);
133
- });
134
- global.chatbotClient.on('error', err => {
135
- logger.error({
136
- code: ResultCode.Fail,
137
- message: '客户端错误',
138
- data: err
139
- });
140
- });
141
- };
142
- start();
89
+ }
90
+ });
143
91
  };
144
92
 
145
93
  export { cbpClient };
@@ -1,40 +1,17 @@
1
1
  import * as flattedJSON from 'flatted';
2
2
  import { WebSocket } from 'ws';
3
- import { deviceId, DEVICE_ID_HEADER, USER_AGENT_HEADER, reconnectInterval } from '../processor/config.js';
3
+ import { deviceId } from '../processor/config.js';
4
4
  import { ResultCode } from '../../core/variable.js';
5
5
  import 'fs';
6
6
  import 'path';
7
7
  import 'yaml';
8
8
  import '../../core/utils.js';
9
- import { useHeartbeat } from './connect.js';
9
+ import { createWSConnector } from './base.js';
10
10
 
11
11
  const cbpPlatform = (url, options = {
12
12
  open: () => { }
13
13
  }) => {
14
- if (global.chatbotPlatform) {
15
- delete global.chatbotPlatform;
16
- }
17
14
  const { open = () => { } } = options;
18
- const [heartbeatControl] = useHeartbeat({
19
- ping: () => {
20
- global?.chatbotPlatform?.ping?.();
21
- },
22
- isConnected: () => {
23
- return global?.chatbotPlatform && global?.chatbotPlatform?.readyState === WebSocket.OPEN;
24
- },
25
- terminate: () => {
26
- try {
27
- global?.chatbotPlatform?.terminate?.();
28
- }
29
- catch (error) {
30
- logger.debug({
31
- code: ResultCode.Fail,
32
- message: '强制断开连接失败',
33
- data: error
34
- });
35
- }
36
- }
37
- });
38
15
  const send = (data) => {
39
16
  if (global.chatbotPlatform && global.chatbotPlatform.readyState === WebSocket.OPEN) {
40
17
  data.DeviceId = deviceId;
@@ -69,23 +46,14 @@ const cbpPlatform = (url, options = {
69
46
  const onapis = (reply) => {
70
47
  apiReplys.push(reply);
71
48
  };
72
- const start = () => {
73
- global.chatbotPlatform = new WebSocket(url, {
74
- headers: {
75
- [USER_AGENT_HEADER]: 'platform',
76
- [DEVICE_ID_HEADER]: deviceId
77
- }
78
- });
79
- global.chatbotPlatform.on('open', () => {
80
- open();
81
- heartbeatControl.start();
82
- });
83
- global.chatbotPlatform.on('pong', () => {
84
- heartbeatControl.pong();
85
- });
86
- global.chatbotPlatform.on('message', message => {
49
+ createWSConnector({
50
+ url,
51
+ role: 'platform',
52
+ globalKey: 'chatbotPlatform',
53
+ onOpen: open,
54
+ onMessage: (messageStr) => {
87
55
  try {
88
- const data = flattedJSON.parse(message.toString());
56
+ const data = flattedJSON.parse(messageStr);
89
57
  if (data.apiId) {
90
58
  for (const cb of apiReplys) {
91
59
  void cb(data, val => replyApi(data, val));
@@ -104,28 +72,8 @@ const cbpPlatform = (url, options = {
104
72
  data: error
105
73
  });
106
74
  }
107
- });
108
- global.chatbotPlatform.on('close', err => {
109
- heartbeatControl.stop();
110
- logger.warn({
111
- code: ResultCode.Fail,
112
- message: '平台端连接关闭,尝试重新连接...',
113
- data: err
114
- });
115
- delete global.chatbotPlatform;
116
- setTimeout(() => {
117
- start();
118
- }, reconnectInterval);
119
- });
120
- global.chatbotPlatform.on('error', err => {
121
- logger.error({
122
- code: ResultCode.Fail,
123
- message: '平台端错误',
124
- data: err
125
- });
126
- });
127
- };
128
- start();
75
+ }
76
+ });
129
77
  const client = {
130
78
  send,
131
79
  onactions,
@@ -0,0 +1,3 @@
1
+ import { Result } from '../../core';
2
+ import type { Apis } from '../../types';
3
+ export declare const sendAPI: (data: Apis) => Promise<Result[]>;
@@ -0,0 +1,32 @@
1
+ import { ResultCode } from '../../core/variable.js';
2
+ import 'fs';
3
+ import 'path';
4
+ import 'yaml';
5
+ import { createResult } from '../../core/utils.js';
6
+ import { generateUniqueId, deviceId, apiResolves, apiTimeouts, timeoutTime } from './config.js';
7
+ import * as flattedJSON from 'flatted';
8
+
9
+ const sendAPI = (data) => {
10
+ const ApiId = generateUniqueId();
11
+ return new Promise(resolve => {
12
+ if (!global.chatbotClient?.send) {
13
+ resolve([createResult(ResultCode.Fail, 'Chatbot client is not available', null)]);
14
+ return;
15
+ }
16
+ data.apiId = ApiId;
17
+ data.DeviceId = deviceId;
18
+ global.chatbotClient?.send(flattedJSON.stringify(data));
19
+ apiResolves.set(ApiId, resolve);
20
+ const timeout = setTimeout(() => {
21
+ if (!apiResolves.has(ApiId) || !apiTimeouts.has(ApiId)) {
22
+ return;
23
+ }
24
+ apiResolves.delete(ApiId);
25
+ apiTimeouts.delete(ApiId);
26
+ resolve([createResult(ResultCode.Fail, '接口超时', null)]);
27
+ }, timeoutTime);
28
+ apiTimeouts.set(ApiId, timeout);
29
+ });
30
+ };
31
+
32
+ export { sendAPI };
@@ -11,27 +11,7 @@ import '../../core/utils.js';
11
11
  import { USER_AGENT_HEADER, USER_AGENT_HEADER_VALUE_MAP, DEVICE_ID_HEADER, FULL_RECEIVE_HEADER, platformClient, childrenClient, fullClient, childrenBind } from '../processor/config.js';
12
12
  import { createTestOneController } from './testone.js';
13
13
 
14
- const handleApi = (DeviceId, message) => {
15
- if (childrenClient.has(DeviceId)) {
16
- const clientWs = childrenClient.get(DeviceId);
17
- if (clientWs && clientWs.readyState === WebSocket.OPEN) {
18
- clientWs.send(message);
19
- }
20
- else {
21
- childrenClient.delete(DeviceId);
22
- }
23
- }
24
- else if (fullClient.has(DeviceId)) {
25
- const clientWs = fullClient.get(DeviceId);
26
- if (clientWs && clientWs.readyState === WebSocket.OPEN) {
27
- clientWs.send(message);
28
- }
29
- else {
30
- fullClient.delete(DeviceId);
31
- }
32
- }
33
- };
34
- const handleAction = (DeviceId, message) => {
14
+ const routeMessageToDevice = (DeviceId, message) => {
35
15
  if (childrenClient.has(DeviceId)) {
36
16
  const clientWs = childrenClient.get(DeviceId);
37
17
  if (clientWs && clientWs.readyState === WebSocket.OPEN) {
@@ -209,11 +189,11 @@ const setPlatformClient = (originId, ws) => {
209
189
  });
210
190
  if (parsedMessage.apiId) {
211
191
  const DeviceId = parsedMessage.DeviceId;
212
- handleApi(DeviceId, message);
192
+ routeMessageToDevice(DeviceId, message);
213
193
  }
214
194
  else if (parsedMessage?.actionId) {
215
195
  const DeviceId = parsedMessage.DeviceId;
216
- handleAction(DeviceId, message);
196
+ routeMessageToDevice(DeviceId, message);
217
197
  }
218
198
  else if (parsedMessage?.name) {
219
199
  const ID = parsedMessage.ChannelId || parsedMessage.GuildId || parsedMessage.DeviceId;
@@ -260,11 +240,11 @@ const setTestOnePlatformClient = (ws) => {
260
240
  });
261
241
  if (parsedMessage.apiId) {
262
242
  const DeviceId = parsedMessage.DeviceId;
263
- handleApi(DeviceId, message);
243
+ routeMessageToDevice(DeviceId, message);
264
244
  }
265
245
  else if (parsedMessage?.actionId) {
266
246
  const DeviceId = parsedMessage.DeviceId;
267
- handleAction(DeviceId, message);
247
+ routeMessageToDevice(DeviceId, message);
268
248
  }
269
249
  else if (parsedMessage?.name) {
270
250
  const ID = parsedMessage.ChannelId || parsedMessage.GuildId || parsedMessage.DeviceId;
package/lib/client.js CHANGED
@@ -23,7 +23,6 @@ import './app/event-group.js';
23
23
  import './app/event-middleware.js';
24
24
  import './app/event-processor.js';
25
25
  import './app/event-response.js';
26
- import 'util/types';
27
26
  import './app/hook-use-api.js';
28
27
  import './app/message-api.js';
29
28
  import './app/message-format.js';
@@ -6,6 +6,8 @@ import { ResultCode } from './variable.js';
6
6
  class ConfigCore {
7
7
  #dir = null;
8
8
  #value = null;
9
+ #mergedValue = null;
10
+ #watcher = null;
9
11
  #initValue = {
10
12
  gui: {
11
13
  port: 17127
@@ -14,6 +16,9 @@ class ConfigCore {
14
16
  constructor(dir) {
15
17
  this.#dir = dir;
16
18
  }
19
+ #invalidateMergedCache() {
20
+ this.#mergedValue = null;
21
+ }
17
22
  #update() {
18
23
  if (!this.#dir) {
19
24
  return this.#value;
@@ -27,6 +32,7 @@ class ConfigCore {
27
32
  const data = readFileSync(dir, 'utf-8');
28
33
  const d = YAML.parse(data);
29
34
  this.#value = d;
35
+ this.#invalidateMergedCache();
30
36
  }
31
37
  catch (err) {
32
38
  logger.error({
@@ -34,13 +40,17 @@ class ConfigCore {
34
40
  message: 'Config file parse error',
35
41
  data: err
36
42
  });
37
- process.cwd();
38
43
  }
39
- watch(dir, () => {
44
+ if (this.#watcher) {
45
+ this.#watcher.close();
46
+ this.#watcher = null;
47
+ }
48
+ this.#watcher = watch(dir, () => {
40
49
  try {
41
50
  const data = readFileSync(dir, 'utf-8');
42
51
  const d = YAML.parse(data);
43
52
  this.#value = d;
53
+ this.#invalidateMergedCache();
44
54
  }
45
55
  catch (err) {
46
56
  logger.error({
@@ -48,7 +58,6 @@ class ConfigCore {
48
58
  message: 'Config file parse error',
49
59
  data: err
50
60
  });
51
- process.cwd();
52
61
  }
53
62
  });
54
63
  return this.#value;
@@ -56,15 +65,15 @@ class ConfigCore {
56
65
  get value() {
57
66
  if (!this.#value) {
58
67
  this.#update();
59
- return {
60
- ...(this.#value || {}),
61
- ...(global?.__options || {})
62
- };
63
68
  }
64
- return {
69
+ if (this.#mergedValue) {
70
+ return this.#mergedValue;
71
+ }
72
+ this.#mergedValue = {
65
73
  ...(this.#value || {}),
66
74
  ...(global?.__options || {})
67
75
  };
76
+ return this.#mergedValue;
68
77
  }
69
78
  saveValue(value) {
70
79
  if (!this.#dir) {
@@ -3,7 +3,8 @@ export declare const processorRepeatedEventTime: number;
3
3
  export declare const processorRepeatedUserTime: number;
4
4
  export declare const processorRepeatedClearTimeMin: number;
5
5
  export declare const processorRepeatedClearTimeMax: number;
6
- export declare const processorPepeatedClearSize = 37;
6
+ export declare const processorRepeatedClearSize = 37;
7
+ export declare const processorMaxMapSize = 10000;
7
8
  export declare const fileSuffixMiddleware: RegExp;
8
9
  export declare const fileSuffixResponse: RegExp;
9
10
  export declare const filePrefixCommon: RegExp;
@@ -2,7 +2,8 @@ const processorRepeatedEventTime = 1000 * 60;
2
2
  const processorRepeatedUserTime = 1000 * 1;
3
3
  const processorRepeatedClearTimeMin = 1000 * 3;
4
4
  const processorRepeatedClearTimeMax = 1000 * 10;
5
- const processorPepeatedClearSize = 37;
5
+ const processorRepeatedClearSize = 37;
6
+ const processorMaxMapSize = 10000;
6
7
  const fileSuffixMiddleware = /^mw(\.|\..*\.)(js|ts|jsx|tsx)$/;
7
8
  const fileSuffixResponse = /^res(\.|\..*\.)(js|ts|jsx|tsx)$/;
8
9
  const filePrefixCommon = /^(@alemonjs\/|alemonjs-)/;
@@ -26,4 +27,4 @@ const ResultCode = {
26
27
  FailInternal
27
28
  };
28
29
 
29
- export { EventMessageText, Fail, FailAuth, FailInternal, FailParams, Ok, ResultCode, Warn, defaultLogin, defaultPlatformCommonPrefix, defaultPlatformPrefix, defaultPort, filePrefixCommon, fileSuffixMiddleware, fileSuffixResponse, processorPepeatedClearSize, processorRepeatedClearTimeMax, processorRepeatedClearTimeMin, processorRepeatedEventTime, processorRepeatedUserTime };
30
+ export { EventMessageText, Fail, FailAuth, FailInternal, FailParams, Ok, ResultCode, Warn, defaultLogin, defaultPlatformCommonPrefix, defaultPlatformPrefix, defaultPort, filePrefixCommon, fileSuffixMiddleware, fileSuffixResponse, processorMaxMapSize, processorRepeatedClearSize, processorRepeatedClearTimeMax, processorRepeatedClearTimeMin, processorRepeatedEventTime, processorRepeatedUserTime };
package/lib/index.js CHANGED
@@ -5,7 +5,7 @@ export { createEventName, createHash, createResult, getInputExportPath, getRecur
5
5
  export { cbpClient } from './cbp/connects/client.js';
6
6
  export { cbpPlatform } from './cbp/connects/platform.js';
7
7
  export { cbpServer } from './cbp/server/main.js';
8
- export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAudoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger } from './app/store.js';
8
+ export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap, Response, ResponseMiddleware, ResponseRouter, State, StateSubscribe, SubscribeList, core, logger } from './app/store.js';
9
9
  export { loadModels, run } from './app/load_modules/load.js';
10
10
  export { loadChildren, loadChildrenFile } from './app/load_modules/loadChild.js';
11
11
  export { defineChildren } from './app/define-children.js';
@@ -7,7 +7,8 @@ export type SubscribeValue = {
7
7
  keys: {
8
8
  [key: string]: string | number | boolean;
9
9
  };
10
- current: Function;
10
+ status?: 'active' | 'paused';
11
+ current: (...arg: any[]) => any;
11
12
  id: string;
12
13
  };
13
14
  export type SubscribeMap = Map<string, SinglyLinkedList<SubscribeValue>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alemonjs",
3
- "version": "2.1.16",
3
+ "version": "2.1.18",
4
4
  "description": "bot script",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",