Commit bfffdf9d authored by Stavros Sachtouris's avatar Stavros Sachtouris Committed by Giorgos Korfiatis

Implement Agkyra GUI and helper

parent f6991720
*.pyc
*.egg-info
*.*.swp
_build
build
dist
from wsgiref.simple_server import make_server
# from ws4py.websocket import EchoWebSocket
from protocol import WebSocketProtocol
from ws4py.server.wsgirefserver import WSGIServer, WebSocketWSGIRequestHandler
from ws4py.server.wsgiutils import WebSocketWSGIApplication
from tempfile import NamedTemporaryFile
import subprocess
import json
from os.path import abspath
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
self.gui_exec_path = gui_exec_path
self.token = token
def handshake_ok(self):
with NamedTemporaryFile(mode='a+') as fp:
json.dump(dict(token=self.token, port=self.port), fp)
fp.flush()
subprocess.call([
'/home/saxtouri/node-webkit-v0.11.6-linux-x64/nw',
abspath('gui/gui.nw'),
fp.name])
class Helper(object):
"""Coordination between the GUI and the Syncer instances
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 __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(self):
gui = GUILauncher(self.port, self.gui_exec_path, self.token)
gui.connect()
self.server.serve_forever()
Helper('ls').run()
{
"port": 1234,
"token": "s0m3-70k3n"
}
\ No newline at end of file
<html>
<head><title>Agkyra Syncing Client for Pithos+</title></head>
<body style="-webkit-app-region: drag; text-align: center">
<div>
<img src="icons/logo.png" style="width: 64px; height: 64px;" />
<h1>Agkyra</h1>
<h2>... it syncs</h2>
<p>&nbsp;</p>
<p><b>Agkyra</b> is a minimal syncing client for Pithos+ containers.</p>
</div>
</body>
</html>
This diff is collapsed.
<!DOCTYPE html>
<html>
<head><title>GUI for Agkyra Pithos+ Syncing Client</title></head>
<body><script src="protocol.js"> </script></body>
</html>
\ No newline at end of file
There must be some logs
{
"name": "Agkyra",
"main": "index.html",
"description": "A Pithos+ Syncing Client for Desktop",
"version": 0.0,
"window": {
"show": false,
"toolbar": false,
"frame": false
},
"maintainers": [{
"name": "Synnefo Development Team",
"web": "http://www.synnefo.org"
}],
"licences": [{"type": "GPLv3"}]
}
var gui = require('nw.gui');
// Read config file
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();
}
// 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'
});
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('.');}
}));
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');}
}));
// 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});
}
}));
// 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
<html>
<head>
<title>Agira client settings</title>
<style>
@import url('foundation.min.css');
</style>
</head>
<body>
<form>
<h1>Account settings</h1>
<h2>Cloud:</h2>
<div class="row">
<div class="large-12 columns">
<label>Cloud URL
<input type="text" placeholder="Authentication URL"/>
</label>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<label>Token
<input type="text" placeholder="User token"/>
</label>
</div>
</div>
<h2>What to sync:</h2>
<div class="row">
<div class="large-4 columns">
<label>Remote container
<input type="text" value="pithos"/>
</label>
</div>
<div class="large-4 columns">
<label>Local directory
<input type="file" nwdirectory />
</label>
</div>
<script>var gui=require('nw.gui');</script>
<div class="large-4 columns">
<label>Exclude these items from syncing
<input
type="button"
onclick="gui.Shell.openItem('logs.txt');"/>
</label>
</div>
</div>
</form>
</body>
</html>
\ No newline at end of file
<html><head>
<script>
// Read config file
var socket = new WebSocket("ws://83.212.96.33:8888");
socket.onopen = function() {
console.log('open dude!');
this.send('Hello World!');
};
socket.onmessage = function(e) {
console.log('message', e.data);
};
socket.onerror = function() {
console.log('error');
};
socket.onclose = function(e) {
console.log('close', e.code, e.reason);
};
</script>
</head><body></body></html>
\ No newline at end of file
from ws4py.websocket import WebSocket
class WebSocketProtocol(WebSocket):
"""Helper-side WebSocket protocol for communication with GUI:
-- INTERRNAL HANDSAKE --
GUI: {"token": <token>}
HELPER: {"ACCEPTED": 202}" or "{"ERROR": 401, "MESSAGE": <message>}
-- GET SETTINGS --
GUI: {"method": "get", "path": "settings"}
HELPER:
{
"token": <user token>,
"url": <auth url>,
"container": <container>,
"directory": <local directory>,
"exclude": <file path>
} or {"ERROR": <error code>, "MESSAGE": <message>}"
-- PUT SETTINGS --
GUI: {
"method": "put", "path": "settings",
"token": <user token>,
"url": <auth url>,
"container": <container>,
"directory": <local directory>,
"exclude": <file path>
}
HELPER: {"CREATED": 201} or {"ERROR": <error code>, "MESSAGE": <message>}
-- GET STATUS --
GUI: {"method": "get", "path": "status"}
HELPER: ""progres": <int>, "paused": <boolean>} or
{"ERROR": <error code>, "MESSAGE": <message>}
"""
def __init__(self, *args, **kwargs):
super(WebSocketProtocol, self).__init__(*args, **kwargs)
print 'lala'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment