Linting
This commit is contained in:
@@ -1,28 +1,36 @@
|
||||
import { getAllFeeds, deleteFeedByLink, createPost, getPostByPostId } from '../modules/mongo-wrappers/mongoFeedsWrappers.mjs';
|
||||
import crypto from 'crypto';
|
||||
import { sendPost } from '../discordBot/modules/rssWrappers.mjs';
|
||||
import {
|
||||
getAllFeeds,
|
||||
deleteFeedByLink,
|
||||
createPost,
|
||||
getPostByPostId,
|
||||
} from "../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
|
||||
import crypto from "crypto";
|
||||
import { sendPost } from "../discordBot/modules/rssWrappers.mjs";
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
import { removeSource } from './sourceManager.mjs'
|
||||
import { removeSource } from "./sourceManager.mjs";
|
||||
import UserAgent from "user-agents";
|
||||
import Parser from 'rss-parser';
|
||||
import Parser from "rss-parser";
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
dotenv.config()
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
// Initialize the User-Agent string
|
||||
process.env.USER_AGENT_STRING = new UserAgent({ platform: 'Win32' }).toString();
|
||||
process.env.USER_AGENT_STRING = new UserAgent({ platform: "Win32" }).toString();
|
||||
|
||||
const parser = new Parser({
|
||||
headers: {
|
||||
'User-Agent': process.env.USER_AGENT_STRING,
|
||||
"Accept": "application/rss+xml,application/xhtml+xml,application/xml"
|
||||
}
|
||||
"User-Agent": process.env.USER_AGENT_STRING,
|
||||
Accept: "application/rss+xml,application/xhtml+xml,application/xml",
|
||||
},
|
||||
});
|
||||
|
||||
const log = new DebugBuilder("server", "feedHandler");
|
||||
|
||||
export const returnHash = (...stringsIncluded) => {
|
||||
return crypto.createHash('sha1').update(stringsIncluded.join("-<<??//\\\\??>>-")).digest("base64");
|
||||
return crypto
|
||||
.createHash("sha1")
|
||||
.update(stringsIncluded.join("-<<??//\\\\??>>-"))
|
||||
.digest("base64");
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,43 +45,55 @@ export const updateFeeds = async (client) => {
|
||||
const records = await getAllFeeds();
|
||||
|
||||
const sourcePromiseArray = records.map(async (source) => {
|
||||
log.DEBUG('Processing source:', source.title);
|
||||
log.DEBUG("Processing source:", source.title);
|
||||
|
||||
try {
|
||||
const parsedFeed = await parser.parseURL(source.link);
|
||||
|
||||
if (parsedFeed?.items) {
|
||||
await Promise.all(parsedFeed.items.reverse().map(async (post) => {
|
||||
log.DEBUG("Processing post:", post.title);
|
||||
await Promise.all(
|
||||
parsedFeed.items.reverse().map(async (post) => {
|
||||
log.DEBUG("Processing post:", post.title);
|
||||
|
||||
if (!post.title || !post.link) throw new Error("Missing title or link in the post");
|
||||
if (!post.content && !post['content:encoded']) log.WARN("No content for post:", post.title);
|
||||
if (!post.title || !post.link)
|
||||
throw new Error("Missing title or link in the post");
|
||||
if (!post.content && !post["content:encoded"])
|
||||
log.WARN("No content for post:", post.title);
|
||||
|
||||
post.postId = post.postId ?? post.guid ?? post.id ?? returnHash(post.title, post.link, post.pubDate ?? Date.now());
|
||||
post.postId =
|
||||
post.postId ??
|
||||
post.guid ??
|
||||
post.id ??
|
||||
returnHash(post.title, post.link, post.pubDate ?? Date.now());
|
||||
|
||||
const existingRecord = await getPostByPostId(post.postId);
|
||||
if (!existingRecord) {
|
||||
const channel = client.channels.cache.get(source.channel_id);
|
||||
const sendResults = await sendPost(post, source, channel);
|
||||
if (!sendResults) throw new Error("Failed to send post");
|
||||
const existingRecord = await getPostByPostId(post.postId);
|
||||
if (!existingRecord) {
|
||||
const channel = client.channels.cache.get(source.channel_id);
|
||||
const sendResults = await sendPost(post, source, channel);
|
||||
if (!sendResults) throw new Error("Failed to send post");
|
||||
|
||||
log.DEBUG("Saving post to database:", post.title, source.channel_id);
|
||||
log.DEBUG(
|
||||
"Saving post to database:",
|
||||
post.title,
|
||||
source.channel_id,
|
||||
);
|
||||
|
||||
const postToSave = {
|
||||
title: post.title,
|
||||
link: post.link,
|
||||
pubDate: post.pubDate,
|
||||
author: post.author,
|
||||
contentSnippet: post.contentSnippet,
|
||||
id: post.id,
|
||||
isoDate: post.isoDate,
|
||||
postId: post.postId
|
||||
};
|
||||
const postToSave = {
|
||||
title: post.title,
|
||||
link: post.link,
|
||||
pubDate: post.pubDate,
|
||||
author: post.author,
|
||||
contentSnippet: post.contentSnippet,
|
||||
id: post.id,
|
||||
isoDate: post.isoDate,
|
||||
postId: post.postId,
|
||||
};
|
||||
|
||||
await createPost(postToSave);
|
||||
log.DEBUG("Post saved:", postToSave);
|
||||
}
|
||||
}));
|
||||
await createPost(postToSave);
|
||||
log.DEBUG("Post saved:", postToSave);
|
||||
}
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
await deleteFeedByLink(source.link);
|
||||
}
|
||||
@@ -90,4 +110,4 @@ export const updateFeeds = async (client) => {
|
||||
log.ERROR("Error updating feeds:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
import { updateFeeds } from "./feedHandler.mjs";
|
||||
import dotenv from 'dotenv';
|
||||
import dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
const log = new DebugBuilder("server", "rssController");
|
||||
@@ -10,40 +10,39 @@ const log = new DebugBuilder("server", "rssController");
|
||||
const refreshInterval = parseInt(process.env.RSS_REFRESH_INTERVAL) || 300000;
|
||||
|
||||
export class RSSController {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.intervalId = null;
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.intervalId = null;
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
log.INFO("Starting RSS Controller");
|
||||
// Get initial feeds before starting the interval loop
|
||||
await this.collectLatestPosts();
|
||||
|
||||
// Start the interval loop for updating feeds
|
||||
this.intervalId = setInterval(async () => {
|
||||
await this.collectLatestPosts();
|
||||
}, refreshInterval);
|
||||
} catch (error) {
|
||||
log.ERROR(`Failed to start RSS Controller: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
try {
|
||||
log.INFO("Starting RSS Controller");
|
||||
// Get initial feeds before starting the interval loop
|
||||
await this.collectLatestPosts();
|
||||
|
||||
// Start the interval loop for updating feeds
|
||||
this.intervalId = setInterval(async () => {
|
||||
await this.collectLatestPosts();
|
||||
}, refreshInterval);
|
||||
|
||||
} catch (error) {
|
||||
log.ERROR(`Failed to start RSS Controller: ${error.message}`);
|
||||
}
|
||||
async stop() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
log.INFO("RSS Controller stopped");
|
||||
}
|
||||
}
|
||||
|
||||
async stop() {
|
||||
if (this.intervalId) {
|
||||
clearInterval(this.intervalId);
|
||||
log.INFO("RSS Controller stopped");
|
||||
}
|
||||
}
|
||||
|
||||
async collectLatestPosts() {
|
||||
try {
|
||||
log.INFO("Updating sources");
|
||||
await updateFeeds(this.client);
|
||||
} catch (error) {
|
||||
log.ERROR(`Error updating feeds: ${error.message}`);
|
||||
}
|
||||
async collectLatestPosts() {
|
||||
try {
|
||||
log.INFO("Updating sources");
|
||||
await updateFeeds(this.client);
|
||||
} catch (error) {
|
||||
log.ERROR(`Error updating feeds: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +1,92 @@
|
||||
import { DebugBuilder } from "../modules/debugger.mjs";
|
||||
const log = new DebugBuilder("server", "sourceManager");
|
||||
import { createFeed, getFeedByLink, deleteFeedByLink } from '../modules/mongo-wrappers/mongoFeedsWrappers.mjs';
|
||||
import {
|
||||
createFeed,
|
||||
getFeedByLink,
|
||||
deleteFeedByLink,
|
||||
} from "../modules/mongo-wrappers/mongoFeedsWrappers.mjs";
|
||||
|
||||
class SourceManager {
|
||||
constructor(sourceFailureLimit) {
|
||||
this.sourceFailureLimit = sourceFailureLimit;
|
||||
this.runningSourcesToRemove = {};
|
||||
}
|
||||
|
||||
async removeSource(sourceURL) {
|
||||
log.INFO(`Removing source: ${sourceURL}`);
|
||||
constructor(sourceFailureLimit) {
|
||||
this.sourceFailureLimit = sourceFailureLimit;
|
||||
this.runningSourcesToRemove = {};
|
||||
}
|
||||
|
||||
const currentTime = Date.now();
|
||||
const sourceData = this.runningSourcesToRemove[sourceURL];
|
||||
async removeSource(sourceURL) {
|
||||
log.INFO(`Removing source: ${sourceURL}`);
|
||||
|
||||
if (!sourceData) {
|
||||
this.runningSourcesToRemove[sourceURL] = { count: 1, timestamp: currentTime, ignoredAttempts: 0 };
|
||||
return;
|
||||
}
|
||||
const currentTime = Date.now();
|
||||
const sourceData = this.runningSourcesToRemove[sourceURL];
|
||||
|
||||
const elapsedTimeSinceLastAttempt = currentTime - sourceData.timestamp;
|
||||
const waitTime = sourceData.count * 30000;
|
||||
|
||||
if (elapsedTimeSinceLastAttempt <= waitTime) {
|
||||
sourceData.ignoredAttempts += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceData.count < this.sourceFailureLimit) {
|
||||
sourceData.count += 1;
|
||||
sourceData.timestamp = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const record = await getFeedByLink(sourceURL);
|
||||
if (!record) {
|
||||
log.ERROR(`Source not found in storage: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await deleteFeedByLink(sourceURL);
|
||||
if (!results) {
|
||||
log.WARN(`Failed to remove source: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.DEBUG(`Source removed after exceeding failure limit: ${sourceURL}`);
|
||||
// Optionally, clean up the entry from runningSourcesToRemove
|
||||
delete this.runningSourcesToRemove[sourceURL];
|
||||
} catch (err) {
|
||||
log.ERROR(`Error removing source from storage: ${sourceURL}`, err);
|
||||
}
|
||||
if (!sourceData) {
|
||||
this.runningSourcesToRemove[sourceURL] = {
|
||||
count: 1,
|
||||
timestamp: currentTime,
|
||||
ignoredAttempts: 0,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
async addSource(title, link, category, guildId, channelId, callback) {
|
||||
try {
|
||||
const feed = { title, link, category, guild_id: guildId, channel_id: channelId };
|
||||
const record = await createFeed(feed);
|
||||
log.DEBUG("Source added:", record);
|
||||
if (callback) callback(null, record);
|
||||
} catch (err) {
|
||||
log.ERROR("Error adding source:", err);
|
||||
if (callback) callback(err, null);
|
||||
}
|
||||
const elapsedTimeSinceLastAttempt = currentTime - sourceData.timestamp;
|
||||
const waitTime = sourceData.count * 30000;
|
||||
|
||||
if (elapsedTimeSinceLastAttempt <= waitTime) {
|
||||
sourceData.ignoredAttempts += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceData.count < this.sourceFailureLimit) {
|
||||
sourceData.count += 1;
|
||||
sourceData.timestamp = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const record = await getFeedByLink(sourceURL);
|
||||
if (!record) {
|
||||
log.ERROR(`Source not found in storage: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await deleteFeedByLink(sourceURL);
|
||||
if (!results) {
|
||||
log.WARN(`Failed to remove source: ${sourceURL}`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.DEBUG(`Source removed after exceeding failure limit: ${sourceURL}`);
|
||||
// Optionally, clean up the entry from runningSourcesToRemove
|
||||
delete this.runningSourcesToRemove[sourceURL];
|
||||
} catch (err) {
|
||||
log.ERROR(`Error removing source from storage: ${sourceURL}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
async addSource(title, link, category, guildId, channelId, callback) {
|
||||
try {
|
||||
const feed = {
|
||||
title,
|
||||
link,
|
||||
category,
|
||||
guild_id: guildId,
|
||||
channel_id: channelId,
|
||||
};
|
||||
const record = await createFeed(feed);
|
||||
log.DEBUG("Source added:", record);
|
||||
if (callback) callback(null, record);
|
||||
} catch (err) {
|
||||
log.ERROR("Error adding source:", err);
|
||||
if (callback) callback(err, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create a default instance of SourceManager
|
||||
const defaultSourceManager = new SourceManager();
|
||||
|
||||
// Export the class and default instance methods
|
||||
export { SourceManager };
|
||||
export const addSource = defaultSourceManager.addSource.bind(defaultSourceManager);
|
||||
export const removeSource = defaultSourceManager.removeSource.bind(defaultSourceManager);
|
||||
export const addSource =
|
||||
defaultSourceManager.addSource.bind(defaultSourceManager);
|
||||
export const removeSource =
|
||||
defaultSourceManager.removeSource.bind(defaultSourceManager);
|
||||
|
||||
Reference in New Issue
Block a user