Skip to content

Commit ba234de

Browse files
authored
refactor: Add delay mechanism for developer message automation (#19562)
1 parent d2efc5c commit ba234de

File tree

2 files changed

+80
-48
lines changed

2 files changed

+80
-48
lines changed

src/script/components/ConfigToolbar/ConfigToolbar.tsx

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ import {wrapperStyles} from './ConfigToolbar.styles';
3333
export function ConfigToolbar() {
3434
const [showConfig, setShowConfig] = useState(false);
3535
const [configFeaturesState, setConfigFeaturesState] = useState<Configuration['FEATURE']>(Config.getConfig().FEATURE);
36-
const [intervalId, setIntervalId] = useState<number | null>(null); // For managing setInterval
36+
const [intervalId, setIntervalId] = useState<number | null>(null); // Stores active timeout id (renamed kept for minimal change)
3737
const messageCountRef = useRef<number>(0); // For the message count
3838
const [prefix, setPrefix] = useState('Message -'); // Prefix input
39+
// Delay between automated messages in seconds (can be fractional). 0 = send back-to-back.
40+
const [messageDelaySec, setMessageDelaySec] = useState<number>(0);
41+
// Ref to always access latest delay inside async loop without re-registering timers
42+
const messageDelaySecRef = useRef<number>(messageDelaySec);
3943
const wrapperRef = useRef(null);
4044
const [avsDebuggerEnabled, setAvsDebuggerEnabled] = useState(!!window.wire?.app?.debug?.isEnabledAvsDebugger()); //
4145

@@ -52,52 +56,56 @@ export function ConfigToolbar() {
5256
};
5357
}, []);
5458

59+
useEffect(() => {
60+
messageDelaySecRef.current = messageDelaySec;
61+
}, [messageDelaySec]);
62+
5563
const startSendingMessages = () => {
5664
if (intervalId) {
5765
return;
5866
}
5967

60-
let isRequestInProgress = false;
61-
62-
const id = window.setInterval(async () => {
63-
if (isRequestInProgress) {
64-
return;
65-
}
66-
68+
const sendNext = async () => {
6769
const conversationState = container.resolve(ConversationState);
6870
const activeConversation = conversationState?.activeConversation();
6971
if (!activeConversation) {
72+
if (intervalId) {
73+
const MS_IN_SEC = 1000;
74+
const retryId = window.setTimeout(sendNext, (messageDelaySecRef.current || 0) * MS_IN_SEC);
75+
setIntervalId(retryId);
76+
}
7077
return;
7178
}
7279

73-
isRequestInProgress = true;
74-
7580
try {
7681
await window.wire.app.repository.message.sendTextWithLinkPreview({
7782
conversation: activeConversation,
7883
textMessage: `${prefix} ${messageCountRef.current}`,
7984
mentions: [],
8085
quoteEntity: undefined,
8186
});
82-
8387
messageCountRef.current++;
8488
} catch (error) {
8589
console.error('Error sending message:', error);
86-
} finally {
87-
isRequestInProgress = false;
8890
}
89-
}, 100);
9091

91-
setIntervalId(id);
92+
const MS_IN_SEC = 1000;
93+
const delayMs = (messageDelaySecRef.current || 0) * MS_IN_SEC;
94+
const nextId = window.setTimeout(sendNext, delayMs);
95+
setIntervalId(nextId);
96+
};
97+
98+
const firstId = window.setTimeout(sendNext, 0);
99+
setIntervalId(firstId);
92100
};
93101

94102
// Stop sending messages and reset the counter
95103
const stopSendingMessages = () => {
96104
if (intervalId) {
97-
clearInterval(intervalId);
105+
clearTimeout(intervalId);
98106
setIntervalId(null);
99-
messageCountRef.current = 0;
100107
}
108+
messageCountRef.current = 0;
101109
};
102110

103111
// Update the config state when form input changes
@@ -184,14 +192,15 @@ export function ConfigToolbar() {
184192
return null;
185193
}
186194

