This commit is contained in:
2025-11-10 20:50:04 +01:00
parent 449f7e2daa
commit f0d864c2aa
2 changed files with 90 additions and 6 deletions

View File

@@ -11,7 +11,7 @@ const { scheduleConfig } = require('./services/pickupScheduler');
const adminConfig = require('./services/adminConfig');
const { readNotificationSettings, writeNotificationSettings } = require('./services/userSettingsStore');
const notificationService = require('./services/notificationService');
const { readStoreWatch, writeStoreWatch } = require('./services/storeWatchStore');
const { readStoreWatch, writeStoreWatch, listWatcherProfiles } = require('./services/storeWatchStore');
const { readPreferences, writePreferences } = require('./services/userPreferencesStore');
const { readStoreStatus, writeStoreStatus } = require('./services/storeStatusStore');
@@ -145,12 +145,63 @@ function getCachedStoreStatus(storeId) {
return storeStatusCache.get(String(storeId)) || null;
}
async function refreshStoreStatus(storeIds = [], cookieHeader, { force = false } = {}) {
async function notifyWatchersForStatusChanges(changes = [], storeInfoMap = new Map()) {
if (!Array.isArray(changes) || changes.length === 0) {
return;
}
const changeMap = new Map();
changes.forEach((change) => {
if (!change) {
return;
}
changeMap.set(String(change.storeId), change);
});
if (changeMap.size === 0) {
return;
}
const profiles = listWatcherProfiles();
for (const profileId of profiles) {
const watchers = readStoreWatch(profileId);
if (!Array.isArray(watchers) || watchers.length === 0) {
continue;
}
let changed = false;
for (const watcher of watchers) {
const change = changeMap.get(String(watcher.storeId));
if (!change) {
continue;
}
if (watcher.lastTeamSearchStatus !== change.newStatus) {
if (change.newStatus === 1 && watcher.lastTeamSearchStatus !== 1) {
const details = storeInfoMap.get(String(watcher.storeId)) || {};
await notificationService.sendStoreWatchNotification({
profileId,
storeName: details.name || watcher.storeName,
storeId: watcher.storeId,
regionName: details.region?.name || watcher.regionName
});
}
watcher.lastTeamSearchStatus = change.newStatus;
changed = true;
}
}
if (changed) {
writeStoreWatch(profileId, watchers);
}
}
}
async function refreshStoreStatus(
storeIds = [],
cookieHeader,
{ force = false, storeInfoMap = new Map() } = {}
) {
if (!Array.isArray(storeIds) || storeIds.length === 0 || !cookieHeader) {
return { refreshed: 0 };
return { refreshed: 0, changes: [] };
}
const now = Date.now();
let refreshed = 0;
const changes = [];
for (const id of storeIds) {
const storeId = String(id);
const entry = storeStatusCache.get(storeId);
@@ -162,10 +213,22 @@ async function refreshStoreStatus(storeIds = [], cookieHeader, { force = false }
const details = await foodsharingClient.fetchStoreDetails(storeId, cookieHeader);
const status = Number(details?.teamSearchStatus);
const normalized = Number.isFinite(status) ? status : null;
const previous = entry ? entry.teamSearchStatus : null;
storeStatusCache.set(storeId, {
teamSearchStatus: normalized,
fetchedAt: now
});
if (previous !== normalized) {
const info = storeInfoMap.get(storeId) || {};
changes.push({
storeId,
previousStatus: previous,
newStatus: normalized,
fetchedAt: now,
storeName: info.name || null,
regionName: info.region?.name || info.regionName || null
});
}
refreshed += 1;
} catch (error) {
console.error(`[STORE-STATUS] Status für Store ${storeId} konnte nicht aktualisiert werden:`, error.message);
@@ -174,7 +237,7 @@ async function refreshStoreStatus(storeIds = [], cookieHeader, { force = false }
if (refreshed > 0) {
persistStoreStatusCache();
}
return { refreshed };
return { refreshed, changes };
}
async function enrichStoresWithTeamStatus(stores = [], cookieHeader, { forceRefresh = false } = {}) {
@@ -184,7 +247,11 @@ async function enrichStoresWithTeamStatus(stores = [], cookieHeader, { forceRefr
const now = Date.now();
const staleIds = [];
let cacheHits = 0;
const storeInfoMap = new Map();
stores.forEach((store) => {
if (store?.id) {
storeInfoMap.set(String(store.id), store);
}
const entry = getCachedStoreStatus(store.id);
const fresh = entry && now - (entry.fetchedAt || 0) <= STORE_STATUS_MAX_AGE_MS;
if (entry && fresh && !forceRefresh) {
@@ -197,9 +264,14 @@ async function enrichStoresWithTeamStatus(stores = [], cookieHeader, { forceRefr
});
let refreshed = 0;
let changes = [];
if (staleIds.length > 0) {
const result = await refreshStoreStatus(staleIds, cookieHeader, { force: forceRefresh });
const result = await refreshStoreStatus(staleIds, cookieHeader, {
force: forceRefresh,
storeInfoMap
});
refreshed = result.refreshed || 0;
changes = result.changes || [];
}
stores.forEach((store) => {
@@ -222,6 +294,9 @@ async function enrichStoresWithTeamStatus(stores = [], cookieHeader, { forceRefr
missing: stores.filter((store) => store.teamStatusUpdatedAt == null).length,
generatedAt: Date.now()
};
if (changes.length > 0) {
await notifyWatchersForStatusChanges(changes, storeInfoMap);
}
return { stores, statusMeta };
}