Quellcode durchsuchen

better handle timeout/error pushing data in mode 0

Mike L vor 4 Jahren
Ursprung
Commit
0ce4f063f0
6 geänderte Dateien mit 100 neuen und 45 gelöschten Zeilen
  1. 13 8
      dist/mirai.js
  2. 34 10
      dist/twitter.js
  3. 1 1
      dist/webshot.js
  4. 14 10
      src/mirai.ts
  5. 37 15
      src/twitter.ts
  6. 1 1
      src/webshot.ts

+ 13 - 8
dist/mirai.js

@@ -23,14 +23,19 @@ const ChatTypeMap = {
 exports.MiraiMessage = message_1.default;
 class default_1 {
     constructor(opt) {
-        this.sendTo = (subscriber, msg) => (() => {
-            switch (subscriber.chatType) {
-                case 'group':
-                    return this.bot.api.sendGroupMessage(msg, subscriber.chatID);
-                case 'private':
-                    return this.bot.api.sendFriendMessage(msg, subscriber.chatID);
-            }
-        })()
+        this.sendTo = (subscriber, msg, timeout) => new Promise((resolve, reject) => {
+            if (timeout === 0 || timeout < -1)
+                reject('Error: timeout must be greater than 0 ms');
+            (() => {
+                switch (subscriber.chatType) {
+                    case 'group':
+                        return this.bot.api.sendGroupMessage(msg, subscriber.chatID);
+                    case 'private':
+                        return this.bot.api.sendFriendMessage(msg, subscriber.chatID);
+                }
+            })().then(resolve).catch(reject);
+            setTimeout(() => reject('Error: request timed out'), timeout);
+        })
             .then(response => {
             logger.info(`pushing data to ${subscriber.chatID} was successful, response:`);
             logger.info(response);

+ 34 - 10
dist/twitter.js

@@ -93,23 +93,47 @@ class default_1 {
                 }
                 if (lock.threads[lock.feed[lock.workon]].offset === 0)
                     tweets.splice(1);
-                return this.webshot(tweets, msg => {
+                const maxCount = 3;
+                let sendTimeout = 5000;
+                const retryTimeout = 1500;
+                const ordinal = (n) => {
+                    switch ((~~(n / 10) % 10 === 1) ? 0 : n % 10) {
+                        case 1:
+                            return `${n}st`;
+                        case 2:
+                            return `${n}nd`;
+                        case 3:
+                            return `${n}rd`;
+                        default:
+                            return `${n}th`;
+                    }
+                };
+                const sendTweets = (msg, text, author) => {
                     lock.threads[lock.feed[lock.workon]].subscribers.forEach(subscriber => {
                         logger.info(`pushing data of thread ${lock.feed[lock.workon]} to ${JSON.stringify(subscriber)}`);
-                        const retry = reason => {
-                            if (typeof (msg) !== 'string') {
-                                logger.warn(`retry sending to ${subscriber.chatID}`);
+                        const retry = (reason, count) => {
+                            if (count <= maxCount)
+                                sendTimeout *= count / (count - 1);
+                            setTimeout(() => {
                                 msg.forEach((message, pos) => {
-                                    if (message.type === 'Image') {
-                                        msg[pos] = mirai_1.MiraiMessage.Plain(`[失败的图片:${message.path}]`);
+                                    if (count > maxCount && message.type === 'Image') {
+                                        if (pos === 0) {
+                                            logger.warn(`${count - 1} consecutive failures sending webshot, trying plain text instead...`);
+                                            msg[pos] = mirai_1.MiraiMessage.Plain(author + text);
+                                        }
+                                        else {
+                                            msg[pos] = mirai_1.MiraiMessage.Plain(`[失败的图片:${message.path}]`);
+                                        }
                                     }
                                 });
-                            }
-                            this.bot.sendTo(subscriber, msg).catch(retry);
+                                logger.warn(`retry sending to ${subscriber.chatID} for the ${ordinal(count)} time...`);
+                                this.bot.sendTo(subscriber, msg, sendTimeout).catch(error => retry(error, count + 1));
+                            }, retryTimeout);
                         };
-                        this.bot.sendTo(subscriber, msg).catch(retry);
+                        this.bot.sendTo(subscriber, msg, sendTimeout).catch(error => retry(error, 1));
                     });
-                }, this.webshotDelay)
+                };
+                return this.webshot(tweets, sendTweets, this.webshotDelay)
                     .then(() => {
                     lock.threads[lock.feed[lock.workon]].offset = tweets[0].id_str;
                     lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();

+ 1 - 1
dist/webshot.js

@@ -253,7 +253,7 @@ class Webshot extends CallableInstance {
             promise.then(() => {
                 logger.info(`done working on ${twi.user.screen_name}/${twi.id_str}, message chain:`);
                 logger.info(JSON.stringify(messageChain));
-                callback(messageChain, text, author);
+                callback(messageChain, xmlEntities.decode(text), author);
             });
         });
         return promise;

+ 14 - 10
src/mirai.ts

@@ -1,5 +1,5 @@
 import axios from 'axios';
-import Mirai, { MessageType } from 'mirai-ts';
+import Mirai, { Api, MessageType } from 'mirai-ts';
 import Message from 'mirai-ts/dist/message';
 
 import command from './helper';
@@ -31,15 +31,19 @@ export default class {
   private botInfo: IQQProps;
   public bot: Mirai;
 
-  public sendTo = (subscriber: IChat, msg: string | MessageChain) =>
-    (() => {
-      switch (subscriber.chatType) {
-        case 'group':
-          return this.bot.api.sendGroupMessage(msg, subscriber.chatID);
-        case 'private':
-          return this.bot.api.sendFriendMessage(msg, subscriber.chatID);
-      }
-    })()
+  public sendTo = (subscriber: IChat, msg: string | MessageChain, timeout?: number) =>
+    new Promise<Api.Response.sendMessage>((resolve, reject) => {
+      if (timeout === 0 || timeout < -1) reject('Error: timeout must be greater than 0 ms');
+      (() => {
+        switch (subscriber.chatType) {
+          case 'group':
+            return this.bot.api.sendGroupMessage(msg, subscriber.chatID);
+          case 'private':
+            return this.bot.api.sendFriendMessage(msg, subscriber.chatID);
+        }
+      })().then(resolve).catch(reject);
+      setTimeout(() => reject('Error: request timed out'), timeout);
+    })
     .then(response => {
       logger.info(`pushing data to ${subscriber.chatID} was successful, response:`);
       logger.info(response);

+ 37 - 15
src/twitter.ts

@@ -135,28 +135,50 @@ export default class {
         return;
       }
       if (lock.threads[lock.feed[lock.workon]].offset === 0) tweets.splice(1);
-      return (this.webshot as any)(tweets, msg => {
+
+      const maxCount = 3;
+      let sendTimeout = 5000;
+      const retryTimeout = 1500;
+      const ordinal = (n: number) => {
+        switch ((~~(n / 10) % 10 === 1) ? 0 : n % 10) {
+          case 1:
+            return `${n}st`;
+          case 2:
+            return `${n}nd`;
+          case 3:
+            return `${n}rd`;
+          default:
+            return `${n}th`;
+        }
+      };
+      const sendTweets = (msg: MessageChain, text: string, author: string) => {
         lock.threads[lock.feed[lock.workon]].subscribers.forEach(subscriber => {
           logger.info(`pushing data of thread ${lock.feed[lock.workon]} to ${JSON.stringify(subscriber)}`);
-          const retry = reason => { // workaround for https://github.com/mamoe/mirai/issues/194
-            if (typeof(msg) !== 'string') {
-              logger.warn(`retry sending to ${subscriber.chatID}`);
+          const retry = (reason, count: number) => { // workaround for https://github.com/mamoe/mirai/issues/194
+            if (count <= maxCount) sendTimeout *= count / (count - 1);
+            setTimeout(() => {
               (msg as MessageChain).forEach((message, pos) => {
-                if (message.type === 'Image') {
-                  msg[pos] = Message.Plain(`[失败的图片:${message.path}]`);
+                if (count > maxCount && message.type === 'Image') {
+                  if (pos === 0) {
+                    logger.warn(`${count - 1} consecutive failures sending webshot, trying plain text instead...`);
+                    msg[pos] = Message.Plain(author + text);
+                  } else {
+                    msg[pos] = Message.Plain(`[失败的图片:${message.path}]`);
+                  }
                 }
               });
-            }
-            this.bot.sendTo(subscriber, msg).catch(retry);
+              logger.warn(`retry sending to ${subscriber.chatID} for the ${ordinal(count)} time...`);
+              this.bot.sendTo(subscriber, msg, sendTimeout).catch(error => retry(error, count + 1));
+            }, retryTimeout);
           };
-          this.bot.sendTo(subscriber, msg).catch(retry);
+          this.bot.sendTo(subscriber, msg, sendTimeout).catch(error => retry(error, 1));
         });
-      }, this.webshotDelay)
-        .then(() => {
-          lock.threads[lock.feed[lock.workon]].offset = tweets[0].id_str;
-          lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
-        });
-
+      };
+      return (this.webshot as any)(tweets, sendTweets, this.webshotDelay)
+      .then(() => {
+        lock.threads[lock.feed[lock.workon]].offset = tweets[0].id_str;
+        lock.threads[lock.feed[lock.workon]].updatedAt = new Date().toString();
+      });
     })
       .then(() => {
         lock.workon++;

+ 1 - 1
src/webshot.ts

@@ -276,7 +276,7 @@ class Webshot extends CallableInstance<[number], Promise<void>> {
       promise.then(() => {
         logger.info(`done working on ${twi.user.screen_name}/${twi.id_str}, message chain:`);
         logger.info(JSON.stringify(messageChain));
-        callback(messageChain, text, author);
+        callback(messageChain, xmlEntities.decode(text), author);
       });
     });
     return promise;