Compare commits
9 Commits
v2.0.0
...
feature/ch
| Author | SHA1 | Date | |
|---|---|---|---|
|
dcf117e1dd
|
|||
|
a0bec9a12c
|
|||
|
189cd1f86d
|
|||
|
8db448c4a0
|
|||
| 84613ed3a3 | |||
|
f83ef92adc
|
|||
|
54352e09e8
|
|||
|
cd93cd4167
|
|||
|
9f477ba14b
|
@@ -1,4 +1,4 @@
|
|||||||
[](https://github.com/67P/remotestorage-module-chat-messages/releases)
|
[](https://www.npmjs.com/package/remotestorage-module-chat-messages)
|
||||||
|
|
||||||
# remoteStorage Module: Chat Messages
|
# remoteStorage Module: Chat Messages
|
||||||
|
|
||||||
|
|||||||
2
dist/build.js
vendored
2
dist/build.js
vendored
File diff suppressed because one or more lines are too long
2
dist/build.js.map
vendored
2
dist/build.js.map
vendored
File diff suppressed because one or more lines are too long
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "remotestorage-module-chat-messages",
|
"name": "remotestorage-module-chat-messages",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2215,6 +2215,12 @@
|
|||||||
"regenerate": "^1.4.0"
|
"regenerate": "^1.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"regenerator-runtime": {
|
||||||
|
"version": "0.13.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||||
|
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.20.0",
|
"version": "1.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "remotestorage-module-chat-messages",
|
"name": "remotestorage-module-chat-messages",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"description": "Stores chat messages in daily archive files",
|
"description": "Stores chat messages in daily archive files",
|
||||||
"main": "./dist/build.js",
|
"main": "./dist/build.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"@babel/preset-env": "^7.14.9",
|
"@babel/preset-env": "^7.14.9",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"webpack": "^5.48.0",
|
"webpack": "^5.48.0",
|
||||||
"webpack-cli": "^4.8.0"
|
"webpack-cli": "^4.8.0",
|
||||||
|
"regenerator-runtime": "^0.13.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'regenerator-runtime/runtime';
|
||||||
|
|
||||||
function pad (num) {
|
function pad (num) {
|
||||||
num = String(num);
|
num = String(num);
|
||||||
if (num.length === 1) { num = "0" + num; }
|
if (num.length === 1) { num = "0" + num; }
|
||||||
@@ -12,9 +14,17 @@ function parseDate (date) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function lowestNumberInListing(items) {
|
||||||
|
const sortedNumbers = Object.keys(items)
|
||||||
|
.map(i => parseInt(i))
|
||||||
|
.filter(i => !Number.isNaN(i))
|
||||||
|
.sort();
|
||||||
|
return sortedNumbers[0];
|
||||||
|
}
|
||||||
|
|
||||||
const ChatMessages = function (privateClient, publicClient) {
|
const ChatMessages = function (privateClient, publicClient) {
|
||||||
/**
|
/**
|
||||||
* Schema: chat-messages/daily
|
* Schema: chat-messages/daily-archive
|
||||||
*
|
*
|
||||||
* Represents one calendar day of chat messages
|
* Represents one calendar day of chat messages
|
||||||
*
|
*
|
||||||
@@ -48,8 +58,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
"properties": {
|
"properties": {
|
||||||
"@context": {
|
"@context": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "https://kosmos.org/ns/v2",
|
"default": "https://kosmos.org/ns/v2/chat-channel"
|
||||||
"enum": ["https://kosmos.org/ns/v2"]
|
|
||||||
},
|
},
|
||||||
"@id": {
|
"@id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -141,59 +150,94 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
"required": []
|
"required": []
|
||||||
};
|
};
|
||||||
|
|
||||||
privateClient.declareType("daily-archive", "https://kosmos.org/ns/v2", archiveSchema);
|
privateClient.declareType("daily-archive", "https://kosmos.org/ns/v2/chat-channel", archiveSchema);
|
||||||
publicClient.declareType("daily-archive", "https://kosmos.org/ns/v2", archiveSchema);
|
publicClient.declareType("daily-archive", "https://kosmos.org/ns/v2/chat-channel", archiveSchema);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A daily archive stores chat messages by calendar day.
|
* Schema: chat-messages/daily-archive-meta
|
||||||
|
*
|
||||||
|
* Stores meta information about the daily archives
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* {
|
||||||
|
* "@context": "https://kosmos.org/ns/v2",
|
||||||
|
* "@id": "chat-messages/irc.libera.chat/channels/kosmos/meta",
|
||||||
|
* "@type": "ChatChannelMeta",
|
||||||
|
* "first": "2009/01/03",
|
||||||
|
* "last": "2021/11/05"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
const archiveMetaSchema = {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"@context": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "https://kosmos.org/ns/v2/chat-channel-meta"
|
||||||
|
},
|
||||||
|
"@id": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
|
"@type": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "ChatChannelMeta",
|
||||||
|
"enum": ["ChatChannelMeta"]
|
||||||
|
},
|
||||||
|
"first": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$"
|
||||||
|
},
|
||||||
|
"last": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["@id", "first", "last"]
|
||||||
|
};
|
||||||
|
|
||||||
|
privateClient.declareType("daily-archive-meta", "https://kosmos.org/ns/v2/chat-channel-meta", archiveMetaSchema);
|
||||||
|
publicClient.declareType("daily-archive-meta", "https://kosmos.org/ns/v2/chat-channel-meta", archiveMetaSchema);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A chat channel
|
||||||
*
|
*
|
||||||
* @class
|
* @class
|
||||||
*/
|
*/
|
||||||
class DailyArchive {
|
class Channel {
|
||||||
/**
|
/**
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @param {object} options.service
|
* @param {object} options.service
|
||||||
* @param {string} options.service.protocol - Type of chat service/protocol (e.g. "IRC", "XMPP", "Campfire", "Slack")
|
* @param {string} options.service.protocol - Type of chat service/protocol (e.g. "IRC", "XMPP", "Campfire", "Slack")
|
||||||
* @param {string} options.service.domain - Domain of the chat service (e.g. "irc.libera.chat", "kosmos.chat")
|
* @param {string} options.service.domain - Domain of the chat service (e.g. "irc.libera.chat", "kosmos.chat")
|
||||||
* @param {string} options.channelName - Name of room/channel (e.g. "#kosmos")
|
* @param {string} options.name - Name of room/channel (e.g. "#kosmos")
|
||||||
* @param {string} [options.channelType] - Type of channel ("room" or "person")
|
* @param {string} [options.type] - Type of channel ("room" or "person")
|
||||||
* @param {date} options.date - Date of archive day
|
|
||||||
* @param {boolean} [options.isPublic] - Store logs in public folder (defaults to false)
|
|
||||||
* @param {string} [options.previous] - Date of previous log file as `YYYY/MM/DD`. Looked up automatically when not given
|
|
||||||
* @param {string} [options.next] - Date of next log file as `YYYY/MM/DD`. looked up automatically when not given
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // IRC archive:
|
* // IRC channel:
|
||||||
* const archive = new chatMessages.DailyArchive({
|
* const channel = new remoteStorage.chatMessages.Channel({
|
||||||
* service: {
|
* service: {
|
||||||
* protocol: 'IRC',
|
* protocol: 'IRC',
|
||||||
* domain: 'irc.libera.chat',
|
* domain: 'irc.libera.chat',
|
||||||
* },
|
* },
|
||||||
* channelName: '#kosmos-dev',
|
* name: '#kosmos-dev',
|
||||||
* channelType: 'room',
|
* type: 'room'
|
||||||
* date: new Date(),
|
|
||||||
* isPublic: true
|
|
||||||
* });
|
* });
|
||||||
*
|
*
|
||||||
* // XMPP archive:
|
* // XMPP channel:
|
||||||
* const archive = new chatMessages.DailyArchive({
|
* const channel = new remoteStorage.chatMessages.Channel({
|
||||||
* service: {
|
* service: {
|
||||||
* protocol: 'XMPP',
|
* protocol: 'XMPP',
|
||||||
* domain: 'kosmos.chat',
|
* domain: 'kosmos.chat',
|
||||||
* },
|
* },
|
||||||
* channelName: 'kosmos-dev',
|
* name: 'kosmos-dev',
|
||||||
* channelType: 'room',
|
* type: 'room'
|
||||||
* date: new Date(),
|
|
||||||
* isPublic: false
|
|
||||||
* });
|
* });
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
//
|
//
|
||||||
// Defaults
|
// Defaults
|
||||||
//
|
//
|
||||||
options.isPublic = options.isPublic || false;
|
options.type = options.type || "room";
|
||||||
options.channelType = options.channelType || "room";
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Validate options
|
// Validate options
|
||||||
@@ -204,16 +248,10 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
if (typeof options.service !== "object" ||
|
if (typeof options.service !== "object" ||
|
||||||
typeof options.service.protocol !== "string" ||
|
typeof options.service.protocol !== "string" ||
|
||||||
typeof options.service.domain !== "string") {
|
typeof options.service.domain !== "string") {
|
||||||
throw "service must be an object containing at least service \"protocol\" and \"domain\"";
|
throw "options.service must be an object containing at least service \"protocol\" and \"domain\"";
|
||||||
}
|
}
|
||||||
if (typeof options.channelName !== "string") {
|
if (typeof options.name !== "string") {
|
||||||
throw "channelName must be a string";
|
throw "options.name must be a string";
|
||||||
}
|
|
||||||
if (!(options.date instanceof Date)) {
|
|
||||||
throw "date must be a date object";
|
|
||||||
}
|
|
||||||
if (typeof options.isPublic !== "boolean") {
|
|
||||||
throw "isPublic must be a boolean value";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,14 +262,130 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
this.service = options.service;
|
this.service = options.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} channelName - Name of channel (e.g. "#kosmos")
|
* @property {string} name - Name of channel (e.g. "#kosmos")
|
||||||
*/
|
*/
|
||||||
this.channelName = options.channelName;
|
this.name = options.name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} channelType - Type of channel ("room" or "person")
|
* @property {string} type - Type of channel ("room" or "person")
|
||||||
*/
|
*/
|
||||||
this.channelType = options.channelType;
|
this.type = options.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property {string} path - Base directory path of the channel archives
|
||||||
|
*/
|
||||||
|
if (this.type === "room") {
|
||||||
|
// Normal chatroom
|
||||||
|
const name = this.name.replace(/#/,'');
|
||||||
|
this.path = `${this.service.domain}/channels/${name}`;
|
||||||
|
} else {
|
||||||
|
// User direct messages
|
||||||
|
this.path = `${this.service.domain}/users/${this.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property {string} metaPath - Path of the channel's metadata document
|
||||||
|
*/
|
||||||
|
this.metaPath = `${this.path}/meta`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the last stored DailyArchive, or a new one for the current day.
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
* @param {boolean} [options.public] - Public or private archive. Defaults to 'false'.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
async openLastDailyArchive (options={}) {
|
||||||
|
const client = options.public ? publicClient : privateClient;
|
||||||
|
const meta = await client.getObject(this.metaPath);
|
||||||
|
|
||||||
|
if (meta && meta.last) {
|
||||||
|
return new DailyArchive({
|
||||||
|
channel: this,
|
||||||
|
date: new Date(meta.last.replace(/\//g,'-')),
|
||||||
|
isPublic: options.public
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new DailyArchive({
|
||||||
|
channel: this,
|
||||||
|
date: new Date(),
|
||||||
|
isPublic: options.public
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a DailyArchive for the given date
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
* @param {date} options.date - Date of archive day
|
||||||
|
* @param {boolean} [options.public] - Public or private archive. Defaults to 'false'.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
openDailyArchive (options={}) {
|
||||||
|
if (!(options.date instanceof Date)) {
|
||||||
|
throw 'options.date must be a date object';
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DailyArchive({
|
||||||
|
channel: this,
|
||||||
|
date: options.date,
|
||||||
|
isPublic: options.public
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A daily archive stores chat messages by calendar day.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class DailyArchive {
|
||||||
|
/**
|
||||||
|
* @param {object} options
|
||||||
|
* @param {string} options.channel - A Channel instance
|
||||||
|
* @param {date} options.date - Date of archive day
|
||||||
|
* @param {boolean} [options.isPublic] - Store logs in public folder (defaults to false)
|
||||||
|
* @param {string} [options.previous] - Date of previous log file as `YYYY/MM/DD`. Looked up automatically when not given
|
||||||
|
* @param {string} [options.next] - Date of next log file as `YYYY/MM/DD`. Looked up automatically when not given
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const channel = new remoteStorage.chatMessages.Channel({ ...options })
|
||||||
|
* const archive = new chatMessages.DailyArchive({
|
||||||
|
* channel: channel,
|
||||||
|
* date: new Date(),
|
||||||
|
* isPublic: true
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
constructor (options) {
|
||||||
|
//
|
||||||
|
// Defaults
|
||||||
|
//
|
||||||
|
options.isPublic = options.isPublic || false;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Validate options
|
||||||
|
//
|
||||||
|
if (typeof options !== "object") {
|
||||||
|
throw "options must be an object";
|
||||||
|
}
|
||||||
|
if (!(options.channel instanceof Channel)) {
|
||||||
|
throw "options.channel must be a Channel object";
|
||||||
|
}
|
||||||
|
if (!(options.date instanceof Date)) {
|
||||||
|
throw "options.date must be a date object";
|
||||||
|
}
|
||||||
|
if (typeof options.isPublic !== "boolean") {
|
||||||
|
throw "options.isPublic must be a boolean value";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property {Channel} channel - A Channel instance
|
||||||
|
*/
|
||||||
|
this.channel = options.channel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} date - Gregorian calendar date of the archive's content
|
* @property {string} date - Gregorian calendar date of the archive's content
|
||||||
@@ -257,16 +411,14 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
this.dateId = this.parsedDate.year+'/'+this.parsedDate.month+'/'+this.parsedDate.day;
|
this.dateId = this.parsedDate.year+'/'+this.parsedDate.month+'/'+this.parsedDate.day;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {string} path - Document path of the archive file
|
* @property {string} path - Path of the archive document
|
||||||
*/
|
*/
|
||||||
if (this.channelType === "room") {
|
this.path = `${this.channel.path}/${this.dateId}`;
|
||||||
// Normal chatroom
|
|
||||||
const channelName = this.channelName.replace(/#/,'');
|
/**
|
||||||
this.path = `${this.service.domain}/channels/${channelName}/${this.dateId}`;
|
* @property {string} metaPath - Path of the channel's metadata document
|
||||||
} else {
|
*/
|
||||||
// User direct message
|
this.metaPath = `${this.channel.path}/meta`;
|
||||||
this.path = `${this.service.domain}/users/${this.channelName}/${this.dateId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {object} client - Public or private remoteStorgage.js BaseClient
|
* @property {object} client - Public or private remoteStorgage.js BaseClient
|
||||||
@@ -290,12 +442,14 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
* @param {string} message.from - The sender of the message
|
* @param {string} message.from - The sender of the message
|
||||||
* @param {string} message.text - The message itself
|
* @param {string} message.text - The message itself
|
||||||
* @param {string} message.type - Type of message (one of text, join, leave, action)
|
* @param {string} message.type - Type of message (one of text, join, leave, action)
|
||||||
* @param {string} [message.id] - Unique ID of message. TODO implement
|
* @param {string} [message.id] - Unique ID of message.
|
||||||
|
* @param {string} [message.sid] - Unique stanza ID of message (XMPP only)
|
||||||
|
* @param {boolean} [message.edited] - If the message has been edited
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
addMessage (message) {
|
addMessage (message) {
|
||||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
if (this.isPublic && !this.channel.name.match(/^#/)) {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +474,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
addMessages (messages, overwrite) {
|
addMessages (messages, overwrite) {
|
||||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
if (this.isPublic && !this.channel.name.match(/^#/)) {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,6 +503,8 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
remove () {
|
remove () {
|
||||||
|
// TODO when removing, if previous is set, but not next, it means the
|
||||||
|
// removed file is the last archive. Thus, set "last" to previous file.
|
||||||
return this.client.remove(this.path);
|
return this.client.remove(this.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +515,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_updateDocument (archive, messages) {
|
async _updateDocument (archive, messages) {
|
||||||
console.debug('[chat-messages] Updating archive document');
|
console.debug('[chat-messages] Updating archive document');
|
||||||
|
|
||||||
if (Array.isArray(messages)) {
|
if (Array.isArray(messages)) {
|
||||||
@@ -380,12 +536,12 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_createDocument (messages) {
|
async _createDocument (messages) {
|
||||||
console.debug('[chat-messages] Creating new archive document');
|
console.debug('[chat-messages] Creating new archive document');
|
||||||
const archive = this._buildArchiveObject();
|
const archive = this._buildArchiveObject();
|
||||||
|
|
||||||
if (Array.isArray(messages)) {
|
if (Array.isArray(messages)) {
|
||||||
messages.forEach((message) => {
|
messages.forEach(message => {
|
||||||
archive.today.messages.push(message);
|
archive.today.messages.push(message);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -397,16 +553,22 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
// That includes setting 'next' in the previous log file
|
// That includes setting 'next' in the previous log file
|
||||||
if (this.previous) { archive.today.previous = this.previous; }
|
if (this.previous) { archive.today.previous = this.previous; }
|
||||||
if (this.next) { archive.today.next = this.next; }
|
if (this.next) { archive.today.next = this.next; }
|
||||||
return this._sync(archive);
|
|
||||||
} else {
|
} else {
|
||||||
// Find and update previous archive, set 'previous' on this one
|
// Find and update previous archive, set 'previous' on this one
|
||||||
return this._updatePreviousArchive().then((previous) => {
|
const previous = await this._updatePreviousArchive();
|
||||||
if (typeof previous === 'object') {
|
if (typeof previous === 'object') {
|
||||||
archive.today.previous = previous.today['@id'];
|
archive.today.previous = previous.today['@id'];
|
||||||
}
|
}
|
||||||
return this._sync(archive);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this._sync(archive);
|
||||||
|
|
||||||
|
// TODO only write meta doc if argument is set on addMessages. This way
|
||||||
|
// we can avoid race conditions when syncing remote chat messages all at
|
||||||
|
// once for multiple days
|
||||||
|
await this._updateArchiveMetaDocument();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -417,14 +579,14 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_buildArchiveObject () {
|
_buildArchiveObject () {
|
||||||
const roomName = this.channelName.replace(/#/,'');
|
const roomName = this.channel.name.replace(/#/,'');
|
||||||
|
|
||||||
const archive = {
|
const archive = {
|
||||||
"@id": "chat-messages/"+this.service.domain+"/channels/"+roomName+"/",
|
"@id": "chat-messages/"+this.channel.service.domain+"/channels/"+roomName+"/",
|
||||||
"@type": "ChatChannel",
|
"@type": "ChatChannel",
|
||||||
"service": this.service,
|
"service": this.channel.service,
|
||||||
"name": this.channelName,
|
"name": this.channel.name,
|
||||||
"type": this.channelType,
|
"type": this.channel.type,
|
||||||
"today": {
|
"today": {
|
||||||
"@id": this.dateId,
|
"@id": this.dateId,
|
||||||
"@type": "ChatLog",
|
"@type": "ChatLog",
|
||||||
@@ -433,10 +595,10 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (this.service.protocol) {
|
switch (this.channel.service.protocol) {
|
||||||
case 'IRC':
|
case 'IRC':
|
||||||
if (!this.channelName.match(/^#/)) {
|
if (!this.channel.name.match(/^#/)) {
|
||||||
archive["@id"] = "chat-messages/"+this.service.domain+"/users/"+this.channelName+"/";
|
archive["@id"] = "chat-messages/"+this.channel.service.domain+"/users/"+this.channel.name+"/";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'XMPP':
|
case 'XMPP':
|
||||||
@@ -461,7 +623,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
const path = this.path.substring(0, this.path.length-this.dateId.length)+archive.today['@id'];
|
const path = this.path.substring(0, this.path.length-this.dateId.length)+archive.today['@id'];
|
||||||
|
|
||||||
return this.client.storeObject('daily-archive', path, archive).then(() => {
|
return this.client.storeObject('daily-archive', path, archive).then(() => {
|
||||||
console.debug('[chat-messages] Previous archive written to remote storage', path, archive);
|
console.debug('[chat-messages] Previous archive written to remote storage at', path);
|
||||||
return archive;
|
return archive;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -537,6 +699,57 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _updateArchiveMetaDocument () {
|
||||||
|
const meta = await this.client.getObject(this.metaPath);
|
||||||
|
if (typeof meta !== 'object') {
|
||||||
|
return this._createArchiveMetaDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update document if current date is newer than known "last"
|
||||||
|
if (Date.parse(meta.last.replace('/','-')) > Date.parse(this.date)) {
|
||||||
|
console.debug('[chat-messages]', 'Updating meta document for channel');
|
||||||
|
meta.last = this.dateId;
|
||||||
|
await this.client.storeObject('daily-archive-meta', this.metaPath, meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _createArchiveMetaDocument () {
|
||||||
|
console.debug('[chat-messages]', 'Creating new meta document for channel');
|
||||||
|
// When creating a new meta doc, we need to find the oldest archive,
|
||||||
|
// because older versions of the module did not write a meta doc.
|
||||||
|
const first = await this._findFirstArchive();
|
||||||
|
const roomName = this.channel.name.replace(/#/,'');
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
'@id': `chat-messages/${this.channel.service.domain}/channels/${roomName}/meta`,
|
||||||
|
'@type': 'ChatChannelMeta',
|
||||||
|
first: first,
|
||||||
|
last: this.dateId // TODO might have to search for last?
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.client.storeObject('daily-archive-meta', this.metaPath, meta)
|
||||||
|
.then(() => console.debug('[chat-messages]', 'Meta document written to remote storage'))
|
||||||
|
.catch(e => {
|
||||||
|
console.log('[chat-messages]', `Failed to store ${this.metaPath}`);
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _findFirstArchive () {
|
||||||
|
console.debug('[chat-messages]', 'Finding first archive for channel');
|
||||||
|
const years = await this.client.getListing(`${this.channelPath}/`);
|
||||||
|
const year = lowestNumberInListing(years);
|
||||||
|
const months = await this.client.getListing(`${this.channelPath}/${year}/`);
|
||||||
|
const month = lowestNumberInListing(months);
|
||||||
|
const days = await this.client.getListing(`${this.channelPath}/${year}/${pad(month)}/`);
|
||||||
|
const day = lowestNumberInListing(days);
|
||||||
|
const firstId = `${year}/${pad(month)}/${pad(day)}`;
|
||||||
|
console.debug('[chat-messages]', 'First is', firstId);
|
||||||
|
return firstId;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write archive document
|
* Write archive document
|
||||||
*
|
*
|
||||||
@@ -544,7 +757,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sync (obj) {
|
async _sync (obj) {
|
||||||
console.debug(`[chat-messages] Writing archive object with ${obj.today.messages.length} messages`);
|
console.debug(`[chat-messages] Writing archive object with ${obj.today.messages.length} messages`);
|
||||||
|
|
||||||
return this.client.storeObject('daily-archive', this.path, obj).then(function(){
|
return this.client.storeObject('daily-archive', this.path, obj).then(function(){
|
||||||
@@ -554,6 +767,8 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
console.warn('[chat-messages] Error trying to store object', error);
|
console.warn('[chat-messages] Error trying to store object', error);
|
||||||
return error;
|
return error;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO await this.client.startSync();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user