Loading backlog from filesystem if logging enabled, having only ~200 messages per channel in memory

This commit is contained in:
aynik 2015-04-04 02:15:37 +02:00
parent 544c281bf6
commit b5fba69545
7 changed files with 168 additions and 21 deletions

29
client/js/libs.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -172,6 +172,7 @@ Client.prototype.connect = function(args) {
port: server.port, port: server.port,
tls: !!args.tls, tls: !!args.tls,
password: args.password, password: args.password,
user: nick,
username: username, username: username,
realname: realname, realname: realname,
commands: args.commands commands: args.commands
@ -252,11 +253,12 @@ Client.prototype.more = function(data) {
return; return;
} }
var chan = target.chan; var chan = target.chan;
var count = chan.messages.length - (data.count || 0); var count = chan.messages.count - (data.count || 0);
var messages = chan.messages.slice(Math.max(0, count - 100), count); chan.messages.fetch(Math.max(0, count - 100), count, function(err, messages){
client.emit("more", { client.emit("more", {
chan: chan.id, chan: chan.id,
messages: messages messages: messages.map(log.parse)
});
}); });
}; };

View File

@ -1,10 +1,75 @@
var path = require("path"); var path = require("path");
var fs = require('fs');
module.exports = { module.exports = {
HOME: (process.env.HOME || process.env.USERPROFILE) + "/.shout", HOME: (process.env.HOME || process.env.USERPROFILE) + "/.shout",
getConfig: getConfig getConfig: getConfig,
getLines: getLines,
countLines: countLines
}; };
function getConfig() { function getConfig() {
return require(path.resolve(this.HOME) + "/config"); return require(path.resolve(this.HOME) + "/config");
}; };
function getLines(filename, from, to, callback) {
var stream = fs.createReadStream(filename, {
flags: 'r',
encoding: 'utf-8',
fd: null,
mode: 0666,
bufferSize: 1024
});
function endReached(){
callback(null, lines.slice(0, lines.length-1));
}
var lines = [];
var count = -1;
var left = "";
stream.on("data", function(data){
data = (left+data).split("\n");
if (data[data.lnegth-1]) left = data.pop();
var next = count + data.length;
var gtn = next >= from;
var gtm = next >= to;
if (gtn) lines = lines.concat(data.slice(lines.length ? 0 : from - count - 1));
if (gtm) {
stream.removeListener("end", endReached);
callback(null, lines.slice(0, to - from));
}
count = next;
});
stream.on("error", function(err){
callback(err);
});
stream.on("end", endReached);
}
function countLines(filename, callback) {
var stream = fs.createReadStream(filename, {
flags: 'r',
encoding: 'utf-8',
fd: null,
mode: 0666,
bufferSize: 1024
});
var count = -1;
stream.on("data", function(data){
count += data.split("\n").length;
});
stream.on("error", function(err){
callback(err);
});
stream.on("end", function(){
callback(null, count);
});
}

View File

@ -43,3 +43,34 @@ module.exports.write = function(user, network, chan, msg) {
} }
); );
}; };
var redt = /^\[\d{4}\-\d{2}\-\d{2} (\d{2}:\d{2}:\d{2})\] /;
var rems = /^<([^<]+)> /;
var reus = /(\S*) */;
module.exports.parse = function(line){
var pmatch = line.match(redt);
var datetime = pmatch[1];
var msg = { id: 0, time: datetime, self: false };
line = line.substr(pmatch[0].length);
if (line[0] === "*") {
line = line.substr(2);
if (line[0] !== " ") {
pmatch = line.match(reus);
msg.from = pmatch[0];
line = line.substr(pmatch[0].length);
} else {
msg.from = "";
line = line.substr(1);
}
pmatch = line.match(reus);
msg.type = pmatch[0];
msg.text = line.substr(pmatch[0].length);
} else {
pmatch = line.match(rems);
msg.from = pmatch[1];
msg.type = "message";
msg.text = line.substr(pmatch[0].length);
}
return msg;
};

View File

@ -1,4 +1,6 @@
var util = require("util");
var _ = require("lodash"); var _ = require("lodash");
var Helper = require("../helper");
module.exports = Chan; module.exports = Chan;
@ -8,18 +10,52 @@ Chan.Type = {
QUERY: "query" QUERY: "query"
}; };
var MessageArray = function(chan){
Array.call(this);
this.chan = chan;
this.log = Helper.HOME + "/logs/" + this.chan.user
+ "/" + this.chan.network + "/" + this.chan.channel + ".log";
var that = this;
Helper.countLines(this.log, function(err, count){
that.count = err ? 0 : count;
});
};
util.inherits(MessageArray, Array);
MessageArray.prototype.push = function(message) {
var config = Helper.getConfig();
if (config.log === true) {
if (this.length > 250) this.splice(50);
}
Array.prototype.push.call(this, message);
this.count++;
};
MessageArray.prototype.fetch = function(from, to, callback) {
var messages = [];
if (from < this.length) messages = messages.concat(this.slice(from));
if (to <= this.length) callback(null, messages.slice(0, to));
else if (this.log) {
var linesFrom = from + messages.length;
Helper.getLines(this.log, linesFrom, to, function(err, lines){
callback(null, messages.concat(lines));
});
}
else callback(null, messages);
};
var id = 0; var id = 0;
function Chan(attr) { function Chan(attr) {
_.merge(this, _.extend({ _.merge(this, _.extend({
id: id++, id: id++,
messages: [],
name: "", name: "",
topic: "", topic: "",
type: Chan.Type.CHANNEL, type: Chan.Type.CHANNEL,
unread: 0, unread: 0,
users: [] users: []
}, attr)); }, attr));
this.messages = new MessageArray(this);
} }
Chan.prototype.sortUsers = function() { Chan.prototype.sortUsers = function() {

View File

@ -24,7 +24,10 @@ function Network(attr) {
this.channels.unshift( this.channels.unshift(
new Chan({ new Chan({
name: this.name, name: this.name,
type: Chan.Type.LOBBY type: Chan.Type.LOBBY,
user: this.user,
network: this.host,
channel: this.host
}) })
); );
} }

View File

@ -9,7 +9,10 @@ module.exports = function(irc, network) {
var chan = _.find(network.channels, {name: data.channel}); var chan = _.find(network.channels, {name: data.channel});
if (typeof chan === "undefined") { if (typeof chan === "undefined") {
chan = new Chan({ chan = new Chan({
name: data.channel name: data.channel,
user: data.nick,
network: network.host,
channel: data.channel
}); });
network.channels.push(chan); network.channels.push(chan);
client.save(); client.save();