UNPKG

10.3 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3const execSync = require('child_process').execSync;
4const args = require('minimist')(process.argv.slice(2));
5const chokidar = require('chokidar');
6const WebSocket = require('ws');
7const bytes = require('bytes');
8const queue = require('async/queue');
9const RawIPC = require('node-ipc').IPC;
10const ipc = new RawIPC();
11const pingClient = new RawIPC();
12const WebSocketServer = WebSocket.Server;
13const library = require("./src/library");
14const CONSTANTS = require("./constants");
15
16const BRACKET_END = CONSTANTS.BRACKET_END;
17const SERVER_PORT = CONSTANTS.SERVER_PORT;
18const APP_NAME = CONSTANTS.SERVER_APP_NAME;
19
20var watcherEnabled = true;
21var latestWriteData = "";
22
23pingClient.config.id = 'sfLibraryManagerPingClient';
24pingClient.config.encoding = "utf8";
25
26pingClient.config.logger = function () { };
27
28ipc.config.id = APP_NAME;
29ipc.config.retry = 5000;
30ipc.config.encoding = "utf8";
31ipc.config.maxConnections = 15;
32ipc.config.logger = function (a) { args.verbose && console.log(a) };
33let sockets = [];
34let wses = [];
35let subscribersForRead = [];
36let watcher = null;
37let _libraryFolder = CONSTANTS.LIBRARY_DIRECTORY;
38
39process.on("uncaughtException", logError);
40process.on('unhandledRejection', logError);
41
42if (args.restart) {
43 try {
44 execSync(`fuser -k ${SERVER_PORT}`);
45 }
46 catch (ex) {
47 // do nothing; process is not running; everything is OK
48 }
49}
50
51function logError(reason) {
52 console.error("├─── ! ☠️ ! ──────── LibraryManager ───── Unhandled Error ─────────────────────────┤\n" +
53 reason.stack ? reason.stack.toString("utf8") : reason.toString("utf8"));
54}
55
56function initLibraryTask(data, cb) {
57 library.createLibDirFile(_libraryFolder, data.initialLibraryData, e => {
58 e && console.error(e);
59 cb && cb(e);
60 watch(_libraryFolder);
61 });
62}
63
64function watch(libraryFolder) {
65 watcher && watcher.close();
66 watcher = chokidar.watch(`${libraryFolder}/*.!(pgx)cpx`, {
67 ignoreInitial: true
68 });
69 var readCounter = 0;
70 watcher.on("all", (e, filename) => {
71 if (!watcherEnabled)
72 return;
73 ++readCounter;
74 setTimeout(() => {
75 --readCounter;
76 if (readCounter !== 0)
77 return;
78 console.log("Watcher ..> ", e, " . ", filename);
79 readTask((e, res) => {
80 notifyBrowsers("Watcher -> ReadDone: ", e, res);
81 notifySubscribers("Watcher -> ReadDone notify subscriber : ", e, res);
82 });
83 }, 800);
84 });
85}
86
87function readTask(cb) {
88 cb = typeof cb === "function" ? cb : function () { };
89 library.read(_libraryFolder, function (err, comps) {
90 if (err) {
91 console.error(err);
92 cb(err);
93 }
94 else {
95 return cb(null, JSON.stringify(comps));
96 }
97 });
98}
99
100function writeTask(data, _cb) {
101 const rawData = data.rawData || data;
102 if (latestWriteData === rawData) {
103 console.log("Library already saved!");
104 return _cb(null);
105 }
106 var cb = err => {
107 if (err)
108 return _cb(err);
109 latestWriteData = rawData;
110 _cb();
111 };
112 let componentsWithChildren = data.parsedData;
113 if (!data.parsedData) {
114 try {
115 componentsWithChildren = JSON.parse(data);
116 }
117 catch (e) {
118 console.error(e);
119 return cb(e);
120 }
121 }
122 library.saveComponents(_libraryFolder, componentsWithChildren, err => {
123 if (err) {
124 console.error(err);
125 return cb(err);
126 }
127 notifySubscribersAndwriteUninitializedComp(componentsWithChildren, cb);
128 });
129}
130
131function notifySubscribersAndwriteUninitializedComp(componentsWithChildren, cb) {
132 var unInitializedComps = [];
133 componentsWithChildren.forEach(comps => {
134 if (!comps[0].initialized) {
135 console.log("Uninitialized comp: ", comps[0].props.name);
136 unInitializedComps.push(comps);
137 }
138 });
139 library.getLibraryPageWithChildren(_libraryFolder, componentsWithChildren, (err, comps) => {
140 if (comps) {
141 notifySubscribers("ReceivedNewData -> notify subscribers :", err, JSON.stringify(comps));
142 }
143 if (unInitializedComps.length) {
144 unInitializedComps.forEach(comps => comps[0].initialized = true);
145 notifyBrowsers("Initialized components -> ", err, JSON.stringify(comps));
146 library.saveComponents(_libraryFolder, unInitializedComps, cb, true);
147 }
148 else {
149 cb();
150 }
151 });
152}
153
154function notifySubscribers(title, err, res) {
155 subscribersForRead.forEach(s => {
156 console.log(title, s.name, " ", bytes(res ? res.length : 0, { unitSeparator: ' ' }), " send.");
157 ipc.server.emit(
158 s,
159 err ? 'error' : 'read',
160 err ? err.toString() : res
161 );
162 });
163}
164
165function notifyBrowsers(title, err, res) {
166 sockets.forEach(s => {
167 console.log(title, s.name, " ", bytes(res ? res.length : 0, { unitSeparator: ' ' }), " send.");
168 ipc.server.emit(
169 s,
170 err ? 'error' : 'read',
171 err ? err.toString() : res
172 );
173 });
174 if (!err) {
175 wses.forEach((ws) => {
176 ws.send(res);
177 ws.send(`\r\n${BRACKET_END}`);
178 });
179 }
180}
181
182var writeTaskQueue = queue((data, next) => {
183 watcherEnabled = false;
184 writeTask(data, next);
185}, 1);
186
187writeTaskQueue.drain = () => setTimeout(() => (watcherEnabled = true), 1000);
188
189ipc.serveNet(
190 SERVER_PORT,
191 () => {
192 console.log(`Smartface libraryManager (${SERVER_PORT}) is up and running...`);
193 ipc.server.on(
194 'writeTask',
195 (data, socket) => {
196 console.log("WriteTask: ", bytes(data.length, { unitSeparator: ' ' }));
197 writeTaskQueue.push(data);
198 }
199 );
200
201 ipc.server.on(
202 'readTask',
203 (data, socket) => {
204 console.log("ReadTask ", data.name);
205 _libraryFolder = _libraryFolder || data.libraryFolder;
206 socket.name = data && data.name;
207 readTask((e, res) => {
208 ipc.server.emit(
209 socket,
210 'read',
211 res
212 );
213 });
214 }
215 );
216 ipc.server.on(
217 'subscribeForRead',
218 (data, socket) => {
219 console.log("SubscribeForRead: ", data.name);
220 _libraryFolder = _libraryFolder || data.libraryFolder;
221 socket.name = data && data.name;
222 subscribersForRead.push(socket);
223 readTask((e, res) => {
224 ipc.server.emit(
225 socket,
226 'read',
227 res
228 );
229 });
230 }
231 );
232
233 ipc.server.on(
234 'init',
235 (data, socket) => {
236 console.log("Init ", data.name);
237 socket.name = data && data.name;
238 _libraryFolder = data.libraryFolder;
239 sockets.push(socket);
240 initLibraryTask(data, e => {
241 readTask((e, res) => {
242 console.log("ReadDone: ", socket.name, " ", bytes(res ? res.length : 0, { unitSeparator: ' ' }));
243 ipc.server.emit(
244 socket,
245 'read',
246 res
247 );
248 });
249 });
250 }
251 );
252
253 ipc.server.on(
254 "ping",
255 (data, socket) => {
256 ipc.server.emit(socket, 'ping', "OK");
257 });
258
259 ipc.server.on(
260 'socket.disconnected',
261 (socket) => {
262 sockets = sockets.filter(s => s !== socket);
263 subscribersForRead = subscribersForRead.filter(s => s !== socket);
264 socket.name && console.log('DISCONNECTED ', socket.name);
265 }
266 );
267 }
268);
269
270ipc.server.on(
271 'error',
272 (err) => {
273 console.log('Got an ERROR!', err);
274 }
275);
276ipc.server.start();
277
278
279function handleWsTask(parsedData, ws) {
280 if (parsedData.task === 'init') {
281 initLibraryTask(parsedData, () => {
282 readTask((e, res) => {
283 ws.send(res);
284 ws.send(`\r\n${BRACKET_END}`);
285 });
286 })
287 }
288}
289
290const wsServer = new WebSocketServer({ port: CONSTANTS.SERVER_WS_PORT });
291console.log(`Smartface libraryManager (${CONSTANTS.SERVER_WS_PORT}) ws server is up and running...`);
292
293wsServer.on('connection', (ws) => {
294
295 wses.push(ws);
296 let msgData = '';
297 ws.on('message', (msg) => {
298 msgData += msg;
299 console.log("RECEIVED:> ", msg);
300 if (msgData.endsWith(BRACKET_END)) {
301 const splitted = msgData.split(BRACKET_END);
302 const rawData = splitted[splitted.length - 2];
303 const parsedData = JSON.parse(rawData);
304 if (parsedData.task) {
305 handleWsTask(parsedData, ws);
306 } else {
307 writeTaskQueue.push({ rawData, parsedData });
308 }
309 msgData = '';
310 }
311 });
312
313 ws.on('close', () => {
314 wses = wses.filter(w => w !== ws);
315 console.info('ws on Close');
316 });
317
318});
319
320var counter = 0;
321var aliveCounter = 0;
322setInterval(_ => {
323 pingClient.connectToNet(
324 APP_NAME,
325 CONSTANTS.SERVER_PORT,
326 function () {
327 pingClient.of.sfLibraryManager.on(
328 'connect',
329 _ => {
330 ((++aliveCounter) % 15 == 0)
331 counter = 0;
332 pingClient.disconnect(APP_NAME);
333 }
334 );
335 pingClient.of.sfLibraryManager.on(
336 'error',
337 (data) => {
338 if (++counter < 3)
339 return;
340 process.stderr.write(data.toString());
341 process.exit(1);
342 }
343 );
344 }
345 );
346}, 5000);