watcher
This commit is contained in:
85
server.js
85
server.js
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,16 @@ function writeStoreWatch(profileId, entries = []) {
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
function listWatcherProfiles() {
|
||||
ensureDir();
|
||||
return fs
|
||||
.readdirSync(STORE_WATCH_DIR)
|
||||
.filter((file) => file.endsWith('-store-watch.json'))
|
||||
.map((file) => file.replace(/-store-watch\.json$/, ''));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
readStoreWatch,
|
||||
writeStoreWatch
|
||||
writeStoreWatch,
|
||||
listWatcherProfiles
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user