Parcourir la source

Event support (not all events yet)
Sync own users and channels

k4be il y a 5 ans
Parent
commit
d062639b96
3 fichiers modifiés avec 252 ajouts et 1 suppressions
  1. 40 0
      irc.js
  2. 184 1
      protocol/unrealircd.js
  3. 28 0
      services.js

+ 40 - 0
irc.js

@@ -11,6 +11,21 @@ var users = [];
 var servers = [];
 var channels = [];
 var me = null;
+var events = {};
+
+function addInternalEvents(){
+	events.netSynced.unshift(function(){
+		for(var i=0; i<users.length; i++){
+			var user = users[i];
+			if(user.uplink == me){
+				uplink.introduceUser(user);
+			}
+		}
+		for(var i=0; i<channels.length; i++){
+			uplink.syncChannel(channels[i]);
+		}
+	});
+}
 
 function findServer(s){
 	for(var i=0; i<servers.length; i++){
@@ -56,6 +71,7 @@ function removeServer(server){
 	for(var i=servers.length-1; i>=0; i--){ // finally, remove the given server
 		if(servers[i] == server){
 			console.log('Removing server '+servers[i].name);
+			events.doEvent('serverDelete', server);
 			servers.splice(i, 1);
 			delete server;
 			break;
@@ -77,6 +93,7 @@ function getChannel(name){
 		channel = new IRCchannel;
 		channel.name = name;
 		channels.push(channel);
+		events.doEvent('channelCreate', channel);
 	}
 	return channel;
 }
@@ -97,6 +114,8 @@ function newUser(nick, distance, TS, ident, host, uid, account, umodes, vhost, c
 	user = new IRCuser;
 	user.introduce(nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname, uplink);
 	users.push(user);
+	events.doEvent('userCreate', user);
+	return user;
 }
 
 function newServer(name, sid, desc, distance, uplink){
@@ -107,6 +126,8 @@ function newServer(name, sid, desc, distance, uplink){
 	server = new IRCserver;
 	server.introduce(name, sid, desc, distance, uplink);
 	servers.push(server);
+	events.doEvent('serverCreate', server);
+	return server;
 }
 
 function ircSendData(tags, from, cmd, args){
@@ -147,6 +168,7 @@ function ircDataReceived(data){
 
 function makeTagsString(tags){
 	return '';
+	//TODO
 }
 
 function ircMessage(data){
@@ -155,6 +177,7 @@ function ircMessage(data){
 }
 
 function ircConnectionClosed(e){
+	events.doEvent('uplinkLost', me);
 	console.log('Closed: '+e);
 	process.exit(1);
 }
@@ -172,6 +195,7 @@ function quitUser(user){
 	for(var i=0; i<users.length; i++){
 		if(users[i] == user){
 			users.splice(i, 1);
+			events.doEvent('userDelete', user);
 			delete user;
 			break;
 		}
@@ -197,6 +221,10 @@ function storeChannelData(channel){
 setInterval(removeEmptyChannels, 1000);
 
 var irc = {
+	'users': users,
+	'channels': channels,
+	'servers': servers,
+	'getChannel': getChannel,
 	'setConnection': function(host, port, protocol){
 		uplink = require('./protocol/' + protocol);
 		me = new IRCserver;
@@ -223,11 +251,23 @@ var irc = {
 			me: me,
 			maxUsers: 0
 		});
+		addInternalEvents();
+		uplink.setEvents(events);
 		connection = new net.Socket();
 		connection.connect(port, host, uplink.connected.bind(this));
 		connection.on('data', ircDataReceived);
 		connection.on('close', ircConnectionClosed);
 	},
+	'setEvents': function(newEvents){
+		events = newEvents;
+	},
+	'makeUser': function(nick, ident, host, realname){
+		var user = new IRCuser;
+		var uid = uplink.makeUid();
+		user.introduce(nick, 0, Math.floor(new Date() / 1000).toString(10), ident, host, uid, null, '+SoB'/*TODO*/, null, null, null, realname, me);
+		users.push(user);
+		return user;
+	},
 	'messagedata': function() {
 		this.text = '';
 		this.args = [];

+ 184 - 1
protocol/unrealircd.js

@@ -37,8 +37,126 @@ var protocol = {
 	},
 	setSettings: function(newSettings){
 		settings = newSettings;
+	},
+	setEvents: function(newEvents){
+		events = newEvents;
+	},
+	// IRC actions
+	introduceUser: function(user){
+		var nick = user.name;
+		var distance = user.distance.toString();
+		var TS = user.TS.toString();
+		var ident = user.ident;
+		var host = user.host;
+		var uid = user.uid;
+		var account = '0';
+		if(user.account){
+			account = user.account;
+		}
+		var umodes = '+oSB'; // TODO
+		var vhost = '*';
+		if(user.vhost){
+			vhost = user.vhost;
+		}
+		var cloakedHost = '*';
+		if(user.cloakedHost){
+			cloakedHost = user.cloakedHost;
+		}
+		var ip = '*';
+		if(user.ip){
+			ip = user.ip;
+		}
+		var realname = user.realname;
+		var args = [nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname];
+		console.log(args);
+		ircSend(null, settings.ID, 'UID', args);
+	},
+	syncChannel: function(channel){
+		var modes = null;
+		var modeArgs = null;
+		// prepare list modes
+		var listModes = [];
+		for(m in channel.listModes){
+			var mode = channel.listModes[m];
+			for(var i=0; i<mode.length; i++){
+				switch(m){
+					case 'BAN': listModes.push('&' + mode[i]); break;
+					case 'EXCEPT': listModes.push('"' + mode[i]); break;
+					case 'INVEX': listModes.push('\'' + mode[i]); break;
+				}
+			}
+		}
+		// prepare users
+		var users = [];
+		for(var i=0; i<channel.users.length; i++){
+			var user = channel.users[i];
+			if(user.uplink != settings.me) continue;
+			var status = '';
+			if(user.uid in channel.statusModes){
+				var statusModes = channel.statusModes[user.uid];
+				for(var j=0; j<statusModes.length; j++){
+					var statusMode = statusModes[j];
+					for(c in chmodeMap){
+						if(chmodeMap[c].name == statusMode){
+							for(sm in connection.statusmodes){
+								if(connection.statusmodes[sm] == c){
+									status += sm;
+									break;
+								}
+							}
+							break;
+						}
+					}
+				}
+			}
+			users.push(status + user.uid);
+		}
+		var done = false;
+		var listCount = 0;
+		var userCount = 0;
+		do {
+			var text = '';
+			var count = 0;
+			for(; listCount < listModes.length; listCount++){
+				if(++count > 10) break;
+				if(text.length > 0) text += ' ';
+				text += listModes[listCount];
+			}
+			
+			for(; userCount < users.length; userCount++){
+				if(++count > 10) break;
+				if(text.length > 0) text += ' ';
+				text += users[userCount];
+			}
+			
+			if(text.length == 0){
+				break;
+			}
+			var args = [Math.floor(new Date() / 1000).toString(10), channel.name];
+			if(modes) args.push(modes); else args.push('+');
+			if(modeArgs) args.push(modeArgs);
+			args.push(text);
+			console.log(args);
+			ircSend(null, settings.ID, 'SJOIN', args);
+			
+		} while(true);
+	},
+	'makeUid': function(){
+		return settings.me.sid + randomID();
 	}
 }
+//>>> @time=2020-03-15T12:17:07.355Z;msgid=FhjgUp20YBKQ32TGPM28tS :143 SJOIN 1580651090 #help +nt :0931Y7O8W 093375CFR 123VTY20R
+
+function randomID(){
+	var result = '';
+	var length = 6;
+	var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+	var charactersLength = characters.length;
+	for(var i=0; i<length; i++ ) {
+		result += characters.charAt(Math.floor(Math.random() * charactersLength));
+	}
+	return result;
+}
 
 module.exports = protocol;
 
@@ -65,6 +183,8 @@ var settings = {
 	maxUsers: null
 };
 
+var events = {};
+
 var connection = {
 	'protoctl': {},
 	'prefixes': {},
@@ -281,10 +401,12 @@ var cmdBinds = {
 		var expr = /^([^-]+)-([^-]+)-([^ ]+) (.*)$/;
 		var match = expr.exec(msg.args[2]);
 		if(match){
-			handlers.newServer(msg.args[0], match[3], match[4], msg.args[1], settings.me);
+			settings.me.uplink = handlers.newServer(msg.args[0], match[3], match[4], msg.args[1], settings.me);
 		} else {
 			throw 'Unknown SERVER message';
 		}
+		events.doEvent('netSynced');
+		ircSend(null, settings.ID, 'EOS');
 	},
 	
 	'MD': function(msg){
@@ -546,6 +668,67 @@ messagedata {
 		var server = handlers.findServer(msg.args[0]);
 		if(!server) return;
 		handlers.removeServer(server);
+	},
+/*messagedata {
+  text: 'TestServ',
+  args: [ '11K3R1VLH', 'TestServ' ],
+  tags: [],
+  command: 'WHOIS',
+  sender: {
+    nick: 'k4be',
+    ident: 'testowy',
+    host: 'localhost',
+    server: false,
+    user: user {
+      name: 'k4be',
+      TS: '1583056052',
+      ident: 'testowy',
+      host: 'localhost',
+      account: null,
+      umodes: [Object],
+      vhost: 'staff:netadmin',
+      cloakedHost: 'ukryty-18D8A42D',
+      ip: '0000:0000:0000:0000:0000:0000:0000:0001',
+      realname: 'realname',
+      uid: '143ZQ0B02',
+      distance: '0',
+      uplink: [server],
+      secure: false,
+      certfp: null,
+      vident: null,
+      metadata: {},
+      introduce: [Function],
+      setSecure: [Function],
+      setFingerprint: [Function],
+      changeVHost: [Function],
+      changeVIdent: [Function],
+      setRealname: [Function],
+      changeNick: [Function],
+      changeUmodes: [Function],
+      setMetadata: [Function]
+    }
+  },
+  time: 2020-03-16T14:02:45.252Z,
+  reply: [Function],
+  originalString: ':143ZQ0B02 WHOIS 11K3R1VLH :TestServ'
+}*/
+	'WHOIS': function(msg){
+	},
+
+	'PRIVMSG': function(msg){
+		if(msg.args[0].charAt(0) == '#'){
+			events.doEvent('channelMessage', msg);
+		} else {
+			events.doEvent('botMessage', msg);
+		}
+	},
+	
+	'NOTICE': function(msg){
+		if(msg.args[0].charAt(0) == '#'){
+			events.doEvent('channelNotice', msg);
+		} else {
+			events.doEvent('botNotice', msg);
+		}
 	}
 };
 

+ 28 - 0
services.js

@@ -1,3 +1,31 @@
 var irc = require('./irc');
 
+var events = {
+	'netSynced': [],
+	'botMessage': [],
+	'channelMessage': [],
+	'channelNotice': [],
+	'botNotice': [],
+	'serverDelete': [],
+	'channelCreate': [],
+	'userCreate': [],
+	'serverCreate': [],
+	'uplinkLost': [],
+	'userDelete': [],
+	'doEvent': function(event, args){
+		if(event in events){
+			for(var i=0; i<events[event].length; i++){
+				args = events[event][i](args);
+			}
+		} else {
+			console.log('Called unknown event '+event);
+		}
+		return args;
+	}
+};
+
+irc.setEvents(events);
 irc.setConnection('localhost', 6667, 'unrealircd');
+var myUser = irc.makeUser('TestServ', 'pirc', 'serwisy.pirc.pl', 'Użytkownik testowy');
+var myChannel = irc.getChannel('#test');
+myChannel.joinUser(myUser);