feat: bootstrap BoxBrain foundation
This commit is contained in:
78
src/timing.ts
Normal file
78
src/timing.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { BoxBrainAvailability } from './types';
|
||||
|
||||
export type RandomSource = () => number;
|
||||
|
||||
export interface TypingDelayOptions {
|
||||
rng?: RandomSource | undefined;
|
||||
minSecondsPerCharacter?: number | undefined;
|
||||
maxSecondsPerCharacter?: number | undefined;
|
||||
}
|
||||
|
||||
export interface ReplyDelayOptions {
|
||||
isFirstReplyInExchange: boolean;
|
||||
rng?: RandomSource | undefined;
|
||||
onlineMinSeconds?: number | undefined;
|
||||
onlineMaxSeconds?: number | undefined;
|
||||
dndReplyProbability?: number | undefined;
|
||||
dndMinSeconds?: number | undefined;
|
||||
dndMaxSeconds?: number | undefined;
|
||||
}
|
||||
|
||||
export const ONLINE_AVAILABILITY: BoxBrainAvailability = { mode: 'online' };
|
||||
export const DND_AVAILABILITY: BoxBrainAvailability = { mode: 'do_not_disturb' };
|
||||
export const OFFLINE_AVAILABILITY: BoxBrainAvailability = { mode: 'offline' };
|
||||
|
||||
export function createTypingDelay(message: string, options: TypingDelayOptions = {}): number {
|
||||
if (message.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rng = options.rng ?? Math.random;
|
||||
const min = options.minSecondsPerCharacter ?? 0.05;
|
||||
const max = options.maxSecondsPerCharacter ?? 0.08;
|
||||
const secondsPerCharacter = interpolate(min, max, clampUnit(rng()));
|
||||
|
||||
return roundSeconds(message.length * secondsPerCharacter);
|
||||
}
|
||||
|
||||
export function createReplyDelay(
|
||||
availability: BoxBrainAvailability,
|
||||
options: ReplyDelayOptions,
|
||||
): number | null {
|
||||
if (availability.mode === 'offline') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!options.isFirstReplyInExchange) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rng = options.rng ?? Math.random;
|
||||
|
||||
if (availability.mode === 'do_not_disturb') {
|
||||
const probability = options.dndReplyProbability ?? 0.2;
|
||||
if (clampUnit(rng()) > probability) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return roundSeconds(interpolate(options.dndMinSeconds ?? 60, options.dndMaxSeconds ?? 600, clampUnit(rng())));
|
||||
}
|
||||
|
||||
return roundSeconds(interpolate(options.onlineMinSeconds ?? 1, options.onlineMaxSeconds ?? 12, clampUnit(rng())));
|
||||
}
|
||||
|
||||
function interpolate(min: number, max: number, ratio: number): number {
|
||||
return min + (max - min) * ratio;
|
||||
}
|
||||
|
||||
function clampUnit(value: number): number {
|
||||
if (Number.isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.min(1, Math.max(0, value));
|
||||
}
|
||||
|
||||
function roundSeconds(value: number): number {
|
||||
return Math.round(value * 1_000_000) / 1_000_000;
|
||||
}
|
||||
Reference in New Issue
Block a user