UNPKG

8.81 kBJavaScriptView Raw
1"use strict";
2
3var net = require('net');
4var sys = require('sys');
5var path = require('path');
6var util = require('util');
7var events = require('events');
8var lineInputStream = require('line-input-stream');
9
10var sock = new net.Socket();
11var commandQueue = [];
12var status = -2;
13var current = false;
14var timeout = 0;
15
16function Alfred() {
17 var self = this;
18 events.EventEmitter.call(this);
19 global.bot_reference = this;
20 global.bot_proto_reference = Alfred;
21
22 self.config = {
23 'name': 'Alfred',
24 'host': '127.0.0.1',
25 'port': 10011,
26 'login-name': 'serveradmin',
27 'login-pass': 'password',
28 'virtual-server': 1,
29 'command-identifier': '.',
30 'admin-file': __dirname + '/core_extensions/admin/admins.json'
31 };
32 self.extensions = [];
33 self.self = -1;
34 self.connected = false;
35
36 core_include('query');
37 core_include('admin');
38 core_include('cmdmanager');
39 core_include('user');
40
41 function checkQueue() {
42 if(!current && commandQueue.length > 0) {
43 current = commandQueue.shift();
44 current.sent = current.cmd + " " + current.params.join(' ');
45 sock.write(current["cmd"] + " " + current["params"].join(' ') + '\r\n');
46 }
47 }
48
49 function timeStamp() {
50 var currentTime = new Date();
51 var hours = currentTime.getHours();
52 var minutes = currentTime.getMinutes();
53 var seconds = currentTime.getSeconds();
54 if(hours < 10) hours = "0" + hours;
55 if(minutes < 10) minutes = "0" + minutes;
56 if(seconds < 10) seconds = "0" + seconds;
57 return "[" + hours + ":" + minutes + ":" + seconds + "]";
58 }
59
60 function core_include(extension) {
61 return require(__dirname + '/core_extensions/' + extension + '/' + extension + '.js');
62 }
63
64 function connect() {
65 sock.connect(self.config.port, self.config.host, function() {
66 self.log('[*] Connected to ' + self.config.host + ':' + self.config.port + ' as ' + self.config.name);
67 self.load();
68 timeout = 0;
69
70 var input = lineInputStream(sock);
71 input.removeAllListeners('line');
72
73 input.on('line', function(recv) {
74 recv = recv.trim();
75 if(status < 0) {
76 status++;
77 if(status === 0) checkQueue();
78 return;
79 }
80
81 var _recv = recv.toString().split(' ');
82 var _data = {};
83
84 for(var i=0; i<_recv.length; i++) {
85 var argument = _recv[i].split(/=(.+)?/);
86 _data[argument[0]] = self.decode(argument[1]);
87 }
88
89 if(_recv[0] == "error") {
90 var _error = _data["id"];
91 delete _data["error"] ;
92 delete _data["id"];
93 if(typeof current.data == 'undefined') current.data = _data;
94 if(current["callback"]) current["callback"].call(current, parseInt(_error), current.data, current.raw_data);
95 current = false;
96 checkQueue();
97 }
98 else if(_recv[0].substr(0, 6) == "notify") {
99 delete _data[_recv[0]];
100 self.emit(_recv[0].slice(6, _recv[0].length), _data);
101 }
102 else if(current) {
103 current.data = _data;
104 current.raw_data = recv.toString();
105 }
106 });
107 });
108 }
109
110 Alfred.prototype.configure = function (settings) {
111 for(var setting in settings) {
112 //if(!self.config.hasOwnProperty(setting)) continue;
113 self.config[setting] = settings[setting];
114 }
115 return this;
116 }
117
118 Alfred.prototype.start = function () {
119 sock = new net.Socket();
120 status = -2;
121 self.connected = false;
122
123 sock.on('error', function(err) {
124 timeout++;
125 if(timeout >= 10) {
126 console.error(timeStamp() + '[*] Connection failed too often... Exiting');
127 self.emit('error', err);
128 process.exit();
129 }
130 console.error(timeStamp() + '[*] Connection to', self.config.host + ':' + self.config.port + ' failed... Retrying [' + timeout + ']');
131
132 setTimeout(function() {
133 self.start();
134 }, 3000);
135 });
136
137 sock.on('end', function() {
138 console.error(timeStamp() + '[*] Connection was closed, maybe the server was shut down... Reconnecting');
139 self.start();
140 });
141
142 connect();
143 }
144
145 Alfred.prototype.load = function() {
146 self.sendCommand('login', [self.config["login-name"], self.config["login-pass"]], function(err, data) {
147 if(err != 0) {
148 data["login-name"] = self.config["login-name"];
149 data["login-pass"] = self.config["login-pass"];
150 self.throwErr(err, data);
151 } else {
152 data["login-name"] = self.config["login-name"];
153 data["login-pass"] = self.config["login-pass"];
154 self.emit('login');
155 self.connected = true;
156 }
157 });
158 self.sendCommand('use', {'sid': self.config["virtual-server"]});
159 self.sendCommand('clientupdate', {'client_nickname': self.config["name"]});
160 self.sendCommand('whoami', null, function(err, data) {
161 self.self = data["client_id"];
162 });
163 self.emit('load');
164
165 setInterval(function() {
166 self.sendCommand('heartbeat');
167 self.emit('heartbeat');
168 }, 300000);
169 }
170
171 Alfred.prototype.include = function(extension) {
172 var extension_path = path.resolve(extension);
173 extension = extension.split('/');
174 self.extensions.push(require(extension_path + '/extension.json'));
175 return require(extension_path + '/' + extension[extension.length - 1] + '.js');
176 }
177
178 Alfred.prototype.encode = function(string) {
179 var ret = String(string);
180 ret = ret.replace(/\\/g, '\\\\');
181 ret = ret.replace(/\//g, '\\/');
182 ret = ret.replace(/\|/g, '\\p');
183 ret = ret.replace(/\n/g, '\\n');
184 ret = ret.replace(/\r/g, '\\r');
185 ret = ret.replace(/\t/g, '\\t');
186 ret = ret.replace(/\v/g, '\\v');
187 ret = ret.replace(/\f/g, '\\f');
188 ret = ret.replace(/ /g, '\\s');
189 return ret;
190 }
191
192 Alfred.prototype.decode = function(string) {
193 var ret = String(string);
194 ret = ret.replace(/\\\\/g, '\\');
195 ret = ret.replace(/\\\//g, "\/");
196 ret = ret.replace(/\\p/g, '|');
197 ret = ret.replace(/\\n/g, '\n');
198 ret = ret.replace(/\\r/g, '\r');
199 ret = ret.replace(/\\t/g, '\t');
200 ret = ret.replace(/\\v/g, '\v');
201 ret = ret.replace(/\\f/g, '\f');
202 ret = ret.replace(/\\s/g, ' ');
203 return ret;
204 }
205
206 Alfred.prototype.sendCommand = function(command, parameters, callbackFunction) {
207 var _parameters = [];
208
209 if(typeof parameters == 'undefined' || parameters == null) {
210 _parameters = [];
211 } else if(Array.isArray(parameters)) {
212 for(var i=0; i<parameters.length; i++) _parameters.push(self.encode(parameters[i]));
213 } else if(typeof parameters == 'object') {
214 for(var param in parameters) _parameters.push(self.encode(param) + '=' + self.encode(parameters[param]));
215 } else {
216 _parameters.push(self.encode(String(parameters)));
217 }
218
219 if(typeof callbackFunction != 'function') callbackFunction = function(err, data) {};
220 commandQueue.push({'cmd': command, 'params': _parameters, 'callback': callbackFunction});
221 if(status === 0) checkQueue();
222 return command + ' ' + _parameters.join(' ');
223 }
224
225 Alfred.prototype.registerEvent = function(event, params) {
226 if(typeof params == 'undefined') params = {};
227 params.event = event;
228 self.sendCommand('servernotifyregister', params);
229 }
230
231 Alfred.prototype.log = function(text) {
232 console.log(timeStamp() + text);
233 return this;
234 }
235
236 Alfred.prototype.throwErr = function(err, err_data) {
237 err_data["err_code"] = parseInt(err);
238 var error = new Error(util.inspect(err_data));
239 if(self.listeners('error').length === 0) throw error;
240 console.error('An error occured:\n', err_data);
241 self.emit('error', err_data);
242 }
243}
244
245util.inherits(Alfred, events.EventEmitter);
246module.exports = new Alfred();