refactor: make PALDRA match PDCA style exactly - remove redundant instanceConfig parameter and convert to pure singleton
All checks were successful
All checks were successful
- Remove instanceConfig parameter from all retriever methods (getTags, getQueue, getHistory) - Retriever instances now use this.url, this.apiKey, this.id instead of passed parameter - Convert ArrRetrieverRegistry from class with convenience functions to pure singleton object - Export singleton instance directly instead of class + convenience functions - Update poller.js and historyFetcher.js to call methods on singleton directly - All 261 tests pass with zero behavior changes
This commit is contained in:
@@ -16,13 +16,11 @@ const retrieverClasses = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Registry and factory for *arr data retrievers
|
||||
* Singleton registry for *arr data retrievers
|
||||
*/
|
||||
class ArrRetrieverRegistry {
|
||||
constructor() {
|
||||
this.retrievers = new Map();
|
||||
this.initialized = false;
|
||||
}
|
||||
const arrRetrieverRegistry = {
|
||||
retrievers: new Map(),
|
||||
initialized: false,
|
||||
|
||||
/**
|
||||
* Initialize all configured *arr retrievers
|
||||
@@ -62,7 +60,7 @@ class ArrRetrieverRegistry {
|
||||
|
||||
this.initialized = true;
|
||||
logToFile(`[ArrRetrieverRegistry] Initialized ${this.retrievers.size} *arr retrievers`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get all registered retrievers
|
||||
@@ -70,7 +68,7 @@ class ArrRetrieverRegistry {
|
||||
*/
|
||||
getAllRetrievers() {
|
||||
return Array.from(this.retrievers.values());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get retriever by instance ID
|
||||
@@ -79,7 +77,7 @@ class ArrRetrieverRegistry {
|
||||
*/
|
||||
getRetriever(instanceId) {
|
||||
return this.retrievers.get(instanceId) || null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get retrievers by type
|
||||
@@ -88,7 +86,7 @@ class ArrRetrieverRegistry {
|
||||
*/
|
||||
getRetrieversByType(type) {
|
||||
return this.getAllRetrievers().filter(retriever => retriever.getRetrieverType() === type);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get tags from all retrievers
|
||||
@@ -104,7 +102,7 @@ class ArrRetrieverRegistry {
|
||||
const results = await Promise.allSettled(
|
||||
retrievers.map(async (retriever) => {
|
||||
try {
|
||||
const tags = await retriever.getTags(retriever);
|
||||
const tags = await retriever.getTags();
|
||||
logToFile(`[ArrRetrieverRegistry] ${retriever.name}: ${tags.length} tags`);
|
||||
return { instance: retriever.getInstanceId(), data: tags };
|
||||
} catch (error) {
|
||||
@@ -117,7 +115,7 @@ class ArrRetrieverRegistry {
|
||||
return results
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get queue from all retrievers
|
||||
@@ -133,7 +131,7 @@ class ArrRetrieverRegistry {
|
||||
const results = await Promise.allSettled(
|
||||
retrievers.map(async (retriever) => {
|
||||
try {
|
||||
const queue = await retriever.getQueue(retriever);
|
||||
const queue = await retriever.getQueue();
|
||||
logToFile(`[ArrRetrieverRegistry] ${retriever.name}: ${(queue.records || []).length} queue items`);
|
||||
return { instance: retriever.getInstanceId(), data: queue };
|
||||
} catch (error) {
|
||||
@@ -146,7 +144,7 @@ class ArrRetrieverRegistry {
|
||||
return results
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get history from all retrievers
|
||||
@@ -163,7 +161,7 @@ class ArrRetrieverRegistry {
|
||||
const results = await Promise.allSettled(
|
||||
retrievers.map(async (retriever) => {
|
||||
try {
|
||||
const history = await retriever.getHistory(retriever, options);
|
||||
const history = await retriever.getHistory(options);
|
||||
logToFile(`[ArrRetrieverRegistry] ${retriever.name}: ${(history.records || []).length} history records`);
|
||||
return { instance: retriever.getInstanceId(), data: history };
|
||||
} catch (error) {
|
||||
@@ -176,7 +174,7 @@ class ArrRetrieverRegistry {
|
||||
return results
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get tags grouped by retriever type
|
||||
@@ -189,7 +187,7 @@ class ArrRetrieverRegistry {
|
||||
const sonarrTags = await Promise.allSettled(
|
||||
sonarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const tags = await retriever.getTags(retriever);
|
||||
const tags = await retriever.getTags();
|
||||
return { instance: retriever.getInstanceId(), data: tags };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching tags from ${retriever.name}: ${error.message}`);
|
||||
@@ -201,7 +199,7 @@ class ArrRetrieverRegistry {
|
||||
const radarrTags = await Promise.allSettled(
|
||||
radarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const tags = await retriever.getTags(retriever);
|
||||
const tags = await retriever.getTags();
|
||||
return { instance: retriever.getInstanceId(), data: tags };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching tags from ${retriever.name}: ${error.message}`);
|
||||
@@ -218,7 +216,7 @@ class ArrRetrieverRegistry {
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value)
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get queue grouped by retriever type
|
||||
@@ -231,7 +229,7 @@ class ArrRetrieverRegistry {
|
||||
const sonarrQueues = await Promise.allSettled(
|
||||
sonarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const queue = await retriever.getQueue(retriever);
|
||||
const queue = await retriever.getQueue();
|
||||
return { instance: retriever.getInstanceId(), data: queue };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching queue from ${retriever.name}: ${error.message}`);
|
||||
@@ -243,7 +241,7 @@ class ArrRetrieverRegistry {
|
||||
const radarrQueues = await Promise.allSettled(
|
||||
radarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const queue = await retriever.getQueue(retriever);
|
||||
const queue = await retriever.getQueue();
|
||||
return { instance: retriever.getInstanceId(), data: queue };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching queue from ${retriever.name}: ${error.message}`);
|
||||
@@ -260,7 +258,7 @@ class ArrRetrieverRegistry {
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.map(result => result.value)
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get history grouped by retriever type
|
||||
@@ -274,7 +272,7 @@ class ArrRetrieverRegistry {
|
||||
const sonarrHistory = await Promise.allSettled(
|
||||
sonarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const history = await retriever.getHistory(retriever, options);
|
||||
const history = await retriever.getHistory(options);
|
||||
return { instance: retriever.getInstanceId(), data: history };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching history from ${retriever.name}: ${error.message}`);
|
||||
@@ -286,7 +284,7 @@ class ArrRetrieverRegistry {
|
||||
const radarrHistory = await Promise.allSettled(
|
||||
radarrRetrievers.map(async (retriever) => {
|
||||
try {
|
||||
const history = await retriever.getHistory(retriever, options);
|
||||
const history = await retriever.getHistory(options);
|
||||
return { instance: retriever.getInstanceId(), data: history };
|
||||
} catch (error) {
|
||||
logToFile(`[ArrRetrieverRegistry] Error fetching history from ${retriever.name}: ${error.message}`);
|
||||
@@ -304,24 +302,6 @@ class ArrRetrieverRegistry {
|
||||
.map(result => result.value)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Create singleton instance
|
||||
const registry = new ArrRetrieverRegistry();
|
||||
|
||||
module.exports = {
|
||||
ArrRetrieverRegistry,
|
||||
registry,
|
||||
|
||||
// Convenience functions
|
||||
initializeRetrievers: () => registry.initialize(),
|
||||
getAllRetrievers: () => registry.getAllRetrievers(),
|
||||
getRetriever: (instanceId) => registry.getRetriever(instanceId),
|
||||
getRetrieversByType: (type) => registry.getRetrieversByType(type),
|
||||
getAllTags: () => registry.getAllTags(),
|
||||
getAllQueues: () => registry.getAllQueues(),
|
||||
getAllHistory: (options) => registry.getAllHistory(options),
|
||||
getTagsByType: () => registry.getTagsByType(),
|
||||
getQueuesByType: () => registry.getQueuesByType(),
|
||||
getHistoryByType: (options) => registry.getHistoryByType(options)
|
||||
};
|
||||
|
||||
module.exports = arrRetrieverRegistry;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2026 Gordon Bolton. MIT License.
|
||||
const cache = require('./cache');
|
||||
const { getSonarrInstances, getRadarrInstances } = require('./config');
|
||||
const { initializeRetrievers, getRetrieversByType } = require('./arrRetrievers');
|
||||
const arrRetrieverRegistry = require('./arrRetrievers');
|
||||
|
||||
// Cache TTL for recent-history data: 5 minutes.
|
||||
// History changes slowly compared to active downloads.
|
||||
@@ -27,17 +27,17 @@ async function fetchSonarrHistory(since) {
|
||||
if (cached) return cached;
|
||||
|
||||
// Ensure retrievers are initialized
|
||||
await initializeRetrievers();
|
||||
await arrRetrieverRegistry.initialize();
|
||||
|
||||
const instances = getSonarrInstances();
|
||||
const sonarrRetrievers = getRetrieversByType('sonarr');
|
||||
const sonarrRetrievers = arrRetrieverRegistry.getRetrieversByType('sonarr');
|
||||
|
||||
const results = await Promise.all(sonarrRetrievers.map(async (retriever) => {
|
||||
const inst = instances.find(i => i.id === retriever.getInstanceId());
|
||||
if (!inst) return [];
|
||||
|
||||
try {
|
||||
const response = await retriever.getHistory(retriever, {
|
||||
const response = await retriever.getHistory({
|
||||
pageSize: 100,
|
||||
sortKey: 'date',
|
||||
sortDir: 'descending',
|
||||
@@ -76,17 +76,17 @@ async function fetchRadarrHistory(since) {
|
||||
if (cached) return cached;
|
||||
|
||||
// Ensure retrievers are initialized
|
||||
await initializeRetrievers();
|
||||
await arrRetrieverRegistry.initialize();
|
||||
|
||||
const instances = getRadarrInstances();
|
||||
const radarrRetrievers = getRetrieversByType('radarr');
|
||||
const radarrRetrievers = arrRetrieverRegistry.getRetrieversByType('radarr');
|
||||
|
||||
const results = await Promise.all(radarrRetrievers.map(async (retriever) => {
|
||||
const inst = instances.find(i => i.id === retriever.getInstanceId());
|
||||
if (!inst) return [];
|
||||
|
||||
try {
|
||||
const response = await retriever.getHistory(retriever, {
|
||||
const response = await retriever.getHistory({
|
||||
pageSize: 100,
|
||||
sortKey: 'date',
|
||||
sortDir: 'descending',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
const axios = require('axios');
|
||||
const cache = require('./cache');
|
||||
const { initializeClients, getAllDownloads, getDownloadsByClientType } = require('./downloadClients');
|
||||
const { initializeRetrievers, getTagsByType, getQueuesByType, getHistoryByType } = require('./arrRetrievers');
|
||||
const arrRetrieverRegistry = require('./arrRetrievers');
|
||||
const {
|
||||
getSonarrInstances,
|
||||
getRadarrInstances
|
||||
@@ -41,7 +41,7 @@ async function pollAllServices() {
|
||||
try {
|
||||
// Ensure download clients and *arr retrievers are initialized
|
||||
await initializeClients();
|
||||
await initializeRetrievers();
|
||||
await arrRetrieverRegistry.initialize();
|
||||
|
||||
const sonarrInstances = getSonarrInstances();
|
||||
const radarrInstances = getRadarrInstances();
|
||||
@@ -53,27 +53,27 @@ async function pollAllServices() {
|
||||
return downloadsByType;
|
||||
}),
|
||||
timed('Sonarr Tags', async () => {
|
||||
const tagsByType = await getTagsByType();
|
||||
const tagsByType = await arrRetrieverRegistry.getTagsByType();
|
||||
return tagsByType.sonarr || [];
|
||||
}),
|
||||
timed('Sonarr Queue', async () => {
|
||||
const queuesByType = await getQueuesByType();
|
||||
const queuesByType = await arrRetrieverRegistry.getQueuesByType();
|
||||
return queuesByType.sonarr || [];
|
||||
}),
|
||||
timed('Sonarr History', async () => {
|
||||
const historyByType = await getHistoryByType({ pageSize: 10 });
|
||||
const historyByType = await arrRetrieverRegistry.getHistoryByType({ pageSize: 10 });
|
||||
return historyByType.sonarr || [];
|
||||
}),
|
||||
timed('Radarr Queue', async () => {
|
||||
const queuesByType = await getQueuesByType();
|
||||
const queuesByType = await arrRetrieverRegistry.getQueuesByType();
|
||||
return queuesByType.radarr || [];
|
||||
}),
|
||||
timed('Radarr History', async () => {
|
||||
const historyByType = await getHistoryByType({ pageSize: 10 });
|
||||
const historyByType = await arrRetrieverRegistry.getHistoryByType({ pageSize: 10 });
|
||||
return historyByType.radarr || [];
|
||||
}),
|
||||
timed('Radarr Tags', async () => {
|
||||
const tagsByType = await getTagsByType();
|
||||
const tagsByType = await arrRetrieverRegistry.getTagsByType();
|
||||
return tagsByType.radarr || [];
|
||||
}),
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user