فهرست منبع

implement queued sending of messages

Mike L 4 سال پیش
والد
کامیت
90b0b391e4
2فایلهای تغییر یافته به همراه66 افزوده شده و 12 حذف شده
  1. 33 6
      dist/koishi.js
  2. 33 6
      src/koishi.ts

+ 33 - 6
dist/koishi.js

@@ -33,6 +33,26 @@ exports.Message = {
 };
 class default_1 {
     constructor(opt) {
+        this.messageQueues = {};
+        this.next = (type, id) => {
+            const queue = this.messageQueues[`${type}:${id}`];
+            if (queue && queue.length) {
+                queue[0]().then(() => queue.shift()).then(() => {
+                    if (!queue.length)
+                        delete this.messageQueues[`${type}:${id}`];
+                    else
+                        this.next(type, id);
+                });
+            }
+        };
+        this.enqueue = (type, id, resolver) => {
+            var _a, _b;
+            const queue = (_a = this.messageQueues)[_b = `${type}:${id}`] || (_a[_b] = []);
+            queue.push(() => koishi_1.sleep(200).then(resolver));
+            logger.debug(`no. of message currently queued for ${type}:${id}: ${queue.length}`);
+            if (queue.length === 1)
+                this.next(type, id);
+        };
         this.getChat = (session) => __awaiter(this, void 0, void 0, function* () {
             switch (session.subtype) {
                 case 'private':
@@ -59,19 +79,26 @@ class default_1 {
                     };
             }
         });
+        this.sendToGroup = (groupID, message) => new Promise(resolve => {
+            this.enqueue('group', groupID, () => this.bot.sendMessage(groupID, message).then(resolve));
+        });
+        this.sendToUser = (userID, message) => new Promise(resolve => {
+            this.enqueue('private', userID, () => this.bot.sendPrivateMessage(userID, message).then(resolve));
+        });
         this.sendTo = (subscriber, messageChain) => utils_1.chainPromises((splitted => [splitted.message, ...splitted.attachments])(exports.Message.separateAttachment(messageChain)).map(msg => {
             switch (subscriber.chatType) {
                 case 'group':
-                    return this.bot.sendMessage(subscriber.chatID.toString(), msg);
+                    return this.sendToGroup(subscriber.chatID.toString(), msg);
                 case 'private':
-                    return this.bot.sendPrivateMessage(subscriber.chatID.toString(), msg);
+                    return this.sendToUser(subscriber.chatID.toString(), msg);
                 case 'temp':
-                    return this.bot.sendPrivateMessage(subscriber.chatID.qq.toString(), msg);
+                    return this.sendToUser(subscriber.chatID.qq.toString(), msg);
             }
         }))
             .then(response => {
-            logger.info(`pushing data to ${JSON.stringify(subscriber.chatID)} was successful, response:`);
-            logger.info(response);
+            if (response === undefined)
+                return;
+            logger.info(`pushing data to ${JSON.stringify(subscriber.chatID)} was successful, response: ${response}`);
         })
             .catch(reason => {
             reason = exports.Message.ellipseBase64(reason);
@@ -118,7 +145,7 @@ class default_1 {
             this.app.middleware((session) => __awaiter(this, void 0, void 0, function* () {
                 const chat = yield this.getChat(session);
                 const cmdObj = command_1.parseCmd(session.content);
-                const reply = (msg) => __awaiter(this, void 0, void 0, function* () { return session.send(msg); });
+                const reply = (msg) => __awaiter(this, void 0, void 0, function* () { return session.sendQueued(msg); });
                 switch (cmdObj.cmd) {
                     case 'twitter_view':
                     case 'twitter_get':

+ 33 - 6
src/koishi.ts

@@ -42,6 +42,25 @@ export default class {
   private app: App;
   public bot: Bot;
 
+  private messageQueues: {[key: string]: (() => Promise<void>)[]} = {};
+
+  private next = (type: 'private' | 'group', id: string) => {
+    const queue = this.messageQueues[`${type}:${id}`];
+    if (queue && queue.length) {
+      queue[0]().then(() => queue.shift()).then(() => {
+        if (!queue.length) delete this.messageQueues[`${type}:${id}`];
+        else this.next(type, id);
+      });
+    }
+  };
+
+  private enqueue = (type: 'private' | 'group', id: string, resolver: () => Promise<void>) => {
+    const queue = this.messageQueues[`${type}:${id}`] ||= [];
+    queue.push(() => sleep(200).then(resolver));
+    logger.debug(`no. of message currently queued for ${type}:${id}: ${queue.length}`);
+    if (queue.length === 1) this.next(type, id);
+  };
+
   private getChat = async (session: Session): Promise<IChat> => {
     switch (session.subtype) {
       case 'private':
@@ -69,22 +88,30 @@ export default class {
     }
   };
 
+  private sendToGroup = (groupID: string, message: string) => new Promise<string>(resolve => {
+    this.enqueue('group', groupID, () => this.bot.sendMessage(groupID, message).then(resolve));
+  });
+
+  private sendToUser = (userID: string, message: string) => new Promise<string>(resolve => {
+    this.enqueue('private', userID, () => this.bot.sendPrivateMessage(userID, message).then(resolve));
+  });
+
   public sendTo = (subscriber: IChat, messageChain: string) => chainPromises(
     (splitted => [splitted.message, ...splitted.attachments])(
       Message.separateAttachment(messageChain)
     ).map(msg => {
       switch (subscriber.chatType) {
         case 'group':
-          return this.bot.sendMessage(subscriber.chatID.toString(), msg);
+          return this.sendToGroup(subscriber.chatID.toString(), msg);
         case 'private':
-          return this.bot.sendPrivateMessage(subscriber.chatID.toString(), msg);
+          return this.sendToUser(subscriber.chatID.toString(), msg);
         case 'temp': // currently unable to open session, awaiting OneBot v12
-          return this.bot.sendPrivateMessage(subscriber.chatID.qq.toString(), msg);
+          return this.sendToUser(subscriber.chatID.qq.toString(), msg);
       }
     }))
     .then(response => {
-      logger.info(`pushing data to ${JSON.stringify(subscriber.chatID)} was successful, response:`);
-      logger.info(response);
+      if (response === undefined) return;
+      logger.info(`pushing data to ${JSON.stringify(subscriber.chatID)} was successful, response: ${response}`);
     })
     .catch(reason => {
       reason = Message.ellipseBase64(reason);
@@ -135,7 +162,7 @@ export default class {
     this.app.middleware(async session => {
       const chat = await this.getChat(session);
       const cmdObj = parseCmd(session.content);
-      const reply = async msg => session.send(msg);
+      const reply = async msg => session.sendQueued(msg);
       switch (cmdObj.cmd) {
         case 'twitter_view':
         case 'twitter_get':