mirror of
https://github.com/tiennm99/store-scraper-bot.git
synced 2026-09-03 16:17:08 +00:00
refactor: merge apple/google app caches into one parametrized repo
Two near-identical per-store repository files collapse into a single createAppCacheRepository(handle, prefix, ttl) factory used twice from app-builder. Scrapers now receive the cache directly (one less layer), and the cache entry shape drops the obsolete _id field — the Redis key already encodes the appId.
This commit is contained in:
+10
-15
@@ -10,40 +10,35 @@ export function buildAppleRequestByBundleId(appId, country) {
|
||||
return { appId, country, ratings: true };
|
||||
}
|
||||
|
||||
export function createAppleScraper(config, repository) {
|
||||
export function createAppleScraper(config, cache) {
|
||||
const { logger } = config;
|
||||
const repo = repository.appleApp;
|
||||
|
||||
async function app(req) {
|
||||
return store.app(req);
|
||||
}
|
||||
|
||||
async function rawApp(req) {
|
||||
return JSON.stringify(await app(req));
|
||||
return JSON.stringify(await store.app(req));
|
||||
}
|
||||
|
||||
async function cache(resp) {
|
||||
async function saveCache(resp) {
|
||||
if (!resp || !resp.appId) return;
|
||||
try {
|
||||
await repo.save({ _id: resp.appId, app: resp, millis: Date.now() });
|
||||
await cache.save(resp.appId, resp);
|
||||
} catch (err) {
|
||||
logger.warn({ appId: resp.appId, err: err.message }, 'failed to cache apple app');
|
||||
}
|
||||
}
|
||||
|
||||
async function getApp(appId, country) {
|
||||
const cached = await repo.getCached(appId);
|
||||
const cached = await cache.getCached(appId);
|
||||
if (cached) return cached.app;
|
||||
const resp = await app(buildAppleRequestByBundleId(appId, country));
|
||||
await cache(resp);
|
||||
const resp = await store.app(buildAppleRequestByBundleId(appId, country));
|
||||
await saveCache(resp);
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function fetchAndCache(req) {
|
||||
const resp = await app(req);
|
||||
await cache(resp);
|
||||
const resp = await store.app(req);
|
||||
await saveCache(resp);
|
||||
return resp;
|
||||
}
|
||||
|
||||
return { rawApp, app, getApp, fetchAndCache };
|
||||
return { rawApp, getApp, fetchAndCache };
|
||||
}
|
||||
|
||||
+10
-15
@@ -6,42 +6,37 @@ export function buildGoogleRequest(appId, country) {
|
||||
return { appId, country: country || 'vn' };
|
||||
}
|
||||
|
||||
export function createGoogleScraper(config, repository) {
|
||||
export function createGoogleScraper(config, cache) {
|
||||
const { logger } = config;
|
||||
const repo = repository.googleApp;
|
||||
|
||||
async function app(req) {
|
||||
return gplay.app(req);
|
||||
}
|
||||
|
||||
async function rawApp(req) {
|
||||
return JSON.stringify(await app(req));
|
||||
return JSON.stringify(await gplay.app(req));
|
||||
}
|
||||
|
||||
async function cache(resp, fallbackId) {
|
||||
async function saveCache(resp, fallbackId) {
|
||||
if (!resp) return;
|
||||
const id = resp.appId || fallbackId;
|
||||
if (!id) return;
|
||||
try {
|
||||
await repo.save({ _id: id, app: resp, millis: Date.now() });
|
||||
await cache.save(id, resp);
|
||||
} catch (err) {
|
||||
logger.warn({ appId: id, err: err.message }, 'failed to cache google app');
|
||||
}
|
||||
}
|
||||
|
||||
async function getApp(appId, country) {
|
||||
const cached = await repo.getCached(appId);
|
||||
const cached = await cache.getCached(appId);
|
||||
if (cached) return cached.app;
|
||||
const resp = await app(buildGoogleRequest(appId, country));
|
||||
await cache(resp, appId);
|
||||
const resp = await gplay.app(buildGoogleRequest(appId, country));
|
||||
await saveCache(resp, appId);
|
||||
return resp;
|
||||
}
|
||||
|
||||
async function fetchAndCache(req) {
|
||||
const resp = await app(req);
|
||||
await cache(resp, req.appId);
|
||||
const resp = await gplay.app(req);
|
||||
await saveCache(resp, req.appId);
|
||||
return resp;
|
||||
}
|
||||
|
||||
return { rawApp, app, getApp, fetchAndCache };
|
||||
return { rawApp, getApp, fetchAndCache };
|
||||
}
|
||||
|
||||
+5
-6
@@ -6,8 +6,7 @@ import { loadConfig } from './config.js';
|
||||
import { createUpstashClient } from './repository/upstash.js';
|
||||
import { createAdminRepository } from './repository/admin-repository.js';
|
||||
import { createGroupRepository } from './repository/group-repository.js';
|
||||
import { createAppleAppRepository } from './repository/apple-app-repository.js';
|
||||
import { createGoogleAppRepository } from './repository/google-app-repository.js';
|
||||
import { createAppCacheRepository } from './repository/app-cache-repository.js';
|
||||
import { createAppleScraper } from './api/apple-scraper.js';
|
||||
import { createGoogleScraper } from './api/google-scraper.js';
|
||||
import { createBot } from './bot/bot.js';
|
||||
@@ -18,11 +17,11 @@ export function buildApp(env) {
|
||||
const store = {
|
||||
admin: createAdminRepository(handle),
|
||||
group: createGroupRepository(handle),
|
||||
appleApp: createAppleAppRepository(handle, config.appCacheSeconds),
|
||||
googleApp: createGoogleAppRepository(handle, config.appCacheSeconds),
|
||||
};
|
||||
const appleScraper = createAppleScraper(config, store);
|
||||
const googleScraper = createGoogleScraper(config, store);
|
||||
const appleCache = createAppCacheRepository(handle, 'apple', config.appCacheSeconds);
|
||||
const googleCache = createAppCacheRepository(handle, 'google', config.appCacheSeconds);
|
||||
const appleScraper = createAppleScraper(config, appleCache);
|
||||
const googleScraper = createGoogleScraper(config, googleCache);
|
||||
const { sender, commands } = createBot(config, store, appleScraper, googleScraper);
|
||||
return { config, store, appleScraper, googleScraper, sender, commands };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { getJson, putJson } from './upstash.js';
|
||||
|
||||
// Per-store cache for upstream app responses. TTL via Redis EX —
|
||||
// expired keys are deleted, so a null read is the cache miss.
|
||||
// `prefix` is the logical key namespace ('apple' or 'google').
|
||||
export function createAppCacheRepository(handle, prefix, appCacheSeconds) {
|
||||
function key(appId) {
|
||||
return `${prefix}:${appId}`;
|
||||
}
|
||||
|
||||
return {
|
||||
async getCached(appId) {
|
||||
return getJson(handle, key(appId));
|
||||
},
|
||||
async save(appId, response) {
|
||||
await putJson(
|
||||
handle,
|
||||
key(appId),
|
||||
{ app: response, millis: Date.now() },
|
||||
{ expirationTtl: appCacheSeconds },
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { getJson, putJson } from './upstash.js';
|
||||
|
||||
// Upstash-backed Apple app cache. Logical key shape: `apple:{appId}`.
|
||||
// Redis EX (via expirationTtl) replaces Java/Mongo's manual
|
||||
// `(now - millis) > cacheMillis` check — expired keys are deleted, so a
|
||||
// get() returning null is the cache miss.
|
||||
export function createAppleAppRepository(handle, appCacheSeconds) {
|
||||
function key(appId) {
|
||||
return `apple:${appId}`;
|
||||
}
|
||||
|
||||
async function get(appId) {
|
||||
return getJson(handle, key(appId));
|
||||
}
|
||||
|
||||
async function save(entry) {
|
||||
await putJson(handle, key(entry._id), entry, { expirationTtl: appCacheSeconds });
|
||||
}
|
||||
|
||||
async function getCached(appId) {
|
||||
return get(appId);
|
||||
}
|
||||
|
||||
return { get, save, getCached };
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { getJson, putJson } from './upstash.js';
|
||||
|
||||
// Upstash-backed Google app cache. Logical key shape: `google:{appId}`.
|
||||
// Redis EX (via expirationTtl) replaces Java/Mongo's manual
|
||||
// `(now - millis) > cacheMillis` check — expired keys are deleted, so a
|
||||
// get() returning null is the cache miss.
|
||||
export function createGoogleAppRepository(handle, appCacheSeconds) {
|
||||
function key(appId) {
|
||||
return `google:${appId}`;
|
||||
}
|
||||
|
||||
async function get(appId) {
|
||||
return getJson(handle, key(appId));
|
||||
}
|
||||
|
||||
async function save(entry) {
|
||||
await putJson(handle, key(entry._id), entry, { expirationTtl: appCacheSeconds });
|
||||
}
|
||||
|
||||
async function getCached(appId) {
|
||||
return get(appId);
|
||||
}
|
||||
|
||||
return { get, save, getCached };
|
||||
}
|
||||
Reference in New Issue
Block a user