From f1fbe92dde26b07713cfe996314b96bf88be0cff Mon Sep 17 00:00:00 2001 From: "Mr. Stallion" Date: Sun, 19 Apr 2020 12:59:49 -0500 Subject: [PATCH] Better management of accidental parallel message posting --- chat/conversations.ts | 83 ++++++++++++++++++++++++++++++++++-------- learn/cache-manager.ts | 2 +- package.json | 2 + readme.md | 17 +++++---- tslint.json | 2 +- yarn.lock | 7 +++- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/chat/conversations.ts b/chat/conversations.ts index 76bd7e8..a587a65 100644 --- a/chat/conversations.ts +++ b/chat/conversations.ts @@ -9,6 +9,8 @@ import l from './localize'; import {CommandContext, isAction, isCommand, isWarn, parse as parseCommand} from './slash_commands'; import MessageType = Interfaces.Message.Type; import {EventBus} from './preview/event-bus'; +import throat from 'throat'; +import Bluebird from 'bluebird'; function createMessage(this: any, type: MessageType, sender: Character, text: string, time?: Date): Message { if(type === MessageType.Message && isAction(text)) { @@ -40,6 +42,8 @@ abstract class Conversation implements Interfaces.Conversation { private lastSent = ''; adManager: AdManager; + protected static readonly conversationThroat = throat(1); // make sure user posting and ad posting won't get in each others' way + constructor(readonly key: string, public _isPinned: boolean) { this.adManager = new AdManager(this); } @@ -124,6 +128,19 @@ abstract class Conversation implements Interfaces.Conversation { } protected abstract doSend(): void | Promise; + + + protected static readonly POST_DELAY = 1250; + + protected static async testPostDelay(): Promise { + const lastPostDelta = Date.now() - core.cache.getLastPost().getTime(); + + // console.log('Last Post Delta', lastPostDelta, ((lastPostDelta < Conversation.POST_DELAY) && (lastPostDelta > 0))); + + if ((lastPostDelta < Conversation.POST_DELAY) && (lastPostDelta > 0)) { + await Bluebird.delay(Conversation.POST_DELAY - lastPostDelta); + } + } } class PrivateConversation extends Conversation implements Interfaces.PrivateConversation { @@ -200,11 +217,23 @@ class PrivateConversation extends Conversation implements Interfaces.PrivateConv return; } - core.connection.send('PRI', {recipient: this.name, message: this.enteredText}); - const message = createMessage(MessageType.Message, core.characters.ownCharacter, this.enteredText); - this.safeAddMessage(message); - if(core.state.settings.logMessages) await core.logs.logMessage(this, message); + const messageText = this.enteredText; + this.clearText(); + + await Conversation.conversationThroat( + async() => { + await Conversation.testPostDelay(); + + core.connection.send('PRI', {recipient: this.name, message: messageText}); + core.cache.markLastPostTime(); + + const message = createMessage(MessageType.Message, core.characters.ownCharacter, messageText); + this.safeAddMessage(message); + + if(core.state.settings.logMessages) await core.logs.logMessage(this, message); + } + ); } private setOwnTyping(status: Interfaces.TypingStatus): void { @@ -335,30 +364,52 @@ class ChannelConversation extends Conversation implements Interfaces.ChannelConv return; } - core.connection.send(isAd ? 'LRP' : 'MSG', {channel: this.channel.id, message: this.enteredText}); - await this.addMessage( - createMessage(isAd ? MessageType.Ad : MessageType.Message, core.characters.ownCharacter, this.enteredText, new Date())); - if(isAd) - this.nextAd = Date.now() + core.connection.vars.lfrp_flood * 1000; - else this.clearText(); + const message = this.enteredText; - core.cache.timeLastPost(); + if (!isAd) { + this.clearText(); + } + + await Conversation.conversationThroat( + async() => { + await Conversation.testPostDelay(); + + core.connection.send(isAd ? 'LRP' : 'MSG', {channel: this.channel.id, message}); + core.cache.markLastPostTime(); + + await this.addMessage( + createMessage(isAd ? MessageType.Ad : MessageType.Message, core.characters.ownCharacter, message, new Date()) + ); + + if(isAd) + this.nextAd = Date.now() + core.connection.vars.lfrp_flood * 1000; + } + ); } + async sendAd(text: string): Promise { if (text.length < 1) return; - core.connection.send('LRP', {channel: this.channel.id, message: text}); + await Conversation.conversationThroat( + async() => { + await Conversation.testPostDelay(); - await this.addMessage( - createMessage(MessageType.Ad, core.characters.ownCharacter, text, new Date()) + core.connection.send('LRP', {channel: this.channel.id, message: text}); + core.cache.markLastPostTime(); + + await this.addMessage( + createMessage(MessageType.Ad, core.characters.ownCharacter, text, new Date()) + ); + + this.nextAd = Date.now() + core.connection.vars.lfrp_flood * 1000; + } ); - - this.nextAd = Date.now() + core.connection.vars.lfrp_flood * 1000; } } + class ConsoleConversation extends Conversation { readonly context = CommandContext.Console; readonly name = l('chat.consoleTab'); diff --git a/learn/cache-manager.ts b/learn/cache-manager.ts index d2e139c..47c9d5d 100644 --- a/learn/cache-manager.ts +++ b/learn/cache-manager.ts @@ -40,7 +40,7 @@ export class CacheManager { protected lastPost: Date = new Date(); - timeLastPost(): void { + markLastPostTime(): void { this.lastPost = new Date(); } diff --git a/package.json b/package.json index acefe21..80ab59f 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@f-list/fork-ts-checker-webpack-plugin": "^3.1.1", "@f-list/vue-ts": "^1.0.3", "@fortawesome/fontawesome-free": "^5.9.0", + "@types/bluebird": "^3.5.30", "@types/lodash": "^4.14.134", "@types/node-fetch": "^2.5.5", "@types/qs": "^6.9.1", @@ -45,6 +46,7 @@ }, "dependencies": { "@cliqz/adblocker-electron": "^1.13.0", + "bluebird": "^3.7.2", "jquery": "^3.4.1", "keytar": "^5.4.0", "node-fetch": "^2.6.0" diff --git a/readme.md b/readme.md index 9ba2575..0382fda 100644 --- a/readme.md +++ b/readme.md @@ -13,17 +13,18 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0 ### More Detailed Differences -* Ads view +* Channel Conversations * Highlight ads from characters most interesting to you * Hide clearly unmatched ads - * View characters' recent ads -* Ad auto-posting +* Ad Auto-Posting * Manage channel ad settings via "Tab Settings" * Automatically re-post ads every 11-18 minutes (randomized) for up to 180 minutes * Rotate multiple ads on a single channel by entering multiple ads in "Ad Settings" -* Ad ratings +* Ad Ratings * LFP ads are automatically rated (great/good/maybe/no) and matched against your profile -* Link previews +* Private Conversations + * View a characters' recent ads +* Link Previews * Hover cursor over any `[url]` to see a preview of it * Middle click any `[url]` to turn the preview into a sticky / interactive mode * Link preview has an ad-blocker to minimize page load times and protect against unfriendly scripts @@ -45,8 +46,8 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0 * Current search filters are listed in the search dialog * Search filters can be reset * Search results can be filtered by species - * Last 15 searches are stored and can be accessed from the 'Search' dialog -* Character status + * Last 15 searches are stored and can be accessed from the 'Character search' dialog +* Character Status Message * Last 10 status messages are stored and can be accessed from the 'Set status' dialog * General * Character profiles, guestbooks, friend lists, and image lists are cached for faster access @@ -55,7 +56,7 @@ This repository contains a heavily customized version of the mainline F-Chat 3.0 * PM list shows characters' online status as a colored icon * Technical Details for Nerds * Upgraded to Electron 9.x - * Replaced `node-spellchecker` with the built-in spellchecker that ships with Electron 8 + * Replaced `node-spellchecker` with the built-in spellchecker that ships with Electron 8+ * Multi-language support for spell checking (Windows only – language is autodetected on MacOS) diff --git a/tslint.json b/tslint.json index 3b1884e..f56a313 100644 --- a/tslint.json +++ b/tslint.json @@ -51,7 +51,7 @@ true, "array" ], - "await-promise": [true, "AxiosPromise"], + "await-promise": [true, "AxiosPromise", "Bluebird"], "comment-format": false, "completed-docs": false, "curly": false, diff --git a/yarn.lock b/yarn.lock index 797e35e..97a4f06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -153,6 +153,11 @@ dependencies: defer-to-connect "^1.0.1" +"@types/bluebird@^3.5.30": + version "3.5.30" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5" + integrity sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw== + "@types/chrome@^0.0.103": version "0.0.103" resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.103.tgz#604f3d94ab4465cc8cde302c4916f4955eb7e8b6" @@ -844,7 +849,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.1.1, bluebird@^3.5.0, bluebird@^3.5.5: +bluebird@^3.1.1, bluebird@^3.5.0, bluebird@^3.5.5, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==