diff --git a/src/client.js b/src/client.js index 54f14d7..be2fa79 100644 --- a/src/client.js +++ b/src/client.js @@ -172,6 +172,7 @@ Client.prototype.connect = function(args) { port: server.port, tls: !!args.tls, password: args.password, + user: nick, username: username, realname: realname, commands: args.commands @@ -252,12 +253,13 @@ Client.prototype.more = function(data) { return; } var chan = target.chan; - var count = chan.messages.length - (data.count || 0); - var messages = chan.messages.slice(Math.max(0, count - 100), count); - client.emit("more", { - chan: chan.id, - messages: messages - }); + var count = chan.messages.count - (data.count || 0); + chan.messages.fetch(Math.max(0, count - 100), count, function(err, messages){ + client.emit("more", { + chan: chan.id, + messages: messages + }); + }); }; Client.prototype.open = function(data) { diff --git a/src/helper.js b/src/helper.js index 565df80..148e608 100644 --- a/src/helper.js +++ b/src/helper.js @@ -1,10 +1,76 @@ var path = require("path"); +var fs = require('fs'); module.exports = { HOME: (process.env.HOME || process.env.USERPROFILE) + "/.shout", - getConfig: getConfig + getConfig: getConfig, + getLines: getLines, + countLines: countLines }; function getConfig() { 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 last = ""; + + stream.on("data", function(data){ + data = (last+data).split("\n"); + last = 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); + stream.close(); + return 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); + }); +} diff --git a/src/log.js b/src/log.js index 7da01d7..1e622f9 100644 --- a/src/log.js +++ b/src/log.js @@ -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; +}; diff --git a/src/models/chan.js b/src/models/chan.js index b80bbfd..47f23e0 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -1,4 +1,7 @@ +var util = require("util"); var _ = require("lodash"); +var Helper = require("../helper"); +var log = require("../log"); module.exports = Chan; @@ -8,18 +11,52 @@ Chan.Type = { 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 > 50) 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.map(log.parse))); + }); + } + else callback(null, messages); +}; + var id = 0; function Chan(attr) { _.merge(this, _.extend({ id: id++, - messages: [], name: "", topic: "", type: Chan.Type.CHANNEL, unread: 0, users: [] }, attr)); + this.messages = new MessageArray(this); } Chan.prototype.sortUsers = function() { diff --git a/src/models/network.js b/src/models/network.js index 8755627..c8405dc 100644 --- a/src/models/network.js +++ b/src/models/network.js @@ -24,7 +24,10 @@ function Network(attr) { this.channels.unshift( new Chan({ name: this.name, - type: Chan.Type.LOBBY + type: Chan.Type.LOBBY, + user: this.user, + network: this.host, + channel: this.host }) ); } diff --git a/src/plugins/irc-events/join.js b/src/plugins/irc-events/join.js index d407990..0e55049 100644 --- a/src/plugins/irc-events/join.js +++ b/src/plugins/irc-events/join.js @@ -9,7 +9,10 @@ module.exports = function(irc, network) { var chan = _.find(network.channels, {name: data.channel}); if (typeof chan === "undefined") { chan = new Chan({ - name: data.channel + name: data.channel, + user: data.nick, + network: network.host, + channel: data.channel }); network.channels.push(chan); client.save();