Skip to content

Commit d71890e

Browse files
committed
refactor(orchestrator): modularize start() and centralize state
- extract initializeState, setupMessenger, setupSessionManager, setupLimiter, setupStorageListener, runInitialChecks, and setupTracker from monolithic start() - promote limiter and reactive state (currentLimit, isLimitEnabled, etc.) to class fields - replace safeBlock closure with evaluateAndEnforceBlock private method - merge time-related storage change handlers into a single conditional block - add orchestrator.test.ts covering startup and bypass enforcement scenarios
1 parent ef7803c commit d71890e

2 files changed

Lines changed: 266 additions & 101 deletions

File tree

src/app/orchestrator.ts

Lines changed: 123 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,15 @@ export class AppOrchestrator {
1919
private sessionManager!: SessionManager;
2020
private messenger!: Messenger;
2121
private tracker!: Tracker;
22-
22+
private limiter!: Limiter;
2323
private storageListener: ((changes: Record<string, StorageChange>) => void) | null = null;
2424

25+
private currentLimit: number = 0;
26+
private isLimitEnabled: boolean = false;
27+
private timeLimitMins: number = 0;
28+
private isTimeEnabled: boolean = false;
29+
private timeSpentMs: number = 0;
30+
2531
constructor(
2632
adapter: PlatformAdapter,
2733
messageBus: MessageBus,
@@ -36,134 +42,159 @@ export class AppOrchestrator {
3642

3743
public async start() {
3844
initOverlayListeners();
45+
await this.initializeState();
3946

40-
const pId = this.activeAdapter.id;
41-
42-
const safeBlock = async (reason: string = 'time') => {
43-
if (this.isBlocked) return;
44-
45-
const reallyBlocked = await this.storage.isCurrentlyBlocked(pId);
46-
if (!reallyBlocked) return;
47-
48-
this.isBlocked = true;
49-
50-
let finalReason = reason;
47+
this.setupMessenger();
48+
await this.setupSessionManager();
49+
await this.setupLimiter();
50+
this.setupStorageListener();
5151

52-
if (reason !== 'bypass') {
53-
const isLimitEnabled = await this.storage.getEnableLimit(pId);
54-
const limit = await this.storage.getLimit(pId);
55-
const count = await this.storage.getCount(pId);
56-
const limitReached = isLimitEnabled && limit > 0 && count >= limit;
57-
58-
const isTimeEnabled = await this.storage.getEnableTime(pId);
59-
const timeLimit = await this.storage.getTimeLimit(pId);
60-
const timeSpent = await this.storage.getTimeSpent(pId);
61-
const timeReached = isTimeEnabled && timeLimit > 0 && timeSpent >= timeLimit * 60 * 1000;
62-
63-
if (limitReached && timeReached) {
64-
finalReason = 'both';
65-
} else if (limitReached) {
66-
finalReason = 'count';
67-
} else if (timeReached) {
68-
finalReason = 'time';
69-
}
70-
}
52+
await this.runInitialChecks();
53+
this.setupTracker();
54+
}
7155

72-
console.warn(`[Limitra] Initiating block logic. Reason: ${finalReason}`);
73-
if (this.sessionManager) {
74-
await this.sessionManager.blockSession();
75-
}
76-
this.activeAdapter.executePunishment();
77-
await showOverlay(finalReason);
78-
};
56+
private async initializeState() {
57+
const pId = this.activeAdapter.id;
58+
this.currentLimit = await this.storage.getLimit(pId);
59+
this.isLimitEnabled = await this.storage.getEnableLimit(pId);
60+
this.timeLimitMins = await this.storage.getTimeLimit(pId);
61+
this.isTimeEnabled = await this.storage.getEnableTime(pId);
62+
this.timeSpentMs = await this.storage.getTimeSpent(pId);
63+
}
7964

65+
private setupMessenger() {
8066
this.messenger = new Messenger(
81-
() => {
82-
void safeBlock('time');
83-
},
67+
() => void this.evaluateAndEnforceBlock('time'),
8468
this.messageBus,
85-
pId,
69+
this.activeAdapter.id,
8670
);
87-
8871
this.messenger.init();
72+
}
8973

74+
private async setupSessionManager() {
9075
this.sessionManager = new SessionManager(
9176
this.messenger,
9277
this.activeAdapter,
9378
this.connectionManager,
9479
this.storage,
9580
);
9681
await this.sessionManager.init();
82+
}
9783

98-
let limit = await this.storage.getLimit(pId);
99-
const initialCount = await this.storage.getCount(pId);
100-
let isLimitEnabled = await this.storage.getEnableLimit(pId);
101-
102-
let timeLimitMins = await this.storage.getTimeLimit(pId);
103-
let timeSpentMs = await this.storage.getTimeSpent(pId);
104-
let isTimeEnabled = await this.storage.getEnableTime(pId);
105-
106-
const limiter = new Limiter(
107-
{ limit: isLimitEnabled ? limit : 0 },
84+
private async setupLimiter() {
85+
const pId = this.activeAdapter.id;
86+
this.limiter = new Limiter(
87+
{ limit: this.isLimitEnabled ? this.currentLimit : 0 },
10888
{
10989
onWarning: (count) => console.warn('Warning at', count),
11090
onBlock: () => {
111-
if (limiter.getLimit() > 0) void safeBlock('count');
91+
if (this.limiter.getLimit() > 0) void this.evaluateAndEnforceBlock('count');
11292
},
11393
},
11494
);
115-
limiter.setInitialCount(initialCount);
95+
const initialCount = await this.storage.getCount(pId);
96+
this.limiter.setInitialCount(initialCount);
97+
}
98+
99+
private async evaluateAndEnforceBlock(reason: string = 'time') {
100+
if (this.isBlocked) return;
101+
const pId = this.activeAdapter.id;
116102

103+
const reallyBlocked = await this.storage.isCurrentlyBlocked(pId);
104+
if (!reallyBlocked) return;
105+
106+
this.isBlocked = true;
107+
let finalReason = reason;
108+
109+
if (reason !== 'bypass') {
110+
const count = await this.storage.getCount(pId);
111+
const limitReached =
112+
this.isLimitEnabled && this.currentLimit > 0 && count >= this.currentLimit;
113+
const timeReached =
114+
this.isTimeEnabled &&
115+
this.timeLimitMins > 0 &&
116+
this.timeSpentMs >= this.timeLimitMins * 60 * 1000;
117+
118+
if (limitReached && timeReached) {
119+
finalReason = 'both';
120+
} else if (limitReached) {
121+
finalReason = 'count';
122+
} else if (timeReached) {
123+
finalReason = 'time';
124+
}
125+
}
126+
127+
console.warn(`[Limitra] Initiating block logic. Reason: ${finalReason}`);
128+
if (this.sessionManager) {
129+
await this.sessionManager.blockSession();
130+
}
131+
this.activeAdapter.executePunishment();
132+
await showOverlay(finalReason);
133+
}
134+
135+
private setupStorageListener() {
136+
const pId = this.activeAdapter.id;
117137
this.storageListener = (changes: Record<string, StorageChange>) => {
118138
if (changes[`limitra_${pId}_limit`] || changes[`limitra_${pId}_enable_limit`]) {
119-
if (changes[`limitra_${pId}_limit`]) {
120-
limit = Number(changes[`limitra_${pId}_limit`].newValue) || 0;
121-
}
122-
if (changes[`limitra_${pId}_enable_limit`]) {
123-
isLimitEnabled = Boolean(changes[`limitra_${pId}_enable_limit`].newValue);
124-
}
125-
limiter.setLimit(isLimitEnabled ? limit : 0);
139+
if (changes[`limitra_${pId}_limit`])
140+
this.currentLimit = Number(changes[`limitra_${pId}_limit`].newValue) || 0;
141+
if (changes[`limitra_${pId}_enable_limit`])
142+
this.isLimitEnabled = Boolean(changes[`limitra_${pId}_enable_limit`].newValue);
143+
this.limiter.setLimit(this.isLimitEnabled ? this.currentLimit : 0);
126144
}
127145

128146
if (changes[`limitra_${pId}_count`]) {
129147
const newVal = Number(changes[`limitra_${pId}_count`].newValue) || 0;
130-
limiter.setInitialCount(newVal);
131-
if (isLimitEnabled && limit > 0 && newVal >= limit) {
132-
void safeBlock('count');
148+
this.limiter.setInitialCount(newVal);
149+
if (this.isLimitEnabled && this.currentLimit > 0 && newVal >= this.currentLimit) {
150+
void this.evaluateAndEnforceBlock('count');
133151
}
134152
}
135153

136-
if (changes[`limitra_${pId}_time_limit`] || changes[`limitra_${pId}_enable_time`]) {
137-
if (changes[`limitra_${pId}_time_limit`]) {
138-
timeLimitMins = Number(changes[`limitra_${pId}_time_limit`].newValue) || 0;
139-
}
140-
if (changes[`limitra_${pId}_enable_time`]) {
141-
isTimeEnabled = Boolean(changes[`limitra_${pId}_enable_time`].newValue);
142-
}
143-
if (isTimeEnabled && timeLimitMins > 0 && timeSpentMs >= timeLimitMins * 60 * 1000) {
144-
void safeBlock('time');
145-
}
146-
}
147-
148-
if (changes[`limitra_${pId}_time_spent`]) {
149-
timeSpentMs = Number(changes[`limitra_${pId}_time_spent`].newValue) || 0;
150-
if (isTimeEnabled && timeLimitMins > 0 && timeSpentMs >= timeLimitMins * 60 * 1000) {
151-
void safeBlock('time');
154+
if (
155+
changes[`limitra_${pId}_time_limit`] ||
156+
changes[`limitra_${pId}_enable_time`] ||
157+
changes[`limitra_${pId}_time_spent`]
158+
) {
159+
if (changes[`limitra_${pId}_time_limit`])
160+
this.timeLimitMins = Number(changes[`limitra_${pId}_time_limit`].newValue) || 0;
161+
if (changes[`limitra_${pId}_enable_time`])
162+
this.isTimeEnabled = Boolean(changes[`limitra_${pId}_enable_time`].newValue);
163+
if (changes[`limitra_${pId}_time_spent`])
164+
this.timeSpentMs = Number(changes[`limitra_${pId}_time_spent`].newValue) || 0;
165+
166+
if (
167+
this.isTimeEnabled &&
168+
this.timeLimitMins > 0 &&
169+
this.timeSpentMs >= this.timeLimitMins * 60 * 1000
170+
) {
171+
void this.evaluateAndEnforceBlock('time');
152172
}
153173
}
154174
};
155-
156175
this.storage.onChange(this.storageListener);
176+
}
157177

178+
private async runInitialChecks() {
179+
const pId = this.activeAdapter.id;
158180
const bypassed = await this.storage.detectBypass(pId);
181+
const count = await this.storage.getCount(pId);
182+
159183
if (bypassed) {
160-
await safeBlock('bypass');
161-
} else if (isLimitEnabled && initialCount >= limit && limit > 0) {
162-
await safeBlock('count');
163-
} else if (isTimeEnabled && timeLimitMins > 0 && timeSpentMs >= timeLimitMins * 60 * 1000) {
164-
await safeBlock('time');
184+
await this.evaluateAndEnforceBlock('bypass');
185+
} else if (this.isLimitEnabled && count >= this.currentLimit && this.currentLimit > 0) {
186+
await this.evaluateAndEnforceBlock('count');
187+
} else if (
188+
this.isTimeEnabled &&
189+
this.timeLimitMins > 0 &&
190+
this.timeSpentMs >= this.timeLimitMins * 60 * 1000
191+
) {
192+
await this.evaluateAndEnforceBlock('time');
165193
}
194+
}
166195

196+
private setupTracker() {
197+
const pId = this.activeAdapter.id;
167198
this.tracker = new Tracker(async () => {
168199
if (this.isBlocked) {
169200
const overlay = document.getElementById('limitra-overlay');
@@ -182,8 +213,7 @@ export class AppOrchestrator {
182213
}
183214
return;
184215
}
185-
186-
if (isLimitEnabled && limit > 0) {
216+
if (this.isLimitEnabled && this.currentLimit > 0) {
187217
await this.storage.incrementCount(pId);
188218
}
189219
});
@@ -196,18 +226,10 @@ export class AppOrchestrator {
196226
this.storage.removeListener(this.storageListener);
197227
this.storageListener = null;
198228
}
199-
if (this.messenger) {
200-
this.messenger.destroy();
201-
}
202-
if (this.activeAdapter) {
203-
this.activeAdapter.disconnect();
204-
}
205-
if (this.sessionManager) {
206-
this.sessionManager.destroy();
207-
}
208-
if (this.tracker) {
209-
this.tracker.destroy();
210-
}
229+
if (this.messenger) this.messenger.destroy();
230+
if (this.activeAdapter) this.activeAdapter.disconnect();
231+
if (this.sessionManager) this.sessionManager.destroy();
232+
if (this.tracker) this.tracker.destroy();
211233

212234
const overlay = document.getElementById('limitra-overlay');
213235
if (overlay) overlay.remove();

0 commit comments

Comments
 (0)