Port source from legacy module repo
This commit is contained in:
commit
12196fdc63
7 files changed
+665
No files matched your search
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"predef": [
|
||||
"global",
|
||||
"Promise",
|
||||
"require",
|
||||
"process",
|
||||
"module",
|
||||
"exports"
|
||||
],
|
||||
"browser": false,
|
||||
"boss": true,
|
||||
"curly": true,
|
||||
"debug": false,
|
||||
"devel": true,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": false,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": false,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"esnext": true,
|
||||
"unused": true
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("remotestoragejs"));else if("function"==typeof define&&define.amd)define(["remotestoragejs"],e);else{var n=e("object"==typeof exports?require("remotestoragejs"):t.RemoteStorage);for(var r in n)("object"==typeof exports?exports:t)[r]=n[r]}}(this,function(t){return function(t){function e(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return t[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict";function r(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e<t.length;e++)n[e]=t[e];return n}return Array.from(t)}var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},s=n(1);s.defineModule("chat-messages",function(t,e){var n={type:"object",properties:{"@context":{type:"string",default:"https://kosmos.org/ns/v1",enum:["https://kosmos.org/ns/v1"]},"@id":{type:"string",required:!0},"@type":{type:"string",default:"ChatChannel",enum:["ChatChannel"]},name:{type:"string",required:!0},ircURI:{type:"string",format:"uri"},xmppURI:{type:"string",format:"uri"},today:{type:"object",properties:{"@id":{type:"string",pattern:"^[0-9]{4}/[0-9]{2}/[0-9]{2}$",required:!0},"@type":{type:"string",default:"ChatLog",pattern:"^ChatLog$"},messageType:{type:"string",default:"InstantMessage",pattern:"^InstantMessage$"},previous:{type:"string",pattern:"^[0-9]{4}/[0-9]{2}/[0-9]{2}$"},next:{type:"string",pattern:"^[0-9]{4}/[0-9]{2}/[0-9]{2}$"},messages:{type:"array",required:!0,items:{type:"object",properties:{date:{type:"string",format:"date-time"},user:{type:"string"},text:{type:"string"},type:"string",default:"text",enum:["text","join","leave","action"]}}}}}},required:[]};t.declareType("daily-archive","https://kosmos.org/ns/v1",n),e.declareType("daily-archive","https://kosmos.org/ns/v1",n);var a=function(n){if(n.isPublic=n.isPublic||!1,"object"!==("undefined"==typeof n?"undefined":i(n)))throw"options must be an object";if("object"!==i(n.server)||"string"!=typeof n.server.type||"string"!=typeof n.server.name)throw'server must be an object containing at least server "type" and "name"';if("string"!=typeof n.channelName)throw"channelName must be a string";if(!(n.date instanceof Date))throw"date must be a date object";if("boolean"!=typeof n.isPublic)throw"isPublic must be a boolean value";switch(this.server=n.server,this.channelName=n.channelName,this.date=n.date,this.isPublic=n.isPublic,this.parsedDate=h(this.date),this.dateId=this.parsedDate.year+"/"+this.parsedDate.month+"/"+this.parsedDate.day,this.server.type){case"irc":if(this.channelName.match(/^#/)){var r=this.channelName.replace(/^#/,"");this.path=this.server.name+"/channels/"+r+"/"+this.dateId}else this.path=this.server.name+"/users/"+this.channelName+"/"+this.dateId;break;default:this.path=this.server.name+"/"+this.channelName+"/"+this.dateId}this.client=this.isPublic?e:t,this.previous=n.previous,this.next=n.next};a.prototype={addMessage:function(t){var e=this;return this.isPublic&&!this.channelName.match(/^#/)?Promise.resolve(!1):(t.type=t.type||"text",this.client.getObject(this.path).then(function(n){return"object"===("undefined"==typeof n?"undefined":i(n))?e._updateDocument(n,t):e._createDocument(t)}))},addMessages:function(t,e){var n=this;return this.isPublic&&!this.channelName.match(/^#/)?Promise.resolve(!1):(e=e||!1,t.forEach(function(t){t.type=t.type||"text"}),e?this._createDocument(t):this.client.getObject(this.path).then(function(e){return"object"===("undefined"==typeof e?"undefined":i(e))?n._updateDocument(e,t):n._createDocument(t)}))},remove:function(){return this.client.remove(this.path)},_updateDocument:function(t,e){return s.log("[chat-messages] Updating archive document",t),Array.isArray(e)?e.forEach(function(e){t.today.messages.push(e)}):t.today.messages.push(e),this._sync(t)},_createDocument:function(t){var e=this;s.log("[chat-messages] Creating new archive document");var n=this._buildArchiveObject();return Array.isArray(t)?t.forEach(function(t){n.today.messages.push(t)}):n.today.messages.push(t),this.previous||this.next?(this.previous&&(n.today.previous=this.previous),this.next&&(n.today.next=this.next),this._sync(n)):this._updatePreviousArchive().then(function(t){return"object"===("undefined"==typeof t?"undefined":i(t))&&(n.today.previous=t.today["@id"]),e._sync(n)})},_buildArchiveObject:function(){var t=this.channelName.replace(/#/,""),e={"@id":"chat-messages/"+this.server.name+"/channels/"+t+"/","@type":"ChatChannel",name:this.channelName,today:{"@id":this.dateId,"@type":"ChatLog",messageType:"InstantMessage",messages:[]}};switch(this.server.type){case"irc":this.channelName.match(/^#/)||(e["@id"]="chat-messages/"+this.server.name+"/users/"+this.channelName+"/"),e.ircURI=this.server.ircURI+"/"+t;break;case"xmpp":e.xmppURI="xmpLine truncated
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap fea08dbeb235bc9f8782","webpack:///./index.js","webpack:///external {\"root\":\"RemoteStorage\",\"commonjs2\":\"remotestoragejs\",\"commonjs\":\"remotestoragejs\",\"amd\":\"remotestoragejs\"}"],"names":["RemoteStorage","require","defineModule","privateClient","publicClient","archiveSchema","declareType","DailyArchive","options","isPublic","server","type","name","channelName","date","Date","parsedDate","parseDate","dateId","year","month","day","match","replace","path","client","previous","next","prototype","addMessage","message","Promise","resolve","getObject","then","archive","_updateDocument","_createDocument","addMessages","messages","overwrite","forEach","remove","log","Array","isArray","today","push","_sync","_buildArchiveObject","_updatePreviousArchive","roomName","ircURI","xmppMUC","_findPreviousArchive","substring","length","storeObject","monthPath","yearPath","basePath","getListing","listing","days","Object","keys","map","i","parseInt","filter","pad","Math","max","toString","months","substr","years","obj","error","console","num","String","getUTCFullYear","getUTCMonth","getUTCDate","exports"],"mappings":"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 truncated
|
||||
@@ -0,0 +1,573 @@
|
||||
var RemoteStorage = require('remotestoragejs');
|
||||
|
||||
RemoteStorage.defineModule("chat-messages", function (privateClient, publicClient) {
|
||||
|
||||
/**
|
||||
* Schema: chat-messages/daily
|
||||
*
|
||||
* Represents one day of chat messages
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* (start code)
|
||||
* {
|
||||
* "@context": "https://kosmos.org/ns/v1",
|
||||
* "@id": "chat-messages/freenode/channels/kosmos/",
|
||||
* "@type": "ChatChannel",
|
||||
* "name": "#kosmos",
|
||||
* "ircURI": "irc://irc.freenode.net/kosmos",
|
||||
* "today": {
|
||||
* "@id": "2015/01/01",
|
||||
* "@type": "ChatLog",
|
||||
* "messageType": "InstantMessage",
|
||||
* "previous": "2014/12/31",
|
||||
* "next": "2015/01/02",
|
||||
* "messages": [
|
||||
* { "date": "2015-06-05T17:35:28.454Z", "user": "hal8000", "text": "knock knock" },
|
||||
* { "date": "2015-06-05T17:37:42.123Z", "user": "raucao", "text": "who's there?" },
|
||||
* { "date": "2015-06-05T17:55:01.235Z", "user": "hal8000", "text": "HAL" }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* (end code)
|
||||
*/
|
||||
|
||||
const archiveSchema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@context": {
|
||||
"type": "string",
|
||||
"default": "https://kosmos.org/ns/v1",
|
||||
"enum": ["https://kosmos.org/ns/v1"]
|
||||
},
|
||||
"@id": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"@type": {
|
||||
"type": "string",
|
||||
"default": "ChatChannel",
|
||||
"enum": ["ChatChannel"]
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"ircURI": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"xmppURI": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"today": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"@id": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$",
|
||||
"required": true
|
||||
},
|
||||
"@type": {
|
||||
"type": "string",
|
||||
"default": "ChatLog",
|
||||
"pattern": "^ChatLog$"
|
||||
},
|
||||
"messageType": {
|
||||
"type": "string",
|
||||
"default": "InstantMessage",
|
||||
"pattern": "^InstantMessage$"
|
||||
},
|
||||
"previous": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$"
|
||||
},
|
||||
"next": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"required": true,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "string",
|
||||
"default": "text",
|
||||
"enum": [
|
||||
"text",
|
||||
"join",
|
||||
"leave",
|
||||
"action"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
};
|
||||
|
||||
privateClient.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 IRC messages by day.
|
||||
*
|
||||
* Parameters (object):
|
||||
* server - Chat server info (see <DailyArchive.server>)
|
||||
* 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)
|
||||
* var archive = new chatMessages.DailyArchive({
|
||||
* server: {
|
||||
* type: 'irc',
|
||||
* name: 'freenode',
|
||||
* ircURI: 'irc://irc.freenode.net'
|
||||
* },
|
||||
* channelName: '#kosmos',
|
||||
* date: new Date(),
|
||||
* isPublic: true
|
||||
* });
|
||||
* (end code)
|
||||
*
|
||||
* Example for XMPP:
|
||||
*
|
||||
* (start code)
|
||||
* var archive = new chatMessages.DailyArchive({
|
||||
* server: {
|
||||
* type: 'xmpp',
|
||||
* name: '5apps',
|
||||
* xmppMUC: 'muc.5apps.com'
|
||||
* },
|
||||
* channelName: 'watercooler',
|
||||
* date: new Date(),
|
||||
* isPublic: false
|
||||
* });
|
||||
* (end code)
|
||||
*/
|
||||
var DailyArchive = function DailyArchive(options) {
|
||||
//
|
||||
// Defaults
|
||||
//
|
||||
options.isPublic = options.isPublic || false;
|
||||
|
||||
//
|
||||
// Validate options
|
||||
//
|
||||
if (typeof options !== "object") {
|
||||
throw "options must be an object";
|
||||
}
|
||||
if (typeof options.server !== "object" ||
|
||||
typeof options.server.type !== "string" ||
|
||||
typeof options.server.name !== "string") {
|
||||
throw "server must be an object containing at least server \"type\" and \"name\"";
|
||||
}
|
||||
if (typeof options.channelName !== "string") {
|
||||
throw "channelName 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";
|
||||
}
|
||||
|
||||
/**
|
||||
* Property: server
|
||||
*
|
||||
* Contains information about the chat server/network
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Property: channelName
|
||||
*
|
||||
* Name of the IRC channel (e.g. "#kosmos")
|
||||
*/
|
||||
this.channelName = options.channelName;
|
||||
|
||||
/**
|
||||
* Property: date
|
||||
*
|
||||
* Date of the archive's content
|
||||
*/
|
||||
this.date = options.date;
|
||||
|
||||
/**
|
||||
* Property: isPublic
|
||||
*
|
||||
* `true` for public archives, `false` for private ones
|
||||
*/
|
||||
this.isPublic = options.isPublic;
|
||||
|
||||
/**
|
||||
* Property: parsedDate
|
||||
*
|
||||
* Object containing padded year, month and day of date
|
||||
*/
|
||||
this.parsedDate = parseDate(this.date);
|
||||
|
||||
/**
|
||||
* Property: dateId
|
||||
*
|
||||
* Date string in the form of YYYY/MM/DD
|
||||
*/
|
||||
this.dateId = this.parsedDate.year+'/'+this.parsedDate.month+'/'+this.parsedDate.day;
|
||||
|
||||
/**
|
||||
* Property: path
|
||||
*
|
||||
* Document path of the archive file
|
||||
*/
|
||||
switch (this.server.type) {
|
||||
case 'irc':
|
||||
if (this.channelName.match(/^#/)) {
|
||||
// normal chatroom
|
||||
var channelName = this.channelName.replace(/^#/,'');
|
||||
this.path = `${this.server.name}/channels/${channelName}/${this.dateId}`;
|
||||
} else {
|
||||
// user direct message
|
||||
this.path = `${this.server.name}/users/${this.channelName}/${this.dateId}`;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this.path = `${this.server.name}/${this.channelName}/${this.dateId}`;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property: client
|
||||
*
|
||||
* Public or private BaseClient, depending on isPublic
|
||||
*/
|
||||
this.client = this.isPublic ? publicClient : privateClient;
|
||||
|
||||
/**
|
||||
* Property: previous
|
||||
*
|
||||
* Date of previous log file as YYYY/MM/DD
|
||||
*/
|
||||
this.previous = options.previous;
|
||||
|
||||
/**
|
||||
* Property: next
|
||||
*
|
||||
* Date of next log file as YYYY/MM/DD
|
||||
*/
|
||||
this.next = options.next;
|
||||
};
|
||||
|
||||
DailyArchive.prototype = {
|
||||
/*
|
||||
* Method: addMessage
|
||||
*
|
||||
* Parameters (object):
|
||||
* 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: function addMessage(message) {
|
||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
message.type = message.type || 'text';
|
||||
|
||||
return this.client.getObject(this.path).then((archive) => {
|
||||
if (typeof archive === 'object') {
|
||||
return this._updateDocument(archive, message);
|
||||
} else {
|
||||
return this._createDocument(message);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: addMessages
|
||||
*
|
||||
* Like <addMessage>, but for multiple messages at once. Useful for bulk
|
||||
* imports of messages.
|
||||
*
|
||||
* Parameters:
|
||||
* messages - Array of message objects (see params for addMessage)
|
||||
* overwrite - If true, creates a new archive file and overwrites the
|
||||
* old one. Defaults to false.
|
||||
*/
|
||||
addMessages: function addMessage(messages, overwrite) {
|
||||
if (this.isPublic && !this.channelName.match(/^#/)) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
overwrite = overwrite || false;
|
||||
|
||||
messages.forEach(function(message) {
|
||||
message.type = message.type || 'text';
|
||||
});
|
||||
|
||||
if (overwrite) {
|
||||
return this._createDocument(messages);
|
||||
} else {
|
||||
return this.client.getObject(this.path).then((archive) => {
|
||||
if (typeof archive === 'object') {
|
||||
return this._updateDocument(archive, messages);
|
||||
} else {
|
||||
return this._createDocument(messages);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: remove
|
||||
*
|
||||
* Deletes the entire archive document from storage
|
||||
*/
|
||||
remove: function() {
|
||||
return this.client.remove(this.path);
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _updateDocument
|
||||
*
|
||||
* Updates and writes an existing archive document
|
||||
*/
|
||||
_updateDocument: function(archive, messages) {
|
||||
RemoteStorage.log('[chat-messages] Updating archive document', archive);
|
||||
|
||||
if (Array.isArray(messages)) {
|
||||
messages.forEach(function(message) {
|
||||
archive.today.messages.push(message);
|
||||
});
|
||||
} else {
|
||||
archive.today.messages.push(messages);
|
||||
}
|
||||
|
||||
return this._sync(archive);
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _createDocument
|
||||
*
|
||||
* Creates and writes a new archive document
|
||||
*/
|
||||
_createDocument: function(messages) {
|
||||
RemoteStorage.log('[chat-messages] Creating new archive document');
|
||||
let archive = this._buildArchiveObject();
|
||||
|
||||
if (Array.isArray(messages)) {
|
||||
messages.forEach((message) => {
|
||||
archive.today.messages.push(message);
|
||||
});
|
||||
} else {
|
||||
archive.today.messages.push(messages);
|
||||
}
|
||||
|
||||
if (this.previous || this.next) {
|
||||
// The app is handling previous/next keys itself
|
||||
// That includes setting 'next' in the previous log file
|
||||
if (this.previous) { archive.today.previous = this.previous; }
|
||||
if (this.next) { archive.today.next = this.next; }
|
||||
return this._sync(archive);
|
||||
} else {
|
||||
// Find and update previous archive, set 'previous' on this one
|
||||
return this._updatePreviousArchive().then((previous) => {
|
||||
if (typeof previous === 'object') {
|
||||
archive.today.previous = previous.today['@id'];
|
||||
}
|
||||
return this._sync(archive);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _buildArchiveObject
|
||||
*
|
||||
* Builds the object to be stored in remote storage
|
||||
*/
|
||||
_buildArchiveObject: function() {
|
||||
let roomName = this.channelName.replace(/#/,'');
|
||||
|
||||
let archive = {
|
||||
"@id": "chat-messages/"+this.server.name+"/channels/"+roomName+"/",
|
||||
"@type": "ChatChannel",
|
||||
"name": this.channelName,
|
||||
"today": {
|
||||
"@id": this.dateId,
|
||||
"@type": "ChatLog",
|
||||
"messageType": "InstantMessage",
|
||||
"messages": []
|
||||
}
|
||||
};
|
||||
|
||||
switch (this.server.type) {
|
||||
case 'irc':
|
||||
if (!this.channelName.match(/^#/)) {
|
||||
archive["@id"] = "chat-messages/"+this.server.name+"/users/"+this.channelName+"/";
|
||||
}
|
||||
archive["ircURI"] = this.server.ircURI+"/"+roomName;
|
||||
break;
|
||||
case 'xmpp':
|
||||
archive["xmppURI"] = `xmpp:${this.channelName}@${this.server.xmppMUC}`;
|
||||
break;
|
||||
}
|
||||
|
||||
return archive;
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _updatePreviousArchive
|
||||
*
|
||||
* Finds the previous archive document and updates its today.next value
|
||||
*/
|
||||
_updatePreviousArchive: function() {
|
||||
return this._findPreviousArchive().then((archive) => {
|
||||
if (typeof archive === 'object' && archive.today) {
|
||||
archive.today.next = this.dateId;
|
||||
let path = this.path.substring(0, this.path.length-this.dateId.length)+archive.today['@id'];
|
||||
|
||||
return this.client.storeObject('daily-archive', path, archive).then(() => {
|
||||
RemoteStorage.log('[chat-messages] Previous archive written to remote storage', path, archive);
|
||||
return archive;
|
||||
});
|
||||
} else {
|
||||
RemoteStorage.log('[chat-messages] Previous archive not found');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _findPreviousArchive
|
||||
*
|
||||
* Returns the previous archive document
|
||||
*/
|
||||
_findPreviousArchive: function() {
|
||||
const monthPath = this.path.substring(0, this.path.length-2);
|
||||
const yearPath = this.path.substring(0, this.path.length-5);
|
||||
const basePath = this.path.substring(0, this.path.length-10);
|
||||
|
||||
return this.client.getListing(monthPath).then((listing) => {
|
||||
let days = Object.keys(listing).map((i) => parseInt(i)).map((i) => {
|
||||
return (i < parseInt(this.parsedDate.day)) ? i : null;
|
||||
}).filter(function(i){ return i != null; });
|
||||
|
||||
if (days.length > 0) {
|
||||
let day = pad(Math.max(...days).toString());
|
||||
return this.client.getObject(monthPath+day);
|
||||
}
|
||||
|
||||
// Find last day in previous month
|
||||
return this.client.getListing(yearPath).then((listing) => {
|
||||
let months = Object.keys(listing).map((i) => parseInt(i.substr(0,2))).map((i) => {
|
||||
return (i < parseInt(this.parsedDate.month)) ? i : null;
|
||||
}).filter(function(i){ return i != null; });
|
||||
|
||||
if (months.length > 0) {
|
||||
let month = pad(Math.max(...months).toString());
|
||||
|
||||
return this.client.getListing(yearPath+month+'/').then((listing) => {
|
||||
let days = Object.keys(listing).map((i) => parseInt(i));
|
||||
let day = pad(Math.max(...days).toString());
|
||||
return this.client.getObject(yearPath+month+'/'+day);
|
||||
});
|
||||
} else {
|
||||
// Find last month and day in previous year
|
||||
return this.client.getListing(basePath).then((listing) => {
|
||||
|
||||
let years = Object.keys(listing).map((i) => parseInt(i.substr(0,4))).map((i) => {
|
||||
return (i < parseInt(this.parsedDate.year)) ? i : null;
|
||||
}).filter(function(i){ return i != null; });
|
||||
|
||||
if (years.length > 0) {
|
||||
let year = Math.max(...years).toString();
|
||||
|
||||
return this.client.getListing(basePath+year+'/').then((listing) => {
|
||||
let months = Object.keys(listing).map((i) => parseInt(i.substr(0,2)));
|
||||
let month = pad(Math.max(...months).toString());
|
||||
|
||||
return this.client.getListing(basePath+year+'/'+month+'/').then((listing) => {
|
||||
let days = Object.keys(listing).map((i) => parseInt(i));
|
||||
let day = pad(Math.max(...days).toString());
|
||||
return this.client.getObject(basePath+year+'/'+month+'/'+day);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Method: _sync
|
||||
*
|
||||
* Write archive document
|
||||
*/
|
||||
_sync: function(obj) {
|
||||
RemoteStorage.log('[chat-messages] Writing archive object', obj);
|
||||
|
||||
return this.client.storeObject('daily-archive', this.path, obj).then(function(){
|
||||
RemoteStorage.log('[chat-messages] Archive written to remote storage');
|
||||
return true;
|
||||
},function(error){
|
||||
console.log('[chat-messages] Error trying to store object', error);
|
||||
return error;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var pad = function(num) {
|
||||
num = String(num);
|
||||
if (num.length === 1) { num = "0" + num; }
|
||||
return num;
|
||||
};
|
||||
|
||||
var parseDate = function(date) {
|
||||
return {
|
||||
year: date.getUTCFullYear(),
|
||||
month: pad( date.getUTCMonth() + 1 ),
|
||||
day: pad( date.getUTCDate() )
|
||||
};
|
||||
};
|
||||
|
||||
var exports = {
|
||||
DailyArchive: DailyArchive,
|
||||
privateClient: privateClient,
|
||||
publicClient: publicClient
|
||||
};
|
||||
|
||||
// Return public functions
|
||||
return { exports: exports };
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "remotestorage-module-chat-messages",
|
||||
"version": "0.6.0",
|
||||
"description": "Stores chat messages in daily archive files",
|
||||
"main": "./dist/build.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"dev": "webpack -w",
|
||||
"build": "NODE_ENV=production webpack"
|
||||
},
|
||||
"author": "Kosmos Developers <mail@kosmos.org> (https://kosmos.org)",
|
||||
"contributors": [
|
||||
"Sebastian Kippe <sebastian@kip.pe>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.18.2",
|
||||
"babel-loader": "^6.2.7",
|
||||
"babel-preset-es2015": "^6.18.0",
|
||||
"webpack": "^1.13.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
var webpack = require('webpack');
|
||||
var isProd = (process.env.NODE_ENV === 'production');
|
||||
|
||||
// minimize only in production
|
||||
var plugins = isProd ? [new webpack.optimize.UglifyJsPlugin({minimize: true })] : []
|
||||
|
||||
module.exports = {
|
||||
entry: './index.js',
|
||||
// source map not in production
|
||||
devtool: !isProd && 'source-map',
|
||||
output: {
|
||||
filename: __dirname + '/dist/build.js',
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
externals: {
|
||||
"remotestoragejs": {
|
||||
root: "RemoteStorage", // <script src='remotestorage.js'> will resolve in this.RemoteStorage
|
||||
commonjs2: "remotestoragejs", // require('remotestoragejs')
|
||||
commonjs: "remotestoragejs", // require('remotestoragejs')
|
||||
amd: "remotestoragejs" // define(['remotestoragejs'], ...)
|
||||
}
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.js$/, exclude: '/node_modules|dist/', loader: 'babel?presets[]=es2015' },
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['', '.js']
|
||||
},
|
||||
plugins: plugins
|
||||
};
|
||||
Reference in new issue
Block a user