1 | "use strict";
|
2 |
|
3 | var net = require('net');
|
4 | var sys = require('sys');
|
5 | var path = require('path');
|
6 | var util = require('util');
|
7 | var events = require('events');
|
8 | var lineInputStream = require('line-input-stream');
|
9 |
|
10 | var sock = new net.Socket();
|
11 | var commandQueue = [];
|
12 | var status = -2;
|
13 | var current = false;
|
14 | var timeout = 0;
|
15 |
|
16 | function 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 |
|
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 |
|
245 | util.inherits(Alfred, events.EventEmitter);
|
246 | module.exports = new Alfred();
|