📄 ipc.py
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.1 (the License). You may not copy or use this file, in either# source code or executable form, except in compliance with the License. You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License# for the specific language governing rights and limitations under the# License.# Written by Greg Hazel# based on code by Uoti Urpalafrom __future__ import generatorsimport osimport sysimport timeimport Queueimport socketimport loggingimport tracebackif os.name == 'nt': from BitTorrent import pykill import win32api import win32event import winerror import win32ui import dde import pywin.mfc.objectfrom binascii import b2a_hexfrom BitTorrent.translation import _from BitTorrent.RawServer_twisted import RawServer, Handlerfrom BitTorrent.platform import get_home_dir, get_dot_dirfrom BitTorrent.platform import encode_for_filesystemfrom BitTorrent import BTFailure, app_nameipc_logger = logging.getLogger('IPC')ipc_logger.setLevel(logging.DEBUG)def toint(s): return int(b2a_hex(s), 16)def tobinary(i): return (chr(i >> 24) + chr((i >> 16) & 0xFF) + chr((i >> 8) & 0xFF) + chr(i & 0xFF))CONTROL_SOCKET_PORT = 46881class ControlsocketListener(Handler): def __init__(self, callback): self.callback = callback def connection_made(self, connection): connection.handler = MessageReceiver(self.callback)class MessageReceiver(Handler): def __init__(self, callback): self.callback = callback self._buffer = [] self._buffer_len = 0 self._reader = self._read_messages() self._next_len = self._reader.next() def _read_messages(self): while True: yield 4 l = toint(self._message) yield l action = self._message if action in ('no-op',): self.callback(action, None) else: yield 4 l = toint(self._message) yield l data = self._message if action in ('show_error','start_torrent'): self.callback(action, data) else: yield 4 l = toint(self._message) yield l path = self._message if action in ('publish_torrent'): self.callback(action, data, path) # copied from Connecter.py def data_came_in(self, conn, s): while True: i = self._next_len - self._buffer_len if i > len(s): self._buffer.append(s) self._buffer_len += len(s) return m = s[:i] if self._buffer_len > 0: self._buffer.append(m) m = ''.join(self._buffer) self._buffer = [] self._buffer_len = 0 s = s[i:] self._message = m try: self._next_len = self._reader.next() except StopIteration: self._reader = None conn.close() return def connection_lost(self, conn): self._reader = None pass def connection_flushed(self, conn): passclass IPC(object): """Used for communication between raw server thread and other threads.""" def __init__(self, rawserver, config, name="controlsocket"): self.rawserver = rawserver self.name = name self.config = config self.callback = None self._command_q = Queue.Queue() def create(self): pass def start(self, callback): self.callback = callback while not self._command_q.empty(): self.callback(*self._command_q.get()) def send_command(self, command, *args): pass def handle_command(self, *args): if callable(self.callback): return self.callback(*args) self._command_q.put(args) def stop(self): passclass IPCSocketBase(IPC): def __init__(self, *args): IPC.__init__(self, *args) self.port = CONTROL_SOCKET_PORT self.controlsocket = None def start(self, callback): IPC.start(self, callback) self.rawserver.start_listening(self.controlsocket, ControlsocketListener(self.handle_command)) def stop(self): # safe double-stop, since MultiTorrent seems to be prone to do so if self.controlsocket: # it's possible we're told to stop after controlsocket creation but # before rawserver registration if self.rawserver: self.rawserver.stop_listening(self.controlsocket) self.controlsocket.close() self.controlsocket = None class IPCUnixSocket(IPCSocketBase): def __init__(self, *args): IPCSocketBase.__init__(self, *args) data_dir,bad = encode_for_filesystem(self.config['data_dir']) if bad: raise BTFailure(_("Invalid path encoding.")) self.socket_filename = os.path.join(data_dir, self.name) def create(self): filename = self.socket_filename if os.path.exists(filename): try: self.send_command('no-op') except BTFailure: pass else: raise BTFailure(_("Could not create control socket: already in use")) try: os.unlink(filename) except OSError, e: raise BTFailure(_("Could not remove old control socket filename:") + unicode(e.args[0])) try: controlsocket = self.rawserver.create_unixserversocket(filename) except socket.error, e: raise BTFailure(_("Could not create control socket: ")+unicode(e.args[0])) self.controlsocket = controlsocket # blocking version without rawserver def send_command(self, command, *args): s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) filename = self.socket_filename try: s.connect(filename) s.send(tobinary(len(command))) s.send(command) for arg in args: s.send(tobinary(len(arg))) s.send(arg) s.close() except socket.error, e: s.close() raise BTFailure(_("Could not send command: ") + unicode(e.args[0]))class IPCWin32Socket(IPCSocketBase): def __init__(self, *args): IPCSocketBase.__init__(self, *args) self.socket_filename = os.path.join(self.config['data_dir'], self.name) self.mutex = None self.master = 0 def _get_sic_path(self): configdir = get_dot_dir() filename = os.path.join(configdir, ".btcontrol") return filename def create(self): obtain_mutex = 1 mutex = win32event.CreateMutex(None, obtain_mutex, app_name) # prevent the PyHANDLE from going out of scope, ints are fine self.mutex = int(mutex)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -