diff --git a/zefie_wtvp_minisrv/includes/WTVNews.js b/zefie_wtvp_minisrv/includes/WTVNews.js index 7583fa23..77f85230 100644 --- a/zefie_wtvp_minisrv/includes/WTVNews.js +++ b/zefie_wtvp_minisrv/includes/WTVNews.js @@ -100,32 +100,37 @@ class WTVNews { }); } - getArticle(articleID) { + getArticle(articleID, get_next_last = true) { var articleID = parseInt(articleID); return new Promise((resolve, reject) => { var promises = []; this.client.article(articleID).then((data) => { - // ask server for next article - promises.push(new Promise((resolve, reject) => { - this.client.next().then((res) => { - data.next_article = res.article.articleNumber; - resolve(data.next_article); - }).catch((e) => { - console.log(e); - data.next_article = null; - resolve(data.next_article); - }) - })); + if (get_next_last) { + // ask server for next article + promises.push(new Promise((resolve, reject) => { + this.client.next().then((res) => { + data.next_article = res.article.articleNumber; + resolve(data.next_article); + }).catch((e) => { + console.log(e); + data.next_article = null; + resolve(data.next_article); + }) + })); - // ask server for previous article - promises.push(new Promise((resolve, reject) => { - this.client.last().then((res) => { - data.prev_article = res.article.articleNumber; - // do it again - this.client.article(data.prev_article).then(() => { - this.client.last().then((res) => { - data.prev_article = res.article.articleNumber; - resolve(data.prev_article); + // ask server for previous article + promises.push(new Promise((resolve, reject) => { + this.client.last().then((res) => { + data.prev_article = res.article.articleNumber; + // do it again + this.client.article(data.prev_article).then(() => { + this.client.last().then((res) => { + data.prev_article = res.article.articleNumber; + resolve(data.prev_article); + }).catch(() => { + data.prev_article = null; + resolve(data.prev_article); + }); }).catch(() => { data.prev_article = null; resolve(data.prev_article); @@ -133,16 +138,15 @@ class WTVNews { }).catch(() => { data.prev_article = null; resolve(data.prev_article); - }); - }).catch(() => { - data.prev_article = null; - resolve(data.prev_article); - }) - })); + }) + })); - Promise.all(promises).then(() => { + Promise.all(promises).then(() => { + resolve(data); + }); + } else { resolve(data); - }); + } }).catch((e) => { reject(`Error reading article ID ${articleID}`); console.error(" * WTVNews Error:", "Command: article", "args:", articleID, "Error:", e); diff --git a/zefie_wtvp_minisrv/includes/WTVNewsServer.js b/zefie_wtvp_minisrv/includes/WTVNewsServer.js index a5780653..4d3a0545 100644 --- a/zefie_wtvp_minisrv/includes/WTVNewsServer.js +++ b/zefie_wtvp_minisrv/includes/WTVNewsServer.js @@ -15,32 +15,7 @@ class WTVNewsServer { const { WTVShared } = require("./WTVShared.js"); this.wtvshared = new WTVShared(minisrv_config); const nntp_server = require('nntp-server'); - var nntp_commands = { - ...nntp_server.commands, - "LAST": { - head: 'LAST', - validate: /^LAST( [^\s]+)$/i, - - // All supported params are defined in separate files - run() { - console.log('hi'); - throw new Error('method LAST is not implemented'); - } - }, - "NEXT": { - head: 'NEXT', - validate: /^NEXT( [^\s]+)$/i, - - // All supported params are defined in separate files - run() { - console.log('hi'); - throw new Error('method NEXT is not implemented'); - } - } - } - - console.log(nntp_commands); - + const nntp_statuses = require('nntp-server/lib/status'); this.username == username || null; this.password == password || null; this.using_auth = using_auth; @@ -53,10 +28,52 @@ class WTVNewsServer { // nntp-server module overrides var self = this; + var nntp_commands = { + ...nntp_server.commands, + "LAST": { + head: 'LAST', + validate: /^LAST$/i, + + // All supported params are defined in separate files + run: function (session) { + try { + if (!session.group.name) return nntp_statuses._412_GRP_NOT_SLCTD; + if (!session.group.current_article) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + if (!self.articleExists(session.group.name, session.group.current_article)) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + var res = self.getLastArticle(session.group.name, session.group.current_article); + if (!res) return nntp_statuses._422_NO_LAST_ARTICLE; + var last = `${nntp_statuses._223_ARTICLE_EXISTS} ${res.articleNumber} ${res.message_id}` + return last + } catch (e) { + console.log(e); + } + } + }, + "NEXT": { + head: 'NEXT', + validate: /^NEXT$/i, + + // All supported params are defined in separate files + run: function (session) { + try { + if (!session.group.name) return nntp_statuses._412_GRP_NOT_SLCTD; + if (!session.group.current_article) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + if (!self.articleExists(session.group.name, session.group.current_article)) return nntp_statuses._420_ARTICLE_NOT_SLCTD; + var res = self.getNextArticle(session.group.name, session.group.current_article); + if (!res) return nntp_statuses._421_NO_NEXT_ARTICLE; + var next = `${nntp_statuses._223_ARTICLE_EXISTS} ${res.articleNumber} ${res.message_id}` + return next + } catch (e) { + console.log(e); + } + } + } + } + nntp_server.prototype = { ...nntp_server.prototype, _authenticate: function (session) { - // authenticte + // authenticate if (session.authinfo_user == self.username && session.authinfo_pass == self.password) return Promise.resolve(true); return Promise.resolve(false); }, @@ -89,12 +106,10 @@ class WTVNewsServer { _getArticle: function (session, message_id) { // getArticle return new Promise((resolve, reject) => { - self.getArticle(session.group.name, message_id).then((res) => { - resolve(res); - }).catch((e) => { - console.log(" * WTVNewsServer Error:", e); - reject(e); - }); + var res = self.getArticle(session.group.name, message_id); + console.log(res); + if (!res.messageId) reject(res); + else resolve(res) }); }, @@ -137,23 +152,28 @@ class WTVNewsServer { return this.getGroupPath(group) + this.path.sep + article + ".newz"; } + articleExists(group, article) { + const g = this.getArticlePath(group, article); + if (this.fs.existsSync(g)) return true; + return false; + } + createGroup(group) { if (!this.fs.existsSync(getGroupPath(group))) return this.fs.mkdirSync(getGroupPath(group)); return true; } getArticle(group, article) { - return new Promise((resolve, reject) => { - const g = this.getArticlePath(group, article); - if (!this.fs.existsSync(g)) return false; - try { - var data = JSON.parse(this.fs.readFileSync(g)); - resolve(data); - } catch (e) { - console.log(" * WTVNewsServer Error:", e); - reject(e) - } - }); + const g = this.getArticlePath(group, article); + if (!this.fs.existsSync(g)) return false; + try { + var data = JSON.parse(this.fs.readFileSync(g)); + data.index = data.articleNumber; + return data + } catch (e) { + console.log(" * WTVNewsServer Error:", e); + } + return null; } selectGroup(group) { @@ -180,6 +200,55 @@ class WTVNewsServer { return out; } + getLastArticle(group, current) { + var g = this.getGroupPath(group); + var res = null; + try { + this.fs.readdirSync(g).forEach(file => { + var articleNumber = parseInt(file.split('.')[0]); + if (articleNumber > current) return false; + res = articleNumber; + return false; + }); + } catch (e) { + console.log(e); + return e; + } + if (res) { + if (res == current) return null; + var message = this.getArticle(group, res); + if (message.messageId) { + res = { "articleNumber": res, "message_id": message.messageId }; + } + } + return res; + } + + getNextArticle(group, current) { + var g = this.getGroupPath(group); + var res = null; + try { + this.fs.readdirSync(g).forEach(file => { + var articleNumber = parseInt(file.split('.')[0]); + if (articleNumber <= current) return; + + res = articleNumber; + return false; + }); + } catch (e) { + console.log(e); + return e; + } + if (res) { + if (res == current) return null; + var message = this.getArticle(group, res); + if (message.messageId) { + res = { "articleNumber": res, "message_id": message.messageId }; + } + } + return res; + } + listGroup(group, start, end) { var g = this.getGroupPath(group); var out = { diff --git a/zefie_wtvp_minisrv/sync_nntp.js b/zefie_wtvp_minisrv/sync_nntp.js index a547b564..bf549144 100644 --- a/zefie_wtvp_minisrv/sync_nntp.js +++ b/zefie_wtvp_minisrv/sync_nntp.js @@ -7,6 +7,7 @@ const groups_to_sync = [ const fs = require('fs'); const path = require('path'); +const crypto = require('crypto'); var classPath = __dirname + "/includes/"; const { WTVShared } = require(classPath + "WTVShared.js"); const wtvshared = new WTVShared(); // creates minisrv_config @@ -58,14 +59,9 @@ function createGroup(group) { function createArticle(group, articleNumber, article) { var g = getGroupPath(group); var file = g + path.sep + articleNumber + ".newz"; - if (fs.existsSync(file)) return "exists"; + if (verifyMessage(group, articleNumber, article)) return "exists"; else { try { - article.article.index = article.article.articleNumber; - delete article.article.articleNumber; - article.article['message-id'] = article.article.messageId; - delete article.article.messageId; - fs.writeFileSync(file, JSON.stringify(article.article)); return file; } catch (e) { @@ -74,6 +70,18 @@ function createArticle(group, articleNumber, article) { } } +function verifyMessage(group, articleNumber, article) { + var g = getGroupPath(group); + var file = g + path.sep + articleNumber + ".newz"; + if (!fs.existsSync(file)) return false; + var old_data = fs.readFileSync(file); + var new_data = JSON.stringify(article.article); + + var old_data_hash = crypto.createHash('md5').update(old_data).digest("hex"); + var new_data_hash = crypto.createHash('md5').update(new_data).digest("hex"); + return (old_data_hash === new_data_hash); +} + function deleteMissing(group, articles) { var g = getGroupPath(group); try { @@ -108,7 +116,7 @@ wtvnews.connectUsenet().then((res) => { deleteMissing(group, res.group.articleNumbers) res.group.articleNumbers.forEach((article) => { promises.push(new Promise((resolve, reject) => { - wtvnews.getArticle(article).then((message) => { + wtvnews.getArticle(article, false).then((message) => { res = createArticle(group, article, message); if (res) { if (res == "exists") { diff --git a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj index 686289d6..01e555d3 100644 --- a/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj +++ b/zefie_wtvp_minisrv/zefie_wtvp_minisrv.njsproj @@ -1103,6 +1103,7 @@ +