From 30281c8fb592b71d25772bfc5dc29400773afe9a Mon Sep 17 00:00:00 2001 From: HelloZeroNet Date: Wed, 15 Apr 2015 02:54:10 +0200 Subject: [PATCH] Sexy system trac icon instead of ugly console, Total received/sent stat, List all site peer, Dont sent passive peers over pex, Dont store passive peers on trackers, Dont monkey patch thread at all, Allow main command plugins --- plugins/Stats/StatsPlugin.py | 16 +- plugins/Trayicon/TrayiconPlugin.py | 91 +++ plugins/Trayicon/__init__.py | 4 + plugins/Trayicon/lib/__init__.py | 0 plugins/Trayicon/lib/notificationicon.py | 800 +++++++++++++++++++++++ plugins/Trayicon/lib/winfolders.py | 48 ++ plugins/Trayicon/trayicon.ico | Bin 0 -> 1150 bytes src/Connection/Connection.py | 12 +- src/Connection/ConnectionServer.py | 5 + src/File/FileRequest.py | 4 +- src/Peer/Peer.py | 2 +- src/Site/Site.py | 5 +- src/Ui/UiServer.py | 6 +- src/main.py | 384 +++++------ 14 files changed, 1170 insertions(+), 207 deletions(-) create mode 100644 plugins/Trayicon/TrayiconPlugin.py create mode 100644 plugins/Trayicon/__init__.py create mode 100644 plugins/Trayicon/lib/__init__.py create mode 100644 plugins/Trayicon/lib/notificationicon.py create mode 100644 plugins/Trayicon/lib/winfolders.py create mode 100644 plugins/Trayicon/trayicon.ico diff --git a/plugins/Stats/StatsPlugin.py b/plugins/Stats/StatsPlugin.py index 11f2758e..b6aa2336 100644 --- a/plugins/Stats/StatsPlugin.py +++ b/plugins/Stats/StatsPlugin.py @@ -53,12 +53,14 @@ class UiRequestPlugin(object): # Memory try: - yield "Ip external: %s | " % config.ip_external - yield "Port opened: %s | " % main.file_server.port_opened + yield "IP external: %s | " % config.ip_external + yield "Opened: %s | " % main.file_server.port_opened + yield "Recv: %.2fMB, Sent: %.2fMB | " % (float(main.file_server.bytes_recv)/1024/1024, float(main.file_server.bytes_sent)/1024/1024) + yield "Peerid: %s | " % main.file_server.peer_id import psutil process = psutil.Process(os.getpid()) mem = process.get_memory_info()[0] / float(2 ** 20) - yield "Memory usage: %.2fMB | " % mem + yield "Mem: %.2fMB | " % mem yield "Threads: %s | " % len(process.threads()) yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times() yield "Open files: %s | " % len(process.open_files()) @@ -69,7 +71,7 @@ class UiRequestPlugin(object): yield "
" # Connections - yield "Connections (%s):
" % len(main.file_server.connections) + yield "Connections (%s, total made: %s):
" % (len(main.file_server.connections), main.file_server.last_connection_id) yield "" yield "" for connection in main.file_server.connections: @@ -100,11 +102,15 @@ class UiRequestPlugin(object): yield "" for site in self.server.sites.values(): yield self.formatTableRow([ - ("%s", site.address), + ("%s", (site.address, site.address)), ("%s", [peer.connection.id for peer in site.peers.values() if peer.connection and peer.connection.connected]), ("%s/%s", ( len([peer for peer in site.peers.values() if peer.connection and peer.connection.connected]), len(site.peers) ) ), ("%s", len(site.content_manager.contents)), ]) + yield "" yield "
id protocol type ip open ping buffidle open delay sent received last sent waiting version peerid
address connected peers content.json
" diff --git a/plugins/Trayicon/TrayiconPlugin.py b/plugins/Trayicon/TrayiconPlugin.py new file mode 100644 index 00000000..5517fa96 --- /dev/null +++ b/plugins/Trayicon/TrayiconPlugin.py @@ -0,0 +1,91 @@ +import re, time, cgi, os, sys +from Plugin import PluginManager +from Config import config +import atexit + +allow_reload = False # No reload supported + +@PluginManager.registerTo("Actions") +class ActionsPlugin(object): + def main(self): + global notificationicon, winfolders + from lib import notificationicon, winfolders + import gevent.threadpool + + self.main = sys.modules["main"] + + icon = notificationicon.NotificationIcon(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'trayicon.ico'), "ZeroNet %s" % config.version) + self.icon = icon + + if not config.debug: # Hide console if not in debug mode + notificationicon.hideConsole() + self.console = False + else: + self.console = True + + @atexit.register + def hideIcon(): + icon.die() + + icon.items = ( + (self.titleIp, False), + (self.titleConnections, False), + (self.titleTransfer, False), + (self.titleConsole, self.toggleConsole), + "--", + ("ZeroNet Twitter", lambda: self.opensite("https://twitter.com/HelloZeroNet") ), + ("ZeroNet Reddit", lambda: self.opensite("http://www.reddit.com/r/zeronet/") ), + ("ZeroNet Github", lambda: self.opensite("https://github.com/HelloZeroNet/ZeroNet") ), + ("Report bug/request feature", lambda: self.opensite("https://github.com/HelloZeroNet/ZeroNet/issues") ), + "--", + ("!Open ZeroNet", lambda: self.opensite("http://%s:%s" % (config.ui_ip, config.ui_port)) ), + #"--", + #("Start ZeroNet when Windows starts", quit), + "--", + ("Quit", self.quit), + + ) + + icon.clicked = lambda: self.opensite("http://%s:%s" % (config.ui_ip, config.ui_port)) + gevent.threadpool.start_new_thread(icon._run, ()) # Start in real thread (not gevent compatible) + super(ActionsPlugin, self).main() + icon._die = True + + def quit(self): + self.icon.die() + time.sleep(0.1) + self.main.ui_server.stop() + self.main.file_server.stop() + #sys.exit() + + def opensite(self, url): + import webbrowser + webbrowser.open(url, new=2) + + 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 + + def titleConsole(self): + if self.console: return "+Show console window" + else: return "Show console window" + + def toggleConsole(self): + if self.console: + notificationicon.hideConsole() + self.console = False + else: + notificationicon.showConsole() + self.console = True diff --git a/plugins/Trayicon/__init__.py b/plugins/Trayicon/__init__.py new file mode 100644 index 00000000..5b584962 --- /dev/null +++ b/plugins/Trayicon/__init__.py @@ -0,0 +1,4 @@ +import sys + +if sys.platform == 'win32': + import TrayiconPlugin \ No newline at end of file diff --git a/plugins/Trayicon/lib/__init__.py b/plugins/Trayicon/lib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/plugins/Trayicon/lib/notificationicon.py b/plugins/Trayicon/lib/notificationicon.py new file mode 100644 index 00000000..73e1c83c --- /dev/null +++ b/plugins/Trayicon/lib/notificationicon.py @@ -0,0 +1,800 @@ +# Pure ctypes windows taskbar notification icon +# via https://gist.github.com/jasonbot/5759510 +# Modified for ZeroNet + +import ctypes +import ctypes.wintypes +import os +#import threading +#import Queue +import uuid +import time +import gevent + +__all__ = ['NotificationIcon'] + +# Create popup menu + +CreatePopupMenu = ctypes.windll.user32.CreatePopupMenu +CreatePopupMenu.restype = ctypes.wintypes.HMENU +CreatePopupMenu.argtypes = [] + +MF_BYCOMMAND = 0x0 +MF_BYPOSITION = 0x400 + +MF_BITMAP = 0x4 +MF_CHECKED = 0x8 +MF_DISABLED = 0x2 +MF_ENABLED = 0x0 +MF_GRAYED = 0x1 +MF_MENUBARBREAK = 0x20 +MF_MENUBREAK = 0x40 +MF_OWNERDRAW = 0x100 +MF_POPUP = 0x10 +MF_SEPARATOR = 0x800 +MF_STRING = 0x0 +MF_UNCHECKED = 0x0 + +InsertMenu = ctypes.windll.user32.InsertMenuW +InsertMenu.restype = ctypes.wintypes.BOOL +InsertMenu.argtypes = [ctypes.wintypes.HMENU, ctypes.wintypes.UINT, ctypes.wintypes.UINT, ctypes.wintypes.UINT, ctypes.wintypes.LPCWSTR] + +AppendMenu = ctypes.windll.user32.AppendMenuW +AppendMenu.restype = ctypes.wintypes.BOOL +AppendMenu.argtypes = [ctypes.wintypes.HMENU, ctypes.wintypes.UINT, ctypes.wintypes.UINT, ctypes.wintypes.LPCWSTR] + +SetMenuDefaultItem = ctypes.windll.user32.SetMenuDefaultItem +SetMenuDefaultItem.restype = ctypes.wintypes.BOOL +SetMenuDefaultItem.argtypes = [ctypes.wintypes.HMENU, ctypes.wintypes.UINT, ctypes.wintypes.UINT] + +#class MENUITEMINFO(ctypes.Structure): +# UINT cbSize; +# UINT fMask; +# UINT fType; +# UINT fState; +# UINT wID; +# HMENU hSubMenu; +# HBITMAP hbmpChecked; +# HBITMAP hbmpUnchecked; +# ULONG_PTR dwItemData; +# LPTSTR dwTypeData; +# UINT cch; +# HBITMAP hbmpItem; +# +#BOOL WINAPI InsertMenuItem( +# __in HMENU hMenu, +# __in UINT uItem, +# __in BOOL fByPosition, +# __in LPCMENUITEMINFO lpmii +#); +# + +class POINT(ctypes.Structure): + _fields_ = [ ('x', ctypes.wintypes.LONG), + ('y', ctypes.wintypes.LONG)] + +GetCursorPos = ctypes.windll.user32.GetCursorPos +GetCursorPos.argtypes = [ctypes.POINTER(POINT)] + +SetForegroundWindow = ctypes.windll.user32.SetForegroundWindow +SetForegroundWindow.argtypes = [ctypes.wintypes.HWND] + +TPM_LEFTALIGN = 0x0 +TPM_CENTERALIGN = 0x4 +TPM_RIGHTALIGN = 0x8 + +TPM_TOPALIGN = 0x0 +TPM_VCENTERALIGN = 0x10 +TPM_BOTTOMALIGN = 0x20 + +TPM_NONOTIFY = 0x80 +TPM_RETURNCMD = 0x100 + +TPM_LEFTBUTTON = 0x0 +TPM_RIGHTBUTTON = 0x2 + +TPM_HORNEGANIMATION = 0x800 +TPM_HORPOSANIMATION = 0x400 +TPM_NOANIMATION = 0x4000 +TPM_VERNEGANIMATION = 0x2000 +TPM_VERPOSANIMATION = 0x1000 + +TrackPopupMenu = ctypes.windll.user32.TrackPopupMenu +TrackPopupMenu.restype = ctypes.wintypes.BOOL +TrackPopupMenu.argtypes = [ctypes.wintypes.HMENU, ctypes.wintypes.UINT, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.wintypes.HWND, ctypes.c_void_p] + +PostMessage = ctypes.windll.user32.PostMessageW +PostMessage.restype = ctypes.wintypes.BOOL +PostMessage.argtypes = [ctypes.wintypes.HWND, ctypes.wintypes.UINT, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM] + +DestroyMenu = ctypes.windll.user32.DestroyMenu +DestroyMenu.restype = ctypes.wintypes.BOOL +DestroyMenu.argtypes = [ctypes.wintypes.HMENU] + +# Create notification icon + +GUID = ctypes.c_ubyte * 16 + +class TimeoutVersionUnion(ctypes.Union): + _fields_ = [('uTimeout', ctypes.wintypes.UINT), + ('uVersion', ctypes.wintypes.UINT),] + +NIS_HIDDEN = 0x1 +NIS_SHAREDICON = 0x2 + +class NOTIFYICONDATA(ctypes.Structure): + def __init__(self, *args, **kwargs): + super(NOTIFYICONDATA, self).__init__(*args, **kwargs) + self.cbSize = ctypes.sizeof(self) + _fields_ = [ + ('cbSize', ctypes.wintypes.DWORD), + ('hWnd', ctypes.wintypes.HWND), + ('uID', ctypes.wintypes.UINT), + ('uFlags', ctypes.wintypes.UINT), + ('uCallbackMessage', ctypes.wintypes.UINT), + ('hIcon', ctypes.wintypes.HICON), + ('szTip', ctypes.wintypes.WCHAR * 64), + ('dwState', ctypes.wintypes.DWORD), + ('dwStateMask', ctypes.wintypes.DWORD), + ('szInfo', ctypes.wintypes.WCHAR * 256), + ('union', TimeoutVersionUnion), + ('szInfoTitle', ctypes.wintypes.WCHAR * 64), + ('dwInfoFlags', ctypes.wintypes.DWORD), + ('guidItem', GUID), + ('hBalloonIcon', ctypes.wintypes.HICON), + ] + +NIM_ADD = 0 +NIM_MODIFY = 1 +NIM_DELETE = 2 +NIM_SETFOCUS = 3 +NIM_SETVERSION = 4 + +NIF_MESSAGE = 1 +NIF_ICON = 2 +NIF_TIP = 4 +NIF_STATE = 8 +NIF_INFO = 16 +NIF_GUID = 32 +NIF_REALTIME = 64 +NIF_SHOWTIP = 128 + +NIIF_NONE = 0 +NIIF_INFO = 1 +NIIF_WARNING = 2 +NIIF_ERROR = 3 +NIIF_USER = 4 + +NOTIFYICON_VERSION = 3 +NOTIFYICON_VERSION_4 = 4 + +Shell_NotifyIcon = ctypes.windll.shell32.Shell_NotifyIconW +Shell_NotifyIcon.restype = ctypes.wintypes.BOOL +Shell_NotifyIcon.argtypes = [ctypes.wintypes.DWORD, ctypes.POINTER(NOTIFYICONDATA)] + +# Load icon/image + +IMAGE_BITMAP = 0 +IMAGE_ICON = 1 +IMAGE_CURSOR = 2 + +LR_CREATEDIBSECTION = 0x00002000 +LR_DEFAULTCOLOR = 0x00000000 +LR_DEFAULTSIZE = 0x00000040 +LR_LOADFROMFILE = 0x00000010 +LR_LOADMAP3DCOLORS = 0x00001000 +LR_LOADTRANSPARENT = 0x00000020 +LR_MONOCHROME = 0x00000001 +LR_SHARED = 0x00008000 +LR_VGACOLOR = 0x00000080 + +OIC_SAMPLE = 32512 +OIC_HAND = 32513 +OIC_QUES = 32514 +OIC_BANG = 32515 +OIC_NOTE = 32516 +OIC_WINLOGO = 32517 +OIC_WARNING = OIC_BANG +OIC_ERROR = OIC_HAND +OIC_INFORMATION = OIC_NOTE + +LoadImage = ctypes.windll.user32.LoadImageW +LoadImage.restype = ctypes.wintypes.HANDLE +LoadImage.argtypes = [ctypes.wintypes.HINSTANCE, ctypes.wintypes.LPCWSTR, ctypes.wintypes.UINT, ctypes.c_int, ctypes.c_int, ctypes.wintypes.UINT] + +# CreateWindow call + +WNDPROC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.wintypes.HWND, ctypes.c_uint, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM) +DefWindowProc = ctypes.windll.user32.DefWindowProcW +DefWindowProc.restype = ctypes.c_int +DefWindowProc.argtypes = [ctypes.wintypes.HWND, ctypes.c_uint, ctypes.wintypes.WPARAM, ctypes.wintypes.LPARAM] + +WS_OVERLAPPED = 0x00000000L +WS_POPUP = 0x80000000L +WS_CHILD = 0x40000000L +WS_MINIMIZE = 0x20000000L +WS_VISIBLE = 0x10000000L +WS_DISABLED = 0x08000000L +WS_CLIPSIBLINGS = 0x04000000L +WS_CLIPCHILDREN = 0x02000000L +WS_MAXIMIZE = 0x01000000L +WS_CAPTION = 0x00C00000L +WS_BORDER = 0x00800000L +WS_DLGFRAME = 0x00400000L +WS_VSCROLL = 0x00200000L +WS_HSCROLL = 0x00100000L +WS_SYSMENU = 0x00080000L +WS_THICKFRAME = 0x00040000L +WS_GROUP = 0x00020000L +WS_TABSTOP = 0x00010000L + +WS_MINIMIZEBOX = 0x00020000L +WS_MAXIMIZEBOX = 0x00010000L + +WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED | + WS_CAPTION | + WS_SYSMENU | + WS_THICKFRAME | + WS_MINIMIZEBOX | + WS_MAXIMIZEBOX) + +SM_XVIRTUALSCREEN = 76 +SM_YVIRTUALSCREEN = 77 +SM_CXVIRTUALSCREEN = 78 +SM_CYVIRTUALSCREEN = 79 +SM_CMONITORS = 80 +SM_SAMEDISPLAYFORMAT = 81 + +WM_NULL = 0x0000 +WM_CREATE = 0x0001 +WM_DESTROY = 0x0002 +WM_MOVE = 0x0003 +WM_SIZE = 0x0005 +WM_ACTIVATE = 0x0006 +WM_SETFOCUS = 0x0007 +WM_KILLFOCUS = 0x0008 +WM_ENABLE = 0x000A +WM_SETREDRAW = 0x000B +WM_SETTEXT = 0x000C +WM_GETTEXT = 0x000D +WM_GETTEXTLENGTH = 0x000E +WM_PAINT = 0x000F +WM_CLOSE = 0x0010 +WM_QUERYENDSESSION = 0x0011 +WM_QUIT = 0x0012 +WM_QUERYOPEN = 0x0013 +WM_ERASEBKGND = 0x0014 +WM_SYSCOLORCHANGE = 0x0015 +WM_ENDSESSION = 0x0016 +WM_SHOWWINDOW = 0x0018 +WM_CTLCOLOR = 0x0019 +WM_WININICHANGE = 0x001A +WM_SETTINGCHANGE = 0x001A +WM_DEVMODECHANGE = 0x001B +WM_ACTIVATEAPP = 0x001C +WM_FONTCHANGE = 0x001D +WM_TIMECHANGE = 0x001E +WM_CANCELMODE = 0x001F +WM_SETCURSOR = 0x0020 +WM_MOUSEACTIVATE = 0x0021 +WM_CHILDACTIVATE = 0x0022 +WM_QUEUESYNC = 0x0023 +WM_GETMINMAXINFO = 0x0024 +WM_PAINTICON = 0x0026 +WM_ICONERASEBKGND = 0x0027 +WM_NEXTDLGCTL = 0x0028 +WM_SPOOLERSTATUS = 0x002A +WM_DRAWITEM = 0x002B +WM_MEASUREITEM = 0x002C +WM_DELETEITEM = 0x002D +WM_VKEYTOITEM = 0x002E +WM_CHARTOITEM = 0x002F +WM_SETFONT = 0x0030 +WM_GETFONT = 0x0031 +WM_SETHOTKEY = 0x0032 +WM_GETHOTKEY = 0x0033 +WM_QUERYDRAGICON = 0x0037 +WM_COMPAREITEM = 0x0039 +WM_GETOBJECT = 0x003D +WM_COMPACTING = 0x0041 +WM_COMMNOTIFY = 0x0044 +WM_WINDOWPOSCHANGING = 0x0046 +WM_WINDOWPOSCHANGED = 0x0047 +WM_POWER = 0x0048 +WM_COPYDATA = 0x004A +WM_CANCELJOURNAL = 0x004B +WM_NOTIFY = 0x004E +WM_INPUTLANGCHANGEREQUEST = 0x0050 +WM_INPUTLANGCHANGE = 0x0051 +WM_TCARD = 0x0052 +WM_HELP = 0x0053 +WM_USERCHANGED = 0x0054 +WM_NOTIFYFORMAT = 0x0055 +WM_CONTEXTMENU = 0x007B +WM_STYLECHANGING = 0x007C +WM_STYLECHANGED = 0x007D +WM_DISPLAYCHANGE = 0x007E +WM_GETICON = 0x007F +WM_SETICON = 0x0080 +WM_NCCREATE = 0x0081 +WM_NCDESTROY = 0x0082 +WM_NCCALCSIZE = 0x0083 +WM_NCHITTEST = 0x0084 +WM_NCPAINT = 0x0085 +WM_NCACTIVATE = 0x0086 +WM_GETDLGCODE = 0x0087 +WM_SYNCPAINT = 0x0088 +WM_NCMOUSEMOVE = 0x00A0 +WM_NCLBUTTONDOWN = 0x00A1 +WM_NCLBUTTONUP = 0x00A2 +WM_NCLBUTTONDBLCLK = 0x00A3 +WM_NCRBUTTONDOWN = 0x00A4 +WM_NCRBUTTONUP = 0x00A5 +WM_NCRBUTTONDBLCLK = 0x00A6 +WM_NCMBUTTONDOWN = 0x00A7 +WM_NCMBUTTONUP = 0x00A8 +WM_NCMBUTTONDBLCLK = 0x00A9 +WM_KEYDOWN = 0x0100 +WM_KEYUP = 0x0101 +WM_CHAR = 0x0102 +WM_DEADCHAR = 0x0103 +WM_SYSKEYDOWN = 0x0104 +WM_SYSKEYUP = 0x0105 +WM_SYSCHAR = 0x0106 +WM_SYSDEADCHAR = 0x0107 +WM_KEYLAST = 0x0108 +WM_IME_STARTCOMPOSITION = 0x010D +WM_IME_ENDCOMPOSITION = 0x010E +WM_IME_COMPOSITION = 0x010F +WM_IME_KEYLAST = 0x010F +WM_INITDIALOG = 0x0110 +WM_COMMAND = 0x0111 +WM_SYSCOMMAND = 0x0112 +WM_TIMER = 0x0113 +WM_HSCROLL = 0x0114 +WM_VSCROLL = 0x0115 +WM_INITMENU = 0x0116 +WM_INITMENUPOPUP = 0x0117 +WM_MENUSELECT = 0x011F +WM_MENUCHAR = 0x0120 +WM_ENTERIDLE = 0x0121 +WM_MENURBUTTONUP = 0x0122 +WM_MENUDRAG = 0x0123 +WM_MENUGETOBJECT = 0x0124 +WM_UNINITMENUPOPUP = 0x0125 +WM_MENUCOMMAND = 0x0126 +WM_CTLCOLORMSGBOX = 0x0132 +WM_CTLCOLOREDIT = 0x0133 +WM_CTLCOLORLISTBOX = 0x0134 +WM_CTLCOLORBTN = 0x0135 +WM_CTLCOLORDLG = 0x0136 +WM_CTLCOLORSCROLLBAR = 0x0137 +WM_CTLCOLORSTATIC = 0x0138 +WM_MOUSEMOVE = 0x0200 +WM_LBUTTONDOWN = 0x0201 +WM_LBUTTONUP = 0x0202 +WM_LBUTTONDBLCLK = 0x0203 +WM_RBUTTONDOWN = 0x0204 +WM_RBUTTONUP = 0x0205 +WM_RBUTTONDBLCLK = 0x0206 +WM_MBUTTONDOWN = 0x0207 +WM_MBUTTONUP = 0x0208 +WM_MBUTTONDBLCLK = 0x0209 +WM_MOUSEWHEEL = 0x020A +WM_PARENTNOTIFY = 0x0210 +WM_ENTERMENULOOP = 0x0211 +WM_EXITMENULOOP = 0x0212 +WM_NEXTMENU = 0x0213 +WM_SIZING = 0x0214 +WM_CAPTURECHANGED = 0x0215 +WM_MOVING = 0x0216 +WM_DEVICECHANGE = 0x0219 +WM_MDICREATE = 0x0220 +WM_MDIDESTROY = 0x0221 +WM_MDIACTIVATE = 0x0222 +WM_MDIRESTORE = 0x0223 +WM_MDINEXT = 0x0224 +WM_MDIMAXIMIZE = 0x0225 +WM_MDITILE = 0x0226 +WM_MDICASCADE = 0x0227 +WM_MDIICONARRANGE = 0x0228 +WM_MDIGETACTIVE = 0x0229 +WM_MDISETMENU = 0x0230 +WM_ENTERSIZEMOVE = 0x0231 +WM_EXITSIZEMOVE = 0x0232 +WM_DROPFILES = 0x0233 +WM_MDIREFRESHMENU = 0x0234 +WM_IME_SETCONTEXT = 0x0281 +WM_IME_NOTIFY = 0x0282 +WM_IME_CONTROL = 0x0283 +WM_IME_COMPOSITIONFULL = 0x0284 +WM_IME_SELECT = 0x0285 +WM_IME_CHAR = 0x0286 +WM_IME_REQUEST = 0x0288 +WM_IME_KEYDOWN = 0x0290 +WM_IME_KEYUP = 0x0291 +WM_MOUSEHOVER = 0x02A1 +WM_MOUSELEAVE = 0x02A3 +WM_CUT = 0x0300 +WM_COPY = 0x0301 +WM_PASTE = 0x0302 +WM_CLEAR = 0x0303 +WM_UNDO = 0x0304 +WM_RENDERFORMAT = 0x0305 +WM_RENDERALLFORMATS = 0x0306 +WM_DESTROYCLIPBOARD = 0x0307 +WM_DRAWCLIPBOARD = 0x0308 +WM_PAINTCLIPBOARD = 0x0309 +WM_VSCROLLCLIPBOARD = 0x030A +WM_SIZECLIPBOARD = 0x030B +WM_ASKCBFORMATNAME = 0x030C +WM_CHANGECBCHAIN = 0x030D +WM_HSCROLLCLIPBOARD = 0x030E +WM_QUERYNEWPALETTE = 0x030F +WM_PALETTEISCHANGING = 0x0310 +WM_PALETTECHANGED = 0x0311 +WM_HOTKEY = 0x0312 +WM_PRINT = 0x0317 +WM_PRINTCLIENT = 0x0318 +WM_HANDHELDFIRST = 0x0358 +WM_HANDHELDLAST = 0x035F +WM_AFXFIRST = 0x0360 +WM_AFXLAST = 0x037F +WM_PENWINFIRST = 0x0380 +WM_PENWINLAST = 0x038F +WM_APP = 0x8000 +WM_USER = 0x0400 +WM_REFLECT = WM_USER + 0x1c00 + +class WNDCLASSEX(ctypes.Structure): + def __init__(self, *args, **kwargs): + super(WNDCLASSEX, self).__init__(*args, **kwargs) + self.cbSize = ctypes.sizeof(self) + _fields_ = [("cbSize", ctypes.c_uint), + ("style", ctypes.c_uint), + ("lpfnWndProc", WNDPROC), + ("cbClsExtra", ctypes.c_int), + ("cbWndExtra", ctypes.c_int), + ("hInstance", ctypes.wintypes.HANDLE), + ("hIcon", ctypes.wintypes.HANDLE), + ("hCursor", ctypes.wintypes.HANDLE), + ("hBrush", ctypes.wintypes.HANDLE), + ("lpszMenuName", ctypes.wintypes.LPCWSTR), + ("lpszClassName", ctypes.wintypes.LPCWSTR), + ("hIconSm", ctypes.wintypes.HANDLE)] + +UpdateWindow = ctypes.windll.user32.UpdateWindow +UpdateWindow.argtypes = [ctypes.wintypes.HWND] + +SW_HIDE = 0 +SW_SHOWNORMAL = 1 +SW_SHOW = 5 + +ShowWindow = ctypes.windll.user32.ShowWindow +ShowWindow.argtypes = [ctypes.wintypes.HWND, ctypes.c_int] + +CS_VREDRAW = 0x0001 +CS_HREDRAW = 0x0002 +CS_KEYCVTWINDOW = 0x0004 +CS_DBLCLKS = 0x0008 +CS_OWNDC = 0x0020 +CS_CLASSDC = 0x0040 +CS_PARENTDC = 0x0080 +CS_NOKEYCVT = 0x0100 +CS_NOCLOSE = 0x0200 +CS_SAVEBITS = 0x0800 +CS_BYTEALIGNCLIENT = 0x1000 +CS_BYTEALIGNWINDOW = 0x2000 +CS_GLOBALCLASS = 0x4000 + +COLOR_SCROLLBAR = 0 +COLOR_BACKGROUND = 1 +COLOR_ACTIVECAPTION = 2 +COLOR_INACTIVECAPTION = 3 +COLOR_MENU = 4 +COLOR_WINDOW = 5 +COLOR_WINDOWFRAME = 6 +COLOR_MENUTEXT = 7 +COLOR_WINDOWTEXT = 8 +COLOR_CAPTIONTEXT = 9 +COLOR_ACTIVEBORDER = 10 +COLOR_INACTIVEBORDER = 11 +COLOR_APPWORKSPACE = 12 +COLOR_HIGHLIGHT = 13 +COLOR_HIGHLIGHTTEXT = 14 +COLOR_BTNFACE = 15 +COLOR_BTNSHADOW = 16 +COLOR_GRAYTEXT = 17 +COLOR_BTNTEXT = 18 +COLOR_INACTIVECAPTIONTEXT = 19 +COLOR_BTNHIGHLIGHT = 20 + +LoadCursor = ctypes.windll.user32.LoadCursorW + +def GenerateDummyWindow(callback, uid): + newclass = WNDCLASSEX() + newclass.lpfnWndProc = callback + newclass.style = CS_VREDRAW | CS_HREDRAW + newclass.lpszClassName = uid.replace("-", "") + newclass.hBrush = COLOR_BACKGROUND + newclass.hCursor = LoadCursor(0, 32512) + ATOM = ctypes.windll.user32.RegisterClassExW(ctypes.byref(newclass)) + #print "ATOM", ATOM + #print "CLASS", newclass.lpszClassName + hwnd = ctypes.windll.user32.CreateWindowExW(0, + newclass.lpszClassName, + u"Dummy Window", + WS_OVERLAPPEDWINDOW | WS_SYSMENU, + ctypes.windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN), + ctypes.windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN), + 800, 600, 0, 0, 0, 0) + ShowWindow(hwnd, SW_SHOW) + UpdateWindow(hwnd) + ShowWindow(hwnd, SW_HIDE) + return hwnd + +# Message loop calls + +TIMERCALLBACK = ctypes.WINFUNCTYPE(None, + ctypes.wintypes.HWND, + ctypes.wintypes.UINT, + ctypes.POINTER(ctypes.wintypes.UINT), + ctypes.wintypes.DWORD) + +SetTimer = ctypes.windll.user32.SetTimer +SetTimer.restype = ctypes.POINTER(ctypes.wintypes.UINT) +SetTimer.argtypes = [ctypes.wintypes.HWND, + ctypes.POINTER(ctypes.wintypes.UINT), + ctypes.wintypes.UINT, + TIMERCALLBACK] + +KillTimer = ctypes.windll.user32.KillTimer +KillTimer.restype = ctypes.wintypes.BOOL +KillTimer.argtypes = [ctypes.wintypes.HWND, + ctypes.POINTER(ctypes.wintypes.UINT)] + +class MSG(ctypes.Structure): + _fields_ = [ ('HWND', ctypes.wintypes.HWND), + ('message', ctypes.wintypes.UINT), + ('wParam', ctypes.wintypes.WPARAM), + ('lParam', ctypes.wintypes.LPARAM), + ('time', ctypes.wintypes.DWORD), + ('pt', POINT)] + +GetMessage = ctypes.windll.user32.GetMessageW +GetMessage.restype = ctypes.wintypes.BOOL +GetMessage.argtypes = [ctypes.POINTER(MSG), ctypes.wintypes.HWND, ctypes.wintypes.UINT, ctypes.wintypes.UINT] + +TranslateMessage = ctypes.windll.user32.TranslateMessage +TranslateMessage.restype = ctypes.wintypes.ULONG +TranslateMessage.argtypes = [ctypes.POINTER(MSG)] + +DispatchMessage = ctypes.windll.user32.DispatchMessageW +DispatchMessage.restype = ctypes.wintypes.ULONG +DispatchMessage.argtypes = [ctypes.POINTER(MSG)] + +def LoadIcon(iconfilename, small=False): + return LoadImage(0, + unicode(iconfilename), + IMAGE_ICON, + 16 if small else 0, + 16 if small else 0, + LR_LOADFROMFILE) + + +class NotificationIcon(object): + def __init__(self, iconfilename, tooltip=None): + assert os.path.isfile(unicode(iconfilename)), "{} doesn't exist".format(iconfilename) + self._iconfile = unicode(iconfilename) + self._hicon = LoadIcon(self._iconfile, True) + assert self._hicon, "Failed to load {}".format(iconfilename) + #self._pumpqueue = Queue.Queue() + self._die = False + self._timerid = None + self._uid = uuid.uuid4() + self._tooltip = unicode(tooltip) if tooltip else u'' + #self._thread = threading.Thread(target=self._run) + #self._thread.start() + self._info_bubble = None + self.items = [] + + + def _bubble(self, iconinfo): + if self._info_bubble: + info_bubble = self._info_bubble + self._info_bubble = None + message = unicode(self._info_bubble) + iconinfo.uFlags |= NIF_INFO + iconinfo.szInfo = message + iconinfo.szInfoTitle = message + iconinfo.dwInfoFlags = NIIF_INFO + iconinfo.union.uTimeout = 10000 + Shell_NotifyIcon(NIM_MODIFY, ctypes.pointer(iconinfo)) + + + def _run(self): + self._windowproc = WNDPROC(self._callback) + self._hwnd = GenerateDummyWindow(self._windowproc, str(self._uid)) + + iconinfo = NOTIFYICONDATA() + iconinfo.hWnd = self._hwnd + iconinfo.uID = 100 + iconinfo.uFlags = NIF_ICON | NIF_SHOWTIP | NIF_MESSAGE | (NIF_TIP if self._tooltip else 0) + iconinfo.uCallbackMessage = WM_MENUCOMMAND + iconinfo.hIcon = self._hicon + iconinfo.szTip = self._tooltip + iconinfo.dwState = NIS_SHAREDICON + iconinfo.dwInfoFlags = NIIF_INFO + # iconinfo.dwStateMask = NIS_SHAREDICON + iconinfo.szInfo = "Application Title" + iconinfo.union.uTimeout = 5000 + + Shell_NotifyIcon(NIM_ADD, ctypes.pointer(iconinfo)) + + iconinfo.union.uVersion = NOTIFYICON_VERSION + self.iconinfo = iconinfo + + Shell_NotifyIcon(NIM_SETVERSION, ctypes.pointer(iconinfo)) + + PostMessage(self._hwnd, WM_NULL, 0, 0) + + #self._timerid = SetTimer(self._hwnd, self._timerid, 25, TIMERCALLBACK()) + message = MSG() + last_time = -1 + ret = None + while not self._die: + ret = GetMessage(ctypes.pointer(message), 0, 0, 0) + TranslateMessage(ctypes.pointer(message)) + DispatchMessage(ctypes.pointer(message)) + time.sleep(0.125) + #KillTimer(self._hwnd, self._timerid) + + Shell_NotifyIcon(NIM_DELETE, ctypes.pointer(iconinfo)) + ctypes.windll.user32.DestroyWindow(self._hwnd) + ctypes.windll.user32.DestroyIcon(self._hicon) + + + def _menu(self): + if not hasattr(self, 'items'): + return + + menu = CreatePopupMenu() + func = None + + try: + iidx = 1000 + defaultitem = -1 + item_map = {} + for fs in self.items: + iidx += 1 + if isinstance(fs, basestring): + if fs and not fs.strip('-_='): + AppendMenu(menu, MF_SEPARATOR, iidx, fs) + else: + AppendMenu(menu, MF_STRING | MF_GRAYED, iidx, fs) + elif isinstance(fs, tuple): + if callable(fs[0]): + itemstring = fs[0]() + else: + itemstring = unicode(fs[0]) + flags = MF_STRING + if itemstring.startswith("!"): + itemstring = itemstring[1:] + defaultitem = iidx + if itemstring.startswith("+"): + itemstring = itemstring[1:] + flags = flags | MF_CHECKED + itemcallable = fs[1] + item_map[iidx] = itemcallable + if itemcallable is False: + flags = flags | MF_DISABLED + elif not callable(itemcallable): + flags = flags | MF_GRAYED + AppendMenu(menu, flags, iidx, itemstring) + + if defaultitem != -1: + SetMenuDefaultItem(menu, defaultitem, 0) + + pos = POINT() + GetCursorPos(ctypes.pointer(pos)) + + PostMessage(self._hwnd, WM_NULL, 0, 0) + + SetForegroundWindow(self._hwnd) + + ti = TrackPopupMenu(menu, TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, pos.x, pos.y, 0, self._hwnd, None) + + if ti in item_map: + func = item_map[ti] + + PostMessage(self._hwnd, WM_NULL, 0, 0) + finally: + DestroyMenu(menu) + if func: func() + + + def clicked(self): + self._menu() + + + + def _callback(self, hWnd, msg, wParam, lParam): + # Check if the main thread is still alive + if msg == WM_TIMER: + if not any(thread.getName() == 'MainThread' and thread.isAlive() + for thread in threading.enumerate()): + self._die = True + elif msg == WM_MENUCOMMAND and lParam == WM_LBUTTONUP: + self.clicked() + elif msg == WM_MENUCOMMAND and lParam == WM_RBUTTONUP: + self._menu() + else: + return DefWindowProc(hWnd, msg, wParam, lParam) + return 1 + + + def die(self): + try: + Shell_NotifyIcon(NIM_DELETE, ctypes.pointer(self.iconinfo)) + except: + pass + ctypes.windll.user32.DestroyWindow(self._hwnd) + ctypes.windll.user32.DestroyIcon(self._hicon) + self._die = True + + + def pump(self): + try: + while not self._pumpqueue.empty(): + callable = self._pumpqueue.get(False) + callable() + except Queue.Empty: + pass + + + def announce(self, text): + self._info_bubble = text + + +def hideConsole(): + ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0) + +def showConsole(): + ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 1) + +if __name__ == "__main__": + import time + def greet(): + ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0) + print "Hello" + def quit(): + ni._die = True + #sys.exit() + def announce(): + ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 1) + ni.announce("Hello there") + + def clicked(): + ni.announce("Hello") + + def dynamicTitle(): + return "!The time is: %s" % time.time() + + ni = NotificationIcon(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../trayicon.ico'), "ZeroNet 0.2.9") + ni.items = [ + (dynamicTitle, False), + ('Hello', greet), + ('Title', False), + ('!Default', greet), + ('+Popup bubble', announce), + 'Nothing', + '--', + ('Quit', quit) + ] + ni.clicked = clicked + import atexit + @atexit.register + def goodbye(): + print "You are now leaving the Python sector." + + ni._run() diff --git a/plugins/Trayicon/lib/winfolders.py b/plugins/Trayicon/lib/winfolders.py new file mode 100644 index 00000000..0e390fad --- /dev/null +++ b/plugins/Trayicon/lib/winfolders.py @@ -0,0 +1,48 @@ +''' Get windows special folders without pythonwin + Example: + import specialfolders + start_programs = specialfolders.get(specialfolders.PROGRAMS) + +Code is public domain, do with it what you will. + +Luke Pinner - Environment.gov.au, 2010 February 10 +''' + +#Imports use _syntax to mask them from autocomplete IDE's +import ctypes as _ctypes +from ctypes.wintypes import HWND as _HWND, HANDLE as _HANDLE,DWORD as _DWORD,LPCWSTR as _LPCWSTR,MAX_PATH as _MAX_PATH, create_unicode_buffer as _cub +_SHGetFolderPath = _ctypes.windll.shell32.SHGetFolderPathW + +#public special folder constants +DESKTOP= 0 +PROGRAMS= 2 +MYDOCUMENTS= 5 +FAVORITES= 6 +STARTUP= 7 +RECENT= 8 +SENDTO= 9 +STARTMENU= 11 +MYMUSIC= 13 +MYVIDEOS= 14 +NETHOOD= 19 +FONTS= 20 +TEMPLATES= 21 +ALLUSERSSTARTMENU= 22 +ALLUSERSPROGRAMS= 23 +ALLUSERSSTARTUP= 24 +ALLUSERSDESKTOP= 25 +APPLICATIONDATA= 26 +PRINTHOOD= 27 +LOCALSETTINGSAPPLICATIONDATA= 28 +ALLUSERSFAVORITES= 31 +LOCALSETTINGSTEMPORARYINTERNETFILES=32 +COOKIES= 33 +LOCALSETTINGSHISTORY= 34 +ALLUSERSAPPLICATIONDATA= 35 + +def get(intFolder): + _SHGetFolderPath.argtypes = [_HWND, _ctypes.c_int, _HANDLE, _DWORD, _LPCWSTR] + auPathBuffer = _cub(_MAX_PATH) + exit_code=_SHGetFolderPath(0, intFolder, 0, 0, auPathBuffer) + return auPathBuffer.value + diff --git a/plugins/Trayicon/trayicon.ico b/plugins/Trayicon/trayicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fad67073e655e317d7283fc04dbd3b383a98ad2a GIT binary patch literal 1150 zcmbVMyGjE=6upbW5^Pf0YAJ-^2h30S3wG9ifqsC9g@k|~V7E=IL`V>9tVA#f7O}C= zM$w=s&h?y`osiv`En=3Fo!mR;&bg0?NQS4~7JRSE&a%j=h-?5b!Q$pQ;BH_~jcpVV6Qz&a719MOEvV4gk)^X9=!Z=T7BJ@V?eWCb`IPNn|hcsQ*WV-@(tl ").lower() == "yes": break + else: logging.info("Please, secure it now, you going to need it to modify your site!") + + logging.info("Creating directory structure...") + from Site import Site + os.mkdir("data/%s" % address) + open("data/%s/index.html" % address, "w").write("Hello %s!" % address) + + logging.info("Creating content.json...") + site = Site(address) + site.content_manager.sign(privatekey=privatekey) + site.settings["own"] = True + site.saveSettings() + + logging.info("Site created!") + + + def siteSign(self, address, privatekey=None, inner_path="content.json"): + from Site import Site + logging.info("Signing site: %s..." % address) + site = Site(address, allow_create = False) + + if not privatekey: # If no privatekey in args then ask it now + import getpass + privatekey = getpass.getpass("Private key (input hidden):") + site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True) + + + def siteVerify(self, address): + from Site import Site + logging.info("Verifing site: %s..." % address) + site = Site(address) + + for content_inner_path in site.content_manager.contents: + logging.info("Verifing %s signature..." % content_inner_path) + if site.content_manager.verifyFile(content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False) == True: + logging.info("[OK] %s signed by address %s!" % (content_inner_path, address)) + else: + logging.error("[ERROR] %s not signed by address %s!" % (content_inner_path, address)) + + logging.info("Verifying site files...") + bad_files = site.storage.verifyFiles() + if not bad_files: + logging.info("[OK] All file sha512sum matches!") + else: + logging.error("[ERROR] Error during verifying site files!") + + + def dbRebuild(self, address): + from Site import Site + logging.info("Rebuilding site sql cache: %s..." % address) + site = Site(address) + s = time.time() + site.storage.rebuildDb() + logging.info("Done in %.3fs" % (time.time()-s)) + + + def dbQuery(self, address, query): + from Site import Site + import json + site = Site(address) + result = [] + for row in site.storage.query(query): + result.append(dict(row)) + print json.dumps(result, indent=4) + + + def siteAnnounce(self, address): + from Site.Site import Site + logging.info("Announcing site %s to tracker..." % address) + site = Site(address) + + s = time.time() + site.announce() + print "Response time: %.3fs" % (time.time()-s) + print site.peers + + + def siteNeedFile(self, address, inner_path): + from Site import Site + site = Site(address) + site.announce() + print site.needFile(inner_path, update=True) + + + def sitePublish(self, address, peer_ip=None, peer_port=15441, inner_path="content.json"): + global file_server + from Site import Site + from File import FileServer # We need fileserver to handle incoming file requests + + logging.info("Creating FileServer....") + file_server = FileServer() + file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity + file_server.openport() + if file_server.port_opened == False: + logging.info("Port not opened, passive publishing not supported yet :(") + return + site = file_server.sites[address] + site.settings["serving"] = True # Serving the site even if its disabled + if peer_ip: # Announce ip specificed + site.addPeer(peer_ip, peer_port) + else: # Just ask the tracker + logging.info("Gathering peers from tracker") + site.announce() # Gather peers + site.publish(20, inner_path) # Push to 20 peers + time.sleep(3) + logging.info("Serving files...") + gevent.joinall([file_server_thread]) + logging.info("Done.") + + + + # Crypto commands + + def cryptoPrivatekeyToAddress(self, privatekey=None): + from Crypt import CryptBitcoin + if not privatekey: # If no privatekey in args then ask it now + import getpass + privatekey = getpass.getpass("Private key (input hidden):") + + print CryptBitcoin.privatekeyToAddress(privatekey) + + + # Peer + + def peerPing(self, peer_ip, peer_port): + logging.info("Opening a simple connection server") + global file_server + from Connection import ConnectionServer + file_server = ConnectionServer("127.0.0.1", 1234) + + from Peer import Peer + logging.info("Pinging 5 times peer: %s:%s..." % (peer_ip, int(peer_port))) + peer = Peer(peer_ip, peer_port) + for i in range(5): + s = time.time() + print peer.ping(), + print "Response time: %.3fs" % (time.time()-s) + time.sleep(1) + + + def peerGetFile(self, peer_ip, peer_port, site, filename): + logging.info("Opening a simple connection server") + global file_server + from Connection import ConnectionServer + file_server = ConnectionServer() + + from Peer import Peer + logging.info("Getting %s/%s from peer: %s:%s..." % (site, filename, peer_ip, peer_port)) + peer = Peer(peer_ip, peer_port) + s = time.time() + print peer.getFile(site, filename).read() + print "Response time: %.3fs" % (time.time()-s) + +actions = Actions() # Starts here when running zeronet.py def start(): - action_func = globals()[config.action] # Function reference - action_kwargs = config.getActionArguments() # non-config arguments when calling zeronet.py - - action_func(**action_kwargs) - - -# Start serving UiServer and PeerServer -def main(): - logging.info("Version: %s, Python %s, Gevent: %s" % (config.version, sys.version, gevent.__version__)) - global ui_server, file_server - from File import FileServer - from Ui import UiServer - logging.info("Creating UiServer....") - ui_server = UiServer() - - logging.info("Creating FileServer....") - file_server = FileServer() - - logging.info("Starting servers....") - gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)]) - - -# Site commands - -def siteCreate(): - logging.info("Generating new privatekey...") - from Crypt import CryptBitcoin - privatekey = CryptBitcoin.newPrivatekey() - logging.info("----------------------------------------------------------------------") - logging.info("Site private key: %s" % privatekey) - logging.info(" !!! ^ Save it now, required to modify the site ^ !!!") - address = CryptBitcoin.privatekeyToAddress(privatekey) - logging.info("Site address: %s" % address) - logging.info("----------------------------------------------------------------------") - - while True: - if raw_input("? Have you secured your private key? (yes, no) > ").lower() == "yes": break - else: logging.info("Please, secure it now, you going to need it to modify your site!") - - logging.info("Creating directory structure...") - from Site import Site - os.mkdir("data/%s" % address) - open("data/%s/index.html" % address, "w").write("Hello %s!" % address) - - logging.info("Creating content.json...") - site = Site(address) - site.content_manager.sign(privatekey=privatekey) - site.settings["own"] = True - site.saveSettings() - - logging.info("Site created!") - - -def siteSign(address, privatekey=None, inner_path="content.json"): - from Site import Site - logging.info("Signing site: %s..." % address) - site = Site(address, allow_create = False) - - if not privatekey: # If no privatekey in args then ask it now - import getpass - privatekey = getpass.getpass("Private key (input hidden):") - site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True) - - -def siteVerify(address): - from Site import Site - logging.info("Verifing site: %s..." % address) - site = Site(address) - - for content_inner_path in site.content_manager.contents: - logging.info("Verifing %s signature..." % content_inner_path) - if site.content_manager.verifyFile(content_inner_path, site.storage.open(content_inner_path, "rb"), ignore_same=False) == True: - logging.info("[OK] %s signed by address %s!" % (content_inner_path, address)) - else: - logging.error("[ERROR] %s not signed by address %s!" % (content_inner_path, address)) - - logging.info("Verifying site files...") - bad_files = site.storage.verifyFiles() - if not bad_files: - logging.info("[OK] All file sha512sum matches!") - else: - logging.error("[ERROR] Error during verifying site files!") - - -def dbRebuild(address): - from Site import Site - logging.info("Rebuilding site sql cache: %s..." % address) - site = Site(address) - s = time.time() - site.storage.rebuildDb() - logging.info("Done in %.3fs" % (time.time()-s)) - - -def dbQuery(address, query): - from Site import Site - import json - site = Site(address) - result = [] - for row in site.storage.query(query): - result.append(dict(row)) - print json.dumps(result, indent=4) - - -def siteAnnounce(address): - from Site.Site import Site - logging.info("Announcing site %s to tracker..." % address) - site = Site(address) - - s = time.time() - site.announce() - print "Response time: %.3fs" % (time.time()-s) - print site.peers - - -def siteNeedFile(address, inner_path): - from Site import Site - site = Site(address) - site.announce() - print site.needFile(inner_path, update=True) - - -def sitePublish(address, peer_ip=None, peer_port=15441, inner_path="content.json"): - global file_server - from Site import Site - from File import FileServer # We need fileserver to handle incoming file requests - - logging.info("Creating FileServer....") - file_server = FileServer() - file_server_thread = gevent.spawn(file_server.start, check_sites=False) # Dont check every site integrity - file_server.openport() - if file_server.port_opened == False: - logging.info("Port not opened, passive publishing not supported yet :(") - return - site = file_server.sites[address] - site.settings["serving"] = True # Serving the site even if its disabled - if peer_ip: # Announce ip specificed - site.addPeer(peer_ip, peer_port) - else: # Just ask the tracker - logging.info("Gathering peers from tracker") - site.announce() # Gather peers - site.publish(20, inner_path) # Push to 20 peers - time.sleep(3) - logging.info("Serving files...") - gevent.joinall([file_server_thread]) - logging.info("Done.") - - - -# Crypto commands - -def cryptoPrivatekeyToAddress(privatekey=None): - from Crypt import CryptBitcoin - if not privatekey: # If no privatekey in args then ask it now - import getpass - privatekey = getpass.getpass("Private key (input hidden):") - - print CryptBitcoin.privatekeyToAddress(privatekey) - - -# Peer - -def peerPing(peer_ip, peer_port): - logging.info("Opening a simple connection server") - global file_server - from Connection import ConnectionServer - file_server = ConnectionServer("127.0.0.1", 1234) - - from Peer import Peer - logging.info("Pinging 5 times peer: %s:%s..." % (peer_ip, int(peer_port))) - peer = Peer(peer_ip, peer_port) - for i in range(5): - s = time.time() - print peer.ping(), - print "Response time: %.3fs" % (time.time()-s) - time.sleep(1) - - -def peerGetFile(peer_ip, peer_port, site, filename): - logging.info("Opening a simple connection server") - global file_server - from Connection import ConnectionServer - file_server = ConnectionServer() - - from Peer import Peer - logging.info("Getting %s/%s from peer: %s:%s..." % (site, filename, peer_ip, peer_port)) - peer = Peer(peer_ip, peer_port) - s = time.time() - print peer.getFile(site, filename).read() - print "Response time: %.3fs" % (time.time()-s) - + # Call function + func = getattr(actions, config.action, None) + action_kwargs = config.getActionArguments() + func(**action_kwargs)