feat(backend): Basic state save/restore
This commit is contained in:
parent
212c544eb1
commit
81b18df1f4
1 changed files with 48 additions and 0 deletions
|
@ -1,10 +1,13 @@
|
||||||
import {fetchMetadata} from "./services/metadata";
|
import {fetchMetadata} from "./services/metadata";
|
||||||
import {DEFAULT_LUCIDA_OPTIONS, DownloadResult, LucidaOptions, ProcessingQueue, Queue, QueueItem} from "./types/queue";
|
import {DEFAULT_LUCIDA_OPTIONS, DownloadResult, LucidaOptions, ProcessingQueue, Queue, QueueItem} from "./types/queue";
|
||||||
import Lucida from "./services/lucida";
|
import Lucida from "./services/lucida";
|
||||||
|
import * as fs from "node:fs";
|
||||||
|
|
||||||
const TIMEOUT: number = 120000;
|
const TIMEOUT: number = 120000;
|
||||||
const RETRIES: number = 5;
|
const RETRIES: number = 5;
|
||||||
|
|
||||||
|
const STATE_FILE: string = '/data/state.json';
|
||||||
|
|
||||||
class QueueManager {
|
class QueueManager {
|
||||||
private readonly queue: Queue;
|
private readonly queue: Queue;
|
||||||
private readonly processing: ProcessingQueue;
|
private readonly processing: ProcessingQueue;
|
||||||
|
@ -20,6 +23,42 @@ class QueueManager {
|
||||||
|
|
||||||
this.lucida = null;
|
this.lucida = null;
|
||||||
this.lucidaOptions = DEFAULT_LUCIDA_OPTIONS;
|
this.lucidaOptions = DEFAULT_LUCIDA_OPTIONS;
|
||||||
|
|
||||||
|
this.loadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveState(): void {
|
||||||
|
const state = {
|
||||||
|
queue: this.processing.map(pi => pi.item).concat(this.queue),
|
||||||
|
history: this.history
|
||||||
|
};
|
||||||
|
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadState(): void {
|
||||||
|
if (!fs.existsSync(STATE_FILE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
|
||||||
|
|
||||||
|
console.log('QueueManager: Restoring state:', state);
|
||||||
|
|
||||||
|
this.queue.push(...state.queue);
|
||||||
|
|
||||||
|
state.history.forEach((item: QueueItem) => {
|
||||||
|
if (!this.queue.some(q => q.id === item.id)) {
|
||||||
|
if (item.result?.success) {
|
||||||
|
// Add successful items to the history
|
||||||
|
this.history.push(item);
|
||||||
|
} else {
|
||||||
|
// Add failed items to the queue
|
||||||
|
this.queue.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.processQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setLucidaOptions(options: LucidaOptions): void {
|
public setLucidaOptions(options: LucidaOptions): void {
|
||||||
|
@ -58,6 +97,7 @@ class QueueManager {
|
||||||
song: await fetchMetadata(song)
|
song: await fetchMetadata(song)
|
||||||
};
|
};
|
||||||
this.queue.push(item);
|
this.queue.push(item);
|
||||||
|
this.saveState();
|
||||||
this.processQueue();
|
this.processQueue();
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
@ -74,6 +114,7 @@ class QueueManager {
|
||||||
song: await fetchMetadata(song)
|
song: await fetchMetadata(song)
|
||||||
};
|
};
|
||||||
this.queue.splice(index, 0, item);
|
this.queue.splice(index, 0, item);
|
||||||
|
this.saveState();
|
||||||
this.processQueue();
|
this.processQueue();
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
@ -87,11 +128,13 @@ class QueueManager {
|
||||||
|
|
||||||
const item: QueueItem = this.queue[index];
|
const item: QueueItem = this.queue[index];
|
||||||
this.queue.splice(index, 1);
|
this.queue.splice(index, 1);
|
||||||
|
this.saveState();
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear(): void {
|
public clear(): void {
|
||||||
this.queue.length = 0;
|
this.queue.length = 0;
|
||||||
|
this.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public move(song: string, to: number): QueueItem {
|
public move(song: string, to: number): QueueItem {
|
||||||
|
@ -102,6 +145,7 @@ class QueueManager {
|
||||||
|
|
||||||
const item: QueueItem = this.queue.splice(index, 1)[0];
|
const item: QueueItem = this.queue.splice(index, 1)[0];
|
||||||
this.queue.splice(to, 0, item);
|
this.queue.splice(to, 0, item);
|
||||||
|
this.saveState();
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +158,7 @@ class QueueManager {
|
||||||
const item: QueueItem = this.history.splice(index, 1)[0];
|
const item: QueueItem = this.history.splice(index, 1)[0];
|
||||||
item.retries = 0;
|
item.retries = 0;
|
||||||
this.queue.push(item);
|
this.queue.push(item);
|
||||||
|
this.saveState();
|
||||||
this.processQueue();
|
this.processQueue();
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
@ -149,9 +194,11 @@ class QueueManager {
|
||||||
item.timeout = (item.timeout ?? TIMEOUT) * 2;
|
item.timeout = (item.timeout ?? TIMEOUT) * 2;
|
||||||
item.result = result;
|
item.result = result;
|
||||||
this.queue.push(item);
|
this.queue.push(item);
|
||||||
|
this.saveState();
|
||||||
} else {
|
} else {
|
||||||
item.result = result;
|
item.result = result;
|
||||||
this.history.push(item);
|
this.history.push(item);
|
||||||
|
this.saveState();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
item.result = {
|
item.result = {
|
||||||
|
@ -159,6 +206,7 @@ class QueueManager {
|
||||||
error: err instanceof Error ? err.message : 'Unknown error'
|
error: err instanceof Error ? err.message : 'Unknown error'
|
||||||
};
|
};
|
||||||
this.history.push(item);
|
this.history.push(item);
|
||||||
|
this.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processing.splice(this.processing.indexOf(current), 1);
|
this.processing.splice(this.processing.indexOf(current), 1);
|
||||||
|
|
Reference in a new issue