minor changes

This commit is contained in:
2025-11-10 21:14:20 +01:00
parent 5c4f136703
commit 7cdd18bf7f
4 changed files with 52 additions and 6 deletions

View File

@@ -13,6 +13,7 @@ const DEFAULT_SETTINGS = {
storeWatchCron: '*/30 * * * *', storeWatchCron: '*/30 * * * *',
storeWatchInitialDelayMinSeconds: 10, storeWatchInitialDelayMinSeconds: 10,
storeWatchInitialDelayMaxSeconds: 60, storeWatchInitialDelayMaxSeconds: 60,
storeWatchRequestDelayMs: 1000,
storePickupCheckDelayMs: 400, storePickupCheckDelayMs: 400,
ignoredSlots: [ ignoredSlots: [
{ {
@@ -113,6 +114,10 @@ function readSettings() {
parsed.storeWatchInitialDelayMaxSeconds, parsed.storeWatchInitialDelayMaxSeconds,
DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds
), ),
storeWatchRequestDelayMs: sanitizeNumber(
parsed.storeWatchRequestDelayMs,
DEFAULT_SETTINGS.storeWatchRequestDelayMs
),
storePickupCheckDelayMs: sanitizeNumber( storePickupCheckDelayMs: sanitizeNumber(
parsed.storePickupCheckDelayMs, parsed.storePickupCheckDelayMs,
DEFAULT_SETTINGS.storePickupCheckDelayMs DEFAULT_SETTINGS.storePickupCheckDelayMs
@@ -143,6 +148,10 @@ function writeSettings(patch = {}) {
patch.storeWatchInitialDelayMaxSeconds, patch.storeWatchInitialDelayMaxSeconds,
current.storeWatchInitialDelayMaxSeconds current.storeWatchInitialDelayMaxSeconds
), ),
storeWatchRequestDelayMs: sanitizeNumber(
patch.storeWatchRequestDelayMs,
current.storeWatchRequestDelayMs
),
storePickupCheckDelayMs: sanitizeNumber( storePickupCheckDelayMs: sanitizeNumber(
patch.storePickupCheckDelayMs, patch.storePickupCheckDelayMs,
current.storePickupCheckDelayMs current.storePickupCheckDelayMs

View File

@@ -6,6 +6,13 @@ const notificationService = require('./notificationService');
const { readConfig, writeConfig } = require('./configStore'); const { readConfig, writeConfig } = require('./configStore');
const { readStoreWatch, writeStoreWatch } = require('./storeWatchStore'); const { readStoreWatch, writeStoreWatch } = require('./storeWatchStore');
function wait(ms) {
if (!ms || ms <= 0) {
return Promise.resolve();
}
return new Promise((resolve) => setTimeout(resolve, ms));
}
const weekdayMap = { const weekdayMap = {
Montag: 'Monday', Montag: 'Monday',
Dienstag: 'Tuesday', Dienstag: 'Tuesday',
@@ -47,6 +54,9 @@ function resolveSettings(settings) {
storeWatchInitialDelayMaxSeconds: Number.isFinite(settings.storeWatchInitialDelayMaxSeconds) storeWatchInitialDelayMaxSeconds: Number.isFinite(settings.storeWatchInitialDelayMaxSeconds)
? settings.storeWatchInitialDelayMaxSeconds ? settings.storeWatchInitialDelayMaxSeconds
: DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds, : DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds,
storeWatchRequestDelayMs: Number.isFinite(settings.storeWatchRequestDelayMs)
? settings.storeWatchRequestDelayMs
: DEFAULT_SETTINGS.storeWatchRequestDelayMs,
ignoredSlots: Array.isArray(settings.ignoredSlots) ? settings.ignoredSlots : DEFAULT_SETTINGS.ignoredSlots, ignoredSlots: Array.isArray(settings.ignoredSlots) ? settings.ignoredSlots : DEFAULT_SETTINGS.ignoredSlots,
notifications: { notifications: {
ntfy: { ntfy: {
@@ -295,7 +305,7 @@ async function checkEntry(sessionId, entry, settings) {
} }
} }
async function checkWatchedStores(sessionId) { async function checkWatchedStores(sessionId, settings = DEFAULT_SETTINGS) {
const session = sessionStore.get(sessionId); const session = sessionStore.get(sessionId);
if (!session?.profile?.id) { if (!session?.profile?.id) {
return; return;
@@ -310,8 +320,10 @@ async function checkWatchedStores(sessionId) {
return; return;
} }
const perRequestDelay = Math.max(0, Number(settings?.storeWatchRequestDelayMs) || 0);
let changed = false; let changed = false;
for (const watcher of watchers) { for (let index = 0; index < watchers.length; index += 1) {
const watcher = watchers[index];
try { try {
const details = await foodsharingClient.fetchStoreDetails(watcher.storeId, session.cookieHeader); const details = await foodsharingClient.fetchStoreDetails(watcher.storeId, session.cookieHeader);
const status = details?.teamSearchStatus === 1 ? 1 : 0; const status = details?.teamSearchStatus === 1 ? 1 : 0;
@@ -329,6 +341,11 @@ async function checkWatchedStores(sessionId) {
} }
} catch (error) { } catch (error) {
console.error(`[WATCH] Prüfung für Store ${watcher.storeId} fehlgeschlagen:`, error.message); console.error(`[WATCH] Prüfung für Store ${watcher.storeId} fehlgeschlagen:`, error.message);
} finally {
const hasNext = index < watchers.length - 1;
if (hasNext && perRequestDelay > 0) {
await wait(perRequestDelay);
}
} }
} }
@@ -338,6 +355,7 @@ async function checkWatchedStores(sessionId) {
} }
function scheduleStoreWatchers(sessionId, settings) { function scheduleStoreWatchers(sessionId, settings) {
const effectiveSettings = settings || DEFAULT_SETTINGS;
const session = sessionStore.get(sessionId); const session = sessionStore.get(sessionId);
if (!session?.profile?.id) { if (!session?.profile?.id) {
return false; return false;
@@ -346,11 +364,11 @@ function scheduleStoreWatchers(sessionId, settings) {
if (!Array.isArray(watchers) || watchers.length === 0) { if (!Array.isArray(watchers) || watchers.length === 0) {
return false; return false;
} }
const cronExpression = settings.storeWatchCron || DEFAULT_SETTINGS.storeWatchCron; const cronExpression = effectiveSettings.storeWatchCron || DEFAULT_SETTINGS.storeWatchCron;
const job = cron.schedule( const job = cron.schedule(
cronExpression, cronExpression,
() => { () => {
checkWatchedStores(sessionId).catch((error) => { checkWatchedStores(sessionId, effectiveSettings).catch((error) => {
console.error('[WATCH] Regelmäßige Prüfung fehlgeschlagen:', error.message); console.error('[WATCH] Regelmäßige Prüfung fehlgeschlagen:', error.message);
}); });
}, },
@@ -358,8 +376,11 @@ function scheduleStoreWatchers(sessionId, settings) {
); );
sessionStore.attachJob(sessionId, job); sessionStore.attachJob(sessionId, job);
setTimeout( setTimeout(
() => checkWatchedStores(sessionId), () => checkWatchedStores(sessionId, effectiveSettings),
randomDelayMs(settings.storeWatchInitialDelayMinSeconds, settings.storeWatchInitialDelayMaxSeconds) randomDelayMs(
effectiveSettings.storeWatchInitialDelayMinSeconds,
effectiveSettings.storeWatchInitialDelayMaxSeconds
)
); );
console.log( console.log(
`[WATCH] Überwache ${watchers.length} Betriebe für Session ${sessionId} (Cron: ${cronExpression}).` `[WATCH] Überwache ${watchers.length} Betriebe für Session ${sessionId} (Cron: ${cronExpression}).`

View File

@@ -210,6 +210,20 @@ const AdminSettingsPanel = ({
/> />
</div> </div>
</SettingField> </SettingField>
<SettingField
label="Verzögerung zwischen Status-Abfragen (ms)"
description="Pausiert zwischen einzelnen Store-Requests, um das Foodsharing-API zu schonen."
>
<input
type="number"
min="0"
value={adminSettings.storeWatchRequestDelayMs}
onChange={(event) => onSettingChange('storeWatchRequestDelayMs', event.target.value, true)}
className="border rounded p-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-purple-500"
placeholder="z. B. 1000"
/>
</SettingField>
</SettingSection> </SettingSection>
<SettingSection <SettingSection

View File

@@ -12,6 +12,7 @@ export const normalizeAdminSettings = (raw) => {
storeWatchCron: raw.storeWatchCron || '', storeWatchCron: raw.storeWatchCron || '',
storeWatchInitialDelayMinSeconds: raw.storeWatchInitialDelayMinSeconds ?? '', storeWatchInitialDelayMinSeconds: raw.storeWatchInitialDelayMinSeconds ?? '',
storeWatchInitialDelayMaxSeconds: raw.storeWatchInitialDelayMaxSeconds ?? '', storeWatchInitialDelayMaxSeconds: raw.storeWatchInitialDelayMaxSeconds ?? '',
storeWatchRequestDelayMs: raw.storeWatchRequestDelayMs ?? '',
ignoredSlots: Array.isArray(raw.ignoredSlots) ignoredSlots: Array.isArray(raw.ignoredSlots)
? raw.ignoredSlots.map((slot) => ({ ? raw.ignoredSlots.map((slot) => ({
storeId: slot?.storeId ? String(slot.storeId) : '', storeId: slot?.storeId ? String(slot.storeId) : '',
@@ -56,6 +57,7 @@ export const serializeAdminSettings = (adminSettings) => {
storeWatchCron: adminSettings.storeWatchCron, storeWatchCron: adminSettings.storeWatchCron,
storeWatchInitialDelayMinSeconds: toNumberOrUndefined(adminSettings.storeWatchInitialDelayMinSeconds), storeWatchInitialDelayMinSeconds: toNumberOrUndefined(adminSettings.storeWatchInitialDelayMinSeconds),
storeWatchInitialDelayMaxSeconds: toNumberOrUndefined(adminSettings.storeWatchInitialDelayMaxSeconds), storeWatchInitialDelayMaxSeconds: toNumberOrUndefined(adminSettings.storeWatchInitialDelayMaxSeconds),
storeWatchRequestDelayMs: toNumberOrUndefined(adminSettings.storeWatchRequestDelayMs),
ignoredSlots: (adminSettings.ignoredSlots || []).map((slot) => ({ ignoredSlots: (adminSettings.ignoredSlots || []).map((slot) => ({
storeId: slot.storeId || '', storeId: slot.storeId || '',
description: slot.description || '' description: slot.description || ''