Merge pull request 'Update data model, documentation' (#4) from feature/2-update_data_model into master
Reviewed-on: #4
This commit is contained in:
commit
21cb5a02c8
3
dist/build.js
vendored
3
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
@ -16,17 +16,19 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
/**
|
/**
|
||||||
* Schema: chat-messages/daily
|
* Schema: chat-messages/daily
|
||||||
*
|
*
|
||||||
* Represents one day of chat messages
|
* Represents one calendar day of chat messages
|
||||||
*
|
*
|
||||||
* Example:
|
* @example
|
||||||
*
|
|
||||||
* (start code)
|
|
||||||
* {
|
* {
|
||||||
* "@context": "https://kosmos.org/ns/v1",
|
* "@context": "https://kosmos.org/ns/v1",
|
||||||
* "@id": "chat-messages/freenode/channels/kosmos/",
|
* "@id": "chat-messages/irc.libera.chat/channels/kosmos/",
|
||||||
* "@type": "ChatChannel",
|
* "@type": "ChatChannel",
|
||||||
|
* "service": {
|
||||||
|
* "domain": "irc.libera.chat",
|
||||||
|
* "protocol": "IRC",
|
||||||
|
* },
|
||||||
* "name": "#kosmos",
|
* "name": "#kosmos",
|
||||||
* "ircURI": "irc://irc.freenode.net/kosmos",
|
* "type": "room",
|
||||||
* "today": {
|
* "today": {
|
||||||
* "@id": "2015/01/01",
|
* "@id": "2015/01/01",
|
||||||
* "@type": "ChatLog",
|
* "@type": "ChatLog",
|
||||||
@ -40,9 +42,7 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
* ]
|
* ]
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* (end code)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const archiveSchema = {
|
const archiveSchema = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -60,17 +60,27 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
"default": "ChatChannel",
|
"default": "ChatChannel",
|
||||||
"enum": ["ChatChannel"]
|
"enum": ["ChatChannel"]
|
||||||
},
|
},
|
||||||
|
"service": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"domain": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"ircURI": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uri"
|
"required": true,
|
||||||
},
|
"enum": [ "room", "person" ]
|
||||||
"xmppURI": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "uri"
|
|
||||||
},
|
},
|
||||||
"today": {
|
"today": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -135,56 +145,55 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
publicClient.declareType("daily-archive", "https://kosmos.org/ns/v1", archiveSchema);
|
publicClient.declareType("daily-archive", "https://kosmos.org/ns/v1", archiveSchema);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class: DailyArchive
|
* A daily archive stores chat messages by calendar day.
|
||||||
*
|
*
|
||||||
* A daily archive stores IRC messages by day.
|
* @class
|
||||||
|
*/
|
||||||
|
class DailyArchive {
|
||||||
|
/**
|
||||||
|
* @param {object} options
|
||||||
|
* @param {object} options.service
|
||||||
|
* @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.channelName - Name of room/channel (e.g. "#kosmos")
|
||||||
|
* @param {string} [options.channelType] - 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
|
||||||
*
|
*
|
||||||
* Parameters (object):
|
* @example
|
||||||
* server - Chat server info (see <DailyArchive.server>)
|
* // IRC archive:
|
||||||
* channelName - Name of room/channel
|
|
||||||
* date - Date of archive day
|
|
||||||
* isPublic - Store logs in public folder (defaults to false)
|
|
||||||
* previous - Date of previous log file as YYYY/MM/DD;
|
|
||||||
* looked up automatically when not given
|
|
||||||
* next - Date of next log file as YYYY/MM/DD;
|
|
||||||
* looked up automatically when not given
|
|
||||||
*
|
|
||||||
* Example for IRC:
|
|
||||||
*
|
|
||||||
* (start code)
|
|
||||||
* const archive = new chatMessages.DailyArchive({
|
* const archive = new chatMessages.DailyArchive({
|
||||||
* server: {
|
* service: {
|
||||||
* type: 'irc',
|
* protocol: 'IRC',
|
||||||
* name: 'freenode',
|
* domain: 'irc.libera.chat',
|
||||||
* ircURI: 'irc://irc.freenode.net'
|
|
||||||
* },
|
* },
|
||||||
* channelName: '#kosmos',
|
* channelName: '#kosmos-dev',
|
||||||
|
* channelType: 'room',
|
||||||
* date: new Date(),
|
* date: new Date(),
|
||||||
* isPublic: true
|
* isPublic: true
|
||||||
* });
|
* });
|
||||||
* (end code)
|
|
||||||
*
|
*
|
||||||
* Example for XMPP:
|
* // XMPP archive:
|
||||||
*
|
|
||||||
* (start code)
|
|
||||||
* const archive = new chatMessages.DailyArchive({
|
* const archive = new chatMessages.DailyArchive({
|
||||||
* server: {
|
* service: {
|
||||||
* type: 'xmpp',
|
* protocol: 'XMPP',
|
||||||
* name: '5apps',
|
* domain: 'kosmos.chat',
|
||||||
* xmppMUC: 'muc.5apps.com'
|
|
||||||
* },
|
* },
|
||||||
* channelName: 'watercooler',
|
* channelName: 'kosmos-dev',
|
||||||
|
* channelType: 'room',
|
||||||
* date: new Date(),
|
* date: new Date(),
|
||||||
* isPublic: false
|
* isPublic: false
|
||||||
* });
|
* });
|
||||||
* (end code)
|
*
|
||||||
*/
|
*/
|
||||||
class DailyArchive {
|
|
||||||
constructor (options) {
|
constructor (options) {
|
||||||
//
|
//
|
||||||
// Defaults
|
// Defaults
|
||||||
//
|
//
|
||||||
options.isPublic = options.isPublic || false;
|
options.isPublic = options.isPublic || false;
|
||||||
|
options.channelType = options.channelType || "room";
|
||||||
|
|
||||||
//
|
//
|
||||||
// Validate options
|
// Validate options
|
||||||
@ -192,10 +201,10 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
if (typeof options !== "object") {
|
if (typeof options !== "object") {
|
||||||
throw "options must be an object";
|
throw "options must be an object";
|
||||||
}
|
}
|
||||||
if (typeof options.server !== "object" ||
|
if (typeof options.service !== "object" ||
|
||||||
typeof options.server.type !== "string" ||
|
typeof options.service.protocol !== "string" ||
|
||||||
typeof options.server.name !== "string") {
|
typeof options.service.domain !== "string") {
|
||||||
throw "server must be an object containing at least server \"type\" and \"name\"";
|
throw "service must be an object containing at least service \"protocol\" and \"domain\"";
|
||||||
}
|
}
|
||||||
if (typeof options.channelName !== "string") {
|
if (typeof options.channelName !== "string") {
|
||||||
throw "channelName must be a string";
|
throw "channelName must be a string";
|
||||||
@ -208,104 +217,82 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: server
|
* @property {object} service
|
||||||
*
|
* @property {string} service.protocol - Type of chat service/protocol (e.g. "IRC", "XMPP", "campfire", "slack")
|
||||||
* Contains information about the chat server/network
|
* @property {string} service.domain - Domain of the chat service (e.g. "irc.libera.chat", "kosmos.chat")
|
||||||
*
|
|
||||||
* Properties:
|
|
||||||
* type - Type of server/protocol (e.g. "irc", "xmpp", "campfire", "slack")
|
|
||||||
* name - Shortname/id/alias of network/server (e.g. "freenode", "mycompanyname")
|
|
||||||
* ircURI - (optional) IRC URI of network (e.g. "irc://irc.freenode.net/")
|
|
||||||
* xmppMUC - (optional) XMPP MUC service host (e.g. "conference.jabber.org")
|
|
||||||
*/
|
*/
|
||||||
this.server = options.server;
|
this.service = options.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: channelName
|
* @property {string} channelName - Name of channel (e.g. "#kosmos")
|
||||||
*
|
|
||||||
* Name of the IRC channel (e.g. "#kosmos")
|
|
||||||
*/
|
*/
|
||||||
this.channelName = options.channelName;
|
this.channelName = options.channelName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: date
|
* @property {string} channelType - Type of channel ("room" or "person")
|
||||||
*
|
*/
|
||||||
* Date of the archive's content
|
this.channelType = options.channelType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property {string} date - Gregorian calendar date of the archive's content
|
||||||
*/
|
*/
|
||||||
this.date = options.date;
|
this.date = options.date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: isPublic
|
* @property {boolean} isPublic - `true` for public archives, `false` for private ones
|
||||||
*
|
|
||||||
* `true` for public archives, `false` for private ones
|
|
||||||
*/
|
*/
|
||||||
this.isPublic = options.isPublic;
|
this.isPublic = options.isPublic || false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: parsedDate
|
* @property {object} parsedDate - Contains padded year, month and day of date
|
||||||
*
|
* @property {string} year
|
||||||
* Object containing padded year, month and day of date
|
* @property {string} month
|
||||||
|
* @property {string} day
|
||||||
*/
|
*/
|
||||||
this.parsedDate = parseDate(this.date);
|
this.parsedDate = parseDate(this.date);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: dateId
|
* @property {string} dateId - Date string in the form of YYYY/MM/DD
|
||||||
*
|
|
||||||
* Date string in the form of YYYY/MM/DD
|
|
||||||
*/
|
*/
|
||||||
this.dateId = this.parsedDate.year+'/'+this.parsedDate.month+'/'+this.parsedDate.day;
|
this.dateId = this.parsedDate.year+'/'+this.parsedDate.month+'/'+this.parsedDate.day;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: path
|
* @property {string} path - Document path of the archive file
|
||||||
*
|
|
||||||
* Document path of the archive file
|
|
||||||
*/
|
*/
|
||||||
switch (this.server.type) {
|
if (this.channelType === "room") {
|
||||||
case 'irc':
|
// Normal chatroom
|
||||||
if (this.channelName.match(/^#/)) {
|
const channelName = this.channelName.replace(/#/,'');
|
||||||
// normal chatroom
|
this.path = `${this.service.domain}/channels/${channelName}/${this.dateId}`;
|
||||||
const channelName = this.channelName.replace(/^#/,'');
|
|
||||||
this.path = `${this.server.name}/channels/${channelName}/${this.dateId}`;
|
|
||||||
} else {
|
} else {
|
||||||
// user direct message
|
// User direct message
|
||||||
this.path = `${this.server.name}/users/${this.channelName}/${this.dateId}`;
|
this.path = `${this.service.domain}/users/${this.channelName}/${this.dateId}`;
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.path = `${this.server.name}/${this.channelName}/${this.dateId}`;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: client
|
* @property {object} client - Public or private remoteStorgage.js BaseClient
|
||||||
*
|
|
||||||
* Public or private BaseClient, depending on isPublic
|
|
||||||
*/
|
*/
|
||||||
this.client = this.isPublic ? publicClient : privateClient;
|
this.client = this.isPublic ? publicClient : privateClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: previous
|
* @property {string} previous - Date of previous log file as YYYY/MM/DD
|
||||||
*
|
|
||||||
* Date of previous log file as YYYY/MM/DD
|
|
||||||
*/
|
*/
|
||||||
this.previous = options.previous;
|
this.previous = options.previous;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property: next
|
* @property {string} next - Date of next log file as YYYY/MM/DD
|
||||||
*
|
|
||||||
* Date of next log file as YYYY/MM/DD
|
|
||||||
*/
|
*/
|
||||||
this.next = options.next;
|
this.next = options.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: addMessage
|
* @param {object} message
|
||||||
|
* @param {string} message.timestamp - Timestamp of the message
|
||||||
|
* @param {string} message.from - The sender of the message
|
||||||
|
* @param {string} message.text - The message itself
|
||||||
|
* @param {string} message.type - Type of message (one of text, join, leave, action)
|
||||||
|
* @param {string} [message.id] - Unique ID of message. TODO implement
|
||||||
*
|
*
|
||||||
* Parameters (object):
|
* @returns {Promise}
|
||||||
* timestamp - Timestamp of the message
|
|
||||||
* from - The sender of the message
|
|
||||||
* text - The message itself
|
|
||||||
* type - Type of message (one of text, join, leave, action)
|
|
||||||
*/
|
*/
|
||||||
addMessage (message) {
|
addMessage (message) {
|
||||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
if (this.isPublic && !this.channelName.match(/^#/)) {
|
||||||
@ -324,15 +311,13 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: addMessages
|
|
||||||
*
|
|
||||||
* Like <addMessage>, but for multiple messages at once. Useful for bulk
|
* Like <addMessage>, but for multiple messages at once. Useful for bulk
|
||||||
* imports of messages.
|
* imports of messages.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* @param {Array} messages - Array of message objects (see params for addMessage)
|
||||||
* messages - Array of message objects (see params for addMessage)
|
* @param {boolean} overwrite - If true, creates a new archive file and overwrites the old one. Defaults to false.
|
||||||
* overwrite - If true, creates a new archive file and overwrites the
|
*
|
||||||
* old one. Defaults to false.
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
addMessages (messages, overwrite) {
|
addMessages (messages, overwrite) {
|
||||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
if (this.isPublic && !this.channelName.match(/^#/)) {
|
||||||
@ -359,18 +344,20 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: remove
|
|
||||||
*
|
|
||||||
* Deletes the entire archive document from storage
|
* Deletes the entire archive document from storage
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
remove () {
|
remove () {
|
||||||
return this.client.remove(this.path);
|
return this.client.remove(this.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _updateDocument
|
|
||||||
*
|
|
||||||
* Updates and writes an existing archive document
|
* Updates and writes an existing archive document
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_updateDocument (archive, messages) {
|
_updateDocument (archive, messages) {
|
||||||
console.debug('[chat-messages] Updating archive document', archive);
|
console.debug('[chat-messages] Updating archive document', archive);
|
||||||
@ -387,9 +374,11 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _createDocument
|
|
||||||
*
|
|
||||||
* Creates and writes a new archive document
|
* Creates and writes a new archive document
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_createDocument (messages) {
|
_createDocument (messages) {
|
||||||
console.debug('[chat-messages] Creating new archive document');
|
console.debug('[chat-messages] Creating new archive document');
|
||||||
@ -421,17 +410,21 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _buildArchiveObject
|
|
||||||
*
|
|
||||||
* Builds the object to be stored in remote storage
|
* Builds the object to be stored in remote storage
|
||||||
|
*
|
||||||
|
* @returns {object}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_buildArchiveObject () {
|
_buildArchiveObject () {
|
||||||
const roomName = this.channelName.replace(/#/,'');
|
const roomName = this.channelName.replace(/#/,'');
|
||||||
|
|
||||||
const archive = {
|
const archive = {
|
||||||
"@id": "chat-messages/"+this.server.name+"/channels/"+roomName+"/",
|
"@id": "chat-messages/"+this.service.domain+"/channels/"+roomName+"/",
|
||||||
"@type": "ChatChannel",
|
"@type": "ChatChannel",
|
||||||
|
"service": this.service,
|
||||||
"name": this.channelName,
|
"name": this.channelName,
|
||||||
|
"type": this.channelType,
|
||||||
"today": {
|
"today": {
|
||||||
"@id": this.dateId,
|
"@id": this.dateId,
|
||||||
"@type": "ChatLog",
|
"@type": "ChatLog",
|
||||||
@ -440,15 +433,14 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (this.server.type) {
|
switch (this.service.protocol) {
|
||||||
case 'irc':
|
case 'IRC':
|
||||||
if (!this.channelName.match(/^#/)) {
|
if (!this.channelName.match(/^#/)) {
|
||||||
archive["@id"] = "chat-messages/"+this.server.name+"/users/"+this.channelName+"/";
|
archive["@id"] = "chat-messages/"+this.service.domain+"/users/"+this.channelName+"/";
|
||||||
}
|
}
|
||||||
archive["ircURI"] = this.server.ircURI+"/"+roomName;
|
|
||||||
break;
|
break;
|
||||||
case 'xmpp':
|
case 'XMPP':
|
||||||
archive["xmppURI"] = `xmpp:${this.channelName}@${this.server.xmppMUC}`;
|
// XMPP-specific adjustments
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,9 +448,11 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _updatePreviousArchive
|
|
||||||
*
|
|
||||||
* Finds the previous archive document and updates its today.next value
|
* Finds the previous archive document and updates its today.next value
|
||||||
|
*
|
||||||
|
* @returns {boolean|Promise}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_updatePreviousArchive () {
|
_updatePreviousArchive () {
|
||||||
return this._findPreviousArchive().then((archive) => {
|
return this._findPreviousArchive().then((archive) => {
|
||||||
@ -478,9 +472,11 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _findPreviousArchive
|
|
||||||
*
|
|
||||||
* Returns the previous archive document
|
* Returns the previous archive document
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_findPreviousArchive () {
|
_findPreviousArchive () {
|
||||||
const monthPath = this.path.substring(0, this.path.length-2);
|
const monthPath = this.path.substring(0, this.path.length-2);
|
||||||
@ -542,9 +538,11 @@ const ChatMessages = function (privateClient, publicClient) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Method: _sync
|
|
||||||
*
|
|
||||||
* Write archive document
|
* Write archive document
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
*
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_sync (obj) {
|
_sync (obj) {
|
||||||
console.debug('[chat-messages] Writing archive object', obj);
|
console.debug('[chat-messages] Writing archive object', obj);
|
@ -3,7 +3,7 @@ const isProd = (process.env.NODE_ENV === 'production');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: ['./index.js'],
|
entry: ['./src/chat-messages.js'],
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
filename: 'build.js',
|
filename: 'build.js',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user