From 7ea712a000dfee7bf17cb59dff242d7234632516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Fri, 4 Mar 2016 15:22:59 -0300 Subject: [PATCH 1/9] A trayicon for osx --- plugins/Trayicon/TrayiconOSXPlugin.py | 55 +++++++++++ plugins/Trayicon/__init__.py | 4 +- plugins/Trayicon/lib/tray_osx.py | 131 ++++++++++++++++++++++++++ src/Config.py | 5 + src/Site/SiteStorage.py | 8 +- src/main.py | 23 ++++- 6 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 plugins/Trayicon/TrayiconOSXPlugin.py create mode 100644 plugins/Trayicon/lib/tray_osx.py diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py new file mode 100644 index 000000000..d26c49ef9 --- /dev/null +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -0,0 +1,55 @@ +import time +import os +import sys +import atexit +import webbrowser + +from Plugin import PluginManager +from Config import config + +allow_reload = False # No source reload supported in this plugin +current_path = os.path.dirname(os.path.abspath(__file__)) + +@PluginManager.registerTo("Actions") +class ActionsPlugin(object): + + def main(self): + import gevent.threadpool , gevent.thread + global tray_app + + self.main = sys.modules["main"] + fs_encoding = sys.getfilesystemencoding() + + config.ui_ip = config.ui_ip if config.ui_ip != "*" else "127.0.0.1" + #info_items = [ self.titleIp, self.titleConnections, + # self.titleTransfer ] + + + import subprocess + status = subprocess.call( + "python %s/lib/tray_osx.py %s %s %s" % ( current_path , + *[config.ui_ip, config.ui_port, config.homepage] ), + shell=True) + print status + + super(ActionsPlugin, self).main() + + + def titleIp(self): + title = "!IP: %s" % config.ip_external + if self.main.file_server.port_opened: + title += " (active)" + else: + title += " (passive)" + return title + + def titleConnections(self): + title = "Connections: %s" % len(self.main.file_server.connections) + return title + + def titleTransfer(self): + title = "Received: %.2f MB | Sent: %.2f MB" % ( + float(self.main.file_server.bytes_recv) / 1024 / 1024, + float(self.main.file_server.bytes_sent) / 1024 / 1024 + ) + return title diff --git a/plugins/Trayicon/__init__.py b/plugins/Trayicon/__init__.py index 5b5849629..30bf77f5e 100644 --- a/plugins/Trayicon/__init__.py +++ b/plugins/Trayicon/__init__.py @@ -1,4 +1,6 @@ import sys if sys.platform == 'win32': - import TrayiconPlugin \ No newline at end of file + import TrayiconPlugin +elif sys.platform == 'darwin': + import TrayiconOSXPlugin diff --git a/plugins/Trayicon/lib/tray_osx.py b/plugins/Trayicon/lib/tray_osx.py new file mode 100644 index 000000000..6919a1040 --- /dev/null +++ b/plugins/Trayicon/lib/tray_osx.py @@ -0,0 +1,131 @@ +import time +import os +import sys +import atexit +import webbrowser + +# OSX AppKit Path +current_path = os.path.dirname(os.path.abspath(__file__)) +python_path = os.path.abspath( os.path.join(current_path, os.pardir, os.pardir, 'python27', '1.0')) + +osx_lib = os.path.join(python_path, 'lib', 'darwin') +sys.path.append(osx_lib) +extra_lib = "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC" +sys.path.append(extra_lib) + +from PyObjCTools import AppHelper +from AppKit import * + + +class MacTrayObject(NSObject): + """ Taken from XX-NET """ + def __init__(self): + print "MacTray Called" + + def set_info_items(self, items): + self.menu_info_items = items + + def applicationDidFinishLaunching_(self, notification): + print 'Ops, didFinishLaunching' + self.setupUI() + self.registerObserver() + + def setupUI(self): + self.statusbar = NSStatusBar.systemStatusBar() + self.statusitem = self.statusbar.statusItemWithLength_(NSVariableStatusItemLength) #NSSquareStatusItemLength #NSVariableStatusItemLength + + # Set initial image icon + icon_path = os.path.join(current_path, "../trayicon.ico") + image = NSImage.alloc().initByReferencingFile_(icon_path) + image.setScalesWhenResized_(True) + image.setSize_((20, 20)) + self.statusitem.setImage_(image) + + # Let it highlight upon clicking + self.statusitem.setHighlightMode_(1) + self.statusitem.setToolTip_("ZeroNet") + + # Build a very simple menu + self.menu = NSMenu.alloc().init() + self.menu.setAutoenablesItems_(False) + + # Create info items + """ + for item in self.menu_info_items: + menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( item, 'info:','') + self.menu.addItem( menuItem ) + """ + + # Other items + menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Open ZeroNet', 'open:', '') + self.menu.addItem_(menuitem) + + # Default event + menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'windowWillClose:', '') + self.menu.addItem_(menuitem) + + # Bind it to the status item + self.statusitem.setMenu_(self.menu) + + # Hide dock icon + NSApp.setActivationPolicy_(NSApplicationActivationPolicyProhibited) + + def registerObserver(self): + nc = NSWorkspace.sharedWorkspace().notificationCenter() + nc.addObserver_selector_name_object_(self, 'windowWillClose:', NSWorkspaceWillPowerOffNotification, None) + + def windowWillClose_(self, notification): + NSApp.terminate_(self) + sys.exit(0) + + def setParams(self, ui_ip , ui_port, homepage ): + self.config = { + 'ui_ip': ui_ip, + 'ui_port': ui_port, + 'homepage': homepage + } + + def open_(self, notification): + print self.config + webbrowser.open_new("http://%s:%s/%s" % + ( self.config['ui_ip'], self.config['ui_port'], self.config['homepage']) ) + + #Note: the function name for action can include '_' + # limited by Mac cocoa + def resetGoagent_(self, _): + print 'goagent stop' + print 'goagent start' + + def enableProxy_(self, _): + print 'enable proxy' + + def disableProxy_(self, _): + print 'disable proxy' + + + + +def tray_items(items): + pass + #self.delegate.set_info_items( items ) + +def tray_init(): + global tray_app, delegate + tray_app = NSApplication.sharedApplication() + delegate = MacTrayObject.alloc().init() + + delegate.setParams( *sys.argv[1:] ) + +def tray_run(): + global tray_app, delegate + tray_app.setDelegate_(delegate) + AppHelper.runEventLoop() + +if __name__ == '__main__': + if(len(sys.argv) <= 1): + print 'Please pass params: (ui_ip, ui_port, homepage)' + sys.exit() + + print sys.argv[1:] + tray_init() + tray_run() diff --git a/src/Config.py b/src/Config.py index e372a4a29..f923dcd7a 100644 --- a/src/Config.py +++ b/src/Config.py @@ -59,6 +59,11 @@ def createArguments(self): action.add_argument('address', help='Site address') action.add_argument('inner_path', help='File inner path') + # SiteClone + action = self.subparsers.add_parser("siteClone", help="Clone a site, copying every file into a new.") + action.add_argument('address', help='Site Address') + action.add_argument('privatekey', help='Private key(default: ask on execute)', nargs='?') + # SiteSign action = self.subparsers.add_parser("siteSign", help='Update and sign content.json: address [privatekey]') action.add_argument('address', help='Site to sign') diff --git a/src/Site/SiteStorage.py b/src/Site/SiteStorage.py index 03110280a..990ba511d 100644 --- a/src/Site/SiteStorage.py +++ b/src/Site/SiteStorage.py @@ -34,8 +34,12 @@ def __init__(self, site, allow_create=True): # Load db from dbschema.json def openDb(self, check=True): - schema = self.loadJson("dbschema.json") - db_path = self.getPath(schema["db_file"]) + try: + schema = self.loadJson("dbschema.json") + db_path = self.getPath(schema["db_file"]) + except Exception, err: + raise Exception("dbschema.json is not a valid JSON", err) + if check: if not os.path.isfile(db_path) or os.path.getsize(db_path) == 0: # Not exist or null self.rebuildDb() diff --git a/src/main.py b/src/main.py index 87e089f85..1eeff55fc 100644 --- a/src/main.py +++ b/src/main.py @@ -164,7 +164,7 @@ def siteCreate(self): def siteSign(self, address, privatekey=None, inner_path="content.json", publish=False): from Site import Site logging.info("Signing site: %s..." % address) - site = Site(address, allow_create=False) + site = Site(address) if not privatekey: # If no privatekey definied from User import UserManager @@ -208,6 +208,27 @@ def siteVerify(self, address): else: logging.error("[ERROR] Error during verifying site files!") + def siteClone(self, address, privatekey=None ): + from Site import Site + logging.info("Cloning site: %s..." % address) + + from Site import SiteManager + from File import FileServer # We need fileserver to handle incoming file requests + from Peer import Peer + + logging.info("Loading site...") + site = Site(address) + site.settings["serving"] = True # Serving the site even if its disabled + + logging.info("Creating FileServer....") + file_server = FileServer() + site.connection_server = file_server + file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity + time.sleep(0) + + result = site.clone(address, privatekey=privatekey) + logging.info('clone result', result) + def dbRebuild(self, address): from Site import Site logging.info("Rebuilding site sql cache: %s..." % address) From d75478d8c2788173b8edf70216edc24013f74417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Fri, 4 Mar 2016 18:51:45 -0300 Subject: [PATCH 2/9] Initial commit of osx trayIcon --- plugins/Trayicon/TrayiconOSXPlugin.py | 75 ++++++++++++++++++++++----- plugins/Trayicon/lib/tray_osx.py | 36 +++++++------ 2 files changed, 82 insertions(+), 29 deletions(-) mode change 100644 => 100755 plugins/Trayicon/lib/tray_osx.py diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py index d26c49ef9..c41559932 100644 --- a/plugins/Trayicon/TrayiconOSXPlugin.py +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -3,6 +3,9 @@ import sys import atexit import webbrowser +import logging + +from threading import Thread from Plugin import PluginManager from Config import config @@ -10,29 +13,65 @@ allow_reload = False # No source reload supported in this plugin current_path = os.path.dirname(os.path.abspath(__file__)) +log = logging.getLogger("ZeronamePlugin") + + +def tray_threaded( plugin_action ): + """ + Tray in another process + Thread to comunicate from<->to tray + """ + global tray + + # Launch tray process + from subprocess import Popen, PIPE + from threading import Thread + + tray_osx = "%s/lib/tray_osx.py" % (current_path ) + tray = Popen( tray_osx , shell=True, stdin=PIPE, stdout=PIPE ) + + # Read data from tray process + while True: + output = non_block_read( tray.stdout ).split(' ') + # Dispatch actions + if(output[0] == 'dispatch'): + action = output[1][:-1] + + try: + app_method = getattr(plugin_action, action) + app_method() + except Exception, e: + print "Unknown action from trayIcon: %s" % action + + time.sleep(1) + @PluginManager.registerTo("Actions") class ActionsPlugin(object): def main(self): - import gevent.threadpool , gevent.thread - global tray_app + import gevent.threadpool + global tray_thread self.main = sys.modules["main"] fs_encoding = sys.getfilesystemencoding() - config.ui_ip = config.ui_ip if config.ui_ip != "*" else "127.0.0.1" - #info_items = [ self.titleIp, self.titleConnections, - # self.titleTransfer ] + tray_thread = gevent.threadpool.start_new_thread( tray_threaded, (self,)) + super(ActionsPlugin, self).main() + @atexit.register + def quitTrayIcon(): + tray.terminate() - import subprocess - status = subprocess.call( - "python %s/lib/tray_osx.py %s %s %s" % ( current_path , - *[config.ui_ip, config.ui_port, config.homepage] ), - shell=True) - print status + def quit(self): + tray.terminate() + sys.exit() - super(ActionsPlugin, self).main() + def start(self): + """ Now Safely read self.main """ + print "Started" + + def open(self): + webbrowser.open_new("http://%s:%s/%s" % ( config.ui_ip, config.ui_port, config.homepage ) ) def titleIp(self): @@ -53,3 +92,15 @@ def titleTransfer(self): float(self.main.file_server.bytes_sent) / 1024 / 1024 ) return title + + +import fcntl +def non_block_read(output): + ''' read without blocking ''' + fd = output.fileno() + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) + try: + return output.read() + except: + return '' diff --git a/plugins/Trayicon/lib/tray_osx.py b/plugins/Trayicon/lib/tray_osx.py old mode 100644 new mode 100755 index 6919a1040..66c14f5af --- a/plugins/Trayicon/lib/tray_osx.py +++ b/plugins/Trayicon/lib/tray_osx.py @@ -1,3 +1,12 @@ +#!/usr/bin/env python +# +# +# This is a standalone script to create a TrayIcon on OSX. +# It's run as a standalone, because AppKit cannot run on +# any way in gevent/threads. +# +# + import time import os import sys @@ -26,10 +35,14 @@ def set_info_items(self, items): self.menu_info_items = items def applicationDidFinishLaunching_(self, notification): - print 'Ops, didFinishLaunching' self.setupUI() + + print 'dispatch start' + sys.stdout.flush() + self.registerObserver() + def setupUI(self): self.statusbar = NSStatusBar.systemStatusBar() self.statusitem = self.statusbar.statusItemWithLength_(NSVariableStatusItemLength) #NSSquareStatusItemLength #NSVariableStatusItemLength @@ -75,8 +88,9 @@ def registerObserver(self): nc.addObserver_selector_name_object_(self, 'windowWillClose:', NSWorkspaceWillPowerOffNotification, None) def windowWillClose_(self, notification): + print 'dispatch quit' + sys.stdout.flush() NSApp.terminate_(self) - sys.exit(0) def setParams(self, ui_ip , ui_port, homepage ): self.config = { @@ -86,9 +100,8 @@ def setParams(self, ui_ip , ui_port, homepage ): } def open_(self, notification): - print self.config - webbrowser.open_new("http://%s:%s/%s" % - ( self.config['ui_ip'], self.config['ui_port'], self.config['homepage']) ) + print 'dispatch open' + sys.stdout.flush() #Note: the function name for action can include '_' # limited by Mac cocoa @@ -103,18 +116,12 @@ def disableProxy_(self, _): print 'disable proxy' - - -def tray_items(items): - pass - #self.delegate.set_info_items( items ) - def tray_init(): global tray_app, delegate tray_app = NSApplication.sharedApplication() delegate = MacTrayObject.alloc().init() - delegate.setParams( *sys.argv[1:] ) + #delegate.setParams( *sys.argv[1:] ) def tray_run(): global tray_app, delegate @@ -122,10 +129,5 @@ def tray_run(): AppHelper.runEventLoop() if __name__ == '__main__': - if(len(sys.argv) <= 1): - print 'Please pass params: (ui_ip, ui_port, homepage)' - sys.exit() - - print sys.argv[1:] tray_init() tray_run() From aa935afc714d39b1f5e5457dfb4228edf95360ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Fri, 4 Mar 2016 19:17:37 -0300 Subject: [PATCH 3/9] Fixed access to main on TrayIconOSXPlugin --- plugins/Trayicon/TrayiconOSXPlugin.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py index c41559932..85498eaf2 100644 --- a/plugins/Trayicon/TrayiconOSXPlugin.py +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -36,7 +36,7 @@ def tray_threaded( plugin_action ): # Dispatch actions if(output[0] == 'dispatch'): action = output[1][:-1] - + try: app_method = getattr(plugin_action, action) app_method() @@ -50,9 +50,9 @@ class ActionsPlugin(object): def main(self): import gevent.threadpool - global tray_thread + global tray_thread , main - self.main = sys.modules["main"] + main = sys.modules["main"] fs_encoding = sys.getfilesystemencoding() tray_thread = gevent.threadpool.start_new_thread( tray_threaded, (self,)) @@ -67,8 +67,8 @@ def quit(self): sys.exit() def start(self): - """ Now Safely read self.main """ - print "Started" + print "start" + print main.file_server.connections def open(self): webbrowser.open_new("http://%s:%s/%s" % ( config.ui_ip, config.ui_port, config.homepage ) ) @@ -76,14 +76,14 @@ def open(self): def titleIp(self): title = "!IP: %s" % config.ip_external - if self.main.file_server.port_opened: + if main.file_server.port_opened: title += " (active)" else: title += " (passive)" return title def titleConnections(self): - title = "Connections: %s" % len(self.main.file_server.connections) + title = "Connections: %s" % len(main.file_server.connections) return title def titleTransfer(self): From 6b2e60e8f13bc810e03f1b12c6dadfa6986de9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Fri, 4 Mar 2016 19:19:31 -0300 Subject: [PATCH 4/9] Removed unused code, increased TrayIconThread to 1s --- plugins/Trayicon/lib/tray_osx.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/plugins/Trayicon/lib/tray_osx.py b/plugins/Trayicon/lib/tray_osx.py index 66c14f5af..81b9d93b8 100755 --- a/plugins/Trayicon/lib/tray_osx.py +++ b/plugins/Trayicon/lib/tray_osx.py @@ -92,39 +92,18 @@ def windowWillClose_(self, notification): sys.stdout.flush() NSApp.terminate_(self) - def setParams(self, ui_ip , ui_port, homepage ): - self.config = { - 'ui_ip': ui_ip, - 'ui_port': ui_port, - 'homepage': homepage - } - def open_(self, notification): print 'dispatch open' sys.stdout.flush() - #Note: the function name for action can include '_' - # limited by Mac cocoa - def resetGoagent_(self, _): - print 'goagent stop' - print 'goagent start' - - def enableProxy_(self, _): - print 'enable proxy' - - def disableProxy_(self, _): - print 'disable proxy' - def tray_init(): global tray_app, delegate tray_app = NSApplication.sharedApplication() delegate = MacTrayObject.alloc().init() - #delegate.setParams( *sys.argv[1:] ) def tray_run(): - global tray_app, delegate tray_app.setDelegate_(delegate) AppHelper.runEventLoop() From 171d4887f227d440f588545f13190194183cf18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Mon, 7 Mar 2016 14:16:17 -0300 Subject: [PATCH 5/9] Quitting zeronet when user asks to quit. Removed not-working INFO from interface --- plugins/Trayicon/TrayiconOSXPlugin.py | 91 +++++++++------------------ plugins/Trayicon/lib/tray_osx.py | 87 ++++++++++++++----------- 2 files changed, 80 insertions(+), 98 deletions(-) diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py index 85498eaf2..e3f05712c 100644 --- a/plugins/Trayicon/TrayiconOSXPlugin.py +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -13,35 +13,16 @@ allow_reload = False # No source reload supported in this plugin current_path = os.path.dirname(os.path.abspath(__file__)) -log = logging.getLogger("ZeronamePlugin") +log = logging.getLogger("plugins-trayicon") +def tray_read(): + global tray_thread, main, tray, plugin -def tray_threaded( plugin_action ): - """ - Tray in another process - Thread to comunicate from<->to tray - """ - global tray - - # Launch tray process - from subprocess import Popen, PIPE - from threading import Thread - - tray_osx = "%s/lib/tray_osx.py" % (current_path ) - tray = Popen( tray_osx , shell=True, stdin=PIPE, stdout=PIPE ) - - # Read data from tray process while True: - output = non_block_read( tray.stdout ).split(' ') - # Dispatch actions - if(output[0] == 'dispatch'): - action = output[1][:-1] - - try: - app_method = getattr(plugin_action, action) - app_method() - except Exception, e: - print "Unknown action from trayIcon: %s" % action + _in = tray.stdout.readline() + (message, action , args ) = _in[:-1].split(' ') + if(action == 'quit'): + plugin.quit() time.sleep(1) @@ -50,12 +31,22 @@ class ActionsPlugin(object): def main(self): import gevent.threadpool - global tray_thread , main + global tray_thread, main, tray , plugin main = sys.modules["main"] fs_encoding = sys.getfilesystemencoding() - tray_thread = gevent.threadpool.start_new_thread( tray_threaded, (self,)) + # Launch tray process + from subprocess import Popen, PIPE + from threading import Thread + + # Wait for file server to start + tray_osx_app = "%s/lib/tray_osx.py %s %s" % (current_path , self.homepage() , self.titleIp()) + tray = Popen( tray_osx_app , shell=True , stdout=PIPE, stdin=PIPE) + + plugin = self + tray_thread = gevent.threadpool.start_new_thread( tray_read , ()) + super(ActionsPlugin, self).main() @atexit.register @@ -64,43 +55,19 @@ def quitTrayIcon(): def quit(self): tray.terminate() - sys.exit() - - def start(self): - print "start" - print main.file_server.connections - - def open(self): - webbrowser.open_new("http://%s:%s/%s" % ( config.ui_ip, config.ui_port, config.homepage ) ) + os._exit(0) + def homepage(self): + ui_ip = config.ui_ip if config.ui_ip != "*" else "127.0.0.1" + return "http://%s:%s/%s" % (ui_ip, config.ui_port, config.homepage) def titleIp(self): - title = "!IP: %s" % config.ip_external - if main.file_server.port_opened: - title += " (active)" - else: - title += " (passive)" - return title - - def titleConnections(self): - title = "Connections: %s" % len(main.file_server.connections) - return title - - def titleTransfer(self): - title = "Received: %.2f MB | Sent: %.2f MB" % ( - float(self.main.file_server.bytes_recv) / 1024 / 1024, - float(self.main.file_server.bytes_sent) / 1024 / 1024 - ) + title = "%s" % (config.ip_external or '127.0.0.1') return title + def transfer(self): + def bytes_to_mb(b): + return '%.2fMB' % (float(b) / 1024 / 1024) -import fcntl -def non_block_read(output): - ''' read without blocking ''' - fd = output.fileno() - fl = fcntl.fcntl(fd, fcntl.F_GETFL) - fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) - try: - return output.read() - except: - return '' + return {'recv': bytes_to_mb(self.main.file_server.bytes_recv), + 'sent': bytes_to_mb(self.main.file_server.bytes_sent)} diff --git a/plugins/Trayicon/lib/tray_osx.py b/plugins/Trayicon/lib/tray_osx.py index 81b9d93b8..3d141e83e 100755 --- a/plugins/Trayicon/lib/tray_osx.py +++ b/plugins/Trayicon/lib/tray_osx.py @@ -1,17 +1,18 @@ #!/usr/bin/env python -# +# -*- coding: utf-8 -*-# # # This is a standalone script to create a TrayIcon on OSX. # It's run as a standalone, because AppKit cannot run on # any way in gevent/threads. # # - import time import os import sys import atexit import webbrowser +import json +import threading # OSX AppKit Path current_path = os.path.dirname(os.path.abspath(__file__)) @@ -23,25 +24,28 @@ sys.path.append(extra_lib) from PyObjCTools import AppHelper -from AppKit import * +from AppKit import NSObject, NSApp, NSApplication, NSWorkspace, NSStatusBar, NSMenu, NSMenuItem, NSImage,NSApplicationActivationPolicyProhibited , NSWorkspaceWillPowerOffNotification, NSVariableStatusItemLength +global MENU_ITEMS, INFO +MENU_ITEMS = dict() +INFO = dict({ + 'homepage': 'http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D', + 'ip_external': '127.0.0.1' +}) class MacTrayObject(NSObject): - """ Taken from XX-NET """ - def __init__(self): - print "MacTray Called" - - def set_info_items(self, items): - self.menu_info_items = items + def message(self,action, args=None): + print 'message %s %s' % (action , (args or '')) + sys.stdout.flush() def applicationDidFinishLaunching_(self, notification): self.setupUI() - - print 'dispatch start' - sys.stdout.flush() - self.registerObserver() + def create_menu_item(self, key, title , callback ): + it = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( title , callback , '') + self.menu.addItem_( it ) + MENU_ITEMS[ key ] = it def setupUI(self): self.statusbar = NSStatusBar.systemStatusBar() @@ -62,25 +66,20 @@ def setupUI(self): self.menu = NSMenu.alloc().init() self.menu.setAutoenablesItems_(False) - # Create info items - """ - for item in self.menu_info_items: - menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_( item, 'info:','') - self.menu.addItem( menuItem ) - """ + #self.create_menu_item( 'ip_external', 'IP: %s' % INFO['ip_external'], 'info:') + self.menu.addItem_( NSMenuItem.separatorItem() ) - # Other items - menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Open ZeroNet', 'open:', '') - self.menu.addItem_(menuitem) + # Links + self.create_menu_item( 'open_zeronet', 'Open ZeroNet', 'open:') + self.create_menu_item( 'open_reddit', 'Zeronet Reddot', 'openreddit:') + self.create_menu_item( 'open_gh', 'Report issues/feature requests', 'opengithub:') - # Default event - menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'windowWillClose:', '') - self.menu.addItem_(menuitem) + self.menu.addItem_( NSMenuItem.separatorItem() ) - # Bind it to the status item - self.statusitem.setMenu_(self.menu) + self.create_menu_item( 'quit_zeronet', 'Quit ZeroNet', 'windowWillClose:' ) - # Hide dock icon + # Bind it to the status item and hide dock icon + self.statusitem.setMenu_(self.menu) NSApp.setActivationPolicy_(NSApplicationActivationPolicyProhibited) def registerObserver(self): @@ -88,25 +87,41 @@ def registerObserver(self): nc.addObserver_selector_name_object_(self, 'windowWillClose:', NSWorkspaceWillPowerOffNotification, None) def windowWillClose_(self, notification): - print 'dispatch quit' - sys.stdout.flush() + self.message('quit') NSApp.terminate_(self) def open_(self, notification): - print 'dispatch open' - sys.stdout.flush() + self.message('open') + webbrowser.open_new( INFO['homepage'] ) + + def openreddit_(self): + webbrowser.open_new("https://www.reddit.com/r/zeronet") + self.message('open','reddit') + def opengithub_(self): + webbrowser.open_new("https://github.com/HelloZeroNet/ZeroNet") + self.message('open','github') + + def info_(self, notification): + pass + + def set(self, key, value): + self.update_title_items() + self.message('ok') def tray_init(): - global tray_app, delegate + global tray_app, app_delegate tray_app = NSApplication.sharedApplication() - delegate = MacTrayObject.alloc().init() - + app_delegate = MacTrayObject.alloc().init() + tray_app.setDelegate_(app_delegate) def tray_run(): - tray_app.setDelegate_(delegate) AppHelper.runEventLoop() if __name__ == '__main__': + if(len(sys.argv) > 2): + INFO['homepage'] = sys.argv[1] + INFO['ip_external'] = sys.argv[2] + tray_init() tray_run() From 001ac5f6a154468794e44e8e493e04378129da4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Mon, 7 Mar 2016 14:28:07 -0300 Subject: [PATCH 6/9] Fixed typo in menu --- plugins/Trayicon/lib/tray_osx.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/Trayicon/lib/tray_osx.py b/plugins/Trayicon/lib/tray_osx.py index 3d141e83e..80b3e0fb0 100755 --- a/plugins/Trayicon/lib/tray_osx.py +++ b/plugins/Trayicon/lib/tray_osx.py @@ -71,7 +71,7 @@ def setupUI(self): # Links self.create_menu_item( 'open_zeronet', 'Open ZeroNet', 'open:') - self.create_menu_item( 'open_reddit', 'Zeronet Reddot', 'openreddit:') + self.create_menu_item( 'open_reddit', 'Zeronet Reddit Community', 'openreddit:') self.create_menu_item( 'open_gh', 'Report issues/feature requests', 'opengithub:') self.menu.addItem_( NSMenuItem.separatorItem() ) @@ -94,11 +94,11 @@ def open_(self, notification): self.message('open') webbrowser.open_new( INFO['homepage'] ) - def openreddit_(self): + def openreddit_(self, notification): webbrowser.open_new("https://www.reddit.com/r/zeronet") self.message('open','reddit') - def opengithub_(self): + def opengithub_(self, notification): webbrowser.open_new("https://github.com/HelloZeroNet/ZeroNet") self.message('open','github') From 5fcdd6087234c19b8d812a0bac552823542bee7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Mon, 7 Mar 2016 14:35:23 -0300 Subject: [PATCH 7/9] reverted changes that doesnt have anything to do with tray --- src/Config.py | 5 ----- src/Site/SiteStorage.py | 8 ++------ src/main.py | 23 +---------------------- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/src/Config.py b/src/Config.py index f923dcd7a..e372a4a29 100644 --- a/src/Config.py +++ b/src/Config.py @@ -59,11 +59,6 @@ def createArguments(self): action.add_argument('address', help='Site address') action.add_argument('inner_path', help='File inner path') - # SiteClone - action = self.subparsers.add_parser("siteClone", help="Clone a site, copying every file into a new.") - action.add_argument('address', help='Site Address') - action.add_argument('privatekey', help='Private key(default: ask on execute)', nargs='?') - # SiteSign action = self.subparsers.add_parser("siteSign", help='Update and sign content.json: address [privatekey]') action.add_argument('address', help='Site to sign') diff --git a/src/Site/SiteStorage.py b/src/Site/SiteStorage.py index 990ba511d..03110280a 100644 --- a/src/Site/SiteStorage.py +++ b/src/Site/SiteStorage.py @@ -34,12 +34,8 @@ def __init__(self, site, allow_create=True): # Load db from dbschema.json def openDb(self, check=True): - try: - schema = self.loadJson("dbschema.json") - db_path = self.getPath(schema["db_file"]) - except Exception, err: - raise Exception("dbschema.json is not a valid JSON", err) - + schema = self.loadJson("dbschema.json") + db_path = self.getPath(schema["db_file"]) if check: if not os.path.isfile(db_path) or os.path.getsize(db_path) == 0: # Not exist or null self.rebuildDb() diff --git a/src/main.py b/src/main.py index 1eeff55fc..87e089f85 100644 --- a/src/main.py +++ b/src/main.py @@ -164,7 +164,7 @@ def siteCreate(self): def siteSign(self, address, privatekey=None, inner_path="content.json", publish=False): from Site import Site logging.info("Signing site: %s..." % address) - site = Site(address) + site = Site(address, allow_create=False) if not privatekey: # If no privatekey definied from User import UserManager @@ -208,27 +208,6 @@ def siteVerify(self, address): else: logging.error("[ERROR] Error during verifying site files!") - def siteClone(self, address, privatekey=None ): - from Site import Site - logging.info("Cloning site: %s..." % address) - - from Site import SiteManager - from File import FileServer # We need fileserver to handle incoming file requests - from Peer import Peer - - logging.info("Loading site...") - site = Site(address) - site.settings["serving"] = True # Serving the site even if its disabled - - logging.info("Creating FileServer....") - file_server = FileServer() - site.connection_server = file_server - file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity - time.sleep(0) - - result = site.clone(address, privatekey=privatekey) - logging.info('clone result', result) - def dbRebuild(self, address): from Site import Site logging.info("Rebuilding site sql cache: %s..." % address) From 739e11f3a6efc7974858f55020585716b6956375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Mon, 7 Mar 2016 14:45:23 -0300 Subject: [PATCH 8/9] Cleaning doc --- plugins/Trayicon/TrayiconOSXPlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py index e3f05712c..f4aa05ef6 100644 --- a/plugins/Trayicon/TrayiconOSXPlugin.py +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -40,10 +40,10 @@ def main(self): from subprocess import Popen, PIPE from threading import Thread - # Wait for file server to start tray_osx_app = "%s/lib/tray_osx.py %s %s" % (current_path , self.homepage() , self.titleIp()) tray = Popen( tray_osx_app , shell=True , stdout=PIPE, stdin=PIPE) + # Read messages from tray app plugin = self tray_thread = gevent.threadpool.start_new_thread( tray_read , ()) From f85d013b57514403b43d94054182d7192601aa83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barrabin=20Fc=2E=20=E2=9A=91?= Date: Mon, 7 Mar 2016 19:09:32 -0300 Subject: [PATCH 9/9] Fix race condition when zeronet quits before tray_app is opened --- plugins/Trayicon/TrayiconOSXPlugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/Trayicon/TrayiconOSXPlugin.py b/plugins/Trayicon/TrayiconOSXPlugin.py index f4aa05ef6..27af8e76f 100644 --- a/plugins/Trayicon/TrayiconOSXPlugin.py +++ b/plugins/Trayicon/TrayiconOSXPlugin.py @@ -51,7 +51,10 @@ def main(self): @atexit.register def quitTrayIcon(): - tray.terminate() + try: + tray.terminate() + except NameError: + pass def quit(self): tray.terminate()