diff --git a/agkyra/__init__.py b/agkyra/__init__.py index bcbf9d2c9c65486c62b7c93428b130fabb78cb6d..29e2b7ef88d0d36658d654a2ff2d0b85d1fa8b51 100644 --- a/agkyra/__init__.py +++ b/agkyra/__init__.py @@ -7,6 +7,9 @@ from tempfile import NamedTemporaryFile import subprocess import json from os.path import abspath +from threading import Thread +from hashlib import sha256 +from os import urandom from ws4py.client import WebSocketBaseClient @@ -14,51 +17,58 @@ from ws4py.client import WebSocketBaseClient class GUILauncher(WebSocketBaseClient): """Launch the GUI when the helper server is ready""" - def __init__(self, port, gui_exec_path, token): - super(GUILauncher, self).__init__('ws://localhost:%s' % port) - self.port = port + def __init__(self, addr, gui_exec_path, token): + """Initialize the GUI Launcher""" + super(GUILauncher, self).__init__(addr) + self.addr = addr self.gui_exec_path = gui_exec_path self.token = token def handshake_ok(self): + """If handshake is OK, the helper is UP, so the GUI can be launched + If the GUI is terminated for some reason, the WebSocket is closed""" with NamedTemporaryFile(mode='a+') as fp: - json.dump(dict(token=self.token, port=self.port), fp) + json.dump(dict(token=self.token, address=self.addr), fp) fp.flush() + # subprocess.call blocks the execution subprocess.call([ '/home/saxtouri/node-webkit-v0.11.6-linux-x64/nw', abspath('gui/gui.nw'), fp.name]) + self.close() -class Helper(object): - """Coordination between the GUI and the Syncer instances +def setup_server(token, port=0): + """Setup and return the helper server""" + WebSocketProtocol.token = token + server = make_server( + '', port, + server_class=WSGIServer, + handler_class=WebSocketWSGIRequestHandler, + app=WebSocketWSGIApplication(handler_cls=WebSocketProtocol)) + server.initialize_websockets_manager() + # self.port = server.server_port + return server - Setup a minimal server at a ephemeral port, create a random token, dump - this information in a local file and launch the GUI with this file as a - parameter. - Then the GUI connects and a WebSocket is established. - """ +def random_token(): + return 'random token' - def __init__(self, gui_exec_path, port=0): - self.server = self.setup_server(port) - self.port = self.server.server_port - self.token = 'some random token' - self.gui_exec_path = gui_exec_path - def setup_server(self, port=0): - server = make_server( - '', port, - server_class=WSGIServer, - handler_class=WebSocketWSGIRequestHandler, - app=WebSocketWSGIApplication(handler_cls=WebSocketProtocol)) - server.initialize_websockets_manager() - # self.port = server.server_port - return server +def run(gui_exec_path): + """Prepare helper and GUI and run them in the proper order""" + token = sha256(urandom(256)).hexdigest() + server = setup_server(token) + addr = 'ws://localhost:%s' % server.server_port + + gui = GUILauncher(addr, gui_exec_path, token) + Thread(target=gui.connect).start() - def run(self): - gui = GUILauncher(self.port, self.gui_exec_path, self.token) - gui.connect() - self.server.serve_forever() + try: + server.serve_forever() + except KeyboardInterrupt: + print 'Shutdown GUI' + gui.close() -Helper('ls').run() +if __name__ == '__main__': + run('/home/saxtouri/node-webkit-v0.11.6-linux-x64/nw gui.nw') diff --git a/agkyra/gui/protocol.js b/agkyra/gui/protocol.js index 897245957f4ecf6fba8e582652e43aaea7ec5508..c6a56a361dfa05ef9e4dae4c27fe30efbc88d9d8 100644 --- a/agkyra/gui/protocol.js +++ b/agkyra/gui/protocol.js @@ -4,95 +4,93 @@ var gui = require('nw.gui'); var fs = require('fs'); var cnf = JSON.parse(fs.readFileSync(gui.App.argv[0], encoding='utf-8')); -setTimeout(function() { - // Connect to helper - var socket = new WebSocket('ws://localhost:' + cnf['port']); - socket.onopen = function() { - console.log('Connecting to helper'); - this.send(cnf['token']); - } - socket.onmessage = function(e) { - console.log('message', e.data); - }; - socket.onerror = function () { - console.log('GUI and helper cannot communicate, quiting'); - gui.Window.get().close(); - } +// Connect to helper +var socket = new WebSocket(cnf['address']); +socket.onopen = function() { + console.log('Connecting to helper'); + this.send(cnf['token']); +} +socket.onmessage = function(e) { + console.log('message', e.data); +}; +socket.onerror = function () { + console.log('GUI and helper cannot communicate, quiting'); + gui.Window.get().close(); +} - // Setup GUI - var windows = { - "settings": null, - "about": null, - "index": gui.Window.get() - } - function closeWindows() { - for (win in windows) if (windows[win]) windows[win].close(); - } +// Setup GUI +var windows = { + "settings": null, + "about": null, + "index": gui.Window.get() +} +function closeWindows() { + for (win in windows) if (windows[win]) windows[win].close(); +} - // GUI components - var tray = new gui.Tray({ - tooltip: 'Paused (0% synced)', - title: 'Agkyra syncs with Pithos+', - icon: 'icons/tray.png' - }); +// GUI components +var tray = new gui.Tray({ + tooltip: 'Paused (0% synced)', + title: 'Agkyra syncs with Pithos+', + icon: 'icons/tray.png' +}); - var menu = new gui.Menu(); +var menu = new gui.Menu(); - // See contents - menu.append(new gui.MenuItem({type: 'separator'})); - menu.append(new gui.MenuItem({ - label: 'Open local folder', - icon: 'icons/folder.png', - click: function () {gui.Shell.showItemInFolder('.');} - })); +// See contents +menu.append(new gui.MenuItem({type: 'separator'})); +menu.append(new gui.MenuItem({ + label: 'Open local folder', + icon: 'icons/folder.png', + click: function () {gui.Shell.showItemInFolder('.');} +})); - menu.append(new gui.MenuItem({ - label: 'Launch Pithos+ page', - icon: 'icons/pithos.png', - click: function () { - gui.Shell.openExternal('https://pithos.okeanos.grnet.gr'); - } - })); +menu.append(new gui.MenuItem({ + label: 'Launch Pithos+ page', + icon: 'icons/pithos.png', + click: function () { + gui.Shell.openExternal('https://pithos.okeanos.grnet.gr'); + } +})); - menu.append(new gui.MenuItem({ - label: 'Recently changed files', - icon: 'icons/logs.png', - click: function () {gui.Shell.openItem('logs.txt');} - })); +menu.append(new gui.MenuItem({ + label: 'Recently changed files', + icon: 'icons/logs.png', + click: function () {gui.Shell.openItem('logs.txt');} +})); - // Settings and About - menu.append(new gui.MenuItem({type: 'separator'})); - menu.append(new gui.MenuItem({ - label: 'Settings', - icon: 'icons/settings.png', - click: function () { - if (windows['settings']) windows['settings'].close(); - windows['settings'] = gui.Window.open("settings.html", { - "toolbar": false, "focus": true}); - } - })); +// Settings and About +menu.append(new gui.MenuItem({type: 'separator'})); +menu.append(new gui.MenuItem({ + label: 'Settings', + icon: 'icons/settings.png', + click: function () { + if (windows['settings']) windows['settings'].close(); + windows['settings'] = gui.Window.open("settings.html", { + "toolbar": false, "focus": true}); + } +})); - menu.append(new gui.MenuItem({ - label: 'About', - icon: 'icons/about.png', - click: function () { - if (windows['about']) windows['about'].close(); - windows['about'] = gui.Window.open("about.html", { - "toolbar": false, "resizable": false, "focus": true}); - } - })); +menu.append(new gui.MenuItem({ + label: 'About', + icon: 'icons/about.png', + click: function () { + if (windows['about']) windows['about'].close(); + windows['about'] = gui.Window.open("about.html", { + "toolbar": false, "resizable": false, "focus": true}); + } +})); - // Quit - menu.append(new gui.MenuItem({type: 'separator'})); - menu.append(new gui.MenuItem({ - label: 'Quit Agkyra', - icon: 'icons/exit.png', - click: function () { - console.log('Exiting client'); - console.log('Exiting GUI'); - closeWindows() - } - })); +// Quit +menu.append(new gui.MenuItem({type: 'separator'})); +menu.append(new gui.MenuItem({ + label: 'Quit Agkyra', + icon: 'icons/exit.png', + click: function () { + console.log('Exiting client'); + console.log('Exiting GUI'); + closeWindows() + } +})); - tray.menu = menu; -}, 100); // Timeout in milliseconds +tray.menu = menu; diff --git a/agkyra/protocol.py b/agkyra/protocol.py index 81e5fe8375edc5041dcc9b4e4e91142c060e9ac3..5454b449f0ed8ee13ff0c92ae071c68260dc3a30 100644 --- a/agkyra/protocol.py +++ b/agkyra/protocol.py @@ -36,6 +36,14 @@ class WebSocketProtocol(WebSocket): {"ERROR": <error code>, "MESSAGE": <message>} """ - def __init__(self, *args, **kwargs): - super(WebSocketProtocol, self).__init__(*args, **kwargs) - print 'lala' + token = None + + def opened(self): + print 'A connection is open', self.token + + def closed(self, *args): + print 'A connection is closed', args + + def received_message(self, message): + print 'Got message', message + self.send(message)