195+
const isSending = intervalId !== null;
196+
187197
return (
188198
<div ref={wrapperRef} css={wrapperStyles}>
189199
<h3>Developer Menu</h3>
190200
<h4 style={{color: 'red', fontWeight: 'bold'}}>
191201
Caution: Modifying these settings can affect the behavior of the application. Ensure you understand the
192202
implications of each change before proceeding. Changes may cause unexpected behavior.
193203
</h4>
194-
<div>{renderConfig(configFeaturesState)}</div>
195204

196205
<hr />
197206

@@ -212,8 +221,26 @@ export function ConfigToolbar() {
212221
onChange={event => setPrefix(event.currentTarget.value)}
213222
placeholder="Prefix for the messages"
214223
/>
215-
<Button onClick={startSendingMessages}>Send Incremented Messages</Button>
216-
<Button onClick={stopSendingMessages}>Stop Sending Messages</Button>
224+
<div style={{marginTop: '8px'}}>
225+
<label htmlFor="message-delay-input" style={{display: 'block', fontWeight: 'bold'}}>
226+
Delay Between Messages (seconds)
227+
</label>
228+
<Input
229+
id="message-delay-input"
230+
type="number"
231+
min={0}
232+
step={0.1}
233+
value={messageDelaySec}
234+
onChange={event => {
235+
const val = parseFloat(event.currentTarget.value);
236+
setMessageDelaySec(Number.isNaN(val) || val < 0 ? 0 : val);
237+
}}
238+
placeholder="0"
239+
/>
240+
</div>
241+
<Button onClick={isSending ? stopSendingMessages : startSendingMessages}>
242+
{isSending ? 'Stop Sending Messages' : 'Send Incremented Messages'}
243+
</Button>
217244

218245
<h3>Database dump & restore</h3>
219246
<h6 style={{color: 'red', fontWeight: 'bold'}}>
@@ -222,6 +249,9 @@ export function ConfigToolbar() {
222249
</h6>
223250
<Button onClick={() => window.wire?.app?.debug?.dumpIndexedDB()}>Dump IndexedDB</Button>
224251
<Button onClick={() => window.wire?.app?.debug?.restoreIndexedDB()}>Restore IndexedDB</Button>
252+
253+
<h3>Environment Variables</h3>
254+
<div>{renderConfig(configFeaturesState)}</div>
225255
</div>
226256
);
227257
}

src/script/repositories/entity/Conversation.ts

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -742,37 +742,39 @@ export class Conversation {
742742
* @returns If a message was replaced in the conversation
743743
*/
744744
addMessage(messageEntity: Message): boolean | void {
745-
if (messageEntity) {
746-
const messageWithLinkPreview = () => this._findDuplicate(messageEntity.id, messageEntity.from);
747-
const editedMessage = () =>
748-
this._findDuplicate((messageEntity as ContentMessage).replacing_message_id, messageEntity.from);
749-
const alreadyAdded = messageWithLinkPreview() || editedMessage();
745+
if (!messageEntity) {
746+
return;
747+
}
750748

751-
if (messageEntity.isContent()) {
752-
this.hasContentMessages(true);
753-
}
754-
if (alreadyAdded) {
755-
return false;
756-
}
749+
const messageWithLinkPreview = () => this._findDuplicate(messageEntity.id, messageEntity.from);
750+
const editedMessage = () =>
751+
this._findDuplicate((messageEntity as ContentMessage).replacing_message_id, messageEntity.from);
752+
const alreadyAdded = messageWithLinkPreview() || editedMessage();
757753

758-
const {contentState} = useAppState.getState();
759-
760-
// When the search tab is active, push message to incomming message and update the timestamps
761-
if (contentState === ContentState.COLLECTION) {
762-
this.incomingMessages.push(messageEntity);
763-
this.updateTimestamps(messageEntity);
764-
} else if (this.hasLastReceivedMessageLoaded()) {
765-
this.updateTimestamps(messageEntity);
766-
this.incomingMessages.remove(({id}) => messageEntity.id === id);
767-
// If the last received message is currently in memory, we can add this message to the displayed messages
768-
this.messages_unordered.push(messageEntity);
769-
} else {
770-
// If the conversation is not loaded, we will add this message to the incoming messages (but not to the messages displayed)
771-
this.incomingMessages.push(messageEntity);
772-
}
773-
amplify.publish(WebAppEvents.CONVERSATION.MESSAGE.ADDED, messageEntity);
774-
return true;
754+
if (messageEntity.isContent()) {
755+
this.hasContentMessages(true);
756+
}
757+
if (alreadyAdded) {
758+
return false;
759+
}
760+
761+
const {contentState} = useAppState.getState();
762+
763+
// When the search tab is active, push message to incomming message and update the timestamps
764+
if (contentState === ContentState.COLLECTION) {
765+
this.incomingMessages.push(messageEntity);
766+
this.updateTimestamps(messageEntity);
767+
} else if (this.hasLastReceivedMessageLoaded()) {
768+
this.updateTimestamps(messageEntity);
769+
this.incomingMessages.remove(({id}) => messageEntity.id === id);
770+
// If the last received message is currently in memory, we can add this message to the displayed messages
771+
this.messages_unordered.push(messageEntity);
772+
} else {
773+
// If the conversation is not loaded, we will add this message to the incoming messages (but not to the messages displayed)
774+
this.incomingMessages.push(messageEntity);
775775
}
776+
amplify.publish(WebAppEvents.CONVERSATION.MESSAGE.ADDED, messageEntity);
777+
return true;
776778
}
777779

778780
/**

0 commit comments

Comments
 (0)