backend work
This commit is contained in:
parent
2b44cec752
commit
7d90a97620
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
/build/
|
/build/
|
||||||
|
/client.config.toml
|
||||||
|
9
client.config.example.toml
Normal file
9
client.config.example.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[server]
|
||||||
|
port=8080
|
||||||
|
|
||||||
|
[client]
|
||||||
|
username="teemant"
|
||||||
|
realname="A Teemant User"
|
||||||
|
default_quit_msg="Teemant IRC"
|
||||||
|
default_part_msg="Bye!"
|
||||||
|
secure_by_default=false
|
@ -13,9 +13,9 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
"jade": "^1.11.0",
|
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"socketio": "^1.0.0"
|
"socketio": "^1.0.0",
|
||||||
|
"toml": "^2.3.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -376,7 +376,11 @@ body {
|
|||||||
color: #03a9f4;
|
color: #03a9f4;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.message.m_nick .content {
|
.message.m_motd .content {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.message.m_nick .content,
|
||||||
|
.message.m_notice .content {
|
||||||
color: #ff9800;
|
color: #ff9800;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,5 @@
|
|||||||
<path d="M239.4,136.001c-57,0-103.3,46.3-103.3,103.3s46.3,103.3,103.3,103.3s103.3-46.3,103.3-103.3S296.4,136.001,239.4,136.001
|
<path d="M239.4,136.001c-57,0-103.3,46.3-103.3,103.3s46.3,103.3,103.3,103.3s103.3-46.3,103.3-103.3S296.4,136.001,239.4,136.001
|
||||||
z M239.4,315.601c-42.1,0-76.3-34.2-76.3-76.3s34.2-76.3,76.3-76.3s76.3,34.2,76.3,76.3S281.5,315.601,239.4,315.601z"/>
|
z M239.4,315.601c-42.1,0-76.3-34.2-76.3-76.3s34.2-76.3,76.3-76.3s76.3,34.2,76.3,76.3S281.5,315.601,239.4,315.601z"/>
|
||||||
</g>
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.0 KiB |
@ -4,6 +4,7 @@ window.irc = {
|
|||||||
timestamps: true,
|
timestamps: true,
|
||||||
timestampFormat: "HH:mm:ss",
|
timestampFormat: "HH:mm:ss",
|
||||||
serverData: {},
|
serverData: {},
|
||||||
|
serverChatQueue: {},
|
||||||
chatType: "simple"
|
chatType: "simple"
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,6 +126,20 @@ Date.prototype.format = function (format, utc){
|
|||||||
return format;
|
return format;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function linkify(text) {
|
||||||
|
// see http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||||
|
let re = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi;
|
||||||
|
let parsed = text.replace(re, function(url) {
|
||||||
|
// turn into a link
|
||||||
|
let href = url;
|
||||||
|
if (url.indexOf('http') !== 0) {
|
||||||
|
href = 'http://' + url;
|
||||||
|
}
|
||||||
|
return '<a href="' + href + '" target="_blank">' + url + '</a>';
|
||||||
|
});
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
function removeClass(element, cl) {
|
function removeClass(element, cl) {
|
||||||
let classList = element.className.split(" ");
|
let classList = element.className.split(" ");
|
||||||
remove_str(classList, cl);
|
remove_str(classList, cl);
|
||||||
@ -154,6 +169,8 @@ let composer = {
|
|||||||
if(irc.timestamps)
|
if(irc.timestamps)
|
||||||
element.innerHTML += "<span class='timestamp'>"+time.format(irc.timestampFormat)+"</span> ";
|
element.innerHTML += "<span class='timestamp'>"+time.format(irc.timestampFormat)+"</span> ";
|
||||||
|
|
||||||
|
message = linkify(message);
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case "action":
|
case "action":
|
||||||
element.innerHTML += "<span class='asterisk'>*</span> <span class='actionee'>"+sender+"</span> ";
|
element.innerHTML += "<span class='asterisk'>*</span> <span class='actionee'>"+sender+"</span> ";
|
||||||
@ -250,6 +267,7 @@ class Nicklist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nickAddObject(obj) {
|
nickAddObject(obj) {
|
||||||
|
if(this.getNickIndex(obj.nickname) != null) return;
|
||||||
this.nicks.push(obj);
|
this.nicks.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,7 +442,7 @@ class Buffer {
|
|||||||
|
|
||||||
if(this.topic != null && this.topic != "") {
|
if(this.topic != null && this.topic != "") {
|
||||||
addClass(clientdom.chat, 'vtopic');
|
addClass(clientdom.chat, 'vtopic');
|
||||||
clientdom.topicbar.innerHTML = this.topic;
|
clientdom.topicbar.innerHTML = linkify(this.topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderMessages();
|
this.renderMessages();
|
||||||
@ -455,7 +473,7 @@ class Buffer {
|
|||||||
|
|
||||||
topicChange(topic) {
|
topicChange(topic) {
|
||||||
if(this.active) {
|
if(this.active) {
|
||||||
clientdom.topicbar.innerHTML = topic;
|
clientdom.topicbar.innerHTML = linkify(topic);
|
||||||
|
|
||||||
if(this.topic == null)
|
if(this.topic == null)
|
||||||
addClass(clientdom.chat, "vtopic");
|
addClass(clientdom.chat, "vtopic");
|
||||||
@ -463,8 +481,8 @@ class Buffer {
|
|||||||
this.topic = topic;
|
this.topic = topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
addMessage(message, sender, type) {
|
addMessage(message, sender, type, time) {
|
||||||
let mesg = {message: message, sender: sender, type: type, time: new Date()}
|
let mesg = {message: message, sender: sender, type: type, time: time || new Date()}
|
||||||
this.messages.push(mesg);
|
this.messages.push(mesg);
|
||||||
|
|
||||||
if(this.active)
|
if(this.active)
|
||||||
@ -689,6 +707,15 @@ class IRCChatWindow {
|
|||||||
this.buffers.push(newServer);
|
this.buffers.push(newServer);
|
||||||
this.render(newServer);
|
this.render(newServer);
|
||||||
this.firstServer = false;
|
this.firstServer = false;
|
||||||
|
|
||||||
|
if(irc.serverChatQueue[serverinfo.address]) {
|
||||||
|
for(let a in irc.serverChatQueue[serverinfo.address]) {
|
||||||
|
let mesg = irc.serverChatQueue[serverinfo.address][a];
|
||||||
|
newServer.addMessage(mesg.message, mesg.from, mesg.type, mesg.time);
|
||||||
|
}
|
||||||
|
delete irc.serverChatQueue[serverinfo.address];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createBuffer(server, name, type, autoswitch) {
|
createBuffer(server, name, type, autoswitch) {
|
||||||
@ -918,16 +945,24 @@ window.onload = function() {
|
|||||||
else if(data['topic'])
|
else if(data['topic'])
|
||||||
irc.chat.topicChange(data.channel, data.server, data.topic, null);
|
irc.chat.topicChange(data.channel, data.server, data.topic, null);
|
||||||
else if(data['set_by'])
|
else if(data['set_by'])
|
||||||
irc.chat.messageBuffer(data.channel, data.server, {message: "Topic set by "+data.set_by+" on "+new Date(data.time), type: "topic", from: null});
|
irc.chat.messageBuffer(data.channel, data.server, {message: "Topic set by "+data.set_by+" on "+new Date(data.time*1000), type: "topic", from: null});
|
||||||
break;
|
break;
|
||||||
case "nick_change":
|
case "nick_change":
|
||||||
irc.chat.nickChange(data.server, data.nick, data.newNick);
|
irc.chat.nickChange(data.server, data.nick, data.newNick);
|
||||||
break;
|
break;
|
||||||
case "server_message":
|
case "server_message":
|
||||||
irc.chat.messageBuffer(data.server, data.server, {message: data.message, type: data.messageType, from: null});
|
if(irc.chat.getBuffersByServer(data.server).length == 0) {
|
||||||
|
if(!irc.serverChatQueue[data.server]) {
|
||||||
|
irc.serverChatQueue[data.server] = [];
|
||||||
|
} else {
|
||||||
|
irc.serverChatQueue[data.server].push({type: data.messageType, message: data.message, from: data.from || null, time: new Date()});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
irc.chat.messageBuffer(data.server, data.server, {message: data.message, type: data.messageType, from: data.from || null});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "connect_message":
|
case "connect_message":
|
||||||
irc.auther.authMessage(data.data, data.error);
|
irc.auther.authMessage(data.message, data.error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -322,7 +322,9 @@ body
|
|||||||
&.m_topic .content
|
&.m_topic .content
|
||||||
color: #03A9F4;
|
color: #03A9F4;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
&.m_nick .content
|
&.m_motd .content
|
||||||
|
font-family: monospace;
|
||||||
|
&.m_nick .content, &.m_notice .content
|
||||||
color: #FF9800;
|
color: #FF9800;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
&.m_action .actionee
|
&.m_action .actionee
|
||||||
|
14
server/config.js
Normal file
14
server/config.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
let fs = require('fs');
|
||||||
|
let toml = require('toml');
|
||||||
|
let filename = __dirname+'/../client.config.toml';
|
||||||
|
|
||||||
|
let config;
|
||||||
|
|
||||||
|
try {
|
||||||
|
config = toml.parse(fs.readFileSync(filename));
|
||||||
|
} catch (e) {
|
||||||
|
throw 'config.toml parse error: ' + e;
|
||||||
|
console.error(e.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config;
|
284
server/irc.js
Normal file
284
server/irc.js
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
let EventEmitter = require('events').EventEmitter;
|
||||||
|
let net = require('net');
|
||||||
|
let configuration = require(__dirname+"/config");
|
||||||
|
let parse = require(__dirname+"/parser");
|
||||||
|
|
||||||
|
let defaultConfig = {
|
||||||
|
nickname: "teemant",
|
||||||
|
username: configuration.client.username,
|
||||||
|
realname: configuration.client.realname,
|
||||||
|
server: "localhost",
|
||||||
|
port: 6667,
|
||||||
|
autojoin: [],
|
||||||
|
secure: configuration.client.secure_by_default,
|
||||||
|
password: "",
|
||||||
|
address: "0.0.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!String.prototype.format) {
|
||||||
|
String.prototype.format = function() {
|
||||||
|
var args = arguments;
|
||||||
|
return this.replace(/{(\d+)}/g, function(match, number) {
|
||||||
|
return typeof args[number] != undefined ? args[number] : match;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigPatcher {
|
||||||
|
constructor(provided, defaults) {
|
||||||
|
this.result = defaults;
|
||||||
|
this.patches = provided;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch() {
|
||||||
|
for(let a in this.patches) {
|
||||||
|
this.result[a] = this.patches[a];
|
||||||
|
}
|
||||||
|
return this.result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IRCConnectionHandler {
|
||||||
|
constructor(connection) {
|
||||||
|
this.conn = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleServerLine(line) {
|
||||||
|
console.log(line);
|
||||||
|
if(this.conn.queue["supportsmsg"] && line.command != "005") {
|
||||||
|
|
||||||
|
delete this.conn.queue["supportsmsg"];
|
||||||
|
|
||||||
|
if(this.conn.config.autojoin.length > 0)
|
||||||
|
for(let t in this.conn.config.autojoin)
|
||||||
|
this.conn.socket.write('JOIN {0}\r\n'.format(this.conn.config.autojoin[t]));
|
||||||
|
|
||||||
|
this.conn.emit('authenticated', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
let serverName = this.conn.config.server;
|
||||||
|
let realServerName = this.conn.data.actualServer;
|
||||||
|
|
||||||
|
switch(line.command) {
|
||||||
|
case "error":
|
||||||
|
this.conn.emit("error", {type: "irc_error", raw: line.raw});
|
||||||
|
break;
|
||||||
|
case "001":
|
||||||
|
this.conn.data.actualServer = line.user.host;
|
||||||
|
break
|
||||||
|
case "005":
|
||||||
|
if(!this.conn.queue["supportsmsg"])
|
||||||
|
this.conn.queue["supportsmsg"] = true;
|
||||||
|
|
||||||
|
let argv = line.arguments.slice(1);
|
||||||
|
for(let a in argv) {
|
||||||
|
let t = argv[a];
|
||||||
|
if(t.indexOf('=') != -1) {
|
||||||
|
t = t.split('=');
|
||||||
|
if(t[0] === 'PREFIX') {
|
||||||
|
let d = t[1].match(/\((\w+)\)(.*)/);
|
||||||
|
let r = d[1].split('');
|
||||||
|
let aa = d[2].split('');
|
||||||
|
for(let b in r)
|
||||||
|
this.conn.data.supportedModes[r[b]] = aa[b];
|
||||||
|
} else if(t[0] === 'NETWORK') {
|
||||||
|
this.conn.data.network = t[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.conn.data.serverSupports[t[0]] = t[1];
|
||||||
|
} else {
|
||||||
|
this.conn.data.serverSupports[t] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "JOIN":
|
||||||
|
this.conn.emit('pass_to_client', {type: "event_join_channel", user: line.user, channel: line.trailing, server: serverName });
|
||||||
|
break;
|
||||||
|
case "PART":
|
||||||
|
this.conn.emit('pass_to_client', {type: "event_part_channel", user: line.user, channel: line.arguments[0], reason: line.trailing, server: serverName });
|
||||||
|
break;
|
||||||
|
case "QUIT":
|
||||||
|
this.conn.emit('pass_to_client', {type: "event_quit", user: line.user, reason: line.trailing, server: serverName });
|
||||||
|
break;
|
||||||
|
case "353":
|
||||||
|
if(!this.conn.queue["names"])
|
||||||
|
this.conn.queue['names'] = {};
|
||||||
|
|
||||||
|
let splittrail = line.trailing.split(' ');
|
||||||
|
for(let a in splittrail) {
|
||||||
|
let nick = splittrail[a];
|
||||||
|
if(nick.trim() == "") continue;
|
||||||
|
if(this.conn.queue["names"][line.arguments[2]])
|
||||||
|
this.conn.queue["names"][line.arguments[2]].push(nick);
|
||||||
|
else
|
||||||
|
this.conn.queue["names"][line.arguments[2]] = [nick];
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "366":
|
||||||
|
if(!this.conn.queue["names"]) break;
|
||||||
|
if(this.conn.queue["names"][line.arguments[1]]) {
|
||||||
|
this.conn.emit('pass_to_client', {type: "channel_nicks", channel: line.arguments[1], nicks: this.conn.queue["names"][line.arguments[1]], server: serverName});
|
||||||
|
delete this.conn.queue["names"][line.arguments[1]];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Object.keys(this.conn.queue["names"]).length == 0)
|
||||||
|
delete this.conn.queue["names"];
|
||||||
|
break;
|
||||||
|
case "PRIVMSG":
|
||||||
|
let type = "privmsg";
|
||||||
|
|
||||||
|
if(line.trailing.indexOf('\x01ACTION') == 0) {
|
||||||
|
line.trailing = line.trailing.substring(8);
|
||||||
|
line.trailing.substring(0, line.trailing.length-1);
|
||||||
|
type = "action";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(line.user.nickname != "")
|
||||||
|
this.conn.emit('pass_to_client', {type: "message", messageType: type, to: line.arguments[0],
|
||||||
|
user: line.user, message: line.trailing, server: serverName});
|
||||||
|
else
|
||||||
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: type, message: line.trailing, server: serverName, from: realServerName});
|
||||||
|
break;
|
||||||
|
case "NOTICE":
|
||||||
|
if(line.user.nickname != "")
|
||||||
|
this.conn.emit('pass_to_client', {type: "message", messageType: "notice", to: line.arguments[0],
|
||||||
|
user: line.user, message: line.trailing, server: serverName});
|
||||||
|
else
|
||||||
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "notice", message: line.trailing, server: serverName, from: realServerName});
|
||||||
|
break;
|
||||||
|
case "NICK":
|
||||||
|
this.conn.emit('pass_to_client', {type: "nick_change", nick: line.user.nickname, newNick: line.arguments[0], server: serverName});
|
||||||
|
break;
|
||||||
|
case "KICK":
|
||||||
|
this.conn.emit('pass_to_client', {type: "event_kick_channel", user: line.user, channel: line.arguments[0], kickee: line.arguments[1], server: serverName});
|
||||||
|
break;
|
||||||
|
case "TOPIC":
|
||||||
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[0], set_by: line.user.nickname, topic: line.trailing, server: serverName});
|
||||||
|
break;
|
||||||
|
case "332":
|
||||||
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[1], topic: line.trailing, server: serverName});
|
||||||
|
break;
|
||||||
|
case "333":
|
||||||
|
this.conn.emit('pass_to_client', {type: "channel_topic", channel: line.arguments[1], set_by: line.arguments[2], time: line.arguments[3], server: serverName});
|
||||||
|
break;
|
||||||
|
case "375":
|
||||||
|
case "372":
|
||||||
|
case "376":
|
||||||
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "motd", message: line.trailing, server: serverName, from: realServerName});
|
||||||
|
break;
|
||||||
|
case "251":
|
||||||
|
case "255":
|
||||||
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "regular", message: line.trailing, server: serverName, from: realServerName});
|
||||||
|
break;
|
||||||
|
case "252":
|
||||||
|
case "254":
|
||||||
|
case "042":
|
||||||
|
this.conn.emit('pass_to_client', {type: "server_message", messageType: "regular", message: line.arguments[1] +" "+ line.trailing, server: serverName, from: realServerName});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IRCConnection extends EventEmitter {
|
||||||
|
constructor(providedInfo) {
|
||||||
|
super();
|
||||||
|
let config_u = new ConfigPatcher(providedInfo, defaultConfig);
|
||||||
|
|
||||||
|
this.config = config_u.patch();
|
||||||
|
this.socket = null;
|
||||||
|
this.connected = false;
|
||||||
|
this.authenticated = false;
|
||||||
|
|
||||||
|
this.handler = new IRCConnectionHandler(this);
|
||||||
|
|
||||||
|
this.data = {
|
||||||
|
serverSupports: {},
|
||||||
|
network: this.config.server,
|
||||||
|
actualServer: this.config.server,
|
||||||
|
supportedModes: {}
|
||||||
|
};
|
||||||
|
this.queue = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
on(...args) {
|
||||||
|
return super.on(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(...args) {
|
||||||
|
return super.emit(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.socket = net.createConnection(this.config.port, this.config.server, () => {
|
||||||
|
this.connected = true;
|
||||||
|
this.authenticate();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.setEncoding('utf8');
|
||||||
|
this.socket.setTimeout(3000);
|
||||||
|
|
||||||
|
this.socket.on('error', (data) => {
|
||||||
|
this.emit('error', {type: "sock_error", message: "A socket error occured.", raw: data});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('lookup', (err, address, family, host) => {
|
||||||
|
if(err) {
|
||||||
|
this.emit('error', {type: "resolve_error", message: "Failed to resolve host."});
|
||||||
|
} else {
|
||||||
|
this.emit('lookup', {address: address, family: address, host: host});
|
||||||
|
this.config.address = address;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let buffer = "";
|
||||||
|
this.socket.on('data', (chunk) => {
|
||||||
|
buffer += chunk;
|
||||||
|
let data = buffer.split('\r\n');
|
||||||
|
buffer = data.pop();
|
||||||
|
data.forEach((line) => {
|
||||||
|
if(line.indexOf('PING') === 0) {
|
||||||
|
this.socket.write('PONG'+line.substring(4)+'\r\n');
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.emit('raw', line);
|
||||||
|
let parsed = parse(line);
|
||||||
|
this.emit('line', parsed);
|
||||||
|
this.handler.handleServerLine(parsed);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('close', (data) => {
|
||||||
|
if(this.queue['close'])
|
||||||
|
this.emit('closed', {type: "sock_closed_success", raw: data, message: "Connection closed."});
|
||||||
|
else
|
||||||
|
this.emit('closed', {type: "sock_closed", raw: data, message: "Connection closed."});
|
||||||
|
|
||||||
|
this.connected = false;
|
||||||
|
this.authenticated = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticate() {
|
||||||
|
if (this.config.password)
|
||||||
|
this.socket.write('PASS {0}\r\n'.format(this.config.password));
|
||||||
|
|
||||||
|
// TODO: WebIRC
|
||||||
|
this.socket.write('USER {0} 8 * :{1}\r\n'.format(this.config.username, this.config.realname));
|
||||||
|
this.socket.write('NICK {0}\r\n'.format(this.config.nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect(message) {
|
||||||
|
if(!this.connected) {
|
||||||
|
this.emit('error', {type: "sock_closed", message: "Connection already closed."});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.queue['close'] = true;
|
||||||
|
this.socket.write('QUIT :{0}\r\n'.format(message != null ? message : configuration.client.default_quit_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = IRCConnection;
|
44
server/parser.js
Normal file
44
server/parser.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
// :nickname!username@hostname command arg ume nts :trailing
|
||||||
|
// or
|
||||||
|
// :hostname command arg ume nts :trailing
|
||||||
|
|
||||||
|
module.exports = function(rawline) {
|
||||||
|
let final = {
|
||||||
|
user: {
|
||||||
|
nickname: "",
|
||||||
|
username: "",
|
||||||
|
hostname: ""
|
||||||
|
},
|
||||||
|
command: "error",
|
||||||
|
arguments: [],
|
||||||
|
trailing: "",
|
||||||
|
raw: rawline
|
||||||
|
}
|
||||||
|
|
||||||
|
let pass1 = (rawline.indexOf(':') == 0 ? rawline.substring(1).split(" ") : rawline.split(" "));
|
||||||
|
if (pass1[0] === "ERROR")
|
||||||
|
return final;
|
||||||
|
|
||||||
|
if(pass1[0].indexOf("!") != -1) {
|
||||||
|
let nickuser = pass1[0].split('!');
|
||||||
|
final.user.nickname = nickuser[0];
|
||||||
|
let userhost = nickuser[1].split('@');
|
||||||
|
final.user.username = userhost[0];
|
||||||
|
final.user.hostname = userhost[1];
|
||||||
|
} else {
|
||||||
|
final.user.hostname = pass1[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
final.command = pass1[1];
|
||||||
|
|
||||||
|
let pass2 = pass1.slice(2).join(" ");
|
||||||
|
if(pass2.indexOf(":") != -1) {
|
||||||
|
final.arguments = pass2.substring(0, pass2.indexOf(' :')).split(" ");
|
||||||
|
final.trailing = pass2.substring(pass2.indexOf(':')+1);
|
||||||
|
} else {
|
||||||
|
final.arguments = pass2.split(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
100
teemant.js
100
teemant.js
@ -2,10 +2,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
let express = require("express");
|
let express = require("express");
|
||||||
let path = require("path");
|
let path = require("path");
|
||||||
let sockio = require('socket.io');
|
let sockio = require("socket.io");
|
||||||
|
let dns = require("dns");
|
||||||
let app = express();
|
let app = express();
|
||||||
|
|
||||||
let pubdir = path.join(__dirname+"/public");
|
let pubdir = path.join(__dirname+"/public");
|
||||||
let port = 8080;
|
let config = require(__dirname+'/server/config');
|
||||||
|
let ircclient = require(__dirname+'/server/irc');
|
||||||
|
|
||||||
|
let port = config.server.port || 8080;
|
||||||
|
|
||||||
let connections = {}
|
let connections = {}
|
||||||
|
|
||||||
@ -19,6 +24,16 @@ let io = sockio.listen(app.listen(port, function() {
|
|||||||
console.log("*** Listening on port " + port);
|
console.log("*** Listening on port " + port);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
function resolveHostname(hostname) {
|
||||||
|
let promise = new Promise(function(resolve, reject) {
|
||||||
|
dns.lookup(hostname, function(err, address, family) {
|
||||||
|
if(err != null) return reject(err);
|
||||||
|
resolve(address);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
io.sockets.on('connection', function (socket) {
|
io.sockets.on('connection', function (socket) {
|
||||||
console.log('clientID: '+socket.id+' connection: ', socket.request.connection._peername);
|
console.log('clientID: '+socket.id+' connection: ', socket.request.connection._peername);
|
||||||
connections[socket.id] = {}
|
connections[socket.id] = {}
|
||||||
@ -28,52 +43,69 @@ io.sockets.on('connection', function (socket) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
socket.on('disconnect', function() {
|
socket.on('disconnect', function() {
|
||||||
for (let d in connections[socket.id]) d.disconnect("Client exited");
|
for (let d in connections[socket.id])
|
||||||
|
connections[socket.id][d].disconnect();
|
||||||
|
|
||||||
delete connections[socket.id];
|
delete connections[socket.id];
|
||||||
|
|
||||||
console.log('clientID: '+socket.id+' disconnect');
|
console.log('clientID: '+socket.id+' disconnect');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('error', (e) => {
|
||||||
|
console.log(e);
|
||||||
|
})
|
||||||
|
|
||||||
socket.on('irc_create', function(connectiondata) {
|
socket.on('irc_create', function(connectiondata) {
|
||||||
console.log(socket.id+" created irc connection: ", connectiondata);
|
console.log(socket.id+" created irc connection: ", connectiondata);
|
||||||
|
socket.emit('act_client', {type: 'connect_message', message: "Connecting to server..", error: false});
|
||||||
|
|
||||||
socket.emit('act_client', {type: 'connect_message', data: "Attempting connection..", error: false});
|
let newConnection = new ircclient(connectiondata);
|
||||||
|
newConnection.connect();
|
||||||
|
|
||||||
setTimeout(function() {
|
connections[socket.id][connectiondata.server] = newConnection;
|
||||||
console.log("fake connect");
|
|
||||||
socket.emit('act_client', {type: 'event_connect', address: connectiondata.server, network: "IcyNet", supportedModes: {"o": "@", "h": "%", "v": "+"}, nickname: connectiondata.nickname, raw: connectiondata});
|
|
||||||
socket.emit('act_client', {type: 'server_message', messageType: "notice", server: connectiondata.server, message: "Connection established"});
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
setTimeout(function() {
|
newConnection.on('authenticated', () => {
|
||||||
console.log("fake channel");
|
console.log("******** AUTH DONE **********");
|
||||||
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, channel: "#channel", user: {nickname: connectiondata.nickname, username: "teemant", hostname: socket.request.connection._peername.address}});
|
console.log("******** AUTH DONE **********");
|
||||||
socket.emit('act_client', {type: 'channel_nicks', channel: "#channel", server: connectiondata.server, nicks: ["+horse", "@scoper", "@aspire", "+random", "lol"]});
|
console.log("******** AUTH DONE **********");
|
||||||
socket.emit('act_client', {type: 'channel_topic', channel: "#channel", server: connectiondata.server, topic: "This channel is the best."});
|
console.log("******** AUTH DONE **********");
|
||||||
socket.emit('act_client', {type: 'channel_topic', channel: "#channel", server: connectiondata.server, set_by: "horse", time: Date.now()});
|
console.log("******** AUTH DONE **********");
|
||||||
socket.emit('act_client', {type: 'message', messageType: "privmsg", server: connectiondata.server, to: "#channel", user: {nickname: "horse"}, message: "I like ponies"});
|
socket.emit('act_client', {type: "event_connect", address: connectiondata.server, network: newConnection.data.network,
|
||||||
|
supportedModes: newConnection.data.supportedModes, nickname: newConnection.config.nickname});
|
||||||
|
});
|
||||||
|
|
||||||
setTimeout(function() {
|
newConnection.on('error', (data) => {
|
||||||
socket.emit('act_client', {type: 'nick_change', server: connectiondata.server, nick: "horse", newNick: "pony"});
|
let message = "An error occured";
|
||||||
}, 2000)
|
let inconnect = false;
|
||||||
|
|
||||||
setTimeout(function() {
|
if(!newConnection.authenticated) {
|
||||||
socket.emit('act_client', {type: 'message', messageType: "action", server: connectiondata.server, to: "#channel", user: {nickname: "pony"}, message: "Is the greatest pony fan"});
|
message = "Failed to connect to the server!";
|
||||||
}, 3000)
|
inconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(function() {
|
socket.emit('act_client', {type: (inconnect ? 'server_message' : 'connect_message'), message: message, type: 'error', error: true});
|
||||||
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, channel: "#poni", user: {nickname: connectiondata.nickname, username: "teemant", hostname: socket.request.connection._peername.address}});
|
});
|
||||||
socket.emit('act_client', {type: 'channel_nicks', channel: "#poni", server: connectiondata.server, nicks: ["+horse", "@Diamond", "@aspire", "+random", "lol"]});
|
|
||||||
socket.emit('act_client', {type: 'channel_topic', channel: "#poni", server: connectiondata.server, topic: "This channel is the second best."});
|
|
||||||
socket.emit('act_client', {type: 'channel_topic', channel: "#poni", server: connectiondata.server, set_by: "Diamond", time: Date.now()});
|
|
||||||
}, 5000)
|
|
||||||
|
|
||||||
setTimeout(function() {
|
newConnection.on('pass_to_client', (data) => {
|
||||||
socket.emit('act_client', {type: 'event_kick_channel', server: connectiondata.server, channel: "#channel", user: {nickname: "scoper", username: "teemant", hostname: socket.request.connection._peername.address}, kickee: "random", reason: "Get out."});
|
socket.emit('act_client', data);
|
||||||
socket.emit('act_client', {type: 'event_quit', server: connectiondata.server, user: {nickname: "lol", username: "teemant", hostname: socket.request.connection._peername.address}, reason: "Sleep."});
|
});
|
||||||
socket.emit('act_client', {type: 'event_part_channel', server: connectiondata.server, channel: "#poni", user: {nickname: "aspire", username: "teemant", hostname: socket.request.connection._peername.address}, reason: "Bye, lol."});
|
|
||||||
}, 6000);
|
newConnection.on('closed', (data) => {
|
||||||
}, 4000);
|
let message = "Connection closed";
|
||||||
|
let inconnect = false;
|
||||||
|
|
||||||
|
switch(data.type) {
|
||||||
|
case "sock_closed_success":
|
||||||
|
inconnect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!newConnection.authenticated) {
|
||||||
|
message = "Failed to connect to the server!";
|
||||||
|
inconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.emit('act_client', {type: (inconnect ? 'server_message' : 'connect_message'), message: message, type: 'error', error: true});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user