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
This commit is contained in:
parent
804fed2659
commit
30281c8fb5
14 changed files with 1170 additions and 207 deletions
|
@ -53,12 +53,14 @@ class UiRequestPlugin(object):
|
||||||
|
|
||||||
# Memory
|
# Memory
|
||||||
try:
|
try:
|
||||||
yield "Ip external: %s | " % config.ip_external
|
yield "IP external: %s | " % config.ip_external
|
||||||
yield "Port opened: %s | " % main.file_server.port_opened
|
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
|
import psutil
|
||||||
process = psutil.Process(os.getpid())
|
process = psutil.Process(os.getpid())
|
||||||
mem = process.get_memory_info()[0] / float(2 ** 20)
|
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 "Threads: %s | " % len(process.threads())
|
||||||
yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times()
|
yield "CPU: usr %.2fs sys %.2fs | " % process.cpu_times()
|
||||||
yield "Open files: %s | " % len(process.open_files())
|
yield "Open files: %s | " % len(process.open_files())
|
||||||
|
@ -69,7 +71,7 @@ class UiRequestPlugin(object):
|
||||||
yield "<br>"
|
yield "<br>"
|
||||||
|
|
||||||
# Connections
|
# Connections
|
||||||
yield "<b>Connections</b> (%s):<br>" % len(main.file_server.connections)
|
yield "<b>Connections</b> (%s, total made: %s):<br>" % (len(main.file_server.connections), main.file_server.last_connection_id)
|
||||||
yield "<table><tr> <th>id</th> <th>protocol</th> <th>type</th> <th>ip</th> <th>open</th> <th>ping</th> <th>buff</th>"
|
yield "<table><tr> <th>id</th> <th>protocol</th> <th>type</th> <th>ip</th> <th>open</th> <th>ping</th> <th>buff</th>"
|
||||||
yield "<th>idle</th> <th>open</th> <th>delay</th> <th>sent</th> <th>received</th> <th>last sent</th> <th>waiting</th> <th>version</th> <th>peerid</th> </tr>"
|
yield "<th>idle</th> <th>open</th> <th>delay</th> <th>sent</th> <th>received</th> <th>last sent</th> <th>waiting</th> <th>version</th> <th>peerid</th> </tr>"
|
||||||
for connection in main.file_server.connections:
|
for connection in main.file_server.connections:
|
||||||
|
@ -100,11 +102,15 @@ class UiRequestPlugin(object):
|
||||||
yield "<tr><th>address</th> <th>connected</th> <th>peers</th> <th>content.json</th> </tr>"
|
yield "<tr><th>address</th> <th>connected</th> <th>peers</th> <th>content.json</th> </tr>"
|
||||||
for site in self.server.sites.values():
|
for site in self.server.sites.values():
|
||||||
yield self.formatTableRow([
|
yield self.formatTableRow([
|
||||||
("%s", site.address),
|
("<a href='#ShowPeers' onclick='document.getElementById(\"peers_%s\").style.display=\"initial\"; return false'>%s</a>", (site.address, site.address)),
|
||||||
("%s", [peer.connection.id for peer in site.peers.values() if peer.connection and peer.connection.connected]),
|
("%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/%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)),
|
("%s", len(site.content_manager.contents)),
|
||||||
])
|
])
|
||||||
|
yield "<tr><td id='peers_%s' style='display: none'>" % site.address
|
||||||
|
for key, peer in site.peers.items():
|
||||||
|
yield "(%s) %s -<br>" % (peer.connection, key)
|
||||||
|
yield "<br></td></tr>"
|
||||||
yield "</table>"
|
yield "</table>"
|
||||||
|
|
||||||
|
|
||||||
|
|
91
plugins/Trayicon/TrayiconPlugin.py
Normal file
91
plugins/Trayicon/TrayiconPlugin.py
Normal file
|
@ -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
|
4
plugins/Trayicon/__init__.py
Normal file
4
plugins/Trayicon/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
import TrayiconPlugin
|
0
plugins/Trayicon/lib/__init__.py
Normal file
0
plugins/Trayicon/lib/__init__.py
Normal file
800
plugins/Trayicon/lib/notificationicon.py
Normal file
800
plugins/Trayicon/lib/notificationicon.py
Normal file
|
@ -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()
|
48
plugins/Trayicon/lib/winfolders.py
Normal file
48
plugins/Trayicon/lib/winfolders.py
Normal file
|
@ -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
|
||||||
|
|
BIN
plugins/Trayicon/trayicon.ico
Normal file
BIN
plugins/Trayicon/trayicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -162,6 +162,7 @@ class Connection:
|
||||||
self.last_recv_time = time.time()
|
self.last_recv_time = time.time()
|
||||||
self.incomplete_buff_recv += 1
|
self.incomplete_buff_recv += 1
|
||||||
self.bytes_recv += len(buff)
|
self.bytes_recv += len(buff)
|
||||||
|
self.server.bytes_recv += len(buff)
|
||||||
if not self.unpacker:
|
if not self.unpacker:
|
||||||
self.unpacker = msgpack.Unpacker()
|
self.unpacker = msgpack.Unpacker()
|
||||||
self.unpacker.feed(buff)
|
self.unpacker.feed(buff)
|
||||||
|
@ -198,12 +199,18 @@ class Connection:
|
||||||
if config.debug_socket: self.log("Got handshake response: %s, ping: %s" % (message, ping))
|
if config.debug_socket: self.log("Got handshake response: %s, ping: %s" % (message, ping))
|
||||||
self.last_ping_delay = ping
|
self.last_ping_delay = ping
|
||||||
self.handshake = message
|
self.handshake = message
|
||||||
|
if self.handshake.get("port_opened", None) == False: # Not connectable
|
||||||
|
self.port = 0
|
||||||
|
else:
|
||||||
self.port = message["fileserver_port"] # Set peer fileserver port
|
self.port = message["fileserver_port"] # Set peer fileserver port
|
||||||
else:
|
else:
|
||||||
self.log("Unknown response: %s" % message)
|
self.log("Unknown response: %s" % message)
|
||||||
elif message.get("cmd"): # Handhsake request
|
elif message.get("cmd"): # Handhsake request
|
||||||
if message["cmd"] == "handshake":
|
if message["cmd"] == "handshake":
|
||||||
self.handshake = message["params"]
|
self.handshake = message["params"]
|
||||||
|
if self.handshake.get("port_opened", None) == False: # Not connectable
|
||||||
|
self.port = 0
|
||||||
|
else:
|
||||||
self.port = self.handshake["fileserver_port"] # Set peer fileserver port
|
self.port = self.handshake["fileserver_port"] # Set peer fileserver port
|
||||||
if config.debug_socket: self.log("Handshake request: %s" % message)
|
if config.debug_socket: self.log("Handshake request: %s" % message)
|
||||||
data = self.handshakeInfo()
|
data = self.handshakeInfo()
|
||||||
|
@ -242,6 +249,7 @@ class Connection:
|
||||||
else: # Normal connection
|
else: # Normal connection
|
||||||
data = msgpack.packb(message)
|
data = msgpack.packb(message)
|
||||||
self.bytes_sent += len(data)
|
self.bytes_sent += len(data)
|
||||||
|
self.server.bytes_sent += len(data)
|
||||||
self.sock.sendall(data)
|
self.sock.sendall(data)
|
||||||
self.last_sent_time = time.time()
|
self.last_sent_time = time.time()
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -22,6 +22,9 @@ class ConnectionServer:
|
||||||
self.running = True
|
self.running = True
|
||||||
self.thread_checker = gevent.spawn(self.checkConnections)
|
self.thread_checker = gevent.spawn(self.checkConnections)
|
||||||
|
|
||||||
|
self.bytes_recv = 0
|
||||||
|
self.bytes_sent = 0
|
||||||
|
|
||||||
self.zmq_running = False
|
self.zmq_running = False
|
||||||
self.zmq_last_connection = None # Last incoming message client
|
self.zmq_last_connection = None # Last incoming message client
|
||||||
|
|
||||||
|
@ -82,6 +85,8 @@ class ConnectionServer:
|
||||||
return connection
|
return connection
|
||||||
|
|
||||||
# No connection found
|
# No connection found
|
||||||
|
if port == 0:
|
||||||
|
raise Exception("This peer is not connectable")
|
||||||
try:
|
try:
|
||||||
connection = Connection(self, ip, port)
|
connection = Connection(self, ip, port)
|
||||||
self.ips[ip] = connection
|
self.ips[ip] = connection
|
||||||
|
|
|
@ -131,10 +131,10 @@ class FileRequest:
|
||||||
address = self.unpackAddress(peer)
|
address = self.unpackAddress(peer)
|
||||||
got_peer_keys.append("%s:%s" % address)
|
got_peer_keys.append("%s:%s" % address)
|
||||||
if (site.addPeer(*address)): added += 1
|
if (site.addPeer(*address)): added += 1
|
||||||
# Send back peers that is not in the sent list
|
# Send back peers that is not in the sent list and connectable (not port 0)
|
||||||
peers = site.peers.values()
|
peers = site.peers.values()
|
||||||
random.shuffle(peers)
|
random.shuffle(peers)
|
||||||
packed_peers = [peer.packAddress() for peer in peers if peer.key not in got_peer_keys][0:params["need"]]
|
packed_peers = [peer.packAddress() for peer in peers if not peer.key.endswith(":0") and peer.key not in got_peer_keys][0:params["need"]]
|
||||||
if added:
|
if added:
|
||||||
self.log.debug("Added %s peers to %s using pex, sending back %s" % (added, site, len(packed_peers)))
|
self.log.debug("Added %s peers to %s using pex, sending back %s" % (added, site, len(packed_peers)))
|
||||||
self.response({"peers": packed_peers})
|
self.response({"peers": packed_peers})
|
||||||
|
|
|
@ -150,7 +150,7 @@ class Peer:
|
||||||
if not site: site = self.site # If no site definied request peers for this site
|
if not site: site = self.site # If no site definied request peers for this site
|
||||||
peers = self.site.peers.values()
|
peers = self.site.peers.values()
|
||||||
random.shuffle(peers)
|
random.shuffle(peers)
|
||||||
packed_peers = [peer.packAddress() for peer in peers][0:need_num]
|
packed_peers = [peer.packAddress() for peer in peers if not peer.key.endswith(":0")][0:need_num]
|
||||||
response = self.request("pex", {"site": site.address, "peers": packed_peers, "need": need_num})
|
response = self.request("pex", {"site": site.address, "peers": packed_peers, "need": need_num})
|
||||||
if not response or "error" in response:
|
if not response or "error" in response:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -319,11 +319,10 @@ class Site:
|
||||||
address_hash = hashlib.sha1(self.address).hexdigest()
|
address_hash = hashlib.sha1(self.address).hexdigest()
|
||||||
my_peer_id = sys.modules["main"].file_server.peer_id
|
my_peer_id = sys.modules["main"].file_server.peer_id
|
||||||
|
|
||||||
# Later, if we have peer exchange
|
if sys.modules["main"].file_server.port_opened:
|
||||||
"""if sys.modules["main"].file_server.port_opened:
|
|
||||||
fileserver_port = config.fileserver_port
|
fileserver_port = config.fileserver_port
|
||||||
else: # Port not opened, report port 0
|
else: # Port not opened, report port 0
|
||||||
fileserver_port = 0"""
|
fileserver_port = 0
|
||||||
|
|
||||||
fileserver_port = config.fileserver_port
|
fileserver_port = config.fileserver_port
|
||||||
s = time.time()
|
s = time.time()
|
||||||
|
|
|
@ -112,7 +112,9 @@ class UiServer:
|
||||||
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
self.log.debug("Stopping...")
|
||||||
# Close WS sockets
|
# Close WS sockets
|
||||||
|
if "clients" in dir(self.server):
|
||||||
for client in self.server.clients.values():
|
for client in self.server.clients.values():
|
||||||
client.ws.close()
|
client.ws.close()
|
||||||
# Close http sockets
|
# Close http sockets
|
||||||
|
|
52
src/main.py
52
src/main.py
|
@ -35,11 +35,10 @@ logging.getLogger('').name = "-" # Remove root prefix
|
||||||
from Debug import DebugHook
|
from Debug import DebugHook
|
||||||
if config.debug:
|
if config.debug:
|
||||||
console_log.setLevel(logging.DEBUG) # Display everything to console
|
console_log.setLevel(logging.DEBUG) # Display everything to console
|
||||||
from gevent import monkey; monkey.patch_all(thread=False) # thread=False because of pyfilesystem
|
|
||||||
else:
|
else:
|
||||||
console_log.setLevel(logging.INFO) # Display only important info to console
|
console_log.setLevel(logging.INFO) # Display only important info to console
|
||||||
from gevent import monkey; monkey.patch_all() # Make time, thread, socket gevent compatible
|
|
||||||
|
|
||||||
|
from gevent import monkey; monkey.patch_all(thread=False) # Make time, socket gevent compatible
|
||||||
import gevent
|
import gevent
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -64,16 +63,10 @@ PluginManager.plugin_manager.loadPlugins()
|
||||||
|
|
||||||
# -- Actions --
|
# -- Actions --
|
||||||
|
|
||||||
# Starts here when running zeronet.py
|
@PluginManager.acceptPlugins
|
||||||
def start():
|
class Actions:
|
||||||
action_func = globals()[config.action] # Function reference
|
# Default action: Start serving UiServer and FileServer
|
||||||
action_kwargs = config.getActionArguments() # non-config arguments when calling zeronet.py
|
def main(self):
|
||||||
|
|
||||||
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__))
|
logging.info("Version: %s, Python %s, Gevent: %s" % (config.version, sys.version, gevent.__version__))
|
||||||
global ui_server, file_server
|
global ui_server, file_server
|
||||||
from File import FileServer
|
from File import FileServer
|
||||||
|
@ -88,9 +81,9 @@ def main():
|
||||||
gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)])
|
gevent.joinall([gevent.spawn(ui_server.start), gevent.spawn(file_server.start)])
|
||||||
|
|
||||||
|
|
||||||
# Site commands
|
# Site commands
|
||||||
|
|
||||||
def siteCreate():
|
def siteCreate(self):
|
||||||
logging.info("Generating new privatekey...")
|
logging.info("Generating new privatekey...")
|
||||||
from Crypt import CryptBitcoin
|
from Crypt import CryptBitcoin
|
||||||
privatekey = CryptBitcoin.newPrivatekey()
|
privatekey = CryptBitcoin.newPrivatekey()
|
||||||
|
@ -119,7 +112,7 @@ def siteCreate():
|
||||||
logging.info("Site created!")
|
logging.info("Site created!")
|
||||||
|
|
||||||
|
|
||||||
def siteSign(address, privatekey=None, inner_path="content.json"):
|
def siteSign(self, address, privatekey=None, inner_path="content.json"):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
logging.info("Signing site: %s..." % address)
|
logging.info("Signing site: %s..." % address)
|
||||||
site = Site(address, allow_create = False)
|
site = Site(address, allow_create = False)
|
||||||
|
@ -130,7 +123,7 @@ def siteSign(address, privatekey=None, inner_path="content.json"):
|
||||||
site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True)
|
site.content_manager.sign(inner_path=inner_path, privatekey=privatekey, update_changed_files=True)
|
||||||
|
|
||||||
|
|
||||||
def siteVerify(address):
|
def siteVerify(self, address):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
logging.info("Verifing site: %s..." % address)
|
logging.info("Verifing site: %s..." % address)
|
||||||
site = Site(address)
|
site = Site(address)
|
||||||
|
@ -150,7 +143,7 @@ def siteVerify(address):
|
||||||
logging.error("[ERROR] Error during verifying site files!")
|
logging.error("[ERROR] Error during verifying site files!")
|
||||||
|
|
||||||
|
|
||||||
def dbRebuild(address):
|
def dbRebuild(self, address):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
logging.info("Rebuilding site sql cache: %s..." % address)
|
logging.info("Rebuilding site sql cache: %s..." % address)
|
||||||
site = Site(address)
|
site = Site(address)
|
||||||
|
@ -159,7 +152,7 @@ def dbRebuild(address):
|
||||||
logging.info("Done in %.3fs" % (time.time()-s))
|
logging.info("Done in %.3fs" % (time.time()-s))
|
||||||
|
|
||||||
|
|
||||||
def dbQuery(address, query):
|
def dbQuery(self, address, query):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
import json
|
import json
|
||||||
site = Site(address)
|
site = Site(address)
|
||||||
|
@ -169,7 +162,7 @@ def dbQuery(address, query):
|
||||||
print json.dumps(result, indent=4)
|
print json.dumps(result, indent=4)
|
||||||
|
|
||||||
|
|
||||||
def siteAnnounce(address):
|
def siteAnnounce(self, address):
|
||||||
from Site.Site import Site
|
from Site.Site import Site
|
||||||
logging.info("Announcing site %s to tracker..." % address)
|
logging.info("Announcing site %s to tracker..." % address)
|
||||||
site = Site(address)
|
site = Site(address)
|
||||||
|
@ -180,14 +173,14 @@ def siteAnnounce(address):
|
||||||
print site.peers
|
print site.peers
|
||||||
|
|
||||||
|
|
||||||
def siteNeedFile(address, inner_path):
|
def siteNeedFile(self, address, inner_path):
|
||||||
from Site import Site
|
from Site import Site
|
||||||
site = Site(address)
|
site = Site(address)
|
||||||
site.announce()
|
site.announce()
|
||||||
print site.needFile(inner_path, update=True)
|
print site.needFile(inner_path, update=True)
|
||||||
|
|
||||||
|
|
||||||
def sitePublish(address, peer_ip=None, peer_port=15441, inner_path="content.json"):
|
def sitePublish(self, address, peer_ip=None, peer_port=15441, inner_path="content.json"):
|
||||||
global file_server
|
global file_server
|
||||||
from Site import Site
|
from Site import Site
|
||||||
from File import FileServer # We need fileserver to handle incoming file requests
|
from File import FileServer # We need fileserver to handle incoming file requests
|
||||||
|
@ -214,9 +207,9 @@ def sitePublish(address, peer_ip=None, peer_port=15441, inner_path="content.json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Crypto commands
|
# Crypto commands
|
||||||
|
|
||||||
def cryptoPrivatekeyToAddress(privatekey=None):
|
def cryptoPrivatekeyToAddress(self, privatekey=None):
|
||||||
from Crypt import CryptBitcoin
|
from Crypt import CryptBitcoin
|
||||||
if not privatekey: # If no privatekey in args then ask it now
|
if not privatekey: # If no privatekey in args then ask it now
|
||||||
import getpass
|
import getpass
|
||||||
|
@ -225,9 +218,9 @@ def cryptoPrivatekeyToAddress(privatekey=None):
|
||||||
print CryptBitcoin.privatekeyToAddress(privatekey)
|
print CryptBitcoin.privatekeyToAddress(privatekey)
|
||||||
|
|
||||||
|
|
||||||
# Peer
|
# Peer
|
||||||
|
|
||||||
def peerPing(peer_ip, peer_port):
|
def peerPing(self, peer_ip, peer_port):
|
||||||
logging.info("Opening a simple connection server")
|
logging.info("Opening a simple connection server")
|
||||||
global file_server
|
global file_server
|
||||||
from Connection import ConnectionServer
|
from Connection import ConnectionServer
|
||||||
|
@ -243,7 +236,7 @@ def peerPing(peer_ip, peer_port):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
def peerGetFile(peer_ip, peer_port, site, filename):
|
def peerGetFile(self, peer_ip, peer_port, site, filename):
|
||||||
logging.info("Opening a simple connection server")
|
logging.info("Opening a simple connection server")
|
||||||
global file_server
|
global file_server
|
||||||
from Connection import ConnectionServer
|
from Connection import ConnectionServer
|
||||||
|
@ -256,3 +249,10 @@ def peerGetFile(peer_ip, peer_port, site, filename):
|
||||||
print peer.getFile(site, filename).read()
|
print peer.getFile(site, filename).read()
|
||||||
print "Response time: %.3fs" % (time.time()-s)
|
print "Response time: %.3fs" % (time.time()-s)
|
||||||
|
|
||||||
|
actions = Actions()
|
||||||
|
# Starts here when running zeronet.py
|
||||||
|
def start():
|
||||||
|
# Call function
|
||||||
|
func = getattr(actions, config.action, None)
|
||||||
|
action_kwargs = config.getActionArguments()
|
||||||
|
func(**action_kwargs)
|
||||||
|
|
Loading…
Reference in a new issue