Commit | Line | Data |
---|---|---|
d8002ae0 D |
1 | /**\r |
2 | * Server control via TCP socket\r | |
3 | *\r | |
4 | * Listens on localhost:8888 by default\r | |
5 | */\r | |
6 | \r | |
7 | var net = require('net'),\r | |
8 | kiwiModules = require('../server/modules'),\r | |
9 | rehash = require('../server/rehash.js'),\r | |
10 | config = require('../server/configuration.js'),\r | |
11 | _ = require('lodash');\r | |
12 | \r | |
ab3043ad | 13 | var control_module = new kiwiModules.Module('Control');\r |
d8002ae0 D |
14 | \r |
15 | \r | |
5a18896d D |
16 | /**\r |
17 | * The socket client\r | |
18 | */\r | |
d8002ae0 D |
19 | function SocketClient (socket) {\r |
20 | this.socket = socket;\r | |
ab3043ad | 21 | this.socket_closing = false;\r |
d8002ae0 D |
22 | \r |
23 | this.remoteAddress = this.socket.remoteAddress;\r | |
24 | console.log('Control connection from ' + this.socket.remoteAddress + ' opened');\r | |
25 | \r | |
26 | this.bindEvents();\r | |
27 | \r | |
28 | socket.write("\nHello, you are connected to the Kiwi server :)\n\n");\r | |
29 | this.displayPrompt();\r | |
30 | }\r | |
31 | \r | |
32 | SocketClient.prototype.bindEvents = function() {\r | |
33 | var that = this;\r | |
34 | \r | |
35 | this.socket.on('data', function() { that.onData.apply(that, arguments); });\r | |
36 | this.socket.on('close', function() { that.onClose.apply(that, arguments); });\r | |
37 | };\r | |
38 | SocketClient.prototype.unbindEvents = function() {\r | |
39 | this.socket.removeAllListeners();\r | |
40 | };\r | |
41 | \r | |
42 | \r | |
43 | \r | |
44 | SocketClient.prototype.write = function(data, append) {\r | |
45 | if (typeof append === 'undefined') append = '\n';\r | |
ab3043ad D |
46 | if (this.socket && !this.socket_closing)\r |
47 | this.socket.write(data + append);\r | |
d8002ae0 D |
48 | };\r |
49 | SocketClient.prototype.displayPrompt = function(prompt) {\r | |
50 | prompt = prompt || 'Kiwi > ';\r | |
51 | this.write(prompt, '');\r | |
52 | };\r | |
53 | \r | |
54 | \r | |
55 | \r | |
56 | SocketClient.prototype.onData = function(data) {\r | |
57 | data = data.toString().trim();\r | |
58 | \r | |
d8002ae0 | 59 | \r |
d8002ae0 | 60 | \r |
5a18896d D |
61 | try {\r |
62 | var data_split = data.split(' ');\r | |
d8002ae0 | 63 | \r |
5a18896d D |
64 | if (typeof socket_commands[data_split[0]] === 'function') {\r |
65 | socket_commands[data_split[0]].call(this, data_split.slice(1));\r | |
66 | } else {\r | |
67 | this.write('Unrecognised command: ' + data);\r | |
d8002ae0 | 68 | }\r |
5a18896d | 69 | \r |
d8002ae0 D |
70 | } catch (err) {\r |
71 | console.log('[Control error] ' + err);\r | |
72 | this.write('An error occured. Check the Kiwi server log for more details');\r | |
73 | }\r | |
74 | \r | |
75 | this.displayPrompt();\r | |
76 | };\r | |
77 | \r | |
78 | \r | |
79 | SocketClient.prototype.onClose = function() {\r | |
80 | this.unbindEvents();\r | |
ab3043ad | 81 | this.socket = null;\r |
d8002ae0 D |
82 | console.log('Control connection from ' + this.remoteAddress + ' closed');\r |
83 | };\r | |
84 | \r | |
85 | \r | |
86 | \r | |
5a18896d D |
87 | /**\r |
88 | * Available commands\r | |
89 | * Each function is run in context of the SocketClient\r | |
90 | */\r | |
91 | var socket_commands = {\r | |
92 | module: function(data) {\r | |
93 | switch(data[0]) {\r | |
94 | case 'reload':\r | |
95 | if (!data[1]) {\r | |
96 | this.write('A module name must be specified');\r | |
97 | return;\r | |
98 | }\r | |
99 | \r | |
100 | if (!kiwiModules.unload(data[1])) {\r | |
ab3043ad | 101 | this.write('Module ' + (data[1] || '') + ' is not loaded');\r |
5a18896d D |
102 | return;\r |
103 | }\r | |
104 | \r | |
ab3043ad D |
105 | if (!kiwiModules.load(data[1])) {\r |
106 | this.write('Error loading module ' + (data[1] || ''));\r | |
107 | }\r | |
5a18896d D |
108 | this.write('Module ' + data[1] + ' reloaded');\r |
109 | \r | |
110 | break;\r | |
111 | \r | |
112 | case 'list':\r | |
113 | case 'ls':\r | |
114 | default:\r | |
ab3043ad D |
115 | var module_names = [];\r |
116 | kiwiModules.getRegisteredModules().forEach(function(module) {\r | |
117 | module_names.push(module.module_name);\r | |
118 | });\r | |
119 | this.write('Loaded modules: ' + module_names.join(', '));\r | |
5a18896d D |
120 | }\r |
121 | \r | |
122 | },\r | |
123 | \r | |
124 | stats: function(data) {\r | |
125 | this.write('Connected clients: ' + _.size(global.clients.clients).toString());\r | |
126 | this.write('Num. remote hosts: ' + _.size(global.clients.addresses).toString());\r | |
127 | },\r | |
d8002ae0 | 128 | \r |
5a18896d D |
129 | rehash: function(data) {\r |
130 | rehash.rehashAll();\r | |
131 | this.write('Rehashed');\r | |
132 | },\r | |
133 | \r | |
134 | reconfig: function(data) {\r | |
135 | if (config.loadConfig()) {\r | |
136 | this.write('New config file loaded');\r | |
137 | } else {\r | |
138 | this.write("No new config file was loaded");\r | |
139 | }\r | |
140 | },\r | |
141 | \r | |
142 | quit: function(data) {\r | |
143 | this.socket.destroy();\r | |
ab3043ad | 144 | this.socket_closing = true;\r |
5a18896d D |
145 | },\r |
146 | exit: function(data) {\r | |
147 | this.socket.destroy();\r | |
ab3043ad | 148 | this.socket_closing = true;\r |
5a18896d D |
149 | }\r |
150 | };\r | |
151 | \r | |
152 | \r | |
153 | /**\r | |
154 | * Start the control socket server to serve connections\r | |
155 | */\r | |
d8002ae0 D |
156 | var server = net.createServer(function (socket) {\r |
157 | new SocketClient(socket);\r | |
158 | });\r | |
5a18896d | 159 | server.listen(8888);\r |
ab3043ad D |
160 | \r |
161 | control_module.on('dispose', function() {\r | |
162 | server.close();\r | |
163 | });\r |