From c5f0368942bfdb4f9984a48992709bd109e71a18 Mon Sep 17 00:00:00 2001 From: F18-Ray Date: Mon, 19 Oct 2026 06:46:40 +0800 Subject: [PATCH 1/5] core-code: add the reconnected and auto recovering the file transfering tasks functions in connect_tcp --- PyFlow/network_api/connect_tcp.py | 2200 +++++++++++++++-- .../web_backend/server_backend.py | 4 +- .../transfer_web/web_front/client_backend.py | 4 +- docs/source/File_Transfer/File_Transfer.rst | 65 +- docs/source/Network_APIs/TCP_Client_APIs.rst | 29 +- docs/source/Network_APIs/TCP_Server_APIs.rst | 26 +- test/integration/conftest.py | 12 +- test/integration/helpers.py | 13 + .../network_api/test_crypto_tcp.py | 2 + .../network_api/test_message_event_store.py | 2 + .../network_api/test_tcp_file_transfer.py | 71 +- .../network_api/test_tcp_transfer_resume.py | 533 ++++ 12 files changed, 2698 insertions(+), 263 deletions(-) create mode 100644 test/integration/network_api/test_tcp_transfer_resume.py diff --git a/PyFlow/network_api/connect_tcp.py b/PyFlow/network_api/connect_tcp.py index 7ec34ab..4745cdb 100644 --- a/PyFlow/network_api/connect_tcp.py +++ b/PyFlow/network_api/connect_tcp.py @@ -14,11 +14,18 @@ file data), and each file/folder transfer sub-connection is framed the same way once both sides hold the session keys (see `_SecureChannel`); - file/folder transfer, message forwarding and port allocation are layered on - the same socket and share its command namespace. + the same socket and share its command namespace; +- an interrupted transfer is resumed after a disconnect: both sides persist + their transfer stores under the protocol's ``.Flow`` directory and the + receiver asks the sender to continue the file from the bytes already on + disk (``resume_transfers``; the wire lines are ``/resume_trans`` and + ``/forward_resume``). The forwarding extensions use the module-level parsers `parse_forwarded_message`, `parse_forward_items_and_addrs`, -`parse_forward_originator` and `forward_skip_message`. +`parse_forward_originator` and `forward_skip_message`; the reconnect logic +uses `parse_resume_command`, `parse_forward_resume_command` and +`_resume_offset_for`. Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and ``TCP_Client_APIs.rst``; argument, return and exception contracts live in the @@ -128,6 +135,16 @@ def _is_closed_socket_error(exc): NETWORK_SPEED_WINDOW = 1.0 # sample window of the real-time speed, in seconds NETWORK_SPEED_MIN_SPAN = 0.1 # seconds floor, so one short burst is not extrapolated +# Transfer reconnect: an interrupted transfer keeps its progress entry and its +# partial file, and both sides persist the stores to .Flow when a connection +# drops (see _persist_transfer_progress). After a reconnect the receiver asks +# the sender to continue from the bytes it already holds (/resume_trans). +RESUME_LINE = "/resume_trans" # receiver -> sender: continue this transfer from an offset +FORWARD_RESUME_LINE = "/forward_resume" # server -> forwarder: re-forward one item from an offset +RESUME_ACCEPT_TIMEOUT = 20.0 # seconds a resumed transfer waits for the sender to connect +RESUME_PORT_TIMEOUT = 20.0 # seconds a resumed sender waits for the receiver's transfer port +RESUME_SECURE_TIMEOUT = 10.0 # seconds a resume drive waits for the framed control channel + def _wait_writable(client_socket, timeout): """Wait until a non-blocking socket accepts more data. @@ -308,6 +325,134 @@ def _transfer_fid(command_part): return None +def _peer_from_text(text): + """Parse an ``"ip:port"`` peer string into an ``(ip, port)`` tuple. + + Returns: + tuple | None: The peer tuple, or None when the text carries none. + """ + if not text: + return None + host, sep, port = str(text).rpartition(":") + if not sep: + return None + try: + return (host, int(port)) + except ValueError: + return None + + +def _peer_from_json(value): + """Parse a persisted ``[ip, port]`` peer into an ``(ip, port)`` tuple. + + Returns: + tuple | None: The peer tuple, or None when the value is not a peer. + """ + if isinstance(value, (list, tuple)) and len(value) == 2: + try: + return (str(value[0]), int(value[1])) + except (TypeError, ValueError): + return None + return None + + +def _resume_offset_for(entry): + """Bytes of an interrupted transfer's file already on the receiver's disk. + + The length of the partial file is what the sender is asked to continue + from, so a missing (or unreadable) partial file restarts the transfer from + its first byte. + + Args: + entry (list): Progress entry ``[received, total, speed, path, peer]``. + + Returns: + int: Byte offset to continue from. + """ + try: + size = os.path.getsize(entry[3]) + except (OSError, TypeError): + return 0 + total = entry[1] + if isinstance(total, int) and size > total: + return 0 # not this transfer's partial file any more: start over + return size + + +def parse_resume_command(command): + """Split a ``/resume_trans `` line. + + Returns: + tuple | None: ``(fid, offset)``, or None when the line is malformed. + """ + try: + parts = shlex.split(command) + except ValueError: + return None + if len(parts) != 3 or parts[0].lower() != RESUME_LINE: + return None + try: + return int(parts[1]), int(parts[2]) + except ValueError: + return None + + +def _pause_command_fid(command): + """Return the fid of a ``/pause_trans``/``/start_trans`` line, or None.""" + try: + return int(shlex.split(command)[1]) + except (IndexError, ValueError): + return None + + +def _open_transfer_target(path, offset): + """Open a transfer's destination file, ready to write from ``offset``. + + A resumed transfer continues a partial file: the file is opened for + update and positioned at the byte the sender continues from, so a late or + duplicated chunk overwrites its own place instead of corrupting the + stream. A fresh transfer (offset 0) truncates the file. + + Args: + path (str): Destination path of the transfer. + offset (int): Byte offset the incoming stream starts at. + + Returns: + file: Open binary file positioned at ``offset``. + """ + if offset <= 0: + return open(path, "wb") + mode = "r+b" if os.path.exists(path) else "w+b" + target = open(path, mode) + target.seek(offset) + return target + + +def parse_forward_resume_command(command): + """Split a ``/forward_resume `` line. + + Returns: + tuple | None: ``(target, fid, offset)``, or None when the line is + malformed. + """ + try: + parts = shlex.split(command) + except ValueError: + return None + if len(parts) != 4 or parts[0].lower() != FORWARD_RESUME_LINE: + return None + try: + target = ast.literal_eval(parts[1]) + except (ValueError, SyntaxError): + return None + if not (isinstance(target, tuple) and len(target) == 2 and isinstance(target[0], str)): + return None + try: + return target, int(parts[2]), int(parts[3]) + except ValueError: + return None + + def parse_forwarded_message(command): """Split a ``/send_msg_from `` relay envelope. @@ -1080,11 +1225,17 @@ class TCP_Server_Base: # TCP server class is_enable_real_time_network_speed (bool): Whether the real-time network speed is measured into ``upload_network_speed``/``recv_network_speed``. file_recv_progress (dict): Running downloads keyed by fid; each value is - ``[received bytes, total bytes, current speed, file name]`` (the - speed is None until the transfer has moved its first chunk, and - while speed measurement is off). + ``[received bytes, total bytes, current speed, file path, peer]`` + (the speed is None until the transfer has moved its first chunk, + and while speed measurement is off; ``peer`` is the sender's + ``(ip, port)``). file_upload_progress (dict): Running uploads keyed by fid; each value is - ``[sent bytes, total bytes, current speed, file name]``, same shape. + ``[sent bytes, total bytes, current speed, file path, peer]``, with + ``peer`` the receiver's ``(ip, port)``. A forwarded transfer stores + the original peer on both sides, never the relay. + file_trans_progress_file (str): Path under the protocol's ``.Flow`` + directory where the two stores are written when a connection drops + and read back on the next reconnect (``resume_transfers``). upload_network_speed (float | None): Bytes per second sent, or None when not measured. recv_network_speed (float | None): Bytes per second received, or None @@ -1176,11 +1327,14 @@ def __init__( self.is_enable_file_transfer_progress_bar = is_enable_file_transfer_progress_bar self.is_enable_real_time_network_speed = is_enable_real_time_network_speed # Per-transfer progress stores: fid -> [transferred bytes, total bytes, - # current speed]. An entry appears when a transfer starts and is removed - # when it ends, so the stores hold exactly the transfers running now; - # iterate over a copy while transfers are in flight. - self.file_recv_progress = {} # downloads: fid -> [received, total, speed] - self.file_upload_progress = {} # uploads: fid -> [sent, total, speed] + # current speed, local file path, peer (ip, port)]. An entry appears + # when a transfer starts and is removed when it ends, so the stores + # hold exactly the transfers running now; iterate over a copy while + # transfers are in flight. A transfer interrupted by a disconnect + # keeps its entry (and its partial file) so it can be resumed once + # the peer is back (see `resume_transfers`). + self.file_recv_progress = {} # downloads: fid -> [received, total, speed, path, peer] + self.file_upload_progress = {} # uploads: fid -> [sent, total, speed, path, peer] self.upload_network_speed = None # bytes/s over the last NETWORK_SPEED_WINDOW seconds self.recv_network_speed = None self._network_speed_lock = threading.Lock() # serialises the speed sample windows @@ -1192,6 +1346,18 @@ def __init__( self._forward_fid_lock = threading.Lock() self._forward_relays = {} self._forward_relays_lock = threading.Lock() + # Relay records kept after their relay died, so a disconnected + # forward can be resumed: relay fid and every target tfid -> record. + self._forward_resume_records = {} + # Resume requests that arrived before the originator reconnected: + # originator (ip, port) -> [(fid, target (ip, port), offset), ...]. + self._pending_relay_resumes = {} + # Outbound-transfer pause switches (see `pause_trans`/`start_trans`): + # fid -> bool. A leg waits while its own fid is marked paused. + self._transfer_pause = {} + self._transfer_pause_cond = threading.Condition() + self._active_transfer_fids = set() # fids of the legs running right now + self._active_transfer_sockets = {} # fid -> socket of the leg running right now self.project_dir = os.path.dirname(os.path.abspath(__file__)) self.project_info_dir = os.path.join(self.project_dir, ".Flow") if os.path.exists(self.project_info_dir) == False: @@ -1202,6 +1368,12 @@ def __init__( self.server_port_lock_file = os.path.join( self.project_temp_info_dir, "server_port_lock.lock" ) + # Interrupted transfers are persisted here on a disconnect and read + # back when a peer returns (see `_persist_transfer_progress`). + self.file_trans_progress_file = os.path.join( + self.project_info_dir, "server_file_trans_progress.json" + ) + self._transfer_progress_lock = threading.RLock() # serialises the persist/load pair self.decode_command_table_file_path = os.path.join( self.project_dir, "decode_command_table.json" ) @@ -1374,7 +1546,7 @@ def _measure_network_speed(self, payload, is_upload): self.recv_network_speed = speed return speed - def _file_progress_start(self, progress_dict, fid, total_bytes, name): + def _file_progress_start(self, progress_dict, fid, total_bytes, path, peer=None, initial=0): """Register one file transfer in a progress store. Args: @@ -1383,17 +1555,27 @@ def _file_progress_start(self, progress_dict, fid, total_bytes, name): fid (int | None): The transfer's fid; None tracks nothing (a leg without a protocol transfer id, such as a key push). total_bytes (int): Size of the file being transferred. - name (str): Name of the file being transferred. + path (str): Local path of the file: the source of an outbound + transfer, the file being written for an inbound one. + peer (tuple | None): ``(ip, port)`` of the transfer's original + peer — the sender for an inbound transfer, the receiver for an + outbound one. A forwarded transfer stores the original peer on + both sides, never the relay; None marks a leg that cannot be + resumed (there is no peer to continue it with). + initial (int): Bytes already transferred when the leg starts; a + resumed transfer continues a partially transferred file. Returns: - list | None: The ``[transferred, total, speed, name]`` entry the - transfer updates, or None when tracking is off + list | None: The ``[transferred, total, speed, path, peer]`` entry + the transfer updates, or None when tracking is off (``is_enable_file_transfer_progress_bar`` False, or no fid). """ if fid is None or not self.is_enable_file_transfer_progress_bar: return None - entry = [0, total_bytes, None, name] + entry = [initial, total_bytes, None, path, _peer_from_json(peer) if peer else None] progress_dict[fid] = entry + with self._transfer_progress_lock: + self._active_transfer_fids.add(fid) return entry def _file_progress_update(self, entry, byte_count, is_upload): @@ -1413,16 +1595,403 @@ def _file_progress_update(self, entry, byte_count, is_upload): entry[0] += byte_count entry[2] = self.upload_network_speed if is_upload else self.recv_network_speed - def _file_progress_finish(self, progress_dict, fid, entry): - """Drop a finished transfer's progress entry. + def _file_progress_finish(self, progress_dict, fid, entry, keep=False): + """Drop a finished transfer's progress entry, or keep it for a resume. A newer transfer may already hold the same fid (transfer ids are reused - as transfers end), so only this transfer's own entry is dropped. + as transfers end), so only this transfer's own entry is dropped. With + ``keep`` True an interrupted transfer keeps its entry — and the partial + file that entry points at — so the reconnect logic can continue it + (`resume_transfers`); the entry then lives until the transfer ends. + + Args: + progress_dict (dict): Store the entry belongs to. + fid (int | None): Transfer id the entry is keyed by. + entry (list | None): Entry to drop; None tracks nothing. + keep (bool): Keep the entry (and persist the stores) instead of + dropping it. Defaults to False. """ if entry is None: return + with self._transfer_progress_lock: + if progress_dict.get(fid) is entry: + # a leg of an earlier session may finish after a newer leg + # took the fid over: only the owner releases it + self._active_transfer_fids.discard(fid) + if keep: + entry[2] = None # a stopped transfer has no live speed any more + self._persist_transfer_progress() + return if progress_dict.get(fid) is entry: del progress_dict[fid] + if os.path.exists(self.file_trans_progress_file): + # the persisted stores are only kept up to date while they exist: + # a transfer that ended must not be resumed on a later reconnect + self._persist_transfer_progress() + + def _transfer_progress_snapshot(self): + """Return the JSON-ready form of every transfer still in play. + + Returns: + dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids + are string keys and every peer is an ``[ip, port]`` list. + """ + + def entries(store): + return { + str(fid): [ + entry[0], + entry[1], + entry[2], + entry[3], + list(entry[4]) if entry[4] else None, + ] + for fid, entry in list(store.items()) + } + + with self._forward_relays_lock: + relays = { + str(key): { + "fid": record.get("fid"), + "originator": list(record["originator"]) if record.get("originator") else None, + "targets": [list(target) for target in record.get("targets") or []], + "tfids": list(record.get("tfids") or []), + "kind": record.get("kind"), + "rel_dir": record.get("rel_dir"), + "fname": record.get("fname"), + "destination": record.get("destination"), + } + for key, record in list(self._forward_resume_records.items()) + } + return { + "upload": entries(self.file_upload_progress), + "download": entries(self.file_recv_progress), + "relays": relays, + } + + def _persist_transfer_progress(self): + """Write the transfer stores to the protocol's ``.Flow`` directory. + + Every in-flight transfer — uploads, downloads, and the relay records a + disconnected forward is resumed from — is written to + ``server_file_trans_progress.json`` when a connection drops, and the + file is what the reconnect logic reads back. Once nothing is left to + transfer the file is emptied; it is only rewritten while it exists, so + a run without an interrupted transfer never creates it. A write + failure is logged, never raised. + """ + snapshot = self._transfer_progress_snapshot() + with self._transfer_progress_lock: + if not any(snapshot.values()) and not os.path.exists(self.file_trans_progress_file): + return + tmp_path = f"{self.file_trans_progress_file}.{os.getpid()}.tmp" + try: + with open(tmp_path, "w", encoding="utf-8") as f: + json.dump(snapshot, f, ensure_ascii=False, indent=2) + os.replace(tmp_path, self.file_trans_progress_file) + except OSError as e: + self._log(f"transfer progress file update failed: {e}") + try: + os.remove(tmp_path) + except OSError: + pass + + def _load_transfer_progress(self): + """Read the persisted interrupted transfers back into the stores. + + Every entry read back keeps the bytes it had already transferred, so + the reconnect logic can ask the sender to continue from there; every + relay record comes back so a disconnected forward can be routed again. + Entries a live transfer (or a relay) already owns are left alone. + + Returns: + int: Number of transfer entries and relay records restored. + """ + with self._transfer_progress_lock: + try: + with open(self.file_trans_progress_file, "r", encoding="utf-8") as f: + data = json.load(f) + except FileNotFoundError: + return 0 + except (OSError, ValueError) as e: + self._log(f"transfer progress file unreadable ({e}), ignored") + return 0 + if not isinstance(data, dict): + return 0 + restored = 0 + with self._forward_relays_lock: + for key_text, record in (data.get("relays") or {}).items(): + try: + key = int(key_text) + except (TypeError, ValueError): + continue + if not isinstance(record, dict): + continue + record = dict(record) + record["originator"] = _peer_from_json(record.get("originator")) + record["targets"] = [ + target + for target in (_peer_from_json(t) for t in record.get("targets") or []) + if target + ] + self._forward_resume_records.setdefault(key, record) + restored += 1 + for key, store in ( + ("download", self.file_recv_progress), + ("upload", self.file_upload_progress), + ): + for fid_text, row in (data.get(key) or {}).items(): + try: + fid = int(fid_text) + entry = [int(row[0]), int(row[1]), None, row[3], _peer_from_json(row[4])] + except (TypeError, ValueError, IndexError, KeyError): + continue + if fid in store or fid in self._forward_resume_records: + continue # a live transfer owns it, or a relay drives it + store[fid] = entry + restored += 1 + return restored + + def _forward_relay_targets(self, fid, peer=None): + """Live relay writers a pause/resume for ``fid`` addresses. + + Args: + fid (int): Relay fid, or one of its per-target transfer ids. + peer (tuple | None): Restrict to the writer serving this peer; + None addresses every writer of the relay. + + Returns: + tuple: ``(relay, [targets])``; ``(None, [])`` when no live relay + writer matches. + """ + with self._forward_relays_lock: + relay = self._forward_relays.get(fid) + if relay is None or not relay.get("writer_pause"): + return None, [] + if peer is None: + return relay, list(relay["writer_pause"]) + for target in relay["writer_pause"]: + if tuple(target) == tuple(peer): + return relay, [target] + return None, [] + + def _mark_transfer_pause(self, fid, paused, peer=None): + """Set or clear one transfer's pause switch (see `pause_trans`). + + Returns: + bool: True when a live relay writer or outbound leg was found. + """ + relay, targets = self._forward_relay_targets(fid, peer) + if targets: + with relay["cond"]: + for target in targets: + relay["writer_pause"][target] = paused + if not paused: + relay["cond"].notify_all() + return True + with self._transfer_progress_lock: + live = fid in self._active_transfer_fids + if live and peer is not None: + entry = self.file_upload_progress.get(fid) + if entry is not None and entry[4] is not None and tuple(entry[4]) != tuple(peer): + return False # that leg belongs to another peer + with self._transfer_pause_cond: + self._transfer_pause[fid] = paused + self._transfer_pause_cond.notify_all() + return live + + def pause_trans(self, fid, peer=None): + """Pause an outbound transfer of this instance. + + The sending leg with this fid stops at its next chunk and stays open + until `start_trans` (or the peer's ``/start_trans``) resumes it. A + forward relay's writer toward ``peer`` is paused the same way the + ``/pause_trans`` line pauses it. + + Args: + fid (int): Transfer id the outbound leg is keyed by. + peer (tuple | None): Restrict the pause to the leg or relay writer + toward this ``(ip, port)``; None addresses every match. + + Returns: + bool: True when a running leg (or relay writer) was marked paused; + False when nothing matched — the switch is still armed, so a + leg later started under this fid starts paused. + """ + return self._mark_transfer_pause(fid, True, peer) + + def start_trans(self, fid, peer=None): + """Resume an outbound transfer paused with `pause_trans`. + + Args: + fid (int): Transfer id the outbound leg is keyed by. + peer (tuple | None): Restrict the resume to the leg or relay + writer toward this ``(ip, port)``; None addresses every match. + + Returns: + bool: True when a live leg (or relay writer) was resumed. + """ + return self._mark_transfer_pause(fid, False, peer) + + def _register_transfer_socket(self, fid, sock): + """Record the socket of a leg, so a dead session can be cleared out.""" + if fid is None: + return + with self._transfer_progress_lock: + self._active_transfer_sockets[fid] = sock + + def _release_transfer_socket(self, fid, sock): + """Forget a leg's socket once the leg is over (its own, not a newer one's).""" + if fid is None: + return + with self._transfer_progress_lock: + if self._active_transfer_sockets.get(fid) is sock: + del self._active_transfer_sockets[fid] + + def _drop_stale_transfers(self, peer=None): + """Close the legs a peer's previous session left behind. + + A peer that (re)connects proves that the legs of its earlier session + are over: their sockets are shut down so the stored transfers can be + resumed without two legs writing the same transfer. + + Args: + peer (tuple | None): Restrict to the legs whose progress entry + names this ``(ip, port)``; None clears every leg of the + instance (a fresh session replaces all of them). + + Returns: + int: Number of legs closed. + """ + stale = [] + for store in (self.file_upload_progress, self.file_recv_progress): + for fid, entry in list(store.items()): + if peer is not None and (entry[4] is None or tuple(entry[4]) != tuple(peer)): + continue + with self._transfer_progress_lock: + sock = self._active_transfer_sockets.pop(fid, None) + if sock is not None: + self._active_transfer_fids.discard(fid) + if sock is not None: + stale.append(sock) + for sock in stale: + try: + sock.shutdown(socket.SHUT_RDWR) + except OSError: + pass # already gone + try: + sock.close() + except OSError: + pass + return len(stale) + + def pause_trans_remote(self, peer, fid): + """Ask a connected client to pause its transfer toward this server. + + Sends the ``/pause_trans `` line the peers use for transfer flow + control (see `pause_trans` on the receiving side). + + Args: + peer (tuple): Connected client ``(ip, port)``. + fid (int): Transfer id of that client's outbound leg. + + Returns: + bool: True when the line was written; False when ``peer`` is not + connected. + """ + info = self.clients.get(peer) if peer is not None else None + if info is None: + self._log(f"pause: {peer} is not a connected client") + return False + return self.send_message(info["socket"], f"/pause_trans {fid}") + + def start_trans_remote(self, peer, fid): + """Ask a connected client to resume a transfer paused earlier. + + Args: + peer (tuple): Connected client ``(ip, port)``. + fid (int): Transfer id of that client's outbound leg. + + Returns: + bool: True when the line was written; False when ``peer`` is not + connected. + """ + info = self.clients.get(peer) if peer is not None else None + if info is None: + self._log(f"start: {peer} is not a connected client") + return False + return self.send_message(info["socket"], f"/start_trans {fid}") + + def _wait_transfer_paused(self, fid): + """Block a sending leg while its fid is marked paused. + + Runs before every chunk so ``/pause_trans`` stops the stream without + closing the transfer; the wait ends when the leg is resumed, when the + instance stops, or when the fid is not paused at all. + """ + if fid is None: + return + with self._transfer_pause_cond: + while self._transfer_pause.get(fid, False): + if not self.running: + return + self._transfer_pause_cond.wait(timeout=0.5) + + def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): + """Wait for the peer's ``/server_file_transfer_port`` of one fid. + + Args: + fid (int): Transfer id the peer announces its listener under. + timeout (float): Seconds to wait. + + Returns: + tuple | None: ``(port, stamp)`` announced for this fid, or None + when the announcement does not arrive in time. + """ + deadline = time.time() + timeout + while time.time() < deadline: + with self.file_transfer_server_port_lock: + for info in reversed(list(self.file_server_port_list)): + if info[1] == fid: + # the newest announcement wins: an older one may belong + # to a leg of a session that is already gone + self.file_server_port_list.remove(info) + stamp = info[2] if len(info) > 2 else "plain" + return info[0], stamp + time.sleep(0.1) + return None + + def _forget_transfer_port(self, fid): + """Drop pending port announcements of a fid an older session left behind.""" + if fid is None: + return + with self.file_transfer_server_port_lock: + self.file_server_port_list[:] = [ + info for info in self.file_server_port_list if info[1] != fid + ] + + def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): + """Wait until a control channel may carry framed protocol lines. + + The reconnect flows run right after a session is established, when the + crypto handshake may still be completing; a resume line sent then would + travel plaintext and be dropped by the peer's framing guard. Without + encryption there is nothing to wait for. + + Returns: + bool: True when the channel speaks frames (or encryption is off). + """ + if not self.is_enable_encrypto or self.crypto is None: + return True + deadline = time.time() + timeout + while time.time() < deadline: + with self._crypto_lock: + channel = self._channels.get(control_socket) + if channel is not None and channel.secure: + return True + time.sleep(0.05) + self._log("resume: control channel is not framed yet, transfers kept for the next reconnect") + return False def alloc_port(self, port_add_step, port_range_num): """Reserve this server's port range under the cross-process lock. @@ -2847,6 +3416,12 @@ def _register_client(self, client_socket, client_address): self._channels[client_socket] = channel self._debug(f"new connection: {client_id}") self._debug(f"connection count mount: {len(self.clients)}") + # a peer that comes back carries interrupted transfers: continue them + # (and wake the forwarded-resume requests that waited for it) off the + # accept path, because the resume may need this peer's handshake first + threading.Thread( + target=self._resume_after_connect, args=(client_address,), daemon=True + ).start() return client_id def _announce_client(self, client_socket, client_id): @@ -2945,6 +3520,9 @@ def _unregister_client(self, client_socket, client_address, client_id): self._channels.pop(client_socket, None) self._crypto_send_locks.pop(client_socket, None) client_socket.close() + # the transfers that died with this connection are written to the + # progress file so a reconnect can continue them (resume_transfers) + self._persist_transfer_progress() self._debug(f"client disconnected: {client_id}") self._debug(f"current connection count: {len(self.clients)}") @@ -3065,10 +3643,19 @@ def handle_command( ).start() return "Command received, processing in background.\n" elif shlex.split(command.lower())[0] == "/pause_trans": - self._forward_pause_target(client_address, command) + self._handle_pause_command(client_address, command, True) return None elif shlex.split(command.lower())[0] == "/start_trans": - self._forward_resume_target(client_address, command) + self._handle_pause_command(client_address, command, False) + return None + elif shlex.split(command.lower())[0] == RESUME_LINE: + parsed = parse_resume_command(command) + if parsed is not None: + threading.Thread( + target=self._resume_request, + args=(client_address, parsed[0], parsed[1]), + daemon=True, + ).start() return None elif ( self.is_enable_encrypto @@ -3377,6 +3964,7 @@ def file_transfer_server_recv_server_start( # deal with file transfer request s new_save_path, file_name, command, + peer=_peer_from_text(client_id), # the sender a resume is asked to continue from ) self.pfree(file_transfer_server_port) @@ -3389,7 +3977,20 @@ def file_transfer_mode_recv( new_save_path, file_name, command, + peer=None, + resume_entry=None, ): + """Receive one file over a transfer sub-connection. + + ``peer`` is the transfer's original sender (the sender for an inbound + transfer, never a relay): it is stored with the progress entry so a + later reconnect can ask that peer to continue the file. + + ``resume_entry`` continues an interrupted transfer: the listener + announces itself, asks the sender to continue from the bytes already + on disk (``RESUME_LINE``) and appends the incoming chunks to the + partial file instead of truncating it. + """ file_running = True client_file_socket = None server_file_socket = None @@ -3433,6 +4034,7 @@ def file_transfer_client_recv(client_id): filename = None full_path = None progress = None # this leg's file_recv_progress entry, when tracked + finished_ok = False try: self.send_message(client_file_socket, self.server_start_file_transfer_sign) except Exception as e: @@ -3507,21 +4109,36 @@ def file_transfer_client_recv(client_id): file_size = int.from_bytes(size_bytes, "big") self.send_message(client_file_socket, self.server_received_file_header_sign) original_filename = filename - if file_name: - final_filename = file_name.strip() - elif command_part[0] == "/crypto_pub_key": - # concurrent key pushes share received_files/: a fixed name would be - # overwritten/moved by another connection before this one consumes it - final_filename = "{}.pem".format(uuid.uuid4().hex) + if resume_entry is not None: + # continued transfer: the receiver's partial file keeps the + # bytes that are already on disk and the sender continues + full_path = resume_entry[3] + final_filename = os.path.basename(full_path) + resume_from = resume_entry[0] # the offset the sender was asked to continue from + if resume_from <= 0 or resume_from > file_size: + resume_from = 0 # not this file's offset: start it over else: - final_filename = os.path.basename(original_filename) - full_path = os.path.join(save_path, final_filename).strip() + if file_name: + final_filename = file_name.strip() + elif command_part[0] == "/crypto_pub_key": + # concurrent key pushes share received_files/: a fixed name would be + # overwritten/moved by another connection before this one consumes it + final_filename = "{}.pem".format(uuid.uuid4().hex) + else: + final_filename = os.path.basename(original_filename) + full_path = os.path.join(save_path, final_filename).strip() + resume_from = 0 os.makedirs(os.path.dirname(full_path), exist_ok=True) progress = self._file_progress_start( - self.file_recv_progress, progress_fid, file_size, final_filename + self.file_recv_progress, + progress_fid, + file_size, + full_path, + peer=peer, + initial=resume_from, ) - with open(full_path.strip(), "wb") as f: - remaining = file_size + with _open_transfer_target(full_path, resume_from) as f: + remaining = file_size - resume_from while remaining > 0: chunk = self.receive_message( client_file_socket, min(self.file_transfer_chunk_len, remaining) @@ -3539,6 +4156,8 @@ def file_transfer_client_recv(client_id): f.write(chunk) remaining -= len(chunk) self._file_progress_update(progress, len(chunk), is_upload=False) + f.truncate() # a longer partial file drops its stale tail + finished_ok = True # TOFU first: the ack is only a notification, and a failed # ack send must not skip the key registration (the server # would never announce readiness and the handshake hangs) @@ -3568,9 +4187,9 @@ def file_transfer_client_recv(client_id): close_socket() except Exception as e: self._log_exc() - if full_path is not None and os.path.exists(full_path): + if full_path is not None and os.path.exists(full_path) and progress is None: try: - os.remove(full_path) # partial transfer: no half-written leftovers + os.remove(full_path) # untracked partial transfer: nothing can resume it except OSError: pass try: @@ -3584,7 +4203,17 @@ def file_transfer_client_recv(client_id): close_socket() return None finally: - self._file_progress_finish(self.file_recv_progress, progress_fid, progress) + self._file_progress_finish( + self.file_recv_progress, + progress_fid, + progress, + keep=( + not finished_ok + and progress is not None + and progress[4] is not None # an interrupted transfer with a peer can be resumed + ), + ) + self._release_transfer_socket(progress_fid, client_file_socket) server_file_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_file_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -3597,6 +4226,7 @@ def file_transfer_client_recv(client_id): stamp = self._crypto_transfer_stamp( client_socket, force_plain=command_part[0] == "/crypto_pub_key" ) + self._forget_transfer_port(progress_fid) # an older session's entry is stale transfer_server_port_msg = "/server_file_transfer_port {} {} {}\n".format( file_transfer_server_port, file_client_id, stamp ) @@ -3604,16 +4234,42 @@ def file_transfer_client_recv(client_id): client_socket, transfer_server_port_msg ) # coordination line: always plaintext (like the handshake) server_file_socket.listen(1) + if resume_entry is not None: + # the receiver drives a resumed transfer: it asks the sender to + # continue the file from the bytes already on disk + offset = _resume_offset_for(resume_entry) + if progress_fid is None or not self.send_message( + client_socket, f"{RESUME_LINE} {progress_fid} {offset}" + ): + self._log( + f"resume: cannot ask {client_id} to continue transfer {progress_fid}" + ) + server_file_socket.close() + return False + server_file_socket.settimeout(RESUME_ACCEPT_TIMEOUT) try: client_file_socket, client_file_address = server_file_socket.accept() + if resume_entry is not None: + client_file_socket.settimeout(None) # the accept timeout is the listener's only self._crypto_attach_transfer_in(client_file_socket, client_socket, stamp) - is_open_file_transfer = setting_file_save_path() - if is_open_file_transfer == None: - pass - else: + self._register_transfer_socket(progress_fid, client_file_socket) + if resume_entry is not None: threading.Thread( target=file_transfer_client_recv, args=(client_id,), daemon=True ).start() + else: + is_open_file_transfer = setting_file_save_path() + if is_open_file_transfer == None: + pass + else: + threading.Thread( + target=file_transfer_client_recv, args=(client_id,), daemon=True + ).start() + except socket.timeout: + self._log( + f"resume: {client_id} did not continue transfer {progress_fid}, " + f"it stays in the progress stores for the next reconnect" + ) except Exception as e: self._log(f"\nget file transfer msg error: {e}") self._log_exc() @@ -3911,6 +4567,7 @@ def file_transfer_server_recv_client_start(self, message, file_folder_abspath): control_socket=client_socket, crypto=stamp, fid=client_id, + peer=client_ip, # the receiver a resume is asked to continue from ) self.pfree(file_transfer_client_port) except IndexError: @@ -3923,10 +4580,11 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist server_address, server_port, client_port, - pause_fid=None, control_socket=None, crypto=None, fid=None, + peer=None, + resume_offset=0, ): """Send one file over a transfer sub-connection. @@ -3936,8 +4594,15 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist ``fid`` is the transfer's id — the caller's own transfer id for a plain send, the relay id for a forwarded upload — and keys this leg in - ``file_upload_progress``. None (a leg without a protocol transfer id, - such as a public-key push) tracks no progress. + ``file_upload_progress``; every leg with a fid can be paused with + ``/pause_trans`` for that fid. None (a leg without a protocol transfer + id, such as a public-key push) tracks no progress. + + ``peer`` is the transfer's original receiver (never a relay): it is + stored with the progress entry so a later reconnect can be resumed. + ``resume_offset`` continues an interrupted transfer from the byte the + receiver already holds: the file is read from there instead of its + first byte. """ self._log(f"start to send file: {filename}") client_file_socket = None @@ -3975,6 +4640,7 @@ def close_socket(): close_socket() return False file_running = True + self._register_transfer_socket(fid, client_file_socket) file_receive_data_from_server = "" def receive_file_transfer_messages(): @@ -4014,6 +4680,8 @@ def receive_file_transfer_messages(): receive_thread.start() waiting_time = 0 progress = None # this leg's file_upload_progress entry, when tracked + file_sent = False # True once the receiver acknowledged the whole file + source_missing = False # True when the source file no longer exists try: while True: if file_receive_data_from_server == self.server_start_file_transfer_sign: @@ -4046,15 +4714,21 @@ def receive_file_transfer_messages(): self.send_message(client_file_socket, name_len.to_bytes(4, "big")) self.send_message(client_file_socket, file_name_encoded) self.send_message(client_file_socket, file_size.to_bytes(8, "big")) + if resume_offset < 0 or resume_offset > file_size: + resume_offset = 0 # not this file's offset any more: send it whole progress = self._file_progress_start( - self.file_upload_progress, fid, file_size, os.path.basename(filename) + self.file_upload_progress, + fid, + file_size, + filename, + peer=peer, + initial=resume_offset, ) with open(filename, "rb") as f: + if resume_offset: + f.seek(resume_offset) while True: - if pause_fid is not None: - with self._forward_pause_cond: - while self._forward_pause.get(pause_fid, False): - self._forward_pause_cond.wait() + self._wait_transfer_paused(fid) file_data = f.read(self.file_transfer_chunk_len) if not file_data: break @@ -4086,10 +4760,13 @@ def receive_file_transfer_messages(): file {filename} sending may have failed" ) return False + file_sent = True self._log(f"Success: file {filename} sent successfully") close_socket() return True except FileNotFoundError: + # the source is gone: this transfer cannot be resumed later + source_missing = True self._log_exc() try: self.send_message(client_file_socket, self.error_sign) @@ -4109,55 +4786,301 @@ def receive_file_transfer_messages(): self._log(f"send error: {e}") return False finally: - self._file_progress_finish(self.file_upload_progress, fid, progress) - - # ---- native in-memory forward relay (server side) ---------------------- + self._file_progress_finish( + self.file_upload_progress, + fid, + progress, + keep=( + not file_sent + and not source_missing + and progress is not None + and progress[4] is not None # an interrupted transfer with a peer can be resumed + ), + ) + self._release_transfer_socket(fid, client_file_socket) + with self._transfer_pause_cond: + self._transfer_pause.pop(fid, None) - def _forward_alloc_fid(self): - with self._forward_fid_lock: - self._forward_fid += 1 - return self._forward_fid + # ---- transfer reconnect (server side) ---------------------------------- - def _forward_notify_error(self, sock, msg): - try: - self.send_message(sock, f"/forward_error {msg}") - except Exception: - pass + def resume_transfers(self, peer=None): + """Continue the interrupted transfers of a peer that is back. - def _forward_parse_items_addrs(self, tokens): - items = [] - addrs = [] - for token in tokens: - if token.startswith("(") and token.endswith(")"): - try: - addr = ast.literal_eval(token) - except (ValueError, SyntaxError): - items.append(token) - continue - if isinstance(addr, tuple) and len(addr) == 2 and isinstance(addr[0], str): - addrs.append(addr) - else: - items.append(token) - else: - items.append(token) - return items, addrs + Reads the persisted stores back (`_load_transfer_progress`) and, for + every download this instance was receiving from ``peer``, opens a + fresh transfer listener and asks the sender to continue the file from + the bytes already on disk. Restored uploads need no action here: the + peer drives their resume from its own side. - def _forward_item_handler(self, sock, addr, cmd): - """Server-side entry for /forward_item <...> . + Args: + peer (tuple | None): Peer ``(ip, port)`` that just connected; None + resumes every peer that is connected right now. - The server never touches disk: it only relays the uploaded byte - stream to every reachable target client from memory. + Returns: + int: Number of resumed receive legs started. """ - try: - parts = shlex.split(cmd) - except Exception: - self._forward_notify_error(sock, "invalid forward command") - return + restored = self._load_transfer_progress() + if restored: + self._log(f"transfer reconnect: restored {restored} interrupted transfer(s)") + with self.client_lock: + connected = {tuple(address) for address in self.clients} + candidates = [] + for fid, entry in list(self.file_recv_progress.items()): + if entry[4] is None: + continue # without a peer there is nobody to continue with + with self._forward_relays_lock: + if fid in self._forward_resume_records: + continue # a forwarded transfer: its target drives the resume + with self._transfer_progress_lock: + if fid in self._active_transfer_fids: + continue # a leg is already running for this fid + peer_addr = tuple(entry[4]) + if peer is not None and peer_addr != tuple(peer): + continue + if peer is None and peer_addr not in connected: + continue + candidates.append((fid, entry, peer_addr)) + started = 0 + for fid, entry, peer_addr in candidates: + with self.client_lock: + info = self.clients.get(peer_addr) + if info is None: + continue + if not self._wait_control_secure(info["socket"]): + continue + threading.Thread( + target=self._resume_receive_leg, + args=( + info["socket"], + peer_addr, + fid, + entry, + f"/file {shlex.quote(os.path.basename(str(entry[3])))} {fid}", + ), + daemon=True, + ).start() + started += 1 + return started + + def _resume_receive_leg(self, control_socket, peer_addr, fid, entry, command): + """Receive the rest of one interrupted transfer, appending to its file. + + Returns: + bool: True when the sender was asked to continue, False when the + request could not be sent. + """ + self._log(f"resume: continuing transfer {fid} with {peer_addr} into {entry[3]}") + entry[0] = _resume_offset_for(entry) # the offset the sender is asked for + port = self.palloc() + try: + return self.file_transfer_mode_recv( + self.host, + port, + control_socket, + f"{peer_addr[0]}:{peer_addr[1]}", + None, + None, + command, + peer=peer_addr, + resume_entry=entry, + ) is not False + finally: + self.pfree(port) + + def resume_trans(self, peer_addr, fid, offset): + """Continue one interrupted transfer this instance was sending. + + Runs when a receiver asks to continue a transfer (``/resume_trans``, + see `resume_transfers` on the receiving side): the leg is + re-established against the receiver's fresh listener and the source + file is read from the byte offset the receiver already holds. Also the + public API for resuming one transfer on demand. + + Args: + peer_addr (tuple | None): Receiver ``(ip, port)`` the request came + from; None skips the peer check. + fid (int): Transfer id of the interrupted transfer. + offset (int): Byte offset the receiver already holds. + + Returns: + bool: True when the resume leg was started. + """ + entry = self.file_upload_progress.get(fid) + if entry is None: + self._log(f"resume: no outgoing transfer with fid {fid} to continue") + return False + if peer_addr is not None and entry[4] is not None and tuple(entry[4]) != tuple(peer_addr): + self._log(f"resume: transfer {fid} is for {entry[4]}, not {peer_addr}, ignored") + return False + with self.client_lock: + info = self.clients.get(tuple(peer_addr)) if peer_addr is not None else None + if info is None: + self._log(f"resume: {peer_addr} is not connected, transfer {fid} kept") + return False + port_info = self._wait_transfer_server_port(fid) + if port_info is None: + self._log(f"resume: {peer_addr} did not announce a transfer port for {fid}") + return False + port, stamp = port_info + threading.Thread( + target=self._run_resume_send_leg, + args=(entry[3], tuple(peer_addr), port, stamp, info["socket"], fid, offset), + daemon=True, + ).start() + return True + + def _run_resume_send_leg(self, path, peer_addr, port, stamp, control_socket, fid, offset): + """Run one resumed sending leg on its own thread.""" + client_port = self.palloc() + try: + self.file_transfer_mode( + path, + peer_addr[0], + port, + client_port, + control_socket=control_socket, + crypto=stamp, + fid=fid, + peer=peer_addr, + resume_offset=offset, + ) + finally: + self.pfree(client_port) + + def _resume_request(self, client_address, fid, offset): + """Route one client's ``/resume_trans`` to the transfer it names. + + The fid identifies either this server's own outbound leg to that + client, or a target leg of a forward relay — the relay record then + names the originator, which is asked to re-forward to this client. + """ + with self._forward_relays_lock: + record = self._forward_resume_records.get(fid) + if record is not None: + originator = record.get("originator") + targets = [tuple(target) for target in record.get("targets") or []] + if ( + originator is not None + and tuple(client_address) in targets + and tuple(originator) != tuple(client_address) + ): + return self._route_forward_resume(record, client_address, offset) + return self.resume_trans(client_address, fid, offset) + + def _route_forward_resume(self, record, target_addr, offset): + """Ask a forwarded transfer's originator to continue it for one target. + + The server only relays: the record of the dead relay names the + originating client, which re-drives the item to this target from the + offset the target already holds (``/forward_resume``). An originator + that is not back yet gets the request as soon as it reconnects. + """ + originator = record.get("originator") + originator_fid = record.get("fid") + if originator is None or originator_fid is None: + return False + request = ( + f"{FORWARD_RESUME_LINE} {shlex.quote(repr(tuple(target_addr)))} " + f"{originator_fid} {offset}" + ) + with self.client_lock: + info = self.clients.get(tuple(originator)) + if info is None: + with self._forward_relays_lock: + self._pending_relay_resumes.setdefault(tuple(originator), []).append( + (originator_fid, tuple(target_addr), offset) + ) + self._log( + f"resume: originator {tuple(originator)} is not connected, " + f"request for {tuple(target_addr)} kept" + ) + return False + self._log( + f"resume: asking {tuple(originator)} to continue forwarded transfer " + f"{originator_fid} for {tuple(target_addr)}" + ) + return self.send_message(info["socket"], request) + + def _flush_pending_relay_resumes(self, client_address): + """Send the forwarded-resume requests that waited for this originator.""" + with self._forward_relays_lock: + pending = self._pending_relay_resumes.pop(tuple(client_address), None) + if not pending: + return + with self.client_lock: + info = self.clients.get(tuple(client_address)) + if info is None: + return + for fid, target, offset in pending: + self.send_message( + info["socket"], + f"{FORWARD_RESUME_LINE} {shlex.quote(repr(tuple(target)))} {fid} {offset}", + ) + + def _resume_after_connect(self, client_address): + """Continue this peer's interrupted transfers after it (re)connected.""" + self._drop_stale_transfers(peer=tuple(client_address)) + self._flush_pending_relay_resumes(tuple(client_address)) + self.resume_transfers(peer=tuple(client_address)) + + # ---- native in-memory forward relay (server side) ---------------------- + + def _forward_alloc_fid(self): + with self._forward_fid_lock: + self._forward_fid += 1 + return self._forward_fid + + def _forward_notify_error(self, sock, msg): + try: + self.send_message(sock, f"/forward_error {msg}") + except Exception: + pass + + def _forward_parse_items_addrs(self, tokens): + items = [] + addrs = [] + for token in tokens: + if token.startswith("(") and token.endswith(")"): + try: + addr = ast.literal_eval(token) + except (ValueError, SyntaxError): + items.append(token) + continue + if isinstance(addr, tuple) and len(addr) == 2 and isinstance(addr[0], str): + addrs.append(addr) + else: + items.append(token) + else: + items.append(token) + return items, addrs + + def _forward_item_handler(self, sock, addr, cmd): + """Server-side entry for /forward_item [resume=] <...> . + + The server never touches disk: it only relays the uploaded byte + stream to every reachable target client from memory. ``resume=`` + marks a repeated forward of a file the target already holds partially: + the uploader starts at that offset, so the relay expects + ``size - offset`` bytes of stream. + """ + try: + parts = shlex.split(cmd) + except Exception: + self._forward_notify_error(sock, "invalid forward command") + return if len(parts) < 3: self._forward_notify_error(sock, "invalid forward command") return kind = parts[1].lower() rest = parts[2:] + resume_offset = 0 + if rest and rest[0].startswith("resume="): + try: + resume_offset = max(0, int(rest[0][len("resume=") :])) + except ValueError: + self._forward_notify_error(sock, "invalid resume offset") + return + rest = rest[1:] # optional destination directory is the very last argument, after the # client address tuples destination_path = None @@ -4194,7 +5117,7 @@ def _forward_item_handler(self, sock, addr, cmd): return threading.Thread( target=self._forward_relay, - args=(sock, addr, kind, rel_dir, fname, valid_targets, destination_path), + args=(sock, addr, kind, rel_dir, fname, valid_targets, destination_path, resume_offset), daemon=True, ).start() @@ -4230,35 +5153,28 @@ def _forward_recv_exact(self, sock, n): buf += data return buf - def _forward_pause_target(self, client_address, command): - try: - fid = int(shlex.split(command)[1]) - except Exception: - return - with self._forward_relays_lock: - relay = self._forward_relays.get(fid) - if relay is None: - return - with relay["cond"]: - if client_address in relay["writer_pause"]: - relay["writer_pause"][client_address] = True + def _handle_pause_command(self, client_address, command, paused): + """Apply a client's ``/pause_trans``/``/start_trans`` on this side. - def _forward_resume_target(self, client_address, command): - try: - fid = int(shlex.split(command)[1]) - except Exception: - return - with self._forward_relays_lock: - relay = self._forward_relays.get(fid) - if relay is None: - return - with relay["cond"]: - if client_address in relay["writer_pause"]: - relay["writer_pause"][client_address] = False - relay["cond"].notify_all() + A client throttles the writer that feeds it (a forward relay's writer + for its target) or, without a relay, this server's own outbound leg to + that client (see `pause_trans`). + """ + fid = _pause_command_fid(command) + if fid is None: + return None + return self._mark_transfer_pause(fid, paused, tuple(client_address)) def _forward_relay( - self, forwarder_sock, originator_addr, kind, rel_dir, fname, targets, destination_path=None + self, + forwarder_sock, + originator_addr, + kind, + rel_dir, + fname, + targets, + destination_path=None, + resume_offset=0, ): """Relay one file/folder item to every target, streaming from the uploader's transfer connection with bounded in-memory buffering. @@ -4275,6 +5191,21 @@ def _forward_relay( with self._forward_relays_lock: for key in [fid] + tfids: self._forward_relays[key] = relay + record = { + "fid": fid, + "originator": [originator_addr[0], originator_addr[1]], + "targets": [[target[0], target[1]] for target in targets], + "tfids": list(tfids), + "kind": kind, + "rel_dir": rel_dir, + "fname": fname, + "destination": destination_path, + } + # the record survives the relay so an interrupted forward can be + # routed back to its originator (see `_route_forward_resume`) + with self._forward_relays_lock: + for key in [fid] + tfids: + self._forward_resume_records[key] = record try: # ask every target to open a receive transfer socket; the # destination directory (if any) goes before the target id so @@ -4336,17 +5267,26 @@ def _forward_relay( up_client, _ = up_sock.accept() self._crypto_attach_transfer_in(up_client, forwarder_sock, up_stamp) self.send_message(up_client, self.server_start_file_transfer_sign) - self._forward_pump(up_client, target_conns, forwarder_sock, fid, fname, relay) + delivered = self._forward_pump( + up_client, target_conns, forwarder_sock, fid, fname, relay, resume_offset + ) self._crypto_drop_channel(up_client) up_client.close() up_sock.close() self.pfree(sport) + if delivered >= len(target_conns): + # every target got the whole item: nothing is left to resume + with self._forward_relays_lock: + for key in [fid] + tfids: + self._forward_resume_records.pop(key, None) finally: with self._forward_relays_lock: for key in [fid] + tfids: self._forward_relays.pop(key, None) - def _forward_pump(self, up_sock, target_conns, forwarder_sock, fid, fname, relay): + def _forward_pump( + self, up_sock, target_conns, forwarder_sock, fid, fname, relay, resume_offset=0 + ): """Pump the uploader's byte stream to every target from memory. The total bytes held in the per-target queues never exceeds @@ -4354,6 +5294,10 @@ def _forward_pump(self, up_sock, target_conns, forwarder_sock, fid, fname, relay (``/pause_trans``) and the reader stops pulling; as the writers drain below the low-water mark the uploader is resumed (``/start_trans``). + + Returns: + int: Targets that acknowledged the whole item (they are the ones + the relay's resume record can be dropped for). """ max_bytes = max(1, self.max_mem_buff) low_water = max(1, max_bytes // 2) @@ -4423,7 +5367,10 @@ def reader(): return for chunk in (name_len_b, name_b, size_b): enqueue(chunk) - remaining = file_size + # a repeated forward uploads only the remainder of the file: the + # offset the command carried says how much of the header's size + # does not travel any more + remaining = max(0, file_size - resume_offset) while remaining > 0: with cond: while state["paused"]: @@ -4450,6 +5397,7 @@ def reader(): except Exception: pass self._log(f"forward: relayed {fname} to {result['ok']}/{len(target_conns)} targets") + return result["ok"] def start_TCP_Server(self): # set up server socket """Bind the server socket, then accept clients until `stop` runs. @@ -4676,6 +5624,8 @@ def stop(self): # shutting down the server self.free_port() self._flush_messages_dict() self._flush_events_dict() + # in-flight transfers die with the server: persist them for the next run + self._persist_transfer_progress() with self.client_lock: # close all clients connections for client_info in self.clients.values(): try: @@ -4740,12 +5690,20 @@ class TCP_Client_Base: # TCP client class transfer is tracked in ``file_recv_progress``/``file_upload_progress``. is_enable_real_time_network_speed (bool): Whether the real-time network speed is measured into ``upload_network_speed``/``recv_network_speed``. + is_auto_reconnect (bool): Whether `start_TCP_client` reconnects after + the connection drops (and resumes the interrupted transfers). file_recv_progress (dict): Running downloads keyed by fid; each value is - ``[received bytes, total bytes, current speed, file name]`` (the - speed is None until the transfer has moved its first chunk, and - while speed measurement is off). + ``[received bytes, total bytes, current speed, file path, peer]`` + (the speed is None until the transfer has moved its first chunk, + and while speed measurement is off; ``peer`` is the sender's + ``(ip, port)``). file_upload_progress (dict): Running uploads keyed by fid; each value is - ``[sent bytes, total bytes, current speed, file name]``, same shape. + ``[sent bytes, total bytes, current speed, file path, peer]``, with + ``peer`` the receiver's ``(ip, port)``. A forwarded transfer stores + the original peer on both sides, never the relay. + file_trans_progress_file (str): Path under the protocol's ``.Flow`` + directory where the two stores are written when the connection + drops and read back on the next reconnect (`resume_transfers`). upload_network_speed (float | None): Bytes per second sent, or None when not measured. recv_network_speed (float | None): Bytes per second received, or None @@ -4774,6 +5732,7 @@ def __init__( is_print_log=True, is_enable_file_transfer_progress_bar=True, is_enable_real_time_network_speed=True, + is_auto_reconnect=False, ): """Create the client and, unless extended, connect and start reading. @@ -4827,6 +5786,12 @@ def __init__( second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False nothing is measured and every speed value is None. Defaults to True. + is_auto_reconnect (bool): Reconnect (and resume the interrupted + transfers, see `resume_transfers`) when the connection drops + while `start_TCP_client` runs. The transfers that died with + the connection are persisted to the protocol's ``.Flow`` + directory and read back on the next connect. Defaults to + False: a dropped connection ends the client. Raises: ValueError: If ``is_wait_server`` is True and ``timeout`` is not None. OSError: If the ``.Flow`` directories or ``decode_command_table.json`` @@ -4838,11 +5803,12 @@ def __init__( self.is_enable_file_transfer_progress_bar = is_enable_file_transfer_progress_bar self.is_enable_real_time_network_speed = is_enable_real_time_network_speed # Per-transfer progress stores: fid -> [transferred bytes, total bytes, - # current speed]. An entry appears when a transfer starts and is removed - # when it ends, so the stores hold exactly the transfers running now; - # iterate over a copy while transfers are in flight. - self.file_recv_progress = {} # downloads: fid -> [received, total, speed] - self.file_upload_progress = {} # uploads: fid -> [sent, total, speed] + # current speed, local file path, peer (ip, port)]. An entry appears + # when a transfer starts and is removed when it ends; a transfer + # interrupted by a disconnect keeps its entry (and its partial file) + # so it can be resumed once the peer is back (see `resume_transfers`). + self.file_recv_progress = {} # downloads: fid -> [received, total, speed, path, peer] + self.file_upload_progress = {} # uploads: fid -> [sent, total, speed, path, peer] self.upload_network_speed = None # bytes/s over the last NETWORK_SPEED_WINDOW seconds self.recv_network_speed = None self._network_speed_lock = threading.Lock() # serialises the speed sample windows @@ -4851,9 +5817,23 @@ def __init__( self._upload_speed_total = 0 # bytes held in the sample windows self._recv_speed_total = 0 self._forward_upload_queue = queue.Queue() - self._forward_pause = {} - self._forward_pause_cond = threading.Condition() + # Relay records of the forwards this client started, kept after their + # leg died so a target's resume request can re-drive them: relay fid + # and every target tfid -> record (see `_resume_forward`). + self._forward_resume_records = {} + # Resumes this client asked a forward's originator for, keyed by the + # local path of the partial file: the fresh relay leg lands on that + # path and must append to what is already there (see + # `_take_pending_resume`). + self._resume_pending_paths = {} # path -> (old fid, byte offset) + self._forward_resume_lock = threading.Lock() self._forward_error = None + # Outbound-transfer pause switches (see `pause_trans`/`start_trans`): + # fid -> bool. A leg waits while its own fid is marked paused. + self._transfer_pause = {} + self._transfer_pause_cond = threading.Condition() + self._active_transfer_fids = set() # fids of the legs running right now + self._active_transfer_sockets = {} # fid -> socket of the leg running right now self.project_dir = os.path.dirname(os.path.abspath(__file__)) self.file_transfer_dir = os.path.join(self.project_dir, "received_files") self.decode_command_table_file_path = os.path.join( @@ -4866,6 +5846,12 @@ def __init__( self.client_port_lock_file = os.path.join( self.project_temp_info_dir, "client_port_lock.lock" ) + # Interrupted transfers are persisted here on a disconnect and read + # back when the client reconnects (see `_persist_transfer_progress`). + self.file_trans_progress_file = os.path.join( + self.project_info_dir, "client_file_trans_progress.json" + ) + self._transfer_progress_lock = threading.RLock() # serialises the persist/load pair if os.path.exists(self.project_temp_info_dir) == False: os.mkdir(self.project_temp_info_dir) self.all_allocated_ports_list = [] @@ -4889,6 +5875,7 @@ def __init__( self.max_thread_num = max_thread_num self.is_input_command_in_console = is_input_command_in_console self.is_wait_server = is_wait_server + self.is_auto_reconnect = is_auto_reconnect if self.is_wait_server and self.timeout != None: error_msg = [ "wait_server_timeout is not applicable when is_wait_server is True,", @@ -5359,7 +6346,7 @@ def _measure_network_speed(self, payload, is_upload): self.recv_network_speed = speed return speed - def _file_progress_start(self, progress_dict, fid, total_bytes, name): + def _file_progress_start(self, progress_dict, fid, total_bytes, path, peer=None, initial=0): """Register one file transfer in a progress store. Args: @@ -5368,17 +6355,27 @@ def _file_progress_start(self, progress_dict, fid, total_bytes, name): fid (int | None): The transfer's fid; None tracks nothing (a leg without a protocol transfer id, such as a key push). total_bytes (int): Size of the file being transferred. - name (str): Name of the file being transferred. + path (str): Local path of the file: the source of an outbound + transfer, the file being written for an inbound one. + peer (tuple | None): ``(ip, port)`` of the transfer's original + peer — the sender for an inbound transfer, the receiver for an + outbound one. A forwarded transfer stores the original peer on + both sides, never the relay; None marks a leg that cannot be + resumed (there is no peer to continue it with). + initial (int): Bytes already transferred when the leg starts; a + resumed transfer continues a partially transferred file. Returns: - list | None: The ``[transferred, total, speed, name]`` entry the - transfer updates, or None when tracking is off + list | None: The ``[transferred, total, speed, path, peer]`` entry + the transfer updates, or None when tracking is off (``is_enable_file_transfer_progress_bar`` False, or no fid). """ if fid is None or not self.is_enable_file_transfer_progress_bar: return None - entry = [0, total_bytes, None, name] + entry = [initial, total_bytes, None, path, _peer_from_json(peer) if peer else None] progress_dict[fid] = entry + with self._transfer_progress_lock: + self._active_transfer_fids.add(fid) return entry def _file_progress_update(self, entry, byte_count, is_upload): @@ -5398,16 +6395,370 @@ def _file_progress_update(self, entry, byte_count, is_upload): entry[0] += byte_count entry[2] = self.upload_network_speed if is_upload else self.recv_network_speed - def _file_progress_finish(self, progress_dict, fid, entry): - """Drop a finished transfer's progress entry. + def _file_progress_finish(self, progress_dict, fid, entry, keep=False): + """Drop a finished transfer's progress entry, or keep it for a resume. A newer transfer may already hold the same fid (transfer ids are reused - as transfers end), so only this transfer's own entry is dropped. + as transfers end), so only this transfer's own entry is dropped. With + ``keep`` True an interrupted transfer keeps its entry — and the partial + file that entry points at — so the reconnect logic can continue it + (`resume_transfers`); the entry then lives until the transfer ends. + + Args: + progress_dict (dict): Store the entry belongs to. + fid (int | None): Transfer id the entry is keyed by. + entry (list | None): Entry to drop; None tracks nothing. + keep (bool): Keep the entry (and persist the stores) instead of + dropping it. Defaults to False. """ if entry is None: return + with self._transfer_progress_lock: + if progress_dict.get(fid) is entry: + # a leg of an earlier session may finish after a newer leg + # took the fid over: only the owner releases it + self._active_transfer_fids.discard(fid) + if keep: + entry[2] = None # a stopped transfer has no live speed any more + self._persist_transfer_progress() + return if progress_dict.get(fid) is entry: del progress_dict[fid] + if os.path.exists(self.file_trans_progress_file): + # the persisted stores are only kept up to date while they exist: + # a transfer that ended must not be resumed on a later reconnect + self._persist_transfer_progress() + + def _transfer_progress_snapshot(self): + """Return the JSON-ready form of every transfer still in play. + + Returns: + dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids + are string keys and every peer is an ``[ip, port]`` list. + """ + + def entries(store): + return { + str(fid): [ + entry[0], + entry[1], + entry[2], + entry[3], + list(entry[4]) if entry[4] else None, + ] + for fid, entry in list(store.items()) + } + + with self._forward_resume_lock: + relays = { + str(key): { + "fid": record.get("fid"), + "kind": record.get("kind"), + "rel_dir": record.get("rel_dir"), + "fname": record.get("fname"), + "path": record.get("path"), + "destination": record.get("destination"), + "targets": [list(target) for target in record.get("targets") or []], + } + for key, record in list(self._forward_resume_records.items()) + } + return { + "upload": entries(self.file_upload_progress), + "download": entries(self.file_recv_progress), + "relays": relays, + } + + def _persist_transfer_progress(self): + """Write the transfer stores to the protocol's ``.Flow`` directory. + + Every in-flight transfer — uploads, downloads, and the relay records + of the forwards this client started — is written to + ``client_file_trans_progress.json`` when a connection drops, and the + file is what the reconnect logic reads back. Once nothing is left to + transfer the file is emptied; it is only rewritten while it exists, so + a run without an interrupted transfer never creates it. A write + failure is logged, never raised. + """ + snapshot = self._transfer_progress_snapshot() + with self._transfer_progress_lock: + if not any(snapshot.values()) and not os.path.exists(self.file_trans_progress_file): + return + tmp_path = f"{self.file_trans_progress_file}.{os.getpid()}.tmp" + try: + with open(tmp_path, "w", encoding="utf-8") as f: + json.dump(snapshot, f, ensure_ascii=False, indent=2) + os.replace(tmp_path, self.file_trans_progress_file) + except OSError as e: + self._log(f"transfer progress file update failed: {e}") + try: + os.remove(tmp_path) + except OSError: + pass + + def _load_transfer_progress(self): + """Read the persisted interrupted transfers back into the stores. + + Every entry read back keeps the bytes it had already transferred, so + the reconnect logic can ask the sender to continue from there; every + relay record comes back so an interrupted forward can be re-driven. + Entries a live transfer (or a relay) already owns are left alone. + + Returns: + int: Number of transfer entries and relay records restored. + """ + with self._transfer_progress_lock: + try: + with open(self.file_trans_progress_file, "r", encoding="utf-8") as f: + data = json.load(f) + except FileNotFoundError: + return 0 + except (OSError, ValueError) as e: + self._log(f"transfer progress file unreadable ({e}), ignored") + return 0 + if not isinstance(data, dict): + return 0 + restored = 0 + with self._forward_resume_lock: + for key_text, record in (data.get("relays") or {}).items(): + try: + key = int(key_text) + except (TypeError, ValueError): + continue + if not isinstance(record, dict): + continue + record = dict(record) + record["targets"] = [ + target + for target in (_peer_from_json(t) for t in record.get("targets") or []) + if target + ] + self._forward_resume_records.setdefault(key, record) + restored += 1 + for key, store in ( + ("download", self.file_recv_progress), + ("upload", self.file_upload_progress), + ): + for fid_text, row in (data.get(key) or {}).items(): + try: + fid = int(fid_text) + entry = [int(row[0]), int(row[1]), None, row[3], _peer_from_json(row[4])] + except (TypeError, ValueError, IndexError, KeyError): + continue + if fid in store or fid in self._forward_resume_records: + continue # a live transfer owns it, or a relay drives it + store[fid] = entry + restored += 1 + return restored + + def _mark_transfer_pause(self, fid, paused, peer=None): + """Set or clear one transfer's pause switch (see `pause_trans`). + + Returns: + bool: True when a running outbound leg was found. + """ + with self._transfer_progress_lock: + live = fid in self._active_transfer_fids + if live and peer is not None: + entry = self.file_upload_progress.get(fid) + if entry is not None and entry[4] is not None and tuple(entry[4]) != tuple(peer): + return False # that leg belongs to another peer + with self._transfer_pause_cond: + self._transfer_pause[fid] = paused + self._transfer_pause_cond.notify_all() + return live + + def pause_trans(self, fid, peer=None): + """Pause an outbound transfer of this instance. + + The sending leg with this fid stops at its next chunk and stays open + until `start_trans` (or the peer's ``/start_trans``) resumes it. This + covers every outgoing transfer — a plain upload as much as a forward + upload — and is what the ``/pause_trans`` line does when it arrives + from a peer. + + Args: + fid (int): Transfer id the outbound leg is keyed by. + peer (tuple | None): Restrict the pause to the leg whose original + receiver is this ``(ip, port)``; None pauses whichever leg + holds the fid. + + Returns: + bool: True when a running leg was marked paused; False when + nothing matched — the switch is still armed, so a leg started + later under this fid starts paused. + """ + return self._mark_transfer_pause(fid, True, peer) + + def start_trans(self, fid, peer=None): + """Resume an outbound transfer paused with `pause_trans`. + + Args: + fid (int): Transfer id the outbound leg is keyed by. + peer (tuple | None): Restrict the resume to the leg whose original + receiver is this ``(ip, port)``; None addresses every match. + + Returns: + bool: True when a running leg was resumed. + """ + return self._mark_transfer_pause(fid, False, peer) + + def pause_trans_remote(self, peer, fid): + """Ask the server to pause its transfer toward this client. + + Sends the ``/pause_trans `` line the peers use for transfer flow + control (a forwarded upload this client relays is throttled this way). + + Args: + peer (tuple | None): The server's ``(ip, port)``; None accepts the + connected server. + fid (int): Transfer id of the server's outbound leg. + + Returns: + bool: True when the line was written. + """ + if peer is not None and tuple(peer) != (self.host, self.port): + self._log(f"pause: {peer} is not the server this client is connected to") + return False + return self.send_message(self.client_socket, f"/pause_trans {fid}") + + def start_trans_remote(self, peer, fid): + """Ask the server to resume a transfer paused earlier. + + Args: + peer (tuple | None): The server's ``(ip, port)``; None accepts the + connected server. + fid (int): Transfer id of the server's outbound leg. + + Returns: + bool: True when the line was written. + """ + if peer is not None and tuple(peer) != (self.host, self.port): + self._log(f"start: {peer} is not the server this client is connected to") + return False + return self.send_message(self.client_socket, f"/start_trans {fid}") + + def _register_transfer_socket(self, fid, sock): + """Record the socket of a leg, so a dead session can be cleared out.""" + if fid is None: + return + with self._transfer_progress_lock: + self._active_transfer_sockets[fid] = sock + + def _release_transfer_socket(self, fid, sock): + """Forget a leg's socket once the leg is over (its own, not a newer one's).""" + if fid is None: + return + with self._transfer_progress_lock: + if self._active_transfer_sockets.get(fid) is sock: + del self._active_transfer_sockets[fid] + + def _drop_stale_transfers(self, peer=None): + """Close the legs a peer's previous session left behind. + + A peer that (re)connects proves that the legs of its earlier session + are over: their sockets are shut down so the stored transfers can be + resumed without two legs writing the same transfer. + + Args: + peer (tuple | None): Restrict to the legs whose progress entry + names this ``(ip, port)``; None clears every leg of the + instance (a fresh session replaces all of them). + + Returns: + int: Number of legs closed. + """ + stale = [] + for store in (self.file_upload_progress, self.file_recv_progress): + for fid, entry in list(store.items()): + if peer is not None and (entry[4] is None or tuple(entry[4]) != tuple(peer)): + continue + with self._transfer_progress_lock: + sock = self._active_transfer_sockets.pop(fid, None) + if sock is not None: + self._active_transfer_fids.discard(fid) + if sock is not None: + stale.append(sock) + for sock in stale: + try: + sock.shutdown(socket.SHUT_RDWR) + except OSError: + pass # already gone + try: + sock.close() + except OSError: + pass + return len(stale) + + def _wait_transfer_paused(self, fid): + """Block a sending leg while its fid is marked paused. + + Runs before every chunk so ``/pause_trans`` stops the stream without + closing the transfer; the wait ends when the leg is resumed, when the + instance stops, or when the fid is not paused at all. + """ + if fid is None: + return + with self._transfer_pause_cond: + while self._transfer_pause.get(fid, False): + if not self.running: + return + self._transfer_pause_cond.wait(timeout=0.5) + + def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): + """Wait for the peer's ``/server_file_transfer_port`` of one fid. + + Args: + fid (int): Transfer id the peer announces its listener under. + timeout (float): Seconds to wait. + + Returns: + tuple | None: ``(port, stamp)`` announced for this fid, or None + when the announcement does not arrive in time. + """ + deadline = time.time() + timeout + while time.time() < deadline: + with self.file_transfer_server_port_lock: + for info in reversed(list(self.file_server_port_list)): + if info[1] == fid: + # the newest announcement wins: an older one may belong + # to a leg of a session that is already gone + self.file_server_port_list.remove(info) + stamp = info[2] if len(info) > 2 else "plain" + return info[0], stamp + time.sleep(0.1) + return None + + def _forget_transfer_port(self, fid): + """Drop pending port announcements of a fid an older session left behind.""" + if fid is None: + return + with self.file_transfer_server_port_lock: + self.file_server_port_list[:] = [ + info for info in self.file_server_port_list if info[1] != fid + ] + + def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): + """Wait until a control channel may carry framed protocol lines. + + The reconnect flows run right after a session is established, when the + crypto handshake may still be completing; a resume line sent then would + travel plaintext and be dropped by the peer's framing guard. Without + encryption there is nothing to wait for. + + Returns: + bool: True when the channel speaks frames (or encryption is off). + """ + if not self.is_enable_encrypto or self.crypto is None: + return True + deadline = time.time() + timeout + while time.time() < deadline: + with self._crypto_lock: + channel = self._channels.get(control_socket) + if channel is not None and channel.secure: + return True + time.sleep(0.05) + self._log("resume: control channel is not framed yet, transfers kept for the next reconnect") + return False def alloc_port(self, port_add_step, port_range_num): """Reserve this client's port range under the cross-process lock. @@ -5814,6 +7165,12 @@ def connect(self): # connect to server self.client_socket = None return False self.running = True + # this client's only control link is the server: the socket is + # up, so every leg still registered belongs to the previous + # session and is over. The sweep runs before the receive thread + # starts, so a resume request of the new session cannot be + # affected by it. + self._drop_stale_transfers() self.receive_thread = threading.Thread( target=self.receive_messages ) # set up get msg thread @@ -5841,6 +7198,11 @@ def connect(self): # connect to server self._crypto_decode_failures = 0 # fresh connection, fresh breaker self._crypto_start_exchange() self._log("connect success! type '/help' to get help.\n") + # a (re)connected session carries the transfers that died with + # the previous one: continue them from what is already on disk + threading.Thread( + target=self.resume_transfers, kwargs={"peer": (self.host, self.port)}, daemon=True + ).start() return True except socket.timeout: if self.is_wait_server: @@ -5881,6 +7243,9 @@ def receive_messages(self): # get server msg self._log("\nbreak the connection from server") self.running = False self.free_port() + # the transfers running on this session died with it: keep + # them on disk for the next connect (resume_transfers) + self._persist_transfer_progress() break buffer += data.decode("utf-8") while "\n" in buffer: # deal with multiple messages in buffer @@ -5925,6 +7290,7 @@ def receive_messages(self): # get server msg self._log_exc() self.running = False self.free_port() + self._persist_transfer_progress() break except Exception as e: if not _is_closed_socket_error(e): @@ -5932,6 +7298,7 @@ def receive_messages(self): # get server msg self._log_exc() self.running = False self.free_port() + self._persist_transfer_progress() break def send_message(self, client_socket, message): # send msg to server @@ -6446,10 +7813,12 @@ def handle_server_command(self, command): # deal with special command from serv Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange lines, - and the transfer lines ``/file``, ``/file_folder``, ``/forward_upload``, - ``/pause_trans``, ``/start_trans``, ``/forward_error``. Any other name goes - to the handlers registered for the "server" side via `register_command`; an - unknown command is only reported on the console. + and the transfer lines ``/file``, ``/file_folder``, + ``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, + ``/start_trans``, ``/resume_trans``, ``/forward_resume`` and + ``/forward_error``. Any other name goes to the handlers registered for + the "server" side via `register_command`; an unknown command is only + reported on the console. Args: command (str): Line including its leading ``/``. @@ -6584,21 +7953,25 @@ def handle_server_command(self, command): # deal with special command from serv stamp = parts[3] if len(parts) > 3 else "plain" # upload leg's mode+nonce self._forward_upload_queue.put((fid, sport, stamp)) elif shlex.split(command.lower())[0] == "/pause_trans": - try: - fid = int(shlex.split(command)[1]) - except (IndexError, ValueError): - return - with self._forward_pause_cond: - self._forward_pause[fid] = True - self._forward_pause_cond.notify_all() + fid = _pause_command_fid(command) + if fid is not None: + self.pause_trans(fid) elif shlex.split(command.lower())[0] == "/start_trans": - try: - fid = int(shlex.split(command)[1]) - except (IndexError, ValueError): - return - with self._forward_pause_cond: - self._forward_pause[fid] = False - self._forward_pause_cond.notify_all() + fid = _pause_command_fid(command) + if fid is not None: + self.start_trans(fid) + elif shlex.split(command.lower())[0] == RESUME_LINE: + parsed = parse_resume_command(command) + if parsed is not None: + threading.Thread( + target=self.resume_trans, + args=((self.host, self.port), parsed[0], parsed[1]), + daemon=True, + ).start() + elif shlex.split(command.lower())[0] == FORWARD_RESUME_LINE: + parsed = parse_forward_resume_command(command) + if parsed is not None: + self._resume_forward(parsed[0], parsed[1], parsed[2]) elif shlex.split(command.lower())[0] == "/forward_error": self._forward_error = command else: @@ -6922,6 +8295,7 @@ def file_transfer_client_recv_client_start(self, message, file_folder_abspath): control_socket=self.client_socket, crypto=stamp, fid=client_id, + peer=(self.host, self.port), # the receiver a resume is asked to continue from ) self.pfree(file_transfer_client_port) except IndexError: @@ -6934,10 +8308,11 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist server_address, server_port, client_port, - pause_fid=None, control_socket=None, crypto=None, fid=None, + peer=None, + resume_offset=0, ): """Send one file over a transfer sub-connection. @@ -6947,8 +8322,15 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist ``fid`` is the transfer's id — the caller's own transfer id for a plain send, the relay id for a forwarded upload — and keys this leg in - ``file_upload_progress``. None (a leg without a protocol transfer id, - such as a public-key push) tracks no progress. + ``file_upload_progress``; every leg with a fid can be paused with + ``/pause_trans`` for that fid. None (a leg without a protocol transfer + id, such as a public-key push) tracks no progress. + + ``peer`` is the transfer's original receiver (the target of a forward, + never the relay): it is stored with the progress entry so a later + reconnect can be resumed. ``resume_offset`` continues an interrupted + transfer from the byte the receiver already holds: the file is read + from there instead of its first byte. """ self._log(f"start to send file: {filename}") client_file_socket = None @@ -6986,6 +8368,7 @@ def close_socket(): close_socket() return False file_running = True + self._register_transfer_socket(fid, client_file_socket) file_receive_data_from_server = "" def receive_file_transfer_messages(): @@ -7025,6 +8408,8 @@ def receive_file_transfer_messages(): receive_thread.start() waiting_time = 0 progress = None # this leg's file_upload_progress entry, when tracked + file_sent = False # True once the receiver acknowledged the whole file + source_missing = False # True when the source file no longer exists try: while True: if file_receive_data_from_server == self.server_start_file_transfer_sign: @@ -7057,15 +8442,21 @@ def receive_file_transfer_messages(): self.send_message(client_file_socket, name_len.to_bytes(4, "big")) self.send_message(client_file_socket, file_name_encoded) self.send_message(client_file_socket, file_size.to_bytes(8, "big")) + if resume_offset < 0 or resume_offset > file_size: + resume_offset = 0 # not this file's offset any more: send it whole progress = self._file_progress_start( - self.file_upload_progress, fid, file_size, os.path.basename(filename) + self.file_upload_progress, + fid, + file_size, + filename, + peer=peer, + initial=resume_offset, ) with open(filename, "rb") as f: + if resume_offset: + f.seek(resume_offset) while True: - if pause_fid is not None: - with self._forward_pause_cond: - while self._forward_pause.get(pause_fid, False): - self._forward_pause_cond.wait() + self._wait_transfer_paused(fid) file_data = f.read(self.file_transfer_chunk_len) if not file_data: break @@ -7097,10 +8488,13 @@ def receive_file_transfer_messages(): file {filename} sending may have failed" ) return False + file_sent = True self._log(f"Success: file {filename} sent successfully") close_socket() return True except FileNotFoundError: + # the source is gone: this transfer cannot be resumed later + source_missing = True self._log_exc() try: self.send_message(client_file_socket, self.error_sign) @@ -7120,7 +8514,247 @@ def receive_file_transfer_messages(): self._log(f"send error: {e}") return False finally: - self._file_progress_finish(self.file_upload_progress, fid, progress) + self._file_progress_finish( + self.file_upload_progress, + fid, + progress, + keep=( + not file_sent + and not source_missing + and progress is not None + and progress[4] is not None # an interrupted transfer with a peer can be resumed + ), + ) + self._release_transfer_socket(fid, client_file_socket) + with self._transfer_pause_cond: + self._transfer_pause.pop(fid, None) + + # ---- transfer reconnect (client side) ---------------------------------- + + def resume_transfers(self, peer=None): + """Continue the interrupted transfers of a peer that is back. + + Reads the persisted stores back (`_load_transfer_progress`) and drives + every download that can be continued: a file the server was sending is + + Args: + peer (tuple | None): Peer ``(ip, port)`` that just connected; None + resumes every peer the client can reach. + + Returns: + int: Number of resumed transfers started or requested. + """ + restored = self._load_transfer_progress() + if restored: + self._log(f"transfer reconnect: restored {restored} interrupted transfer(s)") + if not self.running or self.client_socket is None: + return 0 + server_peer = (self.host, self.port) + if peer is not None and tuple(peer) != server_peer: + # every resume this client drives goes through the server: it is + # the sender of a pushed file and the relay of a forwarded one + return 0 + if not self._wait_control_secure(self.client_socket): + return 0 + candidates = [] + for fid, entry in list(self.file_recv_progress.items()): + if entry[4] is None: + continue # without a peer there is nobody to continue with + with self._forward_resume_lock: + if fid in self._forward_resume_records: + continue # this client relays that transfer: its target drives it + with self._transfer_progress_lock: + if fid in self._active_transfer_fids: + continue # a leg is already running for this fid + candidates.append((fid, entry, tuple(entry[4]))) + started = 0 + for fid, entry, peer_addr in candidates: + if peer_addr == server_peer: + # the server is the sender: ask it directly + threading.Thread( + target=self._resume_receive_leg, + args=(self.client_socket, server_peer, fid, entry), + daemon=True, + ).start() + started += 1 + elif self._request_forward_resume(fid, entry, peer_addr): + # a forwarded transfer: the server routes the request to the + # originating client, which re-forwards it to this one + started += 1 + return started + + def _request_forward_resume(self, fid, entry, originator): + """Ask the server to have a forward's originator continue a transfer. + + The local path is registered before the request goes out: the fresh + relay leg arrives under a new fid but writes the same path, and + `_take_pending_resume` hands its offset to that leg. + """ + offset = _resume_offset_for(entry) + with self._forward_resume_lock: + self._resume_pending_paths[entry[3]] = (fid, offset) + if not self.send_message(self.client_socket, f"{RESUME_LINE} {fid} {offset}"): + with self._forward_resume_lock: + self._resume_pending_paths.pop(entry[3], None) + return False + self._log( + f"resume: asked the server to continue transfer {fid} from {originator} " + f"at byte {offset}" + ) + return True + + def _take_pending_resume(self, path): + """Return the offset a pending resume of this path starts at, or None. + + A forward target that lost a transfer asks its originator to re-send + it; the fresh leg the server then pushes carries a new transfer id but + lands on the same path, so the state registered by the request is what + the leg appends from — and the interrupted entry it replaces is + dropped here. + """ + with self._forward_resume_lock: + pending = self._resume_pending_paths.pop(path, None) + if pending is None: + return None + old_fid, offset = pending + old_entry = self.file_recv_progress.pop(old_fid, None) + if old_entry is not None: + with self._transfer_progress_lock: + self._active_transfer_fids.discard(old_fid) + return offset + + def _resume_receive_leg(self, control_socket, peer_addr, fid, entry): + """Receive the rest of one interrupted transfer, appending to its file. + + Returns: + bool: True when the sender was asked to continue, False when the + request could not be sent. + """ + entry[0] = _resume_offset_for(entry) # the offset the sender is asked for + self._log(f"resume: continuing transfer {fid} with {peer_addr} into {entry[3]}") + port = self.palloc() + try: + return self.file_transfer_mode_recv( + self.host, + port, + control_socket, + f"{peer_addr[0]}:{peer_addr[1]}", + None, + None, + f"/file {shlex.quote(os.path.basename(str(entry[3])))} {fid}", + peer=peer_addr, + resume_entry=entry, + ) is not False + finally: + self.pfree(port) + + def resume_trans(self, peer_addr, fid, offset): + """Continue one interrupted transfer this instance was sending. + + Runs when a receiver asks to continue a transfer (``/resume_trans``, + see `resume_transfers` on the receiving side): the leg is + re-established against the receiver's fresh listener and the source + file is read from the byte offset the receiver already holds. Also the + public API for resuming one transfer on demand. + + Args: + peer_addr (tuple | None): Receiver ``(ip, port)`` the request came + from; None skips the peer check. + fid (int): Transfer id of the interrupted transfer. + offset (int): Byte offset the receiver already holds. + + Returns: + bool: True when the resume leg was started. + """ + entry = self.file_upload_progress.get(fid) + if entry is None: + self._log(f"resume: no outgoing transfer with fid {fid} to continue") + return False + if peer_addr is not None and entry[4] is not None and tuple(entry[4]) != tuple(peer_addr): + self._log(f"resume: transfer {fid} is for {entry[4]}, not {peer_addr}, ignored") + return False + if not self.running or self.client_socket is None: + self._log(f"resume: not connected to the server, transfer {fid} kept") + return False + port_info = self._wait_transfer_server_port(fid) + if port_info is None: + self._log(f"resume: {peer_addr} did not announce a transfer port for {fid}") + return False + port, stamp = port_info + threading.Thread( + target=self._run_resume_send_leg, + args=(entry[3], peer_addr, port, stamp, self.client_socket, fid, offset), + daemon=True, + ).start() + return True + + def _run_resume_send_leg(self, path, peer_addr, port, stamp, control_socket, fid, offset): + """Run one resumed sending leg on its own thread.""" + client_port = self.palloc() + try: + self.file_transfer_mode( + path, + peer_addr[0] if peer_addr else self.host, + port, + client_port, + control_socket=control_socket, + crypto=stamp, + fid=fid, + peer=peer_addr, + resume_offset=offset, + ) + finally: + self.pfree(client_port) + + def _forward_resume_record(self, fid): + """Return the relay record a forwarded resume for ``fid`` belongs to.""" + with self._forward_resume_lock: + return self._forward_resume_records.get(fid) + + def _resume_forward(self, target, fid, offset): + """Re-drive a forwarded transfer to one target, from ``offset``. + + Runs when the server relays a target's resume request + (``/forward_resume``): the recorded relay says what the transfer was, + so the item is forwarded again — only to the target that asked, and + only the remainder of the file it already holds partially. + + Args: + target (tuple): Target client ``(ip, port)`` that lost the file. + fid (int): The relay's transfer id (this client's own namespace). + offset (int): Byte offset the target already holds. + + Returns: + bool: True when the re-forward was started. + """ + record = self._forward_resume_record(fid) + with self._forward_resume_lock: + self._forward_resume_records.pop(fid, None) + entry = self.file_upload_progress.pop(fid, None) + if record is None and entry is None: + self._log(f"resume: no forwarded transfer with fid {fid} to continue") + return False + record = record or {} + targets = [tuple(item) for item in record.get("targets") or []] + kind = record.get("kind") or "file" + rel_dir = record.get("rel_dir") or "" + fname = record.get("fname") or os.path.basename(str((entry or [None, None, None, ""])[3])) + path = record.get("path") or (entry[3] if entry else None) + destination = record.get("destination") + if path is None or not os.path.isfile(path): + self._log(f"resume: the source of forwarded transfer {fid} is gone, giving up") + return False + if targets and tuple(target) not in targets: + self._log(f"resume: {target} is not a target of forwarded transfer {fid}, ignored") + return False + self._log(f"resume: forwarding {path} to {target} again, from byte {offset}") + threading.Thread( + target=self._forward_one, + args=(kind, rel_dir, fname, path, [tuple(target)], destination), + kwargs={"resume_offset": offset}, + daemon=True, + ).start() + return True # ---- native in-memory forward (client side) ---------------------------- @@ -7229,11 +8863,23 @@ def _forward_rel_path(self, base_path, abs_path): return "" return "/" + rel.replace(os.sep, "/") - def _forward_one(self, kind, rel_dir, fname, abspath, addrs, destination_path=None): + def _forward_one( + self, kind, rel_dir, fname, abspath, addrs, destination_path=None, resume_offset=0 + ): + """Forward one item to every target through the server's relay. + + The relay the server answers with is recorded under its fid so a + target that lost the transfer can have it re-driven after a reconnect + (`_resume_forward`); ``resume_offset`` re-sends only the remainder of + a file the target already holds partially. + """ if not os.path.isfile(abspath): self._log(f"forward: {abspath} is not a valid file, skipped") - return + return False msg = f"/forward_item {kind}" + if resume_offset: + # the relay must know how much of the file does not travel again + msg += f" resume={int(resume_offset)}" if kind == "folder": msg += f" {shlex.quote(rel_dir)}" msg += f" {shlex.quote(fname)} " + " ".join(shlex.quote(str(a)) for a in addrs) @@ -7247,7 +8893,7 @@ def _forward_one(self, kind, rel_dir, fname, abspath, addrs, destination_path=No if self._forward_error is not None: self._log(f"forward: server error: {self._forward_error}") self._forward_error = None - return + return False try: upload = self._forward_upload_queue.get(timeout=0.2) break @@ -7255,24 +8901,42 @@ def _forward_one(self, kind, rel_dir, fname, abspath, addrs, destination_path=No continue if upload is None: self._log(f"forward: timed out waiting for an upload slot for {fname}") - return + return False fid, sport, stamp = upload + targets = [(_peer_from_json(target) or (target[0], int(target[1]))) for target in addrs] + record = { + "fid": fid, + "kind": kind, + "rel_dir": rel_dir, + "fname": fname, + "path": abspath, + "destination": destination_path, + "targets": [list(target) for target in targets], + } + with self._forward_resume_lock: + self._forward_resume_records[fid] = record client_port = self.palloc() try: - self.file_transfer_mode( + sent = self.file_transfer_mode( abspath, self.host, sport, client_port, - pause_fid=fid, control_socket=self.client_socket, crypto=stamp, fid=fid, + peer=targets[0] if targets else None, # a forwarded leg stores its original target + resume_offset=resume_offset, ) finally: self.pfree(client_port) - with self._forward_pause_cond: - self._forward_pause.pop(fid, None) + with self._transfer_pause_cond: + self._transfer_pause.pop(fid, None) + if sent: + # the whole item went through: nothing is left to resume for this relay + with self._forward_resume_lock: + self._forward_resume_records.pop(fid, None) + return sent def file_folder_transfer_client_recv_server_start_thread( self, command, client_id, client_socket @@ -7309,9 +8973,37 @@ def file_transfer_client_recv_server_start( new_save_path, file_name, command, + peer=self._command_peer(command), # the sender a resume is asked to continue from ) self.pfree(file_transfer_server_port) + def _own_address_text(self): + """Return this client's own ``"ip:port"`` as the server sees it, when known.""" + if self.client_socket is not None: + try: + address = self.client_socket.getsockname() + return f"{address[0]}:{address[1]}" + except OSError: + pass # the socket is gone: fall back to the configured address + if self.client_port: + return f"{self.client_host}:{self.client_port}" + return None + + def _command_peer(self, command): + """Return the sender a received transfer command belongs to. + + A file pushed by the server itself carries this client's own address, + which `parse_forward_originator` filters out: the sender is then the + server. A forwarded item carries the originating client's address — + the original peer a resume asks to continue the transfer. + + Returns: + tuple: ``(ip, port)`` of the transfer's original sender. + """ + originator = parse_forward_originator(command, own_address=self._own_address_text()) + peer = _peer_from_text(originator) if originator else None + return peer if peer is not None else (self.host, self.port) + def file_transfer_mode_recv( self, server_file_address, @@ -7321,7 +9013,21 @@ def file_transfer_mode_recv( new_save_path, file_name, command, + peer=None, + resume_entry=None, ): + """Receive one file over a transfer sub-connection. + + ``peer`` is the transfer's original sender (the server for a pushed + file, the originating client for a forwarded one — never the relay): + it is stored with the progress entry so a later reconnect can ask that + peer to continue the file. + + ``resume_entry`` continues an interrupted transfer: the listener + announces itself, asks the sender to continue from the bytes already + on disk (``RESUME_LINE``) and appends the incoming chunks to the + partial file instead of truncating it. + """ file_running = True client_file_socket = None server_file_socket = None @@ -7361,11 +9067,22 @@ def file_transfer_client_recv(client_id): nonlocal file_running nonlocal client_file_socket nonlocal server_file_socket - nonlocal save_path filename = None full_path = None progress = None # this leg's file_recv_progress entry, when tracked - self.send_message(client_file_socket, self.server_start_file_transfer_sign) + finished_ok = False + try: + self.send_message(client_file_socket, self.server_start_file_transfer_sign) + except Exception as e: + # the instance stopped (or the peer vanished) between the accept + # and this start sign: the transfer is over. A closing instance + # raises RuntimeError("connection error") by design — the normal + # teardown signal — and it must never kill this thread. + if not _is_closed_socket_error(e): + self._log(f"error while starting the file transfer: {e}") + self._log_exc() + close_socket() + return False try: name_len_bytes = b"" while len(name_len_bytes) < 4: @@ -7427,21 +9144,38 @@ def file_transfer_client_recv(client_id): file_size = int.from_bytes(size_bytes, "big") self.send_message(client_file_socket, self.server_received_file_header_sign) original_filename = filename - if file_name: - final_filename = file_name.strip() - elif command_part[0] == "/crypto_pub_key": - # concurrent key pushes share received_files/: a fixed name would be - # overwritten/moved by another connection before this one consumes it - final_filename = "{}.pem".format(uuid.uuid4().hex) + if resume_entry is not None: + # continued transfer: the receiver's partial file keeps the + # bytes that are already on disk and the sender continues + full_path = resume_entry[3] + final_filename = os.path.basename(full_path) + resume_from = resume_entry[0] # the offset the sender was asked to continue from else: - final_filename = os.path.basename(original_filename) - full_path = os.path.join(save_path, final_filename).strip() + if file_name: + final_filename = file_name.strip() + elif command_part[0] == "/crypto_pub_key": + # concurrent key pushes share received_files/: a fixed name would be + # overwritten/moved by another connection before this one consumes it + final_filename = "{}.pem".format(uuid.uuid4().hex) + else: + final_filename = os.path.basename(original_filename) + full_path = os.path.join(save_path, final_filename).strip() + # a forwarded transfer this client asked to continue arrives + # as a fresh leg on the same path: keep the bytes on disk + resume_from = self._take_pending_resume(full_path) or 0 + if resume_from <= 0 or resume_from > file_size: + resume_from = 0 # not this file's offset any more: start it over os.makedirs(os.path.dirname(full_path), exist_ok=True) progress = self._file_progress_start( - self.file_recv_progress, progress_fid, file_size, final_filename + self.file_recv_progress, + progress_fid, + file_size, + full_path, + peer=peer, + initial=resume_from, ) - with open(full_path.strip(), "wb") as f: - remaining = file_size + with _open_transfer_target(full_path, resume_from) as f: + remaining = file_size - resume_from while remaining > 0: chunk = self.receive_message( client_file_socket, min(self.file_transfer_chunk_len, remaining) @@ -7459,6 +9193,8 @@ def file_transfer_client_recv(client_id): f.write(chunk) remaining -= len(chunk) self._file_progress_update(progress, len(chunk), is_upload=False) + f.truncate() # a longer partial file drops its stale tail + finished_ok = True # TOFU first: the ack is only a notification, and a failed # ack send must not skip the key registration (readiness # would never be announced and the handshake hangs) @@ -7478,9 +9214,9 @@ def file_transfer_client_recv(client_id): close_socket() except Exception as e: self._log_exc() - if full_path is not None and os.path.exists(full_path): + if full_path is not None and os.path.exists(full_path) and progress is None: try: - os.remove(full_path) # partial transfer: no half-written leftovers + os.remove(full_path) # untracked partial transfer: nothing can resume it except OSError: pass try: @@ -7494,7 +9230,17 @@ def file_transfer_client_recv(client_id): close_socket() return None finally: - self._file_progress_finish(self.file_recv_progress, progress_fid, progress) + self._file_progress_finish( + self.file_recv_progress, + progress_fid, + progress, + keep=( + not finished_ok + and progress is not None + and progress[4] is not None # an interrupted transfer with a peer can be resumed + ), + ) + self._release_transfer_socket(progress_fid, client_file_socket) server_file_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_file_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -7507,6 +9253,7 @@ def file_transfer_client_recv(client_id): stamp = self._crypto_transfer_stamp( client_socket, force_plain=command_part[0] == "/crypto_pub_key" ) + self._forget_transfer_port(progress_fid) # an older session's entry is stale transfer_server_port_msg = "/server_file_transfer_port {} {} {}\n".format( file_transfer_server_port, file_client_id, stamp ) @@ -7514,16 +9261,42 @@ def file_transfer_client_recv(client_id): client_socket, transfer_server_port_msg ) # coordination line: always plaintext (like the handshake) server_file_socket.listen(1) + if resume_entry is not None: + # the receiver drives a resumed transfer: it asks the sender to + # continue the file from the bytes already on disk + offset = _resume_offset_for(resume_entry) + if progress_fid is None or not self.send_message( + client_socket, f"{RESUME_LINE} {progress_fid} {offset}" + ): + self._log( + f"resume: cannot ask {client_id} to continue transfer {progress_fid}" + ) + server_file_socket.close() + return False + server_file_socket.settimeout(RESUME_ACCEPT_TIMEOUT) try: client_file_socket, client_file_address = server_file_socket.accept() + if resume_entry is not None: + client_file_socket.settimeout(None) # the accept timeout is the listener's only self._crypto_attach_transfer_in(client_file_socket, client_socket, stamp) - is_open_file_transfer = setting_file_save_path() - if is_open_file_transfer == None: - pass - else: + self._register_transfer_socket(progress_fid, client_file_socket) + if resume_entry is not None: threading.Thread( target=file_transfer_client_recv, args=(client_id,), daemon=True ).start() + else: + is_open_file_transfer = setting_file_save_path() + if is_open_file_transfer == None: + pass + else: + threading.Thread( + target=file_transfer_client_recv, args=(client_id,), daemon=True + ).start() + except socket.timeout: + self._log( + f"resume: {client_id} did not continue transfer {progress_fid}, " + f"it stays in the progress stores for the next reconnect" + ) except Exception as e: self._log(f"\nget file transfer msg error: {e}") self._log_exc() @@ -7535,13 +9308,16 @@ def close(self): # close connection """Close the connection and release everything the client owns. Stops the receive loop, releases the port range, flushes the message and - event stores and closes the socket. Safe to call more than once. + event stores, persists the interrupted transfers and closes the socket. + Safe to call more than once. """ self.running = False self._stopped = True # also cancels a connect() still in flight self.free_port() self._flush_messages_dict() self._flush_events_dict() + # transfers still in flight are kept on disk for the next connect + self._persist_transfer_progress() with self._crypto_lock: if self.client_socket is not None: self._channels.pop(self.client_socket, None) @@ -7566,19 +9342,33 @@ def start_TCP_client(self): # start client process with status 1 when the connection cannot be established; Ctrl-C and the end of the connection both run `close`. A client that was closed while still connecting returns quietly, because that stop was asked for. + + With ``is_auto_reconnect`` True a dropped connection does not end the + client: it reconnects (waiting for the server when ``is_wait_server`` + is set) and every session carries the interrupted transfers of the + previous one (`resume_transfers`). A close or ``/quit`` still stops + the client. """ - if not self.connect(): - if self._stopped: - return # close() won the race with the connection attempt - sys.exit(1) - try: - if self.is_input_command_in_console: - self.interactive_mode() - else: - while self.running: - time.sleep(1) - except KeyboardInterrupt: - self._log("\nclient shutting down...") - self._log_exc() - finally: - self.close() + while True: + if not self.connect(): + if self._stopped: + return # close() won the race with the connection attempt + if not self.is_auto_reconnect: + sys.exit(1) + self._log("reconnect in 1 second...") + time.sleep(1) + continue + try: + if self.is_input_command_in_console: + self.interactive_mode() + else: + while self.running: + time.sleep(1) + except KeyboardInterrupt: + self._log("\nclient shutting down...") + self._log_exc() + if self._stopped or not self.is_auto_reconnect: + self.close() + return + self._log("connection lost, reconnecting in 1 second...") + time.sleep(1) diff --git a/PyFlow/transfer_web/web_backend/server_backend.py b/PyFlow/transfer_web/web_backend/server_backend.py index b3feab4..e47b117 100644 --- a/PyFlow/transfer_web/web_backend/server_backend.py +++ b/PyFlow/transfer_web/web_backend/server_backend.py @@ -213,7 +213,7 @@ def _transfer_rows(progress): - """JSON rows for one progress store (``fid -> [transferred, total, speed, name]``). + """JSON rows for one progress store (``fid -> [transferred, total, speed, path, peer]``). Returns: list[dict]: One row per running transfer, ordered by file name. @@ -223,7 +223,7 @@ def _transfer_rows(progress): rows.append( { "fid": fid, - "name": entry[3], + "name": os.path.basename(str(entry[3])), "transferred": entry[0], "total": entry[1], "speed": entry[2], diff --git a/PyFlow/transfer_web/web_front/client_backend.py b/PyFlow/transfer_web/web_front/client_backend.py index 204f5e6..c6da8a8 100644 --- a/PyFlow/transfer_web/web_front/client_backend.py +++ b/PyFlow/transfer_web/web_front/client_backend.py @@ -261,7 +261,7 @@ def _channel_ready(client): def _transfer_rows(progress): - """JSON rows for one progress store (``fid -> [transferred, total, speed, name]``). + """JSON rows for one progress store (``fid -> [transferred, total, speed, path, peer]``). Returns: list[dict]: One row per running transfer, ordered by file name. @@ -271,7 +271,7 @@ def _transfer_rows(progress): rows.append( { "fid": fid, - "name": entry[3], + "name": os.path.basename(str(entry[3])), "transferred": entry[0], "total": entry[1], "speed": entry[2], diff --git a/docs/source/File_Transfer/File_Transfer.rst b/docs/source/File_Transfer/File_Transfer.rst index 2f04fa4..c47dccf 100644 --- a/docs/source/File_Transfer/File_Transfer.rst +++ b/docs/source/File_Transfer/File_Transfer.rst @@ -647,20 +647,25 @@ Both classes record every running file transfer: The keys are the transfers' fids: the transfer id the sender stamps on the transfer command (``/file ``), which also identifies the relay leg of a forwarded file. The protocol-internal public-key push is not tracked. -Each value is a four-item list: +Each value is a five-item list: - ``[0]``: bytes transferred so far; - ``[1]``: total size of the file, in bytes; - ``[2]``: the current network speed of that direction — ``None`` until the transfer has moved its first chunk, and while ``is_enable_real_time_network_speed`` is ``False``; -- ``[3]``: name of the file being transferred. +- ``[3]``: local path of the file: the source of an outbound transfer, the + file being written for an inbound one; +- ``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender in + a download's entry, the receiver in an upload's. A forwarded transfer + stores the original peer on both sides, never the relaying server. An entry appears when a transfer starts and is removed when it ends, so the stores hold exactly the transfers that are in flight at that moment (iterate over a copy while transfers are running). With ``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is ever -recorded. +recorded — and, since the stores are the state a reconnect resumes from, no +transfer can be resumed either. ``is_enable_real_time_network_speed`` (``True`` by default) measures the protocol's current traffic — the control layer and every temporary @@ -674,6 +679,44 @@ The web tool (``transfer_web``) reads these stores: both backends serve frontend renders the live speed readout in the topbar and one progress bar per running transfer. +.. _transfer-pause-and-reconnect: + +Pausing, Reconnecting and Resuming Transfers +-------------------------------------------- + +An outbound transfer can be held and released at any time with the +``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or from +the peer with the ``/pause_trans `` and ``/start_trans `` lines: +``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, fid)`` send them. +The leg stops before its next chunk and stays open; a leg that is paused +keeps its socket, so nothing is torn down. Every outbound transfer honours +its own fid — a plain upload as much as the upload leg of a forwarded file — +so the flow control the server uses on a relay works on any transfer. + +The temporary connections of a transfer are resumed after a disconnect: + +- when a connection drops, both sides write their transfer stores to + ``.Flow/server_file_trans_progress.json`` / + ``.Flow/client_file_trans_progress.json`` (the ``file_trans_progress_file`` + attribute) — every upload, every download and, on the server, the relay + records a disconnected forward is re-driven from; +- an interrupted transfer keeps its progress entry and its partial file + instead of dropping them, so the file on disk is exactly the state to + continue from; +- after a reconnect the receiver drives the resume (`resume_transfers`): it + opens a fresh transfer listener, announces it and sends + ``/resume_trans `` with the byte offset its partial file + holds. The sender re-establishes the leg, reads its source from that offset + and only the remainder of the file travels. A forwarded transfer is asked + for through the server, which routes ``/forward_resume`` to the originating + client so it re-forwards just the missing part. + +The server resumes a peer's transfers when it reconnects, and a client with +``is_auto_reconnect=True`` reconnects on its own and resumes every transfer it +can reach; `resume_transfers` is public, so an application can also drive the +resume itself. Legs the previous session left behind are closed before the +resume runs, so two legs never write the same transfer. + .. _related-apis: Related API Definitions @@ -755,9 +798,14 @@ file to disk. .. code-block:: python def file_transfer_mode( - self, filename, server_address, server_port, client_port, pause_fid=None, fid=None) + self, filename, server_address, server_port, client_port, + control_socket=None, crypto=None, fid=None, peer=None, resume_offset=0) Low-level send function that connects to the receiver and transmits the file. +``fid`` keys the leg in ``file_upload_progress`` and is what +``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's +original receiver and ``resume_offset`` continues an interrupted file from +the byte the receiver already holds. ### Client-Side File Transfer APIs @@ -823,7 +871,8 @@ Low-level receive function on the client side. .. code-block:: python def file_transfer_mode( - self, filename, server_address, server_port, client_port, pause_fid=None, fid=None) + self, filename, server_address, server_port, client_port, + control_socket=None, crypto=None, fid=None, peer=None, resume_offset=0) Low‑level send function on the client side (identical to server's version). @@ -844,6 +893,9 @@ reference. - ``multiple_file_multiple_client_transfer_server_recv_client_start`` - ``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`` - ``file_folder_transfer_server_recv_server_start_thread`` (folder receiving) +- ``pause_trans`` / ``start_trans`` (hold and release an outbound transfer) +- ``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it) +- ``resume_transfers`` / ``resume_trans`` (continue interrupted transfers) (The low-level helpers ``file_transfer_server_recv_server_start``, @@ -861,6 +913,9 @@ public but are documented for completeness.) - ``file_transfer_client_recv_server_start`` - ``file_transfer_client_recv_server_start_thread`` - ``file_folder_transfer_client_recv_server_start_thread`` +- ``pause_trans`` / ``start_trans`` (hold and release an outbound transfer) +- ``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it) +- ``resume_transfers`` / ``resume_trans`` (continue interrupted transfers) (The low-level helpers are documented but not part of the public API.) diff --git a/docs/source/Network_APIs/TCP_Client_APIs.rst b/docs/source/Network_APIs/TCP_Client_APIs.rst index 7896824..cf7bb4b 100644 --- a/docs/source/Network_APIs/TCP_Client_APIs.rst +++ b/docs/source/Network_APIs/TCP_Client_APIs.rst @@ -74,8 +74,14 @@ The parameters of the ``__init__`` method are as follows: - ``is_enable_file_transfer_progress_bar``: A flag indicating whether every running file transfer is tracked in ``file_recv_progress`` (downloads) and ``file_upload_progress`` (uploads). Each entry is a - ``[transferred bytes, total bytes, current speed, file name]`` list keyed by the - transfer's fid, and is removed once the transfer ends. + ``[transferred bytes, total bytes, current speed, local file path, peer]`` + list keyed by the transfer's fid — ``peer`` is the ``(ip, port)`` of the + transfer's original sender (downloads) or receiver (uploads), never the + relay of a forwarded transfer. The entry is removed once the transfer ends; + an interrupted one keeps its entry (and its partial file) so the reconnect + logic can resume it. + ``file_trans_progress_file`` names the file under the protocol's ``.Flow`` + directory these stores are written to when the connection drops. - ``is_enable_real_time_network_speed``: A flag indicating whether the protocol's real-time network speed is measured. With ``True`` (the default) every send and receive — the control layer and every temporary connection, @@ -117,6 +123,9 @@ Every parameter has default values: (``False`` records no transfer progress) - ``is_enable_real_time_network_speed``: Default is ``True`` (``False`` measures no speed; every speed value is ``None``) +- ``is_auto_reconnect``: Default is ``False`` + (``True`` makes `start_TCP_client` reconnect after the connection drops and + resume the interrupted transfers, see :ref:`transfer-pause-and-reconnect`) The TCP Client Setup API will initialize all the necessary parameters and resources for the TCP client. @@ -724,10 +733,13 @@ And the low-level send mode function is: .. code-block:: python def file_transfer_mode( - self, filename, server_address, server_port, client_port, pause_fid=None) + self, filename, server_address, server_port, client_port, + control_socket=None, crypto=None, fid=None, peer=None, resume_offset=0) -``pause_fid`` is the forwarding id used to pause/resume the transfer with -``/pause_trans`` / ``/start_trans``. +``fid`` keys the leg in ``file_upload_progress`` and is what +``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) +addresses; ``peer`` is the transfer's original receiver and ``resume_offset`` +continues an interrupted file from the byte the receiver already holds. We recommend that for client-to-server file transfers, you use the console commands (``/file``, ``/file_folder``, @@ -846,9 +858,14 @@ is as follows: - `file_transfer_client_recv_server_start` - `file_transfer_client_recv_server_start_thread` - `file_folder_transfer_client_recv_server_start_thread` - - `file_transfer_mode_recv` - `file_transfer_mode` +5.1. The transfer pause and reconnect APIs (see + :ref:`transfer-pause-and-reconnect`): + - `pause_trans` / `start_trans` + - `pause_trans_remote` / `start_trans_remote` + - `resume_transfers` / `resume_trans` + 6. The client console commands (interactive mode): - `/quit` - `/file` diff --git a/docs/source/Network_APIs/TCP_Server_APIs.rst b/docs/source/Network_APIs/TCP_Server_APIs.rst index 4180237..31c76a3 100644 --- a/docs/source/Network_APIs/TCP_Server_APIs.rst +++ b/docs/source/Network_APIs/TCP_Server_APIs.rst @@ -79,8 +79,14 @@ The parameters of the ``__init__`` method are as follows: - ``is_enable_file_transfer_progress_bar``: A flag indicating whether every running file transfer is tracked in ``file_recv_progress`` (downloads) and ``file_upload_progress`` (uploads). Each entry is a - ``[transferred bytes, total bytes, current speed, file name]`` list keyed by the - transfer's fid, and is removed once the transfer ends. + ``[transferred bytes, total bytes, current speed, local file path, peer]`` + list keyed by the transfer's fid — ``peer`` is the ``(ip, port)`` of the + transfer's original sender (downloads) or receiver (uploads), never the + relay of a forwarded transfer. The entry is removed once the transfer ends; + an interrupted one keeps its entry (and its partial file) so the reconnect + logic can resume it. + ``file_trans_progress_file`` names the file under the protocol's ``.Flow`` + directory these stores are written to when a connection drops. - ``is_enable_real_time_network_speed``: A flag indicating whether the protocol's real-time network speed is measured. With ``True`` (the default) every send and receive — the control layer and every temporary connection, @@ -589,7 +595,13 @@ Built-in client commands include: - ``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``: internal handshake messages of the encrypted channel. - ``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, ``/start_trans``: - internal forwarding/transfer-control messages. + internal forwarding/transfer-control messages. ``/pause_trans `` and + ``/start_trans `` hold and release the outbound transfer with that fid + (`pause_trans`/`start_trans` are the same switch as a public API). +- ``/resume_trans `` and ``/forward_resume ``: + internal transfer-reconnect messages: the receiver asks the sender (or, for + a forwarded transfer, the originator) to continue the file from the bytes + already on disk. See `resume_transfers`. - ``/server_file_transfer_port ``: internal protocol message used to coordinate file transfer ports. In `handle_command`, the server will first @@ -1041,6 +1053,14 @@ are as follows: - `folder_file_transfer_server_recv_client_start` - `multiple_file_multiple_client_transfer_server_recv_client_start` - `diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start` + - `file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg + - `forward_item_to` / `forward_message_to`: single forward destinations + +5.1. The transfer pause and reconnect APIs (see + :ref:`transfer-pause-and-reconnect`): + - `pause_trans` / `start_trans` + - `pause_trans_remote` / `start_trans_remote` + - `resume_transfers` / `resume_trans` 6. The server console commands: - `/stop` diff --git a/test/integration/conftest.py b/test/integration/conftest.py index 9143751..7008b3b 100644 --- a/test/integration/conftest.py +++ b/test/integration/conftest.py @@ -1,5 +1,5 @@ import pytest -from helpers import free_port +from helpers import free_port, isolate_instance_files import PyFlow.command_control_extension_tcp as ctl from PyFlow.network_api.connect_tcp import TCP_Client_Base, TCP_Server_Base @@ -7,12 +7,13 @@ @pytest.fixture -def server(monkeypatch): +def server(monkeypatch, tmp_path): """Create a TCP_Server_Base and inject into command_control_extension_tcp.server_instance. Use this fixture when a test only needs a server instance. """ s = TCP_Server_Base(host="127.0.0.1", port=free_port(), is_extend_command=True) + isolate_instance_files(s, tmp_path, "server") monkeypatch.setattr(ctl, "server_instance", s) try: yield s @@ -21,7 +22,7 @@ def server(monkeypatch): @pytest.fixture -def client(monkeypatch): +def client(monkeypatch, tmp_path): """Create a TCP_Client_Base and inject into command_control_extension_tcp.client_instance. Use this fixture when a test only needs a client instance. @@ -29,6 +30,7 @@ def client(monkeypatch): c = TCP_Client_Base( host="127.0.0.1", port=free_port(), client_host="127.0.0.1", is_extend_command=True ) + isolate_instance_files(c, tmp_path, "client") monkeypatch.setattr(ctl, "client_instance", c) try: yield c @@ -37,7 +39,7 @@ def client(monkeypatch): @pytest.fixture -def server_client(monkeypatch): +def server_client(monkeypatch, tmp_path): """Create both server and client and inject both module globals. Use this when a test requires both sides present. @@ -46,6 +48,8 @@ def server_client(monkeypatch): c = TCP_Client_Base( host="127.0.0.1", port=free_port(), client_host="127.0.0.1", is_extend_command=True ) + isolate_instance_files(s, tmp_path, "server") + isolate_instance_files(c, tmp_path, "client") monkeypatch.setattr(ctl, "server_instance", s) monkeypatch.setattr(ctl, "client_instance", c) try: diff --git a/test/integration/helpers.py b/test/integration/helpers.py index 3aa44cf..2cba9e6 100644 --- a/test/integration/helpers.py +++ b/test/integration/helpers.py @@ -40,3 +40,16 @@ def free_port(): _recent_ports.append(port) return port raise RuntimeError("the OS kept handing out recently used ports") + + +def isolate_instance_files(instance, tmp_path, name): + """Point one instance's logs and transfer progress file at a temp directory. + + Every instance defaults to the same files under the protocol's project + directory: concurrent instances would race on them, and a fresh client + would read (and resume) the interrupted transfers another test left + behind. + """ + instance.messages_log_file = str(tmp_path / f"{name}_messages_log.json") + instance.events_log_file = str(tmp_path / f"{name}_events_log.json") + instance.file_trans_progress_file = str(tmp_path / f"{name}_file_trans_progress.json") diff --git a/test/integration/network_api/test_crypto_tcp.py b/test/integration/network_api/test_crypto_tcp.py index 49da71d..3aa8064 100644 --- a/test/integration/network_api/test_crypto_tcp.py +++ b/test/integration/network_api/test_crypto_tcp.py @@ -77,6 +77,7 @@ def tcp_pair(tmp_path): is_enable_encrypto=True, ) _redirect_crypto(server.crypto, tmp_path, ssh_dir, "pub_key") + server.file_trans_progress_file = str(tmp_path / "server_file_trans_progress.json") threading.Thread(target=server.start_TCP_Server, daemon=True).start() assert server_ready(server), "server did not start" @@ -89,6 +90,7 @@ def tcp_pair(tmp_path): is_enable_encrypto=True, ) _redirect_crypto(client.crypto, tmp_path, ssh_dir, "pub_key_client") + client.file_trans_progress_file = str(tmp_path / "client_file_trans_progress.json") assert client.connect() yield server, client, tmp_path diff --git a/test/integration/network_api/test_message_event_store.py b/test/integration/network_api/test_message_event_store.py index 275099a..bdc0f6e 100644 --- a/test/integration/network_api/test_message_event_store.py +++ b/test/integration/network_api/test_message_event_store.py @@ -30,6 +30,7 @@ def pair(tmp_path): ) server.messages_log_file = str(tmp_path / "server_messages_log.json") server.events_log_file = str(tmp_path / "server_events_log.json") + server.file_trans_progress_file = str(tmp_path / "server_file_trans_progress.json") threading.Thread(target=server.start_TCP_Server, daemon=True).start() assert server_ready(server), "server did not start" client = TCP_Client_Base( @@ -42,6 +43,7 @@ def pair(tmp_path): ) client.messages_log_file = str(tmp_path / "client_messages_log.json") client.events_log_file = str(tmp_path / "client_events_log.json") + client.file_trans_progress_file = str(tmp_path / "client_file_trans_progress.json") assert client.connect() yield server, client client.close() diff --git a/test/integration/network_api/test_tcp_file_transfer.py b/test/integration/network_api/test_tcp_file_transfer.py index d7dd6c5..e2710a3 100644 --- a/test/integration/network_api/test_tcp_file_transfer.py +++ b/test/integration/network_api/test_tcp_file_transfer.py @@ -4,11 +4,12 @@ import threading import time import shlex +from pathlib import Path import pytest -from helpers import free_port, server_ready, wait_until +from helpers import free_port, isolate_instance_files, server_ready, wait_until from PyFlow.network_api.connect_tcp import ( TCP_Client_Base, @@ -19,15 +20,14 @@ def _isolate_log_files(instance, log_dir, name): - """Keep an instance's message/event logs out of the shared project directory. + """Keep an instance's logs and transfer progress file out of the project dir. - Every instance defaults to the same ``messages_log.json`` / - ``events_log.json`` under the project directory: concurrent writers then - race on the same temp file and the losing flush is dropped with - "log file update failed". + Every instance defaults to the same files under the project directory: + concurrent writers then race on the same temp file and the losing flush is + dropped with "log file update failed", and a fresh instance would read the + interrupted transfers another test left behind. """ - instance.messages_log_file = str(log_dir / f"{name}_messages_log.json") - instance.events_log_file = str(log_dir / f"{name}_events_log.json") + isolate_instance_files(instance, Path(log_dir), name) @pytest.fixture @@ -807,11 +807,11 @@ def test_multiple_file_multiple_client_console_command(pair, tmp_path): def test_file_progress_and_speed_are_tracked(pair, tmp_path): """A running transfer is tracked in the progress stores of both sides. - The uploader is held before its first data chunk (pause_fid), so the + The uploader is held before its first data chunk (`pause_trans`), so the in-flight state — the entry at zero bytes with the full size — is observed deterministically; after the transfer the entries are gone, while the - captured lists show every byte was folded in and the speed slots hold live - values. + captured lists show every byte was folded in, the peer slot holds the + transfer's original peer and the speed slots hold live values. """ server, client, _ = pair server_recv = tmp_path / "server_recv" @@ -823,16 +823,18 @@ def test_file_progress_and_speed_are_tracked(pair, tmp_path): fid = 4242 server_sock = server.clients[client.client_socket.getsockname()]["socket"] - server.file_transfer_server_recv_server_start_thread("cid", server_sock, f"/file {src} {fid}") + client_id = "%s:%s" % client.client_socket.getsockname() + server.file_transfer_server_recv_server_start_thread( + client_id, server_sock, f"/file {src} {fid}" + ) server_port = _wait_port(client) assert server_port is not None - with client._forward_pause_cond: - client._forward_pause[fid] = True + assert client.pause_trans(fid) is False # armed before the leg exists sender = threading.Thread( target=client.file_transfer_mode, args=(str(src), "127.0.0.1", server_port, 0), - kwargs={"pause_fid": fid, "fid": fid}, + kwargs={"fid": fid, "peer": (server.host, server.port)}, daemon=True, ) sender.start() @@ -847,11 +849,13 @@ def test_file_progress_and_speed_are_tracked(pair, tmp_path): upload_entry = client.file_upload_progress[fid] assert recv_entry[:2] == [0, len(payload)] assert upload_entry[:2] == [0, len(payload)] - assert recv_entry[3] == "upload.bin" and upload_entry[3] == "upload.bin" + # the local path of each side, and the transfer's original peer + assert recv_entry[3] == str(server_recv / "upload.bin") + assert upload_entry[3] == str(src) + assert recv_entry[4] == client.client_socket.getsockname() + assert upload_entry[4] == (server.host, server.port) finally: - with client._forward_pause_cond: - client._forward_pause[fid] = False - client._forward_pause_cond.notify_all() + client.start_trans(fid) sender.join(timeout=15) assert not sender.is_alive(), "the upload did not finish" @@ -871,14 +875,12 @@ def got(): assert server.recv_network_speed > 0 assert client.upload_network_speed > 0 - def test_download_progress_and_speed_are_tracked(pair, tmp_path): """The reverse direction is tracked too: the server uploads, the client downloads, and both progress stores follow the same fid. - The server-side pause gate is created by the test because no server-side - caller passes ``pause_fid`` (only forward uploads use the pause); the send - loop reads both attributes like the client's. + The server-side pause uses the same public API as the client's: any + outbound transfer is held by the fid it runs under. """ server, client, recv_dir = pair src = tmp_path / "download.bin" @@ -895,12 +897,11 @@ def test_download_progress_and_speed_are_tracked(pair, tmp_path): server_port = _wait_port(server) assert server_port is not None - server._forward_pause = {fid: True} - server._forward_pause_cond = threading.Condition() + assert server.pause_trans(fid) is False # armed before the leg exists sender = threading.Thread( target=server.file_transfer_mode, args=(str(src), "127.0.0.1", server_port, 0), - kwargs={"pause_fid": fid, "fid": fid}, + kwargs={"fid": fid, "peer": client.client_socket.getsockname()}, daemon=True, ) sender.start() @@ -915,11 +916,12 @@ def test_download_progress_and_speed_are_tracked(pair, tmp_path): upload_entry = server.file_upload_progress[fid] assert recv_entry[:2] == [0, len(payload)] assert upload_entry[:2] == [0, len(payload)] - assert recv_entry[3] == "download.bin" and upload_entry[3] == "download.bin" + assert recv_entry[3] == str(recv_dir / "download.bin") + assert upload_entry[3] == str(src) + assert recv_entry[4] == (server.host, server.port) + assert upload_entry[4] == client.client_socket.getsockname() finally: - with server._forward_pause_cond: - server._forward_pause[fid] = False - server._forward_pause_cond.notify_all() + server.start_trans(fid) sender.join(timeout=15) assert not sender.is_alive(), "the download did not finish" @@ -981,12 +983,11 @@ def test_file_progress_and_speed_can_be_disabled(tmp_path): server_port = _wait_port(client) assert server_port is not None - with client._forward_pause_cond: - client._forward_pause[fid] = True + client.pause_trans(fid) # the pause works with tracking off too sender = threading.Thread( target=client.file_transfer_mode, args=(str(src), "127.0.0.1", server_port, 0), - kwargs={"pause_fid": fid, "fid": fid}, + kwargs={"fid": fid, "peer": (server.host, server.port)}, daemon=True, ) sender.start() @@ -999,9 +1000,7 @@ def test_file_progress_and_speed_can_be_disabled(tmp_path): assert server.file_recv_progress == {} assert client.file_upload_progress == {} finally: - with client._forward_pause_cond: - client._forward_pause[fid] = False - client._forward_pause_cond.notify_all() + client.start_trans(fid) sender.join(timeout=15) assert not sender.is_alive(), "the upload did not finish" diff --git a/test/integration/network_api/test_tcp_transfer_resume.py b/test/integration/network_api/test_tcp_transfer_resume.py new file mode 100644 index 0000000..ee7e275 --- /dev/null +++ b/test/integration/network_api/test_tcp_transfer_resume.py @@ -0,0 +1,533 @@ +"""Integration tests for the transfer reconnect (resume) mechanism. + +A transfer interrupted by a disconnect keeps its progress entry and its +partial file; both sides write the entries to ``.Flow`` when the connection +drops, and after a reconnect the receiver asks the sender to continue the file +from the bytes it already holds. The tests drive that exchange over real +sockets, with the interrupted state either produced by a real disconnected +session or loaded from the persisted file exactly as a disconnect leaves it. +""" + +import json +import os +import shlex +import threading +import time + +from helpers import free_port, isolate_instance_files, server_ready, wait_until + +from PyFlow.network_api.connect_tcp import TCP_Client_Base, TCP_Server_Base + + +def _isolate(instance, tmp_path, name): + """Keep an instance's logs and its transfer progress file out of the repo.""" + isolate_instance_files(instance, tmp_path, name) + + +def _wait_port(instance, timeout=10.0): + """Wait for the transfer port the instance's peer announced.""" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + with instance.file_transfer_server_port_lock: + ports = list(instance.file_server_port_list) + if ports: + return ports[0][0] + time.sleep(0.05) + return None + + +def _redirect_crypto(crypto, tmp_path, ssh_dir, subdir="pub_key"): + """Keep one instance's key material inside the test's temp directory.""" + crypto.pvt_key_dir = str(tmp_path / "pvt_key") + crypto.pub_key_dir = str(tmp_path / subdir) + crypto.ssh_dir = str(ssh_dir) + crypto.registry_path = os.path.join(crypto.pub_key_dir, "pub_key.json") + os.makedirs(crypto.pvt_key_dir, exist_ok=True) + os.makedirs(crypto.pub_key_dir, exist_ok=True) + + +def _start_server(tmp_path, name="server", **kwargs): + port = free_port() + server = TCP_Server_Base( + host="127.0.0.1", + port=port, + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=False, + **kwargs, + ) + _isolate(server, tmp_path, name) + threading.Thread(target=server.start_TCP_Server, daemon=True).start() + assert server_ready(server), "server did not start" + return server + + +def _start_client(tmp_path, server, name="client", recv_dir=None, **kwargs): + client = TCP_Client_Base( + host="127.0.0.1", + port=server.port, + client_host="127.0.0.1", + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=False, + **kwargs, + ) + _isolate(client, tmp_path, name) + if recv_dir is not None: + client.file_transfer_dir = str(recv_dir) + assert client.connect() + return client + + +def test_progress_entries_round_trip_through_the_progress_file(tmp_path): + """Both stores are written with their peer tuples and read back intact.""" + server = _start_server(tmp_path) + try: + server.file_recv_progress[7] = [128, 1024, None, "/tmp/part.bin", ("127.0.0.1", 5000)] + server.file_upload_progress[9] = [64, 512, None, "/tmp/src.bin", ("127.0.0.1", 6000)] + server._persist_transfer_progress() + + with open(server.file_trans_progress_file, "r", encoding="utf-8") as f: + written = json.load(f) + assert written["download"]["7"] == [ + 128, + 1024, + None, + "/tmp/part.bin", + ["127.0.0.1", 5000], + ] + assert written["upload"]["9"] == [64, 512, None, "/tmp/src.bin", ["127.0.0.1", 6000]] + + server.file_recv_progress.clear() + server.file_upload_progress.clear() + assert server._load_transfer_progress() == 2 # noqa: PLR2004 + assert server.file_recv_progress[7] == [ + 128, + 1024, + None, + "/tmp/part.bin", + ("127.0.0.1", 5000), + ] + assert server.file_upload_progress[9] == [ + 64, + 512, + None, + "/tmp/src.bin", + ("127.0.0.1", 6000), + ] + + # a live transfer owns its fid: a load must not overwrite it + server.file_recv_progress.clear() + server.file_upload_progress.clear() + server.file_recv_progress[7] = [999, 1024, None, "/tmp/live.bin", None] + assert server._load_transfer_progress() == 1 + assert server.file_recv_progress[7] == [999, 1024, None, "/tmp/live.bin", None] + assert server.file_upload_progress[9][0] == 64 # noqa: PLR2004 + finally: + server.stop() + + +def test_paused_transfer_is_persisted_when_the_connection_drops(tmp_path): + """A disconnect during a transfer writes both stores for the next connect. + + The uploader is held paused, so the in-flight state is deterministic: the + receiver keeps its (empty) partial file, and both sides persist their + entries — the receiver with the sender's address, the uploader with the + receiver's — under the protocol's ``.Flow`` directory. + """ + server = _start_server(tmp_path) + server_recv = tmp_path / "server_recv" + server_recv.mkdir() + server.file_transfer_dir = str(server_recv) + client = None + try: + client = _start_client(tmp_path, server) + src = tmp_path / "payload.bin" + payload = os.urandom(64 * 1024) + src.write_bytes(payload) + fid = 77 + + server_sock = server.clients[client.client_socket.getsockname()]["socket"] + sender_id = "%s:%s" % client.client_socket.getsockname() + server.file_transfer_server_recv_server_start_thread( + sender_id, server_sock, f"/file {src} {fid}" + ) + assert _wait_port(client) is not None + + client.pause_trans(fid) # hold the leg before its first chunk + sender = threading.Thread( + target=client.file_transfer_mode, + args=(str(src), "127.0.0.1", _wait_port(client) or 0, 0), + kwargs={"fid": fid, "peer": (server.host, server.port)}, + daemon=True, + ) + sender.start() + assert wait_until(lambda: server.file_recv_progress.get(fid)), ( + "the receiver never registered the transfer" + ) + + # drop the control connection the way a network fault would; the + # receive loop persists the transfers that died with it + client.client_socket.shutdown(2) + assert wait_until( + lambda: os.path.exists(client.file_trans_progress_file), timeout=10 + ), "the client did not persist its interrupted transfers" + + with open(client.file_trans_progress_file, "r", encoding="utf-8") as f: + client_state = json.load(f) + assert client_state["upload"][str(fid)][3] == str(src) + assert client_state["upload"][str(fid)][4] == [server.host, server.port] + + assert wait_until( + lambda: os.path.exists(server.file_trans_progress_file), timeout=10 + ), "the server did not persist its interrupted transfers" + with open(server.file_trans_progress_file, "r", encoding="utf-8") as f: + server_state = json.load(f) + entry = server_state["download"][str(fid)] + assert entry[3] == str(server_recv / "payload.bin") + assert entry[4] == list(client.client_socket.getsockname()) + + client.start_trans(fid) # release the paused leg so the test can end + sender.join(timeout=10) + finally: + if client is not None: + client.close() + server.stop() + + +def test_upload_resumes_after_a_reconnect(tmp_path): + """A client upload interrupted by a disconnect finishes after reconnecting. + + The client reconnects automatically (``is_auto_reconnect``); the server + reads the persisted state when it comes back and asks it to continue the + file from the bytes already on disk — the partially transferred file + completes without any byte being sent twice. + """ + server = _start_server(tmp_path) + server_recv = tmp_path / "server_recv" + server_recv.mkdir() + server.file_transfer_dir = str(server_recv) + client = None + try: + src = tmp_path / "payload.bin" + payload = os.urandom(256 * 1024) + src.write_bytes(payload) + fid = 101 + + # a fixed client port keeps the client's address stable across the + # reconnect, so the server can match the interrupted transfer to it + client = TCP_Client_Base( + host="127.0.0.1", + port=server.port, + client_host="127.0.0.1", + client_port=free_port(), + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=False, + is_auto_reconnect=True, + ) + _isolate(client, tmp_path, "client") + threading.Thread(target=client.start_TCP_client, daemon=True).start() + assert wait_until(lambda: client.running and client.client_socket is not None) + client_addr = client.client_socket.getsockname() + + server_sock = server.clients[client_addr]["socket"] + client_id = "%s:%s" % client_addr + server.file_transfer_server_recv_server_start_thread( + client_id, server_sock, f"/file {shlex.quote(str(src))} {fid}" + ) + assert _wait_port(client) is not None + + client.pause_trans(fid) # freeze the leg, then give it a partial file + sender = threading.Thread( + target=client.file_transfer_mode, + args=(str(src), "127.0.0.1", _wait_port(client) or 0, 0), + kwargs={"fid": fid, "peer": (server.host, server.port)}, + daemon=True, + ) + sender.start() + assert wait_until(lambda: server.file_recv_progress.get(fid)), ( + "the receiver never registered the transfer" + ) + partial = server_recv / "payload.bin" + half = len(payload) // 2 + with open(partial, "wb") as f: # what an interrupted transfer leaves behind + f.write(payload[:half]) + + # a fault drops the control connection; the client reconnects on its + # own and the server drives the resume from the bytes on disk + client.client_socket.shutdown(2) + assert wait_until(lambda: server.clients.get(client_addr) is not None, timeout=20), ( + "the client did not come back" + ) + + def got(): + return partial.exists() and partial.stat().st_size == len(payload) + + assert wait_until(got, timeout=30), "the resumed upload did not finish" + assert partial.read_bytes() == payload + assert wait_until(lambda: fid not in server.file_recv_progress, timeout=10) + assert wait_until(lambda: fid not in client.file_upload_progress, timeout=10) + client.start_trans(fid) + sender.join(timeout=10) + finally: + if client is not None: + client.close() + server.stop() + + +def test_download_resumes_from_the_partial_file(tmp_path): + """The receiver drives a resume of a file the server was sending. + + The interrupted state is exactly what a disconnect leaves: the partial + file on disk plus the persisted entry naming the server as the peer. The + receiver asks the sender to continue from the partial file's length. + """ + server = _start_server(tmp_path) + client = None + try: + recv_dir = tmp_path / "client_recv" + recv_dir.mkdir() + client = _start_client(tmp_path, server, recv_dir=recv_dir) + src = tmp_path / "download.bin" + payload = os.urandom(128 * 1024) + src.write_bytes(payload) + fid = 202 + + partial = recv_dir / "download.bin" + with open(partial, "wb") as f: + f.write(payload[:4096]) + client.file_recv_progress[fid] = [ + len(payload[:4096]), + len(payload), + None, + str(partial), + (server.host, server.port), + ] + server.file_upload_progress[fid] = [ + 0, + len(payload), + None, + str(src), + client.client_socket.getsockname(), + ] + + assert client.resume_transfers(peer=(server.host, server.port)) == 1 + + def got(): + return partial.stat().st_size == len(payload) + + assert wait_until(got, timeout=20), "the resumed download did not finish" + assert partial.read_bytes() == payload + assert wait_until(lambda: fid not in client.file_recv_progress, timeout=10) + assert wait_until(lambda: fid not in server.file_upload_progress, timeout=10) + finally: + if client is not None: + client.close() + server.stop() + + +def test_forwarded_file_resumes_through_the_server(tmp_path): + """A target that lost a forwarded file gets the remainder re-sent. + + The target asks the server to continue the transfer; the server routes + the request to the originator (its relay record names it) and the + originator re-forwards only what the target is missing. Both the target's + download entry and the originator's upload entry name the original peer, + never the relay. + """ + server = _start_server(tmp_path) + recv_dir = tmp_path / "target_recv" + recv_dir.mkdir() + target = None + forwarder = None + try: + target = _start_client(tmp_path, server, name="target", recv_dir=recv_dir) + forwarder = _start_client(tmp_path, server, name="forwarder") + src = tmp_path / "payload.bin" + payload = os.urandom(96 * 1024) + src.write_bytes(payload) + fid = 303 # the forwarder's transfer id + tfid = 304 # the target's transfer id + target_addr = target.client_socket.getsockname() + forwarder_addr = forwarder.client_socket.getsockname() + + # the state a disconnect leaves behind: the target's partial file and + # both sides' persisted entries, plus the relay record the server + # keeps for the dead relay + partial = recv_dir / "payload.bin" + with open(partial, "wb") as f: + f.write(payload[:2048]) + target.file_recv_progress[tfid] = [ + 2048, + len(payload), + None, + str(partial), + forwarder_addr, + ] + forwarder.file_upload_progress[fid] = [0, len(payload), None, str(src), target_addr] + forwarder._forward_resume_records[fid] = { + "fid": fid, + "kind": "file", + "rel_dir": "", + "fname": "payload.bin", + "path": str(src), + "destination": None, + "targets": [list(target_addr)], + } + server._forward_resume_records[tfid] = { + "fid": fid, + "originator": list(forwarder_addr), + "targets": [list(target_addr)], + "tfids": [tfid], + "kind": "file", + "rel_dir": "", + "fname": "payload.bin", + "destination": None, + } + + assert target._request_forward_resume( + tfid, target.file_recv_progress[tfid], forwarder_addr + ) + + def got(): + return partial.stat().st_size == len(payload) + + assert wait_until(got, timeout=20), "the forwarded resume did not finish" + assert partial.read_bytes() == payload + assert wait_until(lambda: tfid not in target.file_recv_progress, timeout=10) + assert wait_until(lambda: fid not in forwarder.file_upload_progress, timeout=10) + finally: + if forwarder is not None: + forwarder.close() + if target is not None: + target.close() + server.stop() + + +def test_pause_and_start_trans_control_a_plain_transfer(tmp_path): + """``pause_trans``/``start_trans`` hold and release any outbound leg. + + The receiver stops reading until the sender is released, so the pause + works on a plain (non-forwarded) transfer: nothing arrives while the leg + is held, and the file completes after ``start_trans``. + """ + server = _start_server(tmp_path) + server_recv = tmp_path / "server_recv" + server_recv.mkdir() + server.file_transfer_dir = str(server_recv) + client = None + try: + client = _start_client(tmp_path, server) + src = tmp_path / "payload.bin" + payload = os.urandom(256 * 1024) + src.write_bytes(payload) + fid = 404 + + server_sock = server.clients[client.client_socket.getsockname()]["socket"] + server.file_transfer_server_recv_server_start_thread( + "cid", server_sock, f"/file {src} {fid}" + ) + assert _wait_port(client) is not None + + assert client.pause_trans(fid) is False # armed before the leg starts + sender = threading.Thread( + target=client.file_transfer_mode, + args=(str(src), "127.0.0.1", _wait_port(client) or 0, 0), + kwargs={"fid": fid, "peer": (server.host, server.port)}, + daemon=True, + ) + sender.start() + assert wait_until(lambda: client.file_upload_progress.get(fid)), ( + "the uploader never registered the transfer" + ) + time.sleep(0.5) + output = server_recv / "payload.bin" + assert not output.exists() or output.stat().st_size == 0, "the paused leg sent data" + + assert client.start_trans(fid) is True # a live leg is released + assert wait_until( + lambda: output.exists() and output.stat().st_size == len(payload), timeout=20 + ), "the released transfer did not finish" + assert output.read_bytes() == payload + sender.join(timeout=10) + finally: + if client is not None: + client.close() + server.stop() + + +def test_download_resumes_over_the_encrypted_channel(tmp_path): + """The resume exchange travels on the framed channel like any transfer line. + + With encryption enabled the resume drive waits for the handshake to finish + before it writes ``/resume_trans``, so the request and the resumed leg + both speak frames. + """ + ssh_dir = tmp_path / "ssh" + ssh_dir.mkdir() + port = free_port() + server = TCP_Server_Base( + host="127.0.0.1", + port=port, + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=True, + ) + _isolate(server, tmp_path, "server") + _redirect_crypto(server.crypto, tmp_path, ssh_dir, "pub_key") + threading.Thread(target=server.start_TCP_Server, daemon=True).start() + assert server_ready(server), "server did not start" + client = None + try: + recv_dir = tmp_path / "client_recv" + recv_dir.mkdir() + client = TCP_Client_Base( + host="127.0.0.1", + port=port, + client_host="127.0.0.1", + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=True, + ) + _isolate(client, tmp_path, "client") + _redirect_crypto(client.crypto, tmp_path, ssh_dir, "pub_key_client") + client.file_transfer_dir = str(recv_dir) + assert client.connect() + assert wait_until(lambda: client.client_socket in client._encrypted_sockets, timeout=15), ( + "the channel never flipped to frames" + ) + + src = tmp_path / "download.bin" + payload = os.urandom(64 * 1024) + src.write_bytes(payload) + fid = 909 + partial = recv_dir / "download.bin" + with open(partial, "wb") as f: + f.write(payload[:1024]) + client.file_recv_progress[fid] = [ + 1024, + len(payload), + None, + str(partial), + (server.host, server.port), + ] + server.file_upload_progress[fid] = [ + 0, + len(payload), + None, + str(src), + client.client_socket.getsockname(), + ] + + assert client.resume_transfers(peer=(server.host, server.port)) == 1 + assert wait_until(lambda: partial.stat().st_size == len(payload), timeout=20), ( + "the encrypted resume did not finish" + ) + assert partial.read_bytes() == payload + assert wait_until(lambda: fid not in client.file_recv_progress, timeout=10) + assert wait_until(lambda: fid not in server.file_upload_progress, timeout=10) + finally: + if client is not None: + client.close() + server.stop() \ No newline at end of file From 94460cfac93497b1e16e1a80e592ba8459f6c449 Mon Sep 17 00:00:00 2001 From: F18-Ray Date: Mon, 19 Oct 2026 08:49:28 +0800 Subject: [PATCH 2/5] core-code: fix the test errors of rebinding the ports which already be used in the same threads --- PyFlow/network_api/connect_tcp.py | 27 +++++++++++++++++++ .../network_api/test_tcp_transfer_resume.py | 11 ++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/PyFlow/network_api/connect_tcp.py b/PyFlow/network_api/connect_tcp.py index 4745cdb..6794f7c 100644 --- a/PyFlow/network_api/connect_tcp.py +++ b/PyFlow/network_api/connect_tcp.py @@ -9334,6 +9334,28 @@ def close(self): # close connection self.client_socket.close() self._log("connection closed") + def _release_client_socket(self): + """Close the socket a finished session left behind. + + An auto-reconnect binds the configured ``client_port`` again, and a + socket that was only shut down still holds it: Windows refuses the + second bind with ``WSAEADDRINUSE`` until the old socket is closed. + """ + sock = self.client_socket + if sock is None: + return + try: + sock.shutdown(socket.SHUT_RDWR) + except OSError: + pass # peer already gone + try: + sock.close() + except OSError: + pass + with self._crypto_lock: + self._channels.pop(sock, None) + self._encrypted_sockets.discard(sock) + def start_TCP_client(self): # start client """Connect to the server and start the client loop. @@ -9355,6 +9377,10 @@ def start_TCP_client(self): # start client return # close() won the race with the connection attempt if not self.is_auto_reconnect: sys.exit(1) + # a dead socket still holds the configured client port: the + # next attempt must be able to bind it again (Windows refuses + # the second bind otherwise) + self._release_client_socket() self._log("reconnect in 1 second...") time.sleep(1) continue @@ -9370,5 +9396,6 @@ def start_TCP_client(self): # start client if self._stopped or not self.is_auto_reconnect: self.close() return + self._release_client_socket() self._log("connection lost, reconnecting in 1 second...") time.sleep(1) diff --git a/test/integration/network_api/test_tcp_transfer_resume.py b/test/integration/network_api/test_tcp_transfer_resume.py index ee7e275..ac76c5b 100644 --- a/test/integration/network_api/test_tcp_transfer_resume.py +++ b/test/integration/network_api/test_tcp_transfer_resume.py @@ -255,8 +255,15 @@ def test_upload_resumes_after_a_reconnect(tmp_path): f.write(payload[:half]) # a fault drops the control connection; the client reconnects on its - # own and the server drives the resume from the bytes on disk - client.client_socket.shutdown(2) + # own and the server drives the resume from the bytes on disk. The + # dead session's socket is closed by the reconnect (a socket that is + # merely shut down keeps the configured client port, which the second + # bind cannot take on Windows). + dead_socket = client.client_socket + dead_socket.shutdown(2) + assert wait_until(lambda: dead_socket.fileno() == -1, timeout=20), ( + "the reconnect did not release the dead session's socket" + ) assert wait_until(lambda: server.clients.get(client_addr) is not None, timeout=20), ( "the client did not come back" ) From 0df534290ac50ddfa3f2c7e41b3668d32f1a3af2 Mon Sep 17 00:00:00 2001 From: F18-Ray Date: Tue, 20 Oct 2026 09:17:23 +0800 Subject: [PATCH 3/5] test: fix the socket never close and the TIME_WAIT on windows when the socket close cause the reconnected loop never success errors --- PyFlow/network_api/connect_tcp.py | 49 +++++++++++----- docs/source/Network_APIs/TCP_Client_APIs.rst | 9 ++- .../network_api/test_tcp_transfer_resume.py | 56 +++++++++++++++++-- 3 files changed, 92 insertions(+), 22 deletions(-) diff --git a/PyFlow/network_api/connect_tcp.py b/PyFlow/network_api/connect_tcp.py index 6794f7c..cc2f171 100644 --- a/PyFlow/network_api/connect_tcp.py +++ b/PyFlow/network_api/connect_tcp.py @@ -41,6 +41,7 @@ import copy import shlex import socket +import struct # SO_LINGER's (l_onoff, l_linger) pair, for abortive closes import selectors import secrets import traceback @@ -1990,7 +1991,7 @@ def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): if channel is not None and channel.secure: return True time.sleep(0.05) - self._log("resume: control channel is not framed yet, transfers kept for the next reconnect") + self._log("resume: control channel not framed yet, transfers kept for the next reconnect") return False def alloc_port(self, port_add_step, port_range_num): @@ -4114,7 +4115,7 @@ def file_transfer_client_recv(client_id): # bytes that are already on disk and the sender continues full_path = resume_entry[3] final_filename = os.path.basename(full_path) - resume_from = resume_entry[0] # the offset the sender was asked to continue from + resume_from = resume_entry[0] # the offset the sender was asked for if resume_from <= 0 or resume_from > file_size: resume_from = 0 # not this file's offset: start it over else: @@ -4210,7 +4211,7 @@ def file_transfer_client_recv(client_id): keep=( not finished_ok and progress is not None - and progress[4] is not None # an interrupted transfer with a peer can be resumed + and progress[4] is not None # resumable: it has a peer ), ) self._release_transfer_socket(progress_fid, client_file_socket) @@ -4794,7 +4795,7 @@ def receive_file_transfer_messages(): not file_sent and not source_missing and progress is not None - and progress[4] is not None # an interrupted transfer with a peer can be resumed + and progress[4] is not None # resumable: it has a peer ), ) self._release_transfer_socket(fid, client_file_socket) @@ -6757,7 +6758,7 @@ def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): if channel is not None and channel.secure: return True time.sleep(0.05) - self._log("resume: control channel is not framed yet, transfers kept for the next reconnect") + self._log("resume: control channel not framed yet, transfers kept for the next reconnect") return False def alloc_port(self, port_add_step, port_range_num): @@ -7156,7 +7157,20 @@ def connect(self): # connect to server pass else: self.local_address = (self.client_host, self.client_port) - self.client_socket.bind(self.local_address) + try: + self.client_socket.bind(self.local_address) + except OSError as e: + # the configured port is not ours to take right now (a + # session that just ended can keep it, in TIME_WAIT on + # Windows): connect anyway, from an OS-assigned port. + # The interrupted transfers of the previous session + # are matched by address, so they stay stored until a + # reconnect that can use the configured port again. + self._log( + f"client port {self.client_port} is not available ({e}); " + f"connecting from an OS-assigned port instead" + ) + self.local_address = None self.client_socket.connect((self.host, self.port)) if self._stopped: # close() arrived while the socket was connecting: stay @@ -8522,7 +8536,7 @@ def receive_file_transfer_messages(): not file_sent and not source_missing and progress is not None - and progress[4] is not None # an interrupted transfer with a peer can be resumed + and progress[4] is not None # resumable: it has a peer ), ) self._release_transfer_socket(fid, client_file_socket) @@ -9149,7 +9163,7 @@ def file_transfer_client_recv(client_id): # bytes that are already on disk and the sender continues full_path = resume_entry[3] final_filename = os.path.basename(full_path) - resume_from = resume_entry[0] # the offset the sender was asked to continue from + resume_from = resume_entry[0] # the offset the sender was asked for else: if file_name: final_filename = file_name.strip() @@ -9237,7 +9251,7 @@ def file_transfer_client_recv(client_id): keep=( not finished_ok and progress is not None - and progress[4] is not None # an interrupted transfer with a peer can be resumed + and progress[4] is not None # resumable: it has a peer ), ) self._release_transfer_socket(progress_fid, client_file_socket) @@ -9337,17 +9351,24 @@ def close(self): # close connection def _release_client_socket(self): """Close the socket a finished session left behind. - An auto-reconnect binds the configured ``client_port`` again, and a - socket that was only shut down still holds it: Windows refuses the - second bind with ``WSAEADDRINUSE`` until the old socket is closed. + An auto-reconnect binds the configured ``client_port`` again, so the + dead session's socket must go away completely: it is closed abortively + (``SO_LINGER`` on with a zero timeout, which the TCP stack turns into a + RST and which skips ``TIME_WAIT`` entirely). A socket that only gets + shut down keeps the port, and an ordinary close leaves the local port + in ``TIME_WAIT`` — Windows then refuses to bind or connect from it + again (``WSAEADDRINUSE``) for the whole two-minute delay. + + The receive thread of that session has already ended when this runs, so + nothing needs the shutdown a graceful close would perform. """ sock = self.client_socket if sock is None: return try: - sock.shutdown(socket.SHUT_RDWR) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", 1, 0)) except OSError: - pass # peer already gone + pass # not a real socket any more try: sock.close() except OSError: diff --git a/docs/source/Network_APIs/TCP_Client_APIs.rst b/docs/source/Network_APIs/TCP_Client_APIs.rst index cf7bb4b..1fffa7e 100644 --- a/docs/source/Network_APIs/TCP_Client_APIs.rst +++ b/docs/source/Network_APIs/TCP_Client_APIs.rst @@ -95,7 +95,10 @@ Every parameter has default values: - ``host``: Default is ``None`` (must be provided before connecting) - ``client_host``: Default is ``'127.0.0.1'`` - ``port``: Default is ``65432`` -- ``client_port``: Default is ``None`` (OS assigns ephemeral port) +- ``client_port``: Default is ``None`` (OS assigns ephemeral port). A + configured port that cannot be bound — a session that just ended can hold + it in the operating system's ``TIME_WAIT`` — is reported and the connection + is made from an OS-assigned port instead. - ``timeout``: Default is ``None`` - ``port_add_step``: Default is ``1`` - ``max_thread_num``: Default is ``10`` @@ -125,7 +128,9 @@ Every parameter has default values: (``False`` measures no speed; every speed value is ``None``) - ``is_auto_reconnect``: Default is ``False`` (``True`` makes `start_TCP_client` reconnect after the connection drops and - resume the interrupted transfers, see :ref:`transfer-pause-and-reconnect`) + resume the interrupted transfers, see :ref:`transfer-pause-and-reconnect`. + The dead session's socket is closed abortively first, so a configured + ``client_port`` can be bound again — Windows refuses it otherwise) The TCP Client Setup API will initialize all the necessary parameters and resources for the TCP client. diff --git a/test/integration/network_api/test_tcp_transfer_resume.py b/test/integration/network_api/test_tcp_transfer_resume.py index ac76c5b..3070a65 100644 --- a/test/integration/network_api/test_tcp_transfer_resume.py +++ b/test/integration/network_api/test_tcp_transfer_resume.py @@ -11,6 +11,7 @@ import json import os import shlex +import socket import threading import time @@ -254,19 +255,25 @@ def test_upload_resumes_after_a_reconnect(tmp_path): with open(partial, "wb") as f: # what an interrupted transfer leaves behind f.write(payload[:half]) - # a fault drops the control connection; the client reconnects on its - # own and the server drives the resume from the bytes on disk. The - # dead session's socket is closed by the reconnect (a socket that is - # merely shut down keeps the configured client port, which the second - # bind cannot take on Windows). + # a fault drops the control connection: the server's side goes away, + # the way a crash looks to the client. The client's own release then + # aborts the dead session (shutdown + linger-0 close), which keeps its + # configured port out of TIME_WAIT: the reconnect must be able to take + # the same port back (Windows refuses it otherwise) and the server must + # match the stored transfer to the same peer address. dead_socket = client.client_socket - dead_socket.shutdown(2) + server_side = server.clients[client_addr]["socket"] + server_side.shutdown(2) # a read blocked in the server only wakes on a shutdown + server_side.close() assert wait_until(lambda: dead_socket.fileno() == -1, timeout=20), ( "the reconnect did not release the dead session's socket" ) assert wait_until(lambda: server.clients.get(client_addr) is not None, timeout=20), ( "the client did not come back" ) + assert client.client_socket.getsockname() == client_addr, ( + "the client came back from a different port" + ) def got(): return partial.exists() and partial.stat().st_size == len(payload) @@ -535,6 +542,43 @@ def test_download_resumes_over_the_encrypted_channel(tmp_path): assert wait_until(lambda: fid not in client.file_recv_progress, timeout=10) assert wait_until(lambda: fid not in server.file_upload_progress, timeout=10) finally: + if client is not None: + client.close() + server.stop() + + +def test_client_connects_when_its_configured_port_is_taken(tmp_path): + """A configured client port that is held elsewhere does not stop the client. + + The port can be stuck after a session ends (TIME_WAIT on Windows), so the + client must still connect — from an OS-assigned port — instead of never + coming back. + """ + server = _start_server(tmp_path) + holder = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + taken = free_port() + holder.bind(("127.0.0.1", taken)) # no SO_REUSEADDR: the bind must fail + client = None + try: + client = TCP_Client_Base( + host="127.0.0.1", + port=server.port, + client_host="127.0.0.1", + client_port=taken, + is_extend_command=True, + is_input_command_in_console=False, + is_enable_encrypto=False, + ) + _isolate(client, tmp_path, "client") + assert client.connect(), "the client did not connect around the taken port" + assert client.client_socket.getsockname()[1] != taken, ( + "the client reported the port it could not bind" + ) + assert wait_until( + lambda: server.clients.get(client.client_socket.getsockname()) is not None + ), "the server never saw the client" + finally: + holder.close() if client is not None: client.close() server.stop() \ No newline at end of file From e5747914fcd26c9a7735985e01c5cb0174a3337b Mon Sep 17 00:00:00 2001 From: F18-Ray Date: Thu, 22 Oct 2026 00:56:12 +0800 Subject: [PATCH 4/5] Docs: updating docs --- docs/readme_translations/README.ja.md | 28 +- docs/readme_translations/readme_cache.json | 17 +- .../locale/ja/LC_MESSAGES/Crypto/Crypto.po | 389 ++-- .../File_Transfer/File_Transfer.po | 1530 +++++++------ .../Instance_Setup/Instance_Setup.po | 588 ++--- .../Network_APIs/TCP_Client_APIs.po | 2010 +++++++++-------- .../Network_APIs/TCP_Server_APIs.po | 1255 +++++----- .../PyFlow.command_control_extension_tcp.po | 72 +- .../api/PyFlow.network_api.connect_tcp.po | 1731 +++++++++----- .../api/PyFlow.network_api.rsa_crypto.po | 182 +- .../api/PyFlow.transfer_web.setup_client.po | 53 +- .../api/PyFlow.transfer_web.setup_server.po | 61 +- ...w.transfer_web.web_backend.mail_service.po | 164 +- ...transfer_web.web_backend.server_backend.po | 190 +- ...w.transfer_web.web_front.client_backend.po | 126 +- .../locale/ko/LC_MESSAGES/Crypto/Crypto.po | 148 +- .../File_Transfer/File_Transfer.po | 917 +++++--- .../Instance_Setup/Instance_Setup.po | 267 ++- .../Network_APIs/TCP_Client_APIs.po | 1178 ++++++---- .../Network_APIs/TCP_Server_APIs.po | 1257 ++++++----- .../PyFlow.command_control_extension_tcp.po | 64 +- .../api/PyFlow.network_api.connect_tcp.po | 1792 ++++++++++----- .../api/PyFlow.network_api.rsa_crypto.po | 180 +- .../api/PyFlow.transfer_web.setup_client.po | 40 +- .../api/PyFlow.transfer_web.setup_server.po | 42 +- ...w.transfer_web.web_backend.mail_service.po | 143 +- ...transfer_web.web_backend.server_backend.po | 149 +- ...w.transfer_web.web_front.client_backend.po | 105 +- .../locale/ru/LC_MESSAGES/Crypto/Crypto.po | 148 +- .../File_Transfer/File_Transfer.po | 920 +++++--- .../Instance_Setup/Instance_Setup.po | 267 ++- .../Network_APIs/TCP_Client_APIs.po | 1195 ++++++---- .../Network_APIs/TCP_Server_APIs.po | 1268 ++++++----- .../PyFlow.command_control_extension_tcp.po | 64 +- .../api/PyFlow.network_api.connect_tcp.po | 1792 ++++++++++----- .../api/PyFlow.network_api.rsa_crypto.po | 180 +- .../api/PyFlow.transfer_web.setup_client.po | 40 +- .../api/PyFlow.transfer_web.setup_server.po | 42 +- ...w.transfer_web.web_backend.mail_service.po | 143 +- ...transfer_web.web_backend.server_backend.po | 149 +- ...w.transfer_web.web_front.client_backend.po | 105 +- .../locale/zh_CN/LC_MESSAGES/Crypto/Crypto.po | 148 +- .../File_Transfer/File_Transfer.po | 917 +++++--- .../Instance_Setup/Instance_Setup.po | 267 ++- .../Network_APIs/TCP_Client_APIs.po | 1168 ++++++---- .../Network_APIs/TCP_Server_APIs.po | 1241 +++++----- .../PyFlow.command_control_extension_tcp.po | 72 +- .../api/PyFlow.network_api.connect_tcp.po | 1790 ++++++++++----- .../api/PyFlow.network_api.rsa_crypto.po | 180 +- .../api/PyFlow.transfer_web.setup_client.po | 40 +- .../api/PyFlow.transfer_web.setup_server.po | 42 +- ...w.transfer_web.web_backend.mail_service.po | 143 +- ...transfer_web.web_backend.server_backend.po | 149 +- ...w.transfer_web.web_front.client_backend.po | 105 +- .../locale/zh_TW/LC_MESSAGES/Crypto/Crypto.po | 148 +- .../File_Transfer/File_Transfer.po | 917 +++++--- .../Instance_Setup/Instance_Setup.po | 267 ++- .../Network_APIs/TCP_Client_APIs.po | 1170 ++++++---- .../Network_APIs/TCP_Server_APIs.po | 1249 +++++----- .../PyFlow.command_control_extension_tcp.po | 64 +- .../api/PyFlow.network_api.connect_tcp.po | 1792 ++++++++++----- .../api/PyFlow.network_api.rsa_crypto.po | 180 +- .../api/PyFlow.transfer_web.setup_client.po | 40 +- .../api/PyFlow.transfer_web.setup_server.po | 42 +- ...w.transfer_web.web_backend.mail_service.po | 143 +- ...transfer_web.web_backend.server_backend.po | 149 +- ...w.transfer_web.web_front.client_backend.po | 105 +- 67 files changed, 20837 insertions(+), 12682 deletions(-) diff --git a/docs/readme_translations/README.ja.md b/docs/readme_translations/README.ja.md index 40355b2..e3cb193 100644 --- a/docs/readme_translations/README.ja.md +++ b/docs/readme_translations/README.ja.md @@ -12,7 +12,7 @@ PyFlowは、拡張可能なインターフェースやその他の機能とと - **TCPサーバー/クライアント** —単一の制御チャネル(`PyFlow/network_api/connect_tcp.py`)を介したメッセージ交換、カスタムコマンド、ファイル転送、コマンド拡張API、およびポート割り当て。 - **UDP通信** —コネクションレスメッセージング(`PyFlow/network_api/connect_udp.py`)。 -- **暗号化されたTCPチャネル** — TOFU ( trust - on - first - use )ピアキーレジストリ、セッションナンス、リプレイに対するシーケンス番号、再交換ストームに対するサーキットブレーカーを使用したRSA - OAEPメッセージ暗号化。[docs/Crypto](docs/source/Crypto/Crypto.rst)およびTCP APIドキュメントの暗号化されたチャネルセクションを参照してください。 +- **Encrypted TCP channel** — after a plaintext key handshake every message and every file/folder/forward transfer connection is framed and encrypted (RSA-OAEP for small text payloads, ECDH-keyed AES-256-GCM for everything else, file data included), with a TOFU (trust-on-first-use) peer-key registry, session nonces and sequence numbers against replay, and a circuit breaker against re-exchange storms. See [docs/Crypto](docs/source/Crypto/Crypto.rst) and the encrypted-channel sections of the TCP API docs. - **C/OpenSSL暗号ライブラリ** — `libcrypto_api`は、RSA - OAEP、ECDH ( P -256/384/521 )、HKDF - SHA 256、およびAES -256 - GCMに、C、CMake、またはpkg - configから使用できる安定したC API (`pf_*`プレフィックス)を提供します。 - **マルチインスタンスランチャー** — `python -m PyFlow`(`PyFlow/flow_setup.py`がサポートするパッケージエントリポイント)は、CLI、インタラクティブプロンプト、または`setup.json`構成ファイルから1つ以上のサーバー/クライアントインスタンスを開始します。 - **Extension protocols** — `command_control_extension_tcp.py` (remote command execution with log collection) and `forward_extension_tcp.py` (upload-then-push forwarding of files/folders to multiple destinations; plain-message forwarding `forward_send_msg` is native to the TCP layer, not part of this extension) plug into any instance via `setup_*_commands()`; `flow_setup.py` loads them automatically for every instance whose `setup.json` config sets `is_extend_command=True`, and starts instances in a background thread when `is_input_command_in_console=False`. Extension files can also be registered persistently with `flow_setup.py --add` / `--delete` (kept in `PyFlow/added_extensions.json` and loaded on every launch by `add_extension.py`). @@ -153,17 +153,17 @@ uv run python PyFlow/transfer_web/setup_server.py uv run python PyFlow/transfer_web/setup_client.py ``` -サーバーのWebアドレスの訪問者は、**ログイン**、**登録**および**パスワード変更**ボタンを使用して、白いランディングページ(クライアントが接続するアドレス)を取得します。スタートアップコンフィギュレーションページ、ステータスページ、およびその背後にあるWeb APIにはセッションが必要です。アカウントはSQLiteデータベース`PyFlow/transfer_web/.Flow_Web/flow_web.db`に存在します:ユーザー名、メールアドレス、PBKDF 2 - SHA 256パスワードレコード、および他のユーザーが検索する一意の8文字のユーザーID。最初の実行は、 administrator `admin`/`admin`(レガシー`users.json`は一度インポートされ、名前が変更されます)。その正確なペアがまだ使用されている間、ログインすると、サーバーがパブリックネットワークに公開される前に、**ユーザー名とパスワードを変更するための目立つ警告がポップアップ表示されます**、またはそれに到達できる誰でも管理できます。管理者は、ユーザー(`Users`サイドバーにあり、ユーザーIDが一覧表示されます)を管理し、スタートアップ構成を変更したり、ロード/拡張したりできるのは管理者のみです。 拡張プロトコル。通常のユーザーは、メッセージ/ファイル/フォルダを送信するステータスページを取得します。`/api/server_info`は、Webクライアントが接続する前にクエリを実行するため、公開されたままになります。 +Visitors of the server's web address get a white landing page (the addresses clients should connect to) with a **Login** button, plus **Register** and **Change password** while a verification mailbox is configured; the startup-configuration page, the status page and the web APIs behind them need a session. Accounts live in the SQLite database `PyFlow/transfer_web/.Flow_Web/flow_web.db`: username, email, a PBKDF2-SHA256 password record and a unique 8-character user ID that other users search by. The first run seeds the administrator `admin` / `admin` (a legacy `users.json` is imported once and renamed); while that exact pair is still in use, a login pops up a prominent warning to change the username and password **before** the server is exposed to a public network, or anyone who can reach it can administer it. Administrators manage users (`Users` in the sidebar, which lists the user IDs) and are the only ones who can change the startup configuration or load/extend extension protocols; regular users get the status page with message/file/folder sending. `/api/server_info` stays public, as web clients query it before they connect. -登録、パスワード変更、コードベースのクライアントログインは電子メールで検証されます。管理者はスタートアップ構成ページに送信メールボックス(ホスト、ポート、アカウント、認証コード、送信者、暗号化)を入力し、設定は`PyFlow/transfer_web/.Flow_Web/email_config.json`に保存される前に実際のSMTPサーバーと照合され、検証メールサービスが開始されます。コードは5分間有効です。1分に1つのコードがリクエストされる場合があります。 送信ボタンは分をカウントします。作業メールボックスがなければ、誰もパスワードを登録またはリセットすることはできません。シードされた管理者はログインしてパスワードを設定することができます。 +The verification mailbox decides how clients connect: with it the server is meant for public networks, without it the server serves an internal network. An administrator fills in the outgoing mailbox (host, port, account, authorization code, sender and encryption) in the startup-configuration page, the settings are checked against the real SMTP server before they are stored in `PyFlow/transfer_web/.Flow_Web/email_config.json`, and only then is the verification mail service started: registration, password reset and every client login are then verified by email. Codes are valid for 5 minutes, one code may be requested per minute, and the send button counts the minute down. The same card offers **Disable Mail Service**, which removes the stored mailbox and switches the server back to internal mode. While no mailbox is configured, no account is needed on the client side at all: no registration, no password reset, no client login — clients connect and use the tool directly, and only the console administrator logs in to administer the server. -最初に実行すると、サーバーランチャーは、デフォルトですべての`TCP_Server_Base`パラメーターを表示するスタートアップコンフィギュレーションページを開きます。保存された構成は`PyFlow/transfer_web/.Flow_Web/setup_server.json`(`setup.json`と同じ形状)にあります。TCPサーバーが起動すると、サーバーのWebバックエンドはステータスページを提供し、クライアント側のAPI (`/api/server_info`はTCPアドレス/ポートを返します)を提供します。クライアントランチャーは、サーバーアドレス(`http`/`https`ドメインまたはベアIP )を要求し、サーバーのWebバックエンドを介して接続します。次に、 アカウントにログインし(ユーザー名/メールアドレス、アカウントパスワード、およびアカウントアドレスに郵送された確認コード—両方の要素が必要です)、パスワードとセッショントークンを`PyFlow/transfer_web/.Flow_Web/client_login.json`に保存するため、**ログアウト**がそのファイルを削除するまで、すべてのリロードがクライアントを再度ログインさせます。両方のページには、接続されたインスタンスとメッセージ/ファイル/フォルダ送信のサイドバーが表示されます(クライアントからクライアントへの送信はサーバーを介して転送されます)。Webクライアントは、 取引先責任者であるアカウント。連絡先は、**連絡先**ボタン(ユーザーID、ユーザー名、またはメールアドレスで検索)で追加されます。相手側は、**リクエスト**リストでリクエストに応答し、両方のアカウントが互いに承認した後にのみ、連絡先がサイドバーに表示されます。拡張プロトコルは、クライアントページとサーバーページの管理者によって読み込まれます。ウェブツールは、残りの状態を同じ`.Flow_Web/`ディレクトリに保持します:`setup_client.json`(最後に クライアント起動構成)、`client_last_server.json`(接続ページによって提供される最後のサーバーアドレス)、`client_extensions_ui.json`/`server_extensions_ui.json`(拡張UI状態)、および`uploads/`ステージングディレクトリ。 +On first run the server launcher opens the startup-configuration page showing every `TCP_Server_Base` parameter with its default; the saved config lives in `PyFlow/transfer_web/.Flow_Web/setup_server.json` (same shape as `setup.json`). Once the TCP server is up, the server's web backend serves a status page and a client-facing API (`/api/server_info` returns the TCP address/port and whether clients have to log in). The client launcher asks for the server address (an `http`/`https` domain or a bare IP) and connects through the server's web backend. A server that asks for accounts makes the client log in (username/email, the account password and a verification code mailed to the account address — both factors are required) and stores the password and the session token in `PyFlow/transfer_web/.Flow_Web/client_login.json`, so every reload logs the client in again until **Log out** deletes that file; an internal server skips the login window and the client's account buttons (**Contacts**, **Requests**, **User info**, **Log out**) do not appear. Both pages show a sidebar of connected instances and message/file/folder sending (client-to-client sends are forwarded through the server); on a public server a web client sees only its contacts, while internal clients see every connected instance. Contacts are added with the **Contacts** button (search by user ID, username or email); the other side answers the request in its **Requests** list, and only after both accounts accepted each other does the contact appear in the sidebar. Every file or folder message links the transferred name: clicking it asks the backend that recorded the transfer to open that location in the file manager of its host — a received file is revealed inside its arrival folder, a sent one opens the staged copy in `uploads/`. The browser only ever carries the opaque token of the record, never a filesystem path. Extension protocols are loaded by the client page and by administrators on the server page. The web tool keeps its remaining state in the same `.Flow_Web/` directory: `setup_client.json` (last client startup configuration), `client_last_server.json` (last server address offered by the connect page), `client_extensions_ui.json` / `server_extensions_ui.json` (extension UI state) and an `uploads/` staging directory. -サーバーページには、`"ftp"`共有もあります(管理者のみ)。これはFTPプロトコルではありません。サーバーホストの1つのフォルダを参照し、プロトコル自身の`/file`および`/file_folder`転送を介して、チェックされたエントリをクライアントに渡します。共有フォルダーはスタートアップ構成(`web.ftp_root`/`setup_server.json`)に保持されているため、再起動すると引き続き提供されます。クライアントのブラウズダイアログには、オプションの**Download to**フォルダーがあります。エントリはクライアントホスト上にあり、 フィールドが空のままの場合、デフォルトの転送フォルダ(`PyFlow/network_api/received_files`)。 +The server page also offers a `"ftp"` share (administrator-only). It is not the FTP protocol: it browses one folder of the server host and hands the ticked entries to clients over the protocol's own `/file` and `/file_folder` transfers. The shared folder is kept in the startup configuration (`web.ftp_root` of `setup_server.json`), so a restart keeps serving it. The client's browse dialog takes an optional **Download to** folder: the entries land there on the client host, and in the default transfer folder (`PyFlow/network_api/received_files`) when the field is left empty. ### `setup.json` -事前に書かれた`setup.json`はランチャーによって表彰されます: +A pre-written `setup.json` is honoured by the launcher: ```json { @@ -175,7 +175,7 @@ uv run python PyFlow/transfer_web/setup_client.py } ``` -### プログラマティックな使用 +### Programmatic use ```python from PyFlow.network_api.connect_tcp import TCP_Server_Base, TCP_Client_Base @@ -184,29 +184,29 @@ server = TCP_Server_Base(host="127.0.0.1", port=12345, is_extend_command=True) client = TCP_Client_Base(host="127.0.0.1", port=12345, is_extend_command=True) ``` -デフォルトでは、両端は暗号化されたチャネル(`is_enable_encrypto=True`)を有効にします。キーは解析可能な場合は`~/.ssh/id_rsa`から来ます。そうでなければ、RSA -2048ペアが`PyFlow/network_api/.Flow/pvt_key/`に生成され、ピアキーが交換され、すべての接続でTOFUチェックされます(`PyFlow/network_api/.Flow/pub_key/pub_key.json`)。`is_custom_keys`と完全なハンドシェイクについては、TCP APIドキュメントを参照してください。 +By default both ends enable the encrypted channel (`is_enable_encrypto=True`): keys come from `~/.ssh/id_rsa` when parseable, otherwise an RSA-2048 pair is generated into `PyFlow/network_api/.Flow/pvt_key/`, and peer keys are exchanged and TOFU-checked on every connection (`PyFlow/network_api/.Flow/pub_key/pub_key.json`). See the TCP API docs for `is_custom_keys` and the full handshake. -## テスト +## Testing ```bash uv run pytest # full Python suite ctest --test-dir build # C library tests ``` -`libcrypto_api`が構築されていない場合、暗号化されたチャネルテスト(`test/unit/network_api/test_crypto_rsa.py`、`test/integration/network_api/test_crypto_tcp.py`)は自動的にスキップされます。他のすべては関係なく実行されます。CIは、UbuntuとWindowsの両方でPython 3.10-3.14でスイートを実行します。また、フリースレッド(非GIL ) 3.14ビルドも渡します。 +The encrypted-channel tests (`test/unit/network_api/test_crypto_rsa.py`, `test/integration/network_api/test_crypto_tcp.py`) are skipped automatically when `libcrypto_api` has not been built; everything else runs regardless. CI runs the suite on Python 3.10–3.14, on both Ubuntu and Windows; it also passes on the free-threaded (no-GIL) 3.14 build. -## ドキュメンテーション +## Documentation -スフィンクスのソースは`docs/source/`(`ja`/`ko`/`ru`/`zh_CN`/`zh_TW`カタログが`docs/source/locale/`の英語のソース)にあり、`docs/`はビルドラッパーを保持しています。次のものを使用してHTMLドキュメントを作成します。 +Sphinx sources live in `docs/source/` (English source with `ja`/`ko`/`ru`/`zh_CN`/`zh_TW` catalogues under `docs/source/locale/`); `docs/` holds the build wrappers. Build the HTML docs with: ```bash make -C docs html # docs/Makefile; docs/make.bat html does the same on Windows uv run python -m sphinx -b html docs/source build/sphinx_doc # equivalent, explicit paths ``` -`docs/reBuild.sh`で翻訳( gettextの抽出、新しい文字列の機械翻訳、`.mo`のコンパイル)を再構築します。スクリプトはそのインタプリタで`source/batch_translate_po.py`を呼び出すため、`pyproject.toml`(`sphinx`、`sphinx-intl`、`polib`、`deep-translator`)と`PATH`の`python3.14`実行可能ファイルからのドキュメント/翻訳依存関係が必要です。`docs/_build/html/`の下で言語ごとに1つのHTMLツリーを書き込みます。ドキュメントを読む`docs/readthedocs_build.sh`は、既存のカタログのみをコンパイルし、単一のHTMLツリーを構築するプレビルドステップとして実行されます rTD出力ディレクトリ。 +Rebuild the translations (extract gettext, machine-translate new strings, compile `.mo`) with `docs/reBuild.sh`; it needs the documentation/translation dependencies from `pyproject.toml` (`sphinx`, `sphinx-intl`, `polib`, `deep-translator`) and a `python3.14` executable on `PATH`, because the script calls `source/batch_translate_po.py` with that interpreter. It writes one HTML tree per language under `docs/_build/html/`. Read the Docs runs `docs/readthedocs_build.sh` as its pre-build step, which only compiles the existing catalogues and builds the single HTML tree for the RTD output directory. -## ライセンス +## License [GPL-3.0](LICENSE) diff --git a/docs/readme_translations/readme_cache.json b/docs/readme_translations/readme_cache.json index a85630c..2447315 100644 --- a/docs/readme_translations/readme_cache.json +++ b/docs/readme_translations/readme_cache.json @@ -1,13 +1,10 @@ { "ja": { "0eb95fb6244c03f1": "クイックスタート", - "116adade1d54e0ca": "登録、パスワード変更、コードベースのクライアントログインは電子メールで検証されます。管理者はスタートアップ構成ページに送信メールボックス(ホスト、ポート、アカウント、認証コード、送信者、暗号化)を入力し、設定は`PyFlow/transfer_web/.Flow_Web/email_config.json`に保存される前に実際のSMTPサーバーと照合され、検証メールサービスが開始されます。コードは5分間有効です。1分に1つのコードがリクエストされる場合があります。 送信ボタンは分をカウントします。作業メールボックスがなければ、誰もパスワードを登録またはリセットすることはできません。シードされた管理者はログインしてパスワードを設定することができます。", - "222aca9c2290d0f4": "`docs/reBuild.sh`で翻訳( gettextの抽出、新しい文字列の機械翻訳、`.mo`のコンパイル)を再構築します。スクリプトはそのインタプリタで`source/batch_translate_po.py`を呼び出すため、`pyproject.toml`(`sphinx`、`sphinx-intl`、`polib`、`deep-translator`)と`PATH`の`python3.14`実行可能ファイルからのドキュメント/翻訳依存関係が必要です。`docs/_build/html/`の下で言語ごとに1つのHTMLツリーを書き込みます。ドキュメントを読む`docs/readthedocs_build.sh`は、既存のカタログのみをコンパイルし、単一のHTMLツリーを構築するプレビルドステップとして実行されます rTD出力ディレクトリ。", "26be11fbb2a6b1cf": "1. Cライブラリをコンパイルする", "296e9947aeba6e74": "そのサーバーに接続するクライアントを起動します(および独自のローカルアドレス/ポートをバインドします)。", "2a3ac1c088714b60": "[uv](https://docs.astral.sh/uv/)の場合(プロジェクトは`pyproject.toml`+`uv.lock`を使用) :", "2cfbfcc1bdd1a9d8": "Webツールは、非ライブラリ使用のためにブラウザUIにTCPプロトコルをラップします(`uv sync`によってインストールされたFlaskが必要です)。パッケージランチャーから起動するか、次の手順に従います。", - "2ee60128eabd4038": "`libcrypto_api`が構築されていない場合、暗号化されたチャネルテスト(`test/unit/network_api/test_crypto_rsa.py`、`test/integration/network_api/test_crypto_tcp.py`)は自動的にスキップされます。他のすべては関係なく実行されます。CIは、UbuntuとWindowsの両方でPython 3.10-3.14でスイートを実行します。また、フリースレッド(非GIL ) 3.14ビルドも渡します。", "380da53a148feb9a": "またはpipを使用する場合:", "4bb8b69b871e43da": "PIP 25.1以降", "4dfe35e71d438989": "サーバー/クライアント設定のプロンプトを表示し、`setup.json`を書き込み、インスタンスを起動します。", @@ -17,19 +14,14 @@ "5dfdb914c67f3556": "ソース配布のみがPyPIに公開されるため、Cライブラリはパッケージをインストールするマシン上でコンパイルされます。Windowsでは、`pip install`の前にコンパイラとOpenSSL開発ファイルがあることを意味します。", "66f3c45a53db9029": "パッケージをインストールすると、次のようにパッケージがコンパイルされます。`setup.py` OpenSSLに対して`crypto_api` Cライブラリを構築し、`PyFlow/_crypto_api.*.so`( Windows上では`.pyd`)としてインストールします。これは、`rsa_crypto.py`が実行時にロードするものです。", "6957f86f4b40424f": "2. Python環境を設定する", - "6a063ec9b7d79401": "サーバーページには、`\"ftp\"`共有もあります(管理者のみ)。これはFTPプロトコルではありません。サーバーホストの1つのフォルダを参照し、プロトコル自身の`/file`および`/file_folder`転送を介して、チェックされたエントリをクライアントに渡します。共有フォルダーはスタートアップ構成(`web.ftp_root`/`setup_server.json`)に保持されているため、再起動すると引き続き提供されます。クライアントのブラウズダイアログには、オプションの**Download to**フォルダーがあります。エントリはクライアントホスト上にあり、 フィールドが空のままの場合、デフォルトの転送フォルダ(`PyFlow/network_api/received_files`)。", "6ab3bdd8c7c69a57": "インタラクティブランチャー", "6b407e2eca82d930": "**TCPサーバー/クライアント** —単一の制御チャネル(`PyFlow/network_api/connect_tcp.py`)を介したメッセージ交換、カスタムコマンド、ファイル転送、コマンド拡張API、およびポート割り当て。", "6ea74252cf2b653f": "`is_extend_command`に関係なく、後で起動するたびにロードされるように、拡張プロトコルファイルを登録(または登録解除)します。", "6f1f0154a2809ff0": " —デフォルト(非「Light」)インストーラーには開発ファイルが含まれていますが、「Light」には含まれていません。ビルドが探している`C:\\Program Files\\OpenSSL`に着陸します。他の場所にある場合、`OPENSSL_ROOT_DIR`は検索を上書きします。", - "77124d1b6f02f562": "サーバーのWebアドレスの訪問者は、**ログイン**、**登録**および**パスワード変更**ボタンを使用して、白いランディングページ(クライアントが接続するアドレス)を取得します。スタートアップコンフィギュレーションページ、ステータスページ、およびその背後にあるWeb APIにはセッションが必要です。アカウントはSQLiteデータベース`PyFlow/transfer_web/.Flow_Web/flow_web.db`に存在します:ユーザー名、メールアドレス、PBKDF 2 - SHA 256パスワードレコード、および他のユーザーが検索する一意の8文字のユーザーID。最初の実行は、 administrator `admin`/`admin`(レガシー`users.json`は一度インポートされ、名前が変更されます)。その正確なペアがまだ使用されている間、ログインすると、サーバーがパブリックネットワークに公開される前に、**ユーザー名とパスワードを変更するための目立つ警告がポップアップ表示されます**、またはそれに到達できる誰でも管理できます。管理者は、ユーザー(`Users`サイドバーにあり、ユーザーIDが一覧表示されます)を管理し、スタートアップ構成を変更したり、ロード/拡張したりできるのは管理者のみです。 拡張プロトコル。通常のユーザーは、メッセージ/ファイル/フォルダを送信するステータスページを取得します。`/api/server_info`は、Webクライアントが接続する前にクエリを実行するため、公開されたままになります。", "78f10a67b868ee69": "**マルチインスタンスランチャー** — `python -m PyFlow`(`PyFlow/flow_setup.py`がサポートするパッケージエントリポイント)は、CLI、インタラクティブプロンプト、または`setup.json`構成ファイルから1つ以上のサーバー/クライアントインスタンスを開始します。", - "7a1f95aab4eb9cbf": "事前に書かれた`setup.json`はランチャーによって表彰されます:", "7d9927114f94d93c": "PyFlowは、拡張可能なインターフェースやその他の機能とともに、メッセージ、ファイル、フォルダを転送するAPIとWebアプリを提供する、高度なネットワークプロトコルです。", - "86d07f053a0a41d2": "**暗号化されたTCPチャネル** — TOFU ( trust - on - first - use )ピアキーレジストリ、セッションナンス、リプレイに対するシーケンス番号、再交換ストームに対するサーキットブレーカーを使用したRSA - OAEPメッセージ暗号化。[docs/Crypto](docs/source/Crypto/Crypto.rst)およびTCP APIドキュメントの暗号化されたチャネルセクションを参照してください。", "903f313bdbcb8186": "Python 3.10以降", "9181fcfff28e4f52": "代わりにCMakeを使用してCライブラリを構築することは、CテストスイートとCコンシューマーにのみ必要です。`build/libcrypto_api.so`(または`.dylib`/`.dll`)を生成し、`rsa_crypto.py`も自動的に位置を特定します。", - "98ba72345416b0ee": "プログラマティックな使用", "9c4af945c3bfee1d": "**Webツール** — `PyFlow/transfer_web/`は、図書館以外で使用するためにブラウザUIでTCPプロトコルをラップします。`setup_server.py`スタートアップコンフィギュレーションページ(`.Flow_Web/setup_server.json`に保存され、`setup.json`と同じ形状)を開き、ステータスページとクライアント対応APIを提供します。`setup_client.py`アドレスでサーバーに接続し、両方のページで接続されたインスタンス、メッセージ/ファイル/フォルダ送信(他のクライアントへの転送付き)、および拡張機能の読み込みのサイドバーを提供します。Flaskに裏打ちされています。", "a0482cf5c31f1877": "チェックアウトから、同じビルドが`uv sync`/`pip install -e .`の一部として実行されます。", "b27fedac51ace626": "`127.0.0.1:12345`でサーバーのリッスンを開始します:", @@ -37,24 +29,17 @@ "b7e3c7f0ae358cc5": ".コンパイラは自動的に検索されます。それがなければ、Microsoft独自の「Microsoft Visual C ++ 14.0以降が必要です」というメッセージでpipが停止します。", "bdd254b65baac169": "構築", "bf815b2c3a78cd2a": "登録は`add_extension.py`までに`PyFlow/added_extensions.json`に保存され、起動ごとに再読み込みされます。", - "c011d6097bfbc8e9": "ライセンス", - "c205924de0fe636c": "ドキュメンテーション", "c54d35312880df3d": "CMake 3.16以降( CテストスイートとCコンシューマーのみ)", "cd74053c54816e47": "アーキテクチャー", - "d06073c8df04b9a9": "スフィンクスのソースは`docs/source/`(`ja`/`ko`/`ru`/`zh_CN`/`zh_TW`カタログが`docs/source/locale/`の英語のソース)にあり、`docs/`はビルドラッパーを保持しています。次のものを使用してHTMLドキュメントを作成します。", "d16d1eb3b458495f": "Cコンパイラ( Linux/macOSではgcc/clang、WindowsではMSVC )", "d6b8aa778277200d": "Pythonレイヤーは、標準ライブラリとFlask (`transfer_web` Webツールでのみ使用)で実行されます。Cライブラリは、`ctypes`を介して実行時にロードされます。", - "d6cc7771583e4255": "`setup.json`", "d83c5085aa03fdd8": "Win 64インストーラーからのOpenSSL", "d9a6d9fec370c44b": "または直接:", "e0cdd07f6a270b82": "要件", "e466cf2d8e1916e6": "コマンドラインランチャー", "e6ffa70bfd2677b1": "OpenSSL 1.1.1以降( Debian/Ubuntuの`libssl-dev`などの開発ヘッダー)", - "e806a291cfc3e61f": "テスト", "ea3562f6d72e0251": "以下の例では、UVユーザーに`uv run`を使用しています。代わりにpipを使用してインストールした場合は、`uv run`プレフィックスをドロップして`python -m`を直接使用します。", - "eff58621a9dcab0a": "Visual Studio **ビルドツール** (C ++ワークロード、\"MSVC v 143\"およびWindows SDK):", - "f2883f13ca34236f": "デフォルトでは、両端は暗号化されたチャネル(`is_enable_encrypto=True`)を有効にします。キーは解析可能な場合は`~/.ssh/id_rsa`から来ます。そうでなければ、RSA -2048ペアが`PyFlow/network_api/.Flow/pvt_key/`に生成され、ピアキーが交換され、すべての接続でTOFUチェックされます(`PyFlow/network_api/.Flow/pub_key/pub_key.json`)。`is_custom_keys`と完全なハンドシェイクについては、TCP APIドキュメントを参照してください。", - "fefd6a69b9ee37bf": "最初に実行すると、サーバーランチャーは、デフォルトですべての`TCP_Server_Base`パラメーターを表示するスタートアップコンフィギュレーションページを開きます。保存された構成は`PyFlow/transfer_web/.Flow_Web/setup_server.json`(`setup.json`と同じ形状)にあります。TCPサーバーが起動すると、サーバーのWebバックエンドはステータスページを提供し、クライアント側のAPI (`/api/server_info`はTCPアドレス/ポートを返します)を提供します。クライアントランチャーは、サーバーアドレス(`http`/`https`ドメインまたはベアIP )を要求し、サーバーのWebバックエンドを介して接続します。次に、 アカウントにログインし(ユーザー名/メールアドレス、アカウントパスワード、およびアカウントアドレスに郵送された確認コード—両方の要素が必要です)、パスワードとセッショントークンを`PyFlow/transfer_web/.Flow_Web/client_login.json`に保存するため、**ログアウト**がそのファイルを削除するまで、すべてのリロードがクライアントを再度ログインさせます。両方のページには、接続されたインスタンスとメッセージ/ファイル/フォルダ送信のサイドバーが表示されます(クライアントからクライアントへの送信はサーバーを介して転送されます)。Webクライアントは、 取引先責任者であるアカウント。連絡先は、**連絡先**ボタン(ユーザーID、ユーザー名、またはメールアドレスで検索)で追加されます。相手側は、**リクエスト**リストでリクエストに応答し、両方のアカウントが互いに承認した後にのみ、連絡先がサイドバーに表示されます。拡張プロトコルは、クライアントページとサーバーページの管理者によって読み込まれます。ウェブツールは、残りの状態を同じ`.Flow_Web/`ディレクトリに保持します:`setup_client.json`(最後に クライアント起動構成)、`client_last_server.json`(接続ページによって提供される最後のサーバーアドレス)、`client_extensions_ui.json`/`server_extensions_ui.json`(拡張UI状態)、および`uploads/`ステージングディレクトリ。" + "eff58621a9dcab0a": "Visual Studio **ビルドツール** (C ++ワークロード、\"MSVC v 143\"およびWindows SDK):" }, "ko": { "0eb95fb6244c03f1": "빠른 시작", diff --git a/docs/source/locale/ja/LC_MESSAGES/Crypto/Crypto.po b/docs/source/locale/ja/LC_MESSAGES/Crypto/Crypto.po index bcf8007..8e9ee5d 100644 --- a/docs/source/locale/ja/LC_MESSAGES/Crypto/Crypto.po +++ b/docs/source/locale/ja/LC_MESSAGES/Crypto/Crypto.po @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,45 +17,45 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../source/Crypto/Crypto.rst:2 bb50e4f310ea43d9ba55e4b367ed7740 +#: ../../source/Crypto/Crypto.rst:2 9878b2fb3d9d4d6ba3cd00002ed6f0b7 msgid "C/OpenSSL Crypto Module" msgstr "C/OpenSSL 暗号化モジュール" -#: ../../source/Crypto/Crypto.rst:4 2838c629d37d42ef92dbabeab8d33801 +#: ../../source/Crypto/Crypto.rst:4 aa824d3e127240b0928431af3dd8c831 #, fuzzy msgid "" -"The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL cryptography" -" library. The library is independent from the Python runtime and is built " -"from the repository root with CMake." +"The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL " +"cryptography library. The library is independent from the Python runtime " +"and is built from the repository root with CMake." msgstr "" -"``src/crypto_api`` ディレクトリには、ServSpy の C/OpenSSL 暗号化ライブラリが含まれています。このライブラリは " -"Python ランタイムから独立しており、CMake を使用してリポジトリ ルートから構築されます。" +"``src/crypto_api`` ディレクトリには、ServSpy の C/OpenSSL 暗号化ライブラリが含まれています。このライブラリは" +" Python ランタイムから独立しており、CMake を使用してリポジトリ ルートから構築されます。" -#: ../../source/Crypto/Crypto.rst:8 2c028ead37a24eb98321135f22f3673d +#: ../../source/Crypto/Crypto.rst:8 294667df2a20495887126b808c7d9706 msgid "The module provides:" msgstr "このモジュールは以下を提供します。" -#: ../../source/Crypto/Crypto.rst:10 e290cfffb80140899093170eda086e61 +#: ../../source/Crypto/Crypto.rst:10 472d4f3082db42f198b7f13fdbf041f2 msgid "RSA-OAEP encryption and decryption with SHA-256." msgstr "RSA-OAEP 暗号化および SHA-256 による復号化。" -#: ../../source/Crypto/Crypto.rst:11 125f1968eba34f6896b44b6406f0e6c2 +#: ../../source/Crypto/Crypto.rst:11 0eb3f7206503452ca2229a1d7c323390 msgid "ECDH key agreement on P-256, P-384, and P-521." msgstr "P-256、P-384、および P-521 に関する ECDH 鍵合意。" -#: ../../source/Crypto/Crypto.rst:12 cee735932767478e95a96b9a59ddcdd2 +#: ../../source/Crypto/Crypto.rst:12 ab0be16cfbca493a88c6eb4a2ef1bb07 msgid "HKDF-SHA256 session-key derivation." msgstr "HKDF-SHA256 セッションキーの導出。" -#: ../../source/Crypto/Crypto.rst:13 7d211e9cf2e64cab9b79c0173805334e +#: ../../source/Crypto/Crypto.rst:13 56667bb7a4554c1b8efc918c9593f950 msgid "AES-256-GCM authenticated encryption for ECDH sessions." msgstr "ECDH セッションの AES-256-GCM 認証暗号化。" -#: ../../source/Crypto/Crypto.rst:14 d345fd729851496c82017971bdb55276 +#: ../../source/Crypto/Crypto.rst:14 8de85fb1a2f843ea91d0aa30df0a00c7 msgid "PEM key persistence and structured error reporting." msgstr "PEM キーの永続性と構造化されたエラー レポート。" -#: ../../source/Crypto/Crypto.rst:16 d86187e532624ac49492cca1b064a89b +#: ../../source/Crypto/Crypto.rst:16 564b1d414738498791d9083f279330fe msgid "" "The library version is 1.0.0 (``PF_CRYPTO_VERSION_MAJOR`` / " "``PF_CRYPTO_VERSION_MINOR`` / ``PF_CRYPTO_VERSION_PATCH`` and " @@ -65,31 +65,31 @@ msgstr "" "PF_CRYPTO_VERSION_MINOR ''/'' PF_CRYPTO_VERSION_PATCH ''および'' " "PF_CRYPTO_VERSION_STRING '')です。" -#: ../../source/Crypto/Crypto.rst:20 5e6c65799ec14fd8b67034bd1b3beb07 +#: ../../source/Crypto/Crypto.rst:20 10fda1fcea98430a8924fdfa8bbce2fa #, fuzzy msgid "The public headers are located in ``PyFlow/crypto_api/include``:" msgstr "パブリックヘッダーは ``src/crypto_api/include`` にあります。" -#: ../../source/Crypto/Crypto.rst:22 87305d509fc94f5186438e34d9583987 +#: ../../source/Crypto/Crypto.rst:22 86168d67fc8047ba8d4c61b2b9e23caf #, fuzzy msgid "``pf_crypto.h`` - common errors, OpenSSL diagnostics, and HKDF." msgstr "``ss_crypto.h`` - 一般的なエラー、OpenSSL 診断、および HKDF。" -#: ../../source/Crypto/Crypto.rst:23 5d221a05e5034eccadaec2206256a2af +#: ../../source/Crypto/Crypto.rst:23 ddfd841fba4b4045bb3fc84419010fe7 #, fuzzy msgid "``pf_rsa.h`` - RSA key and encryption APIs." msgstr "``ss_rsa.h`` - RSA キーおよび暗号化 API。" -#: ../../source/Crypto/Crypto.rst:24 e10e899ebf934a18a686d225d3f967d9 +#: ../../source/Crypto/Crypto.rst:24 eb2168817ac54389a35e194a444250f4 #, fuzzy msgid "``pf_ecdh.h`` - ECDH key agreement and seal/open APIs." msgstr "``ss_ecdh.h`` - ECDH 鍵合意およびシール/オープン API。" -#: ../../source/Crypto/Crypto.rst:27 09186509365444d4ac1ce145d76bcd28 +#: ../../source/Crypto/Crypto.rst:27 43fa12b668bb4dc389f2bbd9edaf9187 msgid "Build" msgstr "建てる" -#: ../../source/Crypto/Crypto.rst:29 ae41004303f342d2ac3e302fe5ff9b40 +#: ../../source/Crypto/Crypto.rst:29 35019410fade4c18b07d32d37c05ba0d msgid "" "The module requires OpenSSL 1.1.1 or newer and CMake 3.16 or newer. On " "Debian or Ubuntu, install the build dependencies with:" @@ -97,126 +97,131 @@ msgstr "" "このモジュールには、OpenSSL 1.1.1 以降および CMake 3.16 以降が必要です。 Debian または Ubuntu " "では、次のコマンドを使用してビルドの依存関係をインストールします。" -#: ../../source/Crypto/Crypto.rst:37 7c534481ca81453b89692a8758bbeba0 +#: ../../source/Crypto/Crypto.rst:37 3834ad9e83c24331b03d264103f5cdad msgid "" -"Installing the Python package builds it automatically: ``setup.py`` compiles" -" the three sources and installs the result inside the package " -"(``PyFlow/_crypto_api.cpython-3XX-.so``), so ``pip install pyflow-" -"net`` needs only a C compiler and the OpenSSL development headers." +"Installing the Python package builds it automatically: ``setup.py`` " +"compiles the three sources and installs the result inside the package " +"(``PyFlow/_crypto_api.cpython-3XX-.so``), so ``pip install " +"pyflow-net`` needs only a C compiler and the OpenSSL development headers." msgstr "" "Pythonパッケージをインストールすると、自動的にビルドされます。'' setup.py " -"''は3つのソースをコンパイルし、パッケージ内に結果をインストールします('' PyFlow " -"/_crypto_api.cpython-3XX-.so '')。したがって、'' pip install pyflow - net" -" ''はCコンパイラとOpenSSL開発ヘッダーのみを必要とします。" +"''は3つのソースをコンパイルし、パッケージ内に結果をインストールします('' PyFlow /_crypto_api.cpython-" +"3XX-.so '')。したがって、'' pip install pyflow - net " +"''はCコンパイラとOpenSSL開発ヘッダーのみを必要とします。" -#: ../../source/Crypto/Crypto.rst:42 6abf3a2d83804b73b1bfd45add4322d8 +#: ../../source/Crypto/Crypto.rst:42 a72fb95d5d114cdca29347b18e2c1253 msgid "" -"Build it from the repository root with CMake when the C test suite or the C " -"API itself is wanted:" +"Build it from the repository root with CMake when the C test suite or the" +" C API itself is wanted:" msgstr "CテストスイートまたはC API自体が必要な場合に、CMakeを使用してリポジトリルートからビルドします。" -#: ../../source/Crypto/Crypto.rst:51 6fbb49d9124649f1b387de2f0377a4af +#: ../../source/Crypto/Crypto.rst:51 96617bb44be2438ebbde9e9f750b3e09 msgid "" "``ctest --test-dir`` was added in CMake 3.20; with the 3.16 minimum the " "equivalent is ``ctest --output-on-failure`` run from inside ``build/``." msgstr "" -"'' ctest -- test - dir ''はCMake 3.20で追加されました。3.16の最小値では、'' ctest -- output -" -" on - failure ''は'' build /''の内部から実行されます。" +"'' ctest -- test - dir ''はCMake 3.20で追加されました。3.16の最小値では、'' ctest -- " +"output - on - failure ''は'' build /''の内部から実行されます。" -#: ../../source/Crypto/Crypto.rst:54 f42772e265ad4248b11c37141f4fb6e8 +#: ../../source/Crypto/Crypto.rst:54 244b7aff35aa4272a121b9fbbadae117 #, fuzzy msgid "" -"The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, ``test_rsa``," -" ``test_ecdh``). It is built only when ``CRYPTO_API_BUILD_TESTS`` (default " -"``ON``) and ``BUILD_TESTING`` are both enabled, and then runs together with " -"the library." +"The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, " +"``test_rsa``, ``test_ecdh``). It is built only when " +"``CRYPTO_API_BUILD_TESTS`` (default ``ON``) and ``BUILD_TESTING`` are " +"both enabled, and then runs together with the library." msgstr "" -"C テストスイートは ``test/crypto_api/`` (``test_hkdf``、``test_rsa``、``test_ecdh``) " -"に存在し、ライブラリと一緒に構築および実行されます。" +"C テストスイートは ``test/crypto_api/`` " +"(``test_hkdf``、``test_rsa``、``test_ecdh``) に存在し、ライブラリと一緒に構築および実行されます。" -#: ../../source/Crypto/Crypto.rst:59 ed6b92c776ca441ab8629088ecd973bc +#: ../../source/Crypto/Crypto.rst:59 30ea804b8270411f8793908bdc7a2a97 #, fuzzy msgid "" -"The library is built as a shared object (``libcrypto_api.so``) so it can be " -"loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes binding" -" used by the TCP layer to encrypt messages with RSA-OAEP (see the " -"``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). The " -"binding also implements the TCP layer's anti-MITM identity check (TOFU): " -"peer public keys are exchanged on every connection, recorded under the " -"peer's ``(ip, port)`` in ``network_api/.Flow/pub_key/pub_key.json`` with the" -" SHA-256 of the received PEM text, and a changed key for a recorded endpoint" -" rejects the connection; a key already known under another endpoint is " -"accepted and re-registered under the new one. The encryption state machine " -"is bounded: three consecutive decode failures trip a circuit breaker " -"(``MAX_DECODE_FAILURES`` in ``connect_tcp.py``) that stops re-keying, and a " -"key that is stale or rotated makes the TCP layer reload its own key and re-" -"exchange. The binding looks for the library via ``ctypes.util.find_library``" -" and then next to the repository root in ``build/`` (``libcrypto_api.so``, " +"The library is built as a shared object (``libcrypto_api.so``) so it can " +"be loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes " +"binding used by the TCP layer. It exposes the RSA-OAEP message encryption" +" and the ECDH/AES-256-GCM sealing (``EcdhKeyPair`` / ``EcdhPubKey`` / " +"``hkdf_sha256``) that the framed TCP channel uses for its bulk and file " +"transfer payloads (see the ``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"encrypted channel sections). The binding also implements the TCP layer's " +"anti-MITM identity check (TOFU): endpoint rejects the connection; a key " +"already known under another endpoint is accepted and re-registered under " +"the new one. The encryption state machine is bounded: three consecutive " +"decode failures trip a circuit breaker (``MAX_DECODE_FAILURES`` in " +"``connect_tcp.py``) that stops re-keying, and a key that is stale or " +"rotated makes the TCP layer reload its own key and re-exchange. The " +"binding looks for the library via ``ctypes.util.find_library`` and then " +"next to the repository root in ``build/`` (``libcrypto_api.so``, " "``libcrypto_api.dylib``, ``libcrypto_api.dll`` and " "``build/Release/crypto_api.dll``)." msgstr "" "このライブラリは共有オブジェクト (``libcrypto_api.so``) として構築されているため、Python からロードできます。 " -"``src/network_api/rsa_crypto.py`` は、RSA-OAEP でメッセージを暗号化するために TCP 層によって使用される " -"ctypes バインディングです (``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"``src/network_api/rsa_crypto.py`` は、RSA-OAEP でメッセージを暗号化するために TCP " +"層によって使用される ctypes バインディングです (``TCP_Server_APIs`` / ``TCP_Client_APIs`` " "暗号化チャネルのセクションを参照)。このバインディングは、TCP 層の反 MITM ID チェック (TOFU) " "も実装します。ピアの公開鍵は接続ごとに交換され、ピアの ``(ip, port)'' の " "``network_api/.Flow/pub_key/pub_key.json`` に SHA-256 " -"で記録され、記録されたエンドポイントの変更されたキーは接続を拒否します。バインディングは ``ctypes.util.find_library`` " -"を介して、およびリポジトリ ルートの隣の ``build/`` 内でライブラリを検索します。" +"で記録され、記録されたエンドポイントの変更されたキーは接続を拒否します。バインディングは ``ctypes.util.find_library``" +" を介して、およびリポジトリ ルートの隣の ``build/`` 内でライブラリを検索します。" -#: ../../source/Crypto/Crypto.rst:77 ad993af85f8f45f5a3661448f69961bf +#: ../../source/Crypto/Crypto.rst:77 9594680fce33464f9ff9cb9590bb5d0a msgid "" "The build produces the SOVERSIONed names ``libcrypto_api.so.1`` / " "``libcrypto_api.so.1.0.0`` plus the ``libcrypto_api.so`` loader symlink." msgstr "" -"ビルドは、SOVERSION形式の名前'' libcrypto_api.so.1 ''/'' libcrypto_api.so.1.0.0 ''と'' " -"libcrypto_api.so ''ローダーのシンボリックリンクを生成します。" +"ビルドは、SOVERSION形式の名前'' libcrypto_api.so.1 ''/'' libcrypto_api.so.1.0.0 " +"''と'' libcrypto_api.so ''ローダーのシンボリックリンクを生成します。" -#: ../../source/Crypto/Crypto.rst:80 7ea41df5c6644e8197d587e03642123f +#: ../../source/Crypto/Crypto.rst:80 80c24657a4c9445088459fff264379b2 #, fuzzy msgid "" -"CMake install rules export the ``crypto_api`` library, its public headers, " -"and a CMake package configuration. All CMake content sits at the repository " -"root: the CMake package template and the pkg-config template are " -"``cmake/crypto_apiConfig.cmake.in`` and ``crypto_api.pc.in``. Consumers use " -"the CMake target ``crypto_api::crypto_api`` (or " +"CMake install rules export the ``crypto_api`` library, its public " +"headers, and a CMake package configuration. All CMake content sits at the" +" repository root: the CMake package template and the pkg-config template " +"are ``cmake/crypto_apiConfig.cmake.in`` and ``crypto_api.pc.in``. " +"Consumers use the CMake target ``crypto_api::crypto_api`` (or " "``find_package(crypto_api)``, ``SameMajorVersion`` compatible), or pkg-" -"config module ``crypto_api`` (``-lcrypto_api`` for linking, ``-lcrypto`` as " -"a private dependency)." +"config module ``crypto_api`` (``-lcrypto_api`` for linking, ``-lcrypto`` " +"as a private dependency)." msgstr "" "CMake インストール ルールは、「crypto_api」 ライブラリ、そのパブリック ヘッダー、および CMake " -"パッケージ構成をエクスポートします。すべての CMake コンテンツはリポジトリ ルートにあります。CMake パッケージ テンプレートと pkg-" -"config テンプレートは ``cmake/crypto_apiConfig.cmake.in`` と ``crypto_api.pc.in`` " -"です。" +"パッケージ構成をエクスポートします。すべての CMake コンテンツはリポジトリ ルートにあります。CMake パッケージ テンプレートと " +"pkg-config テンプレートは ``cmake/crypto_apiConfig.cmake.in`` と " +"``crypto_api.pc.in`` です。" -#: ../../source/Crypto/Crypto.rst:89 0d7e08f1e07445dfa77b47a85a25def7 +#: ../../source/Crypto/Crypto.rst:89 dccd3901c8024859b9a9753e818d6692 msgid "Common API" msgstr "共通API" -#: ../../source/Crypto/Crypto.rst:91 1c9b38b493964582875d168e61ccf829 +#: ../../source/Crypto/Crypto.rst:91 c1b71e19c8f6422eabd99bd0997daae8 msgid "" "Most public functions return ``pf_err_t``; ``PF_OK`` indicates success. " -"Functions that report a size or a string instead have their own return type " -"(``pf_err_string`` returns ``const char *``, ``pf_crypto_openssl_errors`` " -"returns ``void``, ``pf_rsa_ciphertext_len`` and ``pf_rsa_max_plaintext_len``" -" return ``size_t``, and the ``*_free`` functions return ``void``). Use " -"``pf_err_string`` to convert an error code to readable text and " -"``pf_crypto_openssl_errors`` to retrieve the pending OpenSSL error queue." +"Functions that report a size or a string instead have their own return " +"type (``pf_err_string`` returns ``const char *``, " +"``pf_crypto_openssl_errors`` returns ``void``, ``pf_rsa_ciphertext_len`` " +"and ``pf_rsa_max_plaintext_len`` return ``size_t``, and the ``*_free`` " +"functions return ``void``). Use ``pf_err_string`` to convert an error " +"code to readable text and ``pf_crypto_openssl_errors`` to retrieve the " +"pending OpenSSL error queue." msgstr "" "ほとんどのパブリック関数は'' pf_err_t ''を返します。'' PF_OK " "''は成功を示します。代わりに、サイズまたは文字列を報告する関数には、独自の戻り値の型があります('' pf_err_string ''は'' " "const char *''を返し、'' pf_crypto_openssl_errors ''は'' void ''を返し、'' " -"pf_rsa_ciphertext_len ''と'' pf_rsa_max_plaintext_len ''は'' size_t ''を返し、''*_" -" free ''関数は'' void ''を返します)。'' pf_err_string ''を使用して、エラーコードを読み取り可能なテキストに変換し、" -" '' pf_crypto_openssl_errors ''は、保留中のOpenSSLエラーキューを取得します。" +"pf_rsa_ciphertext_len ''と'' pf_rsa_max_plaintext_len ''は'' size_t " +"''を返し、''*_ free ''関数は'' void ''を返します)。'' pf_err_string " +"''を使用して、エラーコードを読み取り可能なテキストに変換し、 '' pf_crypto_openssl_errors " +"''は、保留中のOpenSSLエラーキューを取得します。" -#: ../../source/Crypto/Crypto.rst:114 07ac67f777704ad9822023430f0109c4 +#: ../../source/Crypto/Crypto.rst:114 67ae5556635e43a487c38bf8011e1c5b #, fuzzy msgid "" "The library uses caller-provided output buffers for fixed-size results. " "Functions that return allocated buffers document that the caller must " -"release them with ``free``. Opaque key handles must be released with their " -"corresponding ``*_free`` function. HKDF output is capped at " +"release them with ``pf_crypto_free`` — the library's own ``free``, so the" +" allocation and the deallocation always run on the same C runtime (a host" +" such as CPython on Windows may use a different one, and freeing across " +"runtimes corrupts the heap). Opaque key handles must be released with " +"their corresponding ``*_free`` function. HKDF output is capped at " "``PF_CRYPTO_HKDF_SHA256_MAX_OUT`` (8160 bytes) by both " "``pf_crypto_hkdf_sha256`` and ``pf_ecdh_derive_key``." msgstr "" @@ -224,117 +229,118 @@ msgstr "" "``free`` でバッファを解放する必要があることが文書化されています。不透明なキーハンドルは、対応する ``*_free`` " "関数を使用して解放する必要があります。" -#: ../../source/Crypto/Crypto.rst:122 619e39d223d54a48ba983a3b30bd7d9d +#: ../../source/Crypto/Crypto.rst:125 69248ac47e7e47f18e953dee857db239 msgid "RSA API" msgstr "RSA API" -#: ../../source/Crypto/Crypto.rst:124 5eeaa87820f941dd8e171c973269036e +#: ../../source/Crypto/Crypto.rst:127 a770dcc04e2c42d1be50fe30d298df4b #, fuzzy msgid "" -"RSA keys are generated with ``pf_rsa_keygen``. The implementation uses RSA-" -"OAEP with SHA-256 for encryption and decryption. Key sizes from 2048 to " -"16384 bits are accepted; 2048, 3072, or 4096 bits are recommended." +"RSA keys are generated with ``pf_rsa_keygen``. The implementation uses " +"RSA-OAEP with SHA-256 for encryption and decryption. Key sizes from 2048 " +"to 16384 bits are accepted; 2048, 3072, or 4096 bits are recommended." msgstr "" "RSA キーは ``ss_rsa_keygen`` で生成されます。この実装では、暗号化と復号化に SHA-256 を備えた RSA-OAEP " "を使用します。 2048 ~ 16384 ビットのキー サイズが受け入れられます。 2048、3072、または 4096 ビットが推奨されます。" -#: ../../source/Crypto/Crypto.rst:148 f85a46b466ef47ee9d195f439ba3b153 +#: ../../source/Crypto/Crypto.rst:151 e7b876b8fb354b2da45d3c13f50ededf msgid "" -"The first encryption call with ``out == NULL`` queries the required output " -"size; ``pf_rsa_decrypt`` supports the same query pattern. RSA encryption is " -"binary-safe (it accepts an explicit input length, embedded NUL bytes " -"included) and rejects inputs longer than the value returned by " +"The first encryption call with ``out == NULL`` queries the required " +"output size; ``pf_rsa_decrypt`` supports the same query pattern. RSA " +"encryption is binary-safe (it accepts an explicit input length, embedded " +"NUL bytes included) and rejects inputs longer than the value returned by " "``pf_rsa_max_plaintext_len`` with ``PF_ERR_INVALID_ARG``. " -"``pf_rsa_ciphertext_len`` returns the ciphertext size for a key (equal to " -"its modulus size in bytes), and ``pf_rsa_key_free`` releases a key handle." +"``pf_rsa_ciphertext_len`` returns the ciphertext size for a key (equal to" +" its modulus size in bytes), and ``pf_rsa_key_free`` releases a key " +"handle." msgstr "" "'' out == NULL ''の最初の暗号化呼び出しは、必要な出力サイズをクエリします。'' pf_rsa_decrypt " -"''は、同じクエリパターンをサポートしています。RSA暗号化はバイナリセーフ(明示的な入力長を受け入れ、埋め込まれたNULバイトを含む)であり、'' " -"pf_rsa_max_plaintext_len ''が'' PF_ERR_INVALID_ARG ''で返す値よりも長い入力を拒否します。'' " -"pf_rsa_ciphertext_len ''は、キーの暗号文サイズ(バイト単位の係数サイズに等しい)を返し、 '' pf_rsa_key_free " -"''はキーハンドルを解放します。" +"''は、同じクエリパターンをサポートしています。RSA暗号化はバイナリセーフ(明示的な入力長を受け入れ、埋め込まれたNULバイトを含む)であり、''" +" pf_rsa_max_plaintext_len ''が'' PF_ERR_INVALID_ARG ''で返す値よりも長い入力を拒否します。''" +" pf_rsa_ciphertext_len ''は、キーの暗号文サイズ(バイト単位の係数サイズに等しい)を返し、 '' " +"pf_rsa_key_free ''はキーハンドルを解放します。" -#: ../../source/Crypto/Crypto.rst:156 ff9d2472cf614dd0827d0887f195ed43 +#: ../../source/Crypto/Crypto.rst:159 6af957980305426e915b3f62d9eb1ed4 msgid "Public and private keys can be stored as PEM files:" msgstr "公開キーと秘密キーは PEM ファイルとして保存できます。" -#: ../../source/Crypto/Crypto.rst:167 a3f163de660b4d49a36a8aedead555da +#: ../../source/Crypto/Crypto.rst:170 6bf9df3c51d540b69680723a4845de2d msgid "ECDH API" msgstr "ECDH API" -#: ../../source/Crypto/Crypto.rst:169 4535e8f410a742f38d32ff53d404c37b +#: ../../source/Crypto/Crypto.rst:172 3c69950828364df49bbf0b37313f9987 #, fuzzy msgid "" -"ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The supported " -"curve names are:" +"ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The " +"supported curve names are:" msgstr "ECDH キーペアは ``ss_ecdh_keypair_generate`` で作成されます。サポートされている曲線名は次のとおりです。" -#: ../../source/Crypto/Crypto.rst:172 9624f8475c8d4618a7054e7c18ae5e1f +#: ../../source/Crypto/Crypto.rst:175 6a4d2171568847d4984c8705818c4bf9 msgid "``PF_ECDH_CURVE_P256``" msgstr "「PF_ECDH_CURVE_P256」" -#: ../../source/Crypto/Crypto.rst:173 4585a2433d684621a5f90805b74cef6c +#: ../../source/Crypto/Crypto.rst:176 c0da017a21dc46ed93b3da0727454dc3 msgid "``PF_ECDH_CURVE_P384``" msgstr "「PF_ECDH_CURVE_P384」" -#: ../../source/Crypto/Crypto.rst:174 14dde8ddd1b44ae1a4cb64179caa5aa5 +#: ../../source/Crypto/Crypto.rst:177 b2019f9f782b48dc85c5e3b24647fd94 msgid "``PF_ECDH_CURVE_P521``" msgstr "「PF_ECDH_CURVE_P521」" -#: ../../source/Crypto/Crypto.rst:176 43b77941f20d44958205bea666a208d5 +#: ../../source/Crypto/Crypto.rst:179 0962e1bca8da48d1835cbe8facb8a0ea #, fuzzy msgid "" -"An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` selects " -"P-256. Public keys are exchanged as PEM SubjectPublicKeyInfo strings. Parsed" -" peer keys are checked to lie on the curve before use." +"An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` " +"selects P-256. Public keys are exchanged as PEM SubjectPublicKeyInfo " +"strings. Parsed peer keys are checked to lie on the curve before use." msgstr "公開キーは、PEM SubjectPublicKeyInfo 文字列として交換されます。解析されたピアキーは使用前にチェックされます。" -#: ../../source/Crypto/Crypto.rst:200 ac2db67c049d4f55a2fc2f9972c6d57c +#: ../../source/Crypto/Crypto.rst:203 c5c15560992c48beb7637c19a517f07f #, fuzzy msgid "" -"The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are recommended " -"for application payloads. They derive an AES-256-GCM key with HKDF-SHA256 " -"from a random 16-byte salt and bind both public keys (in byte-sorted " -"canonical order) as the HKDF ``info``, so the same key pair always agrees " -"regardless of call order and a peer using a different key pair fails " -"authentication. They authenticate optional AAD." +"The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are " +"recommended for application payloads. They derive an AES-256-GCM key with" +" HKDF-SHA256 from a random 16-byte salt and bind both public keys (in " +"byte-sorted canonical order) as the HKDF ``info``, so the same key pair " +"always agrees regardless of call order and a peer using a different key " +"pair fails authentication. They authenticate optional AAD." msgstr "" "アプリケーションのペイロードには、より高レベルの ``ss_ecdh_seal`` および ``ss_ecdh_open`` API " -"が推奨されます。これらは、HKDF-SHA256 を使用して AES-256-GCM キーを取得し、ランダム ソルトと IV を含めて、オプションの " -"AAD を認証します。" +"が推奨されます。これらは、HKDF-SHA256 を使用して AES-256-GCM キーを取得し、ランダム ソルトと IV " +"を含めて、オプションの AAD を認証します。" -#: ../../source/Crypto/Crypto.rst:207 70a8e3f511f34359974c9152d60500b2 +#: ../../source/Crypto/Crypto.rst:210 f794a8f7227443e381d5337e9fe95677 #, fuzzy msgid "The ``pf_ecdh_seal`` output format is:" msgstr "`ss_ecdh_seal` の出力形式は次のとおりです。" -#: ../../source/Crypto/Crypto.rst:213 28f1933678854354b8ef357adcfdd380 +#: ../../source/Crypto/Crypto.rst:216 ee4a7ea6853249a7a137f949e3b9d7cc #, fuzzy msgid "" -"The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty plaintext " -"is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` and no " -"plaintext is returned. On success the output buffer is ``malloc``-ed and the" -" caller frees it." +"The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty " +"plaintext is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` " +"and no plaintext is returned. On success the output buffer is " +"``malloc``-ed and the caller releases it with ``pf_crypto_free``." msgstr "" "固定オーバーヘッドは ``SS_ECDH_SEAL_OVERHEAD`` (44 バイト) " "です。空の平文は許可されます。タグチェックが失敗すると「SS_ERR_AUTH_FAILED」が返され、平文は返されません。" -#: ../../source/Crypto/Crypto.rst:218 9a7c6cc7b5a94e5fac26bc6802310183 +#: ../../source/Crypto/Crypto.rst:221 212039cbe4b74827b643af47aaaf9970 msgid "" "ECDH key pairs can be persisted with ``pf_ecdh_keypair_write_priv`` and " -"``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-protected " -"with AES-256-CBC); ``pf_ecdh_keypair_free`` and ``pf_ecdh_pubkey_free`` " -"release the handles." +"``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-" +"protected with AES-256-CBC); ``pf_ecdh_keypair_free`` and " +"``pf_ecdh_pubkey_free`` release the handles." msgstr "" -"ECDHキーペアは、'' pf_ecdh_keypair_write_priv ''および'' pf_ecdh_keypair_read_priv " -"''( PKCS # 8 PEM、オプションでAES -256 - CBCでパスフレーズ保護)で永続化できます。'' " +"ECDHキーペアは、'' pf_ecdh_keypair_write_priv ''および'' pf_ecdh_keypair_read_priv" +" ''( PKCS # 8 PEM、オプションでAES -256 - CBCでパスフレーズ保護)で永続化できます。'' " "pf_ecdh_keypair_free ''および'' pf_ecdh_pubkey_free ''はハンドルを解放します。" -#: ../../source/Crypto/Crypto.rst:224 7f05214ee91a478581014c39643d7bfb +#: ../../source/Crypto/Crypto.rst:227 a84d53d68554474fbb2beaa2146cee86 msgid "Security Notes" msgstr "セキュリティに関する注意事項" -#: ../../source/Crypto/Crypto.rst:226 a6482f5940d1469088bb376b1d25d31c +#: ../../source/Crypto/Crypto.rst:229 5e398f6a7ace4aeea29bcd40e75a59b1 msgid "" "ECDH provides key agreement, but it does not authenticate public-key " "ownership by itself. Public keys must be exchanged over an authenticated " @@ -343,27 +349,28 @@ msgstr "" "ECDH " "は鍵の合意を提供しますが、それ自体では公開鍵の所有権を認証しません。公開キーは、認証されたチャネルを介して交換されるか、外部の署名/証明書メカニズムを使用して検証される必要があります。" -#: ../../source/Crypto/Crypto.rst:230 fb49962bd1f0474c91610fa9dd020584 +#: ../../source/Crypto/Crypto.rst:233 df43fe66482c4e0fb896ab598ce43c7d #, fuzzy msgid "" -"Private key files may be protected with a passphrase: ``pf_rsa_write_priv`` " -"and ``pf_ecdh_keypair_write_priv`` encrypt the PKCS#8 PEM with AES-256-CBC " -"when a passphrase is given, and the matching read function needs the same " -"passphrase. Applications should restrict their file permissions and avoid " -"logging passphrases, private keys, or plaintext session keys." +"Private key files may be protected with a passphrase: " +"``pf_rsa_write_priv`` and ``pf_ecdh_keypair_write_priv`` encrypt the " +"PKCS#8 PEM with AES-256-CBC when a passphrase is given, and the matching " +"read function needs the same passphrase. Applications should restrict " +"their file permissions and avoid logging passphrases, private keys, or " +"plaintext session keys." msgstr "" "秘密キー ファイルはパスフレーズで保護できます。アプリケーションはファイルのアクセス許可を制限し、パスフレーズ、秘密キー、または平文のセッション " "キーのログ記録を避ける必要があります。" -#: ../../source/Crypto/Crypto.rst:238 e09bc96e058a4b14b135a1430b8a3ad9 +#: ../../source/Crypto/Crypto.rst:241 02cb264ad6c747d29b37bfa1f1cc6362 msgid "Error Handling" msgstr "エラー処理" -#: ../../source/Crypto/Crypto.rst:240 8246aab2cf7d4913a7345684940c9220 +#: ../../source/Crypto/Crypto.rst:243 60786ad51ea444da97922957e670ea90 msgid "The main error codes are:" msgstr "主なエラーコードは次のとおりです。" -#: ../../source/Crypto/Crypto.rst:242 45059d6bf45c42c2bc8e8c6f023836f4 +#: ../../source/Crypto/Crypto.rst:245 8c1b057428f2445889d1159d6636b097 msgid "" "``PF_ERR_INVALID_ARG`` - NULL argument, illegal length or bad parameter " "combination (e.g. out-of-range RSA key size, a NULL salt/info with a non-" @@ -372,64 +379,72 @@ msgstr "" "'' PF_ERR_INVALID_ARG '' - " "NULL引数、不正な長さ、または不正なパラメータの組み合わせ(例:範囲外のRSAキーサイズ、長さがゼロでないNULLソルト/INFO、またはキーが許可するよりも長い平文)。" -#: ../../source/Crypto/Crypto.rst:245 daed84defdb64065849a0ef880b22eea +#: ../../source/Crypto/Crypto.rst:248 27e26e555ee24ce68ab7943b4117a57d #, fuzzy msgid "``PF_ERR_NOMEM`` - allocation failure." msgstr "``SS_ERR_NOMEM`` - 割り当て失敗。" -#: ../../source/Crypto/Crypto.rst:246 788a5b4b06714adcab5aeb36b81757e4 +#: ../../source/Crypto/Crypto.rst:249 2b3828e4bfa04329a60b479be7f0dfe5 #, fuzzy msgid "``PF_ERR_OPENSSL`` - OpenSSL operation failure." msgstr "``SS_ERR_IO`` - ファイル操作の失敗。" -#: ../../source/Crypto/Crypto.rst:247 0e06a2169f5d445cab788910aaee188a +#: ../../source/Crypto/Crypto.rst:250 2c3c9ab09d294be8911f4fb31c335db6 #, fuzzy msgid "``PF_ERR_IO`` - file operation failure." msgstr "``SS_ERR_IO`` - ファイル操作の失敗。" -#: ../../source/Crypto/Crypto.rst:248 0d1b17cc4e744efd891efe2d292f6dd8 +#: ../../source/Crypto/Crypto.rst:251 a928f8b90e154bdaa43ef4e4ee7d578d #, fuzzy msgid "" -"``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key passphrase." +"``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key " +"passphrase." msgstr "``SS_ERR_PARSE`` - 不正な形式の PEM/DER 入力または間違った秘密鍵パスフレーズ。" -#: ../../source/Crypto/Crypto.rst:249 8d5f6adfe3b24ecebb6ed2d84cece394 +#: ../../source/Crypto/Crypto.rst:252 9cd41d63123d49caa946160465dda70f #, fuzzy msgid "``PF_ERR_BUFFER_TOO_SMALL`` - caller output buffer is insufficient." msgstr "``SS_ERR_BUFFER_TOO_SMALL`` - 呼び出し元の出力バッファが不十分です。" -#: ../../source/Crypto/Crypto.rst:250 7a88e3913e8948edbcf645b5097b47b3 +#: ../../source/Crypto/Crypto.rst:253 78532f0a764249178076a4adcc032f7f #, fuzzy msgid "``PF_ERR_AUTH_FAILED`` - AES-GCM authentication failed." msgstr "``SS_ERR_AUTH_FAILED`` - AES-GCM 認証が失敗しました。" -#: ../../source/Crypto/Crypto.rst:251 1182998c4b164675a840d89b3a8e994b +#: ../../source/Crypto/Crypto.rst:254 5e5f5421333e4382ae5e700d7570648b #, fuzzy msgid "``PF_ERR_UNSUPPORTED`` - unsupported curve or key type." msgstr "``SS_ERR_UNSUPPORTED`` - サポートされていないカーブまたはキー タイプ。" -#: ../../source/Crypto/Crypto.rst:252 0af6413bc92a46a48a1ea044a6b4f05b +#: ../../source/Crypto/Crypto.rst:255 d1fea86be03940d097132b112b6f14f2 #, fuzzy msgid "``PF_ERR_DECRYPT`` - RSA decryption failed." msgstr "``SS_ERR_DECRYPT`` - RSA 復号化に失敗しました。" -#: ../../source/Crypto/Crypto.rst:254 b425983151054505a243c1d65c68a2b8 +#: ../../source/Crypto/Crypto.rst:257 9b1c2b2d3f48459bbedee21c92aafe31 msgid "For detailed OpenSSL diagnostics:" msgstr "詳細な OpenSSL 診断については、以下を参照してください。" #~ msgid "" -#~ "The library is built as a shared object (``libcrypto_api.so``) so it can be " -#~ "loaded from Python: ``src/network_api/rsa_crypto.py`` is a ctypes binding " -#~ "used by the TCP layer to encrypt messages with RSA-OAEP (see the " -#~ "``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). The " -#~ "binding looks for the library via ``ctypes.util.find_library`` and in " -#~ "``build/`` next to the repository root." +#~ "The library is built as a shared" +#~ " object (``libcrypto_api.so``) so it can" +#~ " be loaded from Python: " +#~ "``src/network_api/rsa_crypto.py`` is a ctypes " +#~ "binding used by the TCP layer to" +#~ " encrypt messages with RSA-OAEP (see" +#~ " the ``TCP_Server_APIs`` / ``TCP_Client_APIs``" +#~ " encrypted channel sections). The binding" +#~ " looks for the library via " +#~ "``ctypes.util.find_library`` and in ``build/`` " +#~ "next to the repository root." #~ msgstr "" -#~ "このライブラリは共有オブジェクト (``libcrypto_api.so``) として構築されているため、Python からロードできます。 " -#~ "``src/network_api/rsa_crypto.py`` は、RSA-OAEP でメッセージを暗号化するために TCP 層によって使用される " -#~ "ctypes バインディングです (``TCP_Server_APIs`` / ``TCP_Client_APIs`` " -#~ "暗号化チャネルのセクションを参照)。バインディングは ``ctypes.util.find_library`` を介して、およびリポジトリ ルートの隣の" -#~ " ``build/`` でライブラリを検索します。" +#~ "このライブラリは共有オブジェクト (``libcrypto_api.so``) " +#~ "として構築されているため、Python からロードできます。 " +#~ "``src/network_api/rsa_crypto.py`` は、RSA-OAEP " +#~ "でメッセージを暗号化するために TCP 層によって使用される ctypes " +#~ "バインディングです (``TCP_Server_APIs`` / ``TCP_Client_APIs``" +#~ " 暗号化チャネルのセクションを参照)。バインディングは ``ctypes.util.find_library`` " +#~ "を介して、およびリポジトリ ルートの隣の ``build/`` でライブラリを検索します。" #~ msgid "``SS_ECDH_CURVE_P256``" #~ msgstr "「SS_ECDH_CURVE_P256」" @@ -447,22 +462,30 @@ msgstr "詳細な OpenSSL 診断については、以下を参照してくださ #~ msgstr "リポジトリのルートからビルドします。" #~ msgid "" -#~ "All public functions return ``pf_err_t``. ``PF_OK`` indicates success. Use " -#~ "``pf_err_string`` to convert an error code to readable text and " -#~ "``pf_crypto_openssl_errors`` to retrieve the pending OpenSSL error queue." +#~ "All public functions return ``pf_err_t``. " +#~ "``PF_OK`` indicates success. Use " +#~ "``pf_err_string`` to convert an error " +#~ "code to readable text and " +#~ "``pf_crypto_openssl_errors`` to retrieve the " +#~ "pending OpenSSL error queue." #~ msgstr "" -#~ "すべてのパブリック関数は ``ss_err_t`` を返します。 ``SS_OK`` は成功を示します。 ``ss_err_string`` " -#~ "を使用してエラーコードを読み取り可能なテキストに変換し、 ``ss_crypto_openssl_errors`` を使用して保留中の OpenSSL " +#~ "すべてのパブリック関数は ``ss_err_t`` を返します。 ``SS_OK`` " +#~ "は成功を示します。 ``ss_err_string`` を使用してエラーコードを読み取り可能なテキストに変換し、" +#~ " ``ss_crypto_openssl_errors`` を使用して保留中の OpenSSL " #~ "エラーキューを取得します。" #~ msgid "" -#~ "The first encryption call with ``out == NULL`` queries the required output " -#~ "size. RSA encryption is binary-safe and accepts an explicit input length. " -#~ "The maximum plaintext size is returned by ``pf_rsa_max_plaintext_len``." +#~ "The first encryption call with ``out " +#~ "== NULL`` queries the required output" +#~ " size. RSA encryption is binary-safe" +#~ " and accepts an explicit input " +#~ "length. The maximum plaintext size is" +#~ " returned by ``pf_rsa_max_plaintext_len``." #~ msgstr "" -#~ "``out == NULL`` を指定した最初の暗号化呼び出しは、必要な出力サイズをクエリします。 RSA " -#~ "暗号化はバイナリセーフであり、明示的な入力長を受け入れます。平文の最大サイズは ``ss_rsa_max_plaintext_len`` " -#~ "によって返されます。" +#~ "``out == NULL`` を指定した最初の暗号化呼び出しは、必要な出力サイズをクエリします。" +#~ " RSA 暗号化はバイナリセーフであり、明示的な入力長を受け入れます。平文の最大サイズは " +#~ "``ss_rsa_max_plaintext_len`` によって返されます。" #~ msgid "``PF_ERR_INVALID_ARG`` - invalid pointer or length." #~ msgstr "``SS_ERR_INVALID_ARG`` - 無効なポインタまたは長さです。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/File_Transfer/File_Transfer.po b/docs/source/locale/ja/LC_MESSAGES/File_Transfer/File_Transfer.po index e9f0495..25fc5cd 100644 --- a/docs/source/locale/ja/LC_MESSAGES/File_Transfer/File_Transfer.po +++ b/docs/source/locale/ja/LC_MESSAGES/File_Transfer/File_Transfer.po @@ -6,291 +6,300 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.18.0\n" #: ../../source/File_Transfer/File_Transfer.rst:2 -#: 2d215e70ec1e43988343e3d32392d8aa +#: d9c92006bc3e49c9a5d184d74f2e7824 msgid "TCP File Transfer Mechanism" msgstr "TCP ファイル転送メカニズム" #: ../../source/File_Transfer/File_Transfer.rst:4 -#: f603ff252cb64bea9b7c9034d2d46221 +#: b32ed3356f814a369d9d4bc153c017fa msgid "" -"This document describes the file transfer subsystem implemented in both the " -"``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file transfer " -"mechanism allows sending and receiving single files, folders, multiple " -"files, and multiple folders between a server and its connected clients. It " -"also supports server-initiated transfers from the server console." +"This document describes the file transfer subsystem implemented in both " +"the ``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file " +"transfer mechanism allows sending and receiving single files, folders, " +"multiple files, and multiple folders between a server and its connected " +"clients. It also supports server-initiated transfers from the server " +"console." msgstr "" "このドキュメントでは、 ``TCP_Server_Base`` クラスと ``TCP_Client_Base`` " "クラスの両方に実装されたファイル転送サブシステムについて説明します。ファイル転送メカニズムを使用すると、サーバーと接続されたクライアントの間で、単一のファイル、フォルダー、複数のファイル、および複数のフォルダーを送受信できます。また、サーバー" " コンソールからサーバーが開始する転送もサポートします。" #: ../../source/File_Transfer/File_Transfer.rst:14 -#: f28ca12001c24b1c954e10fdb63aa493 +#: ad6d3cd551694899ba6998e43167bb10 msgid "The design follows a **two-phase handshake** pattern:" msgstr "この設計は **2 フェーズ ハンドシェイク** パターンに従います。" #: ../../source/File_Transfer/File_Transfer.rst:16 -#: b348421cfc6d4267a58231db041e7d67 +#: f67e58b5ae8b4e2a8f9a9021efba0b5c msgid "A transfer command is exchanged over the main control connection." msgstr "転送コマンドはメイン制御接続を介して交換されます。" #: ../../source/File_Transfer/File_Transfer.rst:18 -#: 0483543fb8f0497a9ee256fee509e4fc +#: 4d267488a6cf4911bc2c3cb7801dce8d msgid "" -"A separate TCP connection is established on a dynamically allocated port to " -"transfer the actual file data (metadata + payload)." +"A separate TCP connection is established on a dynamically allocated port " +"to transfer the actual file data (metadata + payload)." msgstr "実際のファイル データ (メタデータ + ペイロード) を転送するために、動的に割り当てられたポート上で別の TCP 接続が確立されます。" #: ../../source/File_Transfer/File_Transfer.rst:22 -#: 0e13d1b8b6ef46ce855c8949ef36f219 +#: a0490aac6cc74a8f9de5e9872378b87c #, fuzzy msgid "" -"All file transfers use **stream-oriented reading/writing** with fixed-size " -"chunks (65536 bytes, hardcoded in both directions) to avoid blocking and to " -"handle large files efficiently." +"All file transfers use **stream-oriented reading/writing** with a " +"configurable chunk size (``file_transfer_chunk_len``, 65536 bytes by " +"default, in both directions) to avoid blocking and to handle large files " +"efficiently." msgstr "" "すべてのファイル転送では、ブロッキングを回避し、大きなファイルを効率的に処理するために、固定サイズのチャンク (デフォルトでは 64 KiB) " "を使用した **ストリーム指向の読み取り/書き込み** を使用します。" #: ../../source/File_Transfer/File_Transfer.rst:28 -#: a8c11b500a31468aa10fc4d6537c691c +#: 9ad33f3c1a2e4164b384a71388b895f5 msgid "" -"*Note: For a high-level overview of the server and client classes, please " -"refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" +"*Note: For a high-level overview of the server and client classes, please" +" refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" msgstr "" "*注意: サーバー クラスとクライアント クラスの概要については、:doc:`TCP_Server_APIs` および " ":doc:`TCP_Client_APIs` を参照してください。" #: ../../source/File_Transfer/File_Transfer.rst:35 -#: aeba1deb576440f29ab1d507d38fb22d +#: 2c31714fc81743fa9fbb8701d87347ac msgid "File Transfer Protocol" msgstr "ファイル転送プロトコル" #: ../../source/File_Transfer/File_Transfer.rst:37 -#: a97e5fe0762d4d2d8ffef8527985c9e7 +#: 61af0fc38ea74fcfae8b2a1316d2e6ea msgid "" -"The protocol is symmetric: the same low-level exchange is used regardless of" -" whether the server sends to a client or the client sends to the server. The" -" **initiator** of the transfer (the side that sends the command) also acts " -"as the **sender** of the file data; the other side acts as the **receiver**." +"The protocol is symmetric: the same low-level exchange is used regardless" +" of whether the server sends to a client or the client sends to the " +"server. The **initiator** of the transfer (the side that sends the " +"command) also acts as the **sender** of the file data; the other side " +"acts as the **receiver**." msgstr "" "プロトコルは対称的です。サーバーがクライアントに送信するか、クライアントがサーバーに送信するかに関係なく、同じ低レベルの交換が使用されます。転送の**開始者**" " (コマンドを送信する側) は、ファイル データの**送信者**としても機能します。もう一方は**受信者**として機能します。" #: ../../source/File_Transfer/File_Transfer.rst:46 -#: 1a2e27611ea0452d99cd3e8ac299683c +#: 2ef019fa21e74d26873cb1da802747ac msgid "" "The low-level wire markers are stored in " -"``PyFlow/network_api/decode_command_table.json``, which each instance reads " -"in its constructor and exposes both as ``command_decode_table`` and as " -"individual attributes. The attributes used by the transfer loop are:" +"``PyFlow/network_api/decode_command_table.json``, which each instance " +"reads in its constructor and exposes both as ``command_decode_table`` and" +" as individual attributes. The attributes used by the transfer loop are:" msgstr "" "低レベルのワイヤマーカーは、'' PyFlow/network_api/decode_command_table.json " "''に格納され、各インスタンスはそのコンストラクタで読み取り、'' command_decode_table " "''と個々の属性の両方として公開します。転送ループで使用される属性は次のとおりです。" #: ../../source/File_Transfer/File_Transfer.rst:52 -#: ebc9fc6492964c47b4744d8e2faf6ffd +#: be499b6571974e1a87d5c471578ac79b #, fuzzy msgid "" "``server_start_file_transfer_sign`` — from " "``file_send_server_start_file_transfer`` " "(``/FILE_SEND_SERVER_START_FILE_TRANSFER``), sent by the receiver to the " "sender, indicating that the receiver is ready." -msgstr "" -"``server_start_file_transfer_sign`` - 受信側から送信側に送信され、受信側の準備ができていることを示します。" +msgstr "``server_start_file_transfer_sign`` - 受信側から送信側に送信され、受信側の準備ができていることを示します。" #: ../../source/File_Transfer/File_Transfer.rst:57 -#: d23e35d928494417918b1e9e1810d2e9 +#: 3c9a4f28914742dab2a8175df58f9419 msgid "" "``send_file_header_sign`` / ``send_file_data_sign`` — from " -"``file_send_server_header`` / ``file_send_server_data``; both attributes are" -" set but not referenced by the transfer loop." +"``file_send_server_header`` / ``file_send_server_data``; both attributes " +"are set but not referenced by the transfer loop." msgstr "" "'' send_file_header_sign ''/'' send_file_data_sign '' — '' " "file_send_server_header ''/'' file_send_server_data " "''から。両方の属性は設定されていますが、転送ループによって参照されていません。" #: ../../source/File_Transfer/File_Transfer.rst:60 -#: 07ce10ba9a534d2db23cb3505f3d9ad7 +#: 2035637777a449768450196f0fec1397 msgid "" -"``server_received_file_header_sign`` / ``server_received_file_data_sign`` — " -"from ``file_receive_client_header`` / ``file_receive_client_data``; the " -"header one is sent by the receiver after it has successfully read the " -"filename and file size, the data one after the complete file has been " +"``server_received_file_header_sign`` / ``server_received_file_data_sign``" +" — from ``file_receive_client_header`` / ``file_receive_client_data``; " +"the header one is sent by the receiver after it has successfully read the" +" filename and file size, the data one after the complete file has been " "written to disk." msgstr "" -"'' SERVER_RECEIVED_FILE_HEADER_SIGN ''/'' SERVER_RECEIVED_FILE_DATA_SIGN '' " -"— FILE_RECEIVED_CLIENT_HEADER ''/' FILE_RECEIVE_CLIENT_DATA " +"'' SERVER_RECEIVED_FILE_HEADER_SIGN ''/'' SERVER_RECEIVED_FILE_DATA_SIGN " +"'' — FILE_RECEIVED_CLIENT_HEADER ''/' FILE_RECEIVE_CLIENT_DATA " "''から。ヘッダー1は、ファイル名とファイルサイズの読み取りに成功した後にレシーバーによって送信され、データは完全なファイルがディスクに書き込まれた後に送信されます。" #: ../../source/File_Transfer/File_Transfer.rst:67 -#: a2c795d996c4491e9c90f46871d655b0 +#: 0fc372ae19be49029aa105a95e480640 #, fuzzy msgid "" -"``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by either" -" side when an error occurs, causing the transfer socket to be closed." +"``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by " +"either side when an error occurs, causing the transfer socket to be " +"closed." msgstr "``error_sign`` - エラーが発生したときにどちらかの側から送信され、転送ソケットが閉じられます。" #: ../../source/File_Transfer/File_Transfer.rst:72 -#: b95751f788c044d69f86a067e221a340 +#: 41f6d3d6e0e848bc8f6aecb995223622 msgid "" "The remaining keys of the table cover the other three direction/phase " "combinations. Protocol control lines that are not part of this table " "(``/server_file_transfer_port``, ``/client_alloc_port_range``, " -"``/pause_trans``, ``/start_trans``, ``/forward_item``, ``/forward_upload``, " -"``/forward_error``, ``/crypto_*``) are hardcoded in ``connect_tcp.py``." +"``/pause_trans``, ``/start_trans``, ``/forward_item``, " +"``/forward_upload``, ``/forward_error``, ``/crypto_*``) are hardcoded in " +"``connect_tcp.py``." msgstr "" "表の残りのキーは、他の3つの方向/位相の組み合わせをカバーしています。このテーブルの一部ではないプロトコル制御ライン(''/ " -"server_file_transfer_port ''、''/ client_alloc_port_range ''、''/ pause_trans " -"''、''/ start_trans ''、''/ forward_item ''、''/ forward_upload ''、''/ " -"forward_error ''、''/ crypto _*'')は、'' connect_tcp.py ''にハードコードされています。" +"server_file_transfer_port ''、''/ client_alloc_port_range ''、''/ " +"pause_trans ''、''/ start_trans ''、''/ forward_item ''、''/ forward_upload " +"''、''/ forward_error ''、''/ crypto _*'')は、'' connect_tcp.py " +"''にハードコードされています。" #: ../../source/File_Transfer/File_Transfer.rst:80 -#: c481ce301cdc4dddba6f392dc6de4e6a +#: 45a36aa9239d4caba8752e4dc4fd551b msgid "### Metadata Exchange" msgstr "### メタデータ交換" #: ../../source/File_Transfer/File_Transfer.rst:82 -#: a6fea134d58a457ab825ec59930e0c48 +#: d4ace80bc05f4bafb8144e1de31060dc msgid "" -"The sender performs the following steps after the dedicated file-transfer " -"socket is connected:" +"The sender performs the following steps after the dedicated file-transfer" +" socket is connected:" msgstr "専用のファイル転送ソケットが接続された後、送信者は次の手順を実行します。" #: ../../source/File_Transfer/File_Transfer.rst:86 -#: e18ac26158444f719667794153f422d8 +#: 5df80a71cd274a92975e8d010f564872 msgid "" -"Wait for the receiver's start signal (``server_start_file_transfer_sign``) " -"with a 10-second timeout." +"Wait for the receiver's start signal " +"(``server_start_file_transfer_sign``) with a 10-second timeout." msgstr "受信側の開始信号 (``s​​erver_start_file_transfer_sign``) を 10 秒のタイムアウトで待ちます。" #: ../../source/File_Transfer/File_Transfer.rst:89 -#: fb269796ce6d45cbb73b0201dce1cec9 +#: d68741e000fe48d3857ec0b0363d4182 msgid "Send the filename length as a 4-byte unsigned integer (big-endian)." msgstr "ファイル名の長さを 4 バイトの符号なし整数 (ビッグエンディアン) として送信します。" #: ../../source/File_Transfer/File_Transfer.rst:91 -#: c48725bc3ac54f16bef68243c780831d +#: 95260b76f4524ddb8700ca05352f294d msgid "Send the filename encoded in UTF-8." msgstr "ファイル名をUTF-8でエンコードして送信します。" #: ../../source/File_Transfer/File_Transfer.rst:92 -#: 951751cbb7ab400dbfd8ac2e574d2bf0 +#: 7efa294dbe7e4921974628e8fb08cc00 msgid "Send the file size as an 8-byte unsigned integer (big-endian)." msgstr "ファイル サイズを 8 バイトの符号なし整数 (ビッグ エンディアン) として送信します。" #: ../../source/File_Transfer/File_Transfer.rst:94 -#: db806fd98e8b48dabcd3fa755f1d6567 +#: 065d4ab3bf384d81a22df89aeba09349 #, fuzzy -msgid "Send the file content in 65536-byte chunks until EOF." +msgid "" +"Send the file content in ``file_transfer_chunk_len``-byte chunks (65536 " +"by default) until EOF." msgstr "EOF までファイルの内容を 64 KiB のチャンクで送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:95 -#: 265efb19bd5c46569983bb4156bc195c +#: ../../source/File_Transfer/File_Transfer.rst:96 +#: aeec7f8ff0ab424cbc5b7c1a32ff9433 msgid "" -"Wait for the completion acknowledgement (``server_received_file_data_sign``)" -" with a dynamic timeout (base 30 seconds plus 10 seconds per 100 MiB)." +"Wait for the completion acknowledgement " +"(``server_received_file_data_sign``) with a dynamic timeout (base 30 " +"seconds plus 10 seconds per 100 MiB)." msgstr "" "動的タイムアウト (基本 30 秒 + 100 MiB あたり 10 秒) で完了確認 " "(``s​​erver_received_file_data_sign``) を待ちます。" -#: ../../source/File_Transfer/File_Transfer.rst:100 -#: b2944c94e7a9468daf924f021a5f0bab +#: ../../source/File_Transfer/File_Transfer.rst:101 +#: b80094b922a24c409f10eb9c8b05373b msgid "The receiver performs the complementary steps:" msgstr "受信者は補完的な手順を実行します。" -#: ../../source/File_Transfer/File_Transfer.rst:102 -#: 1353e95158fc496db86676f544168584 +#: ../../source/File_Transfer/File_Transfer.rst:103 +#: 5f71fc707ffe4b06a275b3db9f77178d msgid "Send the start signal." msgstr "スタート信号を送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:103 -#: e32e19b7ac2e4a20a76a7c5640212835 +#: ../../source/File_Transfer/File_Transfer.rst:104 +#: 7132d6fe15ce42a3bef64e0073e9baff msgid "Read the 4-byte length, then the filename, then the 8-byte size." msgstr "4 バイトの長さを読み取り、次にファイル名、次に 8 バイトのサイズを読み取ります。" -#: ../../source/File_Transfer/File_Transfer.rst:105 -#: 1bbea38ba8ec4f84970f408827ba1be4 +#: ../../source/File_Transfer/File_Transfer.rst:106 +#: 7e0fcaec6d704455b94fc9f7defbef55 msgid "Acknowledge the header with ``server_received_file_header_sign``." msgstr "``server_received_file_header_sign`` でヘッダを確認します。" -#: ../../source/File_Transfer/File_Transfer.rst:107 -#: ef7144f2c0c94c9fa25c2a5bad6ed5e8 +#: ../../source/File_Transfer/File_Transfer.rst:108 +#: d6a854d18d404082bdec0e2cf355ea62 msgid "Receive the file data in chunks and write to disk." msgstr "ファイル データをチャンクで受信し、ディスクに書き込みます。" -#: ../../source/File_Transfer/File_Transfer.rst:108 -#: bb81c955e5024b6d9b6042fa3eb4c13f +#: ../../source/File_Transfer/File_Transfer.rst:109 +#: 69981b7e399e4de89858906b286aaf06 msgid "Acknowledge completion with ``server_received_file_data_sign``." msgstr "``server_received_file_data_sign`` で完了を確認します。" -#: ../../source/File_Transfer/File_Transfer.rst:111 -#: cd24d3a3f8704419889c764cf5812a99 +#: ../../source/File_Transfer/File_Transfer.rst:112 +#: b98957309caf49eba2657154bffbaf90 msgid "" "Any error during the exchange causes the failing side to send " -"``error_sign``, and both sides close the transfer socket. The main control " -"connection remains unaffected." -msgstr "" -"交換中にエラーが発生すると、失敗した側が ``error_sign`` を送信し、双方とも転送ソケットを閉じます。メイン制御接続は影響を受けません。" +"``error_sign``, and both sides close the transfer socket. The main " +"control connection remains unaffected." +msgstr "交換中にエラーが発生すると、失敗した側が ``error_sign`` を送信し、双方とも転送ソケットを閉じます。メイン制御接続は影響を受けません。" -#: ../../source/File_Transfer/File_Transfer.rst:120 -#: 0313763b7bc6427cb80da39d09a94be1 +#: ../../source/File_Transfer/File_Transfer.rst:121 +#: f289e3c6e5b445f48eda6ed3434c9de8 msgid "Client-Initiated Transfer (Client → Server)" msgstr "クライアント開始の転送 (クライアント → サーバー)" -#: ../../source/File_Transfer/File_Transfer.rst:122 -#: 155d9f3383cf42fe8fa0e4fe095fbae7 +#: ../../source/File_Transfer/File_Transfer.rst:123 +#: 17e1ddd91efe4690ad00f85f54875eda msgid "" "When the user types a file-related command in the client's interactive " "console, the call chain proceeds as follows." msgstr "ユーザーがクライアントの対話型コンソールにファイル関連のコマンドを入力すると、呼び出しチェーンは次のように進行します。" -#: ../../source/File_Transfer/File_Transfer.rst:126 -#: ab7df52a36c742a0be4924b613ddebd4 +#: ../../source/File_Transfer/File_Transfer.rst:127 +#: 9cacd6ea79a14ff6ae602d7ed47926c8 msgid "### Console Input Handling" msgstr "### コンソール入力の処理" -#: ../../source/File_Transfer/File_Transfer.rst:128 -#: 42cde8d25ccd4424b5c871c7adf3af91 +#: ../../source/File_Transfer/File_Transfer.rst:129 +#: 07a7b69b45d04950877f071f25ad7c2c #, fuzzy msgid "" -"In ``TCP_Client_Base.interactive_mode()``, user input is read line by line. " -"Commands starting with ``/file``, ``/multiple_file``, ``/file_folder``, or " -"``/multiple_file_folder`` are recognised. For each such command, the client " -"calls the corresponding entry point described below." +"In ``TCP_Client_Base.interactive_mode()``, user input is read line by " +"line. Commands starting with ``/file``, ``/multiple_file``, " +"``/file_folder``, or ``/multiple_file_folder`` are recognised. For each " +"such command, the client calls the corresponding entry point described " +"below." msgstr "" "``TCP_Client_Base.interactive_mode()`` では、ユーザー入力が 1 行ずつ読み取られます。 " -"``/file``、``/multiple_file``、``/file_folder``、または ``/multiple_file_folder`` " +"``/file``、``/multiple_file``、``/file_folder``、または " +"``/multiple_file_folder`` " "で始まるコマンドが認識されます。このようなコマンドごとに、クライアントは対応するスレッドセーフなエントリ ポイント (``_thread`` " "で終わるメソッド) を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:136 -#: 08d0c910eba54d3cb8447d3cea15064f +#: ../../source/File_Transfer/File_Transfer.rst:137 +#: 250bb94df2a14d339b150a70e8fed215 #, fuzzy msgid "### Entry Points" msgstr "### スレッドセーフなエントリ ポイント" -#: ../../source/File_Transfer/File_Transfer.rst:138 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:139 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "The console dispatches to these methods:" msgstr "コンソールは、次のメソッドにディスパッチします。" -#: ../../source/File_Transfer/File_Transfer.rst:140 -#: 3ddbfd1b9e454342aa47f388d5bc7263 +#: ../../source/File_Transfer/File_Transfer.rst:141 +#: a0f0599853724ff9a15c501c154f52ea #, fuzzy msgid "" "``file_transfer_client_recv_client_start_thread(message, " @@ -300,40 +309,40 @@ msgstr "" "「file_transfer_client_recv_client_start_thread(message, " "file_folder_abspath=None)」" -#: ../../source/File_Transfer/File_Transfer.rst:143 -#: 4db440e1419b4ce895c7e03b85b070c1 +#: ../../source/File_Transfer/File_Transfer.rst:144 +#: 9d60213404014fbe8bee542f67d80398 msgid "``folder_file_transfer_client_recv_client_start(message)``" msgstr "``folder_file_transfer_client_recv_client_start(message)``" -#: ../../source/File_Transfer/File_Transfer.rst:144 -#: 936c7a26041045da8e4e20ec45d3959d +#: ../../source/File_Transfer/File_Transfer.rst:145 +#: 2e6c7b2b820349ebac90f27d835477d0 msgid "``multiple_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_file_transfer_client_recv_client_start(message)``" -#: ../../source/File_Transfer/File_Transfer.rst:145 -#: 972ecc6300354468b126961a483ecf2c +#: ../../source/File_Transfer/File_Transfer.rst:146 +#: bdee0e9084194b45b5fad3a44e9aaf85 msgid "``multiple_folder_file_transfer_client_recv_client_start(message)``" msgstr "「multiple_folder_file_transfer_client_recv_client_start(message)」" -#: ../../source/File_Transfer/File_Transfer.rst:147 -#: fef1e1b2a2024f89abd300268004380d +#: ../../source/File_Transfer/File_Transfer.rst:148 +#: ae9108b44e304198a7d0bff6bae8ab60 msgid "" -"The last three run synchronously on the console thread; they walk the tree " -"or the file list and spawn one worker thread per file themselves, so the " -"console keeps reading input while the transfers run. Every worker holds " -"``file_semaphore`` for the whole transfer, so at most ``max_thread_num`` of " -"them run at once." +"The last three run synchronously on the console thread; they walk the " +"tree or the file list and spawn one worker thread per file themselves, so" +" the console keeps reading input while the transfers run. Every worker " +"holds ``file_semaphore`` for the whole transfer, so at most " +"``max_thread_num`` of them run at once." msgstr "" "最後の3つはコンソールスレッドで同期して実行されます。ツリーまたはファイルリストを移動し、ファイルごとに1つのワーカースレッドを生成するため、転送が実行されている間、コンソールは入力を読み続けます。すべてのワーカーは、転送全体に対して''" " file_semaphore ''を保持しているため、最大'' max_thread_num ''が一度に実行されます。" -#: ../../source/File_Transfer/File_Transfer.rst:153 -#: f5919b72c7ec40e2a1b1d49cf57c9021 +#: ../../source/File_Transfer/File_Transfer.rst:154 +#: 8e945e4bdc124e749ee0a5976249a787 msgid "### Worker Function (Client Side)" msgstr "### ワーカー関数 (クライアント側)" -#: ../../source/File_Transfer/File_Transfer.rst:155 -#: 70bed6a3ccbd47e89653ab1b2d62fb9d +#: ../../source/File_Transfer/File_Transfer.rst:156 +#: cc8b9fc35bfb4cf395a2114786c01718 msgid "" "The core worker function for a single file is " "``file_transfer_client_recv_client_start(message, " @@ -342,30 +351,30 @@ msgstr "" "単一ファイルのコアワーカー関数は「file_transfer_client_recv_client_start(message, " "file_folder_abspath=None)」です。そのロジックは次のとおりです。" -#: ../../source/File_Transfer/File_Transfer.rst:160 -#: f7103ca89460442ba018095bf48ae23c +#: ../../source/File_Transfer/File_Transfer.rst:161 +#: e3d81c4f4e724d81b426fdbfedb9c062 msgid "Allocate a unique client ID using the lock ``file_client_id_lock``." msgstr "ロック ``file_client_id_lock`` を使用して一意のクライアント ID を割り当てます。" -#: ../../source/File_Transfer/File_Transfer.rst:162 -#: ea5fe1051d864a3caccc15bf2373b03e +#: ../../source/File_Transfer/File_Transfer.rst:163 +#: 81b9ac67e27341c0a17468f3b6787d14 msgid "" "Extend the original command string with the client ID (e.g., ``/file " -"mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server over " -"the main control connection using ``send_message()``." +"mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server " +"over the main control connection using ``send_message()``." msgstr "" -"元のコマンド文字列をクライアント ID で拡張し (例: ``/file mydoc.txt`` は ``/file mydoc.txt 42`` " -"になります)、``send_message()`` を使用してメイン制御接続経由でサーバーに送信します。" +"元のコマンド文字列をクライアント ID で拡張し (例: ``/file mydoc.txt`` は ``/file mydoc.txt 42``" +" になります)、``send_message()`` を使用してメイン制御接続経由でサーバーに送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:168 -#: b56d7f67a1844b0cb893a3939ed8ed70 +#: ../../source/File_Transfer/File_Transfer.rst:169 +#: af07c5ef546a4102bbb836b65b2fd3be msgid "" "Obtain a local port for the outgoing file transfer socket by calling " "``palloc()``." msgstr "``palloc()`` を呼び出して、送信ファイル転送ソケットのローカルポートを取得します。" -#: ../../source/File_Transfer/File_Transfer.rst:171 -#: 83314b464667496cb415f119beb0dc31 +#: ../../source/File_Transfer/File_Transfer.rst:172 +#: 37226a4f2e1e4a878ba325fca05df9bf msgid "" "Wait (up to 20 seconds) for the server to reply with a port number. The " "server's reply (``/server_file_transfer_port ``) is " @@ -376,91 +385,92 @@ msgstr "" " ``) はメイン接続によって受信され、``file_server_port_list`` " "に保存されます。一致するエントリが見つかると、ポートが抽出されます。" -#: ../../source/File_Transfer/File_Transfer.rst:179 -#: bd938c291cbe44aa913d35413fc76a6b +#: ../../source/File_Transfer/File_Transfer.rst:180 +#: e9cd68239fe3498597f07ccfa774ae22 msgid "" -"Call the low-level send function ``file_transfer_mode(filename, server_host," -" server_port, client_port)``." -msgstr "" -"低レベルの送信関数「file_transfer_mode(filename,server_host,server_port,client_port)」を呼び出します。" +"Call the low-level send function ``file_transfer_mode(filename, " +"server_host, server_port, client_port)``." +msgstr "低レベルの送信関数「file_transfer_mode(filename,server_host,server_port,client_port)」を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:183 -#: 75779fa321754e05adc2ee87ac490f07 +#: ../../source/File_Transfer/File_Transfer.rst:184 +#: 145c524c53654e84a0bb45d3a065733e #, fuzzy msgid "" "For folder transfers, the worker function " "``folder_file_transfer_client_recv_client_start(message)`` walks the " "directory tree on the console thread. It first sends a ``/file_folder " "`` command for the top-level folder itself to create the " -"corresponding directory on the server, then sends the same command for every" -" subdirectory it walks into. For each file, it starts a daemon thread that " -"holds ``file_semaphore`` around the actual transfer, with a command of the " -"form ``/file_folder ``, so the number of " -"concurrent file transfers is limited to ``max_thread_num``." -msgstr "" -"フォルダー転送の場合、ワーカー関数 ``folder_file_transfer_client_recv_client_start(message)``" -" はディレクトリ ツリーを再帰的に移動します。各サブディレクトリ (最上位を除く) に対して、メイン接続を介して ``/file_folder " +"corresponding directory on the server, then sends the same command for " +"every subdirectory it walks into. For each file, it starts a daemon " +"thread that holds ``file_semaphore`` around the actual transfer, with a " +"command of the form ``/file_folder ``, so the " +"number of concurrent file transfers is limited to ``max_thread_num``." +msgstr "" +"フォルダー転送の場合、ワーカー関数 " +"``folder_file_transfer_client_recv_client_start(message)`` はディレクトリ " +"ツリーを再帰的に移動します。各サブディレクトリ (最上位を除く) に対して、メイン接続を介して ``/file_folder " "`` コマンドを送信し、サーバー上に対応するディレクトリを作成します。ファイルごとに、「/file_folder " " " "」形式のコマンドで「file_transfer_client_recv_client_start_thread」を呼び出します。セマフォ" " (``file_semaphore``) は、同時ファイル転送の数を ``max_thread_num`` に制限します。" -#: ../../source/File_Transfer/File_Transfer.rst:198 -#: bbb76713d93e4920a87d1551cbdf9999 +#: ../../source/File_Transfer/File_Transfer.rst:199 +#: 5a7d502137c8442eafae448cee95a72a msgid "" "``multiple_file_transfer_client_recv_client_start`` loops over the given " -"files and starts one worker thread per file, each holding ``file_semaphore``" -" around its own transfer, so the concurrent transfers are capped by " -"``max_thread_num`` on that path too." +"files and starts one worker thread per file, each holding " +"``file_semaphore`` around its own transfer, so the concurrent transfers " +"are capped by ``max_thread_num`` on that path too." msgstr "" "'' multiple_file_transfer_client_recv_client_start " "''は、指定されたファイルをループし、ファイルごとに1つのワーカースレッドを開始します。各ワーカースレッドは、独自の転送の周りに'' " "file_semaphore ''を保持しているため、同時転送もそのパスの'' max_thread_num ''で制限されます。" -#: ../../source/File_Transfer/File_Transfer.rst:203 -#: d9634b910f4f4509a717a6e7cb8445e2 +#: ../../source/File_Transfer/File_Transfer.rst:204 +#: 4ae4777e086a48558cbe3dda0ecdb3fb msgid "### Server-Side Handler (Receiving)" msgstr "### サーバー側ハンドラー (受信)" -#: ../../source/File_Transfer/File_Transfer.rst:205 -#: ecf51220b2924da78e59cd7118a5d976 +#: ../../source/File_Transfer/File_Transfer.rst:206 +#: 66a812ac1ac84ad2b912deb843f3c059 msgid "" -"When the server receives an extended command like ``/file mydoc.txt 42`` on " -"the main control connection, ``handle_command`` detects it and calls:" +"When the server receives an extended command like ``/file mydoc.txt 42`` " +"on the main control connection, ``handle_command`` detects it and calls:" msgstr "" -"サーバーがメイン制御接続上で ``/file mydoc.txt 42`` のような拡張コマンドを受信すると、 ``handle_command`` " -"がそれを検出して以下を呼び出します。" +"サーバーがメイン制御接続上で ``/file mydoc.txt 42`` のような拡張コマンドを受信すると、 " +"``handle_command`` がそれを検出して以下を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:210 -#: 7437faffb1f7433faaea35c296c7ab96 +#: ../../source/File_Transfer/File_Transfer.rst:211 +#: 081e020d3e674d01bfde15c0922aa25c msgid "" -"``file_transfer_server_recv_server_start_thread(client_id, client_socket, " -"command)``" +"``file_transfer_server_recv_server_start_thread(client_id, client_socket," +" command)``" msgstr "" "「file_transfer_server_recv_server_start_thread(client_id, client_socket, " "command)」" -#: ../../source/File_Transfer/File_Transfer.rst:213 -#: 1ff4d8b0423b490db4a9b179d745dcb7 +#: ../../source/File_Transfer/File_Transfer.rst:214 +#: 4b5b5057002a457db83aed00c6148a7f msgid "The server then:" msgstr "するとサーバーは次のようになります。" -#: ../../source/File_Transfer/File_Transfer.rst:215 -#: 988de890b2fc4ebfbe68944b368ce5b8 +#: ../../source/File_Transfer/File_Transfer.rst:216 +#: e2ad0e97b7854be4a3dded6cf7d602b7 msgid "" -"Creates a new thread via ``file_transfer_server_recv_server_start(client_id," -" client_socket, command, new_save_path=None, file_name=None)``." +"Creates a new thread via " +"``file_transfer_server_recv_server_start(client_id, client_socket, " +"command, new_save_path=None, file_name=None)``." msgstr "" -"「file_transfer_server_recv_server_start(client_id, client_socket, command, " -"new_save_path=None, file_name=None)」により新しいスレッドを作成します。" +"「file_transfer_server_recv_server_start(client_id, client_socket, " +"command, new_save_path=None, file_name=None)」により新しいスレッドを作成します。" -#: ../../source/File_Transfer/File_Transfer.rst:219 -#: 47e1493ecf784674924778f581e6a71a +#: ../../source/File_Transfer/File_Transfer.rst:220 +#: ee8cdc9ae93c4579a05e37b32c86f705 msgid "Allocates a transfer port with ``palloc()``." msgstr "``palloc()`` で転送ポートを割り当てます。" -#: ../../source/File_Transfer/File_Transfer.rst:220 -#: b19bd45b30ee42178dab7b9aafa79e5e +#: ../../source/File_Transfer/File_Transfer.rst:221 +#: ac8a87e1e481417284d90ba8cb843415 msgid "" "Calls ``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``." @@ -468,15 +478,15 @@ msgstr "" "「file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)」を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:223 -#: a2f55cc995c14ec1ac34545e458dccb2 +#: ../../source/File_Transfer/File_Transfer.rst:224 +#: 2f6675b7698c41938542b09cbfb482e8 msgid "" -"This low-level receive function sets up a listening socket on the allocated " -"port, sends the port number back to the client (as " +"This low-level receive function sets up a listening socket on the " +"allocated port, sends the port number back to the client (as " "``/server_file_transfer_port ``), accepts the client's " "connection, and performs the protocol steps described in :ref:`file-" -"transfer-protocol`. The received file is saved under ``received_files/`` (or" -" a subdirectory if a folder transfer was requested)." +"transfer-protocol`. The received file is saved under ``received_files/`` " +"(or a subdirectory if a folder transfer was requested)." msgstr "" "この低レベルの受信関数は、割り当てられたポート上で待機ソケットを設定し、ポート番号をクライアントに送り返し " "(``/server_file_transfer_port `` " @@ -484,20 +494,20 @@ msgstr "" "で説明されているプロトコル手順を実行します。受信したファイルは ``received_files/'' " "(フォルダ転送が要求された場合はサブディレクトリ) に保存されます。" -#: ../../source/File_Transfer/File_Transfer.rst:233 -#: da7e5a1f96b3422bbfd8f056eb28dae3 +#: ../../source/File_Transfer/File_Transfer.rst:234 +#: 9fe861572b8746aeaa8266d8d30f963f msgid "" "After the transfer completes (or fails), the port is released with " "``pfree()``." msgstr "転送が完了(または失敗)すると、ポートは ``pfree()`` で解放されます。" -#: ../../source/File_Transfer/File_Transfer.rst:240 -#: e9956de8dffe4d898caed46c0e78c93b +#: ../../source/File_Transfer/File_Transfer.rst:241 +#: 3e4e81fa8cea4ef5ab2a39602eb29355 msgid "Server-Initiated Transfer (Server → Client)" msgstr "サーバー開始の転送 (サーバー → クライアント)" -#: ../../source/File_Transfer/File_Transfer.rst:242 -#: 5e8dbd4b351d467cb809c3182feac0a2 +#: ../../source/File_Transfer/File_Transfer.rst:243 +#: 3ab21d4beefb41be83651eec10fd3899 msgid "" "When the server administrator types a command in the server console, for " "example ``/file /path/to/file.txt (127.0.0.1,54321)``, the console input " @@ -508,13 +518,13 @@ msgstr "" "(127.0.0.1,54321)」を入力すると、コンソール入力スレッド (``console_input``) " "がコマンドを解析し、適切なサーバー側ファイル転送 API を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:250 -#: 3bec81e76a2c4bf3b37386e180cc4fc1 +#: ../../source/File_Transfer/File_Transfer.rst:251 +#: fa019410dca84c04b24bf9334131aa8d msgid "The recommended entry points for server-to-client transfers are:" msgstr "サーバーからクライアントへの転送に推奨されるエントリ ポイントは次のとおりです。" -#: ../../source/File_Transfer/File_Transfer.rst:253 -#: 585d149b4b3f47f09176b4b61d3baeaa +#: ../../source/File_Transfer/File_Transfer.rst:254 +#: 99103b4e1f234e2dac2ffc955ab5b23e msgid "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` for a single file." @@ -522,30 +532,27 @@ msgstr "" "単一ファイルの場合は「file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)」。" -#: ../../source/File_Transfer/File_Transfer.rst:256 -#: 81935504645c451b844d109037b46ae0 -msgid "" -"``folder_file_transfer_server_recv_client_start(message)`` for a folder." +#: ../../source/File_Transfer/File_Transfer.rst:257 +#: a1560a9b45c043618778f38beb1c3cb2 +msgid "``folder_file_transfer_server_recv_client_start(message)`` for a folder." msgstr "フォルダーの「folder_file_transfer_server_recv_client_start(message)」。" -#: ../../source/File_Transfer/File_Transfer.rst:258 -#: 4ca3cac907c04414925f5219b700d0e5 +#: ../../source/File_Transfer/File_Transfer.rst:259 +#: c18cb827a52f48d6b2883b708e2c871e msgid "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " for multiple files to multiple clients." -msgstr "" -"複数のファイルを複数のクライアントに送信する場合は、「multiple_file_multiple_client_transfer_server_recv_client_start(message)」を使用します。" +msgstr "複数のファイルを複数のクライアントに送信する場合は、「multiple_file_multiple_client_transfer_server_recv_client_start(message)」を使用します。" -#: ../../source/File_Transfer/File_Transfer.rst:260 -#: 536f30cc03f84b218a5ca9b84deb9f88 +#: ../../source/File_Transfer/File_Transfer.rst:261 +#: 1b9fd8eea75e46899f68c6ca1312e896 msgid "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " for different file lists to different clients." -msgstr "" -"異なるファイルリストを異なるクライアントに送信するには、「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)」を使用します。" +msgstr "異なるファイルリストを異なるクライアントに送信するには、「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)」を使用します。" -#: ../../source/File_Transfer/File_Transfer.rst:263 -#: 92500d9fd7124d9ca7b648f03df90141 +#: ../../source/File_Transfer/File_Transfer.rst:264 +#: d34ac75777c74fe4bc63e1a100fd2aa3 msgid "" "The worker function ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` performs the following steps:" @@ -553,57 +560,58 @@ msgstr "" "ワーカー関数 ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` は次の手順を実行します。" -#: ../../source/File_Transfer/File_Transfer.rst:268 -#: 583e8c89824f46ae839d233ab9e70e1a +#: ../../source/File_Transfer/File_Transfer.rst:269 +#: 29d03e172fd346e2a7928b55510df4f1 msgid "" -"Extract the target client address from the last part of the command (e.g., " -"``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the client's " -"socket from ``self.clients``." +"Extract the target client address from the last part of the command " +"(e.g., ``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the " +"client's socket from ``self.clients``." msgstr "" -"``ast.literal_eval()`` を使用して、コマンドの最後の部分 (例: ``(127.0.0.1,54321)``) からターゲット " -"クライアント アドレスを抽出します。クライアントのソケットを ``self.clients`` から取得します。" +"``ast.literal_eval()`` を使用して、コマンドの最後の部分 (例: ``(127.0.0.1,54321)``) " +"からターゲット クライアント アドレスを抽出します。クライアントのソケットを ``self.clients`` から取得します。" -#: ../../source/File_Transfer/File_Transfer.rst:273 -#: fd63ce90d3794b2181cdaa927e1a7a38 +#: ../../source/File_Transfer/File_Transfer.rst:274 +#: 7a8d8ed423524d6e91a311a3aa3d5a9a msgid "" -"Allocate a unique client ID and extend the command with it, then send the " -"extended command to the client over the main connection." +"Allocate a unique client ID and extend the command with it, then send the" +" extended command to the client over the main connection." msgstr "一意のクライアント ID を割り当て、それを使用してコマンドを拡張し、メイン接続を介して拡張コマンドをクライアントに送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:277 -#: 6138738f134b48b2a98d05d3569172c7 +#: ../../source/File_Transfer/File_Transfer.rst:278 +#: 94b6c1f8a6a240e4ba4be8cf20f87c7f msgid "Allocate a local port with ``palloc()``." msgstr "``palloc()`` でローカルポートを割り当てます。" -#: ../../source/File_Transfer/File_Transfer.rst:278 -#: 26fa94f94e1841f6845765f4fd65949d +#: ../../source/File_Transfer/File_Transfer.rst:279 +#: 723a05b6c3974b65a539af723f1e0872 msgid "" "Wait for the client to reply with its own port number (via " "``/server_file_transfer_port``), which is stored in " "``file_server_port_list`` by the main connection's message handler." msgstr "" "クライアントが独自のポート番号 (`/server_file_transfer_port` 経由) " -"で応答するのを待ちます。このポート番号は、メイン接続のメッセージ ハンドラーによって `file_server_port_list` に保存されます。" +"で応答するのを待ちます。このポート番号は、メイン接続のメッセージ ハンドラーによって `file_server_port_list` " +"に保存されます。" -#: ../../source/File_Transfer/File_Transfer.rst:283 -#: 4bd913210d8945ffb7312070e070f252 +#: ../../source/File_Transfer/File_Transfer.rst:284 +#: 878572ca3d2948a9acbb6741f00ddd62 msgid "" -"Call ``file_transfer_mode(filename, client_host, client_port, local_port)`` " -"to send the file." +"Call ``file_transfer_mode(filename, client_host, client_port, " +"local_port)`` to send the file." msgstr "" "ファイルを送信するには、「file_transfer_mode(filename, client_host, client_port, " "local_port)」を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:287 -#: 39d0bdae658241a0a8205977cccd0395 +#: ../../source/File_Transfer/File_Transfer.rst:288 +#: ca517571b2d34c0497fcf5d5b12c93a1 msgid "" "On the client side, when it receives a command like ``/file " -"/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls " -"``file_transfer_client_recv_server_start_thread(client_id, client_socket, " -"command)``. This starts a receiver thread analogous to the server's receiver" -" for client-initiated transfers: it allocates a port, replies with " -"``/server_file_transfer_port``, and calls ``file_transfer_mode_recv`` to " -"receive and save the file." +"/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls" +" ``file_transfer_client_recv_server_start_thread(client_id, " +"client_socket, command)``. This starts a receiver thread analogous to the" +" server's receiver for client-initiated transfers: it allocates a port, " +"replies with ``/server_file_transfer_port``, and calls " +"``file_transfer_mode_recv`` to receive and save the file." msgstr "" "クライアント側では、「/file /path/to/file.txt (127.0.0.1,54321) " "42」のようなコマンドを受け取ると、「handle_server_command」が「file_transfer_client_recv_server_start_thread(client_id," @@ -611,69 +619,68 @@ msgstr "" "command)」を呼び出します。これにより、クライアントが開始した転送用のサーバーのレシーバーに似たレシーバースレッドが開始されます。レシーバースレッドはポートを割り当て、`/server_file_transfer_port`" " で応答し、ファイルを受信して​​保存するために `file_transfer_mode_recv` を呼び出します。" -#: ../../source/File_Transfer/File_Transfer.rst:303 -#: 014166967bb14b20a2782598b535575a +#: ../../source/File_Transfer/File_Transfer.rst:304 +#: cb7bdf5091e54e039de9d5578c273b93 msgid "Folder Transfer Mechanism (Detailed)" msgstr "フォルダー転送の仕組み(詳細)" -#: ../../source/File_Transfer/File_Transfer.rst:305 -#: 38eff5e62e844c0e94d587ba7132d26c +#: ../../source/File_Transfer/File_Transfer.rst:306 +#: b282df0b45bd4bb087ae10816fd3f06d msgid "" "Transferring a folder is implemented as a **recursive walk** that sends " -"separate commands for subdirectories and files. The logic is symmetric on " -"both client and server." -msgstr "" -"フォルダーの転送は、サブディレクトリとファイルに個別のコマンドを送信する**再帰ウォーク**として実装されます。ロジックはクライアントとサーバーの両方で対称です。" +"separate commands for subdirectories and files. The logic is symmetric on" +" both client and server." +msgstr "フォルダーの転送は、サブディレクトリとファイルに個別のコマンドを送信する**再帰ウォーク**として実装されます。ロジックはクライアントとサーバーの両方で対称です。" -#: ../../source/File_Transfer/File_Transfer.rst:311 -#: 7319cca2fbef48679002d3bf0469d842 +#: ../../source/File_Transfer/File_Transfer.rst:312 +#: fb34b1f5d8a4488b9aef8b71dcb764ec msgid "### Creating Directories" msgstr "### ディレクトリの作成" -#: ../../source/File_Transfer/File_Transfer.rst:313 -#: ad592f4510c34ecca1cba340caa2710e +#: ../../source/File_Transfer/File_Transfer.rst:314 +#: 6b67f2390d914745a253523cef9a2e0b msgid "" -"For a directory that needs to be created on the receiver side, the sender " -"sends a command of the form:" +"For a directory that needs to be created on the receiver side, the sender" +" sends a command of the form:" msgstr "受信側でディレクトリを作成する必要がある場合、送信側は次の形式のコマンドを送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:317 -#: 114e36ce42e940cc8f0ec8c64c1db031 +#: ../../source/File_Transfer/File_Transfer.rst:318 +#: 7aaf85bf38fa4621a760dc56b6f99ad6 msgid "``/file_folder ``" msgstr "``/file_folder <相対パス>``" -#: ../../source/File_Transfer/File_Transfer.rst:319 -#: a120552b93294a059a34132ab935068a +#: ../../source/File_Transfer/File_Transfer.rst:320 +#: 046f125a1f6e41e4808a9cd703e34ee4 msgid "" "The receiver's handler for this command (in either " "``file_folder_transfer_server_recv_server_start_thread`` or " "``file_folder_transfer_client_recv_server_start_thread``) creates the " "corresponding directory under the base receive directory " -"(``received_files/`` for the server, the same directory for the client). The" -" relative path uses forward slashes to be platform-independent." +"(``received_files/`` for the server, the same directory for the client). " +"The relative path uses forward slashes to be platform-independent." msgstr "" -"このコマンドの受信側ハンドラ (``file_folder_transfer_server_recv_server_start_thread`` または" -" ``file_folder_transfer_client_recv_server_start_thread``) は、ベース受信ディレクトリ " -"(サーバの場合は ``received_files/``、クライアントの場合は同じディレクトリ) " +"このコマンドの受信側ハンドラ (``file_folder_transfer_server_recv_server_start_thread`` " +"または ``file_folder_transfer_client_recv_server_start_thread``) " +"は、ベース受信ディレクトリ (サーバの場合は ``received_files/``、クライアントの場合は同じディレクトリ) " "の下に対応するディレクトリを作成します。相対パスではプラットフォームに依存しないようにスラッシュを使用します。" -#: ../../source/File_Transfer/File_Transfer.rst:330 -#: 2743fec0a2434e2b96ea3c49fecf268c +#: ../../source/File_Transfer/File_Transfer.rst:331 +#: 3fb5d6322ccd47f79e601e38684fe234 msgid "### Sending Files Inside a Folder" msgstr "### フォルダー内のファイルを送信する" -#: ../../source/File_Transfer/File_Transfer.rst:332 -#: fb31b657a05547109dea51165844a632 +#: ../../source/File_Transfer/File_Transfer.rst:333 +#: c9f77546ed49407fa57c57f0b0a76acf msgid "For each file, the sender sends a command of the form:" msgstr "ファイルごとに、送信者は次の形式のコマンドを送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:334 -#: 2da676ce8dd649169ba224f6d29cbbc9 +#: ../../source/File_Transfer/File_Transfer.rst:335 +#: f5a164466b0d4d4382b7d880bd320e3d msgid "``/file_folder ``" msgstr "``/file_folder <相対パス> <ファイル名>``" -#: ../../source/File_Transfer/File_Transfer.rst:336 -#: 8972f356722148e3b34cbaa95390d700 +#: ../../source/File_Transfer/File_Transfer.rst:337 +#: c507cca92d1c463ea9f4d429a38a9b6a msgid "" "The receiver treats this as a file transfer request. The second argument " "(``file_name``) is used as the final filename, and the relative path " @@ -687,108 +694,107 @@ msgstr "" " (方向に応じて ``file_transfer_client_recv_client_start`` または " "``file_transfer_server_recv_client_start`` 経由)。" -#: ../../source/File_Transfer/File_Transfer.rst:347 -#: a0ded05fd7f2406abb0ee41fcc33b53b +#: ../../source/File_Transfer/File_Transfer.rst:348 +#: e1e2b8dd57524ecfabd47c2c8386dfea msgid "### Concurrency Control for Folders" msgstr "### フォルダーの同時実行制御" -#: ../../source/File_Transfer/File_Transfer.rst:349 -#: 14b0ec4d109c448198db41c196df8a70 +#: ../../source/File_Transfer/File_Transfer.rst:350 +#: 32b26f72bba4482490f38968dcee5837 msgid "" "Because a folder can contain many files, the sender uses a semaphore " "(``file_semaphore``) to limit the number of concurrently active file " -"transfers. The semaphore is acquired before starting each file transfer and " -"released in a ``finally`` block. The maximum concurrency is set by " -"``max_thread_num`` on the client and ``max_file_transfer_thread_num`` on the" -" server." +"transfers. The semaphore is acquired before starting each file transfer " +"and released in a ``finally`` block. The maximum concurrency is set by " +"``max_thread_num`` on the client and ``max_file_transfer_thread_num`` on " +"the server." msgstr "" "フォルダには多数のファイルを含めることができるため、送信者はセマフォ (``file_semaphore``) " "を使用して、同時にアクティブになるファイル転送の数を制限します。セマフォは各ファイル転送を開始する前に取得され、「finally」ブロックで解放されます。最大同時実行数は、クライアントでは" " ``max_thread_num`` 、サーバーでは ``max_file_transfer_thread_num`` によって設定されます。" -#: ../../source/File_Transfer/File_Transfer.rst:362 -#: 2c7d84b855df4587bfb110f525299e39 +#: ../../source/File_Transfer/File_Transfer.rst:363 +#: 8ce424a7f1de4933b3113a0e3ab98155 msgid "Custom Destination Directory" msgstr "カスタム宛先ディレクトリ" -#: ../../source/File_Transfer/File_Transfer.rst:364 -#: b972e019f10143a99af9de9b7a8e371a +#: ../../source/File_Transfer/File_Transfer.rst:365 +#: 6ca8ee9f021842939f446e999c067dfb msgid "" -"Every transfer family accepts an optional trailing ``destination_file_path``" -" argument that replaces the receiver's default save directory " -"(``received_files/`` or the configured ``file_transfer_dir``). When it is " -"omitted, the transfer goes to the default location exactly as before." +"Every transfer family accepts an optional trailing " +"``destination_file_path`` argument that replaces the receiver's default " +"save directory (``received_files/`` or the configured " +"``file_transfer_dir``). When it is omitted, the transfer goes to the " +"default location exactly as before." msgstr "" "すべての転送ファミリーは、受信側のデフォルトの保存ディレクトリ (``received_files/`` または設定された " "``file_transfer_dir``) を置き換えるオプションの末尾の ``destination_file_path`` " "引数を受け入れます。省略すると、以前と同様にデフォルトの場所に転送されます。" -#: ../../source/File_Transfer/File_Transfer.rst:372 -#: 1e801c2a599e4595b5f883ada1a63fc6 +#: ../../source/File_Transfer/File_Transfer.rst:373 +#: 6291da89ffa542dfbd94f599a9321216 msgid "" -"The destination is **always the last argument** of the command and names a " -"*directory* on the receiving machine: the received file keeps its own name " -"(``/``), and a transferred folder keeps its structure" -" under the destination (``//...`` ). An absolute " -"path is used as-is; a relative path is resolved under the default save " -"directory. Missing directories are created." -msgstr "" -"宛先は**常にコマンドの最後の引数**で、受信側マシン上の*ディレクトリ*に名前を付けます。受信したファイルはそれ自体の名前(``<宛先>/<ファイル名>``)を保持し、転送されたフォルダは宛先の下にその構造を保持します(``<宛先>/<フォルダ名>/...``)。絶対パスはそのまま使用されます。相対パスはデフォルトの保存ディレクトリの下で解決されます。不足しているディレクトリが作成されます。" +"The destination is **always the last argument** of the command and names " +"a *directory* on the receiving machine: the received file keeps its own " +"name (``/``), and a transferred folder keeps its " +"structure under the destination (``//...`` ). " +"An absolute path is used as-is; a relative path is resolved under the " +"default save directory. Missing directories are created." +msgstr "宛先は**常にコマンドの最後の引数**で、受信側マシン上の*ディレクトリ*に名前を付けます。受信したファイルはそれ自体の名前(``<宛先>/<ファイル名>``)を保持し、転送されたフォルダは宛先の下にその構造を保持します(``<宛先>/<フォルダ名>/...``)。絶対パスはそのまま使用されます。相対パスはデフォルトの保存ディレクトリの下で解決されます。不足しているディレクトリが作成されます。" -#: ../../source/File_Transfer/File_Transfer.rst:384 -#: 6b85151737b64a3e90154ba763b205d2 +#: ../../source/File_Transfer/File_Transfer.rst:385 +#: 76243e0349c1474bbdf14e1ef2a8e52b msgid "Command syntax:" msgstr "コマンド構文:" -#: ../../source/File_Transfer/File_Transfer.rst:386 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:387 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "Client console (the receiver is the server):" msgstr "クライアント コンソール (受信者はサーバー):" -#: ../../source/File_Transfer/File_Transfer.rst:388 -#: bac62d5b11c84f96b2b3841af7fc7a85 +#: ../../source/File_Transfer/File_Transfer.rst:389 +#: c9fa612895bc4f92839d2de77b6cbc7f msgid "``/file [destination_file_path]``" msgstr "``/file <ファイルパス> [保存先ファイルパス]``" -#: ../../source/File_Transfer/File_Transfer.rst:390 -#: aa07623d0b4048be944b30c6fc07cc1b +#: ../../source/File_Transfer/File_Transfer.rst:391 +#: 2d34a030a1804d299a0b56c14984b1b5 msgid "``/multiple_file ... [destination_file_path]``" msgstr "``/multiple_file <ファイル 1> <ファイル 2> ... [宛先ファイルのパス]``" -#: ../../source/File_Transfer/File_Transfer.rst:392 -#: 1a9cfb266bb24df6ac2ddeb286a212d0 +#: ../../source/File_Transfer/File_Transfer.rst:393 +#: a7dd1e241a4346d4b873072c5948f187 #, fuzzy msgid "``/file_folder [destination_file_path]``" msgstr "``/file_folder <相対パス>``" -#: ../../source/File_Transfer/File_Transfer.rst:394 -#: 46f89a56ef594dec945f21425306e2de -msgid "" -"``/multiple_file_folder ... [destination_file_path]``" +#: ../../source/File_Transfer/File_Transfer.rst:395 +#: 953993d920eb4959987d98423440ce61 +msgid "``/multiple_file_folder ... [destination_file_path]``" msgstr "``/multiple_file_folder <フォルダ 1> <フォルダ 2> ... [保存先ファイルのパス]``" -#: ../../source/File_Transfer/File_Transfer.rst:396 -#: 085ba670e149450a8b385d68c8f9d366 +#: ../../source/File_Transfer/File_Transfer.rst:397 +#: 886c8b7d760044cabe48ce044412ca64 #, fuzzy msgid "" -"Server console (the receiver is the target client, given as a quoted ``(ip, " -"port)`` address tuple, not as a client id):" +"Server console (the receiver is the target client, given as a quoted " +"``(ip, port)`` address tuple, not as a client id):" msgstr "サーバー コンソール (受信者は引用符で囲まれたアドレス タプルとして指定されるターゲット クライアントです):" -#: ../../source/File_Transfer/File_Transfer.rst:400 -#: abc0fb96992e4b09aaa9714ba73a094b +#: ../../source/File_Transfer/File_Transfer.rst:401 +#: 48d3bf6084224062867313a9597044d7 #, fuzzy msgid "``/file <(ip, port)> [destination_file_path]``" msgstr "``/file <ファイルパス> [保存先ファイルパス]``" -#: ../../source/File_Transfer/File_Transfer.rst:402 -#: d9329c72161247bf8d5f0a609178c488 +#: ../../source/File_Transfer/File_Transfer.rst:403 +#: 684fa9b22136418b94cbb4202f702cd2 #, fuzzy msgid "``/file_folder <(ip, port)> [destination_file_path]``" msgstr "``/file_folder <相対パス>``" -#: ../../source/File_Transfer/File_Transfer.rst:404 -#: af78c6ec2f3e4072aaac19d2d131cf5d +#: ../../source/File_Transfer/File_Transfer.rst:405 +#: 9380dc31685947e3a835107f435deed2 #, fuzzy msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -797,192 +803,193 @@ msgstr "" "``/multiple_file_multiple_client ... " " ... [destination_file_path]``" -#: ../../source/File_Transfer/File_Transfer.rst:406 -#: 2fdbf92caa6a46df9dae793592be802d +#: ../../source/File_Transfer/File_Transfer.rst:407 +#: 62488b8bb4e149be86c1d655bd80b6a8 #, fuzzy msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, port)1> ... " "[destination_file_path]``" -msgstr "" -"「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start」" +msgstr "「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start」" -#: ../../source/File_Transfer/File_Transfer.rst:408 -#: abc1dac22b594c54a22b03d59e1a8338 +#: ../../source/File_Transfer/File_Transfer.rst:409 +#: d6a0c51014c9403fb82ebdf5c93928bc msgid "" -"For the multiple-item commands the destination is the last argument; when " -"the last argument is not a ``(ip, port)`` tuple it is treated as the " -"destination path (for the ``/multiple_file_multiple_client`` form, items are" -" classified per token, so files and addresses may be interleaved and a last " -"argument that is not an existing local file/folder is the destination)." +"For the multiple-item commands the destination is the last argument; when" +" the last argument is not a ``(ip, port)`` tuple it is treated as the " +"destination path (for the ``/multiple_file_multiple_client`` form, items " +"are classified per token, so files and addresses may be interleaved and a" +" last argument that is not an existing local file/folder is the " +"destination)." msgstr "" "Multiple - itemコマンドの場合、destinationは最後の引数です。最後の引数が''( ip, port " ")''タプルでない場合、それは宛先パスとして扱われます(''/ multiple_file_multiple_client " "''フォームの場合、アイテムはトークンごとに分類されるため、ファイルとアドレスがインターリーブされ、既存のローカルファイル/フォルダではない最後の引数が宛先になります)。" -#: ../../source/File_Transfer/File_Transfer.rst:418 -#: 0c7fa56659f543ed93adacd874dd2e8b +#: ../../source/File_Transfer/File_Transfer.rst:419 +#: 373c2a5a23334df7a25d23f8d94abd66 msgid "Native In-Memory Forwarding" msgstr "ネイティブのメモリ内転送" -#: ../../source/File_Transfer/File_Transfer.rst:420 -#: 133205c62a0846318b30f5f5fe0dc296 +#: ../../source/File_Transfer/File_Transfer.rst:421 +#: dd57639b3e0e4068bd9533fc039597cd #, fuzzy msgid "" "The main protocol also provides a native, client-side forwarding feature " -"that relays data from one client to several other clients through the server" -" **without any disk I/O on the server**. Unlike the forward extension (which" -" uploads the data to the server's transfer directory first and then has the " -"server push the stored copies), the server only holds the data in memory and" -" streams it straight to the target clients. This avoids the double transfer " -"time and the disk read/write overhead." +"that relays data from one client to several other clients through the " +"server **without any disk I/O on the server**. Unlike the forward " +"extension (which uploads the data to the server's transfer directory " +"first and then has the server push the stored copies), the server only " +"holds the data in memory and streams it straight to the target clients. " +"This avoids the double transfer time and the disk read/write overhead." msgstr "" "メイン プロトコルは、**サーバー上でディスク I/O を行わずに**、サーバーを介して 1 " "つのクライアントから他の複数のクライアントにデータを中継するネイティブのクライアント側転送機能も提供します。前方拡張機能 " "(ディスクにアップロードしてからディスクからダウンロードする) とは異なり、サーバーはデータをメモリ内に保持するだけで、それをターゲット " "クライアントに直接ストリーミングします。これにより、転送時間の 2 倍とディスクの読み取り/書き込みのオーバーヘッドが回避されます。" -#: ../../source/File_Transfer/File_Transfer.rst:432 -#: b177ec0385be4e9da692646b88cd3ed8 +#: ../../source/File_Transfer/File_Transfer.rst:433 +#: 982c4c9538914821a07887fb8ab9b95d #, fuzzy msgid "Commands (client console only; rejected on the server console):" msgstr "クライアント コンソール (受信者はサーバー):" -#: ../../source/File_Transfer/File_Transfer.rst:435 -#: 789bd7878891443fa43ec5111b3a028b +#: ../../source/File_Transfer/File_Transfer.rst:436 +#: 14406316555743359a854540ab6937c8 #, fuzzy msgid "" "``/forward_file ... ... " "[destination_file_path]``" msgstr "``/forward_file ... ...``" -#: ../../source/File_Transfer/File_Transfer.rst:436 -#: 04d9ece635c94b8c9257e0cb41bd5b81 +#: ../../source/File_Transfer/File_Transfer.rst:437 +#: 4dc576898177404da124649f7ce9ac28 #, fuzzy msgid "" "``/forward_folder ... ... " "[destination_file_path]``" msgstr "``/forward_folder <フォルダ 1> <フォルダ 2> ... ...``" -#: ../../source/File_Transfer/File_Transfer.rst:438 -#: 2f7b628a4e0246e385e9e8817b8d7a87 +#: ../../source/File_Transfer/File_Transfer.rst:439 +#: 220dfbf0a0d84559a8befb4eee500ba0 msgid "" "The number of files/folders and the number of target clients (written as " -"quoted address tuples) is unlimited. Target addresses that are unreachable " -"(not connected to the server) or equal to the server itself are skipped and " -"the remaining targets are still served." +"quoted address tuples) is unlimited. Target addresses that are " +"unreachable (not connected to the server) or equal to the server itself " +"are skipped and the remaining targets are still served." msgstr "" "ファイル/フォルダーの数とターゲット クライアント (引用符で囲まれたアドレス タプルとして記述される) の数は無制限です。到達できない " "(サーバーに接続されていない) ターゲット アドレス、またはサーバー自体に等しいターゲット " "アドレスはスキップされ、残りのターゲットは引き続き処理されます。" -#: ../../source/File_Transfer/File_Transfer.rst:446 -#: 84f3e0acf89e4767bbb572cc6edc81aa +#: ../../source/File_Transfer/File_Transfer.rst:447 +#: 6137bf9406784c6f82d9f41560a52566 msgid "" "Like every transfer family, both commands accept an optional trailing " -"``destination_file_path`` that replaces the default save directory on every " -"receiving client: a forwarded file lands at ``/`` and" -" a forwarded folder keeps its structure under " -"``//...``. When the argument is omitted the " -"targets write to their default ``file_transfer_dir``." +"``destination_file_path`` that replaces the default save directory on " +"every receiving client: a forwarded file lands at " +"``/`` and a forwarded folder keeps its structure " +"under ``//...``. When the argument is omitted " +"the targets write to their default ``file_transfer_dir``." msgstr "" "すべての転送ファミリと同様に、両方のコマンドは、すべての受信クライアントのデフォルトの保存ディレクトリを置き換えるオプションの末尾の''" " destination_file_path " "''を受け入れます。転送されたファイルは''/''に着地し、転送されたフォルダはその構造を''//..." " ''の下に保持します。引数が省略されると、ターゲットはデフォルトの'' file_transfer_dir ''に書き込みます。" -#: ../../source/File_Transfer/File_Transfer.rst:457 -#: 6b31e93335824fe1bfdb83b84f42f08c +#: ../../source/File_Transfer/File_Transfer.rst:458 +#: f6697695e9ef4e3694fa9046e41578e0 msgid "The data path reuses the protocol's own transfer machinery:" msgstr "データ パスは、プロトコル独自の転送機構を再利用します。" -#: ../../source/File_Transfer/File_Transfer.rst:460 -#: 469812eff1874189a000989c9260cf1b +#: ../../source/File_Transfer/File_Transfer.rst:461 +#: 6ee037f0e4024d2988fcb2ccf3deef70 #, fuzzy msgid "" -"The forwarding client streams the file with the standard file-transfer byte " -"stream (metadata header + 65536-byte chunks) to a transfer socket on the " -"server." +"The forwarding client streams the file with the standard file-transfer " +"byte stream (metadata header + ``file_transfer_chunk_len``-byte chunks, " +"default 65536) to a transfer socket on the server." msgstr "" "転送クライアントは、標準のファイル転送バイト ストリーム (メタデータ ヘッダー + 64 KiB チャンク) " "を使用してファイルをサーバー上の転送ソケットにストリーミングします。" -#: ../../source/File_Transfer/File_Transfer.rst:465 -#: 42efd096a6744f489dc623a6ee503666 +#: ../../source/File_Transfer/File_Transfer.rst:467 +#: 43c94e746a5c46748846d0dc18a4e0ff msgid "" -"The server acts as a pure relay: it reads the stream into per-target memory " -"queues and writes each chunk to every target's transfer socket. The server " -"never parses the file contents beyond the size header and never writes to " -"disk." +"The server acts as a pure relay: it reads the stream into per-target " +"memory queues and writes each chunk to every target's transfer socket. " +"The server never parses the file contents beyond the size header and " +"never writes to disk." msgstr "" "サーバーは純粋なリレーとして機能します。ストリームをターゲットごとのメモリ " "キューに読み取り、各チャンクをすべてのターゲットの転送ソケットに書き込みます。サーバーは、サイズ " "ヘッダーを超えてファイルの内容を解析したり、ディスクに書き込んだりすることはありません。" -#: ../../source/File_Transfer/File_Transfer.rst:472 -#: f43cb20c7bc648018f6f77ea09c8d538 +#: ../../source/File_Transfer/File_Transfer.rst:474 +#: 9dec57916af34e109bee7ce1e0bae2d4 msgid "" "Every target client receives the stream with the ordinary receive path " -"(``file_transfer_mode_recv``) and writes it to its own local disk, exactly " -"as if the server had pushed the file directly." +"(``file_transfer_mode_recv``) and writes it to its own local disk, " +"exactly as if the server had pushed the file directly." msgstr "" "すべてのターゲットクライアントは、通常の受信パス (``file_transfer_mode_recv``) " "でストリームを受信し、サーバーがファイルを直接プッシュしたかのように、それを独自のローカルディスクに書き込みます。" -#: ../../source/File_Transfer/File_Transfer.rst:478 -#: 3885df70422e4306ac80be623aa9581f +#: ../../source/File_Transfer/File_Transfer.rst:480 +#: a095abaf821e41a6a66adbb776bc35ef msgid "### Memory Bounding and Flow Control" msgstr "### メモリ境界とフロー制御" -#: ../../source/File_Transfer/File_Transfer.rst:480 -#: e371e5b793824e3386b43cb07a4222fd +#: ../../source/File_Transfer/File_Transfer.rst:482 +#: 244214dd675345f8a72b1088ad99fea0 #, fuzzy msgid "" -"Because uploader, server and targets may have different bandwidths, data can" -" pile up in the server's memory. ``TCP_Server_Base`` takes a " -"``max_mem_buff`` parameter (in MiB, default 2048, i.e. 2 GB) that bounds the" -" memory the forwarding machinery may hold in that process. When the server's" -" buffered bytes exceed ``max_mem_buff`` it sends ``/pause_trans`` to the " -"forwarding client, which stops reading the source file; once the writers " -"drain the buffers below the low-water mark (half the limit) the server sends" -" ``/start_trans`` and the upload resumes. Receiving clients drain each chunk" -" to disk synchronously, so their buffered memory stays bounded by a single " -"chunk; the ``/pause_trans``/``/start_trans`` handlers exist on both sides so" -" any side can throttle a transfer when it buffers data." +"Because uploader, server and targets may have different bandwidths, data " +"can pile up in the server's memory. ``TCP_Server_Base`` takes a " +"``max_mem_buff`` parameter (in MiB, default 2048, i.e. 2 GB) that bounds " +"the memory the forwarding machinery may hold in that process. When the " +"server's buffered bytes exceed ``max_mem_buff`` it sends ``/pause_trans``" +" to the forwarding client, which stops reading the source file; once the " +"writers drain the buffers below the low-water mark (half the limit) the " +"server sends ``/start_trans`` and the upload resumes. Receiving clients " +"drain each chunk to disk synchronously, so their buffered memory stays " +"bounded by a single chunk; the ``/pause_trans``/``/start_trans`` handlers" +" exist on both sides so any side can throttle a transfer when it buffers " +"data." msgstr "" "アップローダー、サーバー、ターゲットの帯域幅が異なる場合があるため、サーバーのメモリにデータが蓄積される可能性があります。 " -"``TCP_Server_Base`` と ``TCP_Client_Base`` は両方とも、転送機構がそのプロセスで保持できるメモリを制限する " -"``max_mem_buff`` パラメータ (MB 単位、デフォルトは 2048、つまり 2 GB) " -"を取ります。サーバーのバッファリングされたバイト数が ``max_mem_buff`` を超えると、転送クライアントに ``/pause_trans``" -" が送信され、転送クライアントはソースファイルの読み取りを停止します。ライターが最低水準点 (制限の半分) を下回るバッファを排出すると、サーバーは " -"``/start_trans`` " +"``TCP_Server_Base`` と ``TCP_Client_Base`` は両方とも、転送機構がそのプロセスで保持できるメモリを制限する" +" ``max_mem_buff`` パラメータ (MB 単位、デフォルトは 2048、つまり 2 GB) " +"を取ります。サーバーのバッファリングされたバイト数が ``max_mem_buff`` を超えると、転送クライアントに " +"``/pause_trans`` が送信され、転送クライアントはソースファイルの読み取りを停止します。ライターが最低水準点 (制限の半分) " +"を下回るバッファを排出すると、サーバーは ``/start_trans`` " "を送信し、アップロードが再開されます。受信側クライアントは各チャンクを同期的にディスクに排出するため、バッファリングされたメモリは単一のチャンクによって制限されたままになります。" " ``/pause_trans``/``/start_trans`` " "ハンドラは両側に存在するため、どちらの側でもデータをバッファリングするときに転送を抑制できます。" -#: ../../source/File_Transfer/File_Transfer.rst:504 -#: b737bf957d354491b30903bfb0f89a3b +#: ../../source/File_Transfer/File_Transfer.rst:506 +#: 0aa14deaf6474437b421a65e21fce7d8 msgid "Concurrency and Threading" msgstr "同時実行性とスレッド化" -#: ../../source/File_Transfer/File_Transfer.rst:506 -#: 505576a3522748318a95cd3937a96834 +#: ../../source/File_Transfer/File_Transfer.rst:508 +#: 825c5e1a8b9b405c967ca49a1861e258 msgid "" -"Both the server and the client use multiple levels of concurrency control to" -" ensure stability during file transfers." +"Both the server and the client use multiple levels of concurrency control" +" to ensure stability during file transfers." msgstr "サーバーとクライアントの両方は、ファイル転送中の安定性を確保するために複数レベルの同時実行制御を使用します。" -#: ../../source/File_Transfer/File_Transfer.rst:510 -#: 1d1a7b2ee1434530ae6abb411b0175cc +#: ../../source/File_Transfer/File_Transfer.rst:512 +#: 0d48b1245cd54597928cfc28d5b3c248 msgid "### File Transfer Semaphore" msgstr "### ファイル転送セマフォ" -#: ../../source/File_Transfer/File_Transfer.rst:512 -#: 078680d22b10410db9f7f21fe0e1a91d +#: ../../source/File_Transfer/File_Transfer.rst:514 +#: e2674ee9e0584513bc53aa815603fd24 msgid "Client: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" msgstr "クライアント: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:514 -#: 777a1dcc1258459d89dacbbb7b946c11 +#: ../../source/File_Transfer/File_Transfer.rst:516 +#: 1c0d27d13ad844159d29c6e662d51d09 msgid "" "Server: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" @@ -990,26 +997,26 @@ msgstr "" "サーバー: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:517 -#: 315a82a6dd1a420bbe819a806f3b8292 +#: ../../source/File_Transfer/File_Transfer.rst:519 +#: cb65901904c8411ba53fc629023f732d #, fuzzy msgid "" "This semaphore limits the number of simultaneous file transfers (used " -"primarily when sending folders or multiple files). Each transfer runs in its" -" own thread and the worker acquires the semaphore for the whole transfer, so" -" both the folder and the ``/multiple_file`` path are capped at " -"``max_thread_num`` (``max_file_transfer_thread_num`` on the server)." +"primarily when sending folders or multiple files). Each transfer runs in " +"its own thread and the worker acquires the semaphore for the whole " +"transfer, so both the folder and the ``/multiple_file`` path are capped " +"at ``max_thread_num`` (``max_file_transfer_thread_num`` on the server)." msgstr "" "このセマフォは、同時ファイル転送の数を制限します " "(主にフォルダーまたは複数のファイルを送信する場合に使用されます)。各転送は独自のスレッドで実行され、セマフォはスレッドが開始される前に取得されます。" -#: ../../source/File_Transfer/File_Transfer.rst:524 -#: b39cfe74f74b4b568221d23addc55da3 +#: ../../source/File_Transfer/File_Transfer.rst:526 +#: 6d93783b298e4ce98b999ff890d4a5f4 msgid "### Threading Model" msgstr "### スレッドモデル" -#: ../../source/File_Transfer/File_Transfer.rst:526 -#: 5586d5cc13a940bb92877b1fed3d03fd +#: ../../source/File_Transfer/File_Transfer.rst:528 +#: 036a972600e645119d8a523fa08a52db msgid "" "Each file transfer runs in a dedicated daemon thread, created by the " "``_thread`` wrapper functions (e.g., " @@ -1020,40 +1027,41 @@ msgstr "" "``file_transfer_client_recv_client_start_thread``) " "によって作成された専用のデーモンスレッドで実行されます。これにより、遅い転送によってメイン制御ループがブロックされるのを防ぎます。" -#: ../../source/File_Transfer/File_Transfer.rst:532 -#: 7b1cceca816c426b865265e0c302c425 +#: ../../source/File_Transfer/File_Transfer.rst:534 +#: a84aaf5f9fb64d92b97c32185a1e7cb5 msgid "" "The thread that receives the transfer command (e.g., the server's " -"``handle_command`` thread) does not wait for the transfer to complete; it " -"returns immediately after spawning the worker thread." +"``handle_command`` thread) does not wait for the transfer to complete; it" +" returns immediately after spawning the worker thread." msgstr "" "転送コマンドを受信するスレッド (例: サーバーの ``handle_command`` スレッド) は、転送が完了するのを待ちません。ワーカー " "スレッドを生成した直後に戻ります。" -#: ../../source/File_Transfer/File_Transfer.rst:537 -#: 2d25f2be19fb467bb222d3780e2be853 +#: ../../source/File_Transfer/File_Transfer.rst:539 +#: 669fb6da8e7444dd829a6e14295648b1 msgid "" -"The low-level receive function (``file_transfer_mode_recv``) blocks while " -"reading from the transfer socket, but because it runs in a dedicated thread," -" the main connection remains responsive." +"The low-level receive function (``file_transfer_mode_recv``) blocks while" +" reading from the transfer socket, but because it runs in a dedicated " +"thread, the main connection remains responsive." msgstr "" "低レベルの受信関数 (``file_transfer_mode_recv``) " "は、転送ソケットからの読み取り中にブロックされますが、専用スレッドで実行されるため、メイン接続は応答したままになります。" -#: ../../source/File_Transfer/File_Transfer.rst:543 -#: 641bce0854274c369c0b915a1c3d964a +#: ../../source/File_Transfer/File_Transfer.rst:545 +#: e39f8ae06ae84a6b84de8a3008ca17cb msgid "### Thread Pool for Custom Commands" msgstr "### カスタム コマンド用のスレッド プール" -#: ../../source/File_Transfer/File_Transfer.rst:545 -#: c41d6414ad5542aa8bbeaa67d28730d5 +#: ../../source/File_Transfer/File_Transfer.rst:547 +#: 3ad49853529d4563bacdfb4ca6eee115 msgid "" "Both classes also provide a ``ThreadPoolExecutor`` " -"(``self._custom_executor``) for custom command handlers. When a handler is " -"registered with ``run_in_thread=True``, it is submitted to this pool via " -"``submit_task``, which also uses a semaphore to limit concurrency to " +"(``self._custom_executor``) for custom command handlers. When a handler " +"is registered with ``run_in_thread=True``, it is submitted to this pool " +"via ``submit_task``, which also uses a semaphore to limit concurrency to " "``max_custom_workers``. This mechanism is **independent** of the file " -"transfer semaphore and is intended for general-purpose command processing." +"transfer semaphore and is intended for general-purpose command " +"processing." msgstr "" "どちらのクラスも、カスタム コマンド ハンドラー用の ``ThreadPoolExecutor`` " "(``s​​elf._custom_executor``) を提供します。ハンドラが ``run_in_thread=True`` " @@ -1061,23 +1069,23 @@ msgstr "" "``max_custom_workers`` " "に制限します。このメカニズムはファイル転送セマフォから**独立**しており、汎用コマンド処理を目的としています。" -#: ../../source/File_Transfer/File_Transfer.rst:560 -#: adfe7eb4ec4942e9979652f98b3beed9 +#: ../../source/File_Transfer/File_Transfer.rst:562 +#: 1862d74da28a40219f82cfd7af89c126 msgid "Port Allocation and Management" msgstr "ポートの割り当てと管理" -#: ../../source/File_Transfer/File_Transfer.rst:562 -#: 845beb63ef9c47ba8379637a1b0662fb +#: ../../source/File_Transfer/File_Transfer.rst:564 +#: bd53ec8aa4ef498aa0815db16ed03140 msgid "" -"File transfers require ephemeral ports for the secondary data connections. " -"The ``palloc()`` and ``pfree()`` methods are used to obtain and release " -"these ports. Two modes are available:" +"File transfers require ephemeral ports for the secondary data " +"connections. The ``palloc()`` and ``pfree()`` methods are used to obtain " +"and release these ports. Two modes are available:" msgstr "" "ファイル転送には、セカンダリ データ接続用の一時ポートが必要です。 ``palloc()`` メソッドと ``pfree()`` " "メソッドは、これらのポートを取得および解放するために使用されます。次の 2 つのモードが利用可能です。" -#: ../../source/File_Transfer/File_Transfer.rst:568 -#: 8195ea505bdf43a2a0f68b78d958c709 +#: ../../source/File_Transfer/File_Transfer.rst:570 +#: eeaa9379d7d941159ac34f30ff6bb5f9 msgid "" "**Automatic mode** (``is_hand_alloc_port=False``): ``palloc()`` returns " "``0``, and the operating system assigns a free port when the socket is " @@ -1086,25 +1094,25 @@ msgstr "" "**自動モード** (``is_hand_alloc_port=False``): ``palloc()`` は ``0`` " "を返し、ソケットがバインドされているときにオペレーティング システムが空きポートを割り当てます。これは、ほとんどの使用例で推奨されるモードです。" -#: ../../source/File_Transfer/File_Transfer.rst:573 -#: 9a796b6e464d4d9e8e131401d5022e1f +#: ../../source/File_Transfer/File_Transfer.rst:575 +#: e3dc324e81734bd4bc768174caf200bf #, fuzzy msgid "" -"**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; on " -"the client the flag is set by the server's ``/client_alloc_port_range`` " -"message): Ports are drawn from a configurable range ``[self.min_port, " -"self.max_port]`` with a step size ``port_add_step``. The server sends the " -"allowed range to each client that connects via ``/client_alloc_port_range``," -" and clients then use the same manual allocation logic. See " -":doc:`../Port_Allocation/Port_Allocation` for the range record and the retry" -" behaviour." +"**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; " +"on the client the flag is set by the server's " +"``/client_alloc_port_range`` message): Ports are drawn from a " +"configurable range ``[self.min_port, self.max_port]`` with a step size " +"``port_add_step``. The server sends the allowed range to each client that" +" connects via ``/client_alloc_port_range``, and clients then use the same" +" manual allocation logic. See :doc:`../Port_Allocation/Port_Allocation` " +"for the range record and the retry behaviour." msgstr "" "**手動モード** (``is_hand_alloc_port=True``): ポートは、設定可能な範囲 ``[self.min_port, " "self.max_port]`` からステップ サイズ ``port_add_step`` で描画されます。サーバーは許可された範囲を " "/client_alloc_port_range 経由でクライアントにブロードキャストし、クライアントは同じ手動割り当てロジックを使用します。" -#: ../../source/File_Transfer/File_Transfer.rst:588 -#: 7d275701519c4d60ba94cf086010e92d +#: ../../source/File_Transfer/File_Transfer.rst:590 +#: 29cfdab183eb4f9f83de41ef62a60785 msgid "" "*Note: For more details about port allocation, please visit the Port " "Allocation API sections in :doc:`TCP_Server_APIs` and " @@ -1113,18 +1121,18 @@ msgstr "" "*注意: ポート割り当ての詳細については、:doc:`TCP_Server_APIs` および :doc:`TCP_Client_APIs` " "のポート割り当て API セクションを参照してください。*" -#: ../../source/File_Transfer/File_Transfer.rst:596 -#: e92794553f6f4189978c5486f4d09fce +#: ../../source/File_Transfer/File_Transfer.rst:598 +#: 189736d8d1f8464b8d301f219700fda4 msgid "Error Handling and Timeouts" msgstr "エラー処理とタイムアウト" -#: ../../source/File_Transfer/File_Transfer.rst:598 -#: 6ef0c4c7a91a42d0acc6b0a387247432 +#: ../../source/File_Transfer/File_Transfer.rst:600 +#: bcc373777989436f9df3657446d1a7f2 msgid "### Timeout Values" msgstr "### タイムアウト値" -#: ../../source/File_Transfer/File_Transfer.rst:600 -#: 2b8dea32ffe04d4988e44fca72384271 +#: ../../source/File_Transfer/File_Transfer.rst:602 +#: 27d75d097a804ec28ebec5c67469c9c6 msgid "" "**Start signal timeout**: 10 seconds. If the receiver does not send " "``server_start_file_transfer_sign`` within this time, the sender aborts." @@ -1132,77 +1140,236 @@ msgstr "" "**開始信号のタイムアウト**: 10 秒。受信者がこの時間内に ``server_start_file_transfer_sign`` " "を送信しない場合、送信者は中止します。" -#: ../../source/File_Transfer/File_Transfer.rst:604 -#: 2d19f71ef52b4f3097bf0c2f3e64be7b +#: ../../source/File_Transfer/File_Transfer.rst:606 +#: 93e877c411eb4c96bd7861ff61f35e7a msgid "" -"**Port negotiation timeout**: 20 seconds. The initiator waits for the peer's" -" ``/server_file_transfer_port`` response." +"**Port negotiation timeout**: 20 seconds. The initiator waits for the " +"peer's ``/server_file_transfer_port`` response." msgstr "" "**ポート ネゴシエーション タイムアウト**: 20 秒。イニシエータはピアの ``/server_file_transfer_port`` " "応答を待ちます。" -#: ../../source/File_Transfer/File_Transfer.rst:607 -#: 67dba14dcd534ae484df410cb48c8e53 +#: ../../source/File_Transfer/File_Transfer.rst:609 +#: 9e1d395bb59540a49393bebe6630e5eb msgid "" -"**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 * " -"1024)) * 10`` seconds. Larger files get proportionally more time." +"**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 " +"* 1024)) * 10`` seconds. Larger files get proportionally more time." msgstr "" "**完了確認タイムアウト**: ``30 + (file_size // (100 * 1024 * 1024)) * 10`` " "秒。ファイルが大きいほど、それに比例して時間がかかります。" -#: ../../source/File_Transfer/File_Transfer.rst:611 -#: f175db3ace1448068c029d1527feb065 +#: ../../source/File_Transfer/File_Transfer.rst:613 +#: 6b4e6135669b41178fdbb47ea5975381 msgid "### Error Signalling" msgstr "### エラー通知" -#: ../../source/File_Transfer/File_Transfer.rst:613 -#: 988d9d4636944c0abc8d186178d2a4f7 +#: ../../source/File_Transfer/File_Transfer.rst:615 +#: 448fdc6ba3dd4d9eae925e7e241f8cb8 msgid "" -"Any error during the handshake or data transfer causes the failing side to " -"send ``error_sign`` over the transfer socket." +"Any error during the handshake or data transfer causes the failing side " +"to send ``error_sign`` over the transfer socket." msgstr "ハンドシェイクまたはデータ転送中にエラーが発生すると、失敗した側が転送ソケット経由で ``error_sign`` を送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:616 -#: d171618e798b46d0a6ac7473b4a787ba +#: ../../source/File_Transfer/File_Transfer.rst:618 +#: 5b4c23a93e984ce0af2e43cf4752225b msgid "" -"The other side, upon receiving the error sign, closes the transfer socket " -"and aborts the transfer." +"The other side, upon receiving the error sign, closes the transfer socket" +" and aborts the transfer." msgstr "相手側はエラーサインを受信すると、転送ソケットを閉じて転送を中止します。" -#: ../../source/File_Transfer/File_Transfer.rst:619 -#: c712f2f5e1794c528d4816a761030029 +#: ../../source/File_Transfer/File_Transfer.rst:621 +#: b337a2726ded4d619c5e8026bef3f6ea msgid "" -"The main control connection remains unaffected; only the transfer socket is " -"closed." +"The main control connection remains unaffected; only the transfer socket " +"is closed." msgstr "メイン制御接続は影響を受けません。転送ソケットのみが閉じられます。" -#: ../../source/File_Transfer/File_Transfer.rst:623 -#: 9d55f6049713415794e53bd6a476e11f +#: ../../source/File_Transfer/File_Transfer.rst:625 +#: 68be52c8e5ce447a9c5ec51a661229cf msgid "### Exception Handling" msgstr "### 例外処理" -#: ../../source/File_Transfer/File_Transfer.rst:625 -#: a45a6eaec53b4699a7e61d4e422ace85 +#: ../../source/File_Transfer/File_Transfer.rst:627 +#: 036db9bc1858417ca589816028b83f80 #, fuzzy msgid "" -"All socket operations are wrapped in try-except blocks. When an exception " -"occurs (e.g., connection reset, file not found), the error is logged through" -" the instance's ``_log_exc`` helper, which prints the traceback only when " -"both ``is_print_log`` and ``is_debug`` are true, and the transfer is aborted" -" gracefully. The ``error_sign`` is sent if possible, and the transfer socket" -" is closed." +"All socket operations are wrapped in try-except blocks. When an exception" +" occurs (e.g., connection reset, file not found), the error is logged " +"through the instance's ``_log_exc`` helper, which prints the traceback " +"only when both ``is_print_log`` and ``is_debug`` are true, and the " +"transfer is aborted gracefully. The ``error_sign`` is sent if possible, " +"and the transfer socket is closed." +msgstr "" +"すべてのソケット操作は Try-Except ブロックでラップされます。例外が発生した場合 " +"(接続のリセット、ファイルが見つからないなど)、エラーは ``traceback.print_exc()`` " +"でログに記録され、転送は正常に中止されます。可能な場合は ``error_sign`` が送信され、転送ソケットが閉じられます。" + +#: ../../source/File_Transfer/File_Transfer.rst:640 +#: ba1f05134dd24afa9867881cc45ed14a +msgid "Transfer Progress and Network Speed" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:642 +#: 5c7b182bb5214dd2ad49e5b171876e95 +msgid "Both classes record every running file transfer:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:644 +#: 8adbb686d9b04c97b5a7314ec4a5d1fd +msgid "``file_recv_progress`` — the files being received (downloads);" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:645 +#: 3d2d981185624b5498121d82b12d44ba +msgid "``file_upload_progress`` — the files being sent (uploads)." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:647 +#: e59132f2790d4b4fb2aa707e1d3b43b6 +msgid "" +"The keys are the transfers' fids: the transfer id the sender stamps on " +"the transfer command (``/file ``), which also identifies the " +"relay leg of a forwarded file. The protocol-internal public-key push is " +"not tracked. Each value is a five-item list:" msgstr "" -"すべてのソケット操作は Try-Except ブロックでラップされます。例外が発生した場合 (接続のリセット、ファイルが見つからないなど)、エラーは " -"``traceback.print_exc()`` でログに記録され、転送は正常に中止されます。可能な場合は ``error_sign`` " -"が送信され、転送ソケットが閉じられます。" -#: ../../source/File_Transfer/File_Transfer.rst:638 -#: 00af57a759ec4845b5810bb85ac1f485 +#: ../../source/File_Transfer/File_Transfer.rst:652 +#: bf66e7dae7e24cf3a3687ffd30f547ec +msgid "``[0]``: bytes transferred so far;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:653 +#: 2652aa8074764124b520d4e84b7667d5 +msgid "``[1]``: total size of the file, in bytes;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:654 +#: 8b09fc93700d4b6ca7a517700649c289 +msgid "" +"``[2]``: the current network speed of that direction — ``None`` until the" +" transfer has moved its first chunk, and while " +"``is_enable_real_time_network_speed`` is ``False``;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:657 +#: 311adcc13bd441a985ebcd8c775b152f +msgid "" +"``[3]``: local path of the file: the source of an outbound transfer, the " +"file being written for an inbound one;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:659 +#: 7a1f875aeb8b497ab7785620e402ff97 +msgid "" +"``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender " +"in a download's entry, the receiver in an upload's. A forwarded transfer " +"stores the original peer on both sides, never the relaying server." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:663 +#: da38fbed94114f10b6f7366e43906dd8 +msgid "" +"An entry appears when a transfer starts and is removed when it ends, so " +"the stores hold exactly the transfers that are in flight at that moment " +"(iterate over a copy while transfers are running). With " +"``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is " +"ever recorded — and, since the stores are the state a reconnect resumes " +"from, no transfer can be resumed either." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:670 +#: edbdd37cf5a04d42bf01f6bff5aa3307 +msgid "" +"``is_enable_real_time_network_speed`` (``True`` by default) measures the " +"protocol's current traffic — the control layer and every temporary " +"connection, file transfers included — into ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With the flag ``False`` nothing is " +"sampled and every speed value is ``None``." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:677 +#: c60e3cb78c8d48faace7569bdb50f8f5 +msgid "" +"The web tool (``transfer_web``) reads these stores: both backends serve " +"``/api/transfers`` (the rows plus the two speed attributes), and the " +"shared frontend renders the live speed readout in the topbar and one " +"progress bar per running transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:685 +#: ce90e0b6082e4d37a79346aa7b2763f9 +msgid "Pausing, Reconnecting and Resuming Transfers" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:687 +#: 5fbf414617474bd79978360043f149a3 +msgid "" +"An outbound transfer can be held and released at any time with the " +"``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or " +"from the peer with the ``/pause_trans `` and ``/start_trans `` " +"lines: ``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, " +"fid)`` send them. The leg stops before its next chunk and stays open; a " +"leg that is paused keeps its socket, so nothing is torn down. Every " +"outbound transfer honours its own fid — a plain upload as much as the " +"upload leg of a forwarded file — so the flow control the server uses on a" +" relay works on any transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:696 +#: d4ace80bc05f4bafb8144e1de31060dc +msgid "The temporary connections of a transfer are resumed after a disconnect:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:698 +#: d7d49609832d4c5bb2d7cecb059805eb +msgid "" +"when a connection drops, both sides write their transfer stores to " +"``.Flow/server_file_trans_progress.json`` / " +"``.Flow/client_file_trans_progress.json`` (the " +"``file_trans_progress_file`` attribute) — every upload, every download " +"and, on the server, the relay records a disconnected forward is re-driven" +" from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:703 +#: 353cf50d60014cceb4c5a36bf5b98b83 +msgid "" +"an interrupted transfer keeps its progress entry and its partial file " +"instead of dropping them, so the file on disk is exactly the state to " +"continue from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:706 +#: c7017b370d4147128e54a94458a7b536 +msgid "" +"after a reconnect the receiver drives the resume (`resume_transfers`): it" +" opens a fresh transfer listener, announces it and sends ``/resume_trans " +" `` with the byte offset its partial file holds. The sender " +"re-establishes the leg, reads its source from that offset and only the " +"remainder of the file travels. A forwarded transfer is asked for through " +"the server, which routes ``/forward_resume`` to the originating client so" +" it re-forwards just the missing part." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:714 +#: ee858a76e93f44d5934cb2d89f6709a5 +msgid "" +"The server resumes a peer's transfers when it reconnects, and a client " +"with ``is_auto_reconnect=True`` reconnects on its own and resumes every " +"transfer it can reach; `resume_transfers` is public, so an application " +"can also drive the resume itself. Legs the previous session left behind " +"are closed before the resume runs, so two legs never write the same " +"transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:723 +#: fe9377db9cf04b9da0dbe4d07c730adf msgid "Related API Definitions" msgstr "関連する API 定義" -#: ../../source/File_Transfer/File_Transfer.rst:640 -#: 92c3b5d713cb49cfb144026af574a0b4 +#: ../../source/File_Transfer/File_Transfer.rst:725 +#: cc71cb9b1d6642a2acc89d45a49022cc msgid "" "This section lists all public file-transfer related methods in " "``TCP_Server_Base`` and ``TCP_Client_Base``. For a complete list of all " @@ -1211,317 +1378,352 @@ msgstr "" "このセクションでは、 ``TCP_Server_Base`` および ``TCP_Client_Base`` 内のすべてのパブリック " "ファイル転送関連メソッドをリストします。すべてのパブリック API の完全なリストについては、このドキュメントの最後にある表を参照してください。" -#: ../../source/File_Transfer/File_Transfer.rst:646 -#: bbc49149589d43719bc774a99b84ce6e +#: ../../source/File_Transfer/File_Transfer.rst:731 +#: d6683e415f794c5bb693f8c24370e7f9 msgid "### Server-Side File Transfer APIs" msgstr "### サーバー側ファイル転送 API" -#: ../../source/File_Transfer/File_Transfer.rst:652 -#: 59386d051c734452801f4bd00d5dd654 +#: ../../source/File_Transfer/File_Transfer.rst:737 +#: 9123c69197c34d93bb68d088897ebeca msgid "" "Initiates a server-to-client file transfer. ``message`` is the command " "string (e.g., ``/file /path/to/file.txt (127.0.0.1,54321)``). If " -"``file_folder_abspath`` is provided (for folder transfers), it specifies the" -" absolute path of the parent folder." +"``file_folder_abspath`` is provided (for folder transfers), it specifies " +"the absolute path of the parent folder." msgstr "" "サーバーからクライアントへのファイル転送を開始します。 ``message`` はコマンド文字列です (例: ``/file " -"/path/to/file.txt (127.0.0.1,54321)``)。 ``file_folder_abspath`` が指定されている場合 " -"(フォルダ転送用)、親フォルダの絶対パスを指定します。" +"/path/to/file.txt (127.0.0.1,54321)``)。 ``file_folder_abspath`` " +"が指定されている場合 (フォルダ転送用)、親フォルダの絶対パスを指定します。" -#: ../../source/File_Transfer/File_Transfer.rst:663 -#: 431a043a77bc4d82a206650afde47b86 +#: ../../source/File_Transfer/File_Transfer.rst:748 +#: 367dfd82c95c413d963a15152469fc44 msgid "Thread-safe version that starts a new thread for the transfer." msgstr "転送用に新しいスレッドを開始するスレッドセーフ バージョン。" -#: ../../source/File_Transfer/File_Transfer.rst:669 -#: e17536344cb444b699c7465d8bcbdded +#: ../../source/File_Transfer/File_Transfer.rst:754 +#: d4aa76b7eb2c46c29adee0120a939b66 #, fuzzy msgid "" -"Sends an entire folder from server to client. ``message`` should be of the " -"form ``/file_folder <(ip, port)> [destination_file_path]``." +"Sends an entire folder from server to client. ``message`` should be of " +"the form ``/file_folder <(ip, port)> " +"[destination_file_path]``." msgstr "" "フォルダー全体をサーバーからクライアントに送信します。 ``message`` は ``/file_folder " " `` の形式にする必要があります。" -#: ../../source/File_Transfer/File_Transfer.rst:676 -#: 88f9df0240054009a6957b13ee08f2ef +#: ../../source/File_Transfer/File_Transfer.rst:761 +#: 29f2a5e19bf04a09a8711ac1c892a4ad msgid "" "Sends multiple items to multiple clients. The message format is " "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " -"port)2> ... [destination]``; every token is classified on its own (a ``(ip, " -"port)`` literal is a target, anything else is an item), so items and targets" -" may be interleaved. Each item is dispatched as a file or as a folder " -"depending on what it is on disk, and an optional trailing destination path " -"is accepted." -msgstr "" -"複数のアイテムを複数のクライアントに送信します。メッセージフォーマットは''/ multiple_file_multiple_client" -" ... <( ip, port) 1 > <( ip, port) 2 >... [destination " -"]''です。すべてのトークンはそれ自体で分類されます(''( ip, port " +"port)2> ... [destination]``; every token is classified on its own (a " +"``(ip, port)`` literal is a target, anything else is an item), so items " +"and targets may be interleaved. Each item is dispatched as a file or as a" +" folder depending on what it is on disk, and an optional trailing " +"destination path is accepted." +msgstr "" +"複数のアイテムを複数のクライアントに送信します。メッセージフォーマットは''/ " +"multiple_file_multiple_client ... <( ip, port) 1 > " +"<( ip, port) 2 >... [destination ]''です。すべてのトークンはそれ自体で分類されます(''( ip," +" port " ")''リテラルはターゲットであり、それ以外はアイテムです)。したがって、アイテムとターゲットはインターリーブされる可能性があります。各アイテムは、ディスク上にあるものに応じてファイルまたはフォルダとしてディスパッチされ、オプションの末尾の宛先パスが受け入れられます。" -#: ../../source/File_Transfer/File_Transfer.rst:688 -#: 39b67f1d0e6b438386eb04c6d44da6b8 +#: ../../source/File_Transfer/File_Transfer.rst:773 +#: ff8bc5c8969b45c1bbcf1eba5b77485a msgid "" -"Sends different file lists to different clients. Files that appear before a " -"group of client addresses are sent to that group; a new group starts as soon" -" as a file token follows one or more addresses. Example: " +"Sends different file lists to different clients. Files that appear before" +" a group of client addresses are sent to that group; a new group starts " +"as soon as a file token follows one or more addresses. Example: " "``/diff_multiple_file_diff_multiple_client a.txt b.txt (ip1,port1) " "(ip2,port2) c.txt (ip3,port3)`` — ``a.txt`` and ``b.txt`` go to " "``(ip1,port1)`` and ``(ip2,port2)``, ``c.txt`` to ``(ip3,port3)``. An " "optional trailing destination path is accepted." msgstr "" "異なるファイルリストを異なるクライアントに送信します。クライアントアドレスのグループの前に表示されるファイルがそのグループに送信されます。ファイルトークンが1つ以上のアドレスに従うとすぐに新しいグループが開始されます。例:" -" ''/ diff_multiple_file_diff_multiple_client a.txt b.txt (ip 1, port 1) (ip " -"2, port 2) c.txt (ip 3, port 3 )''-'' a.txt '' and '' b.txt '' go to ''( ip " -"1, port 1 )'' and ''( ip 2, port 2 )'', '' c.txt '' to ''''( ip 3, port 3 " -")'''.オプションの末尾の宛先パスは次のとおりです。 されています。" +" ''/ diff_multiple_file_diff_multiple_client a.txt b.txt (ip 1, port 1) " +"(ip 2, port 2) c.txt (ip 3, port 3 )''-'' a.txt '' and '' b.txt '' go to " +"''( ip 1, port 1 )'' and ''( ip 2, port 2 )'', '' c.txt '' to ''''( ip 3," +" port 3 )'''.オプションの末尾の宛先パスは次のとおりです。 されています。" -#: ../../source/File_Transfer/File_Transfer.rst:701 -#: 37108379b0b9495584bb135d5860ea4a +#: ../../source/File_Transfer/File_Transfer.rst:786 +#: f8a880287b7b49d4bdc2239ecf4a0577 msgid "" -"Receives a file from a client. Called internally when the server receives a " -"``/file`` command from a client." +"Receives a file from a client. Called internally when the server receives" +" a ``/file`` command from a client." msgstr "クライアントからファイルを受信します。サーバーがクライアントから ``/file`` コマンドを受信したときに内部的に呼び出されます。" -#: ../../source/File_Transfer/File_Transfer.rst:710 -#: adeb784cb6b24d6cbf143a7a50eba80a +#: ../../source/File_Transfer/File_Transfer.rst:795 +#: 97bfaa9c24ae47c39328707b8f17a91a msgid "" "Low-level receive function that performs the handshake and writes the " "incoming file to disk." msgstr "ハンドシェイクを実行し、受信ファイルをディスクに書き込む低レベルの受信関数。" -#: ../../source/File_Transfer/File_Transfer.rst:718 -#: 0bb492f5335d426d8dc715847665b3f4 +#: ../../source/File_Transfer/File_Transfer.rst:804 +#: c7be9703e0454f7f96586642bc8f6a22 msgid "" "Low-level send function that connects to the receiver and transmits the " -"file." -msgstr "受信機に接続してファイルを送信する低レベルの送信機能。" +"file. ``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's" +" original receiver and ``resume_offset`` continues an interrupted file " +"from the byte the receiver already holds." +msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:720 -#: 29189fe72c61456ba2d5aa1ece75145e +#: ../../source/File_Transfer/File_Transfer.rst:810 +#: 3e7b689215e840bebd368b4d29104ebc msgid "### Client-Side File Transfer APIs" msgstr "### クライアント側のファイル転送 API" -#: ../../source/File_Transfer/File_Transfer.rst:726 -#: 6c2f54ee2660441291a3fbbcaa95262c +#: ../../source/File_Transfer/File_Transfer.rst:816 +#: 1e97e492d6504579a9a265eb1242395e msgid "" -"Initiates a client-to-server file transfer. ``message`` is the user command " -"(e.g., ``/file mydoc.txt``). Used internally by the interactive console." +"Initiates a client-to-server file transfer. ``message`` is the user " +"command (e.g., ``/file mydoc.txt``). Used internally by the interactive " +"console." msgstr "" "クライアントからサーバーへのファイル転送を開始します。 ``message`` はユーザーコマンドです (例: ``/file " "mydoc.txt``)。対話型コンソールによって内部的に使用されます。" -#: ../../source/File_Transfer/File_Transfer.rst:734 -#: ../../source/File_Transfer/File_Transfer.rst:765 -#: 07c4ae801fb54cbcb508af4b208f75dd +#: ../../source/File_Transfer/File_Transfer.rst:824 +#: ../../source/File_Transfer/File_Transfer.rst:855 +#: 0cd2695763114a0b831df0bfa80a3d56 msgid "Thread-safe version." msgstr "スレッドセーフなバージョン。" -#: ../../source/File_Transfer/File_Transfer.rst:740 -#: 0d66d4aac681414fb7b8a46117571fe9 +#: ../../source/File_Transfer/File_Transfer.rst:830 +#: 261399ca508d463eafa7f03a00bfc658 msgid "Sends a folder from client to server." msgstr "フォルダーをクライアントからサーバーに送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:746 -#: 2818655cecfc49f7ab1c9800b9418018 +#: ../../source/File_Transfer/File_Transfer.rst:836 +#: ef5e3b92b11c4530960c1c344a51c73b msgid "Sends multiple files from client to server." msgstr "複数のファイルをクライアントからサーバーに送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:752 -#: 6ee08a69dbc5486a94fe2f616f0899e2 +#: ../../source/File_Transfer/File_Transfer.rst:842 +#: f2c90ee949d7484480cbb2cd5310bf26 msgid "Sends multiple folders from client to server." msgstr "複数のフォルダーをクライアントからサーバーに送信します。" -#: ../../source/File_Transfer/File_Transfer.rst:759 -#: 5a88c3508e074cff9ae445d00193f212 +#: ../../source/File_Transfer/File_Transfer.rst:849 +#: 0b13d26a40174243a15698b4bfcbb69f msgid "" "Receives a file from the server (called when the server initiates a " "transfer)." msgstr "サーバーからファイルを受信します (サーバーが転送を開始するときに呼び出されます)。" -#: ../../source/File_Transfer/File_Transfer.rst:771 -#: 42db9f7f09c044c8a58243854644adfb +#: ../../source/File_Transfer/File_Transfer.rst:861 +#: 3b78a4355d7f4ee2bbbe6bf934a962c0 msgid "Receives a folder from the server." msgstr "サーバーからフォルダーを受信します。" -#: ../../source/File_Transfer/File_Transfer.rst:779 -#: 0a051d591bb54e529c771345409ec7df +#: ../../source/File_Transfer/File_Transfer.rst:869 +#: 3d044e0754b94d1289b491502ce83610 msgid "Low-level receive function on the client side." msgstr "クライアント側の低レベル受信機能。" -#: ../../source/File_Transfer/File_Transfer.rst:786 -#: e0149bdd716249289f6ba260e3c3f053 +#: ../../source/File_Transfer/File_Transfer.rst:877 +#: 7311023a7fa644ed9b57a2873cd3bca8 msgid "" -"Low‑level send function on the client side (identical to server's version)." +"Low‑level send function on the client side (identical to server's " +"version)." msgstr "クライアント側の低レベル送信機能 (サーバーのバージョンと同じ)。" -#: ../../source/File_Transfer/File_Transfer.rst:791 -#: e612d36affc0456b9314f39816bf62f3 +#: ../../source/File_Transfer/File_Transfer.rst:882 +#: 7e74e9a09a8a4cf2a8a372a50b1ee51b msgid "Public API Summary" msgstr "パブリック API の概要" -#: ../../source/File_Transfer/File_Transfer.rst:793 -#: 8347c97393fe47ea83c13f6777faa36c +#: ../../source/File_Transfer/File_Transfer.rst:884 +#: 87aaf0a5d3b44f41a419d97b6567f6d0 msgid "" -"All public APIs (including non-file-transfer methods) are listed below for " -"reference." +"All public APIs (including non-file-transfer methods) are listed below " +"for reference." msgstr "すべてのパブリック API (ファイル転送以外のメソッドを含む) を参考のために以下にリストします。" -#: ../../source/File_Transfer/File_Transfer.rst:797 -#: 5ac025a5e948425a9a430c7c75b045f9 +#: ../../source/File_Transfer/File_Transfer.rst:888 +#: a195ee393f2a442c810e59811a6ae126 msgid "### TCP_Server_Base Public APIs" msgstr "### TCP_Server_Base パブリック API" -#: ../../source/File_Transfer/File_Transfer.rst:799 -#: ddf4d1d8e04e40659404ebb55c843c41 +#: ../../source/File_Transfer/File_Transfer.rst:890 +#: 0408d74a9140472e9a774143a60e5749 msgid "``file_transfer_server_recv_client_start``" msgstr "``file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:800 -#: 052d49abc8514ed19346f7b023783fa9 +#: ../../source/File_Transfer/File_Transfer.rst:891 +#: 24a33cb212844e04a8a271ada32412f0 msgid "``file_transfer_server_recv_client_start_thread``" msgstr "``file_transfer_server_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:801 -#: 6db2d78cc0b94b4b93d6080164897079 +#: ../../source/File_Transfer/File_Transfer.rst:892 +#: 7e286d1ece6940868bea6b937486e617 msgid "``folder_file_transfer_server_recv_client_start``" msgstr "``folder_file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:802 -#: ec1b13e6e07449ec820d5cdc7a983048 +#: ../../source/File_Transfer/File_Transfer.rst:893 +#: 37fc5bd346c84415bb15138a42508fbe msgid "``multiple_file_multiple_client_transfer_server_recv_client_start``" msgstr "``multiple_file_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:803 -#: 7d780de964e543a8b703dd413d331c43 -msgid "" -"``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -msgstr "" -"「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start」" +#: ../../source/File_Transfer/File_Transfer.rst:894 +#: 38a2b16e3ab648688cf7e8d1cae8be72 +msgid "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" +msgstr "「diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start」" -#: ../../source/File_Transfer/File_Transfer.rst:804 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:895 +#: ad39bc6b71f048b09bca3b895e9d32f8 #, fuzzy msgid "" -"``file_folder_transfer_server_recv_server_start_thread`` (folder receiving)" +"``file_folder_transfer_server_recv_server_start_thread`` (folder " +"receiving)" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:806 -#: 02e685a79bc64a32ad888008a9dde074 +#: ../../source/File_Transfer/File_Transfer.rst:896 +#: ../../source/File_Transfer/File_Transfer.rst:916 +#: 37aeb9835435434881f94eb9951370d6 660ac3b979cc43d0beece659b9b0935f +msgid "``pause_trans`` / ``start_trans`` (hold and release an outbound transfer)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:897 +#: 7641e3ece9314197863d872836635218 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:898 +#: ../../source/File_Transfer/File_Transfer.rst:918 +#: 9c62709c2c06456dbfddee1f1ce6871e de496a0be32c490585ae0cbafc931a71 +msgid "``resume_transfers`` / ``resume_trans`` (continue interrupted transfers)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:900 +#: 11476e0eaa3b4a4286612812e4e2c004 msgid "" "(The low-level helpers ``file_transfer_server_recv_server_start``, " -"``file_transfer_mode_recv``, and ``file_transfer_mode`` are not considered " -"public but are documented for completeness.)" +"``file_transfer_mode_recv``, and ``file_transfer_mode`` are not " +"considered public but are documented for completeness.)" msgstr "" "(低レベルヘルパー " -"``file_transfer_server_recv_server_start``、``file_transfer_mode_recv``、および " -"``file_transfer_mode`` はパブリックとはみなされませんが、完全を期すために文書化されています。)" +"``file_transfer_server_recv_server_start``、``file_transfer_mode_recv``、および" +" ``file_transfer_mode`` はパブリックとはみなされませんが、完全を期すために文書化されています。)" -#: ../../source/File_Transfer/File_Transfer.rst:812 -#: 5193d200c3f245caae4095ab4114a467 +#: ../../source/File_Transfer/File_Transfer.rst:906 +#: 907e861cebe648fbacb799bae8bb15e0 msgid "### TCP_Client_Base Public APIs" msgstr "### TCP_Client_Base パブリック API" -#: ../../source/File_Transfer/File_Transfer.rst:814 -#: df25f04d660046669347072182ca0bde +#: ../../source/File_Transfer/File_Transfer.rst:908 +#: 88bd80083f754caeb026f9ce1b8c6b55 msgid "``file_transfer_client_recv_client_start``" msgstr "``file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:815 -#: 2a43c7e5134b4a64af241547e798bdf3 +#: ../../source/File_Transfer/File_Transfer.rst:909 +#: 3b21ff73da694465906482412b4fb4e3 msgid "``file_transfer_client_recv_client_start_thread``" msgstr "``file_transfer_client_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:816 -#: 6a88ac28f634410ab54d999291b5b309 +#: ../../source/File_Transfer/File_Transfer.rst:910 +#: c8af43896a2443a5b14bd29863731c2c msgid "``folder_file_transfer_client_recv_client_start``" msgstr "``folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:817 -#: 6d47f6da5f54475989d93fca0c141f2d +#: ../../source/File_Transfer/File_Transfer.rst:911 +#: 7a3d3e4a52334b169a62d3b30d7a3190 msgid "``multiple_file_transfer_client_recv_client_start``" msgstr "``multiple_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:818 -#: 06e20b477a9744de9f2d2efcf0fbf57f +#: ../../source/File_Transfer/File_Transfer.rst:912 +#: 19e18754c4674842ad5116f709588e03 msgid "``multiple_folder_file_transfer_client_recv_client_start``" msgstr "``multiple_folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:819 -#: a8dd89a54e0f498b88185761dc4c0f46 +#: ../../source/File_Transfer/File_Transfer.rst:913 +#: 4cf80f9f34e045c59a680d0450c9103a msgid "``file_transfer_client_recv_server_start``" msgstr "``file_transfer_client_recv_server_start``" -#: ../../source/File_Transfer/File_Transfer.rst:820 -#: 0811953096e94bd887990bb58d2de56a +#: ../../source/File_Transfer/File_Transfer.rst:914 +#: c09f5fcba03f461f89238dd31abf6e88 msgid "``file_transfer_client_recv_server_start_thread``" msgstr "``file_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:821 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:915 +#: ad39bc6b71f048b09bca3b895e9d32f8 msgid "``file_folder_transfer_client_recv_server_start_thread``" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:823 -#: bbbea73553dd4dfd98e0ee4076c1d42b +#: ../../source/File_Transfer/File_Transfer.rst:917 +#: 4b82ae9a067f46d5bb297431468a67a4 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:920 +#: 99140d0be72649199911a57a26e2f2cf msgid "(The low-level helpers are documented but not part of the public API.)" msgstr "(低レベルのヘルパーは文書化されていますが、パブリック API の一部ではありません。)" -#: ../../source/File_Transfer/File_Transfer.rst:827 -#: 56f1214838224007ade30eb34009810c +#: ../../source/File_Transfer/File_Transfer.rst:924 +#: 60355543ac904504af8529431ce2c1fa msgid "See Also" msgstr "関連項目" -#: ../../source/File_Transfer/File_Transfer.rst:829 -#: d513a2ce6fdf40eca5746ea840b4314f +#: ../../source/File_Transfer/File_Transfer.rst:926 +#: 7a5902ad3de64bf79d54d7f2f83ecbfb msgid "" -"For more information about the TCP server and client base classes, please " -"refer to:" +"For more information about the TCP server and client base classes, please" +" refer to:" msgstr "TCP サーバーおよびクライアントの基本クラスの詳細については、以下を参照してください。" -#: ../../source/File_Transfer/File_Transfer.rst:833 -#: 66b9f83c47d848779de9019a6f33c9a4 +#: ../../source/File_Transfer/File_Transfer.rst:930 +#: f10c29f467b849e8b4254998b44f99ba msgid ":doc:`../Network_APIs/TCP_Server_APIs`" msgstr ":doc:`../Network_APIs/TCP_Server_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:834 -#: 5cfe4f734d2043c2afe489c53c4ce963 +#: ../../source/File_Transfer/File_Transfer.rst:931 +#: 335ba244d28342449db065c252d7e14c msgid ":doc:`../Network_APIs/TCP_Client_APIs`" msgstr ":doc:`../Network_APIs/TCP_Client_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:836 -#: 47b4292bf8754c389fccf965d9b417d8 +#: ../../source/File_Transfer/File_Transfer.rst:933 +#: 92d0227c356447a098cba072d5b43c98 msgid "" "For details on port allocation, see the Port Allocation API sections in " "those documents." msgstr "ポート割り当ての詳細については、これらのドキュメントの「ポート割り当て API」セクションを参照してください。" #~ msgid "" -#~ "The protocol uses a set of predefined string constants, loaded from " +#~ "The protocol uses a set of " +#~ "predefined string constants, loaded from " #~ "``decode_command_table.json``:" #~ msgstr "このプロトコルは、「decode_command_table.json」からロードされた、事前定義された文字列定数のセットを使用します。" #~ msgid "" -#~ "``server_received_file_header_sign`` - sent by the receiver after it has " -#~ "successfully read the filename and file size." +#~ "``server_received_file_header_sign`` - sent by " +#~ "the receiver after it has successfully" +#~ " read the filename and file size." #~ msgstr "" #~ "``server_received_file_header_sign`` - " #~ "ファイル名とファイルサイズを正常に読み取った後に受信者によって送信されます。" #~ msgid "" -#~ "``server_received_file_data_sign`` - sent by the receiver after the complete" -#~ " file has been written to disk." +#~ "``server_received_file_data_sign`` - sent by " +#~ "the receiver after the complete file " +#~ "has been written to disk." #~ msgstr "" -#~ "``server_received_file_data_sign`` - 完全なファイルがディスクに書き込まれた後に受信者によって送信されます。" +#~ "``server_received_file_data_sign`` - " +#~ "完全なファイルがディスクに書き込まれた後に受信者によって送信されます。" #~ msgid "" -#~ "The client provides the following thread-safe methods for initiating " +#~ "The client provides the following " +#~ "thread-safe methods for initiating " #~ "transfers:" #~ msgstr "クライアントは、転送を開始するために次のスレッドセーフなメソッドを提供します。" #~ msgid "" -#~ "Each of these methods creates a new daemon thread that executes the actual " -#~ "worker function (the non-``_thread`` version). This prevents the console " +#~ "Each of these methods creates a " +#~ "new daemon thread that executes the " +#~ "actual worker function (the non-``_thread``" +#~ " version). This prevents the console " #~ "thread from being blocked." #~ msgstr "" #~ "これらの各メソッドは、実際のワーカー関数 (非 ``_thread`` バージョン) " @@ -1534,28 +1736,44 @@ msgstr "ポート割り当ての詳細については、これらのドキュメ #~ msgstr "``/file_folder <相対パス> <ファイル名>``" #~ msgid "" -#~ "For the multiple-item commands the destination is the last argument; when " -#~ "the last argument is an existing local file/folder it is treated as another " -#~ "item to transfer instead." +#~ "For the multiple-item commands the " +#~ "destination is the last argument; when" +#~ " the last argument is an existing " +#~ "local file/folder it is treated as " +#~ "another item to transfer instead." #~ msgstr "" #~ "複数項目のコマンドの場合、宛先は最後の引数です。最後の引数が既存のローカル " #~ "ファイル/フォルダーである場合、代わりに転送する別のアイテムとして扱われます。" #~ msgid "" -#~ "Sends multiple files to multiple clients. The message format is " -#~ "``/multiple_file_multiple_client ... " -#~ " ...``. Files must appear before clients." +#~ "Sends multiple files to multiple " +#~ "clients. The message format is " +#~ "``/multiple_file_multiple_client ..." +#~ " ...``. Files " +#~ "must appear before clients." #~ msgstr "" -#~ "複数のファイルを複数のクライアントに送信します。メッセージの形式は「/multiple_file_multiple_client " -#~ " ... ...」です。ファイルはクライアントの前に表示される必要があります。" +#~ "複数のファイルを複数のクライアントに送信します。メッセージの形式は「/multiple_file_multiple_client " +#~ " ... " +#~ " ...」です。ファイルはクライアントの前に表示される必要があります。" #~ msgid "" -#~ "Sends different file lists to different clients. The message alternates " -#~ "between groups: a list of files, then a list of client addresses, then the " -#~ "next list of files, etc. Example: ``/diff_multiple_file_diff_multiple_client" -#~ " a.txt b.txt (ip1,port1) (ip2,port2) c.txt (ip3,port3)``" +#~ "Sends different file lists to different" +#~ " clients. The message alternates between" +#~ " groups: a list of files, then " +#~ "a list of client addresses, then " +#~ "the next list of files, etc. " +#~ "Example: ``/diff_multiple_file_diff_multiple_client a.txt" +#~ " b.txt (ip1,port1) (ip2,port2) c.txt " +#~ "(ip3,port3)``" #~ msgstr "" #~ "異なるファイルリストを異なるクライアントに送信します。メッセージは、ファイルのリスト、クライアント " #~ "アドレスのリスト、次のファイルのリストなどのグループ間で交互に表示されます。 例: " -#~ "``/diff_multiple_file_diff_multiple_client a.txt b.txt (ip1,port1) " -#~ "(ip2,port2) c.txt (ip3,port3)``" +#~ "``/diff_multiple_file_diff_multiple_client a.txt b.txt " +#~ "(ip1,port1) (ip2,port2) c.txt (ip3,port3)``" + +#~ msgid "" +#~ "Low-level send function that connects" +#~ " to the receiver and transmits the" +#~ " file." +#~ msgstr "受信機に接続してファイルを送信する低レベルの送信機能。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/Instance_Setup/Instance_Setup.po b/docs/source/locale/ja/LC_MESSAGES/Instance_Setup/Instance_Setup.po index 7af98d6..f0a1865 100644 --- a/docs/source/locale/ja/LC_MESSAGES/Instance_Setup/Instance_Setup.po +++ b/docs/source/locale/ja/LC_MESSAGES/Instance_Setup/Instance_Setup.po @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,295 +18,296 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Instance_Setup/Instance_Setup.rst:3 -#: b4877074f48944ef95449bad6b451f04 +#: 552b0fbec3774a638b0029ce5fd72949 msgid "Flow Setup Launcher" msgstr "フローセットアップランチャー" #: ../../source/Instance_Setup/Instance_Setup.rst:5 -#: 745aff08935b4042b2885b7f10d524f1 +#: 31952c3324264ea28368c7725796ff63 #, fuzzy msgid "" "The ``flow_setup.py`` script is a launcher for the TCP server/client " -"framework defined in ``connect_tcp.py``. It spawns one or more server and " -"client instances, either interactively or from command-line arguments. Each " -"launched instance runs in its own terminal window (or a detached background " -"process on headless systems)." +"framework defined in ``connect_tcp.py``. It spawns one or more server and" +" client instances, either interactively or from command-line arguments. " +"Each launched instance runs in its own terminal window (or a detached " +"background process on headless systems)." msgstr "" "`flow_setup.py` スクリプトは、`connect_tcp.py` で定義された TCP サーバー/クライアント " "フレームワークのランチャーです。これにより、対話形式またはコマンドライン引数を介して、単一のサーバーまたはクライアント " -"インスタンスを迅速に生成できます。起動された各インスタンスは、個別のターミナル ウィンドウ (またはヘッドレス システムのバックグラウンド プロセス) " -"で実行されます。" +"インスタンスを迅速に生成できます。起動された各インスタンスは、個別のターミナル ウィンドウ (またはヘッドレス システムのバックグラウンド " +"プロセス) で実行されます。" #: ../../source/Instance_Setup/Instance_Setup.rst:13 -#: 5cfe71ed904f4f24bef1210b411ee40d +#: c8f9652279de42bb983523a15048596e msgid "Features" msgstr "特徴" #: ../../source/Instance_Setup/Instance_Setup.rst:15 -#: d5544e89cd884c938e1bfed52fdaf35a +#: 2bd321903dd94d9985805a44d9ef3d94 #, fuzzy msgid "" -"**Interactive mode** – step-by-step creation of server and client instances," -" plus a vim-style editor for changing or deleting the instances already " -"stored." +"**Interactive mode** – step-by-step creation of server and client " +"instances, plus a vim-style editor for changing or deleting the instances" +" already stored." msgstr "**対話型モード** – サーバーまたはクライアント インスタンスを段階的に作成します。" #: ../../source/Instance_Setup/Instance_Setup.rst:18 -#: a3239003782944f1aceb438c4b164657 +#: df9cbf9e1d024f9386a4b6278c82249e #, fuzzy msgid "" -"**Command-line mode** – launch one server or one client with all parameters " -"in one command." +"**Command-line mode** – launch one server or one client with all " +"parameters in one command." msgstr "**コマンドライン モード** – 1 つのコマンドですべてのパラメータを指定して起動します。" #: ../../source/Instance_Setup/Instance_Setup.rst:20 -#: 6c36fb284a4b4984bd220e047e26ed37 +#: b3406e8f62894233be438b7988e444da msgid "" -"**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser UI" -" of the ``transfer_web`` web tool." +"**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser" +" UI of the ``transfer_web`` web tool." msgstr "" "**ウェブツールモード** – ''-- web_server ''/''-- web_client ''は、'' transfer_web " "''ウェブツールのブラウザUIを起動します。" #: ../../source/Instance_Setup/Instance_Setup.rst:22 -#: 1a357d61f62b41dd91e150d24c323a98 +#: e359866c167e4e7ca5bf0791fd471ac4 msgid "" -"**Extension registration** – ``--add`` / ``--delete`` register or unregister" -" extension protocol files; the registered files are loaded on every launch." +"**Extension registration** – ``--add`` / ``--delete`` register or " +"unregister extension protocol files; the registered files are loaded on " +"every launch." msgstr "" "**拡張子登録** – ''-- add ''/''-- delete " "''拡張子プロトコルファイルの登録または登録解除。登録されたファイルはすべての起動時に読み込まれます。" #: ../../source/Instance_Setup/Instance_Setup.rst:25 -#: 0deeeb0bc12644eaab437361d69dbe77 +#: 5f7cba6df26144e9840d140f94065b33 #, fuzzy msgid "" "**Persistent configuration** – stores the latest instance definitions in " -"``setup.json`` (same directory as the script). Every entry is completed with" -" the full default parameter set of its type when it is saved." +"``setup.json`` (same directory as the script). Every entry is completed " +"with the full default parameter set of its type when it is saved." msgstr "" "**永続的な構成** – 最新のインスタンス定義を「setup.json」(スクリプトと同じディレクトリ) に保存します。各タイプ " "(サーバー/クライアント) は **1 つのみ** 構成を保持し、更新のたびに上書きされます。" #: ../../source/Instance_Setup/Instance_Setup.rst:29 -#: 0b60fca4ab384444a03750dcb790150f +#: b93809688cb74986ac64e4baceb9f0f6 msgid "" -"**Multiple instances** – the ``servers`` and ``clients`` lists may hold any " -"number of entries. Adding an entry identical to an existing one of the same " -"type is skipped; different entries are appended." +"**Multiple instances** – the ``servers`` and ``clients`` lists may hold " +"any number of entries. Adding an entry identical to an existing one of " +"the same type is skipped; different entries are appended." msgstr "" "**複数のインスタンス** " "–「サーバー」および「クライアント」リストには、任意の数のエントリを保持できます。同じタイプの既存のエントリと同じエントリを追加することはスキップされ、異なるエントリが追加されます。" #: ../../source/Instance_Setup/Instance_Setup.rst:33 -#: af8b8bdd4c994728a0bf4a7b358976b7 +#: be9bc008af594306be21e731d6aefee3 #, fuzzy msgid "" -"**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, xterm, " -"x-terminal-emulator, or a detached background process), and macOS " +"**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, " +"xterm, x-terminal-emulator, or a detached background process), and macOS " "(Terminal.app)." msgstr "" "**クロスプラットフォーム** – Windows (cmd)、Linux (gnome-" "terminal、xterm、またはバックグラウンド)、macOS (ターミナル.app) をサポートします。" #: ../../source/Instance_Setup/Instance_Setup.rst:36 -#: 4696d04613af4a1ea055df8be236adc3 +#: 57005cb0d04f47b2a8f10ad0bc9c7b43 #, fuzzy msgid "" "**Complete parameter support** – all parameters accepted by " -"``TCP_Server_Base`` and ``TCP_Client_Base`` can be stored in ``setup.json`` " -"for fine-tuning." +"``TCP_Server_Base`` and ``TCP_Client_Base`` can be stored in " +"``setup.json`` for fine-tuning." msgstr "" "**完全なパラメータのサポート** – ``TCP_Server_Base`` および ``TCP_Client_Base`` " "によって受け入れられるすべてのパラメータは、微調整のために ``setup.json`` に保存できます。" #: ../../source/Instance_Setup/Instance_Setup.rst:41 -#: 343fcd49c74b4cfd9d351f93c60e59bc +#: 2ff27919a6f64e8fb610158de5ffdf69 msgid "Usage" msgstr "使用法" #: ../../source/Instance_Setup/Instance_Setup.rst:44 -#: 7e39ebc551894366b757ddfb5c406753 +#: dddde4f2d7084bc48efa1296cfd3f22c msgid "Interactive Mode" msgstr "インタラクティブモード" #: ../../source/Instance_Setup/Instance_Setup.rst:46 -#: 5f7b3715a9524fa2a0aed70bbefc5008 +#: f060e64959674f52b223bbc4b01d568c msgid "Run the script without any arguments:" msgstr "引数なしでスクリプトを実行します。" #: ../../source/Instance_Setup/Instance_Setup.rst:52 -#: a17a608e2ac24987b6c4a428acd770e9 +#: 6bb60d44328244d4ab20f3ae5ba2b827 msgid "" "When ``setup.json`` already exists, the launcher first asks whether to " -"overwrite it, and the interactive collection itself asks whether the stored " -"instances should be edited:" +"overwrite it, and the interactive collection itself asks whether the " +"stored instances should be edited:" msgstr "" "'' setup.json " "''が既に存在する場合、ランチャーは最初にそれを上書きするかどうかを尋ね、インタラクティブコレクション自体は保存されたインスタンスを編集するかどうかを尋ねます。" #: ../../source/Instance_Setup/Instance_Setup.rst:56 -#: 7fe4792645644307bf450194c2d98fa7 +#: d247a8d3c3f1430c8dfa6dccad66da0a msgid "" -"``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` launches" -" every stored instance and exits; ``Y`` (or no existing file) continues to " -"the collection below." +"``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` " +"launches every stored instance and exits; ``Y`` (or no existing file) " +"continues to the collection below." msgstr "" "'' setup.jsonが存在します。構成データを上書きしますか? ( Y/N ) :''-'' N " "''は、保存されているすべてのインスタンスを起動して終了します。'' Y ''(または既存のファイルなし)は、以下のコレクションに続きます。" #: ../../source/Instance_Setup/Instance_Setup.rst:59 -#: e60cbc55c5834e8ab8ce55e696159e9a +#: 96169445a67545178cdd4b68ce5faae3 msgid "" -"``Delete or change existing instances or configs? (Y/N):`` – asked only when" -" stored instances exist. ``Y`` opens the instance editor (see below); ``N`` " -"keeps them and goes straight to the add flow." +"``Delete or change existing instances or configs? (Y/N):`` – asked only " +"when stored instances exist. ``Y`` opens the instance editor (see below);" +" ``N`` keeps them and goes straight to the add flow." msgstr "" -"''既存のインスタンスまたは設定を削除または変更しますか? (Y/N): '' –格納されているインスタンスが存在する場合にのみ尋ねられます。'' Y " -"''はインスタンスエディターを開きます(下記参照)。'' N ''はそれらを保持し、直接追加フローに進みます。" +"''既存のインスタンスまたは設定を削除または変更しますか? (Y/N): '' –格納されているインスタンスが存在する場合にのみ尋ねられます。''" +" Y ''はインスタンスエディターを開きます(下記参照)。'' N ''はそれらを保持し、直接追加フローに進みます。" #: ../../source/Instance_Setup/Instance_Setup.rst:63 -#: eaf7134992f44c58aa4181664a3bc638 +#: 80847dcc3e404a779b2e693cf8de50d5 #, fuzzy msgid "``Choose the type (0 for Server, 1 for Client)``." msgstr "タイプを選択します (サーバーの場合は 0、クライアントの場合は 1)。" #: ../../source/Instance_Setup/Instance_Setup.rst:64 -#: 6a5569dd541a4043802c5d85f125db64 +#: cebc8ba62d1a48a69d8019c3862dc18b msgid "Enter the bind address and port (``host:port``)." msgstr "バインドアドレスとポート (``host:port``) を入力します。" #: ../../source/Instance_Setup/Instance_Setup.rst:65 -#: e70e2b6322a04c748193e1cec4b0ee2c +#: 4311b66e1b974b4596f2693908ba3109 msgid "If Client, also enter the server address and port to connect to." msgstr "クライアントの場合は、接続するサーバーのアドレスとポートも入力します。" #: ../../source/Instance_Setup/Instance_Setup.rst:67 -#: df73da29736d4b878bef8427a95945aa +#: 3a5cff8b854c40939873ad57b060d9c3 msgid "" -"Decide whether to add another instance. An entry that already exists in the " -"list is not added again; a new one is appended, so several instances of the " -"same type can be kept side by side." -msgstr "" -"別のインスタンスを追加するかどうかを決定します。既にリストに存在するエントリは再度追加されません。新しいエントリが追加されるため、同じタイプの複数のインスタンスを並べて保持できます。" +"Decide whether to add another instance. An entry that already exists in " +"the list is not added again; a new one is appended, so several instances " +"of the same type can be kept side by side." +msgstr "別のインスタンスを追加するかどうかを決定します。既にリストに存在するエントリは再度追加されません。新しいエントリが追加されるため、同じタイプの複数のインスタンスを並べて保持できます。" #: ../../source/Instance_Setup/Instance_Setup.rst:71 -#: 8e0df08f751f46deb43ba1006ed04b20 +#: 7c893e0f8399455ba1b14d9c796d75a8 msgid "" "After editing, the launcher asks ``Add new instances? (Y/N)`` before " "returning to the add flow." msgstr "編集後、ランチャーは「新しいインスタンスを追加しますか?」と尋ねます。(Y/N )''から追加フローに戻ります。" #: ../../source/Instance_Setup/Instance_Setup.rst:74 -#: 237874cb10d040cf86074695574daf32 +#: 49c58d9bb0b1440485f3cbecdb2843d6 msgid "" -"When the editor is left with changes, ``setup.json`` is rewritten with every" -" instance, and all stored instances (reused plus newly added) are launched." +"When the editor is left with changes, ``setup.json`` is rewritten with " +"every instance, and all stored instances (reused plus newly added) are " +"launched." msgstr "" "エディターに変更が残されると、'' setup.json " "''はすべてのインスタンスで書き換えられ、格納されているすべてのインスタンス(再利用されたインスタンスと新しく追加されたインスタンス)が起動されます。" #: ../../source/Instance_Setup/Instance_Setup.rst:79 -#: c81a1dba5f224291a56257375f84a1a0 +#: a1e74fd1f7f04e548b268c3dc0d6763e msgid "Global commands" msgstr "グローバルコマンド" #: ../../source/Instance_Setup/Instance_Setup.rst:81 -#: 8247157dfc0b4a32aa9ae300813386c6 +#: b8ede51e5254499e9dd613bc93db15ca msgid "" -"The following words can be typed at **every** prompt, including field-value " -"prompts:" +"The following words can be typed at **every** prompt, including field-" +"value prompts:" msgstr "次の単語は、フィールド値プロンプトを含む**すべての**プロンプトで入力できます。" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command" msgstr "コマンド" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: c29ffb659bf3446490bc9eaac6f2e7ea +#: c2b850e77d9b44559be9b25d93611a70 msgid "Effect" msgstr "効果" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``Help``" msgstr "ヘルプ" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 886877e3eb7d407fa62b16a4fc968f62 +#: 200a2a3be7ea46b291882aef0b8d9031 msgid "Print the usage text of the current prompt." msgstr "現在のプロンプトの使用状況テキストを印刷します。" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: c569666357334b05ba4189c122bbeaaf +#: a6ce48cd04e04b3ea42ad16e04e37359 msgid "``Fix_Config``" msgstr "'' Fix_Config ''" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: 0a5c8bdb9c1d4f7eb8a41fce85acf0b4 -msgid "" -"Jump to the instance editor (or, inside it, save and return to the list)." +#: fcd62172378d4da498de2a21a03f97a0 +msgid "Jump to the instance editor (or, inside it, save and return to the list)." msgstr "インスタンスエディターにジャンプします(または、その中に保存してリストに戻ります)。" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 #, fuzzy msgid "``Setup``" msgstr "''-- setup_num ''" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "" "Launch every instance configured in ``setup.json`` and exit the setup " "program." msgstr "'' setup.json ''で構成されているすべてのインスタンスを起動し、セットアッププログラムを終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: cc2a8285cba3495db468d5f007f3ecfc +#: 85343de947b74e3b97e4c59109ebcd9e msgid "``Add_Extension``" msgstr "拡張子を追加" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: a6c3fac6c8f44d75a7a266bae3c54729 +#: 6b8af44d732b4673afbc2f9cbec357d3 msgid "Prompt for extension file path(s) and register them." msgstr "拡張子ファイルのパスを入力して登録します。" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 4febe01e668f4cc1aa1b92e328780ebe +#: a35baf4ca7d949eba92cf6c6279c9cd2 msgid "``Delete_Extension``" msgstr "拡張子を削除" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 5e54a7238b604a5fbe930ff4c5fd05d5 +#: d6f9495c1ad046d5877eb8159799ae88 msgid "Prompt for registered extension path(s) to remove." msgstr "登録されている拡張パスを削除するように求めます。" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 88bb1def13564b809d980ac0d7f22832 +#: 7c985bf621ba4fbeaa8f25042d47ed95 msgid "``Quit``" msgstr "終了" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 22644327258c472aab543baf2ee08784 +#: 18f32c4c66094837a84906ba56ef236d msgid "Exit the setup program immediately." msgstr "すぐにセットアッププログラムを終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:103 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Instance editor" msgstr "インスタンスエディター" #: ../../source/Instance_Setup/Instance_Setup.rst:105 -#: 5832e770c51e4e61b0a372086616ad57 +#: 021cb4d2e2234dff8a9b206826926e33 msgid "" "The editor is reached by typing ``Fix_Config`` (at any prompt) or by " -"answering ``Y`` to the \"Delete or change existing instances\" question. On " -"an interactive terminal it reads real keys (and enables mouse tracking); on " -"a pipe or in tests it falls back to line commands. ``j``/``k`` or the arrow " -"keys move the selection, a mouse click selects the clicked instance, " -"``Enter`` or a double click opens that instance's config editor, and " -"``Delete``/``Backspace`` or ``dd`` deletes the selected instance." +"answering ``Y`` to the \"Delete or change existing instances\" question. " +"On an interactive terminal it reads real keys (and enables mouse " +"tracking); on a pipe or in tests it falls back to line commands. " +"``j``/``k`` or the arrow keys move the selection, a mouse click selects " +"the clicked instance, ``Enter`` or a double click opens that instance's " +"config editor, and ``Delete``/``Backspace`` or ``dd`` deletes the " +"selected instance." msgstr "" "エディタにアクセスするには、(任意のプロンプトで)「Fix_Config」と入力するか、「既存のインスタンスの削除または変更」の質問に「Y」と回答します。インタラクティブ端末では、実際のキーを読み取り(マウストラッキングを有効にします)、パイプまたはテストではラインコマンドにフォールバックします。''" " j ''/'' k ''または矢印キーが選択範囲を移動すると、マウスクリックでクリックされたインスタンスが選択され、'' Enter " @@ -314,37 +315,37 @@ msgstr "" "''は選択したインスタンスを削除します。" #: ../../source/Instance_Setup/Instance_Setup.rst:115 -#: 36e871e8b76b4e6f8ab3d41c6e58e053 +#: be9f3fe33bf943419ada71d457c635e1 msgid "Vim-style commands:" msgstr "Vimスタイルのコマンド:" #: ../../source/Instance_Setup/Instance_Setup.rst:117 -#: bf18c8047500461486e3bc05c6154ecc +#: f11526b8f13f4f6eabba91f7543c7120 msgid "``:w`` – write ``setup.json`` without leaving the editor." msgstr "'': w '' –エディターを離れることなく'' setup.json ''を書き込みます。" #: ../../source/Instance_Setup/Instance_Setup.rst:118 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "``:wq`` – write ``setup.json`` and leave the editor." msgstr "'': wq '' – '' setup.json ''と書き、エディターを終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:119 -#: 8e54b99375e441308cd3dc8ec4cd5d3a +#: 740d1745df7841a59959dbdab98a73b4 msgid "``:q`` – leave; refused while there are unsaved changes." msgstr "'': q '' –離脱。保存されていない変更がある間、拒否されました。" #: ../../source/Instance_Setup/Instance_Setup.rst:120 -#: 32cdc0d2f2f34602a77b692202f56b24 +#: 944a89864f5c46c488287ee0740d83d5 msgid "``:q!`` – leave and discard all changes." msgstr "'': q !'' –すべての変更を残して破棄します。" #: ../../source/Instance_Setup/Instance_Setup.rst:121 -#: 7360415b19b04c13ab167e500f3437ac +#: 927b5a52f9454d65af949f5cc188e33d msgid "``Quit`` – exit the setup program immediately." msgstr "''終了'' –すぐにセットアッププログラムを終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:123 -#: aea22c0686c64df8bc842a51fbd2d67e +#: d4163489911a454f9e4fd1b6cdd1de5a msgid "" "Inside the config editor, ``j``/``k`` move between fields, ``Esc`` or " "``back`` returns to the list, and a field index or ``Enter`` edits the " @@ -354,260 +355,262 @@ msgid "" "``client_port``, ``timeout``, ``is_custom_keys``)." msgstr "" "コンフィグエディタ内では、'' j ''/'' k ''がフィールド間を移動し、'' Esc ''または'' Back " -"''がリストに戻り、フィールドインデックスまたは'' Enter ''が選択したフィールドを編集します。空の入力は現在の値を保持します。ブール値は'' " -"true ''/'' false ''/'' 1 ''/'' 0 ''/'' y ''/'' n ''を受け入れ、整数は'' int " -"()''で解析され、単語'' none ''はnull許容フィールド('' host ''、'' client_port ''、'' timeout " -"''、'' is_custom_keys '')をリセットします。" +"''がリストに戻り、フィールドインデックスまたは'' Enter " +"''が選択したフィールドを編集します。空の入力は現在の値を保持します。ブール値は'' true ''/'' false ''/'' 1 ''/''" +" 0 ''/'' y ''/'' n ''を受け入れ、整数は'' int ()''で解析され、単語'' none " +"''はnull許容フィールド('' host ''、'' client_port ''、'' timeout ''、'' " +"is_custom_keys '')をリセットします。" #: ../../source/Instance_Setup/Instance_Setup.rst:132 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command‑line Mode" msgstr "コマンドラインモード" #: ../../source/Instance_Setup/Instance_Setup.rst:134 -#: 19ffa2fc838a441786de354b2a574153 +#: d798ec606de2454da5f10e9d0a7e677c msgid "Use the following options:" msgstr "次のオプションを使用します。" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: c6dc291839964e119fb50574caedfd9c +#: 4d5c1aebbede473c8598cbc45f8deb20 msgid "Option" msgstr "オプション" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: 4a498223c2cb4e45914dcd53bb7f2f12 +#: a50ba126b168482997fae00497252fd4 msgid "Description" msgstr "内容" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: 649f1c33bb9d4afa89d1796bef081ddf +#: 7755904907ee46f6a34144360ed876f7 #, python-brace-format msgid "``--type {0,1}``" msgstr "''-- type {0,1 }''" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: f0793c0f15584b42bc66b82e672854b5 +#: 0175b3fbf31e44829a685a07be420436 msgid "" -"0 = Server, 1 = Client. Required for a plain command-line launch; without it" -" the launcher runs interactively." -msgstr "" -"0 =サーバー、1 =クライアント。通常のコマンドライン起動に必要です。コマンドラインなしでは、ランチャーはインタラクティブに実行されます。" +"0 = Server, 1 = Client. Required for a plain command-line launch; without" +" it the launcher runs interactively." +msgstr "0 =サーバー、1 =クライアント。通常のコマンドライン起動に必要です。コマンドラインなしでは、ランチャーはインタラクティブに実行されます。" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--setup_addr_port``" msgstr "''-- setup_addr_port ''" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 58e47d807455460fb6e76d76b836bc30 +#: b7962f6d3a194e3eb91915d5681a2b7b #, fuzzy -msgid "" -"Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." +msgid "Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." msgstr "バインドアドレスとポート (``host:port``) を入力します。" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 31efc70f958b4608b07bc24eb1ec633b +#: 388a3dd952ac47a78598792ef7d587bc msgid "``--connect_addr_port``" msgstr "''-- connect_addr_port ''" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 041b4144717b4f54ad1b24d06726293b +#: 7d96425a64374a36a457a9167fc6d39c msgid "" "Server address and port to connect to. Required for Client; rejected in " "Server mode." msgstr "接続先のサーバーアドレスとポート。クライアントに必要です。サーバーモードで拒否されました。" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``--setup_num``" msgstr "''-- setup_num ''" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 139258adce2844a28d57733bb973ec1e +#: 26698837fb26457ba9674e8ccf0cf881 msgid "" -"Number of instances to launch. Only 1 is allowed; a larger value is accepted" -" but ignored with a warning." +"Number of instances to launch. Only 1 is allowed; a larger value is " +"accepted but ignored with a warning." msgstr "起動するインスタンスの数。許可されているのは1だけです。より大きな値は受け入れられますが、警告付きで無視されます。" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_server``" msgstr "Web サーバー" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 108977e4c89b442488c39cad5378e8e5 +#: 9b1821de6d0f4c4d9af6c4e47eab4e5d msgid "" "Launch the ``transfer_web`` server tool (browser UI) instead of a TCP " "instance." msgstr "TCPインスタンスの代わりに'' transfer_web ''サーバーツール(ブラウザーUI)を起動します。" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_client``" msgstr "Webクライアント" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 99410d7adbc749e2bee7ff014945d19b +#: 91fa396110c94aa9a29f0a569763e030 msgid "" "Launch the ``transfer_web`` client tool (browser UI) instead of a TCP " "instance." msgstr "TCPインスタンスの代わりに'' transfer_web ''クライアントツール(ブラウザUI)を起動します。" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: 5de4064738ce4d529c9df9d1da98a556 +#: 118dce4ec3934bd4b5bb6e7b1aa31bf0 msgid "``--add PATH [PATH ...]``" msgstr "''-- add PATH [PATH... ]''" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: be6adb7451d84f9f934044d2891cc4db +#: 2a630e280d3040d6a78cd865dd3e2ae7 msgid "Register extension protocol file(s), then exit." msgstr "拡張プロトコルファイルを登録し、終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 58e2f444f8394dd5a5c41b400675c736 +#: c505cbcf44104e6799bfcb83251c2f72 msgid "``--delete PATH [PATH ...]``" msgstr "''--パス[パス...]を削除''" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 638774f6e42549ad88f930e50a2c3cad +#: 74b797d0ddf046d3b1dda4eea01013b7 msgid "Unregister extension protocol file(s), then exit." msgstr "拡張プロトコルファイルの登録を解除し、終了します。" #: ../../source/Instance_Setup/Instance_Setup.rst:167 -#: e9b3cc31339a4f318337e8c68cc61fd5 +#: 54c5d51b3cb841ceaefda13a7613a8ae msgid "" "A command-line launch replaces ``setup.json`` with the single launching " "instance, so any other stored instance is dropped." -msgstr "" -"コマンドライン起動は、'' setup.json ''を単一の起動インスタンスに置き換えるため、他の保存されたインスタンスはドロップされます。" +msgstr "コマンドライン起動は、'' setup.json ''を単一の起動インスタンスに置き換えるため、他の保存されたインスタンスはドロップされます。" #: ../../source/Instance_Setup/Instance_Setup.rst:171 -#: 327a63e83b8f4df9af4a5e6a32e2ce6e +#: 99952fa68b694654b82a309a26419152 msgid "Examples" msgstr "例" #: ../../source/Instance_Setup/Instance_Setup.rst:173 -#: c03b73272d554d1a885a04e6470d43c9 +#: 9c77e76f40a940e99e754d27e3bc1b05 msgid "**Launch a single server** on ``127.0.0.1:8000``:" msgstr "**「127.0.0.1:8000」で単一サーバーを起動**:" #: ../../source/Instance_Setup/Instance_Setup.rst:179 -#: 69edc9f7ea534c00bdaab2a4c84ef2cf +#: 37df8730dce9408a87ba48b775eb2b0a msgid "" "**Launch a client** bound to port ``9000``, connecting to a server at " "``127.0.0.1:8000``:" msgstr "**ポート ``9000`` にバインドされたクライアントを起動**し、 ``127.0.0.1:8000`` のサーバーに接続します。" #: ../../source/Instance_Setup/Instance_Setup.rst:186 -#: afc6f0adaafd49009ee96e36393060cd -msgid "" -"**Launch from an existing configuration** (if ``setup.json`` is present):" +#: 0bdae3cd584e464ab526840aa032e3a4 +msgid "**Launch from an existing configuration** (if ``setup.json`` is present):" msgstr "**既存の設定から起動** (setup.json が存在する場合):" #: ../../source/Instance_Setup/Instance_Setup.rst:193 -#: f2fd3c19413a4e6abb4b18037a347443 +#: 0538ca5ad181412c9136f318be43dfa0 msgid "**Launch the web tool** instead of a TCP instance:" msgstr "TCPインスタンスの代わりに** Webツールを起動**します。" #: ../../source/Instance_Setup/Instance_Setup.rst:200 -#: 71feceacd5b94bd98ce1973f45c16df1 +#: 4a43a3b821764068aaa05c153037208f msgid "**Register an extension protocol file**:" msgstr "**拡張プロトコルファイルを登録**:" #: ../../source/Instance_Setup/Instance_Setup.rst:207 -#: 00dff5a17f42419585f498c51f7fcc97 +#: ff45af42eb7d4d3faa8640a18bfd61f6 msgid "Configuration File" msgstr "設定ファイル" #: ../../source/Instance_Setup/Instance_Setup.rst:209 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "" "The script writes a file named ``setup.json`` in the same directory. Its " "structure is:" msgstr "スクリプトは同じディレクトリに「setup.json」という名前のファイルを書き込みます。その構造は次のとおりです。" #: ../../source/Instance_Setup/Instance_Setup.rst:233 -#: 82c31bcb59fc481eaa532d1a0696ed8d +#: b0129978b1a9468188663a40126df876 +#, fuzzy msgid "" -"**Both lists may contain any number of objects.** Every entry is completed " -"with the default value of each parameter that the entry does not set. The " -"stored server entry therefore carries ``host``, ``port``, ``max_clients``, " -"``port_add_step``, ``port_range_num``, ``max_file_transfer_thread_num``, " -"``is_hand_alloc_port``, ``is_input_command_in_console``, " -"``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_asynic_clients_io``, ``is_debug``" -" and ``is_print_log``; the client entry carries ``host``, ``client_host``, " +"**Both lists may contain any number of objects.** Every entry is " +"completed with the default value of each parameter that the entry does " +"not set. The stored server entry therefore carries ``host``, ``port``, " +"``max_clients``, ``port_add_step``, ``port_range_num``, " +"``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " +"``is_input_command_in_console``, ``max_custom_workers``, " +"``is_extend_command``, ``is_enable_encrypto``, ``is_custom_keys``, " +"``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_asynic_clients_io``, ``is_debug`` and " +"``is_print_log``; the client entry carries ``host``, ``client_host``, " "``port``, ``client_port``, ``timeout``, ``port_add_step``, " "``max_thread_num``, ``is_input_command_in_console``, ``is_wait_server``, " "``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_debug`` and ``is_print_log``." +"``is_custom_keys``, ``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_debug`` and ``is_print_log``." msgstr "" "**両方のリストには、任意の数のオブジェクトを含めることができます。**すべてのエントリは、エントリが設定されていない各パラメータのデフォルト値で完了します。したがって、格納されたサーバーエントリは、''" -" host ''、'' port ''、'' max_clients ''、'' port_add_step ''、'' port_range_num " -"''、'' max_file_transfer_thread_num ''、'' is_hand_alloc_port ''、'' " -"is_input_command_in_console ''、'' max_custom_workers ''、'' is_extend_command" -" ''、'' is_enable_encrypto ''、'' is_custom_keys ''、 '' max_mem_buff ''、'' " -"is_asynic_clients_io ''、'' is_debug ''および'' is_print_log ''。クライアントエントリには、'' " -"host ''、'' client_host ''、'' port ''、'' client_port ''、'' timeout ''、'' " -"port_add_step ''、'' max_thread_num ''、'' is_input_command_in_console ''、'' " -"is_wait_server ''、'' max_custom_workers ''、'' is_extend_command ''、'' " -"is_enable_encrypto ''、'' is_custom_keys ''、'' max_mem_buff ''、'' is_debug " -"''および'' is_print_log ''が含まれます。" - -#: ../../source/Instance_Setup/Instance_Setup.rst:251 -#: 8ffd3b4e6719464cbd48a2b20d5764f2 +" host ''、'' port ''、'' max_clients ''、'' port_add_step ''、'' " +"port_range_num ''、'' max_file_transfer_thread_num ''、'' " +"is_hand_alloc_port ''、'' is_input_command_in_console ''、'' " +"max_custom_workers ''、'' is_extend_command ''、'' is_enable_encrypto ''、''" +" is_custom_keys ''、 '' max_mem_buff ''、'' is_asynic_clients_io ''、'' " +"is_debug ''および'' is_print_log ''。クライアントエントリには、'' host ''、'' client_host " +"''、'' port ''、'' client_port ''、'' timeout ''、'' port_add_step ''、'' " +"max_thread_num ''、'' is_input_command_in_console ''、'' is_wait_server " +"''、'' max_custom_workers ''、'' is_extend_command ''、'' is_enable_encrypto" +" ''、'' is_custom_keys ''、'' max_mem_buff ''、'' is_debug ''および'' " +"is_print_log ''が含まれます。" + +#: ../../source/Instance_Setup/Instance_Setup.rst:252 +#: 8731a083a201487bb579beb4a238a0db msgid "Custom Parameters" msgstr "カスタムパラメータ" -#: ../../source/Instance_Setup/Instance_Setup.rst:253 -#: 284b4f1899d94269a530dec33958d0c8 +#: ../../source/Instance_Setup/Instance_Setup.rst:254 +#: 8910f94645f54874893c20f724780cbd msgid "" "You may edit ``setup.json`` by hand (or change the same fields in the " -"instance editor) to give any parameter accepted by ``TCP_Server_Base`` or " -"``TCP_Client_Base`` a non-default value. Custom values of an existing entry " -"survive later interactive runs, because the launcher loads the existing " -"entries and merges the defaults underneath them. A **command-line** launch " -"does not: it builds the new instance from ``host``/``port`` (and, for a " -"client, the connect address) only and rewrites ``setup.json`` from that, so " -"hand-written extra keys are lost." +"instance editor) to give any parameter accepted by ``TCP_Server_Base`` or" +" ``TCP_Client_Base`` a non-default value. Custom values of an existing " +"entry survive later interactive runs, because the launcher loads the " +"existing entries and merges the defaults underneath them. A **command-" +"line** launch does not: it builds the new instance from ``host``/``port``" +" (and, for a client, the connect address) only and rewrites " +"``setup.json`` from that, so hand-written extra keys are lost." msgstr "" "'' setup.json ''を手動で編集(またはインスタンスエディタで同じフィールドを変更)して、'' TCP_Server_Base " "''または'' TCP_Client_Base " "''で受け入れられたパラメータにデフォルト値以外の値を与えることができます。既存のエントリのカスタム値は、ランチャーが既存のエントリを読み込み、その下の既定値をマージするため、後で対話型実行されても存続します。**コマンドライン**の起動はそうではありません。新しいインスタンスを''ホスト''/''ポート''からビルドします(そして、クライアントの場合、" " connect address)のみを使用して'' setup.json ''を書き換えるため、手書きの余分なキーが失われます。" -#: ../../source/Instance_Setup/Instance_Setup.rst:264 -#: 3746b90215c84dc38c8ca2bb20d396f6 +#: ../../source/Instance_Setup/Instance_Setup.rst:265 +#: c62b1bfe8ceb40f8865a34ac87b4ba18 msgid "Extension Protocols and Startup Mode" msgstr "拡張プロトコルと起動モード" -#: ../../source/Instance_Setup/Instance_Setup.rst:266 -#: 4c6e6cc80e9c4ce3afe79fad55a2815a +#: ../../source/Instance_Setup/Instance_Setup.rst:267 +#: e6a7dcb4ea184e828e6667ae6505d872 msgid "" -"Two extension protocols ship with the launcher and are loaded automatically " -"for every instance whose ``setup.json`` entry sets " +"Two extension protocols ship with the launcher and are loaded " +"automatically for every instance whose ``setup.json`` entry sets " "``is_extend_command=True``:" msgstr "" -"ランチャーには 2 つの拡張プロトコルが同梱されており、``setup.json`` のエントリで ``is_extend_command=True``" -" が設定されているすべてのインスタンスに自動的にロードされます:" +"ランチャーには 2 つの拡張プロトコルが同梱されており、``setup.json`` のエントリで " +"``is_extend_command=True`` が設定されているすべてのインスタンスに自動的にロードされます:" -#: ../../source/Instance_Setup/Instance_Setup.rst:270 -#: 2d05270538524347899b403011286dcc +#: ../../source/Instance_Setup/Instance_Setup.rst:271 +#: 7159f768fc9a4ac199bfe0a4d8478fba #, fuzzy msgid "" "``command_control_extension_tcp.py`` – remote command execution with per-" -"client log collection (``/command``, with the ``/command_done`` completion " -"report)." +"client log collection (``/command``, with the ``/command_done`` " +"completion report)." msgstr "" "- ``command_control_extension_tcp.py`` – クライアントごとのログ収集を伴うリモートコマンド実行 " "(``/command``)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:273 -#: 1540ce3848be4d519034dd90e1d27fdd +#: ../../source/Instance_Setup/Instance_Setup.rst:274 +#: d2d277053c74470abc949b891493a5f0 #, fuzzy msgid "" -"``forward_extension_tcp.py`` – forwarding messages, files, multiple files, " -"folders and multiple folders to any number of destination clients " +"``forward_extension_tcp.py`` – forwarding messages, files, multiple " +"files, folders and multiple folders to any number of destination clients " "(``/file_forward``, ``/multiple_file_forward``, ``/folder_forward``, " "``/multiple_folder_forward`` on the client, and the ``/forward_file`` / " "``/forward_folder`` relays on the server)." @@ -616,76 +619,76 @@ msgstr "" "メッセージ、ファイル、複数のファイル、フォルダー、および複数のフォルダーを任意の数の宛先クライアントに転送します " "(`/send_msg_forward`、`/file_forward`、`/multiple_file_forward`、`/folder_forward`、`/multiple_folder_forward`)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:281 -#: 92e914da56f1402e85ef75819caf5b3f +#: ../../source/Instance_Setup/Instance_Setup.rst:282 +#: a8194174e5fd4dcf87ede716eaada9a4 msgid "" "Plain-message forwarding is native to the TCP protocol (no extension " -"needed): the client-only command ``/forward_send_msg`` relays messages to " -"the listed destination clients through the server." +"needed): the client-only command ``/forward_send_msg`` relays messages to" +" the listed destination clients through the server." msgstr "" -"プレーンメッセージ転送はTCPプロトコルにネイティブです(拡張子は必要ありません)。クライアント専用コマンド''/ forward_send_msg " -"''は、サーバーを介してリストされた宛先クライアントにメッセージをリレーします。" +"プレーンメッセージ転送はTCPプロトコルにネイティブです(拡張子は必要ありません)。クライアント専用コマンド''/ " +"forward_send_msg ''は、サーバーを介してリストされた宛先クライアントにメッセージをリレーします。" -#: ../../source/Instance_Setup/Instance_Setup.rst:286 -#: 836d703843ed4940a42f3b7a0c36b78e +#: ../../source/Instance_Setup/Instance_Setup.rst:287 +#: 98297b76f3404736b92b6c507726a50a #, fuzzy msgid "" "With ``is_extend_command=False`` (the default) the raw TCP protocol is " "started without these two built-in extensions." msgstr "``is_extend_command=False`` (デフォルト) の場合、生の TCP プロトコルのみが起動されます。" -#: ../../source/Instance_Setup/Instance_Setup.rst:289 -#: 3849c157ba79441e8406bcf9a4fc7695 +#: ../../source/Instance_Setup/Instance_Setup.rst:290 +#: fbbe2f02d9174359baca2c685704b475 msgid "" "Independently of ``is_extend_command``, every launch also loads the " -"extension protocol files registered in ``PyFlow/added_extensions.json`` (see" -" ``--add`` / ``Add_Extension`` above) via " +"extension protocol files registered in ``PyFlow/added_extensions.json`` " +"(see ``--add`` / ``Add_Extension`` above) via " "``add_extension.load_registered_extensions``." msgstr "" "'' is_extend_command ''とは別に、すべての起動は'' " "add_extension.load_registered_extensions ''を介して'' " -"PyFlow/added_extensions.json ''に登録された拡張プロトコルファイルも読み込みます(上記の''-- add ''/'' " -"Add_Extension ''を参照)。" +"PyFlow/added_extensions.json ''に登録された拡張プロトコルファイルも読み込みます(上記の''-- add ''/''" +" Add_Extension ''を参照)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:295 -#: fef96f9c96c64f6690b54175c7e7830d +#: ../../source/Instance_Setup/Instance_Setup.rst:296 +#: 9b5ab0319a9843f1b39721d3a96d1777 msgid "" "The ``is_input_command_in_console`` flag selects how the instance is " "started:" msgstr "``is_input_command_in_console`` フラグは、インスタンスの起動方法を選択します:" -#: ../../source/Instance_Setup/Instance_Setup.rst:298 -#: 407ae406135b42b3a6efd4ba5242b296 +#: ../../source/Instance_Setup/Instance_Setup.rst:299 +#: 1ec730c995b1454da1b208331d9ca8fe #, fuzzy msgid "" -"``True`` (default) – the instance's own start method (``start_TCP_Server()``" -" / ``start_TCP_client()``) runs and keeps its console input loop in the " -"foreground." +"``True`` (default) – the instance's own start method " +"(``start_TCP_Server()`` / ``start_TCP_client()``) runs and keeps its " +"console input loop in the foreground." msgstr "" "'' True '' (デフォルト) – '' START_TCP_SERVER ()''/'' START_TCP_CLIENT " "()''が直接呼び出され、コンソール入力ループは独自のスレッドで実行されます。" -#: ../../source/Instance_Setup/Instance_Setup.rst:301 -#: 1e10d27ee5c04d69ac9de20031a68b31 +#: ../../source/Instance_Setup/Instance_Setup.rst:302 +#: 3cfb2eba312943cea85388f4e9faf40d #, fuzzy msgid "" -"``False`` – the instance is started in a background thread and the launcher " -"keeps the process alive until the instance stops (useful for headless " -"deployments)." +"``False`` – the instance is started in a background thread and the " +"launcher keeps the process alive until the instance stops (useful for " +"headless deployments)." msgstr "" "``start_TCP_client()`` が直接呼び出され、コンソール入力ループは独自のスレッドで実行されます。 - ``False`` – " "インスタンスはバックグラウンド スレッドで実行され、ランチャーはインスタンスが停止するまでプロセスを維持します (ヘッドレス展開に便利)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:305 -#: 3743e0549b4449008324f68e282a0d81 +#: ../../source/Instance_Setup/Instance_Setup.rst:306 +#: 3b3482fa903f4afd81234e588a229c1f #, fuzzy msgid "" "Both extensions also expose injectable registration " -"(``setup_server_commands(server)`` / ``setup_client_commands(client)``) and " -"a convenience ``client_setup(instance=None, " +"(``setup_server_commands(server)`` / ``setup_client_commands(client)``) " +"and a convenience ``client_setup(instance=None, " "is_input_command_in_console=True)`` / ``server_setup(instance=None, " -"is_input_command_in_console=True)`` that accepts an existing instance, so " -"several extensions can be loaded onto the same instance from code." +"is_input_command_in_console=True)`` that accepts an existing instance, so" +" several extensions can be loaded onto the same instance from code." msgstr "" "両方の拡張機能は、注入可能な登録 (``setup_server_commands(instance)`` / " "``setup_client_commands(instance)``) と、既存のインスタンスを受け入れる便利な " @@ -693,58 +696,61 @@ msgstr "" "``server_setup(instance=None, is_input_command_in_console=True)`` " "も公開しているため、コードから複数の拡張機能を同じインスタンスにロードできます。" -#: ../../source/Instance_Setup/Instance_Setup.rst:314 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: ../../source/Instance_Setup/Instance_Setup.rst:315 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Internal Operation" msgstr "内部操作" -#: ../../source/Instance_Setup/Instance_Setup.rst:316 -#: 4ca266ef495b4a61bce44251b65f8c91 +#: ../../source/Instance_Setup/Instance_Setup.rst:317 +#: 8870bc6b731d40a095a40faed0c8f16d #, fuzzy msgid "" -"Each instance is launched in a new terminal window (or background process)." +"Each instance is launched in a new terminal window (or background " +"process)." msgstr "各インスタンスは新しいターミナル ウィンドウで起動されます" -#: ../../source/Instance_Setup/Instance_Setup.rst:318 -#: 2b6246012ce84ec0945a9245b208ae95 +#: ../../source/Instance_Setup/Instance_Setup.rst:319 +#: 13c720a93ba54e8ca330fce3a078bb5b #, fuzzy msgid "" "The configuration is passed via a temporary JSON file to avoid shell " "escaping issues." msgstr "設定は一時的な JSON 経由で渡されます" -#: ../../source/Instance_Setup/Instance_Setup.rst:320 -#: e40392b9adef407ca3ade4bf2d252190 +#: ../../source/Instance_Setup/Instance_Setup.rst:321 +#: 9566eb3cb70e4b77bcbdb584f7e0b6fc #, fuzzy msgid "" -"If an instance fails to start, the error is displayed and the window pauses " -"for inspection." +"If an instance fails to start, the error is displayed and the window " +"pauses for inspection." msgstr "と表示され、検査のためにウィンドウが一時停止します。" -#: ../../source/Instance_Setup/Instance_Setup.rst:324 -#: 2d7f7f35978a449995958b44730759d3 +#: ../../source/Instance_Setup/Instance_Setup.rst:325 +#: 5f0f0f6a41384356986a1182f14a0a4c msgid "Requirements" msgstr "要件" -#: ../../source/Instance_Setup/Instance_Setup.rst:326 -#: ddf48eb8fc2d48f9adbc38a39965ec22 +#: ../../source/Instance_Setup/Instance_Setup.rst:327 +#: 49ceb74e41104b00971cd9edecef08ae #, fuzzy msgid "Python 3.10+" msgstr "Python 3.6+" -#: ../../source/Instance_Setup/Instance_Setup.rst:327 -#: 9bc8a330f1384ade97e4ee55efa58e6b +#: ../../source/Instance_Setup/Instance_Setup.rst:328 +#: 1d80811611c944f9bf772364ab45d1e4 msgid "" -"The ``PyFlow.network_api.connect_tcp`` module must be importable (the script" -" imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." +"The ``PyFlow.network_api.connect_tcp`` module must be importable (the " +"script imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." msgstr "" "'' PyFlow.network_api.connect_tcp ''モジュールはインポート可能でなければなりません(スクリプトはそこから'' " "TCP_Server_Base ''と'' TCP_Client_Base ''をインポートします)。" #~ msgid "" -#~ "- ``forward_extension_tcp.py`` – forwarding messages, files, multiple files," -#~ " folders and multiple folders to any number of destination clients " -#~ "(``/send_msg_forward``, ``/file_forward``, ``/multiple_file_forward``, " +#~ "- ``forward_extension_tcp.py`` – forwarding " +#~ "messages, files, multiple files, folders " +#~ "and multiple folders to any number " +#~ "of destination clients (``/send_msg_forward``, " +#~ "``/file_forward``, ``/multiple_file_forward``, " #~ "``/folder_forward``, ``/multiple_folder_forward``)." #~ msgstr "" #~ "- ``forward_extension_tcp.py`` – " @@ -752,10 +758,13 @@ msgstr "" #~ "(``/send_msg_forward``、``/file_forward``、``/multiple_file_forward``、``/folder_forward``、``/multiple_folder_forward``)。" #~ msgid "" -#~ "- ``True`` (default) – ``start_TCP_Server()`` / ``start_TCP_client()`` is " -#~ "called directly and the console input loop runs in its own thread." +#~ "- ``True`` (default) – ``start_TCP_Server()``" +#~ " / ``start_TCP_client()`` is called " +#~ "directly and the console input loop " +#~ "runs in its own thread." #~ msgstr "" -#~ "- ``True`` (デフォルト) – ``start_TCP_Server()`` / ``start_TCP_client()`` " +#~ "- ``True`` (デフォルト) – ``start_TCP_Server()``" +#~ " / ``start_TCP_client()`` " #~ "が直接呼び出され、コンソール入力ループは独自のスレッドで実行されます。" #~ msgid "``True`` (default) – ``start_TCP_Server()`` /" @@ -771,33 +780,42 @@ msgstr "" #~ msgstr "インスタンスの起動に失敗した場合、次のエラーが発生します。" #~ msgid "" -#~ "**Note:** This launcher supports only **one server** and **one client** " -#~ "instance at a time. Adding a new server or client configuration will " -#~ "completely overwrite any previous configuration of the same type." +#~ "**Note:** This launcher supports only " +#~ "**one server** and **one client** " +#~ "instance at a time. Adding a new" +#~ " server or client configuration will " +#~ "completely overwrite any previous " +#~ "configuration of the same type." #~ msgstr "" -#~ "**注意:** このランチャーは、一度に **1 つのサーバー** と **1 つのクライアント** " +#~ "**注意:** このランチャーは、一度に **1 つのサーバー** と **1" +#~ " つのクライアント** " #~ "インスタンスのみをサポートします。新しいサーバーまたはクライアント構成を追加すると、同じタイプの以前の構成が完全に上書きされます。" #~ msgid "The script will ask you to:" #~ msgstr "スクリプトは次のことを要求します。" #~ msgid "" -#~ "Decide whether to add another instance (if you add the same type again, the " -#~ "previous configuration of that type is overwritten)." +#~ "Decide whether to add another instance" +#~ " (if you add the same type " +#~ "again, the previous configuration of " +#~ "that type is overwritten)." #~ msgstr "別のインスタンスを追加するかどうかを決定します (同じタイプを再度追加すると、そのタイプの以前の構成が上書きされます)。" #~ msgid "" -#~ "If ``setup.json`` already exists, you will be prompted to either reuse the " -#~ "existing configuration (launch the stored instances) or overwrite it with " -#~ "new definitions." +#~ "If ``setup.json`` already exists, you " +#~ "will be prompted to either reuse " +#~ "the existing configuration (launch the " +#~ "stored instances) or overwrite it with" +#~ " new definitions." #~ msgstr "" -#~ "``setup.json`` がすでに存在する場合は、既存の設定を再利用する (保存されたインスタンスを起動する) " -#~ "か、新しい定義で上書きするかを尋ねるメッセージが表示されます。" +#~ "``setup.json`` がすでに存在する場合は、既存の設定を再利用する (保存されたインスタンスを起動する)" +#~ " か、新しい定義で上書きするかを尋ねるメッセージが表示されます。" #~ msgid "" -#~ "**Important:** When you choose to overwrite, the old server/client " -#~ "configuration is **completely replaced** by the new one. There is no " -#~ "merging." +#~ "**Important:** When you choose to " +#~ "overwrite, the old server/client configuration" +#~ " is **completely replaced** by the " +#~ "new one. There is no merging." #~ msgstr "**重要:** 上書きを選択すると、古いサーバー/クライアント構成は新しい構成に**完全に置き換えられます**。合併はありません。" #~ msgid "**Required.** 0 = Server, 1 = Client." @@ -807,29 +825,42 @@ msgstr "" #~ msgstr "クライアントの場合は、接続するサーバーのアドレスとポートも入力します。" #~ msgid "" -#~ "*Ignored.* The script always launches a single instance. This flag is " -#~ "accepted for compatibility but has no effect." +#~ "*Ignored.* The script always launches a" +#~ " single instance. This flag is " +#~ "accepted for compatibility but has no" +#~ " effect." #~ msgstr "*無視。*スクリプトは常に単一のインスタンスを起動します。このフラグは互換性のために受け入れられますが、効果はありません。" #~ msgid "" -#~ "**Each list contains at most one object.** When a new server or client " -#~ "configuration is added, the entire list for that type is replaced." +#~ "**Each list contains at most one " +#~ "object.** When a new server or " +#~ "client configuration is added, the " +#~ "entire list for that type is " +#~ "replaced." #~ msgstr "" #~ "**各リストには最大 1 つのオブジェクトが含まれます。** " #~ "新しいサーバーまたはクライアント構成が追加されると、そのタイプのリスト全体が置き換えられます。" #~ msgid "" -#~ "You can manually edit ``setup.json`` to include any parameter accepted by " -#~ "``TCP_Server_Base`` or ``TCP_Client_Base`` (see the source code for the full" -#~ " list). These custom values are retained when the launcher overwrites the " -#~ "configuration (since the script reads the existing config and updates it " -#~ "with user‑provided values, but if you choose to overwrite, the old config is" -#~ " discarded and only the new fields are saved – so if you want custom " -#~ "parameters, you should add them after the first launch or edit the file " -#~ "manually)." +#~ "You can manually edit ``setup.json`` to" +#~ " include any parameter accepted by " +#~ "``TCP_Server_Base`` or ``TCP_Client_Base`` (see " +#~ "the source code for the full " +#~ "list). These custom values are retained" +#~ " when the launcher overwrites the " +#~ "configuration (since the script reads " +#~ "the existing config and updates it " +#~ "with user‑provided values, but if you" +#~ " choose to overwrite, the old config" +#~ " is discarded and only the new " +#~ "fields are saved – so if you " +#~ "want custom parameters, you should add" +#~ " them after the first launch or " +#~ "edit the file manually)." #~ msgstr "" #~ "「setup.json」を手動で編集して、「TCP_Server_Base」または「TCP_Client_Base」で受け入れられるパラメータを含めることができます" -#~ " (完全なリストについてはソースコードを参照してください)。これらのカスタム値は、ランチャーが構成を上書きするときに保持されます " +#~ " (完全なリストについてはソースコードを参照してください)。これらのカスタム値は、ランチャーが構成を上書きするときに保持されます" +#~ " " #~ "(スクリプトは既存の構成を読み取り、ユーザーが指定した値で更新するためですが、上書きを選択すると、古い構成は破棄され、新しいフィールドのみが保存されます。そのため、カスタム" #~ " パラメーターが必要な場合は、最初の起動後に追加するか、ファイルを手動で編集する必要があります)。" @@ -841,3 +872,4 @@ msgstr "" #~ msgid "and ``TCP_Client_Base`` from there)." #~ msgstr "そこから ``TCP_Client_Base`` となります)。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po b/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po index 3ce2d19..6c2034a 100644 --- a/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po +++ b/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po @@ -6,121 +6,121 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Client_APIs.rst:2 -#: 6dd11dd380344faabc9dea6d41655b1c +#: 596423c8d92e4592b221947ca5595ea7 msgid "The TCP Client APIs" msgstr "TCP クライアント API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:5 -#: 2d8b31ea476c498188b1d3df403c2402 +#: bf347a93657146d6b019250273bc439c msgid "TCP Client setup API" msgstr "TCPクライアントセットアップAPI" #: ../../source/Network_APIs/TCP_Client_APIs.rst:7 -#: d699c50b2310495bb2521c5da6d30543 +#: 7e3dc9343f554fc181d2c2853898916c msgid "" -"The TCP Client Setup API is used to create a TCP client. The client in the " -"protocol is usually used to connect to the TCP server and exchange data with" -" the server." +"The TCP Client Setup API is used to create a TCP client. The client in " +"the protocol is usually used to connect to the TCP server and exchange " +"data with the server." msgstr "" "TCP クライアント セットアップ API は、TCP クライアントを作成するために使用されます。プロトコル内のクライアントは通常、TCP " "サーバーに接続し、サーバーとデータを交換するために使用されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:34 -#: 5505d653e132458686537e957323bb9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 +#: fb61c59ca5e646f3b749359b2ea13a40 msgid "" -"The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The " -"parameters of the ``__init__`` method are as follows:" +"The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The" +" parameters of the ``__init__`` method are as follows:" msgstr "" "TCP クライアント セットアップ API は ``TCP_Client_Base`` クラスで定義されます。 ``__init__`` " "メソッドのパラメータは次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:37 -#: 6a41dd3d0f00421b914a6ae9e588d6b8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 +#: d8b55d105dd144198594dd4f454fe5c5 msgid "``host``: The server host IP address to connect to." msgstr "``host``: 接続先のサーバーホストの IP アドレス。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 -#: cc6ddd6c80bb46f3b393c9882e096a0a -msgid "" -"``client_host``: The local host IP address to bind the client socket to." +#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 +#: ee9f5f584e6643529cdca91384562ebf +msgid "``client_host``: The local host IP address to bind the client socket to." msgstr "``client_host``: クライアントソケットをバインドするローカルホストの IP アドレス。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:39 -#: 949c21452bb94effa6c13959868ac90f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 +#: 03357b8c2f974a419c6933d68976b6eb msgid "``port``: The server port number to connect to." msgstr "``port``: 接続するサーバーのポート番号。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:40 -#: 97c56df67b0c435aaf8ee89bea56266b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 +#: cd50ed1b09934f3bae2a4c615187d157 msgid "" "``client_port``: The local port number to bind the client socket to " "(``None`` means let the OS choose)." msgstr "" -"``client_port``: クライアントソケットをバインドするローカルポート番号 (``None`` は OS に選択させることを意味します)。" +"``client_port``: クライアントソケットをバインドするローカルポート番号 (``None`` は OS " +"に選択させることを意味します)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 -#: 309676fc53ff4cd39a8d9e200c54f1bf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 +#: f8cdf36b87834ea7a95209d2ca048332 msgid "" "``timeout``: The socket timeout in seconds for connection and receive " -"operations. ``None`` (the default) is not \"no timeout\": the socket then " -"uses a fixed 5-second timeout, and receive timeouts are swallowed by the " -"receive loop (it simply continues)." +"operations. ``None`` (the default) is not \"no timeout\": the socket then" +" uses a fixed 5-second timeout, and receive timeouts are swallowed by the" +" receive loop (it simply continues)." msgstr "" "'' timeout '':接続および受信操作の秒単位のソケットタイムアウト。'' None '' (デフォルト)は\"no " "timeout\"ではありません:ソケットは固定の5秒のタイムアウトを使用し、受信タイムアウトは受信ループによって飲み込まれます(単に続行します)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 -#: 9bf924fa535a44e78c98664e8d2b304f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 +#: 20c7ea1afac14f80a2b739cb6ae1957f msgid "" -"``port_add_step``: The step size for incrementing the port number (used only" -" in manual allocation mode)." +"``port_add_step``: The step size for incrementing the port number (used " +"only in manual allocation mode)." msgstr "``port_add_step``: ポート番号を増やすためのステップ サイズ (手動割り当てモードでのみ使用されます)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 -#: 5abb7f5137714757b6957a177747d1e5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 +#: eb06f09e560543e5ba0abb3627a63585 msgid "" "``max_thread_num``: The maximum number of threads for concurrent file " "transfer operations." msgstr "``max_thread_num``: 同時ファイル転送操作の最大スレッド数。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 -#: e71bd35480184667a6390f2a28c0894a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:48 +#: 5ff72dc0ec90411bb0d20f618d015093 msgid "" -"``is_input_command_in_console``: A flag indicating whether to input commands" -" in the console (interactive mode)." +"``is_input_command_in_console``: A flag indicating whether to input " +"commands in the console (interactive mode)." msgstr "``is_input_command_in_console``: コンソール (対話モード) でコマンドを入力するかどうかを示すフラグ。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 -#: f4dd649db47842fdb7b64e39d5887cdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:49 +#: 5e12aa05eb854b15b0b6779b40b5a302 msgid "" -"``is_wait_server``: A flag indicating whether to keep retrying connection " -"until the server is available." +"``is_wait_server``: A flag indicating whether to keep retrying connection" +" until the server is available." msgstr "``is_wait_server``: サーバーが利用可能になるまで接続の再試行を続けるかどうかを示すフラグ。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 -#: 69c7bfb0cc784e9a817d98096357d9d6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:50 +#: b3232047b364478caad5b3e5361e71be msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``: カスタム ワーカー スレッドの最大数。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 -#: 892ac76eabb04f90b9c95f29009b6c11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 +#: a951c5564286432082b3e6a06aae8a48 msgid "" -"``is_extend_command``: A flag for extension protocols. With ``False`` (the " -"default) the constructor starts the client itself by calling " +"``is_extend_command``: A flag for extension protocols. With ``False`` " +"(the default) the constructor starts the client itself by calling " "``start_TCP_client()``; with ``True`` it does not, so an extension can " "register its commands first and connect later." msgstr "" @@ -128,117 +128,163 @@ msgstr "" "START_TCP_CLIENT ()''を呼び出すことによってクライアント自体を開始します。'' True " "''を使用すると開始しません。そのため、拡張機能は最初にコマンドを登録し、後で接続できます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 -#: 0cfe21e428fd45f08a9d8c080c285535 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:55 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " -"with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-channel-" -"api`)." +"with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-" +"channel-api`)." msgstr "" -"``is_enable_encrypto``: サーバーと交換されるメッセージが RSA 暗号化されているかどうかを示すフラグ (:ref:`tcp-" -"client-encrypted-channel-api` を参照)。" +"``is_enable_encrypto``: サーバーと交換されるメッセージが RSA 暗号化されているかどうかを示すフラグ (:ref" +":`tcp-client-encrypted-channel-api` を参照)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:53 -#: 353688102eb6441ebf87384e57f0c661 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 +#: 8ac8a71ca8564a89bb52f882c4fedefc msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " -"user-supplied RSA keys. Both files must exist, parse as PEM, and pair with " -"each other; an invalid pair is silently ignored and the default key lookup " -"is used instead (``None`` keeps the default lookup)." +"user-supplied RSA keys. Both files must exist, parse as PEM, and pair " +"with each other; an invalid pair is silently ignored and the default key " +"lookup is used instead (``None`` keeps the default lookup)." msgstr "" -"``is_custom_keys``: ユーザーが指定した RSA キーのオプションの ``[pub_key_path, pvt_key_path]``" -" ペア。両方のファイルが存在し、PEM " +"``is_custom_keys``: ユーザーが指定した RSA キーのオプションの ``[pub_key_path, " +"pvt_key_path]`` ペア。両方のファイルが存在し、PEM " "として解析され、相互にペアになっている必要があります。無効なペアは黙って無視され、代わりにデフォルトのキー検索が使用されます (``None`` " "はデフォルトの検索を維持します)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 -#: 0176e8b8b8ea44c396d55657d74a91cd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:61 +#: c01569233a864bf0b106a877fb924c27 #, fuzzy msgid "" "``max_mem_buff``: The buffering ceiling in MiB, stored as bytes " -"(``self.max_mem_buff``). It is kept for parity with the server class; the " -"client's forward path does not read it today. The default is 2048." +"(``self.max_mem_buff``). It is kept for parity with the server class; the" +" client's forward path does not read it today. The default is 2048." msgstr "" "'' max_mem_buff '':デフォルトは'' 2048 " "''です(サーバークラスとのパリティのために保持されます。クライアントのフォワードパスは今日それを読み取りません)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:60 -#: 276f7755eaea4b808ad6cfe985eaa8aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:64 +#: 10fb41da1af34a539a962083252bdf55 +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 +#: 1b569fa80b59490dacc6bcdf3a924d60 +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 +#: ac73e6da7c3044f1bf68aff504142765 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " -"(the default) the client logs command content and execution results only; " -"with ``True`` it also logs the key steps of the execution process." +"(the default) the client logs command content and execution results only;" +" with ``True`` it also logs the key steps of the execution process." msgstr "" "'' is_debug '':記録される詳細の量を選択するフラグ。'' False " "''(デフォルト)を使用すると、クライアントはコマンドの内容と実行結果のみをログに記録します。'' True " "''を使用すると、実行プロセスの主要なステップもログに記録します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:63 -#: 58a790ecb724454298659bf9831fb2ae +#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_print_log``: A flag indicating whether the client logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -"'' is_print_log '':クライアントがまったくログを記録しているかどうかを示すフラグ。'' False ''では、'' is_debug " -"''が何であれ、何も出力しません。" +"'' is_print_log '':クライアントがまったくログを記録しているかどうかを示すフラグ。'' False ''では、'' " +"is_debug ''が何であれ、何も出力しません。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 -#: 36eebcb4edbb4f1e96862b64762c4d6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 +#: fa251d2893fa413aac9d5e525df18209 +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when the " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:85 +#: 3a9f1a8e8b8f45dbb9011b3b0e28cd92 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:93 +#: 3272388be97643f98bada0a995516141 msgid "Every parameter has default values:" msgstr "すべてのパラメータにはデフォルト値があります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 -#: 4a2b0f17cb4f47669a8dcb3734c17468 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:95 +#: 9fd3d516d31841fd9054a2a3dfcb1ac4 msgid "``host``: Default is ``None`` (must be provided before connecting)" msgstr "``host``: デフォルトは ``None`` (接続前に指定する必要があります)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:69 -#: 7dea100856734d3ba4ee6352d45cc554 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:96 +#: ece6c7a48ae74f86b6e207d960c6daa2 msgid "``client_host``: Default is ``'127.0.0.1'``" msgstr "``client_host``: デフォルトは ``'127.0.0.1'`` です。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:70 -#: e646757cb9d1425fa72970698c2938e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 +#: 8a9d85bb281e43e69ea0ae48363fb8da msgid "``port``: Default is ``65432``" msgstr "``ポート'': デフォルトは ``65432`` です" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 -#: 4c232543227544acae211825b01a795a -msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" -msgstr "``client_port``: デフォルトは ``None`` (OS が一時的なポートを割り当てます)" +#: ../../source/Network_APIs/TCP_Client_APIs.rst:98 +#: 4653721a3e8143fea8a43899bb0e6437 +msgid "" +"``client_port``: Default is ``None`` (OS assigns ephemeral port). A " +"configured port that cannot be bound — a session that just ended can hold" +" it in the operating system's ``TIME_WAIT`` — is reported and the " +"connection is made from an OS-assigned port instead." +msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:72 -#: 3c772d5ab49243b993d5dfea9af5d472 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:102 +#: 4439e99a222744a9bca762b5f14b4d74 msgid "``timeout``: Default is ``None``" msgstr "``timeout``: デフォルトは ``None`` です。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:73 -#: 501a6c2966d2470cbf9ce2a8909ef130 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 +#: 0b0f6a9551ff4bf28ad02095893db9d8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: デフォルトは ``1`` です" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 -#: 697656b4cb24453c89b1a848299e4167 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:104 +#: bcb1ee681a0f47319338faf71a99adf7 msgid "``max_thread_num``: Default is ``10``" msgstr "``max_thread_num``: デフォルトは ``10``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:75 -#: 632284d8c9b349f89018f8a19ce9662e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:105 +#: 08471d033b174cf395292c36068d4cb8 msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: デフォルトは ``True``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:76 -#: ec7a8bd80ad2471d9208999fc34792f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:106 +#: bbf2ad3b5e4340c9b481f8af135281e2 msgid "``is_wait_server``: Default is ``True``" msgstr "``is_wait_server``: デフォルトは ``True``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:77 -#: c036a352181d422894b56b0c14167bdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:107 +#: 63f2004d0c5b4fef8cf23eaa7be020b1 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: デフォルトは ``10``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:78 -#: 64df1f8395ca45d497875fb232c71b0e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:108 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_client()`` automatically)" @@ -246,43 +292,42 @@ msgstr "" "``is_extend_command``: デフォルトは ``False`` (``True`` の場合、``__init__`` は自動的に " "``start_TCP_client()`` を呼び出しません)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:80 -#: ca18c257b4054fad931a19b59a8a4606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:110 +#: c723e855f50a4ec3abf45aaae2e02f45 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, the client " -"performs an RSA public-key exchange with the server right after connecting " -"and all subsequent messages are encrypted)" +"performs an RSA public-key exchange with the server right after " +"connecting and all subsequent messages are encrypted)" msgstr "" -"``is_enable_encrypto``: デフォルトは ``True'' です (``True`` の場合、クライアントは接続直後にサーバーと " -"RSA 公開鍵交換を実行し、後続のすべてのメッセージが暗号化されます)" +"``is_enable_encrypto``: デフォルトは ``True'' です (``True`` " +"の場合、クライアントは接続直後にサーバーと RSA 公開鍵交換を実行し、後続のすべてのメッセージが暗号化されます)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:83 -#: 0c6ecb6d7f504ef8a9a666bc2659a009 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:113 +#: 16c586bc40d94d6b9624812993e12579 msgid "" -"``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, pvt_key_path]`` " -"list uses a user-supplied keypair instead of the default ``~/.ssh`` / " -"generated keys)" +"``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " +"pvt_key_path]`` list uses a user-supplied keypair instead of the default " +"``~/.ssh`` / generated keys)" msgstr "" "``is_custom_keys``: デフォルトは ``None`` (``[pub_key_path, pvt_key_path]`` " "リストはデフォルトの ``~/.ssh`` / 生成されたキーの代わりにユーザー指定のキーペアを使用します)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:86 -#: 96c8a6add16d4a999f8910133dad83b4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:116 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "'' is_debug '':デフォルトは'' False ''です('' True ''は実行プロセス行をコマンド/結果行に追加します)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:88 -#: 4ea3ee5f013c46c98a380ed9fa7b6e64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:118 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "client would print)" -msgstr "" -"'' is_print_log '':デフォルトは'' True ''です('' False ''はクライアントが印刷するすべての行を無音にします)" +msgstr "'' is_print_log '':デフォルトは'' True ''です('' False ''はクライアントが印刷するすべての行を無音にします)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:90 -#: a1d9d8ceda754443aef4e9dd2031e754 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:120 +#: 58fc5a7851094fcba7903d9e6cd4e8e7 msgid "" "``max_mem_buff``: Default is ``2048`` (kept for parity with the server " "class; the client's forward path does not read it today)" @@ -290,211 +335,249 @@ msgstr "" "'' max_mem_buff '':デフォルトは'' 2048 " "''です(サーバークラスとのパリティのために保持されます。クライアントのフォワードパスは今日それを読み取りません)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:94 -#: 930f7b1c90474a16b2dc7d13c41c238c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:123 +#: 08471d033b174cf395292c36068d4cb8 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_custom_workers``: デフォルトは ``10``" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 +#: ff70e67852154092b227e2f05357a78d +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:125 +#: bd7d9bb9bbe14bc38eed56c574fc0987 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:127 +#: 5282067c345342d4872377ec83b3ba95 +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 +#: d10be044603c42e9a26b3164dcb7cb51 +msgid "" +"``is_auto_reconnect``: Default is ``False`` (``True`` makes " +"`start_TCP_client` reconnect after the connection drops and resume the " +"interrupted transfers, see :ref:`transfer-pause-and-reconnect`. The dead " +"session's socket is closed abortively first, so a configured " +"``client_port`` can be bound again — Windows refuses it otherwise)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:135 +#: 4b99048b2ec14a988fd9b83b23284d25 msgid "" -"The TCP Client Setup API will initialize all the necessary parameters and " -"resources for the TCP client." +"The TCP Client Setup API will initialize all the necessary parameters and" +" resources for the TCP client." msgstr "TCP クライアント セットアップ API は、TCP クライアントに必要なすべてのパラメータとリソースを初期化します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 -#: 221e218700a34372ae96eae9189831aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 +#: b7da2a334a9543aa96178bddc8b6855c msgid "" "*Note: In the main class of the TCP client setup API, we initialize the " -"`start_TCP_client` method to set up all functions which are needed in the " -"TCP client, including connecting to the server, handling incoming messages, " -"and managing user input.*" +"`start_TCP_client` method to set up all functions which are needed in the" +" TCP client, including connecting to the server, handling incoming " +"messages, and managing user input.*" msgstr "" "*注意: TCP クライアント セットアップ API のメイン クラスでは、`start_TCP_client` " "メソッドを初期化し、サーバーへの接続、受信メッセージの処理、ユーザー入力の管理など、TCP クライアントで必要なすべての機能をセットアップします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 -#: 00cb8ca5027d464f88e778a8f2a4faec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 +#: 0aa6b4133bf54878ad5d35aa8523ae88 msgid "" -"*Note: By default ``TCP_Client_Base.__init__`` calls ``start_TCP_client()`` " -"to connect and enter interactive mode. If you set " -"``is_extend_command=True``, the instance will not auto-start and you should " -"call ``start_TCP_client()`` manually when ready.*" +"*Note: By default ``TCP_Client_Base.__init__`` calls " +"``start_TCP_client()`` to connect and enter interactive mode. If you set " +"``is_extend_command=True``, the instance will not auto-start and you " +"should call ``start_TCP_client()`` manually when ready.*" msgstr "" "*注意: デフォルトでは、 ``TCP_Client_Base.__init__`` は ``start_TCP_client()`` " "を呼び出して接続し、対話モードに入ります。 ``is_extend_command=True`` " "を設定した場合、インスタンスは自動起動しないため、準備ができたら手動で ``start_TCP_client()`` を呼び出す必要があります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:109 -#: 4d8f352fa0be45e1b75d44727035e828 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 +#: 7a35992f8c7c410da60029bb06fb054a msgid "" -"*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must be" -" ``None``. The constructor will raise a ``ValueError`` if ``is_wait_server``" -" is ``True`` and ``timeout`` is not ``None``.*" +"*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must" +" be ``None``. The constructor will raise a ``ValueError`` if " +"``is_wait_server`` is ``True`` and ``timeout`` is not ``None``.*" msgstr "" -"*注意: ``is_wait_server=True`` を設定する場合、``timeout`` パラメータは ``None`` にする必要があります。" -" ``is_wait_server`` が ``True`` で、 ``timeout`` が ``None`` でない場合、コンストラクタは " -"``ValueError`` を発生させます。" +"*注意: ``is_wait_server=True`` を設定する場合、``timeout`` パラメータは ``None`` " +"にする必要があります。 ``is_wait_server`` が ``True`` で、 ``timeout`` が ``None`` " +"でない場合、コンストラクタは ``ValueError`` を発生させます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:119 -#: 92cea23fb57c482cb1199cabd89af968 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 +#: 35b6f81f408041c4a7e650d3b92957d1 msgid "" -"In the `start_TCP_client` method, we first attempt to connect to the server " -"by calling the `connect` method. If the connection fails and " -"``is_wait_server`` is ``True``, the client will keep retrying; otherwise it " -"will exit." +"In the `start_TCP_client` method, we first attempt to connect to the " +"server by calling the `connect` method. If the connection fails and " +"``is_wait_server`` is ``True``, the client will keep retrying; otherwise " +"it will exit." msgstr "" "`start_TCP_client` メソッドでは、まず `connect` メソッドを呼び出してサーバーへの接続を試みます。接続が失敗し、 " "``is_wait_server`` が ``True`` の場合、クライアントは再試行を続けます。それ以外の場合は終了します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 -#: 2e529671abf848fd87771801ae4a3763 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:165 +#: d8e70dde1c62462cb4954eb1ceb50f3a #, fuzzy msgid "" "*Note: The client socket is created in the `connect` method (called by " -"`start_TCP_client`), is based on IPv4 and uses the parameters ``self.host`` " -"and ``self.port`` which are provided when creating the client instance.*" +"`start_TCP_client`), is based on IPv4 and uses the parameters " +"``self.host`` and ``self.port`` which are provided when creating the " +"client instance.*" msgstr "" "*注意: `start_TCP_client` メソッドで作成されるクライアント ソケットは IPv4 に基づいており、クライアント " "インスタンスの作成時に提供されるパラメータ `self.host` および `self.port` を使用します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 -#: abe7c8d5d59b4a589ec6537a06a7333b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:170 +#: 80f69db837ec4e1d9bb90bc821019532 msgid "" -"Secondly, according to the ``self.is_input_command_in_console`` parameter, " -"we will either start the interactive input loop (`interactive_mode`) or " -"simply keep the connection alive (no console input)." +"Secondly, according to the ``self.is_input_command_in_console`` " +"parameter, we will either start the interactive input loop " +"(`interactive_mode`) or simply keep the connection alive (no console " +"input)." msgstr "" "次に、`self.is_input_command_in_console` パラメータに従って、対話型入力ループ " "(`interactive_mode`) を開始するか、単純に接続を維持します (コンソール入力なし)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:134 -#: e6ad1c25ef6e409aa4dba10b44fbe7a4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 +#: 445af010e93f421099da8d8dd5212210 msgid "" -"After that, if the interactive mode is enabled, the client will read user " -"input from the console and send messages to the server until the connection " -"is closed." -msgstr "" -"その後、対話モードが有効になっている場合、クライアントはコンソールからユーザー入力を読み取り、接続が閉じられるまでメッセージをサーバーに送信します。" +"After that, if the interactive mode is enabled, the client will read user" +" input from the console and send messages to the server until the " +"connection is closed." +msgstr "その後、対話モードが有効になっている場合、クライアントはコンソールからユーザー入力を読み取り、接続が閉じられるまでメッセージをサーバーに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 -#: c957271185064b21a0bc78265e007969 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:179 +#: 2d4020f99c3c4a4485815c383a0a4bfe msgid "" -"*Note: There is a global variable ``self.running`` which is set to ``True`` " -"after the client successfully connects to the server. The ``self.running`` " -"variable is used to control the main receive loop, and it will be set to " -"``False`` when the client is shutting down.*" +"*Note: There is a global variable ``self.running`` which is set to " +"``True`` after the client successfully connects to the server. The " +"``self.running`` variable is used to control the main receive loop, and " +"it will be set to ``False`` when the client is shutting down.*" msgstr "" "*注意: グローバル変数 ``self.running`` があります。これは、クライアントがサーバーに正常に接続した後に ``True`` " "に変わります。 ``self.running`` 変数はメインの受信ループを制御するために使用され、クライアントがシャットダウンするときに " "``False`` に変わります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 -#: d055f0b3b19940be8b0549705d6cd3b5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:185 +#: e4de5ae390fc4c1c9a50703299f80356 msgid "" -"The `connect` method will try to establish a TCP connection to the server. " -"If a ``client_port`` is specified, the client will bind to that local port " -"before connecting. The method will handle timeouts and connection refused " -"errors gracefully, especially when ``is_wait_server`` is enabled." +"The `connect` method will try to establish a TCP connection to the " +"server. If a ``client_port`` is specified, the client will bind to that " +"local port before connecting. The method will handle timeouts and " +"connection refused errors gracefully, especially when ``is_wait_server`` " +"is enabled." msgstr "" "「connect」メソッドはサーバーへの TCP 接続の確立を試みます。 ``client_port`` " "が指定されている場合、クライアントは接続する前にそのローカル ポートにバインドします。このメソッドは、特に ``is_wait_server`` " "が有効な場合に、タイムアウトや接続拒否エラーを適切に処理します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 -#: 4615e65c81854301ac43f16a4d7e16b1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 +#: 17315c7599be4d2e8d8f62ad4c866eb3 msgid "" -"When the connection is established, a background thread `receive_messages` " -"is started to continuously read data from the server." +"When the connection is established, a background thread " +"`receive_messages` is started to continuously read data from the server." msgstr "接続が確立されると、バックグラウンド スレッド「receive_messages」が開始され、サーバーからデータを継続的に読み取ります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:154 -#: bace28ef9c5841ffac04669beeb4e56a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:195 +#: 26bc6f1cf62947c88fd9de780337d225 msgid "So what can the setup function do if the connection fails?" msgstr "では、接続が失敗した場合、セットアップ関数は何をできるのでしょうか?" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:156 -#: f89e08eff4f84bfba70ee321e26e218b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:197 +#: e7519cc6a4124a008a804ecbe9b10453 msgid "" -"First, if the connection attempt times out, the client will either wait and " -"retry (if ``is_wait_server`` is ``True``) or exit with an error." +"First, if the connection attempt times out, the client will either wait " +"and retry (if ``is_wait_server`` is ``True``) or exit with an error." msgstr "" "まず、接続試行がタイムアウトした場合、クライアントは待機して再試行するか ( ``is_wait_server`` が ``True`` " "の場合)、またはエラーで終了します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 -#: fe3484d9a2b04f29944bc0d412d73536 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:201 +#: 2bcc61a302d34c7dbc18f9bcc7beba5a msgid "" -"Secondly, if the server is not running (connection refused), the behaviour " -"is the same: retry or exit based on ``is_wait_server``." +"Secondly, if the server is not running (connection refused), the " +"behaviour is the same: retry or exit based on ``is_wait_server``." msgstr "" "次に、サーバーが実行されていない (接続が拒否された) 場合でも、動作は同じです。再試行するか、 ``is_wait_server`` " "に基づいて終了します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:164 -#: 18131d4fd10c42d09e1eca9697bda2fb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:205 +#: c33c7409acd94d6b8f69e0f718e50c1f msgid "" -"If any other socket error occurs, the client will print the error message " -"and return ``False``, and the `start_TCP_client` method will call " +"If any other socket error occurs, the client will print the error message" +" and return ``False``, and the `start_TCP_client` method will call " "``sys.exit(1)``." msgstr "" "他のソケットエラーが発生した場合、クライアントはエラーメッセージを出力して ``False`` を返し、 `start_TCP_client` " "メソッドは `sys.exit(1)`` を呼び出します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:168 -#: 050d63fcb50c4053aba93e3d05dae63c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:209 +#: d78f849334b6404d8840b12839d05b8c msgid "For shutting down the client, the `close` method is defined as:" msgstr "クライアントをシャットダウンする場合、「close」メソッドは次のように定義されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 -#: c0860fa6e2c240e5a2a56b278f3369f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 +#: 4b23bb29324b408ca1a3c06128ede442 #, fuzzy msgid "" "In the `close` method, we set ``self.running`` to ``False``, free any " -"allocated ports by calling `free_port`, flush the message and event stores, " -"and then half-close (``shutdown(SHUT_RDWR)``) and close the client socket. " -"This ensures a clean disconnection." +"allocated ports by calling `free_port`, flush the message and event " +"stores, and then half-close (``shutdown(SHUT_RDWR)``) and close the " +"client socket. This ensures a clean disconnection." msgstr "" "`close` メソッドでは、`self.running` を `False` に設定し、`free_port` " "を呼び出して割り当てられたポートを解放してから、クライアント ソケットを閉じます。これにより、きれいな切断が保証されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:180 -#: 6a703de12132431982451a11b661b4d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:221 +#: 510de5709a444a0c8296717f1e8bed2b msgid "" -"``close`` also wins against a connection attempt that is still in flight: if" -" it runs before ``connect`` puts the socket up, that call closes the socket " -"it just connected and returns ``False`` instead of reviving the client." +"``close`` also wins against a connection attempt that is still in flight:" +" if it runs before ``connect`` puts the socket up, that call closes the " +"socket it just connected and returns ``False`` instead of reviving the " +"client." msgstr "" "'' close ''は、まだ実行中の接続試行に対しても勝利します。'' connect " -"''がソケットを起動する前に実行された場合、その呼び出しは接続したソケットを閉じ、クライアントを復活させる代わりに'' False ''を返します。" +"''がソケットを起動する前に実行された場合、その呼び出しは接続したソケットを閉じ、クライアントを復活させる代わりに'' False " +"''を返します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:184 -#: ae54449f52b0491aaeb0c11de7749e4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:225 +#: c67deae0af3b4ab9bf572198122cc09d msgid "" -"*Note: The `free_port` method works similarly to the server side, releasing " -"any manually allocated ports if manual allocation mode is enabled.*" -msgstr "" -"*注意: 「free_port」メソッドはサーバー側と同様に機能し、手動割り当てモードが有効な場合は手動で割り当てられたポートを解放します。" +"*Note: The `free_port` method works similarly to the server side, " +"releasing any manually allocated ports if manual allocation mode is " +"enabled.*" +msgstr "*注意: 「free_port」メソッドはサーバー側と同様に機能し、手動割り当てモードが有効な場合は手動で割り当てられたポートを解放します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 +#: fbb5ed3c54a34df4bc6bf8f9688e295c msgid "TCP Client handling information API" msgstr "TCPクライアント取り扱い情報API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:193 -#: 57895cdce9c1426289087c4448ac2325 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 +#: 7c21a424a7774ad6b4a257c5ad645db4 msgid "" -"The client handling information API documents the core TCP client methods " -"that manage the server connection, receive raw data, and send messages." -msgstr "" -"クライアント処理情報 API は、サーバー接続の管理、生データの受信、メッセージの送信を行うコア TCP クライアント メソッドを文書化します。" +"The client handling information API documents the core TCP client methods" +" that manage the server connection, receive raw data, and send messages." +msgstr "クライアント処理情報 API は、サーバー接続の管理、生データの受信、メッセージの送信を行うコア TCP クライアント メソッドを文書化します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:198 -#: f9294ef58d274a9ba6b8edbec8c07606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:239 +#: b0fc366cad48412999e75faf81120a6e msgid "" -"Unlike the server, the client maintains only a single connection and does " -"not provide broadcast or ``send_msg_to_specific_client`` methods." +"Unlike the server, the client maintains only a single connection and does" +" not provide broadcast or ``send_msg_to_specific_client`` methods." msgstr "" "サーバーとは異なり、クライアントは単一の接続のみを維持し、ブロードキャストまたは ``send_msg_to_specific_client`` " "メソッドを提供しません。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:208 -#: 67e867cdfba84730bef1ad32d859ea24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:249 +#: ff50f500c3804fdb9562b5e9ae1a3482 msgid "" "`receive_messages` is the main background thread function in " "``TCP_Client_Base``. It is started after a successful connection and is " @@ -503,130 +586,129 @@ msgstr "" "`receive_messages` は `TCP_Client_Base` のメインのバックグラウンド " "スレッド関数です。接続が成功した後に開始され、次の役割を果たします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:212 -#: 17684d40e43543e88db7135b66b26e09 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 +#: 364f1d2b080843518fee4bcc0e74a8ca msgid "" "continuously receiving raw bytes from the server socket using " "`receive_message`" msgstr "「receive_message」を使用してサーバーソケットから生のバイトを継続的に受信します" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:213 -#: dc882668c1244dc3b7e57b07ad08612a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:254 +#: cf3b7cf194ec42919b87199c4586dfc4 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "改行で終わるメッセージが完了するまで受信データをバッファリングする" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:214 -#: 707313e8051245478059aa883da7459f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:255 +#: ad695c0a732a4ad78cdd07c79f2d5dc3 msgid "splitting and processing each message line-by-line" msgstr "各メッセージを行ごとに分割して処理する" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:215 -#: e9edeedb0eb64a278e03efa5169a36f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:256 +#: 387a605c25f8407d86b77c452ded00f7 msgid "" -"routing special commands (starting with ``/``) that come from the server to " -"`handle_server_command`" +"routing special commands (starting with ``/``) that come from the server " +"to `handle_server_command`" msgstr "サーバーからの特別なコマンド (「/」で始まる) を `handle_server_command` にルーティングします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 -#: 0ab735831831448a88f60538f859ce4e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:257 +#: d1729cfa1e314df68d3e7ce7e553f3a5 msgid "" "printing every received line to the console with a ``[server]`` prefix " -"(command lines included, after ``handle_server_command`` has processed them)" +"(command lines included, after ``handle_server_command`` has processed " +"them)" msgstr "" -"''[ server ]''プレフィックスを使用して、受信したすべての行をコンソールに出力します( '' handle_server_command " -"''が処理した後、コマンドラインが含まれます)" +"''[ server ]''プレフィックスを使用して、受信したすべての行をコンソールに出力します( '' " +"handle_server_command ''が処理した後、コマンドラインが含まれます)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:218 -#: e09f439632994d0fadb0ae8f58eef0cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:259 +#: 083b077c5c1845338f11ae62bace15b5 msgid "" -"unwrapping forwarded lines (``/send_msg_from``) so a message another client " -"forwarded here is attributed to its author" +"unwrapping forwarded lines (``/send_msg_from``) so a message another " +"client forwarded here is attributed to its author" msgstr "" "転送された行(''/ send_msg_from " "'')の折り返しを解除して、ここで転送された別のクライアントのメッセージがその作成者に帰属するようにします" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:220 -#: 166f9028c1cc41ff94be560b77e17504 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:261 +#: 1dd20cbdeac3480bbaec2f7ae6f1f1ed msgid "" -"handling connection resets and other socket errors, and cleaning up when the" -" server closes the connection" +"handling connection resets and other socket errors, and cleaning up when " +"the server closes the connection" msgstr "接続のリセットやその他のソケット エラーの処理、サーバーが接続を閉じたときのクリーンアップ" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:229 -#: db2e058412bc44d6ba39131b3b40a7ac +#: ../../source/Network_APIs/TCP_Client_APIs.rst:270 +#: e890dee4fb944eeaa9e6b2cf3cd9047a msgid "" -"In `handle_server_command`, the client processes built-in commands sent by " -"the server, such as:" +"In `handle_server_command`, the client processes built-in commands sent " +"by the server, such as:" msgstr "`handle_server_command` では、クライアントはサーバーから送信された次のような組み込みコマンドを処理します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:273 +#: b957ec8457f34618802ea0441634a894 #, fuzzy msgid "" -"``/client_alloc_port_range``: configures the client's manual port allocation" -" range from the line the server sends it on connect." -msgstr "" -"``/client_alloc_port_range``: サーバーのブロードキャストに基づいてクライアントの手動ポート割り当て範囲を設定します。" +"``/client_alloc_port_range``: configures the client's manual port " +"allocation range from the line the server sends it on connect." +msgstr "``/client_alloc_port_range``: サーバーのブロードキャストに基づいてクライアントの手動ポート割り当て範囲を設定します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 -#: 2558e50f505a4b6ca51c7a44fa9ad957 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:275 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" -"``/server_file_transfer_port``: receives the file transfer port assigned by " -"the server for an ongoing file operation." +"``/server_file_transfer_port``: receives the file transfer port assigned " +"by the server for an ongoing file operation." msgstr "" "``/server_file_transfer_port``: " "進行中のファイル操作のためにサーバーによって割り当てられたファイル転送ポートを受け取ります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:236 -#: 5147df6f2f794cf2949b7cef1ed24791 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:277 +#: 4eb4fe22d5db4b56b622dfd29459c3b7 msgid "" -"``/file`` and ``/file_folder``: handle file transfer requests initiated by " -"the server (server-to-client transfers)." +"``/file`` and ``/file_folder``: handle file transfer requests initiated " +"by the server (server-to-client transfers)." msgstr "" -"``/file`` および ``/file_folder``: サーバーによって開始されたファイル転送リクエスト (サーバーからクライアントへの転送) " -"を処理します。" +"``/file`` および ``/file_folder``: サーバーによって開始されたファイル転送リクエスト " +"(サーバーからクライアントへの転送) を処理します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:238 -#: 4755bb63eb0e4f8cbf481633417fc3c7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:279 +#: 3c550345aa484cb8bc44681842864044 msgid "" -"``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``, " -"``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the encrypted-" -"channel handshake messages; a ``/crypto_mode`` mismatch closes the " -"connection." +"``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``," +" ``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the " +"encrypted-channel handshake messages; a ``/crypto_mode`` mismatch closes " +"the connection." msgstr "" -"''/ crypto_mode ''、''/ crypto_key_exchange ''、''/ crypto_key_exchange_ack " -"''、''/ crypto_reject ''、''/ crypto_pub_key ''、''/ crypto_ready " +"''/ crypto_mode ''、''/ crypto_key_exchange ''、''/ crypto_key_exchange_ack" +" ''、''/ crypto_reject ''、''/ crypto_pub_key ''、''/ crypto_ready " "'':暗号化されたチャネルハンドシェイクメッセージ。''/ crypto_mode ''ミスマッチは接続を閉じます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:242 -#: f7cbe268c5e84987aec0bb18a0a81aa7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 +#: 31a62335177b49a19f708aee2aa5b0b1 msgid "" -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, ``/forward_error``:" -" forwarding and transfer-control messages." +"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/forward_error``: forwarding and transfer-control messages." msgstr "" "''/ forward_upload ''、''/ pause_trans ''、''/ start_trans ''、''/ " "forward_error '':転送および転送制御メッセージ。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:245 -#: d89b63a85c3d402fbb0df0f75edc4736 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:286 +#: b4c3c6ea61f344b8a3d3baf6b659d9c7 msgid "" "If you have registered custom commands using the command extension API, " -"`handle_server_command` will also check if the incoming command matches any " -"registered handler and execute it accordingly." +"`handle_server_command` will also check if the incoming command matches " +"any registered handler and execute it accordingly." msgstr "" "コマンド拡張 API を使用してカスタム " "コマンドを登録している場合、「handle_server_command」は受信したコマンドが登録されているハンドラーと一致するかどうかもチェックし、それに応じて実行します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:250 -#: 943d4fb64bad477f969403f360288769 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 +#: 4b6cc84b10d34254b7e6e0d7ae226ddc msgid "" "*Note: For more details of the command extension API, see the :ref:`tcp-" "client-command-api` section.*" -msgstr "" -"*注意: コマンド拡張 API の詳細については、:ref:`tcp-client-command-api` セクションを参照してください。" +msgstr "*注意: コマンド拡張 API の詳細については、:ref:`tcp-client-command-api` セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 -#: c2b4ba39cca64ea7ab62a59d016f0544 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:294 +#: b9ff85e2f76d4c1697602ebf69fed3a8 msgid "" "Closing the connection when the server goes away is not part of " "`handle_server_command`: it is `receive_messages` that reports the " @@ -635,18 +717,18 @@ msgstr "" "サーバーがなくなったときに接続を閉じることは、`handle_server_command`の一部ではありません。切断を報告し、'' " "self.running ''をクリアするのは`receive_messages`です。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:265 -#: 9312fc5109a547d588d98c16a9b79c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:306 +#: 4376aa47bf63490998e7008547d0c86f msgid "" "`receive_message` is identical to the server version: it reads up to " -"``msg_length`` bytes from the given socket and returns the raw byte payload." -" Message decoding and newline framing are handled by the caller." +"``msg_length`` bytes from the given socket and returns the raw byte " +"payload. Message decoding and newline framing are handled by the caller." msgstr "" "`receive_message` はサーバーバージョンと同じです。指定されたソケットから最大 `msg_length` " "バイトを読み取り、生のバイトペイロードを返します。メッセージのデコードと改行フレーム化は呼び出し元によって処理されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:278 -#: 7a64cec6a8084261a443f57f7032a5bb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:319 +#: 29b51f413be748e4b101bf498e593ef2 msgid "" "`send_message` sends data from the client to the server. It verifies the " "client is still running and the socket is valid, then:" @@ -654,18 +736,18 @@ msgstr "" "`send_message` " "はクライアントからサーバーにデータを送信します。クライアントがまだ実行中であり、ソケットが有効であることを確認してから、次のようにします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:281 -#: 9a5d3a7c041b47d68b80186e09492467 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 +#: e4158824d7b04b37a0f75c9ff67eab45 msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "``str`` と ``bytes`` の両方のメッセージペイロードを受け入れます" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:282 -#: c4247339bf084481af72ba498d8f9bcd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:323 +#: ea9158c1798941cb9df13f5a01b14f69 msgid "trims string payloads and appends a newline if missing" msgstr "文字列ペイロードをトリミングし、欠落している場合は改行を追加します" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 -#: 55c0dfde024b4bdea57da54d86297dbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:324 +#: 0fb0befad2844821a59b8c5c686e1c39 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -675,181 +757,185 @@ msgstr "" "ソケットが暗号化モードの場合 (公開鍵交換が完了している)、平文は「_VALID」マーカーで署名され、RSA-OAEP " "はサーバーの公開鍵で暗号化され、平文で送信されるのではなく、base64 でエンコードされ、改行で終了されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:287 -#: 6e2bbc8edbad40568dfe3eae781ab27c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:328 +#: e8d7a04011e74da18b274e1ad3ca3ab8 msgid "encodes string payloads as UTF-8" msgstr "文字列ペイロードを UTF-8 としてエンコードします" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:288 -#: 40b2936e9c6b4325b19b27f83932cf83 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:329 +#: 08c9e9aca2334e67b5051b42cc7dbad0 msgid "sends the complete message with ``client_socket.sendall(data)``" msgstr "`client_socket.sendall(data)` を使用して完全なメッセージを送信します" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:289 -#: 9ab8a09e5ca4416abd843cf1612f20a2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:330 +#: 99b4f8d523b2406499891c514befc372 msgid "" -"returns ``True`` on success, otherwise logs the error and returns ``False``" +"returns ``True`` on success, otherwise logs the error and returns " +"``False``" msgstr "成功した場合は ``True`` を返し、それ以外の場合はエラーをログに記録して ``False`` を返します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 -#: 0eb535b8380441869c432950417def80 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:332 +#: 18101652b1e34996866324fce0aa8a4d msgid "" -"The client also provides an interactive input loop (`interactive_mode`) that" -" reads user input from the console and sends messages to the server." +"The client also provides an interactive input loop (`interactive_mode`) " +"that reads user input from the console and sends messages to the server." msgstr "" "クライアントは、コンソールからユーザー入力を読み取り、サーバーにメッセージを送信する対話型入力ループ (「interactive_mode」) " "も提供します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:298 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:339 +#: fbb5ed3c54a34df4bc6bf8f9688e295c #, fuzzy msgid "TCP Client inbound event listener API" msgstr "TCPクライアントファイル転送API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:300 -#: 8b78c521249c4604933d30cfc99cc7a9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:341 +#: 15461ca186ed497083b901e65a3b33d1 msgid "External code can observe traffic without replacing the protocol loop:" msgstr "外部コードは、プロトコルループを置き換えることなくトラフィックを観察できます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:310 -#: 2f13976d605042919a1a19e346d85bd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:351 +#: 0d916f8d3eaf4336b5be87a5faf153a3 +#, fuzzy msgid "" "``add_message_listener`` registers ``listener(sender_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands go" -" to `handle_server_command` instead). ``sender_id`` is the author's " -"``\"ip:port\"`` — for a message another client forwarded here through the " -"``/send_msg_from`` envelope it is the forwarding client, and it is ``None`` " -"for a direct push from the server. ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a " -"file sent by the server has been fully written to disk. Both listeners run " -"on a protocol thread, so they must not block, and an exception inside a " -"listener is logged and swallowed. The ``remove_*`` counterparts unregister a" -" listener and ignore unknown ones." +"every inbound line, commands included, so a listener observes all inbound" +" traffic; a message another client forwarded here through the " +"``/send_msg_from`` envelope is reported as its payload. ``sender_id`` is " +"the author's ``\"ip:port\"`` — the forwarding client for such a forwarded" +" message, and it is ``None`` for a direct push from the server. " +"``add_file_listener`` registers ``listener(client_id, full_path, name, " +"size, command)`` and fires after a file sent by the server has been fully" +" written to disk. Both listeners run on a protocol thread, so they must " +"not block, and an exception inside a listener is logged and swallowed. " +"The ``remove_*`` counterparts unregister a listener and ignore unknown " +"ones." msgstr "" "'' add_message_listener ''は、すべての受信プレーンメッセージに対して'' listener (sender_id, " -"message )''を登録します(''/''で始まらない行;コマンドは代わりに`handle_server_command`に移動します)。'' " -"sender_id ''は、作成者の''\" ip: port \"''です。— ''/ send_msg_from " +"message )''を登録します(''/''で始まらない行;コマンドは代わりに`handle_server_command`に移動します)。''" +" sender_id ''は、作成者の''\" ip: port \"''です。— ''/ send_msg_from " "''エンベロープを介してここに転送されるメッセージの別のクライアントの場合、それは転送クライアントであり、サーバーからの直接プッシュの場合は'' " -"None ''です。'' add_file_listener ''は登録します。 '' listener (client_id, full_path, " -"name, size, command " +"None ''です。'' add_file_listener ''は登録します。 '' listener (client_id, " +"full_path, name, size, command " ")''は、サーバーから送信されたファイルがディスクに完全に書き込まれた後に発生します。両方のリスナーはプロトコルスレッド上で実行されるため、ブロックしてはならず、リスナー内の例外がログに記録されて飲み込まれます。''" " remove _*''はリスナーの登録を解除し、未知のリスナーを無視します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 -#: 75d993e34b944014be1b88aee03a4f9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:364 +#: 196be233dc00497a94ee87f9999a9897 msgid "" "Received messages and events are also stored per sender socket in " -"``messages_dict`` / ``events_dict`` (each entry a ``[content, timestamp]`` " -"pair). When a store reaches ``max_dict_size`` (64 KiB) it is flushed to " -"``messages_log.json`` / ``events_log.json`` under ``network_api/.Flow`` and " -"cleared; ``close`` flushes both stores." +"``messages_dict`` / ``events_dict`` (each entry a ``[content, " +"timestamp]`` pair). When a store reaches ``max_dict_size`` (64 KiB) it is" +" flushed to ``messages_log.json`` / ``events_log.json`` under " +"``network_api/.Flow`` and cleared; ``close`` flushes both stores." msgstr "" "受信したメッセージとイベントは、送信者ソケットごとに'' messages_dict ''/'' events_dict " -"''に格納されます(各エントリは''[ content, timestamp ]''ペアです)。ストアが'' max_dict_size '' (64 " -"KiB)に達すると、'' network_api /.Flow ''の下で'' messages_log.json ''/' " +"''に格納されます(各エントリは''[ content, timestamp ]''ペアです)。ストアが'' max_dict_size '' " +"(64 KiB)に達すると、'' network_api /.Flow ''の下で'' messages_log.json ''/' " "events_log.json ''にフラッシュされ、クリアされます。'' close ''は両方のストアをフラッシュします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:331 -#: 6535dcf4080e4090bf82df637e452cc6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:373 +#: 6d52a0605748445694e0f4b1a6c52ea7 msgid "TCP Client encrypted channel API" msgstr "TCPクライアント暗号化チャネルAPI" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:333 -#: e2dbda95b2ff4483b8b71394ae4b83c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:375 +#: 14a20833906f4e18b92856c3e98a8886 msgid "" -"When the client is created with ``is_enable_encrypto=True`` (the default), " -"it performs an RSA public-key exchange with the server immediately after " -"connecting, before any message content is encrypted." +"When the client is created with ``is_enable_encrypto=True`` (the " +"default), it performs an RSA public-key exchange with the server " +"immediately after connecting, before any message content is encrypted." msgstr "" "クライアントが ``is_enable_encrypto=True`` (デフォルト) " "で作成された場合、接続直後、メッセージの内容が暗号化される前に、サーバと RSA 公開鍵交換が実行されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:338 -#: 411e33f708ba4961aaf9073beffe7404 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:380 +#: 46166a685e064cd29ad7701d3a352fc4 msgid "Key material" msgstr "キーマテリアル" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:340 -#: 89d96a4b9abe4ccd98bdd72682b94a56 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:382 +#: ffdef9bf79aa41e6a401b0a16c24a674 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " "otherwise a fresh RSA-2048 keypair is generated into " -"``network_api/.Flow/pvt_key`` (``client_priv.pem`` / ``client_pub.pem``). An" -" ``~/.ssh/id_rsa`` that cannot be parsed is skipped, not reported." +"``network_api/.Flow/pvt_key`` (``client_priv.pem`` / ``client_pub.pem``)." +" An ``~/.ssh/id_rsa`` that cannot be parsed is skipped, not reported." msgstr "" -"PEM 秘密鍵が ``~/.ssh/id_rsa`` に存在する場合、それは再利用されます。それ以外の場合は、新しい RSA-2048 キーペアが " -"``network_api/.Flow/pvt_key`` (``client_priv.pem`` / ``client_pub.pem``) " -"に生成されます。交換される公開鍵は常に秘密鍵から派生するため、ローテーションされた ``~/.ssh`` ペアが自動的に選択されます。" +"PEM 秘密鍵が ``~/.ssh/id_rsa`` に存在する場合、それは再利用されます。それ以外の場合は、新しい RSA-2048 キーペアが" +" ``network_api/.Flow/pvt_key`` (``client_priv.pem`` / ``client_pub.pem``)" +" に生成されます。交換される公開鍵は常に秘密鍵から派生するため、ローテーションされた ``~/.ssh`` ペアが自動的に選択されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:345 -#: 74eb9aca2b1849e48138cbea3e76a39d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 +#: 2c27cfc2e8ce47fb8732aec1e00d3479 msgid "" -"The public-key file next to the private key is re-derived from the private " -"key on every load: if it is missing or does not match the key in use (a " -"rotated ``~/.ssh/id_rsa``, a hand-edited pair) it is replaced, so the " -"exchanged public key always belongs to the private key that encrypts and " -"decrypts. An identical file is left untouched, which keeps a second instance" -" from replacing a file another process has open for reading (Windows rejects" -" ``os.replace`` with EACCES while a handle is open)." +"The public-key file next to the private key is re-derived from the " +"private key on every load: if it is missing or does not match the key in " +"use (a rotated ``~/.ssh/id_rsa``, a hand-edited pair) it is replaced, so " +"the exchanged public key always belongs to the private key that encrypts " +"and decrypts. An identical file is left untouched, which keeps a second " +"instance from replacing a file another process has open for reading " +"(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" "秘密鍵の横にある公開鍵ファイルは、すべての読み込みで秘密鍵から再取得されます。使用中の鍵(回転された''~/.ssh/id_rsa " "''、手動で編集されたペア)が欠落しているか一致しない場合、交換された公開鍵は常に暗号化および復号化する秘密鍵に属します。同じファイルはそのまま残されているため、別のプロセスが読み取りのために開いているファイルを2番目のインスタンスが置き換えることはありません(" " Windowsは ハンドルが開いている間、'' os.replace ''をEACCESに置き換えます)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:352 -#: e935794dae5f4c2682336e72732afec3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:394 +#: 425ba3d582c3490b9375d99baa9b61e6 msgid "" -"A user-supplied keypair can be forced with ``is_custom_keys = [pub_key_path," -" pvt_key_path]``: both files must exist, parse as PEM and pair with each " -"other (a probe encrypted with the public key must decrypt with the private " -"key); an invalid pair is ignored and the default lookup is used." +"A user-supplied keypair can be forced with ``is_custom_keys = " +"[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " +"pair with each other (a probe encrypted with the public key must decrypt " +"with the private key); an invalid pair is ignored and the default lookup " +"is used." msgstr "" "ユーザー指定のキーペアは、「is_custom_keys = [pub_key_path, " "pvt_key_path]」で強制できます。両方のファイルが存在し、PEM として解析され、相互にペアになる必要があります " "(公開キーで暗号化されたプローブは秘密キーで復号化する必要があります)。無効なペアは無視され、デフォルトの検索が使用されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:357 -#: 72a43fff94f04914848603d6ede43cfd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:399 +#: 696441cc5dd44fc4af958c547c8b6b90 msgid "" "Public keys received from the server are cached in " "``network_api/.Flow/pub_key`` as ``server__.pem`` (the server " -"endpoint the key came from; ``:`` is replaced with ``_`` so IPv6 literals " -"are safe on every platform, including Windows)." +"endpoint the key came from; ``:`` is replaced with ``_`` so IPv6 literals" +" are safe on every platform, including Windows)." msgstr "" "サーバーから受信した公開キーは、「network_api/.Flow/pub_key」に「server__.pem」としてキャッシュされます" " (キーの取得元のサーバーエンドポイント。「:」は「_」に置き換えられるため、IPv6 リテラルは Windows " "を含むすべてのプラットフォームで安全です)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:363 -#: a4903fbcbc6f4c9d93c8fc3066fcc1c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:405 +#: 2a81e756d1c947d384d20dbbbe5d6d52 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM ID チェック (TOFU)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:365 -#: e30dc3b276654ea2b6ec48793d8df984 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:407 +#: 7a915eef76594c3ea715adb845fcabc6 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " -"records the peer in ``network_api/.Flow/pub_key/pub_key.json``: the object " -"key is the endpoint the peer is reachable at written as a string — " -"``str((ip, port))``, e.g. ``\"('127.0.0.1', 65432)\"``, since JSON object " -"keys are strings — the value is ``[, ]``." +"records the peer in ``network_api/.Flow/pub_key/pub_key.json``: the " +"object key is the endpoint the peer is reachable at written as a string —" +" ``str((ip, port))``, e.g. ``\"('127.0.0.1', 65432)\"``, since JSON " +"object keys are strings — the value is ``[," +" ]``." msgstr "" "すべての接続は公開鍵を平文で再交換し、各側がピアを ``network_api/.Flow/pub_key/pub_key.json`` " -"に記録します。キーは ``(ip, port)`` (ピアが到達可能なエンドポイントの Python タプル)、値は ``[<公開鍵の sha256>," -" <公開鍵 PEM>]`` です。" +"に記録します。キーは ``(ip, port)`` (ピアが到達可能なエンドポイントの Python タプル)、値は ``[<公開鍵の " +"sha256>, <公開鍵 PEM>]`` です。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:372 -#: 247a92c41f0d45ed9a5f8ad2d12bca2e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:414 +#: 4d56fbd290604113a600a56d8e89cdfb msgid "" -"First connection from an endpoint: the key is recorded and trusted (trust on" -" first use)." +"First connection from an endpoint: the key is recorded and trusted (trust" +" on first use)." msgstr "エンドポイントからの最初の接続: キーは記録され、信頼されます (初回使用時の信頼)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:374 -#: 7adc6b725e7244df8bc1b861b4cec80c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:416 +#: a6be8828e0594ddc8aa71229934cc73d msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -858,49 +944,52 @@ msgstr "" "*同じ* キーを提示するその後の接続: 受け入れられました。エンドポイントが変更された場合 (動的 IP / " "ユーザーが変更したポート)、レコードは複製されるのではなく、新しい ``(ip, port)`` に移動されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:377 -#: ba6d10fef7fb42cd8dd6518c415762d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 +#: fda350faac9a4efd82575a386fc929c0 msgid "" "Later connection presenting a *different* key for an already-recorded " -"endpoint: the connection is rejected (``/crypto_reject`` is received and the" -" client closes)." +"endpoint: the connection is rejected (``/crypto_reject`` is received and " +"the client closes)." msgstr "" "すでに記録されているエンドポイントに対して *異なる* キーを提示するその後の接続: 接続は拒否されます (``/crypto_reject`` " "が受信され、クライアントが閉じます)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:381 -#: 7f2ec5e5c2604098906635697130c4fd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:423 +#: 9d62655e00324c518633c6c1d615d515 msgid "" "The client-side record is keyed by the fixed server address, so a server " "that changes its public key (for example a MITM substitution) is always " -"rejected on later connections. To reset trust (rotated keys, new server), " -"delete the ``pub_key.json`` entry (or the whole file)." +"rejected on later connections. To reset trust (rotated keys, new server)," +" delete the ``pub_key.json`` entry (or the whole file)." msgstr "" "クライアント側のレコードは固定サーバー アドレスによってキー設定されるため、公開キーを変更するサーバー (MITM 置換など) " -"は、以降の接続では常に拒否されます。信頼 (ローテーションされたキー、新しいサーバー) をリセットするには、``pub_key.json`` エントリ " -"(またはファイル全体) を削除します。" +"は、以降の接続では常に拒否されます。信頼 (ローテーションされたキー、新しいサーバー) をリセットするには、``pub_key.json`` " +"エントリ (またはファイル全体) を削除します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 -#: 9a08bf51aea742de8d0a0f351d055b3a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:429 +#: 799c58ee59b0416688562166f58a14c1 msgid "Handshake" msgstr "ハンドシェーク" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:389 -#: 879e1be6d2de4859bc0777d1cd1682f8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:431 +#: 6f92afe3b8314a9985b62fe55cdeee70 #, fuzzy msgid "" "Right after connecting, the client announces its encryption mode with a " -"plaintext ``/crypto_mode <0|1>`` and waits up to 10 seconds for the server's" -" answer; a mode mismatch closes the connection. It then sends a plaintext " -"``/crypto_key_exchange `` greeting; the server replies with " -"``/crypto_key_exchange_ack ``. Both " -"sides then push their public key files over the file-transfer mechanism " -"(plaintext) and TOFU-check the received key. Both sides switch to encrypted " -"mode only after ``/crypto_ready`` has been received from the peer (so " -"plaintext and ciphertext never interleave on a connection). On later " -"connections the keys are re-exchanged and TOFU-checked again; the exchange " -"is never skipped, only the identity check short-circuits for known keys. " -"Public-key pushes are only accepted while a handshake is in progress, so an " +"plaintext ``/crypto_mode <0|1>`` and waits up to 10 seconds for the " +"server's answer; a mode mismatch closes the connection. It then sends a " +"plaintext ``/crypto_key_exchange `` greeting; the server " +"replies with ``/crypto_key_exchange_ack " +"``. Both (plaintext) and TOFU-check the received key. Both sides " +"switch to encrypted mode only after ``/crypto_ready`` has been received " +"from the peer (so plaintext and framed traffic never interleave on a " +"connection), then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted while a handshake is in progress, so an " "arbitrary unauthenticated server cannot poison the registry." msgstr "" "クライアントは接続直後に平文の ``/crypto_key_exchange`` " @@ -910,148 +999,177 @@ msgstr "" "(そのため、平文と暗号文が接続上でインターリーブされることはありません)。その後の接続では、キーが再交換され、再度 TOFU " "チェックが行われます。交換は決してスキップされず、既知のキーに対する ID チェックのみがショートします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:406 -#: a36303a34b174e6a8c4a421f297e4452 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:451 +#: a501267a3c9848e6aac40eb13359da87 msgid "Replay protection" msgstr "リプレイ保護" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:408 -#: dd11c43faac347858ff85f846d7af6d1 -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line on " -"the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does not " -"match the current session (ciphertext replayed from an older connection) or " -"whose sequence number is not the expected one (ciphertext replayed within " -"the session / out of order); both counters reset when the socket flips to " +#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 +#: cde1f1712c904c89aa5838bc54c715b6 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " "encrypted mode after a (re-)exchange." msgstr "" -"ハンドシェイクではランダムなセッション nonce が交換され、回線上のすべての暗号化された回線には、それに加えて接続ごとのシーケンス番号 " -"``||`` が付けられます。受信者は、ノンスが現在のセッションと一致しない行 " -"(古い接続から再生された暗号文)、またはシーケンス番号が予期したものではない行 (セッション内で再生された暗号文 / 順序が乱れている) " -"をドロップします。 (再) 交換後にソケットが暗号化モードに切り替わると、両方のカウンタがリセットされます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:417 -#: ddfd9d5832b541ba81de53f2f9abd91b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:469 +#: 51478387b6dd4b2e9f7a3d10f72a8b90 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 +#: a47f9db0c3674a12ab6d3ab5d056a8c4 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:483 +#: 6740137a28b84e5dbb3f85e8d58d32b5 msgid "Decode verification and key rotation" msgstr "デコード検証とキーローテーション" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 -#: 2f8d9ddc0f434f0b98331fc3c14f710b -msgid "" -"Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated by " -"``_``). If a message cannot be decrypted, or the suffix is missing, the " -"socket drops out of encrypted mode, the local key is reloaded, and a forced " -"``/crypto_key_exchange`` restarts the handshake so both sides re-push their " -"current public keys. The re-exchange itself re-runs the TOFU check: a peer " -"whose key did not change is accepted again, while a peer presenting a " -"*different* key for a recorded endpoint is rejected (see the TOFU section " -"above). A user who intentionally rotates a keypair must delete the stale " -"``pub_key.json`` entry (or the whole file) on the peer side to re-trust the " -"new key." +#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 +#: 8445bf9265124e38a642f9d46fc43c36 +msgid "" +"Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " +"by ``_``). If a message cannot be decrypted, or the suffix is missing, " +"the socket drops out of encrypted mode, the local key is reloaded, and a " +"forced ``/crypto_key_exchange`` restarts the handshake so both sides re-" +"push their current public keys. The re-exchange itself re-runs the TOFU " +"check: a peer whose key did not change is accepted again, while a peer " +"presenting a *different* key for a recorded endpoint is rejected (see the" +" TOFU section above). A user who intentionally rotates a keypair must " +"delete the stale ``pub_key.json`` entry (or the whole file) on the peer " +"side to re-trust the new key." msgstr "" "すべての暗号化された平文には、固定サフィックス ``_VALID`` (``_`` で区切られる) " "が付けられます。メッセージを復号化できない場合、またはサフィックスが欠落している場合、ソケットは暗号化モードから外れ、ローカル鍵が再ロードされ、強制的な" -" ``/crypto_key_exchange`` によってハンドシェイクが再開されるため、双方は現在の公開鍵を再プッシュします。再交換自体によって " -"TOFU チェックが再実行されます。キーが変更されなかったピアは再び受け入れられますが、記録されたエンドポイントに対して *異なる* " +" ``/crypto_key_exchange`` " +"によってハンドシェイクが再開されるため、双方は現在の公開鍵を再プッシュします。再交換自体によって TOFU " +"チェックが再実行されます。キーが変更されなかったピアは再び受け入れられますが、記録されたエンドポイントに対して *異なる* " "キーを提示するピアは拒否されます (上記の TOFU " "セクションを参照)。意図的にキーペアをローテーションするユーザーは、新しいキーを再度信頼するには、ピア側の古い ``pub_key.json`` " "エントリ (またはファイル全体) を削除する必要があります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:430 -#: 3b373e99ee2c4aff93e808c206dfb3f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:496 +#: 5698fde8f08b4be3a059d92a69ae3459 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures the connection is closed instead of re-" -"exchanging, so a garbage-injection or persistent-mismatch storm cannot spin " -"the loop forever. A successful decryption resets the counter." +"exchanging, so a garbage-injection or persistent-mismatch storm cannot " +"spin the loop forever. Genuine peer traffic (messages and commands other " +"than the protocol's own handshake/coordination lines) resets the counter." +" Frames the peer had already sent when this side dropped out of encrypted" +" mode are stale: they cannot be authenticated any more, so they are " +"consumed and dropped — they neither surface as messages nor reset the " +"counter." msgstr "" "再交換はサーキットブレークです。 MAX_DECODE_FAILURES (3) " "連続したデコード失敗の後、再交換ではなく接続が閉じられるため、ガベージインジェクションや永続的な不一致のストームによってループが永久に回転することはありません。復号化が成功すると、カウンターがリセットされます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:438 -#: aaefbbdc89554770aebdf60c16950f0f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:508 +#: 6569277ee0b644488685204e70c3e425 msgid "TCP Client command API" msgstr "TCPクライアントコマンドAPI" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:440 -#: 22612be28f9d4da5b01258de1c7520f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:510 +#: b2ab9f46d6b14c8eaa97512fd117c6db msgid "" "The client supports both built-in commands that the user can type in the " -"console, and a command extension API similar to the server. The main entry " -"point for incoming server commands is `handle_server_command`, while user-" -"typed commands are processed in `interactive_mode`." +"console, and a command extension API similar to the server. The main " +"entry point for incoming server commands is `handle_server_command`, " +"while user-typed commands are processed in `interactive_mode`." msgstr "" "クライアントは、ユーザーがコンソールに入力できる組み込みコマンドと、サーバーと同様のコマンド拡張 API の両方をサポートします。受信サーバー " "コマンドのメイン エントリ ポイントは `handle_server_command` ですが、ユーザーが入力したコマンドは " "`interactive_mode` で処理されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:446 -#: 5607f70cfddc4466946bc9082ce494ab +#: ../../source/Network_APIs/TCP_Client_APIs.rst:516 +#: 5e296796f3694cdfbf48c8538979bb7f msgid "" -"The client supports two modes of operation: interactive console input (when " -"``is_input_command_in_console`` is ``True``) or programmatic control (when " -"it is ``False``)." +"The client supports two modes of operation: interactive console input " +"(when ``is_input_command_in_console`` is ``True``) or programmatic " +"control (when it is ``False``)." msgstr "" "クライアントは、対話型コンソール入力 ( ``is_input_command_in_console`` が ``True`` の場合) " "またはプログラムによる制御 (``False`` の場合) の 2 つの動作モードをサポートします。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:450 -#: bfa689507e214d7a961f1042698850ce +#: ../../source/Network_APIs/TCP_Client_APIs.rst:520 +#: 0261c3323c4248e3bfb846d5751da36f msgid "Built-in client console commands (user-typed) include:" msgstr "組み込みのクライアント コンソール コマンド (ユーザー入力) には次のものがあります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:452 -#: 9a2bcb83868f473aae1fa0090af2dd49 -msgid "" -"``/quit``: sends a quit message to the server and closes the connection." +#: ../../source/Network_APIs/TCP_Client_APIs.rst:522 +#: d466b066b3654e7183cf72f86523bcd1 +msgid "``/quit``: sends a quit message to the server and closes the connection." msgstr "``/quit``: サーバーに終了メッセージを送信し、接続を閉じます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 -#: 84be485738544bd98d7e0d2f49415cda +#: ../../source/Network_APIs/TCP_Client_APIs.rst:523 +#: 3d22aacfa1914a879be55a3518fb2a7e msgid "" "``/send_msg ``: sends the second token of the line as a chat " -"message (``send_message_to_server`` drops the command name and sends only " -"the next token)." +"message (``send_message_to_server`` drops the command name and sends only" +" the next token)." msgstr "" "''/ send_msg '':行の2番目のトークンをチャットメッセージとして送信します('' " "send_message_to_server ''はコマンド名を削除し、次のトークンのみを送信します)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:456 -#: 6bb0b49ebc5743fe9332f66948330822 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 +#: 16b438ba77f945d2a68bb24f97a69ef5 msgid "``/file ``: starts a file transfer from client to server." msgstr "``/file ``: クライアントからサーバーへのファイル転送を開始します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:457 -#: eb7e88c4607340ba8795bacb617ae98a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:527 +#: 65a2f7cca5684f21ae85deaf2675b2fa #, fuzzy msgid "" -"``/multiple_file ...``: sends multiple files from client to " -"server, one sender thread per file, at most ``max_thread_num`` of them at a " -"time." +"``/multiple_file ...``: sends multiple files from client " +"to server, one sender thread per file, at most ``max_thread_num`` of them" +" at a time." msgstr "" "``/multiple_file ...``: 複数のファイルをクライアントからサーバに送信します " "(セマフォの制限に従って、それぞれが独自のスレッドにあります)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:460 -#: 98dda85c8e2a4623a9dc2d39643cddbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:530 +#: 0cb1732f55e8499ab36b6923ed56a8ec msgid "" "``/file_folder ``: sends an entire folder from client to " "server, preserving the directory structure." -msgstr "" -"``/file_folder ``: ディレクトリ構造を維持したまま、フォルダ全体をクライアントからサーバーに送信します。" +msgstr "``/file_folder ``: ディレクトリ構造を維持したまま、フォルダ全体をクライアントからサーバーに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:462 -#: 1f2e6b52be7f4875aa8434ff22117ee0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:532 +#: f8d95f978af24a0d8056fc369d555f5f msgid "" -"``/multiple_file_folder ...``: sends multiple folders " -"from client to server." +"``/multiple_file_folder ...``: sends multiple folders" +" from client to server." msgstr "" "``/multiple_file_folder ...``: " "複数のフォルダをクライアントからサーバーに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:464 -#: 48811f3665104578b8921efe71ada53a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:534 +#: c3477f2df53d499db3c6a9b41f8bdedf msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands (client-only; the server refuses " @@ -1060,372 +1178,385 @@ msgstr "" "''/ forward_file ''、''/ forward_folder ''、''/ forward_send_msg " "'':転送拡張機能のコンソールコマンド(クライアント専用。サーバーが拒否)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:468 -#: 3fe8e4c73ecc42e98bde402ff3858c64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:538 +#: d6c13262c84f4ae2a43371ee4e09cfad msgid "" "Ctrl-C and EOF close the connection, send a final ``/quit`` and wait 0.5 " "seconds before the process ends." msgstr "Ctrl - CとEOFが接続を閉じ、最後の''/ quit ''を送信し、プロセスが終了するまで0.5秒待ちます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 -#: c330e7622ffc46a19b41f3e6394c3dc8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 +#: 7971066cb1de4bc2b8047248fa93d58e msgid "" "*Note: Unlike the server, the client does not have built-in ``/help``, " -"``/time``, or ``/clients`` commands because those are typically handled by " -"the server. The client's ``/help`` command is not implemented; users should " -"refer to the server documentation for available commands.*" +"``/time``, or ``/clients`` commands because those are typically handled " +"by the server. The client's ``/help`` command is not implemented; users " +"should refer to the server documentation for available commands.*" msgstr "" "*注意: サーバーとは異なり、クライアントには組み込みの ``/help``、``/time``、または ``/clients`` " "コマンドがありません。これらは通常、サーバによって処理されるためです。クライアントの ``/help`` " "コマンドは実装されていません。ユーザーは、使用可能なコマンドについてはサーバーのドキュメントを参照する必要があります。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:477 -#: f7ea97482c86419cb7e1e5db99cd79c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:547 +#: 44cf1d07758f4fa89eb47d9aad2369a5 msgid "" -"A user-typed line that is not built-in and not a registered custom command " -"is sent to the server as a chat message, and the client logs ``Unknown " -"server command: `` for it (so plain chat text is echoed with that " -"wording too)." -msgstr "" -"組み込まれておらず、登録されていないカスタムコマンドでもないユーザータイプの行がチャットメッセージとしてサーバーに送信され、クライアントはそのために「不明なサーバーコマンド:」をログに記録します(したがって、プレーンチャットテキストもその表現でエコーされます)。" +"A user-typed line that is not built-in and not a registered custom " +"command is sent to the server as a chat message, and the client logs " +"``Unknown server command: `` for it (so plain chat text is echoed " +"with that wording too)." +msgstr "組み込まれておらず、登録されていないカスタムコマンドでもないユーザータイプの行がチャットメッセージとしてサーバーに送信され、クライアントはそのために「不明なサーバーコマンド:」をログに記録します(したがって、プレーンチャットテキストもその表現でエコーされます)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:482 -#: 677fc4a9eabd4d5ab97bf0e2e73b05ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:552 +#: 7f463379f38f44558c3121e202f9343b msgid "" -"*Note: a custom command is matched against the first token of the line, so a" -" handler registered for ``/mycmd`` runs when the user types ``/mycmd ...``.*" +"*Note: a custom command is matched against the first token of the line, " +"so a handler registered for ``/mycmd`` runs when the user types ``/mycmd " +"...``.*" msgstr "" "*注:カスタムコマンドは行の最初のトークンと一致するため、ユーザーが「/ mycmd...」と入力すると、「/ " "mycmd」に登録されたハンドラーが実行されます。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 -#: 1325358de66e4303bb8f9ff817415890 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:555 +#: ae962d51828a4e859fd9080b6eb9ec88 msgid "The command extension API for the client is defined as:" msgstr "クライアントのコマンド拡張 API は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:494 -#: 24f976022e4245e0aa95c2cf112854c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:565 +#: cfa1714f672d4103bae0af84db5a1d63 msgid "" "The arguments of the `register_command` function are the same as on the " "server side:" msgstr "「register_command」関数の引数はサーバー側の引数と同じです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:497 -#: 087de666d0cb46b39328508976a7dc92 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:568 +#: 2f936e153d6f4587b918adf94d6ba438 msgid "" -"``command_name``: The name of the command to register (should start with a " -"slash, e.g., ``/mycmd``)." +"``command_name``: The name of the command to register (should start with " +"a slash, e.g., ``/mycmd``)." msgstr "``command_name``: 登録するコマンドの名前 (``/mycmd`` のようにスラッシュで始める必要があります)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:499 -#: 3acea6e2461e40f9b02b90154cb62c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 +#: c19aa473ddf5488cbe8b5039b68e08cf msgid "" -"``handler``: The function to call when the command is received. The handler " -"must accept three parameters: ``client_socket``, ``client_address``, and " -"``command``." +"``handler``: The function to call when the command is received. The " +"handler must accept three parameters: ``client_socket``, " +"``client_address``, and ``command``." msgstr "" "``handler``: コマンドを受信したときに呼び出す関数。ハンドラは 3 " -"つのパラメータ、``client_socket``、``client_address``、および ``command`` を受け入れる必要があります。" +"つのパラメータ、``client_socket``、``client_address``、および ``command`` " +"を受け入れる必要があります。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:501 -#: 60a8ef01850843b48c37e1ce0248d247 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 +#: d327d91dee274ac1951b18ee3700c15a msgid "" "``where_to_run``: Specifies where the command should be executed. Valid " -"values are ``\"server\"`` (command sent from the server) or ``\"client\"`` " -"(command typed in the client's console)." +"values are ``\"server\"`` (command sent from the server) or " +"``\"client\"`` (command typed in the client's console)." msgstr "" -"``where_to_run``: コマンドを実行する場所を指定します。有効な値は、``\"server\"`` (サーバーから送信されたコマンド) " -"または ``\"client\"`` (クライアントのコンソールに入力されたコマンド) です。" +"``where_to_run``: コマンドを実行する場所を指定します。有効な値は、``\"server\"`` " +"(サーバーから送信されたコマンド) または ``\"client\"`` (クライアントのコンソールに入力されたコマンド) です。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:503 -#: 0a59b9453a5145ffa92a1e91741cfa49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:574 +#: 17b9e2d9c50344bdb8e704423df3c4c8 msgid "" "``run_in_thread``: A boolean indicating whether to run the handler in a " "separate thread from the thread pool." msgstr "``run_in_thread``: ハンドラをスレッドプールとは別のスレッドで実行するかどうかを示すブール値。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:506 -#: 73925e7106344a879ba8a7e1f4ea6408 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:577 +#: a4fcfb0b0f89415fa269eccf366b2539 msgid "" "It returns ``False`` when ``where_to_run`` is neither ``\"server\"`` nor " -"``\"client\"`` (nothing is registered then); on success it returns ``None``." +"``\"client\"`` (nothing is registered then); on success it returns " +"``None``." msgstr "" "'' where_to_run ''が''\" server \"''でも''\" client \"''でもない場合は'' False " "''を返します(その後は何も登録されません)。成功すると'' None ''を返します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:509 -#: e9b4b0ddbfd143759ab38205955ff2de +#: ../../source/Network_APIs/TCP_Client_APIs.rst:580 +#: 55e17f10381d4c6e9c13c484a6d7b2f7 +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code, on the client as on the server; the command's first token " +"selects it, exactly as it does for a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 +#: 889fe9598c0045ccaee7de4e93d59f8e #, python-brace-format msgid "" -"*Note: The client stores registered commands in the same structure as the " -"server: ``self._custom_handlers = [{}, {}]``, where index 0 is for commands " -"coming from the server, and index 1 is for commands typed in the client " -"console.*" +"*Note: The client stores registered commands in the same structure as the" +" server: ``self._custom_handlers = [{}, {}]``, where index 0 is for " +"commands coming from the server, and index 1 is for commands typed in the" +" client console.*" msgstr "" "*注意: クライアントは、登録されたコマンドをサーバーと同じ構造に保存します: ``self._custom_handlers = [{}, " "{}]``。インデックス 0 はサーバーからのコマンド用、インデックス 1 はクライアント コンソールに入力されたコマンド用です。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:514 -#: 87c31576643d4e328b32b14b69b4f818 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:589 +#: 9a244a7eb66d4c0c9666537c17e6f3ac msgid "" -"The client also provides the `submit_task` method to submit functions to its" -" internal thread pool executor, and `_execute_custom_handler` to safely " -"execute registered handlers with error handling." +"The client also provides the `submit_task` method to submit functions to " +"its internal thread pool executor, and `_execute_custom_handler` to " +"safely execute registered handlers with error handling." msgstr "" "クライアントは、内部スレッド プール エグゼキュータに関数を送信するための `submit_task` " "メソッドと、エラー処理を備えた登録済みハンドラーを安全に実行するための `_execute_custom_handler` メソッドも提供します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:519 -#: e64628a99ba249f8acef54a08b182c79 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:594 +#: 4cbf4048c25443dda40d622c49a8e26e #, fuzzy msgid "" -"The `submit_task` method works identically to the server version: it submits" -" a callable to the client's thread pool, using a semaphore to limit " -"concurrency to ``max_custom_workers``, and returns the " -"``concurrent.futures.Future`` for it (the worker slot is released when the " -"call finishes)." +"The `submit_task` method works identically to the server version: it " +"submits a callable to the client's thread pool, using a semaphore to " +"limit concurrency to ``max_custom_workers``, and returns the " +"``concurrent.futures.Future`` for it (the worker slot is released when " +"the call finishes)." msgstr "" "`submit_task` メソッドはサーバー バージョンと同じように動作します。セマフォを使用して同時実行数を " "`max_custom_workers` に制限し、呼び出し可能ファイルをクライアントのスレッド プールに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 -#: e8f3baf910cb4b2497cb6f6eab9053e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:601 +#: 3a2bd1984dd14769b92c6e40c6ad357c msgid "Temporary server and client creation" msgstr "一時的なサーバーとクライアントの作成" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:528 -#: 26cf9b3fd35d4af993c53f9a8e4bffb6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:603 +#: 0c9b9ad8c6ca4f679f8e54fb58940d3e msgid "" -"The client also includes temporary TCP server and client creation APIs. They" -" are similar to those in the server class but use `self.client_host` as the " -"local binding address." +"The client also includes temporary TCP server and client creation APIs. " +"They are similar to those in the server class but use `self.client_host` " +"as the local binding address." msgstr "" "クライアントには、一時的な TCP サーバーとクライアント作成 API も含まれています。これらはサーバー クラスのものと似ていますが、ローカル " "バインディング アドレスとして `self.client_host` を使用します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 -#: 6fb3cae805964394bf0864814b4b8ecd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:616 +#: 03e3fc356d234c01a0bd94bad68b8ddc #, fuzzy msgid "" -"`create_temporary_server` binds to ``(self.client_host, port)``. If ``port``" -" is ``None``, it calls ``self.palloc()`` to obtain a port (``0`` in " -"automatic mode, letting the OS choose, or a range port in manual mode) and " -"raises ``RuntimeError`` when no port can be allocated. It returns a tuple " -"``(port, server_thread, stop_event)``." +"`create_temporary_server` binds to ``(self.client_host, port)``. If " +"``port`` is ``None``, it calls ``self.palloc()`` to obtain a port (``0`` " +"in automatic mode, letting the OS choose, or a range port in manual mode)" +" and raises ``RuntimeError`` when no port can be allocated. It returns a " +"tuple ``(port, server_thread, stop_event)``." msgstr "" -"`create_temporary_server` は `(self.client_host, port)` にバインドします。 ``port`` が " -"``None`` の場合、``self.palloc()`` を呼び出してポートを取得するか (手動モードの場合)、または ``0`` を返します " -"(OS によって割り当てられます)。タプル「(port,server_thread,stop_event)」を返します。" +"`create_temporary_server` は `(self.client_host, port)` にバインドします。 ``port``" +" が ``None`` の場合、``self.palloc()`` を呼び出してポートを取得するか (手動モードの場合)、または ``0`` " +"を返します (OS によって割り当てられます)。タプル「(port,server_thread,stop_event)」を返します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:558 -#: 8ab44b7d114a4eca8079a87b61ca219f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:633 +#: 61b63d2c156f4512aead02cbbfe0569e #, fuzzy msgid "" -"`create_temporary_client` connects to the specified server. If ``bind_port``" -" is given, it binds to ``(self.client_host, bind_port)``. If ``bind_port`` " -"is ``None``, the socket is left unbound before connecting and the OS picks " -"the local port. It returns a tuple ``(client_sock, recv_thread, " -"stop_event)``." +"`create_temporary_client` connects to the specified server. If " +"``bind_port`` is given, it binds to ``(self.client_host, bind_port)``. If" +" ``bind_port`` is ``None``, the socket is left unbound before connecting " +"and the OS picks the local port. It returns a tuple ``(client_sock, " +"recv_thread, stop_event)``." msgstr "" "`create_temporary_client` は指定されたサーバーに接続します。 ``bind_port`` が指定されている場合は、 " "``(self.client_host,bind_port)`` にバインドします。 ``bind_port`` が ``None`` " "の場合、``self.palloc()`` 経由でポートを取得し、自動的にバインドします。タプル ``(client_sock, " "recv_thread, stop_event)`` を返します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:564 -#: d5a66d0848e24412a1e121fba226cff8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 +#: a528285ae2714861bf6162938ad1aa0a msgid "" -"These methods allow the client to act as a temporary server or to spawn a " -"separate client connection for auxiliary tasks (such as file transfers), " -"without interfering with the main connection." +"These methods allow the client to act as a temporary server or to spawn a" +" separate client connection for auxiliary tasks (such as file transfers)," +" without interfering with the main connection." msgstr "" "これらのメソッドを使用すると、クライアントはメインの接続を妨げることなく、一時的なサーバーとして機能したり、補助タスク (ファイル転送など) " "のために別のクライアント接続を生成したりできます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 -#: 16bd0374c6194f4b9bd2db749597217f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:645 +#: 46a7a0338f5040f38903a61af8ff8ae5 msgid "TCP Client console commands (interactive mode)" msgstr "TCPクライアントコンソールコマンド(対話モード)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 -#: dbe05db8944f49818decf56adb4855b6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:647 +#: 8a93646c1be14bb8bfcb5be5140f1572 msgid "" -"When the client is started with ``is_input_command_in_console=True`` (the " -"default), the `interactive_mode` method is invoked. This method reads lines " -"from standard input and processes them." +"When the client is started with ``is_input_command_in_console=True`` (the" +" default), the `interactive_mode` method is invoked. This method reads " +"lines from standard input and processes them." msgstr "" "クライアントが ``is_input_command_in_console=True`` (デフォルト) で起動されると、 " "`interactive_mode` メソッドが呼び出されます。このメソッドは、標準入力から行を読み取り、処理します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:576 -#: eea6d19cd2f44de6ae2bd67081f49b5a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:651 +#: 5370ea52c70741728cc72ae1618e65e8 msgid "Supported console commands (user-typed) include:" msgstr "サポートされているコンソール コマンド (ユーザー入力) は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:578 -#: 3d1b84c153974f14bdd57c17a892a158 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 +#: 3ee645c39b844b1e8b14a1eb54bef876 msgid "``/quit``: closes the connection and exits the client." msgstr "``/quit``: 接続を閉じてクライアントを終了します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:579 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:654 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" -"``/send_msg ``: sends the second token of the line to the server" -" as a chat message." +"``/send_msg ``: sends the second token of the line to the " +"server as a chat message." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:581 -#: 50b34e795f4a4d1595f8a2f6c1ebfad5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:656 +#: c34b32925f024797841232729eca131e msgid "``/file ``: sends a single file to the server." msgstr "``/file ``: 単一のファイルをサーバーに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:582 -#: d90b52a3886c48c1b86fe1d4a08adb11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:657 +#: 739e72b7a06a4eefa6cdd1a952d3d781 #, fuzzy msgid "" -"``/multiple_file ...``: sends multiple files to the server, " -"one thread per file, limited to ``max_thread_num`` at a time." +"``/multiple_file ...``: sends multiple files to the " +"server, one thread per file, limited to ``max_thread_num`` at a time." msgstr "" "``/multiple_file ...``: 複数のファイルをサーバーに同時に送信します " "(``max_thread_num`` によって制限されます)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:583 -#: 66d2f7d1d87847e39e4172ae789b6a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:658 +#: d9421edab02e4b33850db50a0011ad16 msgid "" "``/file_folder ``: sends an entire folder to the server, " "recursively." msgstr "``/file_folder ``: フォルダ全体をサーバーに再帰的に送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 -#: 321bde30af944560b349b5dd6a162a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:659 +#: efd08f6cefcd4f44bcd4ff0687cee8bc msgid "" -"``/multiple_file_folder ...``: sends multiple folders to" -" the server." -msgstr "" -"``/multiple_file_folder ...``: 複数のフォルダをサーバーに送信します。" +"``/multiple_file_folder ...``: sends multiple folders" +" to the server." +msgstr "``/multiple_file_folder ...``: 複数のフォルダをサーバーに送信します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:585 -#: 9feff7033be8445599773701f51926df +#: ../../source/Network_APIs/TCP_Client_APIs.rst:660 +#: ed70094fabb34d46afadb56fd5c7c37d msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:587 -#: 6489b5a0fb2948748f0f1bd5f303c779 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:662 +#: 1dc2bd43fd56402785fb76b3895b03b2 msgid "" -"Any other non-empty line is sent as-is to the server — the same path chat " -"text takes." +"Any other non-empty line is sent as-is to the server — the same path chat" +" text takes." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:591 -#: 3295a0d774d0473da7c5d7405d72abd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:666 +#: d72b6516a43b4f26bb5750604f41ff74 msgid "" -"The client does not have a built-in ``/help`` command. Please refer to the " -"server's help for available commands (e.g., by typing ``/help`` after " -"connecting to the server)." +"The client does not have a built-in ``/help`` command. Please refer to " +"the server's help for available commands (e.g., by typing ``/help`` after" +" connecting to the server)." msgstr "" "クライアントには組み込みの ``/help`` コマンドがありません。使用可能なコマンドについては、サーバーのヘルプを参照してください " "(サーバーに接続した後、「/help」と入力するなど)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:595 -#: dd63bf8cfd3641c0be9adad9b06aa8e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:670 +#: e6081a66251a4a57bc5724dccb8c852b msgid "" -"A line registered with ``register_command(..., where_to_run=\"client\")`` " -"runs when its first token matches a registered name; handlers registered " -"with ``where_to_run=\"server\"`` match the first token of the lines the " +"A line registered with ``register_command(..., where_to_run=\"client\")``" +" runs when its first token matches a registered name; handlers registered" +" with ``where_to_run=\"server\"`` match the first token of the lines the " "server sends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:600 -#: 7efd09ba06ba4067b03810eb838caa24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:675 +#: 4befe76529e04e859f9422d8ebe3921a msgid "" -"*Note: The client logs ``Unknown server command: `` for any line it " -"did not recognise, including plain chat text, because those lines take the " -"same fallback path.*" +"*Note: The client logs ``Unknown server command: `` for any line it" +" did not recognise, including plain chat text, because those lines take " +"the same fallback path.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:604 -#: 8cd9357ee0494a20b9ba9d4b8ed3514b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:679 +#: 2cbc548821b84721b1aea4f88573f02f msgid "Example interactive session::" msgstr "インタラクティブセッションの例::" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:617 -#: 45b4cc10dbab4342a2653adafcad5e63 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:692 +#: bd36c89659694280b349cc621b598254 msgid "TCP Client file transfer API" msgstr "TCPクライアントファイル転送API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:619 -#: 2476ecf352184c39a27da75545ff67b9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 +#: 0f20edbf8203493aa579cb5a1195712b msgid "" -"The TCP client contains a file transfer subsystem that supports both client-" -"to-server and server-to-client transfers, using the same underlying protocol" -" as the server." +"The TCP client contains a file transfer subsystem that supports both " +"client-to-server and server-to-client transfers, using the same " +"underlying protocol as the server." msgstr "" "TCP " "クライアントには、サーバーと同じ基盤プロトコルを使用して、クライアントからサーバーへの転送とサーバーからクライアントへの転送の両方をサポートするファイル転送サブシステムが含まれています。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:623 -#: 37c359049bd04adcbcde988494c16efa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:698 +#: 02806a329fba478293ef172f63bfb93d msgid "" -"As with the server documentation, only the list of APIs is provided here. " -"For detailed internal flow, please refer to the server documentation or the " -"source code." +"As with the server documentation, only the list of APIs is provided here." +" For detailed internal flow, please refer to the server documentation or " +"the source code." msgstr "" "サーバーのドキュメントと同様に、ここでは API のリストのみを提供します。内部フローの詳細については、サーバーのドキュメントまたはソース " "コードを参照してください。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:627 -#: a0aef36e6c984775b79dc1c35e39cd61 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 +#: 2a7f8a3995cf4e2b81a3bf5c3c85b0fa msgid "The file transfer API for the client includes:" msgstr "クライアント用のファイル転送 API には次のものが含まれます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:629 -#: e340f1fe00774c58bc70b398a745589d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:704 +#: dc5da9cf7ac441c8842cc97d904582ba msgid "The basic function for client-to-server file transfer is:" msgstr "クライアントからサーバーへのファイル転送の基本機能は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 -#: 3cfc45f71fac4d49b0c188b84068d5b7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:714 +#: db4145949f7a42aab5ff42bf72d6ff2e msgid "" "The non-``_thread`` versions take the destination folder as a required " -"argument (the ``_thread`` wrappers default it to ``None``, which means the " -"default transfer folder)." +"argument (the ``_thread`` wrappers default it to ``None``, which means " +"the default transfer folder)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:643 -#: 6058cc068109448faaad1e4936bb7863 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:718 +#: 743dd6f0cdba49678277c1d19c178f20 msgid "" -"For server-initiated transfers (server-to-client), the client provides these" -" handlers:" +"For server-initiated transfers (server-to-client), the client provides " +"these handlers:" msgstr "サーバーが開始する転送 (サーバーからクライアント) の場合、クライアントは次のハンドラーを提供します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 -#: 1e596cb7ccd942aeb30e335c53e1afa1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:728 +#: 72f8a6d975094c7984fbef810a422975 msgid "The low-level receive mode function is:" msgstr "低レベル受信モード関数は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:661 -#: 885c49e37dd94f2bb3aca9d95dc72222 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:736 +#: b04d81d08ea941b3b6beea16e4a05bc0 msgid "And the low-level send mode function is:" msgstr "低レベル送信モード関数は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:668 -#: 17759b30b9ae4c68b00432ae33741a99 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:744 +#: 724cadb0ca764d9aaafd664c63b858d6 msgid "" -"``pause_fid`` is the forwarding id used to pause/resume the transfer with " -"``/pause_trans`` / ``/start_trans``." +"``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) " +"addresses; ``peer`` is the transfer's original receiver and " +"``resume_offset`` continues an interrupted file from the byte the " +"receiver already holds." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:671 -#: 4dc07ef115aa4712807fede2f2040e12 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 +#: f5823da74e1a4879a65624511d10e0cb msgid "" -"We recommend that for client-to-server file transfers, you use the console " -"commands (``/file``, ``/file_folder``, etc.) rather than calling these APIs " -"directly, because the console commands already handle threading and " -"semaphore limits correctly. If you need to call the API directly, use the " -"`_thread` versions (e.g., `file_transfer_client_recv_client_start_thread`) " -"to avoid blocking the main thread." +"We recommend that for client-to-server file transfers, you use the " +"console commands (``/file``, ``/file_folder``, etc.) rather than calling " +"these APIs directly, because the console commands already handle " +"threading and semaphore limits correctly. If you need to call the API " +"directly, use the `_thread` versions (e.g., " +"`file_transfer_client_recv_client_start_thread`) to avoid blocking the " +"main thread." msgstr "" "クライアントからサーバーへのファイル転送には、これらの API を直接呼び出すのではなく、コンソール コマンド " "(``/file``、``/file_folder`` など) を使用することをお勧めします。これは、コンソール " @@ -1433,69 +1564,71 @@ msgstr "" "を直接呼び出す必要がある場合は、メインスレッドのブロックを避けるために、`_thread` バージョン (例: " "`file_transfer_client_recv_client_start_thread`) を使用してください。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:680 -#: 1165a3c7f2bc470da7c706aead0fc73f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 +#: 2d0ea3d6726e43a3b3b551bf23c5ce00 msgid "" -"*Note: The file transfer API functions follow the same handshake protocol as" -" the server: the initiator sends a command over the main connection, then a " -"temporary port is negotiated, and the actual file data is transferred over a" -" separate TCP connection.*" +"*Note: The file transfer API functions follow the same handshake protocol" +" as the server: the initiator sends a command over the main connection, " +"then a temporary port is negotiated, and the actual file data is " +"transferred over a separate TCP connection.*" msgstr "" "*注意: ファイル転送 API 関数はサーバーと同じハンドシェイク " "プロトコルに従います。イニシエーターはメイン接続を介してコマンドを送信し、一時ポートがネゴシエートされ、実際のファイル データは別の TCP " "接続を介して転送されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:687 -#: 95c14f0f60154aa3b15d0dd0dfe41a69 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 +#: 997f666f071d44499a4be946c3a808e5 msgid "Port allocation API" msgstr "ポート割り当てAPI" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:689 -#: 9e3832473379404391011a22af4fb605 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 +#: 937556f090f74e86ab56041fbda5c543 msgid "" -"The client port allocation APIs are nearly identical to those of the server." -" They allow you to allocate ephemeral ports either automatically (by " -"returning 0, letting the OS choose) or manually within a configured range." +"The client port allocation APIs are nearly identical to those of the " +"server. They allow you to allocate ephemeral ports either automatically " +"(by returning 0, letting the OS choose) or manually within a configured " +"range." msgstr "" "クライアントのポート割り当て API はサーバーの API とほぼ同じです。これらを使用すると、一時ポートを自動的に (0 を返して OS " "に選択させることで)、または構成された範囲内で手動で割り当てることができます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 -#: 93aa2cdf7f3c49fb8ad14ad1b78415e4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 +#: a37e79b6f8e34e3ab589f9127a2fbaf2 msgid "" "To configure the port allocation mode, the client reads the " "``/client_alloc_port_range`` line the server sends it right after the " -"connection is accepted. When the server sends that command with a number, " -"the client sets ``self.is_hand_alloc_port = True`` and configures the range." -" If the server sends ``NO_LIMIT``, the client uses automatic allocation " -"(return 0 from allocation calls)." -msgstr "" -"ポート割り当てモードを構成するには、クライアントは、接続が受け入れられた直後にサーバーが送信する''/ client_alloc_port_range " -"''行を読み取ります。サーバーが番号付きでそのコマンドを送信すると、クライアントは'' self.is_hand_alloc_port = True " -"''を設定し、範囲を設定します。サーバーが'' NO_LIMIT " +"connection is accepted. When the server sends that command with a number," +" the client sets ``self.is_hand_alloc_port = True`` and configures the " +"range. If the server sends ``NO_LIMIT``, the client uses automatic " +"allocation (return 0 from allocation calls)." +msgstr "" +"ポート割り当てモードを構成するには、クライアントは、接続が受け入れられた直後にサーバーが送信する''/ " +"client_alloc_port_range ''行を読み取ります。サーバーが番号付きでそのコマンドを送信すると、クライアントは'' " +"self.is_hand_alloc_port = True ''を設定し、範囲を設定します。サーバーが'' NO_LIMIT " "''を送信した場合、クライアントは自動割り当てを使用します(割り当て呼び出しから0を返します)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 -#: 3d693309e5ae4fbaa587212cf81bc16f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 +#: a29288d0ba7d46409b9fbc7e4b3ff7b0 msgid "" "In manual allocation mode, the port range is determined by the server's " -"broadcast value. The client maintains its own range based on ``self.port`` " -"(the server port) and the received range. The minimum allocatable port is " -"``self.port - self.port_add_step * each_client_port_range``, and the maximum" -" is ``self.port + 1 + self.port_add_step * each_client_port_range``." -msgstr "" -"手動割り当てモードでは、ポート範囲はサーバーのブロードキャスト値によって決まります。クライアントは、``self.port`` (サーバー ポート) " -"と受信した範囲に基づいて独自の範囲を維持します。割り当て可能なポートの最小値は「self.port - self.port_add_step * " -"each_client_port_range」、最大値は「self.port + 1 + self.port_add_step * " -"each_client_port_range」です。" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:710 -#: ab3bb204b8f5402093e6d329cd98cd64 +"broadcast value. The client maintains its own range based on " +"``self.port`` (the server port) and the received range. The minimum " +"allocatable port is ``self.port - self.port_add_step * " +"each_client_port_range``, and the maximum is ``self.port + 1 + " +"self.port_add_step * each_client_port_range``." +msgstr "" +"手動割り当てモードでは、ポート範囲はサーバーのブロードキャスト値によって決まります。クライアントは、``self.port`` (サーバー " +"ポート) と受信した範囲に基づいて独自の範囲を維持します。割り当て可能なポートの最小値は「self.port - " +"self.port_add_step * each_client_port_range」、最大値は「self.port + 1 + " +"self.port_add_step * each_client_port_range」です。" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 +#: baf74c2478324ced80df912ff96e7baa msgid "The main methods for port allocation are:" msgstr "ポート割り当ての主な方法は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:717 -#: 93b31be2d4bf4e5ca9f8b4ab9b095a45 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 +#: c4170cd3e6844792b110dfba945f0298 msgid "" "`palloc` returns an available port (either 0 for automatic mode, or a " "concrete port number from the manual range). It internally calls " @@ -1505,372 +1638,440 @@ msgstr "" "`palloc` は使用可能なポート (自動モードの場合は 0、または手動範囲の具体的なポート番号) を返します。これは、ループ内で内部的に " "`file_palloc` (加算的割り当て) と `spy_palloc` (減算的割り当て) を呼び出します。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:729 -#: d54f0b635e194239932cf1bb5cace701 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:807 +#: 1c21e96227684b8998d8a6c6c595caf0 msgid "" -"`pfree` releases a previously allocated port. In manual mode, it removes the" -" port from the internal list and adjusts the latest port pointers. In " +"`pfree` releases a previously allocated port. In manual mode, it removes " +"the port from the internal list and adjusts the latest port pointers. In " "automatic mode, it does nothing." msgstr "" "`pfree` は、以前に割り当てられたポートを解放します。手動モードでは、内部リストからポートを削除し、最新のポート " "ポインターを調整します。自動モードでは何も行いません。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:734 -#: 60b2327bda49480fac483fb4ca52eb5d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:812 +#: e270023d96364a59a4436f846b296202 msgid "" -"As with the server, the automatic mode (returning 0) is recommended for most" -" use cases because it avoids port conflicts and simplifies code. Manual mode" -" is provided for environments where port ranges must be strictly controlled " -"(e.g., firewalls or testing)." +"As with the server, the automatic mode (returning 0) is recommended for " +"most use cases because it avoids port conflicts and simplifies code. " +"Manual mode is provided for environments where port ranges must be " +"strictly controlled (e.g., firewalls or testing)." msgstr "" "サーバーと同様に、ポートの競合を回避し、コードを簡素化するため、ほとんどのユースケースでは自動モード (0 を返す) " "をお勧めします。手動モードは、ポート範囲を厳密に制御する必要がある環境 (ファイアウォールやテストなど) に提供されます。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:741 -#: bade6122477d4a959b6f9a942b150ea0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:819 +#: 31a306a34d04473c85f2c36abe5747e7 msgid "TCP Client APIs table" msgstr "TCP クライアント API テーブル" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:743 -#: be55c1d2020c4088ac45dcd1f2c6add4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:821 +#: e38b3c22a1e041be93c1b9133368dacb msgid "In short, the table of contents of the public APIs is as follows:" msgstr "つまり、パブリック API の目次は次のとおりです。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:746 -#: 8bb46aea2dff4e57853087e452fdca3f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:824 +#: 5c9291fc111d4f87a26c3b323d69bf27 msgid "The client setup APIs:" msgstr "クライアントセットアップ API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:747 -#: 6c95cdbfa4634d9f9561908b316ab03e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:825 +#: dc26d3c73e994b2a89d83b6dc2b0ff20 msgid "`TCP_Client_Base`" msgstr "`TCP_クライアント_ベース`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:748 -#: a5ab88edb0dd42dd81166dc614c4c353 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:826 +#: caab3a11f54d4540890a84cada3cecd3 msgid "`start_TCP_client`" msgstr "`start_TCP_client`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 -#: 11f6500a3ac64b41ba44c22ef2069007 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:827 +#: c38e962856a84b6eaf6f0759e9a48ec4 msgid "`connect`" msgstr "「接続」" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:750 -#: 0263dd292461441192546c1f9237adaf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:828 +#: 411023a9191243338f22e59a33cb72c2 msgid "`close`" msgstr "「閉じる」" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:752 -#: 11848e9f043f4952afaad4305b07486d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:830 +#: 982308344bc1464c982613021965e40f msgid "The client handling information APIs:" msgstr "クライアント処理情報 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:753 -#: 6c2bd74a71a64468b3247862791409e1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:831 +#: 611645ffa9bb4259923b685f7389fab4 msgid "`receive_messages`" msgstr "`メッセージを受信する`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:754 -#: a15228535750492caa9b3ebfba4d9901 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:832 +#: b5a951b6b0694dd7992bcb3d054bd2b3 msgid "`handle_server_command`" msgstr "`ハンドルサーバーコマンド`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:755 -#: 47cb15f07d394f78a15345f254e42b0b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:833 +#: 334fb0ff014d4f418ac474db4c68d247 msgid "`receive_message`" msgstr "`受信メッセージ`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:756 -#: f0074be846de4eef8d98f07a3fd153a7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:834 +#: df7b9a0f6c034b8ab9b1fb20b3bf879a msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:757 -#: ca1943c93c2048d9805e6c3494744d90 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:835 +#: ffb875c0ebd844368deedf382811f851 msgid "`interactive_mode`" msgstr "`インタラクティブモード`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:836 +#: 5630f1fb130842aba877cdb0c29e4ff1 #, fuzzy msgid "`send_message_to_server`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:760 -#: 1059c94b173f48aa9304663c6d74a805 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:838 +#: 494c8644a7254a7b81e9886d840813e8 msgid "2.1. The inbound event listener APIs:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:761 -#: 54202f3279bb4bb19457be283d4f5d75 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:839 +#: 6f15aa9d9fe142088b15a802e28823f5 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:762 -#: 88625c35b2ec49889b14309d8373c1ef +#: ../../source/Network_APIs/TCP_Client_APIs.rst:840 +#: d240527b31854c3eb36c83b57b838e5d msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:763 -#: eca517026718488aa026202ff440ce41 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:841 +#: fb735c656faa4a28983b3c90a8f9f452 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 -#: a5c242c6e4084aef98fa59f17778731d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:843 +#: 7299f59deb95485b9ce5f240b3318d86 msgid "" -"The client encrypted channel APIs (see :ref:`tcp-client-encrypted-channel-" -"api`):" +"The client encrypted channel APIs (see :ref:`tcp-client-encrypted-" +"channel-api`):" msgstr "クライアント暗号化チャネル API (:ref:`tcp-client-encrypted-channel-api` を参照):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:766 -#: c5006b19599d4a45bc86d5cfac770d94 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:844 +#: 51757de232d548c3b7c230b7e6456906 msgid "`_crypto_exchange_thread`" msgstr "`_crypto_exchange_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 -#: 3d8e73d09493460c845a98dabf5ad9f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:845 +#: ad3834da9c474029952e0043a46c2ed6 msgid "`_crypto_after_ack`" msgstr "`_crypto_after_ack`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:768 -#: 75bbad7153834bad9492a242fa26b789 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:846 +#: 0ca576944d8a497abeb39cdf5c4ccdb7 msgid "`_crypto_push_pub_key`" msgstr "`_crypto_push_pub_key`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:769 -#: 59aff25473e942eb9b11f6aa4c1ff235 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:847 +#: 11b6eacdaa484d689499dad3be56bd79 msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:771 -#: aeba48f8f86e45f199838191146c7f4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:849 +#: b71d430231c24a6995ba0b267f09f4bf msgid "The client command APIs:" msgstr "クライアント コマンド API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 -#: 0a25d8003bd64c63ad151aedf3fb15ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:850 +#: efb7ccdbabfd477d83af89aed1eb4c5d msgid "`register_command`" msgstr "`register_command`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:773 -#: c9e2f51101b942ef8e722216e59ed972 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:851 +#: 72f8a6d975094c7984fbef810a422975 +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:852 +#: d549ceac7407457f81c403d7be88aa99 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:774 -#: 92211b1c671c48ce8e0d14c9d12b71f1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:853 +#: c6fe8883469e47b88e0a4bb3be30c1a6 msgid "`submit_task`" msgstr "`submit_task`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:775 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:854 +#: 5630f1fb130842aba877cdb0c29e4ff1 msgid "`create_temporary_server`" msgstr "「一時サーバーの作成」" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:776 -#: e23b2af57072452ab0fab0c5652bde72 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:855 +#: 9cf956cb593f4c758da50d45c684466b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:778 -#: 91270c73be944993a8751739a6ef133e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:857 +#: 55aa7c66f7a24443a58e108948608136 msgid "The client file transfer APIs:" msgstr "クライアント ファイル転送 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:779 -#: 358e4cb2a7174129b65dc582f3b977f7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:858 +#: d79011e4d398480cbdb00e021f1461fe msgid "`file_transfer_client_recv_client_start`" msgstr "`file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 -#: f4971cf5af03413e9b0011378a57d487 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:859 +#: 300f91c72ed8400d85821a3e2a0ab1ec msgid "`file_transfer_client_recv_client_start_thread`" msgstr "`file_transfer_client_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:781 -#: 077b6550f3b8496fb4d8d8592eac5ca6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:860 +#: 1f3a30d9bf5d44baa9459a21df8f70d4 msgid "`folder_file_transfer_client_recv_client_start`" msgstr "`folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:782 -#: 194dd830cddc49acaad93077b41fb646 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:861 +#: 5619c7c126b14852ace1e5ed9a428e0a msgid "`multiple_file_transfer_client_recv_client_start`" msgstr "`multiple_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:783 -#: e6ea79e90d794733b2bb84b5799ab3ec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:862 +#: e1e3f53d8275406f9f2f31a406617843 msgid "`multiple_folder_file_transfer_client_recv_client_start`" msgstr "`multiple_folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:784 -#: ce228984911540d29bef2d0b7e73eabc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:863 +#: 0f3b14e3c193426191323ee76959278e msgid "`file_transfer_client_recv_server_start`" msgstr "`file_transfer_client_recv_server_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:785 -#: 7ff0717c8e504c869e36a3d9fd829652 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:864 +#: 4612a53ee9154895a8758a6cc45c0b76 msgid "`file_transfer_client_recv_server_start_thread`" msgstr "`file_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:786 -#: db7e615cfbd347359a6a683642049c31 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:865 +#: 5dff8ca27b7b40e6941b8190a136173c msgid "`file_folder_transfer_client_recv_server_start_thread`" msgstr "`file_folder_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:787 -#: 16a578b31e344b5d82b9935e56aafa02 -msgid "`file_transfer_mode_recv`" -msgstr "`file_transfer_mode_recv`" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 -#: 7659e4e26bef45e89e4659a045cd77cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:866 +#: c66340b3ef204af29e58170db0efc057 msgid "`file_transfer_mode`" msgstr "`ファイル転送モード`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:790 -#: 6a81df270092467db215985a9b0ea90e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:868 +#: 87af784aa34949379dc6a73c148a402d +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:869 +#: 9aa5be3d37804a5c8286d23160add073 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:870 +#: 4612a53ee9154895a8758a6cc45c0b76 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:871 +#: e340c2c825324df7b3aee14da0f9d919 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:872 +#: 0f3b14e3c193426191323ee76959278e +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:874 +#: 5bf1072901734d3d8d0b119e5f50627c msgid "The client console commands (interactive mode):" msgstr "クライアント コンソール コマンド (対話モード):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:791 -#: c2174ab210464a2e82c298e0f70fee20 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:875 +#: cb2350fc1fd047f39fb9841ce78dd4ed msgid "`/quit`" msgstr "`/やめる`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:792 -#: ffa9f9ef47ae46629a6fc29d29d9ab44 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:876 +#: 70b54395545d4421bd90e40acd8b28d5 msgid "`/file`" msgstr "`/ファイル`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:793 -#: 86990039800e4a999b76a431d6a6dd8a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:877 +#: bd2dec3b0774465d87ed9f3f853f30db msgid "`/multiple_file`" msgstr "`/multiple_file`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:794 -#: 6f26c82663494206964a6bb68ddcfe6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:878 +#: efe4930f9bd34df19b1ee98085605346 msgid "`/file_folder`" msgstr "`/ファイルフォルダー`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 -#: 63d6611c586c46d3a9053712a112162d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:879 +#: acb8ceac4b5540aca3230cff6bfefa86 msgid "`/multiple_file_folder`" msgstr "`/複数のファイルフォルダー`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:798 -#: 7bb84bbf4494463d9e477ddce9f0fec2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:882 +#: 9db1c5c6b375448e80c2af32c0464023 msgid "See Also" msgstr "関連項目" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:800 -#: 5cc4da34c3dc479eb9af04123c8502f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:884 +#: 0c84c6f4e6e9450aa96935335c505122 msgid ":doc:`TCP_Server_APIs` — TCP server." msgstr ":doc:`TCP_Server_APIs` — TCP サーバー。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:801 -#: 134b0d0b135c4e68a08b0d14959d6307 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:885 +#: efc25fa97296452199853b1bb3cc3f21 msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP エンドポイント。" #~ msgid "" -#~ "For more information about the server APIs, please visit the server API " -#~ "documentation, at :doc:`TCP_Server_APIs`." +#~ "For more information about the server" +#~ " APIs, please visit the server API" +#~ " documentation, at :doc:`TCP_Server_APIs`." #~ msgstr "サーバー API の詳細については、サーバー API ドキュメント (:doc:`TCP_Server_APIs`) を参照してください。" #~ msgid "" -#~ "Public keys received from the server are stored in " -#~ "``network_api/.Flow/pub_key`` as ``server_.pem``. The peer's MAC " -#~ "address is appended to the exchanged key so each entry is clearly labelled " -#~ "with which server it came from; in the file name the MAC uses ``_`` " -#~ "separators (``:`` is an illegal filename character on Windows)." +#~ "Public keys received from the server " +#~ "are stored in ``network_api/.Flow/pub_key`` as" +#~ " ``server_.pem``. The peer's MAC" +#~ " address is appended to the exchanged" +#~ " key so each entry is clearly " +#~ "labelled with which server it came " +#~ "from; in the file name the MAC " +#~ "uses ``_`` separators (``:`` is an " +#~ "illegal filename character on Windows)." #~ msgstr "" -#~ "サーバーから受信した公開鍵は ``network_api/.Flow/pub_key`` に ``server_.pem`` " -#~ "として保存されます。ピアの MAC アドレスが交換されたキーに追加されるため、各エントリにはどのサーバーから来たのかが明確にラベル付けされます。" +#~ "サーバーから受信した公開鍵は ``network_api/.Flow/pub_key`` に " +#~ "``server_.pem`` として保存されます。ピアの MAC " +#~ "アドレスが交換されたキーに追加されるため、各エントリにはどのサーバーから来たのかが明確にラベル付けされます。" #~ msgid "" -#~ "The client sends a plaintext ``/crypto_key_exchange `` greeting " -#~ "right after connecting; the server replies with ``/crypto_key_exchange_ack " -#~ " ``. Either side that is missing the " -#~ "other's public key pushes its own key file over the file-transfer mechanism," -#~ " and both sides switch to encrypted mode only after ``/crypto_ready`` has " -#~ "been received from the peer (so plaintext and ciphertext never interleave on" -#~ " a connection). On later connections the registry is consulted first and the" -#~ " exchange is skipped when the keys are already known." +#~ "The client sends a plaintext " +#~ "``/crypto_key_exchange `` greeting " +#~ "right after connecting; the server " +#~ "replies with ``/crypto_key_exchange_ack ``. Either" +#~ " side that is missing the other's " +#~ "public key pushes its own key file" +#~ " over the file-transfer mechanism, " +#~ "and both sides switch to encrypted " +#~ "mode only after ``/crypto_ready`` has " +#~ "been received from the peer (so " +#~ "plaintext and ciphertext never interleave " +#~ "on a connection). On later connections" +#~ " the registry is consulted first and" +#~ " the exchange is skipped when the " +#~ "keys are already known." #~ msgstr "" -#~ "クライアントは、接続直後に平文の ``/crypto_key_exchange `` " -#~ "グリーティングを送信します。サーバーは「/crypto_key_exchange_ack " -#~ "」で応答します。もう一方の公開鍵を欠いているどちらかの側は、ファイル転送メカニズムを介して自分の鍵ファイルをプッシュし、ピアから " -#~ "``/crypto_ready`` を受信した後でのみ、両方の側が暗号化モードに切り替わります " +#~ "クライアントは、接続直後に平文の ``/crypto_key_exchange `` グリーティングを送信します。サーバーは「/crypto_key_exchange_ack " +#~ " " +#~ "」で応答します。もう一方の公開鍵を欠いているどちらかの側は、ファイル転送メカニズムを介して自分の鍵ファイルをプッシュし、ピアから" +#~ " ``/crypto_ready`` を受信した後でのみ、両方の側が暗号化モードに切り替わります " #~ "(そのため、接続上で平文と暗号文がインターリーブされることはありません)。その後の接続では、最初にレジストリが参照され、キーがすでにわかっている場合は交換がスキップされます。" #~ msgid "" -#~ "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated by " -#~ "``_``). If a message cannot be decrypted, or the suffix is missing, the " -#~ "socket drops out of encrypted mode, the local key is reloaded, and a forced " -#~ "``/crypto_key_exchange`` restarts the handshake so both sides re-push their " -#~ "current public keys. This is what recovers when a user rotates the " -#~ "``~/.ssh`` keypair while connections are active: the stale key is detected " -#~ "on the first decode failure and the peers automatically re-exchange." +#~ "Every encrypted plaintext carries the " +#~ "fixed suffix ``_VALID`` (separated by " +#~ "``_``). If a message cannot be " +#~ "decrypted, or the suffix is missing, " +#~ "the socket drops out of encrypted " +#~ "mode, the local key is reloaded, " +#~ "and a forced ``/crypto_key_exchange`` restarts" +#~ " the handshake so both sides re-" +#~ "push their current public keys. This " +#~ "is what recovers when a user " +#~ "rotates the ``~/.ssh`` keypair while " +#~ "connections are active: the stale key" +#~ " is detected on the first decode " +#~ "failure and the peers automatically " +#~ "re-exchange." #~ msgstr "" -#~ "すべての暗号化された平文には、固定サフィックス ``_VALID`` (``_`` で区切られる) " +#~ "すべての暗号化された平文には、固定サフィックス ``_VALID`` (``_`` で区切られる)" +#~ " " #~ "が付けられます。メッセージを復号化できない場合、またはサフィックスが欠落している場合、ソケットは暗号化モードから外れ、ローカル鍵が再ロードされ、強制的な" #~ " ``/crypto_key_exchange`` " -#~ "によってハンドシェイクが再開されるため、双方は現在の公開鍵を再プッシュします。これは、接続がアクティブなときにユーザーが ``~/.ssh`` " +#~ "によってハンドシェイクが再開されるため、双方は現在の公開鍵を再プッシュします。これは、接続がアクティブなときにユーザーが " +#~ "``~/.ssh`` " #~ "キーペアをローテーションすると回復するものです。最初のデコード失敗時に古いキーが検出され、ピアは自動的に再交換されます。" #~ msgid "" -#~ "To change the port allocation mode, the client listens to the server's " -#~ "broadcast of ``/client_alloc_port_range``. When the server sends that " -#~ "command with a number, the client sets ``self.is_hand_alloc_port = True`` " -#~ "and configures the range. If the server sends ``NO_LIMIT``, the client uses " -#~ "automatic allocation (return 0 from allocation calls)." +#~ "To change the port allocation mode, " +#~ "the client listens to the server's " +#~ "broadcast of ``/client_alloc_port_range``. When " +#~ "the server sends that command with " +#~ "a number, the client sets " +#~ "``self.is_hand_alloc_port = True`` and " +#~ "configures the range. If the server " +#~ "sends ``NO_LIMIT``, the client uses " +#~ "automatic allocation (return 0 from " +#~ "allocation calls)." #~ msgstr "" #~ "ポート割り当てモードを変更するには、クライアントはサーバーの ``/client_alloc_port_range`` " -#~ "のブロードキャストをリッスンします。サーバーが番号付きのコマンドを送信すると、クライアントは ``self.is_hand_alloc_port = " -#~ "True`` を設定し、範囲を設定します。サーバーが ``NO_LIMIT`` を送信すると、クライアントは自動割り当てを使用します " -#~ "(割り当て呼び出しから 0 を返します)。" +#~ "のブロードキャストをリッスンします。サーバーが番号付きのコマンドを送信すると、クライアントは " +#~ "``self.is_hand_alloc_port = True`` " +#~ "を設定し、範囲を設定します。サーバーが ``NO_LIMIT`` " +#~ "を送信すると、クライアントは自動割り当てを使用します (割り当て呼び出しから 0 を返します)。" #~ msgid "" -#~ "``timeout``: The socket timeout in seconds for connection and receive " +#~ "``timeout``: The socket timeout in " +#~ "seconds for connection and receive " #~ "operations (``None`` means no timeout)." #~ msgstr "``timeout``: 接続および受信操作のソケットタイムアウト (秒単位) (``None`` はタイムアウトなしを意味します)。" #~ msgid "" -#~ "printing normal (non‑command) messages to the console with a ``[server]`` " -#~ "prefix" +#~ "printing normal (non‑command) messages to " +#~ "the console with a ``[server]`` prefix" #~ msgstr "通常の (コマンド以外の) メッセージを ``[server]`` プレフィックスを付けてコンソールに出力します" #~ msgid "logging errors and disconnecting when the server closes the socket." #~ msgstr "エラーをログに記録し、サーバーがソケットを閉じるときに切断します。" #~ msgid "" -#~ "If a user types a command that is not built-in, the client will check if it " -#~ "matches any registered custom commands (see command extension API below). If" -#~ " it does, the client will call the associated handler; otherwise the message" -#~ " is sent as a normal chat message to the server." +#~ "If a user types a command that " +#~ "is not built-in, the client will" +#~ " check if it matches any registered" +#~ " custom commands (see command extension " +#~ "API below). If it does, the client" +#~ " will call the associated handler; " +#~ "otherwise the message is sent as a" +#~ " normal chat message to the server." #~ msgstr "" -#~ "ユーザーが組み込みではないコマンドを入力すると、クライアントはそれが登録されているカスタム コマンドと一致するかどうかを確認します (下記のコマンド拡張" -#~ " API を参照)。存在する場合、クライアントは関連するハンドラーを呼び出します。それ以外の場合、メッセージは通常のチャット " +#~ "ユーザーが組み込みではないコマンドを入力すると、クライアントはそれが登録されているカスタム " +#~ "コマンドと一致するかどうかを確認します (下記のコマンド拡張 API " +#~ "を参照)。存在する場合、クライアントは関連するハンドラーを呼び出します。それ以外の場合、メッセージは通常のチャット " #~ "メッセージとしてサーバーに送信されます。" #~ msgid "" -#~ "Any other text not starting with ``/`` is sent as a normal chat message to " -#~ "the server." +#~ "Any other text not starting with " +#~ "``/`` is sent as a normal chat " +#~ "message to the server." #~ msgstr "「/」で始まらないその他のテキストは、通常のチャット メッセージとしてサーバーに送信されます。" #~ msgid "" -#~ "If a user types a custom command that has been registered with " -#~ "``register_command(..., where_to_run=\"client\")``, the client will execute " -#~ "the associated handler (synchronously or in a thread, as configured)." +#~ "If a user types a custom command" +#~ " that has been registered with " +#~ "``register_command(..., where_to_run=\"client\")``, the" +#~ " client will execute the associated " +#~ "handler (synchronously or in a thread," +#~ " as configured)." #~ msgstr "" -#~ "ユーザーが ``register_command(..., where_to_run=\"client\")`` で登録されたカスタム " -#~ "コマンドを入力すると、クライアントは関連付けられたハンドラを (同期的に、または設定に従ってスレッド内で) 実行します。" +#~ "ユーザーが ``register_command(..., where_to_run=\"client\")``" +#~ " で登録されたカスタム コマンドを入力すると、クライアントは関連付けられたハンドラを " +#~ "(同期的に、または設定に従ってスレッド内で) 実行します。" #~ msgid "" -#~ "*Note: The client will print an error message for unknown commands that " -#~ "start with ``/``.*" +#~ "*Note: The client will print an " +#~ "error message for unknown commands that" +#~ " start with ``/``.*" #~ msgstr "*注意: クライアントは、「/」で始まる不明なコマンドに対してエラー メッセージを出力します。*" #~ msgid "The thread-safe version (recommended for direct calls) is:" @@ -1884,3 +2085,38 @@ msgstr ":doc:`UDP_APIs` — UDP エンドポイント。" #~ msgid "The multiple folders transfer function is:" #~ msgstr "複数フォルダー転送機能は次のとおりです。" + +#~ msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" +#~ msgstr "``client_port``: デフォルトは ``None`` (OS が一時的なポートを割り当てます)" + +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "ハンドシェイクではランダムなセッション nonce " +#~ "が交換され、回線上のすべての暗号化された回線には、それに加えて接続ごとのシーケンス番号 ``||`` が付けられます。受信者は、ノンスが現在のセッションと一致しない行 " +#~ "(古い接続から再生された暗号文)、またはシーケンス番号が予期したものではない行 (セッション内で再生された暗号文 /" +#~ " 順序が乱れている) をドロップします。 (再) " +#~ "交換後にソケットが暗号化モードに切り替わると、両方のカウンタがリセットされます。" + +#~ msgid "" +#~ "``pause_fid`` is the forwarding id used" +#~ " to pause/resume the transfer with " +#~ "``/pause_trans`` / ``/start_trans``." +#~ msgstr "" + +#~ msgid "`file_transfer_mode_recv`" +#~ msgstr "`file_transfer_mode_recv`" + diff --git a/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po b/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po index 05d9ffb..689f9e6 100644 --- a/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po +++ b/docs/source/locale/ja/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ja\n" @@ -20,17 +20,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Server_APIs.rst:2 -#: 6233736da6d8410985a7db552ebb0405 +#: c4332266e3f842cc912424ee842fcfe0 msgid "The TCP Server APIs" msgstr "TCP サーバー API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:5 -#: 6e1c64d13b9e4deebc7c276d00bfca94 +#: 769ff5b424d54086a70b199663089327 msgid "TCP Server setup API" msgstr "TCPサーバーセットアップAPI" #: ../../source/Network_APIs/TCP_Server_APIs.rst:7 -#: 05209d5966c24f19bcf70e93d016fe24 +#: 2d81aa6d8ba84a868113fd9e08fc5c60 msgid "" "The TCP Server Setup API is used to create a TCP server. The server in " "the protocol is usually used to connect and listen to the TCP clients and" @@ -39,8 +39,8 @@ msgstr "" "TCP サーバー セットアップ API は、TCP サーバーを作成するために使用されます。プロトコル内のサーバーは通常、TCP " "クライアントに接続してリッスンし、クライアントからのデータを処理するために使用されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:35 -#: c6d17d88ca43468cab262d7b50bb7d43 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 +#: ddc5d0f6bc1b4162af2bb49f6b25a031 msgid "" "The TCP Server Setup API is defined in the ``TCP_Server_Base`` class. The" " parameters of the ``__init__`` method are as follows:" @@ -48,62 +48,62 @@ msgstr "" "TCP サーバー設定 API は ``TCP_Server_Base`` クラスで定義されます。 ``__init__`` " "メソッドのパラメータは次のとおりです。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:38 -#: 7c3b5b3185bb436bbaabf0aaea5f11fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 +#: f1ffcdd5c8e74b9cbdb5e5fc8eeb34ce msgid "``host``: The host IP address to bind the TCP server to." msgstr "``host``: TCP サーバーをバインドするホストの IP アドレス。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 -#: 8dbeeea956834b28a5d13a47b9eaf651 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 +#: 7e419c2e704a44228bd0bdeed976d861 msgid "``port``: The port number to bind the TCP server to." msgstr "``port``: TCP サーバーをバインドするポート番号。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:40 -#: 3710af3c13574f088cd84d34ae8c83ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 +#: 854e298d71f140069b6ed51806224ca5 #, fuzzy msgid "" "``max_clients``: The maximum number of concurrent clients the server can " "handle (ignored when ``is_asynic_clients_io`` is ``True``)." msgstr "``max_clients``: サーバーが処理できる同時クライアントの最大数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 -#: c92cda0f3bdb4f839ab24c2c65c926db +#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 +#: 203462f6b127478cb9bb0c2093362827 msgid "``port_add_step``: The step size for incrementing the port number." msgstr "``port_add_step``: ポート番号をインクリメントするステップ サイズ。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 -#: 43155638bb1344798a37f85065d411ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 +#: 3d0355b5c1924055a7d8b6acb907fad0 msgid "``port_range_num``: The number of ports to check in the range." msgstr "``port_range_num``: 範囲内でチェックするポートの数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 -#: 0459f804445d47519971903bce3e36eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 +#: a7852ea136454a1298541e96cdece1bc msgid "" "``max_file_transfer_thread_num``: The maximum number of threads for file " "transfer operations." msgstr "``max_file_transfer_thread_num``: ファイル転送操作の最大スレッド数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:45 -#: 3103e7d29cb647f9922e0b507d47a171 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:49 +#: 0f1b0f03ffe2472cb58725dc446f6f7c msgid "" "``is_hand_alloc_port``: A flag indicating whether to manually allocate " "the port." msgstr "``is_hand_alloc_port``: ポートを手動で割り当てるかどうかを示すフラグ。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 -#: ee86acb3489f408ca9ba116a66c5ea3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:50 +#: 969ca405744f4d57a8e70db30eada3f7 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console." msgstr "``is_input_command_in_console``: コンソールにコマンドを入力するかどうかを示すフラグ。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 -#: d593644fa1664037b99afd05ecbf9cf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:51 +#: 6b01091b3f124b8d87c9423eb6998be4 msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``: カスタム ワーカー スレッドの最大数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 -#: b46e9e9d9066432bbe75dc461b0f951f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 +#: c9d16d29465a48779ee2a54e4b9cc66e msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the server itself by calling " @@ -111,8 +111,8 @@ msgid "" "register its commands first and start the server later." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 -#: 60e4bd55be9940a48d6ae6421561fdaf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:56 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with clients are RSA-encrypted (see :ref:`tcp-server-encrypted-channel-" @@ -121,8 +121,8 @@ msgstr "" "``is_enable_encrypto``: クライアントと交換されるメッセージが RSA 暗号化されているかどうかを示すフラグ (:ref" ":`tcp-server-encrypted-channel-api` を参照)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:54 -#: c6dcdd076b864336834f8490c0a25708 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 +#: 3558d7e8c52442818701d4eb794b3643 msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -134,16 +134,30 @@ msgstr "" "として解析され、相互にペアになっている必要があります。無効なペアは黙って無視され、代わりにデフォルトのキー検索が使用されます (``None`` " "はデフォルトの検索を維持します)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 -#: d0e99e1bc78f40f7af7470a66315bb04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:62 +#: 86265e57f3aa48e58e3fb5d9de0a9277 msgid "" "``max_mem_buff``: The in-memory buffering ceiling of the forward pump, " "given in MiB and stored as bytes (``self.max_mem_buff``); past it the " "uploading peer is told to pause. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:61 -#: 970d44aa127b40c7854cfc4dee215dcf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 +#: 7d4dd6bf4eff4f4db8ce0187088f172c +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:67 +#: 8fb93ff5bf2f49b18f2f42c92e66123f +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:69 +#: f12bacde2a874840879a51af63eeefde msgid "" "``is_asynic_clients_io``: A flag indicating whether clients are served by" " asyncio coroutines on one event loop instead of one thread per client. " @@ -154,8 +168,8 @@ msgstr "" "'':クライアントごとに1つのスレッドではなく、1つのイベントループでクライアントがasyncioコルーチンによって提供されるかどうかを示すフラグ。これにより、''" " max_clients ''の制限が解除されるため、1台のサーバーで数千の同時接続を保持できます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 -#: 269ce1f748d942949c0c20017fdf4a9b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 +#: 3a36a9bba6004a41b358be9975788707 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the server logs command content and execution results only;" @@ -165,8 +179,8 @@ msgstr "" "''(デフォルト)を使用すると、サーバーはコマンドの内容と実行結果のみをログに記録します。'' True " "''を使用すると、実行プロセスの主要なステップもログに記録します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:68 -#: 09d8448517374602938d9ca4872e0356 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_print_log``: A flag indicating whether the server logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." @@ -174,58 +188,86 @@ msgstr "" "'' is_print_log '':サーバーがまったくログを記録しているかどうかを示すフラグ。'' False ''では、'' is_debug" " ''が何であれ、何も出力しません。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:71 -#: dc30e9a1ba5044319a3ed5ad1842b348 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 +#: 2994b78415964ff0adc713a4daed1b6b +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when a " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 +#: 9f9de22b50a94553ac1113f290dff1b4 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 +#: 8b0a1bb7ed944884854a936968f3b4bd msgid "All parameters have default values:" msgstr "すべてのパラメータにはデフォルト値があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 -#: 5774cd0576f349d18492b59a0b6d68bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:100 +#: 89299feb872b49758f7c9bf680114bbc msgid "``host``: Default is ``'127.0.0.1'``" msgstr "``host``: デフォルトは ``'127.0.0.1'`` です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:74 -#: 4437fda8aa004d7483cefd29ad594bca +#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 +#: 38b84b10fc4d492497c3e0b20cb9fe8c msgid "``port``: Default is ``65432``" msgstr "``ポート'': デフォルトは ``65432`` です" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:75 -#: 559c3b634b1043f2a6541f45eba488d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:102 +#: 3ccf25b3de4749a7ad73a1001fea86fb msgid "``max_clients``: Default is ``10``" msgstr "``max_clients``: デフォルトは ``10``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 -#: 8988cc48e66a472ebe8d505bdf8d6db9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:103 +#: 63455575485f4a25b4d2d2b83803e6b8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: デフォルトは ``1`` です" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:77 -#: 063ec78e76b3439aafe539fad81a6036 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:104 +#: d8759c586e7143838c1ffe24c9fd6f62 msgid "``port_range_num``: Default is ``100``" msgstr "``port_range_num``: デフォルトは ``100``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:78 -#: 4a3115c33bd349fba0768f79f18c47c0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:105 +#: a8020929e0f14b5394b6dd502b7a7b67 msgid "``max_file_transfer_thread_num``: Default is ``10``" msgstr "``max_file_transfer_thread_num``: デフォルトは ``10``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 -#: fe7bf4015de045dcadc0024aef2bbdac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:106 +#: a9307e89f7cd471d96794bf7fbc9313c msgid "``is_hand_alloc_port``: Default is ``False``" msgstr "``is_hand_alloc_port``: デフォルトは ``False``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:80 -#: 2529e795d9b0401d930f3c09766c56d5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:107 +#: 76084a80a458455bb952e8acad677eba msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: デフォルトは ``True``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:81 -#: a95bee48d609469398e5a878b3d1e810 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:108 +#: f32a6549330a43f482e01def905e7415 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: デフォルトは ``10``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:82 -#: c825fae2eaaa4afeaa551e65e4ea1ff1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:109 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_Server()`` automatically)" @@ -233,8 +275,8 @@ msgstr "" "``is_extend_command``: デフォルトは ``False`` (``True`` の場合、``__init__`` は自動的に " "``start_TCP_Server()`` を呼び出しません)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:84 -#: 0ab49ef330a94ecb80e160bbe0f00fe9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:111 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, client " "connections go through an RSA public-key exchange and all subsequent " @@ -243,8 +285,8 @@ msgstr "" "``is_enable_encrypto``: デフォルトは ``True`` です (``True`` の場合、クライアント接続は RSA " "公開鍵交換を経由し、後続のメッセージはすべて暗号化されます)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:87 -#: 6087b88026574d56aa37a817f0fe790a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:114 +#: c259e80f53a14b79a94190bcded7b30d msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -253,8 +295,20 @@ msgstr "" "``is_custom_keys``: デフォルトは ``None`` (``[pub_key_path, pvt_key_path]`` " "リストはデフォルトの ``~/.ssh`` / 生成されたキーの代わりにユーザー指定のキーペアを使用します)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 -#: 26758c8f847b47c9839124e86e042349 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:117 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_clients``: デフォルトは ``10``" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:118 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "``max_file_transfer_thread_num``: デフォルトは ``10``" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_asynic_clients_io``: Default is ``False`` (when ``True``, every " "accepted connection is served by a coroutine on one asyncio event loop, " @@ -263,29 +317,43 @@ msgstr "" "'' is_asynic_clients_io '':デフォルトは'' False ''です( '' True " "''の場合、受け入れられたすべての接続は1つの非同期イベントループのコルーチンによって提供され、'' max_clients ''は無視されます)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:93 -#: 79dca8f502bb4401952542fb3dba6939 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:122 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "'' is_debug '':デフォルトは'' False ''です('' True ''は実行プロセス行をコマンド/結果行に追加します)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:95 -#: 656b6904625a4ea0977c85a93e62fd84 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:124 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "server would print)" msgstr "'' is_print_log '':デフォルトは'' True ''です( '' False ''はサーバーが印刷するすべての行を無音にします)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 -#: a3fd35f818f84d7399b7d41208ff9319 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:126 +#: abd7d3032e15468e92f96a0b5af1f926 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:128 +#: 9b2bfa874c4e4969905923bd7aa0f80c +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 +#: ff0d716f8c6344408337c57ab32bad28 msgid "" "The TCP Server Setup API will initialize all the necessary parameters and" " resources for the TCP server." msgstr "TCP サーバー セットアップ API は、TCP サーバーに必要なすべてのパラメータとリソースを初期化します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 -#: c38ba680fb704c4b9af31bcd33224c02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:134 +#: 06c57226c0e9415ab1618ae20a14f513 msgid "" "*Note: By default ``TCP_Server_Base.__init__`` calls " "``start_TCP_Server()`` to start the server automatically. If you set " @@ -296,8 +364,8 @@ msgstr "" "を呼び出してサーバを自動的に起動します。 ``is_extend_command=True`` " "を設定すると、インスタンスは自動起動しないため、準備ができたら手動で ``start_TCP_Server()`` を呼び出す必要があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:112 -#: a0900d8246aa4cda80638035485659e5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:145 +#: e473a54dc4534e29ac4361429d24cb63 msgid "" "In the `start_TCP_Server` method, we first create a TCP server socket and" " bind it to the ``self.host`` and ``self.port`` which are initialized in " @@ -306,15 +374,15 @@ msgstr "" "`start_TCP_Server` メソッドでは、まず TCP サーバーソケットを作成し、それを `__init__` メソッドで初期化される " "`self.host` と `self.port` にバインドします。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:116 -#: 4b6e513817d44c1d93cf1c39866ecf18 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:149 +#: 68dff731e96c46788af52f9c536a6d2f msgid "" "*Note: The server socket which is set up in the `start_TCP_Server` method" " is based on IPv4 form.*" msgstr "*注意: `start_TCP_Server` メソッドで設定されるサーバー ソケットは IPv4 形式に基づいています。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 -#: b8a255c83b3346199c3197dd596427b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:152 +#: 1c6fc605850b4e988e7f5dac390f905e msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will start a thread to listen to the console input of the " @@ -323,13 +391,13 @@ msgstr "" "次に、``self.is_input_command_in_console`` " "パラメータに従って、サーバーのコンソール入力をリッスンするかどうかを監視するスレッドを開始します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:123 -#: bd35c2a4858f46ecb2f1ea1b7e987bb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 +#: 493d7ac50eb3446394da3c71f307b0a5 msgid "After that, a main loop to accept clients will be started." msgstr "その後、クライアントを受け入れるメインループが開始されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:125 -#: 8b06edd210564df19035b30b72121c82 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 +#: 46f0159fb9a84874959c103ac08656f5 msgid "" "*Note: there is another global variable ``self.running`` which is set to " "``True`` after the server socket is successfully created. The " @@ -341,8 +409,8 @@ msgstr "" "に変わります。 ``self.running`` 変数は、TCP " "サーバーのメインループを制御するために使用され、サーバーがシャットダウンするときに ``False`` に設定されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 -#: 0920728e22cf4fdcbd6b6a5f32b251d4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:164 +#: ed335af1339644a090d7fc4ebdc859f1 msgid "" "With ``is_asynic_clients_io=True`` the main loop is the asyncio event " "loop instead: it accepts clients in non-blocking mode and schedules one " @@ -353,8 +421,8 @@ msgstr "" "''では、代わりにメインループはasyncioイベントループです。ノンブロッキングモードでクライアントを受け入れ、接続ごとに1つのコルーチンをスケジュールし、''" " max_clients ''の制限を適用せず、ループを終了できるように`stop`が解放されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:136 -#: ca2a678a5119456daf70ba9c6bcfacf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:169 +#: 613624f457b847f994b739812b6e7aed msgid "" "The main loop of the TCP server setup function first checks whether the " "number of connected clients exceeds the maximum number of clients. The " @@ -365,8 +433,8 @@ msgstr "" "`TCP_Server_Base` クラスの `self.max_clients` 引数によって定義され、 ``__init__`` " "で初期化されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:141 -#: 295d9fd021d94b94b5bb5e3290af9b94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:174 +#: d6142df9dee34a85a449a322bcfc5729 #, fuzzy msgid "" "If the number of the clients is already over the limit of the connect " @@ -378,8 +446,8 @@ msgstr "" "クライアントの数がすでに接続数の制限を超えている場合、サーバーは過負荷メッセージを送信し、接続を閉じます。しかし、制限を超えていない場合、サーバーはクライアント" " ハンドラー関数 `handle_client` をセットアップし、サーバー ハンドラー関数は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:153 -#: a15c83c5c9984e68b88602f6a3c56d16 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:186 +#: e0d97e64db41406aa120fbdcd2ee5bb3 msgid "" "*Note: For more details of the `handle_client` function, see the :ref" ":`tcp-server-handling-information-api` section.*" @@ -387,13 +455,13 @@ msgstr "" "*注意: `handle_client` 関数の詳細については、:ref:`tcp-server-handling-information-" "api` セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 -#: 4e4b61d041b24075b90f598ef42bbe78 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:189 +#: 686ed007e14d4a98b931c0c651bb7bf5 msgid "So what can the setup function do if it fails?" msgstr "では、セットアップ関数の実行が失敗した場合、セットアップ関数は何ができるのでしょうか?" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 -#: bfc7899a0ec649d49c956d569bbad0bc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:191 +#: 189abee61a444611a486dec294da6561 #, fuzzy msgid "" "First, the try-except block in the main server loop checks whether the " @@ -402,8 +470,8 @@ msgstr "" "まず、メインサーバーループの try および else コードブロックは、エラーが ``OSError`` " "であるかどうかを検出します。そうであれば、メインループは直接終了します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:162 -#: 8a3a4854f3a3441b87d0257cb4eb4e52 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 +#: e4e1ba68f4b64dc280490157405acab9 #, fuzzy msgid "" "Secondly, if the error is from the network socket, it first logs the " @@ -413,8 +481,8 @@ msgstr "" "次に、エラーがネットワークソケットからのものである場合、最初にエラーメッセージを出力し、関数 `stop` " "を呼び出してサーバーを停止します。そして、停止関数は次のように定義されています。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:171 -#: 4eb334cfa82e4557b51ed511bb35fea1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:204 +#: 9eb5b6fb9d2e4394b3dbb4a1905767d0 msgid "" "To stop the TCP server, it first sets the ``self.running`` variable to " "False, to stop the main loop of the server. After that, it calls the " @@ -424,8 +492,8 @@ msgstr "" "TCP サーバーを停止するには、まず ``self.running`` 変数を False " "に設定して、サーバーのメインループを停止します。その後、「free_port」関数を呼び出して、割り当てられたポートを解放します。そして、「free_port」は次のように定義されています。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:182 -#: 2d0515291a604c0996149873392657f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:215 +#: 18d7078902794d629ad9f4e92a334402 msgid "" "*Note: For more details of the `free_port` function, see the :ref:`tcp-" "server-port-allocation-api` section.*" @@ -433,8 +501,8 @@ msgstr "" "*注意: `free_port` 関数の詳細については、:ref:`tcp-server-port-allocation-api` " "セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:185 -#: ee8148b7ac254bbba148a8ad7a4ebb94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:218 +#: dc449dddb5014d40a50ff66277707822 #, fuzzy msgid "" "At the end of the operations, the TCP server closes all client sockets " @@ -444,8 +512,8 @@ msgstr "" "操作の終了時に、TCP サーバーは辞書変数 ``self.clients`` に含まれるクライアントのソケットをすべて閉じ、サーバー " "ソケットも閉じます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:188 -#: e3cce971756a4931af9b546a1e12aeb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:221 +#: 1d2d730ca10e484d9dadc386b02af66c msgid "" "Before closing the listening socket it shuts it down, which releases a " "thread that is blocked in ``accept()`` (closing alone would leave the " @@ -456,8 +524,8 @@ msgid "" "come up behind the caller's back." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 -#: eb7d0cdf9cb4455eab2a5ba068942fd5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:228 +#: 2975a8e2dfe646cc92f5b112afc6101f msgid "" "*Note: The ``self.clients`` variable is a dictionary that maps client " "address tuples to an info dictionary. The key is the client address tuple" @@ -471,20 +539,20 @@ msgstr "" "``'connected_time'`` " "などの接続の詳細を含むディクショナリです。エントリがどのように保存されるかを示す以下の例を参照してください。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:217 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 +#: 8936cbe70fcf44ac9cabec9e38c0195d msgid "TCP Server handling information API" msgstr "TCPサーバー取り扱い情報API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:219 -#: 45ece19ab8684f67b0f85203f442103e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 +#: 1bbc64aa745a4dc3a537c6c10fd9e3c5 msgid "" "The server handling information API documents the core TCP server methods" " that manage client sockets, receive raw data, and send messages." msgstr "サーバー処理情報 API は、クライアント ソケットの管理、生データの受信、メッセージの送信を行うコア TCP サーバー メソッドを文書化します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:231 -#: 4603ad1e2ffc400491456f7abf750937 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:264 +#: 8b1b042f66a243d9b9abd829a3fefcfe msgid "" "`handle_client` is the main per-client handler in ``TCP_Server_Base``. It" " is invoked after a client connection is accepted and is responsible for:" @@ -492,33 +560,33 @@ msgstr "" "`handle_client` は、 `TCP_Server_Base` " "のメインのクライアントごとのハンドラです。これはクライアント接続が受け入れられた後に呼び出され、次の役割を果たします。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:235 -#: dbeed4ea23664ab298a9c5e356642ddc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:268 +#: 67121b0c979f421eb7ddbfb432dad873 msgid "" "adding the client entry into ``self.clients`` with socket, address, id, " "and connected time" msgstr "ソケット、アドレス、ID、接続時刻を含むクライアントエントリを「self.clients」に追加します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:236 -#: 98d885826d6743a0ad2c72f44e0e9944 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:269 +#: 65ac2e1844dd4a86a5e550063ee90460 msgid "printing connection information and current client count" msgstr "接続情報と現在のクライアント数を出力する" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:237 -#: f9a1536ee7a540d693a2f4f4b3ad690c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:270 +#: 21670e3d261c41b4a0cbf772ab3f0d73 msgid "sending a welcome message to the client" msgstr "クライアントにウェルカムメッセージを送信する" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:238 -#: e75d30ed5656490994353520e09cf789 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 +#: a48af59d8ef54c12929e843db0d51e01 #, fuzzy msgid "" "sending the ``/client_alloc_port_range`` information to that client " "depending on the port allocation mode" msgstr "ポート割り当てモードに応じて、「/client_alloc_port_range」情報をすべてのクライアントにブロードキャストします。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:241 -#: 0e3762f344ff4b88bbb6699610627b41 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 +#: 034082645d394f158d8927076c6b38e9 #, fuzzy msgid "" "*Note: You can specify the port allocation mode in the arguments which " @@ -529,33 +597,33 @@ msgstr "" "*注意: ``TCP_Server_Base`` クラスで定義された引数でポート割り当てモードを指定できます。変更できる引数は " "``port_add_step``、``port_range_num``、および ``is_hand_alloc_port`` です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:247 -#: 3a8f9b23f43a469ca5d7cea807598bd6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:280 +#: 2cb1bb2c2ed84122a479e562a1156bf3 msgid "receiving raw bytes from the socket using `receive_message`" msgstr "「receive_message」を使用してソケットから生のバイトを受信する" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:248 -#: 8f1c9c44d13e41d1b4fdadac75fc4613 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:281 +#: f4db70de0d7d4b4f9f02a1fc2325b172 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "改行で終わるメッセージが完了するまで受信データをバッファリングする" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:249 -#: 54fef48b6314483cbd813885b82ead02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:282 +#: c17ac3c5095746448b497f228eb10c88 msgid "splitting and processing each message line-by-line" msgstr "各メッセージを行ごとに分割して処理する" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 -#: f7728d56338d464cad635232865f9fb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:283 +#: ba1a3439be1d43af80a46d2ee3658ac8 msgid "routing special commands beginning with ``/`` to `handle_command`" msgstr "`/` で始まる特殊コマンドを `handle_command` にルーティングする" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 -#: f87fc68b008a4e06a719e9ab316016f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 +#: 37462f705b094332a79be9d2765c4796 msgid "The `handle_command` function is defined as:" msgstr "`handle_command` 関数は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:263 -#: 8b47f53ad413459393250da7b5f249eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:296 +#: d5bdce3eed0b4171882356d2b207f6d2 #, fuzzy msgid "" "In `handle_command`, there are variable conditional branches to handle " @@ -568,8 +636,8 @@ msgstr "" "には、`/help`、`/time`、`/clients`、`/quit`、およびいくつかのファイル転送コマンドなどの組み込みコマンドを処理するための変数条件分岐があります。コマンド拡張" " API によってすでにコマンドを追加している場合、関数は入力されたメッセージが拡張コマンドと一致するかどうかを判断します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 -#: 1b5f22ecb31f4b17bc31eeba617e9373 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 +#: 21bedf659c7c44a783ed367bebbec813 msgid "" "*Note: For more details of the command extension API and the built-in " "commands, see the :ref:`tcp-server-command-api` section.*" @@ -577,20 +645,20 @@ msgstr "" "*注意: コマンド拡張 API と組み込みコマンドの詳細については、:ref:`tcp-server-command-api` " "セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 -#: f4e3e8921f9c4825b54b7e26c77dfaa1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:307 +#: 85099f44cbb14013a55dcaf602370b51 msgid "logging normal chat messages and acknowledging receipt" msgstr "通常のチャットメッセージのログ記録と受信確認" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:275 -#: e25f3746f80f4046a7aeb5f0b61bba85 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:308 +#: c4a9e9f9ccd74f0ca064b3fe6a95e739 msgid "" "removing the client from ``self.clients`` and closing the socket when the" " client disconnects or an error occurs" msgstr "クライアントが切断されるかエラーが発生したときに、クライアントを「self.clients」から削除し、ソケットを閉じる" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 -#: 21e6108f8c1243a39f017b806967fb1d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:318 +#: 5f6ae0695302473a8adf476a72c72d3a msgid "" "`receive_message` is a thin wrapper around socket receive operations. It " "reads up to ``msg_length`` bytes from the given ``client_socket`` and " @@ -601,8 +669,8 @@ msgstr "" "`msg_length` バイトを読み取り、生のバイト " "ペイロードを返します。メッセージのデコードと改行メッセージのフレーム化は呼び出し元によって処理されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:300 -#: b7e713b412334cc98292e1ca8abbf861 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:333 +#: 114485120bad452e8af2626995798eda msgid "" "`send_message` sends data back to a specific connected client. It " "verifies the server is running and the socket is valid, then:" @@ -610,18 +678,18 @@ msgstr "" "`send_message` " "は、接続されている特定のクライアントにデータを送り返します。サーバーが実行中であり、ソケットが有効であることを確認してから、次のようにします。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:303 -#: 923c92c05c79407e841f3a5d6fefeb92 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:336 +#: 78639cd82b2f42db9ddd7d84bf06e9ee msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "``str`` と ``bytes`` の両方のメッセージペイロードを受け入れます" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 -#: f890eeb62bbc4b5ab359452c6dd40b17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:337 +#: bff4a398dec3443391a0c6e6a9fb00ee msgid "trims string payloads and appends a newline if missing" msgstr "文字列ペイロードをトリミングし、欠落している場合は改行を追加します" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:305 -#: 21a1156ab51b4dc598f583c1d9f9defc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:338 +#: 033e533bc19f484bb0fe7d61fe01dc46 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -631,42 +699,42 @@ msgstr "" "ソケットが暗号化モードの場合 (公開鍵交換が完了している)、平文は「_VALID」マーカーで署名され、RSA-OAEP " "はピアの公開鍵で暗号化され、平文で送信されるのではなく、base64 でエンコードされ、改行で終了されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:309 -#: 94980e8ed8db4bfeb6bb4f4278c10d04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:342 +#: 1f1be9fb9dff4409aa040671a8e89013 msgid "encodes string payloads as UTF-8" msgstr "文字列ペイロードを UTF-8 としてエンコードします" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:310 -#: ce93763396994dbabdc93a51b56ed8c3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:343 +#: 38c4b6970f644bf6b1dee52c1d6f7157 msgid "" "sends the message with ``client_socket.sendall(data)`` when the server " "serves clients with one thread each, or through a non-blocking ``send()``" " loop when ``is_asynic_clients_io`` is ``True``" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:313 -#: eb3454d6feb84ce1a3e00a573cf20972 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 +#: b3f2ff47fdc74a1fb5b599b1f3706a59 msgid "" "returns ``True`` on success; it returns ``False`` for an unsupported " "payload type, and an invalid/closed connection raises ``RuntimeError`` " "(other socket failures are logged and re-raised)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:317 -#: 62174575716644e69c0d479ff05a9df0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:350 +#: 042c1637a86c494ca7da9ba4299b08be msgid "" "And there are also some other functions which are used to send message in" " bulk to the clients, such as the `broadcast` function and the " "`send_msg_to_specific_client` function." msgstr "また、「broadcast」関数や「send_msg_to_specific_client」関数など、クライアントにメッセージを一括送信するために使用される関数もいくつかあります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:325 -#: 762f3bf7c5bb46e091ca12b1f0393624 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:358 +#: eeecf353189a46f8972335c059bef718 msgid "TCP Server encrypted channel API" msgstr "TCPサーバー暗号化チャネルAPI" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:327 -#: 67ffdc91d9694e77ab33c0c60253430d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:360 +#: e5659287613a419dbbecdc491f57b514 msgid "" "When the server is created with ``is_enable_encrypto=True`` (the " "default), every connected client goes through an RSA public-key exchange " @@ -675,13 +743,13 @@ msgstr "" "サーバーが ``is_enable_encrypto=True`` (デフォルト) " "で作成された場合、接続されているすべてのクライアントは、メッセージの内容が暗号化される前に RSA 公開鍵交換を通過します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:332 -#: 8de167f009be4406b25e0e3d3be6cb4b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:365 +#: a31863451ad94e828e4d5826811dc4e9 msgid "Key material" msgstr "キーマテリアル" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:334 -#: 01312565566c4707b6d4b55a223882d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:367 +#: aae09222bb4b42dfb9db4c7ebc329d10 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -694,8 +762,8 @@ msgstr "" "``server_pub.pem``) に生成されます。交換される公開鍵は常に秘密鍵から派生するため、ローテーションされた ``~/.ssh`` " "ペアが自動的に選択されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:339 -#: 5e641bcd12c44f73bd22b43332b12b91 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:372 +#: f4206182556e4cca9a9284905e3de143 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -706,8 +774,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 -#: 26f407b8ad29482ca30db4edd0f20abe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:379 +#: bab30142a34845e5b01353a55c4ba643 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -719,8 +787,8 @@ msgstr "" "pvt_key_path]」で強制できます。両方のファイルが存在し、PEM として解析され、相互にペアになる必要があります " "(公開キーで暗号化されたプローブは秘密キーで復号化する必要があります)。無効なペアは無視され、デフォルトの検索が使用されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:351 -#: 3af59fcb848044718426e6b9427c017d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 +#: 324dcdafcfa048218e102466956bd1a5 msgid "" "Public keys received from clients are cached in " "``network_api/.Flow/pub_key`` as ``client__.pem`` (the peer " @@ -731,13 +799,13 @@ msgstr "" " (鍵の取得元のピアエンドポイント。「:」は「_」に置き換えられるため、IPv6 リテラルは Windows " "を含むすべてのプラットフォームで安全です)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:357 -#: 26ea5ad884b4402097ce3f800bb7e8d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:390 +#: aee5a1316ad24fab8db1dedeb6c95790 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM ID チェック (TOFU)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:359 -#: 69fe026672cc44c7b931a2a404468eb0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:392 +#: 8ceb7ab10998464e93c80c1609797ac7 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -751,15 +819,15 @@ msgstr "" "に記録します。キーは ``(ip, port)`` (ピアの接続元エンドポイントの Python タプル)、値は ``[<公開鍵の " "sha256>, <公開鍵 PEM>]`` です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:366 -#: f8e45fa616844ba287ea1d9a249d5157 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:399 +#: e63b24b8eded401fb82be09174963c1b msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "エンドポイントからの最初の接続: キーは記録され、信頼されます (初回使用時の信頼)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:368 -#: faa949fc11b74c9692009fba21d3a5f2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:401 +#: 9c091413145845f3b15fac0bdc9b583c msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -768,8 +836,8 @@ msgstr "" "*同じ* キーを提示するその後の接続: 受け入れられました。エンドポイントが変更された場合 (動的 IP / " "ユーザーが変更したポート)、レコードは複製されるのではなく、新しい ``(ip, port)`` に移動されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:371 -#: d80fbe47d78343d6a5ae8b7a7388b177 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:404 +#: d89337a304a24744a703acaa977b3290 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is sent and the " @@ -778,8 +846,8 @@ msgstr "" "すでに記録されているエンドポイントに対して *異なる* キーを提示するその後の接続: 接続は拒否されます (``/crypto_reject`` " "が送信され、ソケットが閉じられます)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:375 -#: c12761b71fbb40e9b5d9f17ce7389981 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:408 +#: ff44ccbece9b48ab8e86a12cba949078 msgid "" "Because the server-side record is keyed by the client's source port, a " "client that rotates its keypair is only detected when it reconnects from " @@ -794,13 +862,13 @@ msgstr "" "アドレスによってキー設定されるため、変更されたサーバー キーは常に拒否されます。信頼 (ローテーションされたキー、新しいサーバー) " "をリセットするには、``pub_key.json`` エントリ (またはファイル全体) を削除します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 -#: 160b797ceb5340aaa631e6a42ed052f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:417 +#: e011f68df76445d18659be173dba1877 msgid "Handshake" msgstr "ハンドシェーク" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:386 -#: 6f031912413e4e4b8b7105c3c59f1b99 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:419 +#: 700f2215924f4bfb92c3f90f37c3e514 #, fuzzy msgid "" "The client initiates the exchange by sending a plaintext " @@ -809,12 +877,16 @@ msgid "" "Both sides then push their public key files over the file-transfer " "mechanism (plaintext) and TOFU-check the received key. Both sides switch " "to encrypted mode only after ``/crypto_ready`` has been received from the" -" peer (so plaintext and ciphertext never interleave on a connection). On " -"later connections the keys are re-exchanged and TOFU-checked again; the " -"exchange is never skipped, only the identity check short-circuits for " -"known keys. Public-key pushes are only accepted from a connection that " -"actually started the handshake, so an arbitrary unauthenticated peer " -"cannot poison the registry." +" peer (so plaintext and framed traffic never interleave on a connection)," +" then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted from a connection that actually started the " +"handshake, so an arbitrary unauthenticated peer cannot poison the " +"registry." msgstr "" "クライアントは、平文の ``/crypto_key_exchange`` " "グリーティングを送信することで交換を開始します。サーバーは「/crypto_key_exchange_ack " @@ -823,34 +895,58 @@ msgstr "" "(そのため、平文と暗号文が接続上でインターリーブされることはありません)。その後の接続では、キーが再交換され、再度 TOFU " "チェックが行われます。交換は決してスキップされず、既知のキーに対する ID チェックのみがショートします。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:400 -#: 1efd337c73d249a3b4b15394337e6307 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:437 +#: a9531ad5339a4633a1e6cc54fb8bb79b msgid "Replay protection" msgstr "リプレイ保護" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:402 -#: 28c8ec1c26d946a19bc02d6aacc9961b -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." -msgstr "" -"ハンドシェイクではランダムなセッション nonce が交換され、回線上のすべての暗号化された回線には、それに加えて接続ごとのシーケンス番号 " -"``||`` が付けられます。受信者は、ノンスが現在のセッションと一致しない行 " -"(古い接続から再生された暗号文)、またはシーケンス番号が予期したものではない行 (セッション内で再生された暗号文 / 順序が乱れている) " -"をドロップします。 (再) 交換後にソケットが暗号化モードに切り替わると、両方のカウンタがリセットされます。" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:411 -#: c11de683c36c42c59ff73d0839f5afce +#: ../../source/Network_APIs/TCP_Server_APIs.rst:439 +#: e9505df5322640ce8671b5098d655374 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:455 +#: 3fd7ac4d381e41589a62998726dd22f7 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:457 +#: 8ca69d91005b459a8a56f21902eaa690 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:469 +#: b32b4fa4788d4f9d88926958c81ad73f msgid "Decode verification and key rotation" msgstr "デコード検証とキーローテーション" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:413 -#: ba7b28826b9f4d0a85328f08be4a76e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:471 +#: d09ae3121b0f40fb85374589b851d45c msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -872,20 +968,25 @@ msgstr "" "セクションを参照)。意図的にキーペアをローテーションするユーザーは、新しいキーを再度信頼するには、ピア側の古い ``pub_key.json`` " "エントリ (またはファイル全体) を削除する必要があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:424 -#: 6f0160000f2b451a81771556bbc3b8e7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:482 +#: 7312fb4bd4c345ff9cec7ffe4245afb7 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures on one connection the connection is closed " "instead of re-exchanging, so a garbage-injection or persistent-mismatch " -"storm cannot spin the loop forever. A successful decryption resets the " -"counter." +"storm cannot spin the loop forever. Genuine peer traffic (messages and " +"commands other than the protocol's own handshake/coordination lines) " +"resets the counter. Frames the peer had already sent when this side " +"dropped out of encrypted mode are stale: they cannot be authenticated any" +" more, so they are consumed and dropped — they neither surface as " +"messages nor reset the counter." msgstr "" "再交換はサーキットブレークです。 ``MAX_DECODE_FAILURES`` (3) 1 " "つの接続で連続したデコード失敗の後、接続は再交換されずに閉じられるため、ガベージインジェクションや永続的な不一致の嵐によってループが永久に回転することはありません。復号化が成功すると、カウンターがリセットされます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:438 -#: 850c5c67b6504551a3104a9cfa5710e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 +#: 4fb05c76f6734fd58aa33ee628ad933d #, fuzzy msgid "" "The `broadcast` function sends a message to all clients in the " @@ -899,8 +1000,8 @@ msgstr "" "``exclude_client`` パラメータが ``None`` でない場合、サーバーはメッセージ送信時に " "``exclude_client`` パラメータで指定されたクライアントを除外します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:452 -#: 9ddd28be0e6b439891a25d79adbaf823 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:514 +#: 0b4f67331831429b85514fbbe3ce2602 #, fuzzy msgid "" "The `send_msg_to_specific_client` function sends one or more messages to " @@ -913,41 +1014,43 @@ msgstr "" "`send_msg_to_specific_client` 関数は、クライアント ID によって 1 つ以上の特定のクライアントに 1 " "つ以上のメッセージを送信するために使用されます。そして、メッセージ送信コマンドには ``message`` 引数を入力する必要があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:459 -#: 4f7cd128081c4062bffdacfb4b67137c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 +#: c8f357719cc548719792a5a2cade0c03 msgid "" "These methods form the server's client I/O loop and ensure reliable " "message exchange for connected TCP clients." msgstr "これらのメソッドはサーバーのクライアント I/O ループを形成し、接続された TCP クライアントに対する信頼性の高いメッセージ交換を保証します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:466 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 +#: 8936cbe70fcf44ac9cabec9e38c0195d #, fuzzy msgid "TCP Server inbound event listener API" msgstr "TCPサーバーファイル転送API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:468 -#: f86e7c53407b43509932d19288024a54 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 +#: 583ef0a34dfc480da5b4fc87108cbf2f msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:478 -#: f59f2230d9f648ca99834633af460deb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:540 +#: 0a30ecd70b364968a892136d9bec809f msgid "" "``add_message_listener`` registers ``listener(client_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to the command handlers instead). ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a" -" file uploaded by a client has been fully written to the transfer " -"directory (``command`` is the wire command that triggered it, so protocol" -" pushes such as ``/crypto_pub_key`` can be recognised). Both listeners " -"run on a protocol thread, so they must not block, and an exception inside" -" a listener is logged and swallowed. The ``remove_*`` counterparts " -"unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:489 -#: a39677d08af4439989a6fced80cb12d1 +"every inbound line, commands included (``/help``, ``/file ...``, the " +"crypto handshake lines, ...), so a listener observes all inbound traffic;" +" line dispatch is unaffected, a command still goes to the command " +"handlers. ``add_file_listener`` registers ``listener(client_id, " +"full_path, name, size, command)`` and fires after a file uploaded by a " +"client has been fully written to the transfer directory (``command`` is " +"the wire command that triggered it, so protocol pushes such as " +"``/crypto_pub_key`` can be recognised). Both listeners run on a protocol " +"thread, so they must not block, and an exception inside a listener is " +"logged and swallowed. The ``remove_*`` counterparts unregister a listener" +" and ignore unknown ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:553 +#: a7bb1a9276bd4860882ffd43a680d6bf msgid "" "In addition, received messages and events are stored per sender socket in" " ``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -956,13 +1059,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``stop`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:498 -#: cdfe98e71ed34af9a2976b7e884b5201 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 +#: 403a3b0e938b4895be69267c66ecff98 msgid "TCP Server command API" msgstr "TCPサーバーコマンドAPI" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 -#: 25c853b63e744fd6a370ecd365c58fd7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 +#: 9c016262f199458585bb12055da6d30d msgid "" "The server supports several built-in commands and a command extension " "API. The main entry point is the `handle_command` method, which is " @@ -971,19 +1074,20 @@ msgstr "" "サーバーは、いくつかの組み込みコマンドとコマンド拡張 API をサポートしています。メインのエントリ ポイントは `handle_command`" " メソッドで、これは `/` で始まるメッセージに対して呼び出されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:505 -#: d0e290f03c1242b580024033ffab5e04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 +#: b26b06ec49a644c9b034acf6930006bd #, fuzzy msgid "" "We support two solutions for command handling: inputting a command in the" " console or receiving a command from other clients. You can also call the" -" functions defined for each command in the code." +" functions defined for each command in the code via " +"`call_extension_functions`." msgstr "" "コマンド処理には 2 つのソリューションがサポートされています。1 つはコンソールにコマンドを入力する方法、もう 1 " "つは他のクライアントからコマンドを受信する方法です。また、コード内でコマンドに定義されている関数を呼び出すこともできます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:510 -#: aad12adb23334f4e9c5b6b7f7637dd3e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:575 +#: 5f20432236324511acfc720b1e616e49 #, fuzzy msgid "" "*Note: You can select the solution which you want to use by changing the " @@ -995,44 +1099,44 @@ msgstr "" "`is_input_command_in_console` です。 ``True`` " "はサーバーがコンソールにコマンドを入力することを許可しますが、 ``False`` は許可しません。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:517 -#: 88e051e4fef245c7a474a8478dc74b88 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:582 +#: cc5dd7cfa448466399da9463e53c1a08 msgid "Built-in client commands include:" msgstr "組み込みのクライアント コマンドには次のものが含まれます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:519 -#: c8a591e28fcf4243862e820e582e9127 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:584 +#: 989d1b29c70e4f9883b95523b0b420d9 msgid "``/help``: returns the available command list and usage hints." msgstr "``/help``: 利用可能なコマンドのリストと使用法のヒントを返します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:520 -#: 453004b0bb914398a4d9a437f5d1b864 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:585 +#: a4795afd8b3249538f031ed27783f0a7 msgid "``/time``: returns the current server time." msgstr "``/time``: 現在のサーバー時刻を返します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 -#: 324cbdab33984517a498f1e2747a6387 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:586 +#: b2d813b2d8bb46c59195ed01431d150b msgid "``/clients``: returns the list of connected client IDs." msgstr "``/clients``: 接続されているクライアント ID のリストを返します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:522 -#: a4411c0f498c434fbe864ea1627384fb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:587 +#: d81ad6c5cbe44bd589f32ce7f3e36d31 msgid "" "``/quit``: writes a goodbye message (``Bye!``) and shuts the connection " "down, so a client that stays after sending ``/quit`` is disconnected by " "the server." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:525 -#: 1248e1b365da420e8d96182e8a237d57 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:590 +#: a9fbf429095b4483b18a247ef327b461 msgid "" "``/file [destination_file_path]``: starts a file transfer " "from the client to the server. The trailing token of the wire line is the" " sender's own transfer id, appended by the sending client." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 -#: c8de5282934945bab929e1084d7848f5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 +#: cef48a93703449f8813fab1d3fb199fb #, fuzzy msgid "" "``/file_folder [destination_file_path]``: starts a folder " @@ -1041,22 +1145,34 @@ msgstr "" "``/file_folder ``: " "クライアントからサーバーへのフォルダ転送リクエストを開始します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 -#: d006c91db83f4404b7f7022cb9bb61c5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:595 +#: 92bf2736c9c14f1cb24ec110315f8caa msgid "" "``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``:" " internal handshake messages of the encrypted channel." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:532 -#: c026024882d44552a578b0fe4e096b34 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:597 +#: 38987654adbf4707b84c8048a9cdcbb3 msgid "" "``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, " -"``/start_trans``: internal forwarding/transfer-control messages." +"``/start_trans``: internal forwarding/transfer-control messages. " +"``/pause_trans `` and ``/start_trans `` hold and release the " +"outbound transfer with that fid (`pause_trans`/`start_trans` are the same" +" switch as a public API)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:534 -#: 5fb7405e0dae4344a58d3a61aa5f2779 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:601 +#: 7f3801d57ac34670bbe16736683db30e +msgid "" +"``/resume_trans `` and ``/forward_resume " +"``: internal transfer-reconnect messages: the receiver asks the " +"sender (or, for a forwarded transfer, the originator) to continue the " +"file from the bytes already on disk. See `resume_transfers`." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:605 +#: abd7d3032e15468e92f96a0b5af1f926 msgid "" "``/server_file_transfer_port ``: internal protocol " "message used to coordinate file transfer ports." @@ -1064,8 +1180,8 @@ msgstr "" "``/server_file_transfer_port ``: " "ファイル転送ポートを調整するために使用される内部プロトコル メッセージ。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:536 -#: 94f93b06051f4eebaf0b64ccf589160b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:607 +#: 1e9e32071bb1425b8617a419a7ef87f6 msgid "" "In `handle_command`, the server will first check if the command matches " "any built-in commands. If it does, the `handle_command` will call the " @@ -1075,8 +1191,8 @@ msgstr "" "では、サーバーはまずコマンドが組み込みコマンドと一致するかどうかを確認します。実行すると、`handle_command` " "はコマンドに定義されている関数を呼び出します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:541 -#: 16991ef553344476af487507dc3a1a0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:612 +#: f08564b44ab0442788145105b1086bb8 msgid "" "If a command is not recognized by the built-in handler, `handle_command` " "will check if it matches any registered custom commands from the command " @@ -1088,18 +1204,26 @@ msgstr "" "コマンドと一致するかどうかをチェックします。コマンドがすでに登録されている場合、「handle_command」はそのコマンドに定義された関数を呼び出します。コマンド拡張" " API は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:559 -#: 9c0334fe21e34b6ab8b1c941e1c62e2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:633 +#: ac06208b93d54ede93002123521d921b +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code; the command's first token selects it, exactly as it does for " +"a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:637 +#: 11c186c6375b4eeeb337ac755b136a94 msgid "The args of the `register_command` function are as follows:" msgstr "`register_command` 関数の引数は次のとおりです。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 -#: ac4db02fce3d492b81a094400f44b0a8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 +#: 6741d64e02414c1c8759b14d41ec69a1 msgid "``command_name``: The name of the command to register." msgstr "``command_name``: 登録するコマンドの名前。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 -#: 8e250a4664ce40c89f0190ce7eb67848 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:642 +#: 21a28c492d33486a81f97ca3d8a32266 msgid "" "*Note: The ``command_name`` should start with a slash (e.g., " "``/my_command``) to be recognized as a command.*" @@ -1107,13 +1231,13 @@ msgstr "" "*注意: コマンドとして認識されるように、``command_name`` はスラッシュで始まる必要があります (例: " "``/my_command``)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:567 -#: f91cdc45f9ea4c35891b087f1097ba51 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:645 +#: 6deb6588265049cbbeaea615b7d6c2cf msgid "``handler``: The function to call when the command is received." msgstr "``handler``: コマンドを受信したときに呼び出す関数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 -#: 1797ec404bbe45b380d46588adbb731f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:647 +#: 16d22c49f16d4430bfe740374d70705f #, fuzzy msgid "" "*Note: The ``handler`` function must have exactly three parameters: " @@ -1128,20 +1252,20 @@ msgstr "" "はコマンドを送信したネットワークソケットオブジェクトとして受け入れられ、 ``client_address`` " "はコマンドを送信したクライアントのアドレスとして受け入れられます。一方、 ``command`` パラメータには実際のコマンド文字列が含まれます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:577 -#: 56b8f72098b84ccea4d1bf143a31e04c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:655 +#: 7605062541fa4d70ae37d67efdfd5fdf msgid "``where_to_run``: Specifies where the command should be executed." msgstr "``where_to_run``: コマンドを実行する場所を指定します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:578 -#: 7572e9944acd4704b2c55643fb1fbcd4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:656 +#: f6ee42356212497ba468266c87e127d4 msgid "" "``run_in_thread``: A boolean indicating whether to run the command in a " "separate thread." msgstr "``run_in_thread``: コマンドを別のスレッドで実行するかどうかを示すブール値。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:580 -#: 0ac212e49ef54e77b5429272e05561aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:658 +#: 37adfd2db6af47bf995b271dd70ad293 msgid "" "This extension API allows server-side and console-side custom commands to" " be registered dynamically. Valid values for ``where_to_run`` are " @@ -1155,16 +1279,16 @@ msgstr "" "は、クライアントがコマンドを送信したときにコマンドが処理されることを意味し、一方、``\"client\"`` " "は、サーバがコンソールにコマンドを入力したときにコマンドが処理されることを意味します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:589 -#: c0201e2dd3fd4c7fa8d363060c5ff49a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:667 +#: 24c64499179b4f01a92ffd8e88515738 #, fuzzy msgid "" "*Note: It's true that the valid values for ``where_to_run`` are not " "ideal, but we have not yet found a better way to define that.*" msgstr "*注意: ``where_to_run`` の有効な値が奇妙すぎるのは事実ですが、それを定義するより良い方法が見つかりませんでした。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 -#: ec3b9b188728413eb3cd5871542b83cd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:671 +#: fbdb162f54a64fd3b454ddbf85a6e5d4 #, fuzzy msgid "" "The ways to run the command will be different according to the args " @@ -1178,8 +1302,8 @@ msgstr "" "ハンドラはサーバーのスレッド プールとは別のスレッドで実行されます。 run_in_thread が False の場合、コマンド " "ハンドラはメイン サーバー スレッドで同期的に実行されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:603 -#: 0a62647e915e4e4c80071b3d7fb41464 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:681 +#: 9576b9601ddd48749947aa7b18bc2c82 #, fuzzy msgid "" "*Note: We store the registered commands in a list variable with two " @@ -1201,16 +1325,16 @@ msgstr "" " として定義された別のリスト変数もあります。これは `__init__` " "メソッドで初期化され、別のスレッドで実行する必要があるかどうかに関係なく、すべてのコマンドが含まれています。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:617 -#: eb202f79be654e5a8cccf56c79446b3d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:695 +#: b1f239408f354bf2bdc608ad523f233e msgid "" "*Note: ``register_command`` returns ``False`` when ``where_to_run`` is " "neither ``\"server\"`` nor ``\"client\"`` (nothing is registered then); " "on success it returns ``None``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:626 -#: 088dcc7ce39046a4afa6451d7e6369f9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:704 +#: b10dad811f9b444bb0a2e3642709b5d1 msgid "" "After that, the command handler will be called according to the command " "name, and run them by a command executor which is defined as:" @@ -1218,8 +1342,8 @@ msgstr "" "その後、コマンド名に従ってコマンド ハンドラーが呼び出され、次のように定義されたコマンド エグゼキューターによってコマンド " "ハンドラーが実行されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 -#: 0e56345aa429469cb44d7708b6af8711 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:718 +#: 7c0987568cf245b9b78d1db2f403717f msgid "" "In this executor function, there is a try-except code block to catch the " "error when running the command handler. If there is an error when running" @@ -1235,8 +1359,8 @@ msgstr "" "ハンドラーがコマンド引数を使用して呼び出されます。また、コマンドがクライアント側からのものである場合は、クライアント ソケットとクライアント " "アドレスも使用されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:650 -#: 6467226e231c4e458bb78687c9da8659 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:728 +#: a98408c31eee4f3fbad1c3afdb2a036c #, fuzzy msgid "" "If the command doesn't run in the thread, the command executor will be " @@ -1249,8 +1373,8 @@ msgstr "" "関数内で直接呼び出されます。ただし、コマンドを別のスレッドで実行する必要がある場合、コマンド実行プログラムは、次のように定義される " "`submit_task` メソッドを使用してサーバーのスレッド プールに送信されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:665 -#: fb9ac9433b8342dd9e90707a01990fd0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:743 +#: c3401f2293044a31a7e8e6d2e8407797 #, fuzzy msgid "" "The `submit_task` method is a helper function that submits a callable to " @@ -1265,8 +1389,8 @@ msgstr "" "エグゼキュータに呼び出し可能ファイルを送信するヘルパー関数です。関数とその引数を受け取り、それを別のスレッドで実行するようにスケジュールします。これにより、メイン" " サーバー ループをブロックすることなく、長時間実行またはブロックされているコマンド ハンドラーを実行できます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:675 -#: 711e7a3b8f114200857fc39218e2820f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 +#: 9a327fd5482b4575a777e49024f42f56 msgid "" "In this high-level TCP network protocol, a temporary TCP server and " "client can also be created very simply. The temporary TCP server or " @@ -1280,8 +1404,8 @@ msgstr "" "ループとの競合を避けるために追加のソケットまたはポートが必要なシナリオに使用できます。たとえば、ファイル転送機能です。一時的な TCP " "サーバーとクライアントを作成する API は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:688 -#: 7368e712e93f4be7aaeeae265b22e832 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:766 +#: b1e9ab095ed84ef8ae08333047df5b93 msgid "" "``create_temporary_server`` returns ``(port, thread, stop_event)``: the " "bound port (``palloc()`` picks one when ``port`` is None), the accept-" @@ -1290,21 +1414,21 @@ msgid "" " allocated." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:693 -#: 0750bd372cf6478eb8123ca0603de9c2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:771 +#: d23ff87180c44746b62528903a34cdb5 msgid "" "``create_temporary_client`` returns ``(client_socket, thread, " "stop_event)``: the connected socket, the receiver thread and an event " "whose ``set()`` ends that thread." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:700 -#: edf78b86ed664657adc2b46ab0f7efdd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:778 +#: c14e33129d3b41ee8c1dac7189f0408d msgid "TCP Server console commands" msgstr "TCPサーバーコンソールコマンド" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:702 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:780 +#: 2ad09a3887894e01a67d31c28272f730 msgid "" "The server console input thread accepts administrative commands when " "``is_input_command_in_console`` is ``True``. Supported console commands " @@ -1313,23 +1437,23 @@ msgstr "" "サーバーコンソール入力スレッドは、 ``is_input_command_in_console`` が ``True`` " "の場合に管理コマンドを受け入れます。サポートされているコンソール コマンドは次のとおりです。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:706 -#: 5a059eb897914040873e954609c66c0c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:784 +#: 4d4368102eae41dbac5a8938a4726e1a msgid "``/stop``: stops the server and closes all active connections." msgstr "``/stop``: サーバーを停止し、アクティブな接続をすべて閉じます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:707 -#: db67da00bf70423a9a3cf4a2fa3a01e1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:785 +#: 8035f922921f4301bbe4ca4936ea38b3 msgid "``/status``: prints the current connection count and running state." msgstr "``/status``: 現在の接続数と実行状態を出力します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:708 -#: 15ab35eecbd84e64b8dfc0ac50c3d173 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:786 +#: ce2138bd90784f1daffb39cc8d46d1f1 msgid "``/clients``: prints the connected clients and their connection times." msgstr "``/clients``: 接続されているクライアントとその接続時間を出力します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:709 -#: 2d1d3fe9ee9f4d6899754d296f8ede75 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:787 +#: 8c9f96a3d0cd4fbcb311c201db9ff789 msgid "" "``/send_msg <(ip, port)> ...``: sends one or more messages " "to specific clients. Targets are literal ``(ip, port)`` tuples (its own " @@ -1337,24 +1461,24 @@ msgid "" "form)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:710 -#: 92d75f708fe642cf8a77f986f2d891b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:788 +#: 033fdbf663a04e12bfdff63da6e0f6c1 #, fuzzy msgid "" "``/file <(ip, port)> [destination_file_path]``: sends a file " "from the server to a specific client." msgstr "``/file ``: サーバーから特定のクライアントにファイルを送信します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:711 -#: 8b28ccd83c594ee5a0ccd126db3bb2dd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:789 +#: 49fea0c411844c689ea2cabaa11c70b3 #, fuzzy msgid "" "``/file_folder <(ip, port)> [destination_file_path]``: " "sends a folder from the server to a specific client." msgstr "``/file_folder ``: フォルダをサーバーから特定のクライアントに送信します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:712 -#: 585e54ca3b1545f49a347b69680d3cd2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:790 +#: d4c2a98b15c04214bfca54bd719f9ab4 msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " "port)2> ...``: sends multiple files to multiple clients. Tokens are " @@ -1362,8 +1486,8 @@ msgid "" "otherwise, so files and targets may be interleaved." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:713 -#: 60def6731a3a43d1a074374978801dbc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:791 +#: e6c9995a12a24a6ba5534e475f158d86 msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, " "port)1> <(ip, port)2> ...``: sends the files that precede a group of " @@ -1372,13 +1496,13 @@ msgid "" " that is not a tuple) is accepted and passed on." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:714 -#: 0f9a9437ddcd4894b6be7502e1303c6e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:792 +#: d8253e90b4fe4d8dbe0b2bbd23134dc0 msgid "``/help``: prints a help summary of console commands." msgstr "``/help``: コンソールコマンドのヘルプ概要を出力します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:716 -#: 1e898bf6aeb54dcb8533615767d03791 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:794 +#: 8cf019297938433ebe65839a4513ae63 msgid "" "The forward commands (``/forward_send_msg``, ``/forward_file``, " "``/forward_folder``) are client-only and are refused on the server " @@ -1386,15 +1510,15 @@ msgid "" "``where_to_run=\"client\"``." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:721 -#: aff923b39d6843bb976f5bb40d38a71d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:799 +#: 43db2954705945c3b3b0742033f122b9 msgid "" "These console commands make it easy to manage the active server and " "perform server-initiated file transfers without modifying the code." msgstr "これらのコンソール コマンドを使用すると、コードを変更せずに、アクティブ サーバーの管理とサーバー開始のファイル転送の実行が簡単になります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:725 -#: bcbb903def99415298bb7b29d21f31f6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:803 +#: 261fde939721476abba9b40f0290944f #, fuzzy msgid "" "*Note: It is too long to introduce all the console commands, so for more " @@ -1403,13 +1527,13 @@ msgstr "" "*注意: すべてのコンソール コマンドを紹介するには長すぎるため、詳細については、:ref:`tcp-server-console-" "commands` セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:729 -#: c68a8d4ecb904da7980049abc5210fdf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 +#: 0e848b37570e4fc8b23ff7eb13a2ae3e msgid "TCP Server file transfer API" msgstr "TCPサーバーファイル転送API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:731 -#: 1e9d70417dbf4446bc8528cf692db8ed +#: ../../source/Network_APIs/TCP_Server_APIs.rst:809 +#: 27472ef4f13641ba9a08e6a97bb651dc msgid "" "The TCP server contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers." @@ -1417,8 +1541,8 @@ msgstr "" "TCP " "サーバーには、クライアントからサーバーへの転送とサーバーからクライアントへの転送の両方をサポートするファイル転送サブシステムが含まれています。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:735 -#: 695753d4c2bc4f15972565a20be6b6c8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 +#: eadd29678d8a449c9659c4792b5f2cb0 #, fuzzy msgid "" "It's too long to introduce all the file transfer functions, so there is " @@ -1428,40 +1552,40 @@ msgstr "" "すべてのファイル転送機能を紹介するには長すぎるため、ファイル転送機能の API " "のリストのみを示します。ファイル転送機能の詳細については、以下を参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:740 -#: 5f303019ed3747a691e61b7f20cdb1cf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:818 +#: 1ca2a6ce0f124ebc87676b1155c4c022 msgid "The file transfer API for you to use includes:" msgstr "使用できるファイル転送 API には次のものが含まれます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:742 -#: 376da0b60e9641efa6a75ed7e52af8bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:820 +#: 63c118c7e7c4478fa14f3cb0950f6c1c msgid "The basic function for the server-to-client file transfer is defined as:" msgstr "サーバーからクライアントへのファイル転送の基本機能は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 -#: 80a158519403430f8f7c43893634e6d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 +#: 4e3a0194c55744898eb3884b60d75672 msgid "The file transfer function which will run in the threads is defined as:" msgstr "スレッド内で実行されるファイル転送関数は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:764 -#: 771b5bd6acad467d92fbeebcacbc6dba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 +#: 3fd7ac4d381e41589a62998726dd22f7 msgid "The folder transfer function is defined as:" msgstr "フォルダー転送関数は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:773 -#: da45b1e2fcc34c1a96c1d1f9e809f742 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 +#: 833a77a7c8fa480db0a0b6e8387132d3 msgid "The multiple files transfer to multiple clients function is defined as:" msgstr "複数のファイルを複数のクライアントに転送する機能は次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:783 -#: 15099b87947a4f08a34ca87734c23306 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:861 +#: 26032ba6212f443980c40351874b2139 msgid "" "The different multiple files transfer to the different multiple clients " "function is defined as:" msgstr "異なる複数のファイルを異なる複数のクライアントに転送する関数は、次のように定義されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:793 -#: d93a80b4acca404f98faaf0a7f133079 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:871 +#: 0c9b95c194634285aade290fb17bef5b #, fuzzy msgid "" "We recommend that if you want to use the mono-file transfer function, use" @@ -1481,8 +1605,8 @@ msgstr "" "`file_transfer_server_recv_client_start` " "関数を直接呼び出すことができます。そうでない場合、ファイル転送関数はあまりステートブルではない可能性があります。また、他のファイル転送関数については、スレッドで使用することはあまりお勧めしません。関数にはすでにいくつかのスレッド制御メカニズムが組み込まれているため、同時パフォーマンスについては心配する必要はありません。また、スレッド内でそれらを呼び出すと、予期しないエラーが発生したり、過度に複雑になったりする可能性があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 -#: c3f69c0b152c44df91753c54cf94593f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:885 +#: 28c7d60dd34d48ababd9c06199091309 msgid "" "*Note: The file transfer API functions are designed to be called from the" " command handlers for both client-initiated and server-initiated " @@ -1493,18 +1617,18 @@ msgstr "" "ハンドラーから呼び出されるように設計されています。これらは、転送ポート、クライアント接続、および実際のファイル " "データ転送操作の調整を処理します。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 -#: 666eecd4aa974e2d8b5b9a1ff3acbc25 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:891 +#: 0fcf1a7def3e437d9ecbaf8d5d02470a msgid "Client-to-server transfer flow:" msgstr "クライアントからサーバーへの転送フロー:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:815 -#: f6b96397ab484021974c50cf86144a12 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:893 +#: 740bd9ad4564417e8f76f28500d1da68 msgid "The client sends ``/file`` or ``/file_folder`` to request a transfer." msgstr "クライアントは、転送をリクエストするために ``/file`` または ``/file_folder`` を送信します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:817 -#: d6b57e1e1e6e4ea78d59d9a47a1a4ccc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:895 +#: e26bd8a6fb5a4977a3039fd2bdf22114 #, fuzzy msgid "" "``handle_command`` starts a dedicated file-server thread: " @@ -1515,8 +1639,8 @@ msgstr "" "``handle_command`` は ``file_transfer_server_recv_server_start_thread`` " "を使用して専用のファイルサーバースレッドを開始します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:821 -#: 3ba05b4bc071401d959f68b7019c7aa3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:899 +#: e5ef46040255421fa92c6de33d976671 msgid "" "The server allocates an ephemeral transfer port with ``palloc`` and sends" " ``/server_file_transfer_port `` back to the client." @@ -1524,25 +1648,25 @@ msgstr "" "サーバーは ``palloc`` で一時転送ポートを割り当て、``/server_file_transfer_port " "`` をクライアントに送り返します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:825 -#: 9f8b5c7e3b8048c9b9ded191ecd70d6b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:903 +#: 6eaa70d4d985489e8f0e683baa6b52a1 msgid "" "The client connects to that transfer port and sends file metadata, " "including length-prefixed filename and file size." msgstr "クライアントはその転送ポートに接続し、長さの接頭辞が付いたファイル名やファイル サイズなどのファイル メタデータを送信します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:828 -#: 95c2b39e285840678adb522483da672b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:906 +#: 245d5d51d72a41ee86c9925ec1872e35 msgid "The server receives the file and writes it under ``received_files``." msgstr "サーバーはファイルを受信し、それを ``received_files`` の下に書き込みます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 -#: 8254cf417a46471ea770e4917e96b05b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 +#: 5ad02fbb498f483580e470b2f5291a53 msgid "Server-to-client transfer flow:" msgstr "サーバーからクライアントへの転送フロー:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:833 -#: 69032201d7254006b52a86961f08530a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:911 +#: 341ba310459442de906ec90ad72a16d9 msgid "" "``file_transfer_server_recv_client_start`` is used to initiate outgoing " "transfers from server to a connected client." @@ -1550,15 +1674,15 @@ msgstr "" "``file_transfer_server_recv_client_start`` " "は、サーバから接続されたクライアントへの送信転送を開始するために使用されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:835 -#: 408f93d233f44860a854950b3e60f8f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:913 +#: c5f727be6f954b9d87c3ebf0b8ae32ce msgid "" "The server sends transfer commands to the client socket and waits for the" " client to establish the file transfer connection." msgstr "サーバーは転送コマンドをクライアント ソケットに送信し、クライアントがファイル転送接続を確立するのを待ちます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:837 -#: 718dadb723164e65a2eb6fdcfb7d8420 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:915 +#: 88151618a44849269aea215557a4ca1c msgid "" "Folder transfers are performed recursively, with each file transfer " "respecting ``self.max_file_transfer_thread_num`` and the configured " @@ -1567,26 +1691,26 @@ msgstr "" "フォルダー転送は再帰的に実行され、各ファイル転送は ``self.max_file_transfer_thread_num`` " "と設定されたセマフォ制限に従って行われます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:840 -#: f23efbda41cb40289b93c954f6d051b0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:918 +#: 4734f1f535e7485ca5c91b06dec65f79 msgid "Common file transfer helper methods include:" msgstr "一般的なファイル転送ヘルパー メソッドには次のものがあります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 -#: b86c426b7c8a46b59735ef1a6a0da725 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:920 +#: aaa12a7a9d3f4adeb08d59d5fbc9d131 msgid "" "``file_transfer_server_recv_server_start``: receives file data from a " "client." msgstr "``file_transfer_server_recv_server_start``: クライアントからファイルデータを受け取ります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:843 -#: 74859cc9d4a745d99225f6522b4455c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:921 +#: 404a990c105247b09e2f2d1716527269 #, fuzzy msgid "``file_transfer_server_recv_client_start``: sends a file to a client." msgstr "``file_transfer_server_recv_client_start``: ファイルまたはフォルダをクライアントに送信します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:844 -#: 78042f93790547a8a844087d3daf81b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:922 +#: 0ec7dfbbfb1644f1ad5c42a1b2a04dc9 #, fuzzy msgid "" "``file_transfer_mode``: performs the low-level sender-side transfer " @@ -1594,28 +1718,28 @@ msgid "" "key to a client)." msgstr "``file_transfer_mode``: 低レベルのクライアント側転送ハンドシェイクを実行します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:846 -#: a03a3b41f63c4c7d8e6800e6e42c215f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:924 +#: 6056cfcc5fa740e58986f2e8ce900042 msgid "" "``file_transfer_mode_recv``: performs the low-level receive-side transfer" " handshake." msgstr "``file_transfer_mode_recv``: 低レベルの受信側転送ハンドシェイクを実行します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 -#: 82f418a15fbf4c009e188c0fe656a483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:929 +#: e0dc9b775fb94f0ab2728b56c57f88bd msgid "Port allocation API" msgstr "ポート割り当てAPI" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:853 -#: c041090f476c4f37a46fc7a3f49653cb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:931 +#: 9711bca31e6b464e940739ba262f5153 #, fuzzy msgid "" "The server allocation APIs allow you to allocate a new port for other " "servers. There are two kinds of port allocation modes." msgstr "サーバー割り当て API を使用すると、別のサーバーに新しいポートを割り当てることができます。ポート割り当てモードには 2 種類があります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:857 -#: 4fa11de65ebc4b51b83ea26802b43e3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:935 +#: 30e2a47526db46b29ef31b8730b5dd8a msgid "" "To change the port allocation mode, you can set the " "``is_hand_alloc_port`` argument on the server instance. When set to " @@ -1625,8 +1749,8 @@ msgstr "" "ポート割り当てモードを変更するには、サーバーインスタンスで ``is_hand_alloc_port`` 引数を設定します。 " "「False」に設定すると、サーバー インスタンスは自動ポート割り当てモードを選択し、「True」に設定すると手動割り当てモードを選択します。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:863 -#: aaa3428304234c0f81e2f83ab0481f17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 +#: 2a3a8472358240aea19de918a8d83602 #, fuzzy msgid "" "We strongly recommend using the automatic port allocation mode, which is " @@ -1638,8 +1762,8 @@ msgstr "" "自動ポート割り当てモードは手動ポート割り当てモードよりもシンプルで安定しているため、サーバーのデフォルト " "モードである自動ポート割り当てモードを使用することを最もお勧めします。このモードでは、割り当て API を呼び出すと、「0」が返されます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:870 -#: f9fbfedba34e4c3386442a9425b52a44 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 +#: 29df017de0bc4b399ebbe204db974707 msgid "" "*Note: The `bind` function in standard lib `socket` of the python " "executor, when input ``0`` to the port parameter, will automatically " @@ -1648,8 +1772,8 @@ msgstr "" "*注意: Python エグゼキュータの標準ライブラリ `socket` の `bind` 関数は、ポート パラメータに `0` " "を入力すると、オペレーティング システムによって利用可能なポートを自動的に割り当てます。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:875 -#: 4a1a578af0b14571a4180ebfc88073d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 +#: df4b1b82912e444c89fd2ea7adbec615 #, fuzzy msgid "" "The other port allocation mode is the manual port allocation mode, there " @@ -1660,8 +1784,8 @@ msgstr "" "もう 1 " "つのポート割り当てモードは手動ポート割り当てモードで、サーバーに対するポート割り当て範囲があります。既存のバージョンではポートの割り当て範囲が競合し、予期せぬエラーが発生する可能性があるため、同一ホスト内で他のサーバをオープンすることは避けてください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:882 -#: d9301928a8f643868d7cc5852f986e0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 +#: c835077f32f6478a8c0ad000340fd11f msgid "" "The range of the port allocation is configured in the server settings. " "The minimum allocatable port is ``self.port-" @@ -1672,8 +1796,8 @@ msgstr "" "self.port_add_step*self.port_range_num``、割り当て可能な最大ポートは " "``self.port+1+self.port_add_step*self.port_range_num`` です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:888 -#: 17b2666361504a0d8f5e10eb5fc9056a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 +#: 5ad5c89c89a141f2bb5c56e49b94bf1a msgid "" "*Note: The ``self.port`` is the ``port`` argument of the server class. " "The ``self.port_add_step`` is the ``port_add_step`` argument. And the " @@ -1683,13 +1807,13 @@ msgstr "" "``port_add_step`` 引数です。そして ``self.port_range_num`` は ``port_range_num`` " "引数です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:894 -#: fefbe2307beb49d083c05018a96a2f3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 +#: 8ea7c9e4e1ad46efb978d3d466a53db6 msgid "There are some relevant methods that can be used:" msgstr "使用できる関連する方法がいくつかあります。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 -#: 60738ce1224042aa9b39f5e5feec0e95 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 +#: f9525c162a254de4b11de650677ffd79 #, fuzzy msgid "" "The `palloc` method allows you to get a port. When using this function, " @@ -1703,8 +1827,8 @@ msgstr "" "`palloc` " "メソッドを使用すると、ポートを取得できます。この機能を使用する場合、このメソッドには割り当てモード検出機能がすでに実装されているため、ポートの割り当てモードを気にする必要はありません。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:919 -#: 54ccf91661524b1487fb666243fb627a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:997 +#: dee22bb387e140e9ae43d6ebc9afbd58 #, fuzzy msgid "" "The `pfree` method allows you to free a port. Like the `palloc` method, " @@ -1714,8 +1838,8 @@ msgstr "" "`pfree` メソッドを使用すると、`p​​alloc` " "メソッドと同様にポートを解放できます。このメソッドを使用するときにポート割り当てモードを気にする必要はありません。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:923 -#: f4a62c2b675845148f52b3437e9c151e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1001 +#: 6bd53cf6dcea462fbad9ca450e42eec4 msgid "" "And there are the main functions for you to call, and for more " "information about the port allocation functions, see the :ref:`tcp-" @@ -1724,8 +1848,8 @@ msgstr "" "呼び出すことができる主な関数もあります。ポート割り当て関数の詳細については、「tcp-server-port-allocation-" "api」セクションを参照してください。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:927 -#: 9aead9c3ede94037a42b4f83a45b3bb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1005 +#: d158c9d060c14aa39d042757684d6131 msgid "" "This mode is useful when you need an individual port for the server or " "must reserve a controlled range of ports for client-file transfers by " @@ -1736,251 +1860,291 @@ msgstr "" "プロセスが同じホストを共有する場合など、サーバーに個別のポートが必要な場合、または手動ポート割り当てによってクライアント " "ファイル転送用に制御された範囲のポートを予約する必要がある場合に便利です。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:934 -#: bad6d4dc4cdb4524b686b936a219637d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1012 +#: e51f806efbae4f9daf44365d182f21fa msgid "TCP Server APIs table" msgstr "TCP サーバー API テーブル" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:936 -#: 7d833bb126d34e528b706e8bf0e8a755 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1014 +#: c07f101dcc584239b2a4a7532c1ada42 msgid "In short, the table of contents of the public APIs are as follows:" msgstr "つまり、パブリック API の目次は次のとおりです。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:939 -#: 665b3f99a31a46a1af942df11ae56b08 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1017 +#: 66d85143ceff487f9620241fa1391d21 msgid "The server setup APIs:" msgstr "サーバーセットアップ API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:940 -#: fadd7d9d1d664608bca880a41e9ea51d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1018 +#: 904c44d78ca84c5cb7b595c6d360b2df msgid "`TCP_Server_Base`" msgstr "`TCP_サーバー_ベース`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 -#: 53e896a56ad44c29b03df161113e8d24 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1019 +#: 5da37cfc4922407dab0d65df73991067 msgid "`start_TCP_Server`" msgstr "`start_TCP_Server`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:942 -#: 80dc73e7ae064470b60bf81cf731b1a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1020 +#: 6e0f0866c62749239469bceea81ae727 msgid "`stop`" msgstr "「やめて」" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:944 -#: bad96f05bf9741c3a015b46ddb0c5485 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1022 +#: f84f11b7394147a9802c7de69d1d99e5 msgid "The server handling information APIs:" msgstr "サーバー処理情報 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:945 -#: c11c56f2f920425cb0f8a796ba8436ae +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1023 +#: 0ee5a3ad2c3643b9b85c813b5a5ba4be msgid "`handle_client`" msgstr "`ハンドル_クライアント`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:946 -#: 601d3f32dca44ce0aa8f90496fa82683 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1024 +#: 803b7f781de04d00ae128d89b0350cf5 msgid "`handle_command`" msgstr "`ハンドルコマンド`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:947 -#: a95b98f525c44f8e99aa1ce37d14521c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1025 +#: cb9095dd05b24093984b4609ee0bb8b6 msgid "`receive_message`" msgstr "`受信メッセージ`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 -#: b4d6756915c3424eac84ee276c68ec48 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1026 +#: c40a11b2d9b34f389fce8bc6d8076ab2 msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:949 -#: 5458006437d24bb68711e2523f7d7cba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1027 +#: 3c4a73128c044a38bac0b64d6551f512 msgid "`broadcast`" msgstr "「放送」" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:950 -#: e87f4ae0d0284a778641c6198ee918fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1028 +#: 16f4acaa490c4ec7afbd88fb3b50f62c msgid "`send_msg_to_specific_client`" msgstr "「特定のクライアントにメッセージを送信」" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:951 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1029 +#: 2ad09a3887894e01a67d31c28272f730 #, fuzzy msgid "" "`console_input` (only started when ``is_input_command_in_console`` is " "``True``)" msgstr "``is_input_command_in_console``: デフォルトは ``True``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1031 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 #, fuzzy msgid "" "2.1. The inbound event listener APIs (see :ref:`tcp-server-event-" "listener-api`):" msgstr "サーバー暗号化チャネル API (:ref:`tcp-server-encrypted-channel-api` を参照):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:954 -#: e0409b880c784bc4a8cb876315709114 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1032 +#: 6f0e5784864d4f62b0fd68d41a8105c4 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:955 -#: 2dea82fdc0a04600801da255ef214a2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1033 +#: 647c22de04784b0c97bbc829edf1e2b3 msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:956 -#: d90982abe8e24aefb021d1bdb6cb8ca8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1034 +#: 8fc8a08031dd48eba706b833414ef995 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:958 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1036 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 msgid "" "The server encrypted channel APIs (see :ref:`tcp-server-encrypted-" "channel-api`):" msgstr "サーバー暗号化チャネル API (:ref:`tcp-server-encrypted-channel-api` を参照):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:959 -#: 0164b9a39ec64638b0951431e562f5c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1037 +#: 67ad7bf1d5754801a36a114c86e650f9 msgid "`_crypto_on_client_hello`" msgstr "`_crypto_on_client_hello`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 -#: 35472e2955b24167aadb9aa8587b2674 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1038 +#: e2ec1fc9abbc4a1389e8df768c33e7c8 msgid "`_crypto_wait_server_ready`" msgstr "`_crypto_wait_server_ready`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:961 -#: 2e8d4e8d8741462e8e6a6b36b36e0c07 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1039 +#: e3987c4ee8ae4d79b0aafb035a806494 msgid "`_crypto_push_pub_to_client`" msgstr "`_crypto_push_pub_to_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:962 -#: b7eb540259ae4240ba76640b6afd72b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1040 +#: b1829201e7fe4428b9689b03e50374bf msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:964 -#: 9265fbd06c8a43fc972c1010a348684d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1042 +#: c875b30243a24ac4923a442613a677e0 msgid "The server command APIs:" msgstr "サーバーコマンド API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:965 -#: 6c53a87d79a749ffa1e2a93231037ac1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1043 +#: 5d011d31b13d446f814fd6bd5e63efce msgid "`register_command`" msgstr "`register_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 -#: 30a77ceac778437989abfaa0a23c1f4a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1044 +#: 2f117382a2154410989fb34342460f8b +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1045 +#: ffa5682de7884beb92ad1259ff1b8dd2 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:967 -#: 1940d4e8daf143e9ad1c971530233180 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1046 +#: cf39c195db7c41caa0f01bd982276547 msgid "`submit_task`" msgstr "`submit_task`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:968 -#: f2448f5089ba44458298a4194c2795f0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1047 +#: 85f02dafa5374a7b89e8bd8a65e54b19 msgid "`create_temporary_server`" msgstr "「一時サーバーの作成」" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:969 -#: 097562a3555e413385ee95ded3a46118 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1048 +#: 2f117382a2154410989fb34342460f8b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:971 -#: af034155f20a44b79b9c6ec49fc189aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1050 +#: 0131ddf38e824d959a1d61148155ae0d msgid "The server file transfer APIs:" msgstr "サーバー ファイル転送 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 -#: 9cbb9edbc9574de99f8168bf2df7df03 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1051 +#: 7483d578f02a4babb71dda0efb204b61 msgid "`file_transfer_server_recv_client_start`" msgstr "`file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:973 -#: fc70c45345764fb2aa8bc3d71f927248 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1052 +#: c2cf0a257e2543478df2dccdf52fdb00 msgid "`file_transfer_server_recv_client_start_thread`" msgstr "`file_transfer_server_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:974 -#: c1918a177fcf47cbb881d7e14300776d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1053 +#: 187f0ce4a65e41adb7ee99b021de4d2b msgid "`folder_file_transfer_server_recv_client_start`" msgstr "`folder_file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:975 -#: 6f61085c3cb24ae298dc0eadbe113f6c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1054 +#: be99cf24a4ae4f03b5472d8ee3412889 msgid "`multiple_file_multiple_client_transfer_server_recv_client_start`" msgstr "`multiple_file_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:976 -#: 46d60103b77c4de19be1ac4a12d4331b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1055 +#: ea76c872d16c4a709ec52ab7415e40a0 msgid "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" msgstr "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:978 -#: 565a0271f5ed4b679a742f7677ed9e63 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1056 +#: 6056cfcc5fa740e58986f2e8ce900042 +msgid "`file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1057 +#: 8df3552dd5ae41a4b3020c15ebe8509d +msgid "`forward_item_to` / `forward_message_to`: single forward destinations" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1059 +#: ad8e7d49e5294f5b976ae225ccb67d22 +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1060 +#: 92ba3cd2c6004b60abe5976efa845d76 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1061 +#: 8cee01b7bbd1439b81f24891d7149fa4 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1062 +#: f5615a6934a141c9aa2bb01bcab9aea0 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1063 +#: 187f0ce4a65e41adb7ee99b021de4d2b +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1065 +#: 944bb0f890764ad7a62584cc73782927 msgid "The server console commands:" msgstr "サーバーコンソールのコマンドは次のとおりです。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:979 -#: e79a38bbae1d44e5b9e7b3e939b42e14 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1066 +#: e85b5444c86048cfa691dc42bb7c9f88 msgid "`/stop`" msgstr "`/停止`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:980 -#: 98cb7e67ddc64c7e91c8f445d3d7b601 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1067 +#: 7250fb98f32f47d4b6204ceb5f93f550 msgid "`/status`" msgstr "`/ステータス`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:981 -#: ec1899e60fc1456ba2117f7b0bf676e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1068 +#: 48237f11d42c41e392b282787896bd00 msgid "`/clients`" msgstr "`/クライアント`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:982 -#: 0bb68238715a4e889bef60bf524c996a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1069 +#: 65fddabf6eec444fa89598e10a43f63f msgid "`/send_msg`" msgstr "`/send_msg`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:983 -#: 4c5dc721d573437385383ec46f76658a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1070 +#: c53a3810c2784772a6cb72f993ae8b4d msgid "`/file`" msgstr "`/ファイル`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:984 -#: 4fca7dce90044c119e5722297774fabe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1071 +#: 57d39ac1201f4866a57b5d291385d207 msgid "`/file_folder`" msgstr "`/ファイルフォルダー`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:985 -#: 29fe035c678b49ef80321587017ba483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1072 +#: 2cbc4a81ca0548d4aa183c2ad034ab6a msgid "`/multiple_file_multiple_client`" msgstr "`/multiple_file_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:986 -#: ba4e2c65e7034bd8a7a278697b76e8a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1073 +#: ce0f96a7a5e24b3cab89623df65ac40f msgid "`/diff_multiple_file_diff_multiple_client`" msgstr "`/diff_multiple_file_diff_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 -#: 97c3c838cb784a729fc52242a89f7156 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1074 +#: a9bffb7745c94e7cb45f4fc030c00da3 msgid "`/help`" msgstr "`/ヘルプ`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:990 -#: 0b5cb5ab31e648b99f176a269cbad11e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1077 +#: 2d084d51c4c44ebda431944babb6c256 msgid "See Also" msgstr "関連項目" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:992 -#: d85e9537bf8e453ea2d533f25e659d2a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1079 +#: aa497d5f407a4e439cd10a4de1e24b05 msgid ":doc:`TCP_Client_APIs` — TCP client." msgstr ":doc:`TCP_Client_APIs` — TCP クライアント。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:993 -#: 1893e2b71add4e0ba8840ea169e0b102 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1080 +#: e1e5363e891e4e68855f9b021bbd4abf msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP エンドポイント。" @@ -2217,3 +2381,52 @@ msgstr ":doc:`UDP_APIs` — UDP エンドポイント。" #~ " ... ...``: " #~ "異なるファイルリストを異なるクライアントに送信します。" +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "ハンドシェイクではランダムなセッション nonce " +#~ "が交換され、回線上のすべての暗号化された回線には、それに加えて接続ごとのシーケンス番号 ``||`` が付けられます。受信者は、ノンスが現在のセッションと一致しない行 " +#~ "(古い接続から再生された暗号文)、またはシーケンス番号が予期したものではない行 (セッション内で再生された暗号文 /" +#~ " 順序が乱れている) をドロップします。 (再) " +#~ "交換後にソケットが暗号化モードに切り替わると、両方のカウンタがリセットされます。" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(client_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to the " +#~ "command handlers instead). ``add_file_listener`` " +#~ "registers ``listener(client_id, full_path, name, " +#~ "size, command)`` and fires after a " +#~ "file uploaded by a client has been" +#~ " fully written to the transfer " +#~ "directory (``command`` is the wire " +#~ "command that triggered it, so protocol" +#~ " pushes such as ``/crypto_pub_key`` can " +#~ "be recognised). Both listeners run on" +#~ " a protocol thread, so they must " +#~ "not block, and an exception inside " +#~ "a listener is logged and swallowed. " +#~ "The ``remove_*`` counterparts unregister a " +#~ "listener and ignore unknown ones." +#~ msgstr "" + +#~ msgid "" +#~ "``/forward_item``, ``/forward_send_msg``, " +#~ "``/pause_trans``, ``/start_trans``: internal " +#~ "forwarding/transfer-control messages." +#~ msgstr "" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po index 540b8b7..d0b5ae2 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po @@ -6,24 +6,85 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-16 11:10+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.18.0\n" -#: ../../api/PyFlow.command_control_extension_tcp.rst:2 +#: ../../source/api/PyFlow.command_control_extension_tcp.rst:2 #: a6084f2941f34f579f28c55e9dfb768d msgid "PyFlow.command\\_control\\_extension\\_tcp module" msgstr "PyFlow.command \\_ control \\_ extension \\_ tcpモジュール" +#: 9209095513ec402980427a0ddd988219 PyFlow.command_control_extension_tcp:1 of +#, fuzzy +msgid "Command-control extension for the TCP protocol." +msgstr "PyFlow.command \\_ control \\_ extension \\_ tcpモジュール" + +#: 47d5c98c564241a6911eff0abea987ec PyFlow.command_control_extension_tcp:3 of +msgid "" +"One command batch, run by every listed client, with each client's output " +"collected on the server:" +msgstr "" + +#: PyFlow.command_control_extension_tcp:6 b14c7eec72b44dc1bd343997acf1cf44 of +msgid "/command ... ... " +msgstr "" + +#: PyFlow.command_control_extension_tcp:7 fe2fb5a737534088b175ea340c1763f9 of +msgid "" +"typed on the server console. Every client runs the whole command list in " +"a single shell session, in order, so state such as a changed working " +"directory carries over from one command to the next: ``/command \"cd " +"/path/to/search\" \"ls ./\" \"(ip, port)\"`` lists the files of " +"``/path/to/search``, while sending ``cd`` and ``ls`` as two separate " +"``/command`` lines does not." +msgstr "" + +#: 29a70dd76bf34e90a9ea54ac27202289 PyFlow.command_control_extension_tcp:14 of +msgid "" +"Commands come first and client addresses last; every address is written " +"as a Python address tuple, e.g. ``\"('127.0.0.1', 3000)\"``. There is no " +"limit on the number of commands or on the number of clients, and every " +"listed client receives the same command list. Two internal commands carry" +" the log back:" +msgstr "" + +#: 9ef58aea395a436382e23f39797e3e8e PyFlow.command_control_extension_tcp:19 of +msgid "/command_log_chunk " +msgstr "" + +#: 3361f3fb70584140989542af7c3361a7 PyFlow.command_control_extension_tcp:20 of +msgid "" +"sent by the client after it uploaded one log chunk through the file " +"transfer channel; the server appends the chunk's entries to that client's" +" log file" +msgstr "" + +#: 2563d4e4d9744c2fb16d84690c2e94e2 PyFlow.command_control_extension_tcp:24 of +msgid "" +"sent by the client when the batch is over; the server merges every " +"collected log file into ``merged_logs.json``" +msgstr "" + +#: PyFlow.command_control_extension_tcp:27 e40a302503cb4bdda5420aa79d0c57eb of +msgid "" +"A client captures the output of the running commands and uploads a chunk " +"every ``_LOG_CHUNK_BYTES`` of captured output (a smaller final chunk " +"closes each command), so a command that never stops is still tracked in " +"real time. Every chunk is appended to the same log file - " +"``logs__.json`` in the server's ``logs`` directory - which is " +"therefore never re-sent and never rewritten, only extended." +msgstr "" + #: 9209095513ec402980427a0ddd988219 #: PyFlow.command_control_extension_tcp.setup_server_commands:1 of msgid "Register the control-extension commands on a server instance." @@ -33,3 +94,4 @@ msgstr "サーバーインスタンスにcontrol - extensionコマンドを登 #: PyFlow.command_control_extension_tcp.setup_client_commands:1 of msgid "Register the control-extension commands on a client instance." msgstr "クライアントインスタンスにcontrol - extensionコマンドを登録します。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po index dba6d8e..ef95d60 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ja\n" @@ -20,17 +20,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.connect_tcp.rst:2 -#: 59f41330dfa54a88831a20f4dc97c0f6 +#: 1e4cd09ce3ef45ceb95b8eb81eb7493b msgid "PyFlow.network\\_api.connect\\_tcp module" msgstr "PyFlow.network \\_api.connect \\_ tcpモジュール" -#: PyFlow.network_api.connect_tcp:1 dca225f091cb4dd1810a8bd04c3a5004 of +#: 25b88cdb337c44539a843c674ba6825b PyFlow.network_api.connect_tcp:1 of msgid "" "TCP transport for PyFlow: the server and client base classes and the wire" " parsers." msgstr "PyFlowのTCPトランスポート:サーバーとクライアントのベースクラス、および配線パーサー。" -#: PyFlow.network_api.connect_tcp:3 d5888d829f2e4850926eb364ede4678e of +#: 1f1482fc5c2849a68f34c74a8b55ab79 PyFlow.network_api.connect_tcp:3 of msgid "" "``TCP_Server_Base`` accepts connections and dispatches inbound lines; " "``TCP_Client_Base`` connects, sends and reads on the same conventions:" @@ -38,36 +38,55 @@ msgstr "" "'' TCP_Server_Base ''は、接続を受け入れ、インバウンドラインをディスパッチします。'' TCP_Client_Base " "''は、同じ規則で接続、送信、読み取りを行います。" -#: PyFlow.network_api.connect_tcp:6 bd065af9d94b44298f9716ca96809b8c of +#: 104e5170c1c34bf9ad719f896e0c4226 PyFlow.network_api.connect_tcp:6 of msgid "" -"one message per line, terminated by a newline; a line that starts with " -"``/`` is a command and goes to the command handlers, anything else is a " -"plain message reported to the registered message listeners;" -msgstr "行ごとに1つのメッセージが改行で終了します。''/''で始まる行はコマンドであり、コマンドハンドラに行き、それ以外は登録されたメッセージリスナーに報告されたプレーンメッセージです。" +"one message per line, terminated by a newline; every inbound line is " +"reported to the registered message listeners (commands included), and a " +"line that starts with ``/`` is then dispatched to the command handlers, " +"anything else treated as a plain message;" +msgstr "" -#: 91ea1db95e554f2fbd2c1e92eb2d1353 PyFlow.network_api.connect_tcp:9 of +#: 6c6c01958e5741e080edcb804b4d12d1 PyFlow.network_api.connect_tcp:10 of msgid "" -"an RSA-encrypted channel is negotiated right after connect unless " -"``is_enable_encrypto`` is False;" -msgstr "'' is_enable_encrypto ''がFalseでない限り、RSA暗号化チャネルは接続直後にネゴシエートされます。" +"unless ``is_enable_encrypto`` is False, an encrypted channel is " +"negotiated right after connect: the handshake lines and the public-key " +"pushes stay plaintext, then every later message travels as a frame (RSA-" +"OAEP for small text payloads, an ECDH-keyed AES-GCM seal for everything " +"else, including file data), and each file/folder transfer sub-connection " +"is framed the same way once both sides hold the session keys (see " +"`_SecureChannel`);" +msgstr "" -#: PyFlow.network_api.connect_tcp:11 dfcece05b6774c5496b99d6c08039fce of +#: 9702905f1f8a4750905b2ffb96f99ec8 PyFlow.network_api.connect_tcp:16 of +#, fuzzy msgid "" "file/folder transfer, message forwarding and port allocation are layered " -"on the same socket and share its command namespace." +"on the same socket and share its command namespace;" msgstr "ファイル/フォルダ転送、メッセージ転送、およびポート割り当ては、同じソケット上に重ねられ、そのコマンド名前空間を共有します。" -#: 89db462eaa88489c9390ddfa67a77a73 PyFlow.network_api.connect_tcp:14 of +#: 3488995e2a8349a58393d9f2d1155b99 PyFlow.network_api.connect_tcp:18 of +msgid "" +"an interrupted transfer is resumed after a disconnect: both sides persist" +" their transfer stores under the protocol's ``.Flow`` directory and the " +"receiver asks the sender to continue the file from the bytes already on " +"disk (``resume_transfers``; the wire lines are ``/resume_trans`` and " +"``/forward_resume``)." +msgstr "" + +#: 4cc5743bdfe54148ad38f54f10e688c9 PyFlow.network_api.connect_tcp:24 of +#, fuzzy msgid "" "The forwarding extensions use the module-level parsers " "`parse_forwarded_message`, `parse_forward_items_and_addrs`, " -"`parse_forward_originator` and `forward_skip_message`." +"`parse_forward_originator` and `forward_skip_message`; the reconnect " +"logic uses `parse_resume_command`, `parse_forward_resume_command` and " +"`_resume_offset_for`." msgstr "" "転送拡張機能は、モジュールレベルのパーサー`parse_forwarded_message '、` " "parse_forward_items_and_addrs '、`parse_forward_originator '、および` " "forward_skip_message `を使用します。" -#: 98c270e82fa8468487e1b4d25bab8c0c PyFlow.network_api.connect_tcp:18 of +#: 49796529cb7f49ee8131b257212b5420 PyFlow.network_api.connect_tcp:30 of msgid "" "Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and " "``TCP_Client_APIs.rst``; argument, return and exception contracts live in" @@ -76,64 +95,66 @@ msgstr "" "コンセプトは'' docs/source/NETWORK_APIs/TCP_Server_APIs.rst ''および'' " "TCP_Client_APIs.rst ''にあります。引数、戻り値、例外の契約は以下のdocstringにあります。" -#: 76126c02e928423b89dc4662d9a190f2 +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_resume_command:1 of +msgid "Split a ``/resume_trans `` line." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 14dcda8b059b480982e3fb03399e665b 99035a24f6e94207b84545f8c71a451e +#: cb62202c244d4c08974c674c13a02dca +msgid "Returns" +msgstr "返品" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_resume_command:3 of +#, fuzzy +msgid "``(fid, offset)``, or None when the line is malformed." +msgstr "送信者の''\" ip: port \"''、または行が整形式のエンベロープでない場合はNone。" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 19eb6fca79324b0791f8ec7488a5246c +msgid "Return type" +msgstr "戻り値" + +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:1 of +msgid "Split a ``/forward_resume `` line." +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:3 of +msgid "``(target, fid, offset)``, or None when the line is malformed." +msgstr "" + +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:5 of +msgid "``(target, fid, offset)``, or None when the line is" +msgstr "" + +#: 4ead8d8f93644adeb812150e760f7792 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:6 of +msgid "malformed." +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 #: PyFlow.network_api.connect_tcp.parse_forwarded_message:1 of msgid "Split a ``/send_msg_from `` relay envelope." msgstr "''/ send_msg_from ''リレーエンベロープを分割します。" #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0e9ae2e0bd0c44da835c0999abec5f08 1aaf58afc7f043919f411c02d435031d -#: 1c819a8207464e439fd4675d1b823409 1d2cff780d6642deb6ab5fbf32c34185 -#: 1e24bfa274504842b67c3cb0c7a37118 26160724c12740ecbe3cc707bc46c197 -#: 2edb81613e9c4bd0949f5d6efa1a542f 30a7ccf5e56e4640a7a6e592d13a4f7c -#: 3514f6292626456eb4b0c31a30e24cf5 38d82b9bc4414212a8458de940d3b69b -#: 406f1bd372c14cd897f0d2dc1fdc8fd7 4400798a6d9d41a89b686b015f53a454 -#: 54f261fe47134a9494f12b5053492006 5e9d8d1799714d389a6fd79edd0e5bac -#: 6239fd721a0f476aaf509ab580317c75 6658645eabff4ba6b0b326727f89a4f1 -#: 6f375e9a65e04034a4fd1475f3073e42 70b19bc5e5da467dbbae99d81fe54ed7 -#: 79e2d4be536b429cbbfe5016df915b72 7c3cf59acfe34a15a6c920a0f58ec56f -#: 822df543855349c2993aabd5596b5383 8245849b603f4313a3ea2423abd5c899 -#: 83eba13f6fae4ded929924151baa0c52 9449c184a2e145909d2e1f114534253d -#: 9a393c8c90d0446a97c34af1c173f83d 9cdc7d0b4bc2400498e9c57ed16ba459 -#: a2ddcff09d1641b5b269ec31031008f9 a5cbf7c6c5b0494b8652be7d28a7b3d1 -#: a9ec9ede7c8144ddb920261d29edc23d b5b42f99934e4b0b939671c6fb08f748 -#: b630deb98dea40c28f1cb88dcbfdb261 b6e3a01b0f044a15a7d322c63f58c262 -#: bb3b7e5558c74c8eb287944b93b9c664 bd95cc8d5960426e92ad149ce0ecaeb4 -#: be47c4f21d4d4515be0684c6c1215c0c cdebf66a7b714ef39236c1dc9773c8f7 -#: d02c1be3236b424f87b75728f76d672c d5b3f5bf790c4fc6aefb763d9c473474 -#: da6cef9244b1429881584994b097c71a e98998d054b74d0e820367ea5de54d02 -#: ea4e1b708c2f409f89bf4ca2a6e4fbf3 ebca3c62590345118f3fe5a8d85ce154 -#: ebcdb45484b64f7f9023808632316025 efca1ecd18f440db9489b40ae6480409 -#: f7766cda09fd4c0bb6b565f5fa4a3688 fe80dd07199943c784dd488826f958b7 +#: 4fa9ba6e763440b8ab00832520b4d305 501a0caef71d436e84469bc1ef9c1e5f +#: 70d6dae11a144ed7b7e9d8e16dbf478c acdf8b3b266f4eccb6ceca17a110603b msgid "Parameters" msgstr "パラメーター" -#: 35b277cd5b2249dc8b38c36654b1f75a -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 +#: e42a6166c82d4861b25cb55f587db28c of msgid "Received line, e.g. ``/send_msg_from ('127.0.0.1', 3000) hello``." msgstr "''/ send_msg_from (' 127.0.0.1 ', 3000) hello ''などの行を受信しました。" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0cd9914c895f4b308548863df6d8c13c 113c57937f6f402da7758e74266680ea -#: 139720899e024d348d0b43b9af2b2ef7 2cb731c57fb64497a6424e4e51fe17bb -#: 30c59afde30c44428a97266ca87baa21 3f574beaf02948d599ffd8c50922e530 -#: 40e4cbf377a94cf8803c13b2f01dbc77 4aa76ebde46243b18f2a5d811d902d1e -#: 4d5706674a0c40a99769b5cfba21b29d 5518a67cc7364710b2b0c03f6de9de1b -#: 564a8841a88d40e0a44b1b0d72a0b3a4 56e96f344ac14995adeb056f90d3e39a -#: 638d047aee4d45a689f4a54f8d2be451 6e5db10681f24a01a208604d8de1ecf4 -#: 6ea11f9fd50e46f8aef42a25872d8d47 833d97bdb57049979db335d24819041a -#: a00fef59262447aa931fe606e260a7ab a9795b94ba634cb8a7dc1fd6a7e6f326 -#: b1a77959b26540128ea564370170744f b1e2a43372ac48fe9a367121a736eaee -#: b2f18766a5ec40d69bfd15b13fa54aa2 b963bb66a63649d5b5cc0ce3d852aab4 -#: c1bd9b5e40e644e3a1f1198e5d2247c2 d558170070474bcb9d798b72d878f185 -#: d86bf79c265c42ec969d2c8058f20a3c d906d179eca24642883fb6ff991399b8 -#: ddfeae931eb14b529e08b61ae9de5aaf ecb12ada91914625a7c5e9894b67886f -#: f8e1381487764684b80cbc9d8f6a511c fa2587a106c540d1a870afc4a3ae97b7 -msgid "Returns" -msgstr "返品" - -#: 24de94d25531410aa507869ac615529b -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 +#: f25d1962656c4f339805427e2573f84f of msgid "" "``(sender_id, payload)`` where ``sender_id`` is the sender's " "``\"ip:port\"``, or None when the line is not a well-formed envelope." @@ -142,43 +163,24 @@ msgstr "" "\"''であり、行が整形式のエンベロープでない場合はNoneです。" #: PyFlow.network_api.connect_tcp.parse_forwarded_message:9 -#: f4818c7037924b089072be17dbe65cda of +#: d0d7af37e4134902ae64e10b2e43b4c1 of msgid "``(sender_id, payload)`` where ``sender_id`` is the" msgstr "''( sender_id, payload )''ここで'' sender_id ''は" -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 -#: e4ce35611cb240c382217f2166803af1 of +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 of msgid "" "sender's ``\"ip:port\"``, or None when the line is not a well-formed " "envelope." msgstr "送信者の''\" ip: port \"''、または行が整形式のエンベロープでない場合はNone。" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f2c39309f3e47aa9157bf244f35d1e6 126027ff5c8b494e8223688394767c35 -#: 15e8f6af90d84f4c99e9a9706f995a3f 18eed5a02c0346f6966237e6812afce0 -#: 208eff4f470f474395ac42a58f179feb 308f9ffcdfe2443cb6fe0f3a79e7d4b3 -#: 30fd0d7f7d9547149d06568b9ae4b217 34500bb5a5ea4428ba3ba1f34f8555f3 -#: 357fa966af0e4661a01d3a18b3686c63 38f178d3602f47bcbf100a047fc22ccc -#: 4268152920654e59975b69aed4638761 43cc49d0a3b2478f8a24fcdea7c2ce78 -#: 448b06753df84443af4aae1dcb008d56 4530cc6fc87d4dbcb79dd0e90ea83694 -#: 496c6102672e49fc96cd7210ed1ec602 502647c8224842608ded5058bf1c6748 -#: 574093f9f9054b898b9ab8b20a239a40 5882a32ac8a34ab7b568b256092e1aca -#: 73e564d3b91d42388f95effb067d6218 7f2f462183d442c98c624d6750d86319 -#: 8203a323a9af48edb0f9e91ca6260ed6 87a376020e0a47fb90cc4f2d9b045d7c -#: 8f12aa18be1a4aaf97b8db14f282a929 a61c3c1917b8486bad659991683c48cb -#: a9e445f3a3094e3bb7957551bcf7fd21 c0afcff99bfc47f3ba7a3f0b3e836444 -#: c4d251b617f2419cb1093f6896b14cb8 d4bc332ce5f34c61b3105fb392b302e5 -#: e9a98b5852d84cf4939d9ea0f17b038c f17ca1aa780b447cb305e1db1c181efb -msgid "Return type" -msgstr "戻り値" - -#: 1ad7def88bd34ce7accca28c4d123b79 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 +#: f22254d8ca2d47ad8bc9c98664369d61 of msgid "Split forward-command tokens into items and destination addresses." msgstr "転送コマンドトークンをアイテムと宛先アドレスに分割します。" -#: 67578e526f0b4dfc924c46a44e7bea78 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 +#: b207f60051004834bab91ba392a88437 of msgid "" "A token of the form ``('ip', port)`` is a destination, everything else is" " a forwarded item (message text or a path). Used by the native message " @@ -189,12 +191,12 @@ msgstr "" ")''形式のトークンは宛先であり、それ以外はすべて転送されたアイテム(メッセージテキストまたはパス)です。ネイティブメッセージ転送(''/ " "forward_send_msg '')およびファイル/フォルダ転送拡張子で使用されます。" -#: 18a87e9cbc124ce5a6f91d61a72fc6de +#: 5329fb72f5954768a6cec05ff4cccfea #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:7 of msgid "Tokens after the command name." msgstr "コマンド名の後のトークン。" -#: 0e46577c966b41c4ad6f0aea95fd7e5c +#: 2aebf669048046ddb279a935bcfcfde4 #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:10 of msgid "" "``(items, addrs)`` in the order given; ``items`` holds texts and " @@ -203,38 +205,38 @@ msgstr "" "''( items, addrs )''は指定された順序で、'' items ''はテキストとパスを保持し、'' addrs ''は''( ip," " port )''タプルを保持します。" -#: 608bcdb865a94f869885cd560de7012e +#: 96b96bd19fe94312bddf340fad073cbc #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:12 of msgid "``(items, addrs)`` in the order given; ``items`` holds texts and" msgstr "指定された順序で''( items, addrs )''、'' items ''はテキストを保持し、" -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 -#: e8c390dc356e4be9bb2f52cd0540e859 of +#: 8e82954621d748e2b412952a7fb2753b +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 of msgid "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "パス、'' addrs ''は''( ip, port )''タプルを保持します。" -#: 0e422066050d4ba18799efa53c6b771e -#: PyFlow.network_api.connect_tcp.forward_skip_message:1 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:1 +#: a51324658c7943158d90ed706cecc41d of msgid "Build the console notice for a forward destination that cannot be served." msgstr "配信できない転送先のコンソール通知を作成します。" -#: 1eb2f924bcbc4e3783e3a4706c93052f -#: PyFlow.network_api.connect_tcp.forward_skip_message:3 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:3 +#: b541e8446e374bc8b38cd7912a1fa33c of msgid "Destination ``(ip, port)`` that is unreachable or is the server itself." msgstr "到達不能であるか、サーバー自体である宛先''( ip, port )''。" -#: PyFlow.network_api.connect_tcp.forward_skip_message:7 -#: b7ceaa070f754fe88242c2b495b3ff9f of +#: 10e03f21d05e478d9cde0c7176f6e1b8 +#: PyFlow.network_api.connect_tcp.forward_skip_message:7 of msgid "One-line notice for the console." msgstr "コンソールの1行通知。" -#: 59d83fde0d964794ba76d45749bfc021 +#: 8005e532fe9d491ca8ddd996889d605d #: PyFlow.network_api.connect_tcp.parse_forward_originator:1 of msgid "Extract the originator's ``\"ip:port\"`` from a received transfer command." msgstr "受信した転送コマンドから発信者の''\" ip: port \"''を抽出します。" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 -#: b91ee97cb2574a19b8c87c99bf8ca181 of +#: 2cf3052a89c645e782430f1f05fb37a1 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 of msgid "" "The server's forward relay tags every pushed ``/file`` and " "``/file_folder`` command with the forwarding client's address tuple; a " @@ -243,50 +245,63 @@ msgstr "" "サーバーのフォワードリレーは、フォワーディングクライアントのアドレスタプルを使用して、プッシュされたすべての''/ file ''および''/ " "file_folder ''コマンドにタグを付けます。ダイレクト送信は、代わりに受信者自身のアドレスを伝送します。" -#: 20da4b9824cd4fd6bb0ef55ebc38158b +#: 335f6c1b16104395ba38a33188943d8a #: PyFlow.network_api.connect_tcp.parse_forward_originator:7 of msgid "Received transfer command." msgstr "転送コマンドを受信しました。" -#: 9f25fa22a7b14822b8cbc1fd929976b9 -#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 of +#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 +#: e5bd1024ad3f47f19cafc4c83a844b60 of msgid "" "This instance's own ``\"ip:port\"``; a command carrying it is a direct " "send and yields None." msgstr "このインスタンス自身の''\" ip: port \"'';それを運ぶコマンドは直接送信であり、Noneを返します。" -#: 6455c3bb288d4239811cb0104086c0fa +#: 65469492f844448fab269b701cbdb704 #: PyFlow.network_api.connect_tcp.parse_forward_originator:13 of msgid "" "Originator ``\"ip:port\"``, or None when the command carries no " "originator (direct send or non-transfer command)." msgstr "オリジネータ''\" ip: port \"''、またはコマンドがオリジネータを持たない場合はなし(直接送信または非転送コマンド)。" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 -#: a466d04757ec40f1a2888518b8fb1d9a of +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 of msgid "Originator ``\"ip:port\"``, or None when the command carries no" msgstr "オリジネーター''\" ip: port \"''、またはコマンドがない場合はなし" #: PyFlow.network_api.connect_tcp.parse_forward_originator:16 -#: da8c46fb38624c7d97d91970aee4667c of +#: a2d34276c4f54c69981f9b51f36cc31d of msgid "originator (direct send or non-transfer command)." msgstr "発信者(直接送信または非転送コマンド)。" -#: 201f6bd5376a4ebaa7488dd3b58197c0 +#: 31646cd2d4f049a38b7910ac6836d2f9 +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:1 of +msgid "A command passed to `call_extension_functions` is not registered." +msgstr "" + +#: 42bee6e5f57b43cba7c5b4c4a1769e9a +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:3 of +msgid "" +"Raised when the first token of the command matches no handler registered " +"with `register_command`, on either instance class." +msgstr "" + +#: 7297b41c47664243b9677b32e21de07e #: PyFlow.network_api.connect_tcp.TCP_Server_Base:1 of msgid "TCP server: accept clients, dispatch commands, relay messages and files." msgstr "TCPサーバー:クライアント、ディスパッチコマンド、リレーメッセージ、ファイルを受け入れます。" -#: 4f7013d76f9d447b974f22cca228ba0f +#: 0d632c9f5b234888a691b03ade8ff7da #: PyFlow.network_api.connect_tcp.TCP_Server_Base:3 of +#, fuzzy msgid "" "Each accepted connection is served by `handle_client`, either in its own " "thread (the default) or by a coroutine on an asyncio event loop when " -"``is_asynic_clients_io`` is True: a line starting with ``/`` goes to " -"`handle_command` (built-in commands plus the handlers registered with " -"`register_command`), any other line is a plain message delivered to the " -"listeners registered with `add_message_listener` and stored in " -"``messages_dict``." +"``is_asynic_clients_io`` is True: every inbound line is delivered to the " +"listeners registered with `add_message_listener` first; a line starting " +"with ``/`` then goes to `handle_command` (built-in commands plus the " +"handlers registered with `register_command`), any other line is a plain " +"message stored in ``messages_dict``." msgstr "" "受け入れられた各接続は、独自のスレッド(デフォルト)または'' is_asynic_clients_io " "''がTrueの場合のasyncioイベントループ上のコルーチンのいずれかで'handle_client`によって提供されます。''/'で始まる行は`handle_command" @@ -294,44 +309,38 @@ msgstr "" "add_message_listener 'で登録され、'' messages_dict " "''に格納されたリスナーに配信されるプレーンメッセージです。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 -#: fd2aa2103a434e7b84e9f5300dfb2637 of +#: 2870b0163d68487daf7526e91eb49ff6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 of msgid "Address the server socket binds to." msgstr "サーバーソケットがバインドするアドレス。" -#: 0887ce96e330478f83984d935911cd2b 13fa6bd77a314fcbae42aeef584d47b6 -#: 1d012f62b99a4b0d8802295d814667dd 1d5b594e02824d74b812b69dc7b34a88 -#: 3b8af6dc474d493eb9749cb07384c5d1 4916b5bac8044e249473dae03d0af5e5 -#: 6a138e9d5ed24b6b9a9f213ffa6d07bb 7c114dabd42344d790a98003f7d68a6a -#: 889f9fb97d4b483cbfd9ae6bbb3e1dbb 89e6193e8e8c45f3ba6d49b9ec578812 #: PyFlow.network_api.connect_tcp.TCP_Client_Base #: PyFlow.network_api.connect_tcp.TCP_Server_Base -#: a0a81405abb64b70834a292dfa52ea47 a32afd5e800648f08c2ed1582462900f -#: a4c849cfce9b4544a50162a1abd07ffc e953785e3c774cb783e506a118b6f5f9 -#: efd7bf86f2f3403a843bdc7079ed87ae f87fe645a0c846168779119b106eb83b of +#: cf754e752b6c445989b3301b807fc9eb of msgid "type" msgstr "種別" -#: 194d7e538b9142bb9cadf40639c7dfc2 8d779f308c7343fca45fb6b7c544b6f8 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: 568be916ae0340289a6569e718e7cbf2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:16 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:106 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:15 -#: a043713065174240b3b3cb2839829b42 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:100 of msgid "str" msgstr "筋力" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 -#: eaf91e01d29744a4b66b30d163b14bd4 of +#: 6ac74cca7b0f443ca89f3d2c3bbe1aaa +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 of msgid "First port considered for binding and for allocation." msgstr "バインドと割り当てのために考慮される最初のポート。" -#: 143512a7a9624b79853380f79b9db5e0 6093b43271e041dfb256e660e61561c5 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 +#: 9ecf88c5193c470b98dc95d184c94f92 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:22 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:21 of msgid "int" msgstr "int" -#: 0f4f0acdd1a64e9cb4eb06b5fc12103e +#: 6746407aac194c4880c7cbf82b7fa2fb #: PyFlow.network_api.connect_tcp.TCP_Server_Base:25 of msgid "" "Accepted connections keyed by ``(ip, port)``; each value holds " @@ -340,76 +349,145 @@ msgstr "" "''( ip, port )''でキー化された受け入れられた接続。各値は'' socket ''、'' address ''、'' id " "''および'' connected_time ''を保持します。" -#: 6fcc166b59cb4ae7a6a6e30f2dbd2784 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 of +#: 7ba2aaf3fe4c42739121eb3ca2bcc79a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:89 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:98 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:92 of msgid "dict" msgstr "dict" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 -#: d85332af5e73403388989eacf82a251d of +#: 93556efee2aa445684af3fdc1532548a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 of msgid "True while the accept loop runs." msgstr "ACCEPTループが実行されている間はtrueです。" -#: 0effb5fc02cf402ab9d27f4a51954fd1 168f4d3c8da74ebab98953585b27b866 -#: 21bd44747d4e4c9aa4a0afa0f559707d 3c8b6ad08eac44ba9eacbb2fb9752304 -#: 420ec28762864e58ad5f3a63f2811a0f 87eb97e54ef847398f653aa5b65b0191 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: 0ab0667a38254203929e173ab5024f1d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:40 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:46 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:52 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:58 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:65 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:72 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:79 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:34 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:41 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:47 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:53 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:59 -#: e1e2580e801a44cc962b509779f690fc f827c454ead24d7587ae4125b1f60fda -#: f8f0e0ce3c4841278a15e583a0ec5f92 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:66 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:73 of msgid "bool" msgstr "ブール型" -#: 62103bebe6fe47aa8a3830133baa0a70 +#: 9023ee78c5fe4680a3875c881abe3307 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:38 of msgid "" "Whether clients are served by coroutines on an event loop instead of one " "thread per client." msgstr "クライアントがクライアントごとに1つのスレッドではなく、イベントループ上のコルーチンによって提供されるかどうか。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:42 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 -#: c291fba3b400472996751ffdc24251b7 d0ade3e16cf044fca75a0e1bdf17038c of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 of msgid "Whether the RSA channel is negotiated." msgstr "RSAチャネルがネゴシエートされているかどうか。" -#: 8bb4af4279e44eef8df452f4429780ff -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:48 +#: 3c5a67d3c5824c15b42b71fbadddf5d3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:51 -#: c9414c44325b4b5eaed34bf2a7e49ed4 of +#: a5ac1b25d44547ba836c5dc354438315 of msgid "Whether execution-process lines are logged as well." msgstr "実行プロセス行もログに記録されているかどうか。" -#: 5bdaf96cd6894bc4a179ae3ddc66c29c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:54 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 -#: a50b56a084674a89bb56dd9791348a75 of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 of msgid "Whether the instance logs anything at all." msgstr "インスタンスが何かをログに記録するかどうか。" -#: 75856a665d5045349622c29bee22fe17 +#: 3114d37d38af4cfcaa75397192202b93 62437fad8325442b91f177e93b8be7ef +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:62 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:63 of +msgid "" +"Whether every running file transfer is tracked in " +"``file_recv_progress``/``file_upload_progress``." +msgstr "" + +#: 58bd8f0892f044a583a276490dc2a7f5 855f8e2ee2a449398779d56b269628d6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:70 of +msgid "" +"Whether the real-time network speed is measured into " +"``upload_network_speed``/``recv_network_speed``." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:77 +#: afff1dd047f4479b84d46859c7da90b8 ce793576b862473cb130a29582aab5fd of +msgid "" +"Running downloads keyed by fid; each value is ``[received bytes, total " +"bytes, current speed, file path, peer]`` (the speed is None until the " +"transfer has moved its first chunk, and while speed measurement is off; " +"``peer`` is the sender's ``(ip, port)``)." +msgstr "" + +#: 36c2c0e7900d436a977b8895e671c9f0 659caaa0c8bc40d3a9ce8d0905787584 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:93 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:87 of +msgid "" +"Running uploads keyed by fid; each value is ``[sent bytes, total bytes, " +"current speed, file path, peer]``, with ``peer`` the receiver's ``(ip, " +"port)``. A forwarded transfer stores the original peer on both sides, " +"never the relay." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:96 +#: f9528e6c490d4807b949f6730c6ece8e of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when a connection drops and read back on the next reconnect " +"(``resume_transfers``)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:110 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:104 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second sent, or None when not measured." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:113 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:120 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:107 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:114 +#: d926b4f3eb4b40a4acb21f780a4dc227 of +#, fuzzy +msgid "float | None" +msgstr "int |なし" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:117 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:111 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second received, or None when not measured." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:1 of msgid "Create the server and, unless extended, start accepting clients." msgstr "サーバーを作成し、拡張されていない限り、クライアントの受け入れを開始します。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:3 -#: a2cce435d92d46e5b0b2cd59d43c8759 of +#: bf58d54a167d45de9a18641877ada912 of msgid "Address the server socket binds to. Defaults to \"127.0.0.1\"." msgstr "サーバーソケットがバインドするアドレス。デフォルトは「127.0.0.1」です。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 -#: d4c7cd9cc01e4371961f0950fd861b12 of +#: 2f4d0c4bfd8246d4984d4c843510775d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 of msgid "First port to bind; also the base of the allocation range." msgstr "バインドする最初のポート。また、割り当て範囲のベース。" -#: 716408a19bf349878edfd5f1948f57ec +#: 47138ce8f587467aa353e302f473df48 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:8 of msgid "" "Maximum concurrent clients served in thread mode; ignored when " @@ -418,36 +496,36 @@ msgstr "" "スレッドモードで提供される最大同時クライアント数。'' is_asynic_clients_io " "''がTrueの場合は無視されます。デフォルトは10です。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 -#: c37fcc062f6947228f3dc0b85ec5a5ca of +#: 8786a9d2b6b449209be813778d785712 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 of msgid "Step between candidate ports. Defaults to 1." msgstr "候補ポート間のステップ。デフォルトは1です。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 -#: e683b27a8b884c5b99511f99e20b6bf9 of +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 of msgid "Number of ports per step. Defaults to 100." msgstr "ステップあたりのポート数。デフォルトは100です。" -#: 6291e503f9bf4c78a9c226058a67bce1 +#: 973382c423524d44a569c318399e0b99 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:15 -#: e59cefed7c4e4148b863b89e4d17004e of +#: d5f8f341d98d478289d9a226f37c1003 of msgid "Concurrent file transfers allowed. Defaults to 10." msgstr "同時ファイル転送が許可されています。デフォルトは10です。" -#: 792cebf4ce084bd9b222b9ee83eeb5f4 +#: 4fe9a7607dbc4eebbce4e62f9306c76f #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:18 of msgid "" "Reserve a port range across processes, so several instances on one host " "do not collide. Defaults to False." msgstr "1つのホスト上の複数のインスタンスが衝突しないように、プロセス間でポート範囲を予約します。デフォルトはFalseです。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 -#: befe96138f8544cbb8320f33af43af3e of +#: 8aa56addc6ae4a7790dc957d1e1c2b60 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 of msgid "Start the console command thread. Defaults to True." msgstr "コンソールコマンドスレッドを起動します。既定値はTrueです。" -#: 10c1ed53a097472297ade439439e218f 3bc54f27f3db4bce846f5ec756f0e68f +#: 242566ff64584fba88e4fed8bb189110 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:28 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:24 of msgid "" @@ -455,242 +533,387 @@ msgid "" " 10." msgstr "`submit_task`とスレッドコマンドハンドラのワーカースロット。デフォルトは10です。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 -#: f0a3afe6bc0c4eb2ad2e9e5ae43e2d88 of +#: 87d1cd7d6569498b8af8bc7064235784 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 of msgid "" "When True, do not call `start_TCP_Server`; the caller starts the server " "when ready. Defaults to False." msgstr "Trueの場合、`START_TCP_SERVER`を呼び出さないでください。呼び出し元は準備ができたらサーバーを起動します。デフォルトはFalseです。" -#: 577dd2f594554ceab51324eaedf4b1b3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 +#: ac43634ddb1a4d15a9f3d0f58d011441 of msgid "" "Negotiate the RSA-encrypted channel for every connection. Defaults to " "True." msgstr "すべての接続でRSA暗号化チャネルをネゴシエートします。既定値はTrueです。" -#: 1ea6dc3b1a34463881e1aa7e96a14525 +#: 1ffccca56902418ba98ee0c6776ad8fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:37 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 -#: ecd4aa80607e4f988ac59b64e85c8fbe of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 of msgid "" "``[pub_key_path, pvt_key_path]`` pair used instead of the default key " "lookup; an invalid pair is ignored." msgstr "デフォルトのキー検索の代わりに''[ pub_key_path, pvt_key_path ]''ペアが使用されました。無効なペアは無視されます。" -#: 0b92e71977dc4312b9e31fab903eadf2 +#: 420bbdf8d6bb400fbd3548bea03354ac #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:36 of msgid "" "Buffering ceiling in MiB for the in-memory forward pump; past it the " "uploader is told to pause. Defaults to 2048." msgstr "メモリ内フォワードポンプのMiB単位のバッファリング天井。それを過ぎると、アップローダーは一時停止するように指示されます。デフォルトは2048です。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 -#: e14dae3d183249e19a0f6cf671ead02b of +#: 94e4a7e67e3047fd9d565f9a5d8122ab 9dcb36b97a004812bbcf264efa812441 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 of +msgid "" +"Bytes read per receive on the control connection, covering commands and " +"messages. Defaults to 4096." +msgstr "" + +#: 116dc6d56dd44f4ebaab990a3658359d 397abb5fbc1a46db90a7829daac02465 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:42 of +msgid "" +"Chunk size in bytes streamed when sending or receiving a file or folder. " +"Defaults to 65536 (64 KiB)." +msgstr "" + +#: 446099293d824f27aed7245f3c77df69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:45 of msgid "" "Serve clients with asyncio coroutines on an event loop instead of one " "thread per client, so a single server can hold thousands of concurrent " "connections. Defaults to False." msgstr "クライアントごとに1つのスレッドではなく、イベントループ上の非同期コルーチンを使用してクライアントにサービスを提供するため、1台のサーバーで数千の同時接続を保持できます。デフォルトはFalseです。" -#: 07311d6c7a2f4516a4209df5c7798be6 9f213be174d243d4af26f79ae9624945 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:44 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:50 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:50 of msgid "" "Log execution-process lines in addition to command and result lines. " "Defaults to False." msgstr "コマンド行と結果行に加えて、実行プロセス行をログに記録します。デフォルトはFalseです。" -#: 28ea5071c3344615b114f12ad5be447c 497004294ca244138115a713c0ffed15 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:47 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:53 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:53 of msgid "" "Log at all; False silences every line this instance would print. Defaults" " to True." msgstr "まったくログを記録します。このインスタンスが印刷するすべての行を誤って沈黙させます。既定値はTrueです。" +#: 1608cb9ad7104c82a43f23bb929f7d84 744b24d9e233457fb87cc8faefc5a498 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:56 of +msgid "" +"Track every running file transfer in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads): each entry holds the bytes " +"transferred so far, the total size and the current speed (None while " +"``is_enable_real_time_network_speed`` is False). An entry appears when a " +"transfer starts and is dropped when it ends. Defaults to True." +msgstr "" + +#: 3658f6b3ec994d15b9321a10ae33b351 769ed811a0cb4b18aeacdd39e4b4bbe2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:64 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:64 of +msgid "" +"Measure the real-time network speed of every send and receive — the " +"control layer and every temporary connection (file transfers included) — " +"into ``upload_network_speed`` and ``recv_network_speed`` (bytes per " +"second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False " +"nothing is measured and every speed value is None. Defaults to True." +msgstr "" + #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f0e9eea68114cf3b085d08796aaf552 3f8c413bab284fb78ac0b2ef8b8fb44a -#: 4a7a4c0862a84c53b2ccf0de3b00d495 4c3773b74abf40118b9ed681d9bef66a -#: 9f4fa9dc8d5045e39702036409f07a5d aa175c9daeab453a848bb2ef9f2e3dcf -#: cf96ad3305794cd7b9578ecb55ecd8b9 fbbf706646e24207aaf3b2532903a31b +#: 63ab5a2f2327475ba324e245f8e6e2ac msgid "Raises" msgstr "レイズ" -#: 0c72321c656641a5b684299b915cbb39 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:52 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:51 -#: d72a9dcf6bc748e5898640448e229b3b of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:81 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:73 +#: ed59ec69b9a1430597e6d8758051aff5 of msgid "" "If the ``.Flow`` directories or ``decode_command_table.json`` cannot " "be created or read." msgstr "''.Flow ''ディレクトリまたは'' decode_command_table.json ''を作成または読み取ることができない場合。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 -#: e2bb545e7ee1419286f58495abc4bcd2 of +#: 031d3e96394c454093561375a377dcce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:1 of +msgid "Pause an outbound transfer of this instance." +msgstr "" + +#: 342e6dfc6f6a4399914bc72372aa5f2d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. A " +"forward relay's writer toward ``peer`` is paused the same way the " +"``/pause_trans`` line pauses it." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:3 of +msgid "Transfer id the outbound leg is keyed by." +msgstr "" + +#: 7ecc0c956c8b408688fca517eb6370fd +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:10 of +msgid "" +"Restrict the pause to the leg or relay writer toward this ``(ip, port)``;" +" None addresses every match." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:14 +#: bdee1944910b4ee3908cf225a151a5fd of +msgid "" +"True when a running leg (or relay writer) was marked paused; False " +"when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 99ba2aa702f74621ba4dd31b8c045467 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:16 of +msgid "True when a running leg (or relay writer) was marked paused;" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:17 +#: c85ed4c1a84443a98394146efcf04315 of +msgid "" +"False when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 2771724616054f628d60add2c7407e7b 3a0594b22c6849c88310243022e8ee23 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:1 of +msgid "Resume an outbound transfer paused with `pause_trans`." +msgstr "" + +#: 7a864ecc76fe40459eeff353522482fb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg or relay writer toward this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:9 of +msgid "True when a live leg (or relay writer) was resumed." +msgstr "" + +#: 364557403e3d480896c0ffc57a19df04 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:1 of +msgid "Ask a connected client to pause its transfer toward this server." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:3 +#: f13c2e0e5310443080b0f63c773d8497 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (see `pause_trans` on the receiving side)." +msgstr "" + +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:3 of +#, fuzzy +msgid "Connected client ``(ip, port)``." +msgstr "発信元クライアント''( ip, port )''。" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:5 of +msgid "Transfer id of that client's outbound leg." +msgstr "" + +#: 5ea8eea489fc43108a439d54fba31068 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:8 of +#, fuzzy +msgid "True when the line was written; False when ``peer`` is not connected." +msgstr "要求がサーバーに書き込まれた場合はTRUE。クライアントが接続されていない場合はFALSE。" + +#: 38905ec7539d42e0839907c32dd8667f +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:13 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:10 of +#, fuzzy +msgid "True when the line was written; False when ``peer`` is not" +msgstr "ペイロードが書き込まれた場合はTRUE、クライアントがそうでない場合はFALSE" + +#: 1c7b88e29a0143a39e13441769186ef4 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:11 of +msgid "connected." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:1 +#: adfc486a05ae4063bda6a61f2a6f3c36 of +msgid "Ask a connected client to resume a transfer paused earlier." +msgstr "" + +#: 810bc26336b24ad1acba3f56d466f8e9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 of msgid "Reserve this server's port range under the cross-process lock." msgstr "クロスプロセスロックの下でこのサーバーのポート範囲を予約します。" +#: 5540b6efb5864c188e080ec7aad5c3ca #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 -#: c9ae1464a03b44049e826b9b73e2aca2 d23fda91e3e645e081dd5bbd5332fc4c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 of msgid "No-op unless ``is_hand_alloc_port`` is True." msgstr "'' is_hand_alloc_port ''がTrueでない限り、操作はありません。" -#: 0b8bb2090cd04385a9d960dd2808f5bc 55b8a82ae1ce4769a1c62b35d253810e -#: 6d17c5fb7b4d484ba017edb4c5d5535e +#: 356ed2e8333d49b98ed6834612b4b56d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 -#: c3818bbf57ac448cb073fb780326fdf7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 of msgid "Step between candidate ports." msgstr "候補ポート間のステップ。" -#: 1080747700804d04ae169eef511d5bb5 45799e3c1b6e446a86b111e06365ca9b -#: 5bfd1aa496dc41b7ab2abd78f134c389 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:8 -#: efa8e8819eec4e1ba0d90562f34755b5 of +#: e18848eedc5d4d8abd97d73a0984a5d3 of msgid "Number of ports per step." msgstr "ステップあたりのポート数。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 -#: c1cf751ac2774558925ef1ffd1a6c3dc of +#: 11e0523d1b194702a07a92748468da25 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 of msgid "Release this server's reserved port range." msgstr "このサーバーの予約済みポート範囲を解放します。" +#: 801c063c5fa447bda1dbf7f5ccbc6a9a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_lock:1 -#: b2b2a77e9deb4423955004a9e3390aca of +#: of msgid "Create the lock file that reserves the server port range for this process." msgstr "このプロセスのサーバーポート範囲を予約するロックファイルを作成します。" -#: 658bc1e35a794bf5a22c70ffbef94b87 +#: 672bb7a9496c43ac8b706a3d0062ddfd #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:1 #: of msgid "Report whether the server port range is reserved by some process." msgstr "サーバーポート範囲が何らかのプロセスによって予約されているかどうかを報告します。" -#: 39bb21b4d3a0404fb64295a73c2ad5ba 5dc09f28266e4a3bb083923d8784f09c +#: 39423e052b70403ba07a713aa9e3cb4a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:3 #: of msgid "True while the lock file exists." msgstr "ロックファイルが存在する場合はtrueです。" -#: 6512b0b8da7041e8a917014e5562583c +#: 5b6cf828ffb24e098a0c86a09818da73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_unlock:1 #: of msgid "Remove the lock file that reserves the server port range." msgstr "サーバーポート範囲を予約するロックファイルを削除します。" -#: 90520dc2f5704cdaba37211d6390b03d +#: 479bdf5518dc4a029ecf47ad44bdcd5d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:1 of msgid "Allocate the next free server port range and record it on disk." msgstr "次の空きサーバーポート範囲を割り当て、ディスクに記録します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 -#: cf0980ef8455426781e617a911f73732 of +#: 34c085a1bfca4dedafc749bfdcf14ad5 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 of msgid "" "``port`` is moved past the ranges already recorded by other servers, so " "the instance ends up with a range of its own." msgstr "'' port ''は、他のサーバーによって既に記録されている範囲を超えて移動されるため、インスタンスは独自の範囲で終了します。" -#: 1e5f1ba9b8bf4d28971b92ef12f747f2 +#: 197b30e318d741c2b1f8afc925e91e5c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:11 of msgid "If the server port info file cannot be read or written." msgstr "サーバーポート情報ファイルの読み取りまたは書き込みができない場合。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 -#: bf4bb338fcf846a29910656081787945 of +#: 1c97c8ef484b42ab86d36b3742bf3879 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 of msgid "Drop this server's entry from the on-disk port range record." msgstr "このサーバーのエントリをディスク上のポート範囲レコードからドロップします。" -#: 30208c231b534eedbe843d42a3cad90d +#: 9fc07e857fa048e2956e64bf78f6e386 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:1 of msgid "Allocate a transfer port, waiting until one is free." msgstr "転送ポートを割り当て、1つが空くまで待ちます。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 -#: f219ec3cd1d1448fb4e0171853a7d779 of +#: 505d7b9fb1024bc8ba886e5b0a38fbf2 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 of msgid "" "Allocated port, or 0 when allocation is disabled " "(``is_hand_alloc_port`` False)." msgstr "割り当てられたポート、または割り当てが無効な場合は0 ('' is_hand_alloc_port '' False )。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:5 -#: af35fb0d306d447ca2a70b0f2b63ecee of +#: e85fdf7f7a594e0b9aed565b4a3ab42f of msgid "Allocated port, or 0 when allocation is disabled" msgstr "割り当てられたポート、または割り当てが無効になっている場合は0" -#: 94b2dff9085247fda189e063a4fa4a7f +#: 153357eb91794cb692467afe5e94b41c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:6 of msgid "(``is_hand_alloc_port`` False)." msgstr "('' is_hand_alloc_port '' False )。" -#: 06c8b24821f94f48b265dd90995e10a9 57f02c9c5f32443e82feac04411b32ed +#: 26c5c3768e1446e78c9efc5f8038b23d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:1 of msgid "Release a port obtained from `palloc`." msgstr "`palloc`から取得したポートを解放します。" -#: 750aeace3a2043978210096a24199700 +#: 0e0379de669843778f6827973c29372e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 -#: a400ec85715c462e941f3f590f646046 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 of msgid "Port to release." msgstr "開放するポート。" +#: 6a8d4efd9f9a45e399525e2f169035ee #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 -#: c6c5882e52c74fb1a5aa68e621922150 e95eb44c45ea42a5b63026f73274f990 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 of msgid "Allocate the next port above the base, or the first free one in range." msgstr "ベースの上の次のポート、または範囲内の最初の空きポートを割り当てます。" -#: 2aec0e66e9e44175a6d6a36917137cf9 +#: 73e9e2ddd451402a93d10dbac6ac9374 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "割り当てられたポート。上限範囲が尽きた場合はなし。割り当てが無効の場合は0 ('' is_hand_alloc_port '' False )。" -#: 14bd404133c744e68356290e50c91f4c +#: 9d96a242eab8433ca750d670a5f63b82 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:5 of msgid "Allocated port; None when the upward range is exhausted; 0 when" msgstr "割り当てられたポート。上向きの範囲が排出された場合はなし。0の場合は" +#: 7b05e18fccbe4ab081d3cd22d59a48e0 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 -#: a2a1781441e64797a0d7942463680610 bccdcb4c96de4d6a9f6c4318d0b1f55e of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 of msgid "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "割り当てが無効になっています('' is_hand_alloc_port '' False )。" -#: 9b0a4b0fa07b4f7e8e4476f99d191837 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:1 -#: a4c53c6cf9d24f1ca624f8ade02cfb07 of +#: f2d9abe435cf49f6825bb72a68013934 of msgid "Release a port obtained from `file_palloc` and step the cursor back." msgstr "`file_palloc`から取得したポートを解放し、カーソルを戻します。" -#: 24467ee3998b40bd9563059c6610e4e9 2a1c562ca62f40158d89d6f16896ed18 +#: 6c1fb07a212d4bf19717407b0c7184d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 -#: ace99e97fef7403faf20dc5040a47bfa ba3e6daae9e34590bc0f2abc98c02da3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 of msgid "Port to release. Ignored when allocation is disabled." msgstr "リリースするポート。割り当てが無効になっている場合は無視されます。" -#: 053f2e52a148421eb080c1df3d3de1cc 9052b949aa354df7968cacc9ed930921 +#: 1afd81c685234a20aa41c5cde93d327d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:1 of msgid "Allocate the next port below the base, or the first free one in range." msgstr "ベースの下の次のポート、または範囲内の最初の空きポートを割り当てます。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 -#: eb3a97b7706a47dda4cfb5e12930ba02 of +#: 3fc63f6d51aa4c0fb22fd0f945f9cfd7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." @@ -698,36 +921,34 @@ msgstr "" "割り当てられたポート。下向きの範囲が枯渇した場合はなし。割り当てが無効の場合は0 ('' is_hand_alloc_port '' False " ")。" -#: 3c8cc24113bd420eb7f373cde6a27ef2 +#: 74a441ccfa5e421dadd215ef0725a25f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 -#: f70a4f056d6c49b2b953824ffab19db7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 of msgid "Allocated port; None when the downward range is exhausted; 0 when" msgstr "割り当てられたポート。下向きの範囲が排出された場合はなし。0" -#: 383142a0285745bb8ef4b95b1d597151 9f78428fda474dffac2f3cdf4c3a2aeb +#: 9c4b9bddd98c463f9e140bd2d8425dad #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:1 of msgid "Release a port obtained from `spy_palloc` and step the cursor back." msgstr "`spy_palloc`から取得したポートを解放し、カーソルを戻します。" -#: 57c8111cd86f49c7af67d8e9a177a591 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:1 -#: e435af0f27b641168044b3cac4130ac5 of +#: c66c76cab8564da4b6b6cb855fd63fd5 of msgid "Register a custom command handler." msgstr "カスタムコマンドハンドラーを登録します。" -#: 39f637bfe6ff4822952d67419861841d 51f84d06854b4b96b7ce1fb2e778b5e5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of msgid "" "Command to intercept, e.g. \"/my_command\"; matched case-insensitively " "against the first token." msgstr "\"/ my_command \"などのインターセプトコマンド。最初のトークンに対して大文字と小文字を区別せずに一致しました。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:6 -#: b53c2039d55947d689c2cfe09cac93c2 of +#: c7c29a3836c9493e9c8804cc5896144a of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back to the sender as the response." @@ -735,25 +956,24 @@ msgstr "" "'' handler (client_socket, client_address, command " ")''が生行で呼び出されました。None以外の戻り値がレスポンスとして送信者に返されます。" -#: 15398a9c312e459a897c07b18dc9fbaa +#: 7c64d0c0b9ac44b995811a0fdaa0dfaf #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:10 of msgid "" "\"server\" for commands arriving from clients, \"client\" for commands " "typed on this instance's console." msgstr "クライアントから到着するコマンドの場合は「server」、このインスタンスのコンソールに入力されたコマンドの場合は「client」。" -#: 7ff63de06e854f88b1cebc42b464397d 8f139fd48e9c496287f9df897ccf01d6 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 +#: a0c074a9da664c5eb5fa63deb6765c36 of msgid "" "Run the handler on the worker pool instead of the reader thread. Defaults" " to False." msgstr "リーダースレッドの代わりに、ワーカープールでハンドラーを実行します。デフォルトはFalseです。" -#: 1a0a724bef6140ceb235cbeaea95c1d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:17 -#: e73cb64f1ef544db8009b026ab5c376c of +#: e6c616f887334cb6925c03de2ad6f64c of msgid "" "False when ``where_to_run`` is neither \"server\" nor \"client\"; the" " handler is then not registered." @@ -761,30 +981,80 @@ msgstr "'' where_to_run ''が\"server\"でも\"client\"でもない場合はFALS #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:19 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:19 -#: e1cba64f5b384d169c366d8e16078683 eaab849e83884bd6be80fa08867ccde2 of +#: f125f1386b434f3a8199b1ceb8c44eca of msgid "False when ``where_to_run`` is neither \"server\" nor" msgstr "'' where_to_run ''が\"server\"でもなければFALSE" -#: 4cbf71104b8544d18962b7a9adca8b7e 82c461f38cc44bc9914cb7009a5cf3e1 +#: 1a68dac068db434eb76e28015005f29c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:20 of msgid "\"client\"; the handler is then not registered." msgstr "\"client \";ハンドラは登録されていません。" -#: 15aa55a075a64bb98f5819a8a5d37113 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 of -msgid "Register ``listener(client_id, message)`` for every inbound plain message." +#: 25c1023e97b64226a58cdf83f8ba07bf 9ebd0da560d747168cebc59ca93b1cb1 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:1 of +msgid "Call one registered extension command handler directly from code." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:3 +#: b14f4ed43e6c43c39579c1c16b169645 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines clients send. " +"The handler runs on the calling thread — ``run_in_thread`` only affects " +"the console and inbound dispatch paths — and is called with ``None`` for " +"both ``client_socket`` and ``client_address``, since a direct call names " +"no peer." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:11 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of +msgid "" +"Command line to run, e.g. ``\"/my_command arg\"``; the handler receives " +"it unchanged." +msgstr "" + +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:15 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:15 +#: of +msgid "Whatever the handler returns." +msgstr "" + +#: 0ab70b2e8ed040d4908d0900da96f6c2 0d85b81af0634a448e6a74d63c06045f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:18 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:18 +#: of +msgid "If no registered handler matches the first token of ``command``." +msgstr "" + +#: 1f5b21975ad2499a86fe21c69bfd7ca0 42f8d27a5499457da7302224dcc8a521 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:19 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:19 +#: of +msgid "If ``command`` cannot be split (unbalanced quotes)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 +#: ef5d20f1a16945368383a8cdbc3daa19 of +#, fuzzy +msgid "Register ``listener(client_id, message)`` for every inbound line." msgstr "すべての受信プレーンメッセージに'' listener (client_id, message )''を登録します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 -#: f914714947174f2298278112a91d82b0 of +#: 2459179e833b4e7db8e1d70571ac793a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 of msgid "" -"Plain messages are the lines received from clients that do not start with" -" ``/``; commands go through the registered command handlers instead." -msgstr "プレーンメッセージは、''/''で始まらないクライアントから受信した行です。コマンドは、代わりに登録されたコマンドハンドラを経由します。" +"Every line received from a client is reported, commands included " +"(``/help``, ``/file ...``, the crypto handshake lines, ...), so the " +"listener observes all inbound traffic; dispatch is unaffected, a command " +"still goes through the command handlers." +msgstr "" -#: 1b5e4524170242099c808039098d64c3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:6 of +#: 9ec5fafe8ded489785400e3e489b8573 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:8 of msgid "" "``listener(client_id, message)`` where ``client_id`` is the sender's " "``\"ip:port\"``. It runs on the receive thread, so it must not block, and" @@ -793,30 +1063,28 @@ msgstr "" "'' listener (client_id, message )''ここで、'' client_id ''は送信者の''\" ip: port " "\"''です。受信スレッド上で実行されるため、ブロックしてはならず、内部で発生した例外は飲み込まれます。" -#: 2e65864bfdd2429298dbf86682b3be81 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:1 -#: e562b99848544a8cb47afb41478d1b66 of +#: edb8edc2eb3f433186b54807a8ac43ad of msgid "Unregister a listener previously added by `add_message_listener`." msgstr "以前に`add_message_listener`によって追加されたリスナーの登録を解除します。" -#: 346bd1c9d44045868b59b7643f1cf09e 8ff591c39e334e1eab8d05267532faed +#: 6fd7bb75a29e4973ac2bd05119255039 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 -#: a0e48bdcb67e49498a113a58a504553c ab196c3b77b143069faa85a52626d946 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 of msgid "Listener to remove; an unknown one is ignored." msgstr "削除するリスナー。未知のリスナーは無視されます。" -#: 46010db8ce4d4eb1b06348f29e115846 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 +#: cf95477e5794404fbdf4e877a132ba1c of msgid "" "Register ``listener(client_id, full_path, name, size, command)`` per " "saved file." msgstr "保存されたファイルごとに''リスナー(client_id, full_path, name, size, command )''を登録します。" -#: 72536042242c4ea9bd2e6efa63fc9336 +#: 9c57d09f6d3d437890ae3ad306071701 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:3 of msgid "" "Fired after a file uploaded by a client (a direct send, or a forwarded " @@ -826,8 +1094,8 @@ msgstr "" "クライアントによってアップロードされたファイル(ダイレクト送信、またはサーバー上にステージングされた転送ファイル/フォルダアイテム)が'' " "file_transfer_dir ''に完全に書き込まれた後に発生します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 -#: f4ba3546e2b048d49d9c274ef8d8ac98 of +#: 6c938b7c8be3464f9925527b6deb4e1d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 of msgid "" "``listener(client_id, full_path, name, size, command)``; ``client_id`` is" " the uploader's ``\"ip:port\"`` and ``command`` the wire command that " @@ -840,92 +1108,85 @@ msgstr "" "''の配線コマンドであるため、リスナーは''/ crypto_pub_key " "''などのプロトコルプッシュを認識できます。転送スレッド上で実行されるため、ブロックしてはいけません。" -#: 2e1706c637c54db9b8ed55ba98665535 3d6b3f43b6094b2e9776fcb9e4ce7bcb +#: 57b1e98125974187b986386da7991dd0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:1 of msgid "Unregister a listener previously added by `add_file_listener`." msgstr "以前に`add_file_listener`によって追加されたリスナーの登録を解除します。" -#: 0a8d57625bba4ce4949fc23bce63f033 +#: 58f1ccd078ea406dab00d6d4be886a76 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 -#: c27185227a5f434f9641501d1d3bca2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 of msgid "Run a callable on the instance's worker pool." msgstr "インスタンスのワーカープールで呼び出し可能なを実行します。" -#: 0c5aed09b63647cd87a3234ef9a4903c 40fade944d8d43b18599150134015443 +#: 6e05c7f46b244ae195c32ee52797fa37 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:3 of msgid "Callable to run." msgstr "呼び出して実行できます。" -#: 6bcb8f96e0584f66bbb94fe2573a7f61 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:5 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:5 -#: e959076fdf3843fc9c53ccb8492adfe6 of +#: e1c79706c9414895bdf7bf183bf5d41a of msgid "Positional arguments forwarded to ``func``." msgstr "位置引数は'' func ''に転送されました。" -#: 41d755cbd3cf48e7a0bc9d2b1aa3ab14 628a65eab1354dda83077715a47e63fb +#: 9221436fa83a4831942cf5be4e37e2cb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:7 of msgid "Keyword arguments forwarded to ``func``." msgstr "キーワード引数が'' func ''に転送されました。" -#: 1c03aa271c37431d974f08f11c93d7af 4b1078858cf64a1e92b36fa109fc1409 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 +#: a6b26d6cf54d4fafac2950cbe33ba56f of msgid "" "Handle for the submitted call; its worker slot is released when the " "call finishes." msgstr "送信されたコールのハンドル。コールが終了すると、そのワーカースロットが解放されます。" -#: 169f874c0ebb40d5aecd2549e60b4600 1e45486e3fd84627b015bf5a9a0a24b4 +#: 60f19983f7384aefbb6c97b84dd25f93 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:12 of msgid "Handle for the submitted call; its worker" msgstr "送信された通話のハンドル。そのワーカー" -#: 037748a51dd94d43a3939fa8ec538d66 655c7802ef7c42a686c74d426531db8b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 +#: eadf6af0a0954798933dc427ba8e107e of msgid "slot is released when the call finishes." msgstr "スロットは、コールが終了すると解放されます。" -#: 7b0b391fc53d42fb8f331d8e2da2be54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:1 -#: d6578909a33e4eef8afe892b33e0f70b of +#: fece61298a354d6db119309b29c6751d of msgid "Start a temporary listener for a side channel (not the main protocol)." msgstr "サイドチャネルの一時的なリスナーを開始します(メインプロトコルではありません)。" -#: 1164584733744eb2aa574d6f61476c2d +#: 01d42ba32c2b41f482dd077cfb950f9b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 -#: c132c5365e7c487c92b4072a0020b52c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 of msgid "" "``handler(client_socket, address)`` started in its own thread for every " "accepted connection." msgstr "'' handler (client_socket, address )''は、承認されたすべての接続に対して独自のスレッドで開始されました。" -#: 03583460bc824965b9152433dfdfb097 +#: 5e1b84445ee34c9cac00e1a2c9ef297b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 -#: e81f361ea0fb46ee9c6760b0c6ef11c1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 of msgid "Port to bind; None allocates one with `palloc`." msgstr "バインドするポート。Noneは`palloc`を持つポートを割り当てます。" -#: 4f2f3f063e9c4834a77fbdb1a46d65dc +#: 9c69c4dd1d904078af48c6308ba35895 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 -#: b655787e48384873b4446ee1147bdedd of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 of msgid "Listen backlog. Defaults to 1." msgstr "バックログを聞きます。デフォルトは1です。" -#: 31cd65b92bb846f6b9c97b003fa00db5 +#: 47f98fd15e6144bd845d175cd039a6c2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 -#: ec56b80af0a843a991cbe77c5ee9ae45 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 of msgid "" "``(port, thread, stop_event)``; setting ``stop_event`` ends the loop," " which closes the socket and frees the port." @@ -933,59 +1194,56 @@ msgstr "" "''( port, thread, stop_event )'';設定'' stop_event " "''はループを終了し、ソケットを閉じてポートを解放します。" -#: 7b73372b2ada4ce5b210b527015d925c 86cfce9d36f04328ba76e88df87fbcd8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 +#: ecf3d32c44db40a8a13545d623ffe2c9 of msgid "``(port, thread, stop_event)``; setting ``stop_event`` ends the" msgstr "''( port, thread, stop_event )'';設定'' stop_event ''は" -#: 11b0347a0ebd4ae3931ed1f77c26a04e 9017aeb8480241f3a5f426c718bc4ee0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:14 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 +#: abce9546b7444c6383c9020c4133ec63 of msgid "loop, which closes the socket and frees the port." msgstr "ループは、ソケットを閉じてポートを解放します。" -#: 3c32a346019741da9aa2a3e409a7b0e2 82f16e3e9ba1468d8a87c91db28cc45e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 +#: a270cfabdac64296b8a33ad4d662896f of msgid "If ``port`` is None and no port can be allocated." msgstr "'' port ''がNoneで、ポートを割り当てることができない場合。" +#: 031d3e96394c454093561375a377dcce #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 -#: d63b5db9eab6478ca088c9a5e90163fc f0869b5be0ab40e4a2a7eca275922557 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 of msgid "Open a temporary outbound connection for a side channel." msgstr "サイドチャネルの一時的なアウトバウンド接続を開きます。" -#: 3d194b9f95794116b17720aa74ce0878 +#: 112fda54e1eb4981b4272df61c5416e2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 -#: d0bb03d9590540fd980dd79c28d98e97 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 of msgid "Host to connect to." msgstr "接続するホスト:" -#: 98a5441019de48258a099f2ec25751f5 +#: 59d3c414b4304673be5d3232d2291680 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 -#: b443afa67dc84e1a8ac501ad5c6b0ff1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 of msgid "Port to connect to." msgstr "接続先ポートです。" -#: 537482efdcc0447e81bd001ad2d4d85a -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 +#: c5766672f68f47c9908e68d2ed3be7f3 of msgid "Local port to bind; None lets the OS choose." msgstr "バインドするローカルポート。OSが選択できるものはありません。" -#: 2230b0e486fc4229acc03f78ec4b1e09 300e61efcfef4a2f8c87725e183ceda8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 +#: bfc1b713e9fc4fe797e50c357f472e76 of msgid "``on_data(data, client_socket)`` called for every received chunk." msgstr "受信したすべてのチャンクに対して'' on_data (data, client_socket )''が呼び出されました。" -#: 2f63095ce33849b78465729923d04ff0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:14 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:13 -#: e07d5e5deb1a4fb086664ed896076feb of +#: c563d04fcd7a41f1a2aeace42974430a of msgid "" "``(client_socket, thread, stop_event)``; setting ``stop_event`` ends " "the receiver thread." @@ -993,47 +1251,46 @@ msgstr "" "''( client_socket, thread, stop_event )'';設定'' stop_event " "''はレシーバースレッドを終了します。" +#: 0e1b9679f3104a9caab601e6bc7c0905 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:16 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 -#: bf9994c99c8a48139d4c00d0dcfeca63 dbf60e58abd04e02b50316b1cb4b7b2f of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 of msgid "``(client_socket, thread, stop_event)``; setting ``stop_event``" msgstr "''( client_socket, thread, stop_event )''; '' stop_event ''の設定" -#: 6af1621f80734591950e545b955c4bbe #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:16 -#: e69a51e576e446c59185c2eceae72657 of +#: c76fce92c3f944c1857df89bbc134540 of msgid "ends the receiver thread." msgstr "レシーバースレッドを終了します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 -#: c291ec3d31094e589a1bfc5713b47ee3 of +#: 5ea5fd66c3d3434292e4d8e1dd1da094 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 of msgid "Send one message to every connected client." msgstr "接続されているすべてのクライアントに1つのメッセージを送信します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 -#: c28f38641c704c1e912c602ced57fc9e of +#: 32945f04e0564f9d88495506f0ab4f90 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 of msgid "Clients whose send fails are disconnected and removed from ``clients``." msgstr "送信に失敗したクライアントは切断され、「クライアント」から削除されます。" -#: 3f3e7a6a5de746518e9ddd135983d073 +#: 00de0b1f60b14189b1629f8146db68a6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:5 of msgid "Payload passed to `send_message`." msgstr "`send_message`にペイロードが渡されました。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:7 -#: cae2a2c29d96447d8b1056e36bbf5572 of +#: a91c8f6921c7435e990516c2134efcf8 of msgid "``(ip, port)`` to leave out, typically the client the message came from." msgstr "''( ip, port )''を省略します。通常、メッセージが送信されたクライアントです。" -#: 9b2b7c4e77844a82bfd61276bf46f6d7 +#: 9d57c62f1fd94c1dacfe32aa50cc9665 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:1 #: of msgid "Send the messages of a console line to the clients named in it." msgstr "コンソール回線のメッセージを、その中に指定されたクライアントに送信します。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:3 -#: cabc278e7f6a49e6bd6e533f632d0f99 of +#: e7fbf4bbd84b4920a2b9591fabcaf2d9 of msgid "" "``/send_msg`` line as typed: message text followed by one or more ``(ip, " "port)`` identifiers; each message is delivered to the identifiers that " @@ -1043,17 +1300,18 @@ msgstr "" "入力された''/ send_msg ''行:メッセージテキストの後に1つ以上の''( ip, port " ")''識別子が続きます。各メッセージは、それに続く識別子に配信されます。接続されていないアドレスは、コンソール通知でスキップされます。" -#: 888e165ca1554b4db63e714e3adc63f1 +#: 9d4819fe4ca94a1b81c9e0423ff98212 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:1 of -msgid "Write one line to a client socket, encrypting when the channel is up." +#, fuzzy +msgid "Write one message to a client socket, framing it when the channel is up." msgstr "1行をクライアントソケットに書き込み、チャネルが稼働しているときに暗号化します。" -#: 64d6f6cc29de4d4290671afc59d808c7 +#: 1c7b88e29a0143a39e13441769186ef4 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:3 of msgid "Target connection." msgstr "ターゲット接続情報" -#: 73953d67bcbf4bfabae7b0ff91bfce8c 7e2e221f6a6b43a08f534ca2d8cfb6e8 +#: 6f8bd9adaf2b4c44a9446b049144fe21 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:5 of msgid "" @@ -1061,62 +1319,73 @@ msgid "" " are." msgstr "ペイロード。文字列は削除され、改行は終了し、バイトはそのまま送信されます。" -#: 240dadd589af42e18e15d2c53b5c96b0 +#: 5c03983cb460497fb72f126c1d8a2bc1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:9 of msgid "" "True when the payload was written, False for an unsupported payload " "type." msgstr "ペイロードが書き込まれたときはtrue、サポートされていないペイロードタイプの場合はFalse。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 -#: dbfc49c3c67c48d5860a61f8ded20950 of +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 of msgid "True when the payload was written, False for an unsupported" msgstr "ペイロードが書き込まれたときはtrue、サポートされていない場合はFalse" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 -#: cab2f5321ba54adca315d34d921a09b5 of +#: 602950a9f5ad48ea92ab60aea3b26488 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 of msgid "payload type." msgstr "ペイロードタイプ。" -#: 4519dac81e714164a0edbf6ac75c9c19 +#: 149f767d72dc4da7b1d88fed768d2474 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:15 of msgid "If the server is not running or no socket was passed." msgstr "サーバーが実行されていないか、ソケットが渡されていない場合。" -#: 7ea1b30273604db4854189502fdf734e +#: 07dac2d20d7041779c8b189d45ee2e64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:16 of msgid "If the socket write fails (the original error is re-raised)." msgstr "ソケット書き込みに失敗した場合(元のエラーが再生成されます)。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:1 -#: b228437e9cb4461e9ceb078f084544eb of +#: caf2377ee7f348ab8c95bf2a27c44be4 of msgid "Read up to ``msg_length`` bytes from a client socket." msgstr "クライアントソケットから最大'' msg_length ''バイトを読み取ります。" -#: 292c2ed074e14a5eb184dceb245cab6f 58a8806cd0bb4dc9895b7f74a1b45765 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 +#: c702e4a63a5240ea97feb5bc393b4d09 e9256fbce5d848b59ae2e6d0ce88ce24 of +msgid "" +"A socket speaking frames (see `_SecureChannel`) returns decrypted " +"plaintext, served from the channel's buffer; a socket without one is read" +" raw. A read that started while the channel was raw is classified by the " +"channel when it returns, so bytes of a flip that landed during the read " +"never land in the line reader." +msgstr "" + +#: 214af2667d0f443eb16c0a4aaf723b2e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:9 of msgid "Connection to read from." msgstr "読み取り元への接続。" -#: 547ccf662a6945738e8c761628807ab1 624220029a624009adb07a49140d8a2c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:5 of +#: 7c3eb31687804ba5a59acc140ba50230 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:11 of msgid "Maximum number of bytes to read." msgstr "読み取る最大バイト数。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:8 -#: b0973e75b118425db7e7bfc966e5eb87 ff5195026f8143fea9240d4f21e81981 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:14 of msgid "Received bytes, empty when the peer closed the connection." msgstr "ピアが接続を閉じたときに空のバイトを受信しました。" -#: 7acd066bfa87415094144b0e0c1ea0d4 +#: 7103cfcec26c44999cb5464251ee461c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:1 of msgid "Serve one accepted client until it disconnects." msgstr "接続が切断されるまで、受け入れられたクライアント1人にサービスを提供します。" -#: 53591274f0824492afab6874b284c33e +#: 65f9de7f44774aa6aef81fcbe4dc1c64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:3 of msgid "" "Registers the client, greets it, announces the encryption mode and reads " @@ -1129,8 +1398,8 @@ msgstr "" " messages_dict " "''に移動します。何らかの理由で読み取りループが終了すると、クライアントは「クライアント」から削除され、そのソケットは閉じられます。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 -#: fba3167476a94b62af90bfc4101d1ed6 of +#: 87d5085c31a14ad38b060c48f8cf1262 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 of msgid "" "With ``is_asynic_clients_io`` False (the default) the call blocks and " "owns its thread; with it True the client is served by a coroutine on the " @@ -1141,22 +1410,22 @@ msgstr "" "'' is_asynic_clients_io ''がFalse " "(デフォルト)の場合、コールはそのスレッドをブロックして所有します。Trueの場合、クライアントは代わりにサーバーのイベントループのコルーチンによって提供され、そのコルーチンがスケジュールされるとすぐにコールが返されます。そのモードがオンの間に到着した接続が、イベントループが実行されていない場合、コンソール通知で閉じられます。" -#: 72edaf343723458fb9b2fe0f40bc01b8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 +#: db3915757e2842c8afee97b2d471411e of msgid "Accepted connection." msgstr "接続が承認されました。" -#: 6a2427e7b7de4d609bf61e3fad46b413 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 +#: fae378e888be4821a14ed2483cfde1e0 of msgid "Peer ``(ip, port)``; used as the client id and as the key in ``clients``." msgstr "ピア''( ip, port )'';クライアントIDおよび'' clients ''のキーとして使用されます。" -#: 061015c431a54fafb45ea722ae696003 +#: 32886e2babcf4283924034c600453c4a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:1 of msgid "Dispatch one command line received from a client." msgstr "クライアントから受信した1つのコマンドラインをディスパッチします。" -#: 9cc9ee25bc464440a4ac2bca19e5a413 +#: 8972b8c4edf149fd9a4008832c85ed31 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:3 of #, fuzzy msgid "" @@ -1172,24 +1441,23 @@ msgstr "" "server_file_transfer_port " "''、および暗号交換行)はここで処理されます。その他の名前は、`register_command`を介して\"server\"側に登録されたハンドラに送られます。暗号化モードの不一致は接続を閉じます。不明なコマンドはコンソールでのみ報告されます。" -#: 9a970df310fc4b59b113bb6160f24fd2 +#: 208294924333477a8e7d65aa3130777e #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:10 of msgid "Connection the line came from." msgstr "回線が発信された接続。" -#: 8856eb18fd044b60b869be64e5f4576e +#: 306e5026cfc1441d8c754f0e02866cf3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:12 of msgid "Peer ``(ip, port)``." msgstr "ピア'' (ip, port )''。" -#: 6ea3bacf1baf4eadb98d5e38236ecf90 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:14 -#: e212b51318ea4d46ab6354b818dc262b of +#: a2a3a1fd57e14260a53675457fdff0b4 of msgid "Line including its leading ``/``." msgstr "先頭の''/''を含む行。" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:17 of #, fuzzy msgid "" @@ -1199,11 +1467,11 @@ msgid "" msgstr "そのクライアントの応答、または応答がない場合はなし(バックグラウンドで実行される暗号行、ファイル転送、およびカスタムハンドラ)。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:19 -#: b3f201060ae548098d8284d4c18c0560 of +#: ed04a3bf285b4f57bb6a5de0c4f7284f of msgid "Response for that client, or None when no response is due" msgstr "そのクライアントに対する応答、または応答期限がない場合はなし" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:20 of #, fuzzy msgid "" @@ -1212,12 +1480,12 @@ msgid "" msgstr "(バックグラウンドで実行される暗号行、ファイル転送、およびカスタムハンドラ)。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:1 -#: b4ee832e0ad64d189740b45a297d713d of +#: a784dfdc5ded411d985426e36f6e5435 of msgid "Send one plain message to a connected target, tagged with its origin." msgstr "接続されたターゲットに、その起点でタグ付けされたプレーンメッセージを1つ送信します。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:3 -#: ec8cc922a2ee4e70bdff9a8e81b74e98 of +#: b545977244dc402aa8586264d2d933f3 of msgid "" "Public API for forward extensions: the message is wrapped in a " "``/send_msg_from `` envelope so the receiver can " @@ -1227,102 +1495,96 @@ msgstr "" "''エンベロープでラップされているため、受信者はオリジネーターにアトリビュートできます(' " "parse_forwarded_message `を参照)。" -#: 660b6f4493ec4c9994af44960900cb10 +#: 8ee5275fbf894581ade9e6f30d5d4aff #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:7 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 -#: b8a3838c85624f3dbe705afac78acc47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 of msgid "Destination ``(ip, port)``." msgstr "宛先''( ip, port )''。" -#: 1dfa946975cf4768891292e84a2bbc63 +#: 38ffd8a7079d4794811e3504c01052f8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:9 of msgid "Payload to deliver." msgstr "配達するペイロード。" -#: 09f6b3913160404b9927d5e70252d9bc 5251c2b3867b4dc1b8dd8d09ea570d90 +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:15 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 -#: a8ee713ff78b42bd8adb5743ab369aef of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 of msgid "Originating client ``(ip, port)``." msgstr "発信元クライアント''( ip, port )''。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:14 -#: ad5e4419a1d04b27bec64cf1aee14c53 of +#: d2471a90e269464c977239f406051120 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the envelope was sent." msgstr "''ターゲット''が接続されていない場合はFALSE (コンソール通知が印刷されます)。エンベロープが送信された場合はTRUEです。" -#: 2fd94dad15884a56b9657090a33988f9 9e706f8851a74b569ade8deb4f8f70ab +#: 320d99b8923f4eaa886ffe0a16bfc6d9 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:24 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:16 of msgid "False when ``target`` is not connected (a console notice is" msgstr "「ターゲット」が接続されていない場合はFALSE (コンソール通知は" -#: 59049e3514b74a7ba90fb8886ecca185 +#: 1a97f59b270f404096d9c2b37ab09a8c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:17 of msgid "printed); True when the envelope was sent." msgstr "印刷);封筒が送信されたときにTrue。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 -#: b9019e7dae074d64a66ae1c81967b9b8 of +#: 6baab06dc12e4ecc80d1a16c26c2a19a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 of msgid "Build the tagged wire command that pushes one forwarded item." msgstr "1つの転送アイテムをプッシュするタグ付きワイヤーコマンドを構築します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 -#: fcde926ccf5640b2b2ac6aab009aa4d0 of +#: 0c3f9dcbcf8f413fbd5befefb960c402 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 of msgid "" "Public API for forward extensions. The originator tuple sits before the " "trailing transfer id, where the receiver's existing parsers ignore it and" " `parse_forward_originator` recovers it for attribution." msgstr "フォワード拡張機能のパブリックAPI。発信元タプルは、末尾の転送IDの前に位置し、受信者の既存のパーサはそれを無視し、`parse_forward_originator`がアトリビューションのためにそれを回復します。" -#: 3cee0d37a9e5460a90b7c9b1abe53a92 +#: 3cf58937a2d04172bf544119279d85c1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 -#: d5cb9e15787a435ab586217498d98e2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 of msgid "\"file\" or \"file_folder\"." msgstr "\"file\"または\"file_folder \"。" -#: 8efbb4663727491e8ee77edc824ce1c0 +#: 621a93603c8549c0ba047bee6aae5a38 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 -#: e8aeb2b89d5f4969aeaf2244f06a1a47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 of msgid "Relative folder path (folders only)." msgstr "相対フォルダーのパス(フォルダーのみ)。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:13 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:11 -#: b439157e6df44d7bac2a4367c5fb66ee b9cb86fb0ad642e18ec19debb44a2648 of +#: f0f56fb642874c3889fb0dacfed4f4ef of msgid "File or folder name." msgstr "ファイル名またはフォルダー名。" -#: 5f249d30e8934ed0ae07c1ca2666c6c6 +#: 72d2b6fdd324482eaea9803def1fe2da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 -#: df45d1036cb9437a853551afb3f31775 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 of msgid "Transfer id shared by the pushed item." msgstr "プッシュされたアイテムによって共有された転送ID。" -#: 9bc7aaf1a36a4311a736f5528525d33a +#: 0aa1bd5b053544e98ae4ab3ae1add5f7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:19 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 -#: f806614c8aeb428292d6ca51db8ca35b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 of msgid "Receiver-side destination directory." msgstr "受信側の宛先ディレクトリ。" -#: 1f3c679edcf34e71a946e8668ca27a58 +#: 93e666db45e745619b90c744e1646b73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:20 of msgid "Command line to hand to `send_message`." msgstr "`send_message`に渡すコマンドライン。" -#: 3499106d953f41789e53f24bfcae3af5 +#: 56d8327bb7414a5e85292f8f2ace9d42 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:1 of msgid "Push one forwarded file or folder item to a connected target." msgstr "1つの転送されたファイルまたはフォルダアイテムを接続されたターゲットにプッシュします。" -#: 959c24d8afff4486ad5f787311bf3c8b +#: 3098afa7f4ac43a184d081dda8faa6ba #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:3 of msgid "" "Public API for forward extensions: sends the line built by " @@ -1332,24 +1594,160 @@ msgstr "" "フォワード拡張のパブリックAPI " ":レシーバーが'parse_forward_originator`で属性指定する`forward_target_command`によって構築された行を送信します。" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 -#: cb11d22918824fb09fa82fd432aeb74a of +#: 9b9634061040430484cd2596f43a8feb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the command was sent." msgstr "「ターゲット」が接続されていない場合はFALSE (コンソール通知が印刷されます)。コマンドが送信された場合はTRUEです。" -#: 66262977fc014465964289448673a5b9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 +#: b8bb8c432f7649d5a35480fec0509a51 of msgid "printed); True when the command was sent." msgstr "print);コマンドが送信されたときにTRUE。" -#: 1df1cd85678d4149bdac92c3591c9e50 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:1 of +msgid "Receive one file over a transfer sub-connection." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:3 +#: d3367c6f97aa4bf4b9cb3d79b3117fce of +msgid "" +"``peer`` is the transfer's original sender (the sender for an inbound " +"transfer, never a relay): it is stored with the progress entry so a later" +" reconnect can ask that peer to continue the file." +msgstr "" + +#: 5c4faf52e8bb4808805bae58d30ac0cc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:7 +#: de641d48c530435bb4adc04755a47a6d of +msgid "" +"``resume_entry`` continues an interrupted transfer: the listener " +"announces itself, asks the sender to continue from the bytes already on " +"disk (``RESUME_LINE``) and appends the incoming chunks to the partial " +"file instead of truncating it." +msgstr "" + +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:1 of +msgid "Send one file over a transfer sub-connection." +msgstr "" + +#: 87862abb10ad423f820952355f5936bc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:3 +#: d6a618c007ec433fa10a44b0a7a90fe4 of +msgid "" +"``control_socket``/``crypto`` carry the listener's mode stamp (\"plain\" " +"or \"enc:\"): an encrypted leg aborts when the session key " +"material is missing rather than downgrading silently." +msgstr "" + +#: 97e1a0538f544c2a8e755c78805fda7c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:7 +#: a405431dfd62434b82c7052edc456123 of +msgid "" +"``fid`` is the transfer's id — the caller's own transfer id for a plain " +"send, the relay id for a forwarded upload — and keys this leg in " +"``file_upload_progress``; every leg with a fid can be paused with " +"``/pause_trans`` for that fid. None (a leg without a protocol transfer " +"id, such as a public-key push) tracks no progress." +msgstr "" + +#: 6cb58bfd1dde4b49ba3525af014e44c7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (never a relay): it is " +"stored with the progress entry so a later reconnect can be resumed. " +"``resume_offset`` continues an interrupted transfer from the byte the " +"receiver already holds: the file is read from there instead of its first " +"byte." +msgstr "" + +#: 1634dbe84a95421a92a660f7c6fdd10e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:1 of +msgid "Continue the interrupted transfers of a peer that is back." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:3 +#: eb46142fa4e44147ad3ad8c680d5bee0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and, for " +"every download this instance was receiving from ``peer``, opens a fresh " +"transfer listener and asks the sender to continue the file from the bytes" +" already on disk. Restored uploads need no action here: the peer drives " +"their resume from its own side." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:9 +#: b7d54977ca494a8b9968365dffd9bd3d of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer that is " +"connected right now." +msgstr "" + +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:13 of +msgid "Number of resumed receive legs started." +msgstr "" + +#: 52cb873f015542b6a94506cebfe735a1 737ed182911443bc8cfff3c4d094b9a9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:1 of +msgid "Continue one interrupted transfer this instance was sending." +msgstr "" + +#: 50f292ac853841c9b082eb3c3ff4d6f4 6c968a5b77b342ed891883336cfcc255 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:3 of +msgid "" +"Runs when a receiver asks to continue a transfer (``/resume_trans``, see " +"`resume_transfers` on the receiving side): the leg is re-established " +"against the receiver's fresh listener and the source file is read from " +"the byte offset the receiver already holds. Also the public API for " +"resuming one transfer on demand." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:9 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "Receiver ``(ip, port)`` the request came from; None skips the peer check." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:12 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:12 of +#, fuzzy +msgid "Transfer id of the interrupted transfer." +msgstr "プッシュされたアイテムによって共有された転送ID。" + +#: 7124e1ce01df4fcea9516bed4ca55dc7 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:14 +#: d94da1700d0e46028f7bf114d7c5da62 of +#, fuzzy +msgid "Byte offset the receiver already holds." +msgstr "レシーバースレッドを終了します。" + +#: 1a97f59b270f404096d9c2b37ab09a8c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:17 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:17 of +#, fuzzy +msgid "True when the resume leg was started." +msgstr "印刷);封筒が送信されたときにTrue。" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 +#: b03f4edeca5f4cc19f6d695aac3690de of msgid "Bind the server socket, then accept clients until `stop` runs." msgstr "サーバーソケットをバインドし、「停止」が実行されるまでクライアントを受け入れます。" -#: 42bb4623926449f5b91a451bcac30a2f +#: 7e027ea659ab48e19ea346cb284fe144 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:3 of msgid "" "Blocks the calling thread. A console command thread is started when " @@ -1364,12 +1762,12 @@ msgstr "" " is_asynic_clients_io ''がTrueの場合、asyncioイベントループのコルーチンによって提供されます。この場合、'' " "max_clients ''は接続数を制限しなくなります。ソケットエラーとアクセプトループの終了は、どちらも`stop`で終了します。" -#: 3d3320ce03544f23ac6f43883e5a580c +#: 291f5a8cc4f648ee9910e5cd45074675 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:1 of msgid "Read console commands until the server stops." msgstr "サーバーが停止するまでコンソールコマンドを読み取ります。" -#: 5f7369176edb4567b3eb5332588b8c57 +#: 1ba2e428d432496688ef23f1c07562da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:3 of msgid "" "Handles ``/stop``, ``/status``, ``/clients``, ``/send_msg``, ``/file``, " @@ -1386,12 +1784,12 @@ msgstr "" "\"''に登録されたハンドラーに送られます。Ctrl - CキーとEOFキーでサーバーを停止します。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:1 -#: ccbb242b51984c9f8ce9fb519c202485 of +#: eb90f49c77e64006a0c9ae861ff849b1 of msgid "Stop the server and release everything it owns." msgstr "サーバーを停止し、所有しているすべてを解放します。" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:3 -#: e379bbd3f7b249c6b296f371548a5b1e of +#: a059b1e71106487999c83c2e2042f509 of msgid "" "Closes the server socket and every client connection, flushes the message" " and event stores, releases the allocated port range, clears ``running`` " @@ -1399,23 +1797,25 @@ msgid "" " Safe to call more than once." msgstr "サーバーソケットとすべてのクライアント接続を閉じ、メッセージとイベントストアをフラッシュし、割り当てられたポート範囲を解放し、「実行中」をクリアし、「is_asynic_clients_io」がTrueの場合にクライアントイベントループを解放します。複数回電話しても大丈夫です。" -#: 06fe9e3a48914447af6464acedea1fa0 +#: 32b06ea315b3404caa3a05c4aed0ce64 #: PyFlow.network_api.connect_tcp.TCP_Client_Base:1 of msgid "" "TCP client: connect to a server, dispatch commands, send and receive " "messages." msgstr "TCPクライアント:サーバーに接続し、コマンドをディスパッチし、メッセージを送受信します。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 -#: ef04371450674badb666b7fb31c203da of +#: 2b30f5c9ecd24fc89cdcd58000ee1e99 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 of +#, fuzzy msgid "" -"Lines received from the server go through `receive_messages`: a line " -"starting with ``/`` is handled by `handle_server_command` (protocol " -"commands plus the handlers registered for the \"server\" side), any other" -" line is a plain message delivered to the listeners registered with " -"`add_message_listener` and stored in ``messages_dict``. With " -"``is_input_command_in_console`` the console thread `interactive_mode` " -"sends typed lines to the server." +"Lines received from the server go through `receive_messages`: every line " +"is delivered to the listeners registered with `add_message_listener` " +"first (commands included; a forwarded ``/send_msg_from`` envelope is " +"delivered as its payload), then a line starting with ``/`` is handled by " +"`handle_server_command` (protocol commands plus the handlers registered " +"for the \"server\" side), any other line is stored in ``messages_dict`` " +"as a plain message. With ``is_input_command_in_console`` the console " +"thread `interactive_mode` sends typed lines to the server." msgstr "" "サーバーから受信した行は`RECEIVE_MESSAGES`を経由します。''/''で始まる行は'handle_server_command " "'(プロトコルコマンドと\"server\"側に登録されたハンドラー)によって処理されます。その他の行は、` " @@ -1423,108 +1823,133 @@ msgstr "" "''に格納されているリスナーに配信されるプレーンメッセージです。'' is_input_command_in_console " "''を使用すると、コンソールスレッド` interactive_mode `は入力された行をサーバーに送信します。" -#: 840ff55e5e444cfbb85251e9c4123178 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:12 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 +#: b9532c86786c43d5aea58b24157fefed of msgid "Server address this client connects to." msgstr "このクライアントが接続するサーバーアドレス。" -#: 1f65ef8a745743ebb31ebc5805c5b02f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:18 of +#: 2cfa1e3e1674407ba1e2683e76fef65d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 of msgid "Server port this client connects to." msgstr "このクライアントが接続するサーバーポート。" -#: 5956a034ca2347f384f682b52d927ee3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:24 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: af04fdee2c95431a9b0c17f96e50c18c of msgid "Local address the socket binds to." msgstr "ソケットがバインドするローカルアドレス。" -#: 1d2b7be8ff994d15b9a3f63c0e4fab11 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:30 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 +#: b1d4b5606e1c48b6a915815527542758 of msgid "Local port, None when the OS chose one." msgstr "ローカルポート、OSが1つを選択した場合はなし。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 -#: d616019e80a741638b6ac020d6abb336 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:34 +#: d926b4f3eb4b40a4acb21f780a4dc227 of msgid "int | None" msgstr "int |なし" -#: 0a015a4f44194fe2b25bbd4dfe52d1eb -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:36 of +#: 500cfd177cf5453d887f6904b73b7851 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 of msgid "True while the connection is up." msgstr "接続が確立している間はtrueです。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 -#: da7ca1204aea47779bbaaa809f79da93 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:76 +#: fd832e1d72b642838382d529c3e1f22c of +msgid "" +"Whether `start_TCP_client` reconnects after the connection drops (and " +"resumes the interrupted transfers)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:102 +#: c194bbee7cf14d268c330e06f94ae973 of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when the connection drops and read back on the next reconnect " +"(`resume_transfers`)." +msgstr "" + +#: 40f2a9e1b730422db3dd58bc2a6046e3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 of msgid "Create the client and, unless extended, connect and start reading." msgstr "クライアントを作成し、拡張されていない限り、接続して読み始めます。" -#: 9e0577d19b76432089a46a53a2bbf7be +#: 0552aa36b7b74474af8f43b380dbee54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:3 of msgid "Server address to connect to; required before `connect` is called." msgstr "接続先のサーバーアドレス。`connect`が呼び出される前に必要です。" -#: 8400b2487cfb4cff8a72f452e3b4c83e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 +#: d246ff9aaf154bfa91b5c4c9d293afd5 of msgid "Local address the socket binds to. Defaults to \"127.0.0.1\"." msgstr "ソケットがバインドするローカルアドレス。デフォルトは「127.0.0.1」です。" -#: 7cb2047b830c4996832b4623812a687b -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 +#: e981b68ebbea46e9b556b09f4b5cd44a of msgid "Server port. Defaults to 65432." msgstr "サーバーポート。デフォルトは65432です。" -#: 7a0404b673f84a1191af5479097f8cf5 +#: 766bf4c138234fe081bbd2668dcb2a5d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:11 of msgid "Local port to bind; None lets the OS choose an ephemeral port." msgstr "バインドするローカルポート。OSが一時的なポートを選択できるようにするものはありません。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 -#: df784379acc1474aba6566c969dbb7bc of +#: 5d661c0f91f64ef39cacb1a5466d752c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 of msgid "" "Socket timeout in seconds for connect and receive. Must be None when " "``is_wait_server`` is True." msgstr "接続と受信のための秒単位のソケットタイムアウト。'' is_wait_server ''がTrueの場合、Noneにする必要があります。" -#: 2b8bf92e3eb049ee8e994aa8b6d92fa5 +#: 9478d02062284ecaa7838f931ab80780 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:17 of msgid "Step between candidate ports in the allocation range. Defaults to 1." msgstr "割り当て範囲内の候補ポート間のステップ。デフォルトは1です。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 -#: fa74d746eefe4cb6862068fdbf384dd8 of +#: 2e1695ae510b43758793257124fd23c2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 of msgid "Enter interactive mode after connecting. Defaults to True." msgstr "接続後、インタラクティブモードに入ります。既定値はTrueです。" -#: 95ebbc90f84a41ada4b6edbec2c7a95e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 +#: e02da86957dd4f45bf84ede4e9c82cda of msgid "Keep retrying while the server is not reachable. Defaults to True." msgstr "サーバーに到達できない間、再試行を続けてください。既定値はTrueです。" -#: 259f9e8d0d1547ae81e047e8ec24875d -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 +#: e1fb7f67e1714a61a9e8fe500555c700 of msgid "" "When True, do not call `start_TCP_client`; the caller connects when " "ready. Defaults to False." msgstr "Trueの場合、`START_TCP_CLIENT`を呼び出さないでください。発信者は準備ができたら接続します。デフォルトはFalseです。" -#: 794bfe7ef8594729b0e87230d3ed9e49 +#: 1634dbe84a95421a92a660f7c6fdd10e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:34 of msgid "Negotiate the RSA-encrypted channel with the server. Defaults to True." msgstr "RSA暗号化チャネルをサーバーとネゴシエートする。既定値はTrueです。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:40 -#: e3f9232109d34798af1f681b250ec7d5 of +#: cff66a7ac1ad410f96ed1ee03cb1cf53 of msgid "" "Buffer ceiling in MiB, kept for parity with the server class; the " "client's forward path does not read it today. Defaults to 2048." msgstr "サーバークラスとのパリティのために保持されるMiB単位のバッファ上限。クライアントのフォワードパスは今日それを読み取りません。デフォルトは2048です。" -#: 71b662106e594538b8a5fcb9bc190b1f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:51 of +#: 14c4889553fb42f7b0393a4a7ab46b4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:72 of +msgid "" +"Reconnect (and resume the interrupted transfers, see `resume_transfers`) " +"when the connection drops while `start_TCP_client` runs. The transfers " +"that died with the connection are persisted to the protocol's ``.Flow`` " +"directory and read back on the next connect. Defaults to False: a dropped" +" connection ends the client." +msgstr "" + +#: 0f06ff3b6db940da96ec09bee3dba526 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:80 of msgid "If ``is_wait_server`` is True and ``timeout`` is not None." msgstr "'' is_wait_server ''がTrueで、'' timeout ''がNoneでない場合。" -#: 4388cbc6302341adbdfa566d93526ef1 +#: 5dd677b9627d4b84b53dc7a6b2848b3f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:6 of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " @@ -1533,7 +1958,7 @@ msgstr "" "'' handler (client_socket, client_address, command " ")''が生行で呼び出されました。None以外の戻り値が応答として返されます。" -#: 14fcd0c8f3554ae983ac746cf3e58621 +#: 0a57a7875bb94767904ff8d93fa77eb8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:10 of msgid "" "\"server\" for commands pushed by the server, \"client\" for commands " @@ -1542,18 +1967,33 @@ msgstr "" "サーバーによってプッシュされたコマンドの場合は\"server \"、このインスタンスのコンソールに入力されたコマンドの場合は\" client " "\"。" -#: 88087ef71067485dbd40d569a7b950d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:3 +#: acb1af86a6184624a47ac6cc3b7127d0 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines the server " +"sends. The handler runs on the calling thread — ``run_in_thread`` only " +"affects the console and inbound dispatch paths — and is called with this " +"client's socket and id, the context its dispatch paths give it." +msgstr "" + +#: 876e8fe2a6d645829ba12ddbad5006df #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:1 of -msgid "Register ``listener(sender_id, message)`` for every inbound plain message." +#, fuzzy +msgid "Register ``listener(sender_id, message)`` for every inbound line." msgstr "すべての受信プレーンメッセージに'' listener (sender_id, message )''を登録します。" -#: 50556c2d788d4e39a4a7cfed81ef6d6d +#: 2658650e027a4697b248f261903a4e29 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:3 of -msgid "Mirrors the server-side contract; commands are not reported here." -msgstr "サーバー側の契約をミラーリングします。ここではコマンドは報告されません。" +msgid "" +"Every line received from the server is reported, commands included, so " +"the listener observes all inbound traffic; a message another client " +"forwarded here is reported as its payload, attributed to the forwarder." +msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:5 -#: e6bec65449634cff953afd74d0e23e7a of +#: 412834182c9442adaf0b85e24c200ccc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:7 of msgid "" "``listener(sender_id, message)``; ``sender_id`` is the author's " "``\"ip:port\"`` — the forwarding client for a message another client " @@ -1566,15 +2006,15 @@ msgstr "" "\"'' —ここで転送された別のクライアント(''/ send_msg_from " "''エンベロープ)のメッセージの転送クライアント、またはクライアント作成者の名前がないサーバーからの直接プッシュのNoneです。受信スレッド上で実行されるため、ブロックしてはならず、内部で発生した例外は飲み込まれます。" -#: 38c576fe994b4a77830eaba36ca063b3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 +#: fc8a83e0b5f84273a8287b122c1a9a3e of msgid "" "Register ``listener(full_path, name, size, command)`` per saved inbound " "file." msgstr "保存されたインバウンドファイルごとに'' listener (full_path, name, size, command )''を登録します。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 -#: e258540084d64816a08e0783810c4e3e of +#: 34e3386853564aab9a824e96438fc3e5 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 of msgid "" "Fired after a file pushed by the server (a direct send, or a forwarded " "file/folder item) has been fully written to ``file_transfer_dir``." @@ -1582,7 +2022,7 @@ msgstr "" "サーバーによってプッシュされたファイル(ダイレクト送信、または転送されたファイル/フォルダアイテム)が'' file_transfer_dir " "''に完全に書き込まれた後に発生します。" -#: 4e10b4a74e9142e0868ab1b0b423f359 +#: 63f925709b83433e967610672b6fbc79 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:6 of msgid "" "``listener(full_path, name, size, command)``; ``command`` is the wire " @@ -1594,115 +2034,202 @@ msgstr "" "''は転送をトリガーした配線コマンドであるため、リスナーは''/ crypto_pub_key " "''などのプロトコルプッシュを認識できます。転送スレッド上で実行されるため、ブロックしてはいけません。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 -#: afdf1e13067b4914a6aead736d7604e3 of +#: 4bc88415dfff40a3884ee0284b0ccc3f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. This " +"covers every outgoing transfer — a plain upload as much as a forward " +"upload — and is what the ``/pause_trans`` line does when it arrives from " +"a peer." +msgstr "" + +#: 7e190ff27df349ae90eb7bd98a0b6b5b +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:11 of +msgid "" +"Restrict the pause to the leg whose original receiver is this ``(ip, " +"port)``; None pauses whichever leg holds the fid." +msgstr "" + +#: 5479763134c04a418df6a9e5011a9dcf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:16 of +msgid "" +"True when a running leg was marked paused; False when nothing matched" +" — the switch is still armed, so a leg started later under this fid " +"starts paused." +msgstr "" + +#: 2bc5d7e5dfa94eb29b49f12562f57c88 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:18 of +#, fuzzy +msgid "True when a running leg was marked paused; False when" +msgstr "要求がサーバーに書き込まれた場合はTRUE、要求がサーバーに書き込まれた場合はFALSE" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:19 +#: a9c7cb3036f8409faad4c1db964d8a91 of +msgid "" +"nothing matched — the switch is still armed, so a leg started later under" +" this fid starts paused." +msgstr "" + +#: 59fa8126f08348bb9368c35b5d2336e2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg whose original receiver is this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:9 of +msgid "True when a running leg was resumed." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:1 of +msgid "Ask the server to pause its transfer toward this client." +msgstr "" + +#: 89fa1c905614496ea12a4cfde9eb3cce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:3 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (a forwarded upload this client relays is throttled this way)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:3 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "The server's ``(ip, port)``; None accepts the connected server." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:6 of +msgid "Transfer id of the server's outbound leg." +msgstr "" + +#: 39423e052b70403ba07a713aa9e3cb4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:12 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:9 of +#, fuzzy +msgid "True when the line was written." +msgstr "印刷);封筒が送信されたときにTrue。" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:1 of +msgid "Ask the server to resume a transfer paused earlier." +msgstr "" + +#: 0e91f82d8856443497c399f97643b757 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 of msgid "Reserve this client's port range under the cross-process lock." msgstr "クロスプロセスロックの下でこのクライアントのポート範囲を予約します。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 -#: cd973d56799848ecbd65c434c9f5f0ae of +#: 6029a28126344e45b24394cb56b2f8f8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 of msgid "No-op until the server assigns a range (see ``/client_alloc_port_range``)." msgstr "サーバーが範囲を割り当てるまで操作しません(''/ client_alloc_port_range ''を参照)。" -#: 29e4db224e2d4208a5fc08a1523f9e6b +#: 32bed401c3574959ba5ed08fc9078401 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:1 of msgid "Release this client's reserved port range." msgstr "このクライアントの予約済みポート範囲を解放します。" -#: 7b0f2f6530984dcc888286f471f14747 +#: 9f86b7aac4f44886be9cd87b56072b63 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:3 of msgid "No-op unless a range was assigned (``is_hand_alloc_port`` True)." msgstr "範囲が割り当てられていない限り、操作はありません('' is_hand_alloc_port '' True )。" +#: 8154f96d9ec74bd588971a806d42f8c1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_lock:1 -#: c6e04e800074445da45886940c77a9f8 of +#: of msgid "Create the lock file that reserves the client port range for this process." msgstr "このプロセスのクライアントポート範囲を予約するロックファイルを作成します。" -#: 2c7b09854c254d0bbfa62d2a356cfb24 +#: 69c2dd5d5d1d497c8bac1e62ab4fc30a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:1 #: of msgid "Report whether the client port range is reserved by some process." msgstr "クライアントポート範囲が何らかのプロセスによって予約されているかどうかを報告します。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_unlock:1 -#: b2cbf44d95154896ab2df64bf8be1a3d of +#: c88f37ef2d5c47bda346e804508d6ec0 of msgid "Remove the lock file that reserves the client port range." msgstr "クライアントポート範囲を予約するロックファイルを削除します。" -#: 690717115cb64dfeb32f56302992451c +#: 478443e187814a6ca7ad798277db023f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:1 of msgid "Allocate the next free client port range and record it on disk." msgstr "次の空きクライアントポート範囲を割り当て、ディスクに記録します。" -#: 2e8d17873f8b4b419f2f6cd1f2000a62 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 +#: a8736540f4c3402fad9508e619d559d7 of msgid "" "``port`` is moved past the ranges already recorded by other clients on " "this host, so each instance ends up with a range of its own." msgstr "'' port ''は、このホスト上の他のクライアントによって既に記録されている範囲を超えて移動されるため、各インスタンスは独自の範囲で終了します。" -#: 2d7cb151d3bc4798914cbe3d73391c16 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 +#: bc44b1604e02467280b59cb8ad63d0af of msgid "If the client port info file cannot be read or written." msgstr "クライアントポート情報ファイルを読み書きできない場合。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_free_port:1 -#: b6079f909975409c86477341dcf2990c of +#: e48dff576a074109a135db168b5dbe98 of msgid "Drop this client's entry from the on-disk port range record." msgstr "このクライアントのエントリをディスク上のポート範囲レコードからドロップします。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 -#: c7fc083bff234cb7b377bc7adbb65ca5 of +#: 3aa62e8843c6495c862f43fc6dda9d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 of msgid "Allocate a port, waiting until one is free." msgstr "ポートを割り当て、空きがあるまで待ちます。" -#: 85129bb5393542e498835f3ba6dc981a +#: 2f7752fa51d946b1a4a566b38f046e80 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:3 of msgid "Allocated port, or 0 when no allocation range was assigned." msgstr "割り当てられたポート、または割り当て範囲が割り当てられていない場合は0。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 -#: e77dc25d62bc4eedbd153b7420d109f4 of +#: 503ab40fc32c4d548f65fa3272b2f4d2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when no " "allocation range was assigned." msgstr "割り当てられたポート。上限範囲が枯渇した場合はなし。割り当て範囲が割り当てられていない場合は0。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:5 -#: c452f87d6e18446cbbb2f48b1dc47b9b of +#: b9fd549c95f24c2080d87cec92514db6 of msgid "Allocated port; None when the upward range is exhausted; 0 when no" msgstr "割り当てられたポート。上向きの範囲が排出された場合はなし。なしの場合は0" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 -#: e195a16298f14417b95ed3dc3ad60fac of +#: 151a65f1c1984e4196c750108d0611cb +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 of msgid "allocation range was assigned." msgstr "割り当て範囲が割り当てられました。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 -#: f7330894d1a041ca9a31ca1b390d5af7 of +#: 0c6201bb2d7e45d3a4916d7e50a21e10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when no " "allocation range was assigned." msgstr "割り当てられたポート。ダウンワードレンジが排出された場合はなし。割り当て範囲が割り当てられていない場合は0。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 -#: a8d7d910fb874925acb423d08187908d of +#: 76c766a9c61f4075a762ccf55038a65e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 of msgid "no allocation range was assigned." msgstr "割り当て範囲が割り当てられていません。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 -#: c76dd143ea224bb69081222ac4228f8f of +#: 8d500513e8854ba4bb91c8905a9adb73 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 of msgid "Local port to bind; None allocates one with `palloc`." msgstr "バインドするローカルポート。Noneは`palloc`を持つポートを割り当てます。" -#: 5a8b77d5b1e243d9b5b24039b6ff25d0 +#: 840360623c8a4c2bbafe8fe7bbf9209c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:1 of msgid "Connect to the server and start reading from it." msgstr "サーバーに接続し、読み取りを開始します。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:3 -#: b59d15dc7c7844a5bd0226eb081c9887 of +#: df94288e660b48f6809358b3dc234ec9 of msgid "" "Binds ``client_port`` when one was configured, then retries while " "``is_wait_server`` is True and the server is not reachable yet. Once the " @@ -1712,7 +2239,7 @@ msgstr "" "設定されているときに'' client_port ''をバインドし、'' is_wait_server " "''がTrueでサーバーにまだ到達できないときに再試行します。ソケットが起動すると、受信スレッドが開始され、暗号化モードがネゴシエートされ、両者が合意しない場合に接続が閉じます。" -#: 8711ef70ac704a48b05e13ded3546471 +#: 22fccba0ab36499a9a7f4427abe5e9f4 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:8 of msgid "" "True when the connection is established (and, if encryption is " @@ -1722,13 +2249,13 @@ msgstr "" "接続が確立された場合はtrue " "(暗号化が有効になっている場合は、キー交換が開始されています)。試行が失敗した場合、またはモードネゴシエーションが接続を閉じた場合はfalseです。" -#: 850616ca4a614020b9627a3c39a54555 +#: 0270d0a2d42740a9889106339d9f2dbb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:10 of msgid "True when the connection is established (and, if encryption is" msgstr "接続が確立されたときにtrue (および、暗号化が" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:11 -#: cd0e7073f18d4d2ba990f1bfda735fd4 of +#: c194691cedfb48c6bfd97d9bdc6f2246 of msgid "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." @@ -1736,85 +2263,89 @@ msgstr "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 -#: b7b9e013f50348379a0208a7702b9b1f of +#: 4dc38e3ef3b74b8e8c27378242a1925a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 of msgid "Read from the server until the connection ends." msgstr "接続が終了するまでサーバーから読み取ります。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 -#: ae819668995f44878eaa9c4a8db02583 of +#: 431649a0d703476dadc6afa8adbe53d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 of +#, fuzzy msgid "" -"Runs on the receive thread: plain lines are reported to the message " -"listeners and stored in ``messages_dict`` (``/send_msg_from`` envelopes " -"are attributed to their sender first), other ``/`` lines go to " -"`handle_server_command`. Any end of the connection clears ``running`` and" -" releases the port range." +"Runs on the receive thread: every inbound line is reported to the message" +" listeners (commands included); a plain message is also stored in " +"``messages_dict``, while a ``/send_msg_from`` envelope is reported and " +"stored as its payload attributed to the forwarding client, and other " +"``/`` lines additionally go to `handle_server_command`. Any end of the " +"connection clears ``running`` and releases the port range." msgstr "" "受信スレッドで実行:プレーンラインはメッセージリスナーに報告され、'' messages_dict ''に格納されます(''/ " "send_msg_from " "''エンベロープは最初に送信者に帰属します)。他の''/''行は'handle_server_command`に移動します。接続のいずれかの端は、「実行中」をクリアし、ポート範囲を解放します。" -#: 32feafb4504a473dbbe6b0957d3658f0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 +#: cf284b59f7f849039404ced20f8e12db of msgid "Write one line to a socket, encrypting when the channel is up." msgstr "1行をソケットに書き込み、チャネルが起動したときに暗号化します。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 -#: c639152d8792432ba220c33c860f1211 of +#: 40ba2ede2d3f4666b82107af129d24d0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 of msgid "Target connection; the client passes ``self.client_socket``." msgstr "ターゲット接続。クライアントは'' self.client_socket ''を渡します。" -#: 5b421459787b4210b8bce3e7003cf35b +#: 2e663941eaf142cb96738add05f9ef4d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:10 of msgid "" "True when the payload was written; False when the client is not " "running, no socket was passed, or the payload type is unsupported." msgstr "ペイロードが書き込まれた場合はtrue。クライアントが実行されていない場合、ソケットが渡されていない場合、またはペイロードタイプがサポートされていない場合はfalse。" -#: 1684a06aa826439784ce149aece2f637 +#: 38905ec7539d42e0839907c32dd8667f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:12 of msgid "True when the payload was written; False when the client is not" msgstr "ペイロードが書き込まれた場合はTRUE、クライアントがそうでない場合はFALSE" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 -#: bc5ff108fa3d46afb45fd86d4106ac2f of +#: 3f7e2e6fedda476f996132c3f677f2f0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 of msgid "running, no socket was passed, or the payload type is unsupported." msgstr "実行中、ソケットが渡されていない、またはペイロードタイプがサポートされていません。" -#: 3b27239d40244e35817e0806e3363df0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 +#: a9220a130e694e0aba1d3b6320dff498 of msgid "Send the payload of a console line to the server." msgstr "コンソール回線のペイロードをサーバーに送信します。" -#: 66bc43727101429bacd6a76534c53f7b +#: 2e208e83a89e4dac9793460a8808a042 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:3 of msgid "" "Console line such as ``/send_msg hello``; the first token (the command " "name) is dropped and the second one is sent." msgstr "''/ send_msg hello ''のようなコンソールライン。最初のトークン(コマンド名)がドロップされ、2番目のトークンが送信されます。" -#: 4cb6da8a7d464be983bf467e65fe55b0 +#: 39c8e70ca92b43b8ac687bc0aa7f4073 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:7 of msgid "If the line has fewer than two tokens." msgstr "ラインのトークンが2つ未満の場合。" -#: 369743f21d0f4656aa801c8f29b4129b +#: 8d47f30ae7b0451f8ecfe207ec835ff3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:1 of msgid "Read up to ``msg_length`` bytes from a socket." msgstr "ソケットから最大'' msg_length ''バイトを読み取ります。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 -#: f6749336c57b4a82b5c0b19f27bd8906 of +#: 10a39005f45c46728ef9a000eeaf9109 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 of msgid "Dispatch one command line pushed by the server." msgstr "サーバーによってプッシュされた1つのコマンドラインをディスパッチします。" -#: 510b3d71451048138e11fe92fdb160b4 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 +#: a7e781fde939475cb081204adac16ded of +#, fuzzy msgid "" "Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the" " connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange " "lines, and the transfer lines ``/file``, ``/file_folder``, " -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, " +"``/start_trans``, ``/resume_trans``, ``/forward_resume`` and " "``/forward_error``. Any other name goes to the handlers registered for " "the \"server\" side via `register_command`; an unknown command is only " "reported on the console." @@ -1825,12 +2356,12 @@ msgstr "" "''、''/ forward_error " "''。他の名前は、`register_command`を介して\"server\"側に登録されたハンドラに送られます。不明なコマンドはコンソールでのみ報告されます。" -#: 7724aab357eb408dbbf018c214f8eba0 +#: 91942d88960c4793b5eab8c3654c1400 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:1 of msgid "Forward plain messages to other connected clients through the server." msgstr "プレーンメッセージをサーバーを介して他の接続されたクライアントに転送します。" -#: 12403f5be7704258849974d103865b9c +#: 75bb9147a7464a278e19af9d03b04ecb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:3 of msgid "" "The console command ``/forward_send_msg`` uses this; the client must be " @@ -1841,40 +2372,40 @@ msgstr "" "''はこれを使用します。クライアントは接続されている必要があります。サーバーは各メッセージを''/ send_msg_from " "''エンベロープでラップし、受信クライアントがこのメッセージにアトリビュートできるようにします。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 -#: fc0907a1c7484f66a7b2cc1a99d24dc0 of +#: 0f3c201936df45b687dc5532531b4a4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 of msgid "Message texts to forward." msgstr "転送するメッセージテキスト。" -#: 8d07efc16f6c45d7b9d1d4f85f945317 +#: 277bbcb2143943b5b983badb00c3f4fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:9 of msgid "Destination ``(ip, port)`` tuples." msgstr "宛先''( ip, port )''タプル。" -#: 4afafed2326a42e391e3b098cfea4f06 +#: 5ea8eea489fc43108a439d54fba31068 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:12 of msgid "" "True when the request was written to the server; False when the " "client is not connected." msgstr "要求がサーバーに書き込まれた場合はTRUE。クライアントが接続されていない場合はFALSE。" -#: 85c761742fa5450f846373591e4af1ff +#: 2bc5d7e5dfa94eb29b49f12562f57c88 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:14 of msgid "True when the request was written to the server; False when the" msgstr "要求がサーバーに書き込まれた場合はTRUE、要求がサーバーに書き込まれた場合はFALSE" -#: 6ae9ff84b7d64c30abd31cde1715b783 +#: 45d974ad946b408b91d41bcce65abcc8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:15 of msgid "client is not connected." msgstr "クライアントが接続されていません。" -#: 7b79bd0e677c42fd921308a34e9a0929 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 +#: c9401da7c37e40e5978c80e4876b11a0 of msgid "Read console lines and act on them until the client stops." msgstr "コンソールラインを読み取り、クライアントが停止するまでそれらに対応します。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 -#: d91a5c812cdb4705a2fa27ac33ef693a of +#: 793bcfd02c014200b0ec47f8e15b4d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 of msgid "" "``/quit`` closes the connection; ``/send_msg``, ``/file``, " "``/multiple_file``, ``/file_folder``, ``/multiple_file_folder``, " @@ -1889,38 +2420,78 @@ msgstr "" "where_to_run =\" client \"''に登録されたハンドラーに送られ、残りはそのままサーバーに送信されます。Ctrl - " "CキーとEOFキーで接続を閉じます。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 -#: dc2c54034ec64b61a3af655e86bc81a2 of +#: 7ba721f9d59742b99e89e3b6e249e754 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (the target of a forward, " +"never the relay): it is stored with the progress entry so a later " +"reconnect can be resumed. ``resume_offset`` continues an interrupted " +"transfer from the byte the receiver already holds: the file is read from " +"there instead of its first byte." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:3 +#: a3c59554b8de41b280df7536b307bed0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and drives " +"every download that can be continued: a file the server was sending is" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:6 +#: fae378e888be4821a14ed2483cfde1e0 of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer the " +"client can reach." +msgstr "" + +#: 48061103ed9d4bcaae8a8a837b363557 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:10 of +msgid "Number of resumed transfers started or requested." +msgstr "" + +#: 6dbae803a56c442588b28af664b7a0e9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 of msgid "" "/forward_file ... ... [dest] (client " "only)." msgstr "/forward_file ... ... [dest ](クライアントのみ)。" -#: 303ae7e9e20444e38b303177bef0fb36 +#: 05cad8b03e0747dc804ffbfda3122fe1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_folder_console:1 of msgid "" "/forward_folder ... ... [dest] " "(client only)." msgstr "/forward_folder ... ... [dest ](クライアントのみ)。" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 -#: ec2b9ff3c5cf4fb5a79e29242221fe67 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:3 +#: f6f606236f434f0287a969ccbe5ba2c5 of +msgid "" +"``peer`` is the transfer's original sender (the server for a pushed file," +" the originating client for a forwarded one — never the relay): it is " +"stored with the progress entry so a later reconnect can ask that peer to " +"continue the file." +msgstr "" + +#: 6e9a9717a782419baecca63fd1f46baf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 of msgid "Close the connection and release everything the client owns." msgstr "接続を閉じ、クライアントが所有するすべてを解放します。" -#: 43645acb6c524c348b870d288aafae5e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 +#: ba6c5badecf6465db6036735870ed305 of +#, fuzzy msgid "" "Stops the receive loop, releases the port range, flushes the message and " -"event stores and closes the socket. Safe to call more than once." +"event stores, persists the interrupted transfers and closes the socket. " +"Safe to call more than once." msgstr "受信ループを停止し、ポート範囲を解放し、メッセージをフラッシュし、イベントがソケットを格納して閉じます。複数回電話しても大丈夫です。" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:1 -#: afb1904037404a6c99f6b7ae2df119e2 of +#: c91a3245b93f46abbb49dbef7bcfeb1c of msgid "Connect to the server and start the client loop." msgstr "サーバーに接続し、クライアントループを開始します。" -#: 6f912c76416e4f37a750eda0c126da35 +#: 0c83552867484ea780fcff8d34e5c2d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:3 of #, fuzzy msgid "" @@ -1934,6 +2505,15 @@ msgstr "" "''がTrueの場合は'interactive_mode`を入力します。そうでない場合は、接続がアップしている間はプロセスをアクティブにします。接続を確立できない場合、ステータス1でプロセスを終了します。Ctrl" " - Cと接続の終了は両方とも「閉じる」を実行します。" +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:9 +#: eec663f58484446ebce460e6402d7b5f of +msgid "" +"With ``is_auto_reconnect`` True a dropped connection does not end the " +"client: it reconnects (waiting for the server when ``is_wait_server`` is " +"set) and every session carries the interrupted transfers of the previous " +"one (`resume_transfers`). A close or ``/quit`` still stops the client." +msgstr "" + #~ msgid "" #~ "Concepts live in " #~ "``docs/Network_APIs/TCP_Server_APIs.rst`` and " @@ -2003,3 +2583,28 @@ msgstr "" #~ "Safe to call more than once." #~ msgstr "サーバーソケットとすべてのクライアント接続を閉じ、メッセージとイベントストアをフラッシュし、割り当てられたポート範囲を解放し、「実行中」をクリアします。複数回電話しても大丈夫です。" +#~ msgid "" +#~ "one message per line, terminated by " +#~ "a newline; a line that starts with" +#~ " ``/`` is a command and goes to" +#~ " the command handlers, anything else " +#~ "is a plain message reported to the" +#~ " registered message listeners;" +#~ msgstr "行ごとに1つのメッセージが改行で終了します。''/''で始まる行はコマンドであり、コマンドハンドラに行き、それ以外は登録されたメッセージリスナーに報告されたプレーンメッセージです。" + +#~ msgid "" +#~ "an RSA-encrypted channel is negotiated" +#~ " right after connect unless " +#~ "``is_enable_encrypto`` is False;" +#~ msgstr "'' is_enable_encrypto ''がFalseでない限り、RSA暗号化チャネルは接続直後にネゴシエートされます。" + +#~ msgid "" +#~ "Plain messages are the lines received" +#~ " from clients that do not start " +#~ "with ``/``; commands go through the " +#~ "registered command handlers instead." +#~ msgstr "プレーンメッセージは、''/''で始まらないクライアントから受信した行です。コマンドは、代わりに登録されたコマンドハンドラを経由します。" + +#~ msgid "Mirrors the server-side contract; commands are not reported here." +#~ msgstr "サーバー側の契約をミラーリングします。ここではコマンドは報告されません。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po index 01e18bb..93a37be 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ja\n" @@ -20,21 +20,21 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.rsa_crypto.rst:2 -#: a48a4f614e834981afd42e2cb723ce06 +#: def9740b5a2e4aaeb2aeed8b4f02c0ec msgid "PyFlow.network\\_api.rsa\\_crypto module" msgstr "PyFlow.network \\_api.rsa \\_ cryptoモジュール" -#: PyFlow.network_api.rsa_crypto:1 e529881eccb0440c888d5c69244133f9 of +#: 46d3090efafd4504870cf72a4bea22ab PyFlow.network_api.rsa_crypto:1 of msgid "crypto_api (C/OpenSSL) RSA integration for PyFlow's TCP layer." msgstr "pyFlowのTCPレイヤー用のcrypto_api ( C/OpenSSL ) RSA統合。" -#: PyFlow.network_api.rsa_crypto:3 d9d01596a65340fb84c25298550845cf of +#: 5b1ff4a00b0f46258cda2e7440368de1 PyFlow.network_api.rsa_crypto:3 of msgid "" "A thin ctypes binding to the shared ``libcrypto_api`` plus the key " "lifecycle required by the encrypted TCP channel:" msgstr "共有'' libcrypto_api ''にバインドするシンタイプと、暗号化されたTCPチャネルに必要なキーライフサイクル:" -#: 232e71aebc434fb6bece23f593557e9f PyFlow.network_api.rsa_crypto:6 of +#: PyFlow.network_api.rsa_crypto:6 a5a0d6d600604683990a92555a49a3fe of msgid "" "Reuse an existing RSA keypair from ``~/.ssh`` (PEM private key) when one " "is present and parseable, otherwise generate a fresh keypair into " @@ -45,7 +45,7 @@ msgstr "" "''に新しいキーペアを生成します。呼び出し元が指定したキーペア('' custom_keys " "'')は、両方のファイルが解析され、ペアが一致する場合に使用されます。" -#: 29d30af10f8c4180890f876bb14b00e3 PyFlow.network_api.rsa_crypto:10 of +#: PyFlow.network_api.rsa_crypto:10 bb413dc908624589a3e57f8a2c702728 of msgid "" "Anti-MITM identity check (TOFU): every connection exchanges public keys " "in plaintext. Each side records the peer in " @@ -59,7 +59,7 @@ msgstr "" "''にピアを記録します。異なる鍵を提示する同じエンドポイントからの後の接続は拒否され、新しいエンドポイントから見られる既知の鍵は、新しい''( " "ip, port )''の下に再登録されます。" -#: PyFlow.network_api.rsa_crypto:16 d4873e3b840e4e7fbe4c6f85850dc2a7 of +#: PyFlow.network_api.rsa_crypto:16 aec1a7998276428881efcfac6fe4cebe of msgid "" "RSA-OAEP encrypt/decrypt with the ``_VALID`` plaintext signature so a " "stale key (for example a rotated ``~/.ssh`` pair) is detected and the " @@ -68,7 +68,14 @@ msgstr "" "RSA - OAEPは、''_ VALID ''平文署名で暗号化/復号化するため、古いキー(例えば、ローテーションされた''~/.ssh " "''ペア)が検出され、ピアは公開鍵を再交換します。" -#: 49f63152bca249588cf98871d5bafa64 PyFlow.network_api.rsa_crypto:20 of +#: 392850c432f2466ab9ecfd64770e648d PyFlow.network_api.rsa_crypto:19 of +msgid "" +"ECDH key agreement (P-256/P-384/P-521) with HKDF-SHA256 session-key " +"derivation and AES-256-GCM ``seal``/``open`` (``EcdhKeyPair``, " +"``EcdhPubKey``, ``hkdf_sha256``)." +msgstr "" + +#: 55cfc03aeb3f4d6ba37b10a01dfcdccc PyFlow.network_api.rsa_crypto:23 of msgid "" "The C library is compiled into the installed package by ``setup.py`` (a C" " compiler and OpenSSL development headers are needed at install time); a " @@ -76,21 +83,33 @@ msgid "" "still supported. See ``load_library`` for the search paths." msgstr "" -#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 -#: a3ac757cc1fa4c73be13eaa020c8e60b of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 of msgid "Raised when the shared libcrypto_api cannot be loaded." msgstr "共有libcrypto_apiが読み込めない場合に発生します。" -#: 9c5bbad270ac48cd997b23cd4f284152 PyFlow.network_api.rsa_crypto.RsaKey:1 of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:1 of +msgid "Raised when a ``pf_*`` call fails." +msgstr "" + +#: 2c3651ee5dc94886986aa9804b164e3d +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:3 of +msgid "" +"``code`` is the ``pf_err_t`` value (one of the ``PF_ERR_*`` module " +"constants), or ``None`` when the failing call returned no code." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.RsaKey:1 e620122ff0bc48dd985c4b6a0b3b41ce of msgid "Owns an ``pf_rsa_key_t*`` handle; frees it on GC." msgstr "'' pf_rsa_key_t *''ハンドルを所有しています。GCで解放します。" -#: 0eab5b9b31774196a46b7d400341a404 +#: 1a7d8e9db5a3435486d716b13f2a2a56 #: PyFlow.network_api.rsa_crypto.load_library:1 of msgid "Locate and load the shared crypto_api library (cached)." msgstr "共有されたcrypto_apiライブラリ(キャッシュされた)を見つけて読み込みます。" -#: 8bcac9994a6048e4920e23b8f94bb000 +#: 287fcfd81df2461d8e4bceebf61b7e40 #: PyFlow.network_api.rsa_crypto.load_library:3 of msgid "" "Search order: the library ``setup.py`` compiles into the installed " @@ -101,13 +120,88 @@ msgid "" "reported only if no other candidate works." msgstr "" -#: PyFlow.network_api.rsa_crypto.get_local_mac:1 -#: b555d90eff7c445a8a28cb3de88bd581 of +#: PyFlow.network_api.rsa_crypto.EcdhPubKey:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +#, fuzzy +msgid "Owns a ``pf_ecdh_pubkey_t*`` handle; frees it on GC." +msgstr "'' pf_rsa_key_t *''ハンドルを所有しています。GCで解放します。" + +#: 556fdf46d6c543e0ab06e2d4fabad7f1 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:1 of +msgid "Parse a peer public key from a PEM string." +msgstr "" + +#: 88cd040e91194a3785bf56d7c52d3543 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_PARSE`` for " +"malformed PEM or a point that is not on the curve (the C library verifies" +" the point)." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +#, fuzzy +msgid "Owns a ``pf_ecdh_keypair_t*`` handle; frees it on GC." +msgstr "'' pf_rsa_key_t *''ハンドルを所有しています。GCで解放します。" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:3 f12b2d8d1d4846edbf60d64c34860558 +#: of +msgid "" +"``curve`` is one of ``\"P-256\"``/``\"P-384\"``/``\"P-521\"`` (``None`` " +"selects P-256). OpenSSL key objects are not safe for concurrent use, so " +"``public_pem``/``seal``/``open`` are serialised by an internal lock." +msgstr "" + +#: 07643e7c481f49cba8b4ab33bd4174e0 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.public_pem:1 of +msgid "Export our public key as a PEM SubjectPublicKeyInfo string." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:1 +#: ce09888aa11f4f01a8d4bdb80f94321f of +msgid "Encrypt ``plain`` to ``peer`` with an ECDH-derived AES-256-GCM key." +msgstr "" + +#: 965e41e97f5547c3a0bc77531ae3b3f9 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:3 of +msgid "" +"Returns the wire blob, exactly ``PF_ECDH_SEAL_OVERHEAD`` bytes longer " +"than ``plain``. Raises ``CryptoOperationError``." +msgstr "" + +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:1 of +msgid "Inverse of :meth:`seal`, using ``peer``'s public key." +msgstr "" + +#: 4212d23f4b14479b971145af1bc12fa5 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_AUTH_FAILED`` when" +" the tag does not verify (tampered ciphertext, wrong peer key or " +"mismatched AAD)." +msgstr "" + +#: 7fec5dc58def4bbc886ca30568df0661 PyFlow.network_api.rsa_crypto.hkdf_sha256:1 +#: of +msgid "HKDF-SHA256 (RFC 5869 extract-and-expand) over ``ikm``." +msgstr "" + +#: 462a97910aff4e9aae066e31f55d5233 PyFlow.network_api.rsa_crypto.hkdf_sha256:3 +#: of +msgid "" +"``salt`` and ``info`` may be empty. ``out_len`` must be in " +"``1.._HKDF_SHA256_MAX_OUT``. Raises ``CryptoOperationError``." +msgstr "" + +#: 670f4a719bf24c24b48ecb5d73b373ce +#: PyFlow.network_api.rsa_crypto.get_local_mac:1 of msgid "Return a stable 48-bit machine identifier as colon-separated hex." msgstr "安定した48ビットマシン識別子をコロン区切りの16進数で返します。" -#: 311d6e5bcdba40d1b05fd63528abcf74 -#: PyFlow.network_api.rsa_crypto.get_local_mac:3 of +#: PyFlow.network_api.rsa_crypto.get_local_mac:3 +#: f1306bb875d34b558f7418278fded413 of msgid "" "Uses ``uuid.getnode()`` (the real hardware MAC when one is available). " "Server and client on the same host share this value; the ``_`` " @@ -116,12 +210,12 @@ msgstr "" "'' uuid.getnode ()'' " "(利用可能な場合は実際のハードウェアMAC)を使用します。同じホスト上のサーバーとクライアントはこの値を共有します。キーファイル名の''_''プレフィックスはそれらを分離します。" -#: PyFlow.network_api.rsa_crypto.RsaCrypto:1 b385913eca73436ab76b76787114e163 +#: 333763d798c54d52a9a56a3e4e3e2155 PyFlow.network_api.rsa_crypto.RsaCrypto:1 #: of msgid "Key lifecycle plus RSA-OAEP encrypt/decrypt for one role." msgstr "キーライフサイクルと1つのロールのRSA - OAEP暗号化/復号化。" -#: 7c2b4fafe779449a8245780da7a4ef91 PyFlow.network_api.rsa_crypto.RsaCrypto:3 +#: PyFlow.network_api.rsa_crypto.RsaCrypto:3 f52515121ac74575aaa36d45dd0341a2 #: of msgid "" "``role`` is ``\"server\"`` or ``\"client\"`` and is used to name the " @@ -134,13 +228,13 @@ msgstr "" "'')に名前を付けるために使用されます。ピアアイデンティティは'' " "pub_key/pub_key.json ''で追跡されます( TOFU、'' verify_peer_pub ''を参照)。" -#: 1e24448b89684701a1fa13b02e9d0d84 +#: 56fed5bcfe194b7f90a0c662ae36d6c0 #: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:1 of msgid "Create the crypto wrapper for ``role`` (\"server\" or \"client\")." msgstr "'' role '' (\" server \"または\" client \")の暗号ラッパーを作成します。" -#: 00101f4b9ef44a83b2e51f9974a3d92a -#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 +#: ca4e27664ccf40ce935d991db43f7c69 of msgid "" "``custom_keys`` may be a ``[pub_key_path, pvt_key_path]`` pair to use a " "user-supplied RSA keypair instead of the default lookup (``~/.ssh`` / " @@ -152,32 +246,32 @@ msgstr "" "generated)の代わりにユーザーが指定したRSAキーペアを使用する''[ pub_key_path, pvt_key_path " "]''ペアであってもよいです。ペアは最初の使用時に検証されます(パスが存在し、ファイルが解析され、キーが一致します)。無効なペアは無視され、代わりにデフォルトのルックアップが使用されます。" -#: 4e9b33835a9448bca28d9e2e3a782d77 +#: 7d89122ff0f54090b67209e3b08ae29c #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:1 of msgid "Load the RSA keypair (see module docstring) and cache handles." msgstr "RSAキーペア(モジュールdocstringを参照)とキャッシュハンドルを読み込みます。" #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:3 -#: e7fd217ab95d483084e4c7d58b715349 of +#: d5e494e00be44891b33cb8e0ecfb8081 of msgid "" "Runs under ``_key_lock``: the private-key handle must never be replaced " "(or freed on GC) while another thread is decrypting." msgstr "''_ KEY_LOCK ''の下で実行:別のスレッドが復号化されている間は、秘密鍵ハンドルを交換(またはGCで解放)してはなりません。" #: PyFlow.network_api.rsa_crypto.RsaCrypto.reload_own_key:1 -#: c1e8b452b697431aaafee424e1edd3e2 of +#: f6f7d6ec8837464dad2dc647e6141a99 of msgid "Re-read the private key (e.g. after a ~/.ssh rotation)." msgstr "秘密鍵を再読み取ります(例:~/.sshローテーション後)。" #: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:1 -#: fabae86a23844d9cba130ff2f2adc080 of +#: e95d18da34d14376987a62f6cbbec778 of msgid "" "Path of the exchanged public key file for ``peer_role`` at ``(peer_ip, " "peer_port)``." msgstr "''( peer_ip, peer_port )''で交換された'' peer_role ''の公開鍵ファイルのパス。" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 -#: fa9eee0dbc724d0bbfa8e36bcdd89ba4 of +#: 52dc6fb74f0c4175bfa2a2acc23cda0d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 of msgid "" "The IP is sanitized for the filesystem (``:`` -> ``_`` so IPv6 literals " "are safe on every platform, including Windows)." @@ -185,12 +279,12 @@ msgstr "" "IPはファイルシステム用にサニタイズされます('':''-> ''_''ので、IPv " "6リテラルはWindowsを含むすべてのプラットフォームで安全です)。" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 -#: ce570f7fdb834fc3982aa0ec0e98b896 of +#: 731d92a1b64342dfbf7c467af0a4c00e +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 of msgid "TOFU check-and-record for a peer public key." msgstr "ピア公開鍵の豆腐チェックアンドレコード。" -#: 2879d5b42eed4eaca2af859a86db52e8 +#: 634283c14fb44424bf148a34d156fb71 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:3 of msgid "" "``peer_pem`` is the PEM text received on this connection, ``(peer_ip, " @@ -199,8 +293,8 @@ msgstr "" "'' peer_pem ''は、この接続で受信されたPEMテキストであり、''( peer_ip, peer_port " ")''はそれが来たエンドポイントです。''( ok, reason )''を返します:" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 -#: b6f7afce352240b8ba2cf6a4e38aa457 of +#: 6bb58c88f8454d7daca92b5a478ae788 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 of msgid "" "key already registered under any endpoint -> accept, and re-register it " "under the current endpoint when it moved (IPs are dynamic and ports are " @@ -210,7 +304,7 @@ msgstr "" " under the current endpoint when it moved (IPs are dynamic and ports are " "user - changeable);" -#: 014d219898a04debb9eace0ea28aaa83 +#: 74e2bcc89bae4fe5aecf99e6208e21d1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:10 of msgid "" "key unknown but the endpoint already holds a *different* key -> reject (a" @@ -219,20 +313,20 @@ msgstr "" "key unknown but the endpoint already hold a * different * key -> reject " "(a trusted endpoint suddenly presenting a new key);" -#: 5aabe21775144f3fb2e5b4ae5a190569 -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 +#: f856b875adc34f4a80c2b21cd506b143 of msgid "" "key and endpoint both unknown -> accept and record (first connection is " "trusted, TOFU)." msgstr "keyとendpointの両方が不明-> acceptとrecord (最初の接続は信頼され、TOFU )。" -#: 2bcc3b43a6d54e91b48a51fdf715a346 +#: 556fdf46d6c543e0ab06e2d4fabad7f1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:1 of msgid "Move a freshly received public key file into the key cache." msgstr "受信したばかりの公開鍵ファイルを鍵キャッシュに移動します。" #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:3 -#: a32f32a711ec453684a2fa927aaaa06e of +#: a47e84f5d21949bf98e24834f18bed76 of msgid "" "Idempotent under concurrency: several transfers may deliver the same peer" " key at once (multi-connection handshakes, several client processes " @@ -244,13 +338,13 @@ msgstr "" "received_files " "/''ディレクトリを共有する複数のクライアントプロセス)。並行ストアが移動したためにソースがすでに存在している場合、宛先が所定の位置にあるときに成功が想定されます。" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 -#: c54c296562484982abff2e1436305b98 of +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 of msgid "Encrypt ``plaintext`` with the peer's public key file." msgstr "ピアの公開鍵ファイルで''平文''を暗号化します。" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 -#: f7f5e3490fb44e85919611c0b3b9ecc7 of +#: 4b4dded0ad904ce2bb87c9a43c8f87e5 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 of msgid "" "Returns the ASCII wire body (no trailing newline): each chunk is RSA-OAEP" " encrypted and base64 encoded, chunks joined with ``|``. Raises if no " @@ -263,12 +357,12 @@ msgstr "" "''にまだピアキーが格納されていない場合に発生します。暗号化全体は''_ PEER_PUB_CACHE_LOCK " "''の下で実行されるため、ピアハンドルを暗号化の途中で解放することはできません( GILセーフではありません)。" -#: 8860142532044e87aa78adc123c33d62 +#: 8f1687f4ab984c029859fd1f9cfb968c #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:1 of msgid "Decrypt a wire body with our private key." msgstr "私たちの秘密鍵でワイヤーボディを解読します。" -#: 888f7928d8274beda354f5b657613fec +#: 8a1d1504bf4248fa9e1288776d19810b #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:3 of msgid "" "Returns ``(True, plaintext)`` on success, or ``(False, None)`` when the " diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po index be632ff..d0491a9 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po @@ -6,38 +6,41 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_client.rst:2 -#: 8379b786205a4447995cf82b275ee87a +#: 09f60d1b11ac4e92b480fa6284489970 msgid "PyFlow.transfer\\_web.setup\\_client module" msgstr "PyFlow.transfer \\_web.setup \\_ clientモジュール" -#: 8412539bd9af49e8976ccf5c028061d4 PyFlow.transfer_web.setup_client:1 of +#: 2f786e174934474a93c6498878a68612 PyFlow.transfer_web.setup_client:1 of msgid "PyFlow TCP client web launcher." msgstr "PyFlow TCPクライアントWebランチャー。" -#: PyFlow.transfer_web.setup_client:3 d2ed4df91a474301aee43eaf09e1ac87 of +#: 24fa9f33454d4afc9d15c80a0299922d PyFlow.transfer_web.setup_client:3 of +#, fuzzy msgid "" -"Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI in " -"the browser. The user enters the server address (an http/https domain or a " -"bare IP); the backend asks the server's web backend for the TCP server " -"address/port, starts the TCP client, and keeps the backend running to relay " -"the user's frontend actions. The account of the server logs in from the " -"same backend: saved credentials in ``.Flow_Web/client_login.json`` are " -"replayed on every start, and the login window appears whenever no session " -"could be restored." +"Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI " +"in the browser. The user enters the server address (an http/https domain" +" or a bare IP); the backend asks the server's web backend for the TCP " +"server address/port, starts the TCP client, and keeps the backend running" +" to relay the user's frontend actions. A server that needs accounts (a " +"verification mailbox is configured) makes the same backend log in: saved " +"credentials in ``.Flow_Web/client_login.json`` are replayed on every " +"start, and the login window appears whenever no session could be " +"restored. A server without a mailbox needs no accounts, so the login " +"window and the account controls are skipped." msgstr "" "127.0.0.1で軽量のFlaskバックエンドを起動し、ブラウザで接続UIを開きます。ユーザーはサーバーアドレス( " "http/httpsドメインまたはベアIP " @@ -45,17 +48,23 @@ msgstr "" " ''.Flow_Web/client_login.json ''に保存された資格情報が再生されます " "セッションを復元できない場合はログインウィンドウが表示されます。" -#: PyFlow.transfer_web.setup_client.main:1 fd5a9b075a2a4b9a97dbad26743e0403 of +#: PyFlow.transfer_web.setup_client.main:1 ca4ce7c686c84b44ae429e4de15b9afd of msgid "Start the client web backend and serve its UI." msgstr "クライアントWebバックエンドを起動し、そのUIを提供します。" #~ msgid "" -#~ "Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI in " -#~ "the browser. The user enters the server address (an http/https domain or a " -#~ "bare IP); the backend asks the server's web backend for the TCP server " -#~ "address/port, starts the TCP client, and keeps the backend running to relay " -#~ "the user's frontend actions." +#~ "Starts a lightweight Flask backend on" +#~ " 127.0.0.1 and opens the connect UI" +#~ " in the browser. The user enters " +#~ "the server address (an http/https domain" +#~ " or a bare IP); the backend " +#~ "asks the server's web backend for " +#~ "the TCP server address/port, starts the" +#~ " TCP client, and keeps the backend" +#~ " running to relay the user's frontend" +#~ " actions." #~ msgstr "" #~ "127.0.0.1で軽量のFlaskバックエンドを起動し、ブラウザで接続UIを開きます。ユーザーはサーバーアドレス( " #~ "http/httpsドメインまたはベアIP " #~ ")を入力します。バックエンドはサーバーのWebバックエンドにTCPサーバーアドレス/ポートを尋ね、TCPクライアントを起動し、バックエンドを実行してユーザーのフロントエンドアクションを中継します。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po index 425d4f3..6a88089 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po @@ -6,68 +6,73 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_server.rst:2 -#: 88492dfde47b4dbb914aaba07f359440 +#: e6642bb55a204188b0abd0b07207713e msgid "PyFlow.transfer\\_web.setup\\_server module" msgstr "PyFlow.transfer \\_web.setup \\_サーバーモジュール" -#: 103789700f8d41aa80e1cb374abb02a3 PyFlow.transfer_web.setup_server:1 of +#: 5966876a4564470ea674311ddb3ef63e PyFlow.transfer_web.setup_server:1 of msgid "PyFlow TCP server web launcher." msgstr "PyFlow TCPサーバーWebランチャー。" -#: 581fc0a8029c44f7998895401060a79b PyFlow.transfer_web.setup_server:3 of +#: 588fea0dc68a4a308f9a7cfb6fe5d819 PyFlow.transfer_web.setup_server:3 of msgid "Checks ``transfer_web/.Flow_Web/setup_server.json``:" msgstr "'' transfer_web /.Flow_Web/setup_server.json ''をチェックします:" -#: 60412e56b0d44018bbc88cd258e2c48b PyFlow.transfer_web.setup_server:5 of +#: PyFlow.transfer_web.setup_server:5 c3df4df524da40b18a58607efd9b5e4a of msgid "" -"missing -> opens the server startup-configuration UI in the browser; the UI" -" saves the config (same shape as ``flow_setup``'s ``setup.json``) and starts" -" the TCP server class;" +"missing -> opens the server startup-configuration UI in the browser; the" +" UI saves the config (same shape as ``flow_setup``'s ``setup.json``) and " +"starts the TCP server class;" msgstr "" "missing ->ブラウザでサーバーのスタートアップ構成UIを開きます。UIは設定を保存し('' flow_setup ''の'' " "setup.json ''と同じ形状)、TCPサーバークラスを開始します。" -#: 15dae71f4c1243ecb188218cd72eb7c2 PyFlow.transfer_web.setup_server:8 of -msgid "" -"present -> starts the TCP server class directly from the saved config." +#: 211850fce6d34d50ae152bce6d1aa3af PyFlow.transfer_web.setup_server:8 of +msgid "present -> starts the TCP server class directly from the saved config." msgstr "present ->保存された設定から直接TCPサーバークラスを開始します。" -#: 921ebc855440467cacd9d366085db41a PyFlow.transfer_web.setup_server:10 of +#: 7170b50dcaf2462f918af2271f247c84 PyFlow.transfer_web.setup_server:10 of +#, fuzzy msgid "" -"After the TCP server is up, the lightweight Flask backend serves the status " -"page and the client-facing API (``/api/server_info`` etc.) on the server's " -"address. Anonymous visitors also get the landing page with the registration" -" and password-reset flows; accounts live in the SQLite store " -"``.Flow_Web/flow_web.db``, and the verification mails are sent through the " -"mailbox configured in ``.Flow_Web/email_config.json``." +"After the TCP server is up, the lightweight Flask backend serves the " +"status page and the client-facing API (``/api/server_info`` etc.) on the " +"server's address. Anonymous visitors also get the landing page; its " +"registration and password-reset flows exist while a verification mailbox " +"is configured (settings in ``.Flow_Web/email_config.json``, accounts in " +"the SQLite store ``.Flow_Web/flow_web.db``). That mailbox is also the " +"switch of the client side: with it clients log in with an account, " +"without it they connect without any account at all." msgstr "" "TCPサーバーが起動した後、軽量のFlaskバックエンドは、サーバーのアドレスにステータスページとクライアント向けAPI (''/ " "api/server_info " "''など)を提供します。匿名の訪問者は、登録フローとパスワードリセットフローを含むランディングページも取得します。アカウントはSQLiteストア''.Flow_Web/flow_web.db" " ''に存在し、検証メールは''.Flow_Web/email_config.json ''で構成されたメールボックスを介して送信されます。" -#: 2f09f9248b0e47e3ba9c9792d83a622b PyFlow.transfer_web.setup_server.main:1 of +#: PyFlow.transfer_web.setup_server.main:1 cbf05c29afe74ebd84b898146c971457 of msgid "Start the server web backend and serve its UI." msgstr "サーバーWebバックエンドを起動し、そのUIを提供します。" #~ msgid "" -#~ "After the TCP server is up, the lightweight Flask backend serves the status " -#~ "page and the client-facing API (``/api/server_info`` etc.) on the server's " -#~ "address." +#~ "After the TCP server is up, the" +#~ " lightweight Flask backend serves the " +#~ "status page and the client-facing " +#~ "API (``/api/server_info`` etc.) on the " +#~ "server's address." #~ msgstr "" -#~ "TCPサーバーが起動した後、軽量のFlaskバックエンドは、サーバーのアドレスにステータスページとクライアント向けAPI (''/ " -#~ "api/server_info ''など)を提供します。" +#~ "TCPサーバーが起動した後、軽量のFlaskバックエンドは、サーバーのアドレスにステータスページとクライアント向けAPI " +#~ "(''/ api/server_info ''など)を提供します。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po index c635fb9..0856cec 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po @@ -6,207 +6,231 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst:2 -#: 86d4061dc1f542ac95555aa2deab1101 +#: ffcd351a76b74899a0105947d1049e12 msgid "PyFlow.transfer\\_web.web\\_backend.mail\\_service module" msgstr "PyFlow.transfer \\_web.web \\_backend.mail \\_サービスモジュール" -#: 99f2cb604d5c450c9cda427b22b2c8cb -#: PyFlow.transfer_web.web_backend.mail_service:1 of +#: PyFlow.transfer_web.web_backend.mail_service:1 +#: c6f6b5571d954e7b986a3355033cd30c of msgid "SMTP delivery of account verification codes for the web tool." msgstr "Webツールのアカウント認証コードのSMTP配信。" -#: 1d2a4d079f6c44f182332c5b44d0705a +#: 9764afd408ca43ce829f03d7d4ca675b #: PyFlow.transfer_web.web_backend.mail_service:3 of +#, fuzzy msgid "" -"The administrator configures the outgoing mailbox from the server's startup-" -"configuration page. The settings are validated with a real SMTP login and " -"only then written to ``.Flow_Web/email_config.json``; while no validated " -"configuration is present the service refuses to send, so a server can never " -"silently drop verification codes." +"The administrator configures the outgoing mailbox from the server's " +"startup-configuration page. The settings are validated with a real SMTP " +"login and only then written to ``.Flow_Web/email_config.json``; while no " +"validated configuration is present the service refuses to send, so a " +"server can never silently drop verification codes. The same page takes " +"the mailbox away again (`disable`), which switches the server back to " +"internal use." msgstr "" "管理者は、サーバーのスタートアップ構成ページから送信メールボックスを構成します。設定は実際のSMTPログインで検証され、''.Flow_Web/email_config.json" " " "''にのみ書き込まれます。検証された構成は存在しませんが、サービスは送信を拒否するため、サーバーは検証コードをサイレントでドロップすることはできません。" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 -#: e0597ff2442b43dd87c4efaef6c574c5 of +#: 5fdca457edd340eab7c9f05558a37dc5 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 of msgid "Validate untrusted SMTP settings and return them in canonical form." msgstr "信頼できないSMTP設定を検証し、正規の形式で返します。" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 069dae5e8fb0426e897adc279499319b 4c58519a459f4b9486f0a571939d4834 -#: 83045ebe35d54d76b13e40961c070d4f eb5501cac4f240b19f2d4f5e5443e3c6 +#: 1cad23766791477aa6fb46051363ef81 73b1f3a5025140ec8701e976293f7af0 +#: 817b9cde77bb4327ad3b9f8356d27f4c a9b0b41ab3fd438c8cb2551b61e1af31 msgid "Parameters" msgstr "パラメーター" -#: 14138866fd924a0083c8e6562b3860ff +#: 1b2b400edc914a76977297cb9ef6da5d #: PyFlow.transfer_web.web_backend.mail_service.normalize_config:3 of msgid "" -"Settings with ``host``, ``port``, ``username``, ``password``, ``from`` and " -"``encryption`` keys. ``from`` defaults to the username and ``encryption`` to" -" ``DEFAULT_ENCRYPTION``." +"Settings with ``host``, ``port``, ``username``, ``password``, ``from`` " +"and ``encryption`` keys. ``from`` defaults to the username and " +"``encryption`` to ``DEFAULT_ENCRYPTION``." msgstr "" "'' host ''、'' port ''、'' username ''、'' password ''、'' from '' and '' " -"encryption '' keys .'' from '' defaults to the username and '' encryption ''" -" to '' DEFAULT_ENCRYPTION ''." +"encryption '' keys .'' from '' defaults to the username and '' encryption" +" '' to '' DEFAULT_ENCRYPTION ''." #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 170588e452e5431e815fad88a5b5537b 887b6607974c4ea8b99b628ea3efbf45 -#: a16996418f0e4e5ab58b7244ded5e63b c0463031a23c4f799b6a8217f31cc1b1 +#: 097b6a08fc5548d1a5a4568b07bf4326 1388175dc5e64a8eb1a99affd4807d9f +#: 334d15f3b1264e0b8abfc34e8fee985e 8f894b6967fd4867b82c726e85c83dc9 msgid "Returns" msgstr "返品" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 -#: dafcbdb3cccc40fa89a38363dd5680b0 of +#: 4695369c64494340bb98d06f4029f854 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 of msgid "" "The same settings with a string host, an integer port, a lowercase " "encryption mode and an explicit sender." msgstr "文字列ホスト、整数ポート、小文字の暗号化モード、および明示的な送信者と同じ設定です。" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 -#: a68a2cdaeea44ccdb70c8e49efbcb5dd of +#: 5c191d5d632a4a71a814aa300592c904 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 of msgid "The same settings with a string host, an integer port, a lowercase" msgstr "文字列ホスト、整数ポート、小文字で同じ設定" -#: 2bd9bb82ad2749df9c60df8271733a8c -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 of +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 +#: f98ed07dd1474127973e40ea5d133476 of msgid "encryption mode and an explicit sender." msgstr "暗号化モードと明示的な送信者。" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 24fb33faf10542c7a1d5bcd8bc20e135 53904db2f0da42c6ac410c40a9e555a0 -#: 59876b786ae244308cb80d0e15975404 a636a96a44754c789c671d6e95914aea +#: 2ceb9aabd15149e2a74ab44ffc0e7e3b 4f9ea7be9a9d4179b3371b7ffaaf9c64 +#: 75ab32112eb54385b832e99cc66c0f3b 951ba3e6400f48c2baaffe4aceb25ae3 msgid "Return type" msgstr "戻り値" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 4375f894dabe4fd49e5d470f602e7e4e 669fcb172313407fa0df09ca10280e22 -#: 9ce7848878e44efba62bd42bd640bdeb +#: 051ee4ae623e4c52aca28e50c43a8659 6c5929a2e83444a0b5026560f2c5af02 +#: 7d5aee61dcaa450790fdaa12bda90f1c b717337ce24a4644a8684f6c14ced1d5 msgid "Raises" msgstr "レイズ" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 -#: f6db2cc04ccd4bc0a06c34c8d5d00b29 of +#: 8e1b87a14fc44d6383f43b22bdb71770 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 of msgid "If a setting is missing, malformed or out of range." msgstr "設定が欠落している、形式が正しくない、または範囲外の場合。" -#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 -#: a46df3ad1b4d47838e7d86646e5e45d4 of +#: 9104ff2767b4468db4119f0de6103975 +#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 of msgid "SMTP client delivering verification codes." msgstr "SMTPクライアントが検証コードを配信します。" #: PyFlow.transfer_web.web_backend.mail_service.MailService:3 -#: a6a714e990194ee9b2c023afa0423ec6 of +#: b29996ad41f1488f8540e22a48f131fa of msgid "" -"The stored configuration is read on construction, so a validated mailbox is " -"available again after a restart." +"The stored configuration is read on construction, so a validated mailbox " +"is available again after a restart." msgstr "保存された構成は構築時に読み取られるため、再起動後に検証されたメールボックスが再び使用可能になります。" -#: 906ef645c3f0431c8d4f44bb661e3119 +#: 67ba292bfc8c40ee863f2bf892ff74cb #: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:1 of msgid "Create the service and load the stored configuration." msgstr "サービスを作成し、格納された構成を読み込みます。" -#: 886b800f093c4d758d14028b4233d623 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 +#: f7b0ac874bc34b408853f868c5c1a9cd of msgid "" "JSON file holding the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "SMTP設定を保持するJSONファイル。デフォルトは''.Flow_Web/email_config.json ''です。" -#: 10490a10be734ca58da591842794088d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 +#: cdbf836d9e9c4e2a948458972edbfbae of msgid "Report whether a validated configuration lets codes be sent." msgstr "検証された構成がコードを送信できるかどうかを報告します。" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 -#: a19f7729857a4995be526dded313b07d of +#: 6f529ae442fb4a4ba2e0fd72533d0e29 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 of msgid "True when the SMTP settings were validated and stored." msgstr "SMTP設定が検証され、保存された場合はtrueです。" -#: 646e8fd83be4421ab0d3b4d38fe2b1c8 +#: 93c564a9ccd64ebca089cbd00f434f9e #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:1 of msgid "Return the validated SMTP settings." msgstr "検証されたSMTP設定を返します。" -#: 1728b9dc41484d35851721b141e661be +#: 83356ba5ccea4bceae862cc0934959cf #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:3 of msgid "" "Copy of the stored settings, or ``None`` while the service is not " "configured." msgstr "保存された設定のコピー、またはサービスが構成されていない間の「なし」。" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 -#: cb61516a7cac473fa2ab322e29340899 of +#: 77ff24f402974e8681e2273634e17e4c +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 of msgid "Copy of the stored settings, or ``None`` while the" msgstr "保存されている設定のコピー、または" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 -#: ba7116251d3b4ce7b97a3e79808c4415 of +#: 383ba8fc4ed940f38097d10bfbc8ff84 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 of msgid "service is not configured." msgstr "サービスが設定されていません。" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:1 -#: a2161943624d40a39a45564117df6d9e of +#: c7110be43ff548edb573b0b645e49ef5 of msgid "Validate SMTP settings, store them and start the sending service." msgstr "SMTP設定を検証し、保存して、送信サービスを開始します。" -#: 8d8686cd5b9b46d295719719f9b29929 +#: 99385960778b4785bb73f4db98d2dada #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:3 of msgid "Settings accepted by `normalize_config`." msgstr "`normalize_config`によって受け入れられた設定。" -#: 5aa35eba13e04367b7f99d754176a39d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 +#: d801399842874f19943e8d2eb6dd6e6d of msgid "The validated settings as stored." msgstr "保存されている検証済みの設定。" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:9 -#: ab75660bdd60437dbb05953445043ce0 of +#: c4c8574eb0634811a9fd71b2e00233a9 of msgid "" "If a setting is missing or malformed, or the server refuses the " "connection or the login." msgstr "設定が欠落しているか、形式が正しくない場合、またはサーバーが接続またはログインを拒否した場合。" -#: 4ebf6576a62643d9910acdfba3fcd799 +#: 5c332d9d6242449f97b7bddbe36a20cd +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:1 of +msgid "Remove the stored mailbox so no verification code can be sent." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:3 +#: bc6f8bbf1f0047cebea68882e633945d of +msgid "" +"This is the switch back to internal mode: with no mailbox the server " +"serves its clients without accounts again." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:6 +#: f669f3bdc1f44730a90a6127ff7db331 of +msgid "" +"If the stored file cannot be removed; the service then keeps its " +"settings and stays enabled." +msgstr "" + +#: 7b942af00fc54d9d836170d61972977e #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:1 of msgid "Send one verification code by email." msgstr "認証コードを1つメールで送信します。" -#: 8f04bd37dc8b4483af595c5e66f8fbf4 +#: 6cdc276558b54671b93a8a839f34a682 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:3 of msgid "Recipient address." msgstr "受信者の住所" -#: 57f0544cdf234e00b9f03da47566354f +#: 60f83153ebac42eeb7ba36ed193d0eb1 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:5 of msgid "Verification code to deliver." msgstr "お届けする認証コード。" -#: 627ee080c93e46679b0eb1dea17640f6 +#: 25f348d2347c4274a624e6d13eb6dfd3 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:7 of -msgid "\"register\", \"login\" or \"reset_password\"; decides the wording of the message." +msgid "" +"\"register\", \"login\" or \"reset_password\"; decides the wording of the" +" message." msgstr "\"register \",\" login \"or\" reset_password \";メッセージの文言を決定します。" -#: 6733b65d0a2347e1918c983503394f49 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 +#: f16d610fc9f14559af45cddea444add9 of msgid "Code lifetime in seconds, stated in the message." msgstr "メッセージに記載されている秒単位のコードライフタイム。" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 -#: ce7cf70f7a2d4deca8256ada1fc9b63d of -msgid "" -"If the service is not configured, or the message cannot be delivered." +#: 134b78c9128942938629dd61e9048916 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 of +msgid "If the service is not configured, or the message cannot be delivered." msgstr "サービスが設定されていない場合、またはメッセージを配信できない場合。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po index cc9a1ba..c904152 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po @@ -6,137 +6,153 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst:2 -#: 7bc35f7e619347e0b976ca49c973de8f +#: 4e16e69f9ae9491a95bfcab9c70cfe24 msgid "PyFlow.transfer\\_web.web\\_backend.server\\_backend module" msgstr "PyFlow.transfer \\_web.web \\_backend.server \\_ backendモジュール" -#: PyFlow.transfer_web.web_backend.server_backend:1 -#: fd1d19a74e7a4e14a3863a4f2d4e6eef of +#: 15eb6d4006b3429a8fa230a2b460b1c5 +#: PyFlow.transfer_web.web_backend.server_backend:1 of msgid "Flask backend wrapping the PyFlow TCP server for the web tool." msgstr "Webツール用のPyFlow TCPサーバーをラップするFlaskバックエンド。" -#: 6fa9dfd64064447c82ade7290b523d5c +#: 3c413c9e37f94c7485dba6d4f96b9bf2 #: PyFlow.transfer_web.web_backend.server_backend:3 of msgid "Two modes, one process:" msgstr "2つのモード、1つのプロセス:" -#: 8e61412bb72d49b086f03a2245cd959d +#: 557b793ac8e441db86cf59cad5e85371 #: PyFlow.transfer_web.web_backend.server_backend:5 of msgid "" -"``config`` mode: serves the server startup-configuration UI. The UI shows " -"every ``TCP_Server_Base`` parameter with its default value; on submit the " -"config is written to ``.Flow_Web/setup_server.json`` (same shape as " -"``flow_setup``'s ``setup.json``) and the TCP server class is started." +"``config`` mode: serves the server startup-configuration UI. The UI " +"shows every ``TCP_Server_Base`` parameter with its default value; on " +"submit the config is written to ``.Flow_Web/setup_server.json`` (same " +"shape as ``flow_setup``'s ``setup.json``) and the TCP server class is " +"started." msgstr "" -"'' config ''モード:サーバーのスタートアップ構成UIを提供します。UIは、デフォルト値を持つすべての'' TCP_Server_Base " -"''パラメーターを表示します。送信すると、構成は''.Flow_Web/setup_server.json '' ('' flow_setup " -"''の'' setup.json ''と同じ形状)に書き込まれ、TCPサーバークラスが開始されます。" +"'' config ''モード:サーバーのスタートアップ構成UIを提供します。UIは、デフォルト値を持つすべての'' " +"TCP_Server_Base ''パラメーターを表示します。送信すると、構成は''.Flow_Web/setup_server.json '' " +"('' flow_setup ''の'' setup.json ''と同じ形状)に書き込まれ、TCPサーバークラスが開始されます。" #: PyFlow.transfer_web.web_backend.server_backend:10 -#: b15a182866794bf7bfe71605fc47a301 of +#: cb922669795b42c6ad5587b527c4356a of msgid "" -"``status`` mode: serves the minimal status page plus the same sidebar/input " -"UI as the client frontend (forwarding disabled; native sends to connected " -"clients allowed). Also exposes the HTTP API that clients use to discover " -"the TCP server address/port." +"``status`` mode: serves the minimal status page plus the same " +"sidebar/input UI as the client frontend (forwarding disabled; native " +"sends to connected clients allowed). Also exposes the HTTP API that " +"clients use to discover the TCP server address/port." msgstr "" "'' status " "''モード:最小ステータスページに加えて、クライアントフロントエンドと同じサイドバー/入力UIを提供します(転送は無効です。ネイティブは接続されたクライアントに送信できます)。また、クライアントがTCPサーバーアドレス/ポートを検出するために使用するHTTP" " APIも公開します。" -#: PyFlow.transfer_web.web_backend.server_backend:15 -#: a297544539714d03afa00d1112541712 of +#: 0c6784517a194d65926c71b7ce7f4836 +#: PyFlow.transfer_web.web_backend.server_backend:15 of msgid "" "The backend monitors ``server.clients``: whenever a client connects or " "disconnects it broadcasts the current instance list to every connected " "client (``/web_clients_update``), and it re-checks the list every minute." msgstr "" "バックエンドは'' server.clients " -"''を監視します:クライアントが接続または切断するたびに、接続されているすべてのクライアントに現在のインスタンスリストをブロードキャストし(''/ " -"web_clients_update '')、毎分リストを再確認します。" +"''を監視します:クライアントが接続または切断するたびに、接続されているすべてのクライアントに現在のインスタンスリストをブロードキャストし(''/" +" web_clients_update '')、毎分リストを再確認します。" -#: 9ad7bd78687141a8a282a951ddc57689 +#: 535e49236690482ebf574e6c65b10f39 #: PyFlow.transfer_web.web_backend.server_backend:20 of +#, fuzzy msgid "" -"Inbound events (plain-text messages and file uploads arriving from clients) " -"are captured on the TCP server's receive threads through " -"``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` APIs, " -"queued here, and polled by the frontend via ``/api/events``." +"Inbound events (plain-text messages and file uploads arriving from " +"clients) are captured on the TCP server's receive threads through " +"``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` " +"APIs, queued here, and polled by the frontend via ``/api/events``. The " +"message listener reports every inbound line, protocol commands included; " +"the commands are dropped here, so the queue carries user messages only. A" +" file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -"インバウンドイベント(クライアントから到着するプレーンテキストメッセージとファイルアップロード)は、'' TCP_Server_Base ''の'' " -"add_message_listener ''/'' add_file_listener '' " +"インバウンドイベント(クライアントから到着するプレーンテキストメッセージとファイルアップロード)は、'' TCP_Server_Base " +"''の'' add_message_listener ''/'' add_file_listener '' " "APIを介してTCPサーバーの受信スレッドにキャプチャされ、ここにキューイングされ、''/ api/events " "''を介してフロントエンドによってポーリングされます。" -#: 69da06074d1141308bd12409e851f506 -#: PyFlow.transfer_web.web_backend.server_backend:25 of +#: 6ee75a9919554a3cb05d55c0f9dba653 +#: PyFlow.transfer_web.web_backend.server_backend:30 of +#, fuzzy msgid "" "Authentication: anonymous visitors get a white landing page (the server " -"addresses, a login button, a registration button and a password-reset " -"button); the configuration and status pages need a session. Accounts live " -"in the SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the " -"first run seeds the ``admin``/``admin`` administrator and the frontend warns" -" on every login until those default credentials are changed. Registration, " +"addresses and a login button; while a verification mailbox is configured," +" also a registration button and a password-reset button); the " +"configuration and status pages need a session. Accounts live in the " +"SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the first " +"run seeds the ``admin``/``admin`` administrator and the frontend warns on" +" every login until those default credentials are changed. Registration, " "password reset and code-based client logins are delivered by the mailbox " "configured from the startup-configuration page (see `mail_service`)." msgstr "" "認証:匿名の訪問者には、白いランディングページ(サーバーアドレス、ログインボタン、登録ボタン、パスワードリセットボタン)が表示されます。設定ページとステータスページにはセッションが必要です。アカウントはSQLiteストア''.Flow_Web/flow_web.db" " ''(' user_database `を参照)に存在します。最初の実行は'' admin ''/'' admin " "''管理者をシードし、フロントエンドはデフォルトの資格情報が変更されるまですべてのログイン時に警告します。登録、パスワード " -"リセットおよびコードベースのクライアントログインは、スタートアップコンフィギュレーションページから構成されたメールボックスによって配信されます(' " -"mail_service `を参照)。" +"リセットおよびコードベースのクライアントログインは、スタートアップコンフィギュレーションページから構成されたメールボックスによって配信されます('" +" mail_service `を参照)。" -#: 1fb7feafe6ba447e992cd3ebd42801c8 -#: PyFlow.transfer_web.web_backend.server_backend:34 of +#: 14b91efc5192438eb9eb025aa4a50ef2 +#: PyFlow.transfer_web.web_backend.server_backend:40 of +#, fuzzy msgid "" -"Client accounts: the client web frontend logs in through " -"``/api/client_login`` with a username/email, the account password *and* a " -"mailed verification code — both factors are required — and receives a " -"session token. Re-entering the client web UI replays the saved credentials " -"and token through ``/api/client_verify``, which only accepts them while they" -" still open that account. The token binds the TCP connection the client " -"opens (``/web_bind``) to that account, and the instance list pushed to a " -"client is limited to its contacts, so accounts that never exchanged a " -"contact request cannot see each other." +"Client accounts: the verification mailbox is the switch of the whole " +"client side. While ``.Flow_Web/email_config.json`` holds a validated " +"mailbox the server is meant for public networks: the client web frontend " +"logs in through ``/api/client_login`` with a username/email, the account " +"password *and* a mailed verification code — both factors are required — " +"and receives a session token. Re-entering the client web UI replays the " +"saved credentials and token through ``/api/client_verify``, which only " +"accepts them while they still open that account. The token binds the TCP" +" connection the client opens (``/web_bind``) to that account, and the " +"instance list pushed to a client is limited to its contacts, so accounts " +"that never exchanged a contact request cannot see each other. Without a " +"mailbox the server is an internal tool: clients connect without " +"registration or login, every client sees every other connected instance, " +"and the client account routes are closed — only the console administrator" +" keeps an account." msgstr "" "クライアントアカウント:クライアントウェブフロントエンドは、ユーザー名/メールアドレス、アカウントパスワード*、*郵送された確認コード(両方の要素が必要です)を使用して''/" " api/client_login ''経由でログインし、セッショントークンを受け取ります。クライアントWeb " "UIを再入力すると、保存された資格情報とトークンが''/ api/client_verify " -"''を通じてリプレイされます。これは、アカウントを開いている間にのみ受け入れられます。トークンは、クライアントが開くTCP接続をバインドします(''/ " -"web_bind '') " +"''を通じてリプレイされます。これは、アカウントを開いている間にのみ受け入れられます。トークンは、クライアントが開くTCP接続をバインドします(''/" +" web_bind '') " "クライアントにプッシュされたインスタンスリストはその連絡先に制限されているため、連絡先リクエストを交換したことがないアカウントはお互いを見ることができません。" -#: 123122acd40847679e349c6e3b8d9c5e -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 of +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 +#: ab4c37912c524489a26700248a06704c of msgid "Flask app + TCP_Server_Base wrapper for the web tool." msgstr "Flask APP + TCP_Server_Webツールの基本ラッパー。" #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:1 -#: b7ccb1c765d744b988819d0afbbab22d of +#: fb6d7d555b47497fa6861b7f8a6a5f5d of msgid "Create the Flask app and its stores." msgstr "Flaskアプリとそのストアを作成します。" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst -#: b841315945d14f34a8ef0541284d23e3 +#: 0fb91f29d163495c8c5e4b758c29cf92 msgid "Parameters" msgstr "パラメーター" -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 -#: c8c0a79297824242960049876ebd3e56 of +#: 79acd75ba91d4388972788215a4dcde7 +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 of msgid "" "Port of this web backend; defaults to ``DEFAULT_WEB_PORT``. A busy port " "falls back to the next free one." @@ -144,37 +160,43 @@ msgstr "" "このWebバックエンドのポート。デフォルトは'' DEFAULT_WEB_PORT " "''です。混雑しているポートは、次の空いているポートにフォールバックします。" -#: 652d75ee0a3d4dd18396a8e2b5aa315e +#: 7dd94be740ee476ea378e766ecf5640b #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:6 of msgid "SQLite account database; defaults to ``.Flow_Web/flow_web.db``." msgstr "SQLiteアカウントデータベース。デフォルトは''.Flow_Web/flow_web.db ''です。" -#: 34f17ede4f7c4556a62f8cc47f3c399d +#: 1db79ba202e74aeebefe1de0df4f3f3f #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:9 of msgid "" "JSON file with the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "SMTP設定のJSONファイル。デフォルトは''.Flow_Web/email_config.json ''です。" -#: 011de011008f44dc9c247510315a2341 +#: 7e707a76895243cbb7e49d4a943df5f2 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:1 #: of msgid "Read ``.Flow_Web/setup_server.json`` and start the TCP server." msgstr "''.Flow_Web/setup_server.json ''を読み、TCPサーバーを起動します。" +#: 7a3de044fc304747a1be4161fe0f2e51 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:3 -#: baae3df9217643d0a41c83324c8f035d of +#: of msgid "" -"The saved \"ftp\" share is restored as well, so a folder shared before the " -"restart keeps being served." +"The saved \"ftp\" share is restored as well, so a folder shared before " +"the restart keeps being served." msgstr "保存された「ftp」共有も復元されるため、再起動前に共有されたフォルダは引き続き提供されます。" #~ msgid "" -#~ "Authentication: anonymous visitors get a white landing page (the server " -#~ "addresses plus a login button); the configuration and status pages need a " -#~ "session. Accounts live in ``.Flow_Web/users.json``; the first run seeds the" -#~ " ``admin``/``admin`` administrator, and the frontend warns on every login " -#~ "until those default credentials are changed." +#~ "Authentication: anonymous visitors get a " +#~ "white landing page (the server addresses" +#~ " plus a login button); the " +#~ "configuration and status pages need a" +#~ " session. Accounts live in " +#~ "``.Flow_Web/users.json``; the first run seeds" +#~ " the ``admin``/``admin`` administrator, and " +#~ "the frontend warns on every login " +#~ "until those default credentials are " +#~ "changed." #~ msgstr "" #~ "認証:匿名の訪問者には白いランディングページ(サーバーアドレスとログインボタン)が表示されます。構成ページとステータスページにはセッションが必要です。アカウントは''.Flow_Web/users.json" #~ " ''にあります。最初の実行は'' admin ''/'' admin " @@ -184,17 +206,25 @@ msgstr "保存された「ftp」共有も復元されるため、再起動前に #~ msgstr "サーバーのWebログインをバックアップするアカウントストア(''.Flow_Web/users.json '')。" #~ msgid "" -#~ "Passwords are PBKDF2-SHA256 records with a per-user salt. A missing store " -#~ "file seeds the default ``admin``/``admin`` administrator; a store file that " -#~ "exists but cannot be read is *not* re-seeded, so a damaged file can never " -#~ "silently restore the default account." +#~ "Passwords are PBKDF2-SHA256 records with " +#~ "a per-user salt. A missing store" +#~ " file seeds the default ``admin``/``admin``" +#~ " administrator; a store file that " +#~ "exists but cannot be read is *not*" +#~ " re-seeded, so a damaged file " +#~ "can never silently restore the default" +#~ " account." #~ msgstr "" -#~ "パスワードは、ユーザー単位のソルトを持つPBKDF 2 - SHA 256レコードです。見つからないストアファイルは、デフォルトの'' admin " -#~ "''/'' admin ''管理者をシードします。存在するが読み取ることができないストアファイルは* not * re - " -#~ "seededであるため、損傷したファイルはデフォルトアカウントをサイレントで復元することはできません。" +#~ "パスワードは、ユーザー単位のソルトを持つPBKDF 2 - SHA " +#~ "256レコードです。見つからないストアファイルは、デフォルトの'' admin ''/'' admin" +#~ " ''管理者をシードします。存在するが読み取ることができないストアファイルは* not * re" +#~ " - seededであるため、損傷したファイルはデフォルトアカウントをサイレントで復元することはできません。" -#~ msgid "Return ``{\"username\", \"role\"}`` for valid credentials, else ``None``." +#~ msgid "" +#~ "Return ``{\"username\", \"role\"}`` for valid" +#~ " credentials, else ``None``." #~ msgstr "有効な資格情報については''{\" username \",\" role \"}''を返し、それ以外の場合は'' None ''を返します。" #~ msgid "Rename ``username`` and set its password (self-service)." #~ msgstr "「ユーザー名」の名前を変更し、パスワードを設定します(セルフサービス)。" + diff --git a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po index 2fe6554..ba2f05c 100644 --- a/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po +++ b/docs/source/locale/ja/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po @@ -6,121 +6,141 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: ja \n" "Language: ja\n" +"Language-Team: ja \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_front.client_backend.rst:2 -#: 411a61682c95447192de34eca6a7b40c +#: a7e084a5059341aa9b7419059c4fa4b0 msgid "PyFlow.transfer\\_web.web\\_front.client\\_backend module" msgstr "PyFlow.transfer \\_web.web \\_front.client \\_ backendモジュール" -#: PyFlow.transfer_web.web_front.client_backend:1 -#: c5b03318abd74b32b6ffba1696f8b20b of +#: 22485674cb53445a86703fb118698523 +#: PyFlow.transfer_web.web_front.client_backend:1 of msgid "Flask backend wrapping the PyFlow TCP client for the web tool." msgstr "WebツールのPyFlow TCPクライアントをラップするFlaskバックエンド。" -#: 13a2da9087074258858c4dd7a697671e +#: 31862d77d7184e55a1e729d7e72baed0 #: PyFlow.transfer_web.web_front.client_backend:3 of msgid "" -"The launcher (``setup_client.py``) starts this backend and opens the connect" -" UI in the browser. The user enters the server address (an " -"``http``/``https`` domain or a bare IP); the backend queries the server's " -"web backend ``/api/server_info`` for the TCP server address and port, then " -"starts the ``TCP_Client_Base`` instance. The backend stays up to relay the " -"user's frontend actions:" +"The launcher (``setup_client.py``) starts this backend and opens the " +"connect UI in the browser. The user enters the server address (an " +"``http``/``https`` domain or a bare IP); the backend queries the server's" +" web backend ``/api/server_info`` for the TCP server address and port, " +"then starts the ``TCP_Client_Base`` instance. The backend stays up to " +"relay the user's frontend actions:" msgstr "" -"ランチャー('' setup_client.py '')はこのバックエンドを起動し、ブラウザーで接続UIを開きます。ユーザーはサーバーアドレス('' " -"HTTP ''/'' HTTPS ''ドメインまたはベアIP )を入力します。バックエンドはサーバーのWebバックエンド''/ " -"api/server_info ''にTCPサーバーアドレスとポートを問い合わせ、次に'' TCP_Client_Base " +"ランチャー('' setup_client.py " +"'')はこのバックエンドを起動し、ブラウザーで接続UIを開きます。ユーザーはサーバーアドレス('' HTTP ''/'' HTTPS " +"''ドメインまたはベアIP )を入力します。バックエンドはサーバーのWebバックエンド''/ api/server_info " +"''にTCPサーバーアドレスとポートを問い合わせ、次に'' TCP_Client_Base " "''インスタンスを開始します。バックエンドは、ユーザーのフロントエンドアクションを中継するために立ち上がります。" -#: 95d3503d45ac47ba8c8a9522aceb4764 +#: 1a028258cda844ee945b9522d51afb9d #: PyFlow.transfer_web.web_front.client_backend:10 of msgid "messages/files/folders to the server use the native transfer methods;" msgstr "サーバーへのメッセージ/ファイル/フォルダは、ネイティブ転送方法を使用します。" #: PyFlow.transfer_web.web_front.client_backend:11 -#: be1496ab996044798cfc05692616cd8a of +#: e160c2a0daf9498cbe2041a8e964ff47 of msgid "" -"messages to other clients use the native ``/forward_send_msg`` forwarding (a" -" client-only command relayed by the server);" +"messages to other clients use the native ``/forward_send_msg`` forwarding" +" (a client-only command relayed by the server);" msgstr "" "他のクライアントへのメッセージは、ネイティブ''/ forward_send_msg " "''転送(サーバーによって中継されるクライアント専用コマンド)を使用します。" -#: PyFlow.transfer_web.web_front.client_backend:13 -#: a59ab775ca734b828f09313089028a9f of +#: 16da18234f0a499893b711e7b555b42a +#: PyFlow.transfer_web.web_front.client_backend:13 of msgid "" "files/folders to other clients are forwarded through the built-in " "``forward_extension_tcp`` extension." msgstr "他のクライアントへのファイル/フォルダは、組み込みの'' forward_extension_tcp ''拡張子を介して転送されます。" -#: PyFlow.transfer_web.web_front.client_backend:16 -#: ea807a0c324b430c8731aa632d099643 of +#: 79dee862a03f4d0c9bc9403f8d461465 +#: PyFlow.transfer_web.web_front.client_backend:16 of msgid "" "The sidebar instance list is kept fresh by the server's " -"``/web_clients_update`` broadcasts; a reload button re-requests the list via" -" ``/web_sync_clients``." +"``/web_clients_update`` broadcasts; a reload button re-requests the list " +"via ``/web_sync_clients``." msgstr "" "サイドバーインスタンスリストは、サーバーの''/ web_clients_update " "''ブロードキャストによって最新の状態に保たれます。リロードボタンは、''/ web_sync_clients ''を介してリストを再要求します。" -#: 3656f3e4bded46b596db7d1bdc666b90 +#: 13d20ecd894c4e26a28266b7ac128dfd #: PyFlow.transfer_web.web_front.client_backend:20 of +#, fuzzy msgid "" -"Inbound events (plain-text messages and files pushed by the server, whether " -"direct sends or client forwards) are captured on the TCP client's receive " -"threads through ``TCP_Client_Base``'s " -"``add_message_listener``/``add_file_listener`` APIs, queued here, and polled" -" by the frontend via ``/api/events``." +"Inbound events (plain-text messages and files pushed by the server, " +"whether direct sends or client forwards) are captured on the TCP client's" +" receive threads through ``TCP_Client_Base``'s " +"``add_message_listener``/``add_file_listener`` APIs, queued here, and " +"polled by the frontend via ``/api/events``. The message listener reports" +" every inbound line, protocol commands included; a direct command from " +"the server is dropped here, so the queue carries user messages only. A " +"file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" "インバウンドイベント(プレーンテキストメッセージとサーバーによってプッシュされたファイル、直接送信かクライアント転送かにかかわらず)は、'' " "TCP_Client_Base ''の'' add_message_listener ''/'' add_file_listener '' " "APIを介してTCPクライアントの受信スレッドにキャプチャされ、ここにキューイングされ、''/ api/events " "''を介してフロントエンドによってポーリングされます。" -#: 565c32267ec64ccbb0904ef2ec5609df -#: PyFlow.transfer_web.web_front.client_backend:26 of +#: 5c1c2971ea0e45d8a56544972cdc4ff4 +#: PyFlow.transfer_web.web_front.client_backend:31 of +#, fuzzy msgid "" -"Accounts: a connected client logs in with a server account before the " -"instance list is usable. A forced login needs both factors — the account " -"password and a verification code mailed to the account address — while a " -"client that starts again replays the saved credentials and session token " -"through ``/api/client_verify``. ``/api/login`` opens the session, the " -"``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the contact " -"management to the server, and the session token is sent over TCP with " -"``/web_bind`` so the server can push the contact list of that account. The " -"credentials are remembered in ``.Flow_Web/client_login.json`` (owner-" -"readable only) and the login window is shown whenever no session could be " -"restored." +"Accounts: the connected server decides whether its clients need accounts." +" A server with a verification mailbox is public, so this backend forces " +"the account login before the instance list is usable; a server without " +"one is internal and everything account-related is skipped — no login " +"window, no contacts, and every client sees every other instance. A " +"forced login needs both factors — the account password and a verification" +" code mailed to the account address — while a client that starts again " +"replays the saved credentials and session token through " +"``/api/client_verify``. ``/api/login`` opens the session, the " +"``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the " +"contact management to the server, and the session token is sent over TCP " +"with ``/web_bind`` so the server can push the contact list of that " +"account. The credentials are remembered in " +"``.Flow_Web/client_login.json`` (owner-readable only)." msgstr "" "アカウント:インスタンスリストが使用可能になる前に、接続されたクライアントがサーバーアカウントでログインします。強制ログインには、アカウントパスワードとアカウントアドレスに郵送される確認コードの両方が必要ですが、再度開始するクライアントは、''/" " api/client_verify ''を介して保存された認証情報とセッショントークンをリプレイします。''/ api/login " "''はセッションを開き、''/ api/contacts /*''と''/ api/contact_requests " "''ルートは連絡先管理をプロキシします セッショントークンはTCP経由で''/ web_bind " -"''で送信されるため、サーバーはそのアカウントの連絡先リストをプッシュできます。資格情報は''.Flow_Web/client_login.json " -"'' (owner - readableのみ)に記憶され、セッションを復元できない場合はログインウィンドウが表示されます。" +"''で送信されるため、サーバーはそのアカウントの連絡先リストをプッシュできます。資格情報は''.Flow_Web/client_login.json" +" '' (owner - readableのみ)に記憶され、セッションを復元できない場合はログインウィンドウが表示されます。" -#: 1e6c10d599f046398e16a7b47e0b8dab +#: 0913e15917534119b775fb5c545c439d #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp:1 of msgid "Flask app + TCP_Client_Base wrapper for the web tool." msgstr "Flaskアプリ+ WebツールのTCP_Client_Baseラッパー。" -#: 6c87b744956640d682bef32158496990 #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:1 -#: of -msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +#: bc85ca281f4e4df5a0f10290029fca34 of +#, fuzzy +msgid "Start the TCP client from ``.Flow_Web/setup_client.json``." msgstr "''.Flow_Web/setup_client.json ''からTCPクライアントを起動し、ログインします。" +#: 612871943a7e45a2bacdc377aec78b77 +#: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:3 +#: of +msgid "" +"The connected server reports whether its clients log in; only then is a " +"saved session replayed, and the login window is only shown then." +msgstr "" + #~ msgid "Read ``.Flow_Web/setup_client.json`` and start the TCP client." #~ msgstr "''.Flow_Web/setup_client.json ''を読み、TCPクライアントを起動します。" + diff --git a/docs/source/locale/ko/LC_MESSAGES/Crypto/Crypto.po b/docs/source/locale/ko/LC_MESSAGES/Crypto/Crypto.po index 3955d92..871ae5f 100644 --- a/docs/source/locale/ko/LC_MESSAGES/Crypto/Crypto.po +++ b/docs/source/locale/ko/LC_MESSAGES/Crypto/Crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../source/Crypto/Crypto.rst:2 bb50e4f310ea43d9ba55e4b367ed7740 +#: ../../source/Crypto/Crypto.rst:2 9878b2fb3d9d4d6ba3cd00002ed6f0b7 msgid "C/OpenSSL Crypto Module" msgstr "C/OpenSSL 암호화 모듈" -#: ../../source/Crypto/Crypto.rst:4 2838c629d37d42ef92dbabeab8d33801 +#: ../../source/Crypto/Crypto.rst:4 aa824d3e127240b0928431af3dd8c831 #, fuzzy msgid "" "The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL " @@ -31,62 +31,62 @@ msgstr "" "``src/crypto_api`` 디렉토리에는 ServSpy의 C/OpenSSL 암호화 라이브러리가 포함되어 있습니다. 라이브러리는" " Python 런타임과 독립적이며 CMake를 사용하여 저장소 루트에서 빌드됩니다." -#: ../../source/Crypto/Crypto.rst:8 2c028ead37a24eb98321135f22f3673d +#: ../../source/Crypto/Crypto.rst:8 294667df2a20495887126b808c7d9706 msgid "The module provides:" msgstr "모듈은 다음을 제공합니다." -#: ../../source/Crypto/Crypto.rst:10 e290cfffb80140899093170eda086e61 +#: ../../source/Crypto/Crypto.rst:10 472d4f3082db42f198b7f13fdbf041f2 msgid "RSA-OAEP encryption and decryption with SHA-256." msgstr "SHA-256을 사용한 RSA-OAEP 암호화 및 암호 해독." -#: ../../source/Crypto/Crypto.rst:11 125f1968eba34f6896b44b6406f0e6c2 +#: ../../source/Crypto/Crypto.rst:11 0eb3f7206503452ca2229a1d7c323390 msgid "ECDH key agreement on P-256, P-384, and P-521." msgstr "P-256, P-384 및 P-521에 대한 ECDH 주요 계약." -#: ../../source/Crypto/Crypto.rst:12 cee735932767478e95a96b9a59ddcdd2 +#: ../../source/Crypto/Crypto.rst:12 ab0be16cfbca493a88c6eb4a2ef1bb07 msgid "HKDF-SHA256 session-key derivation." msgstr "HKDF-SHA256 세션 키 파생." -#: ../../source/Crypto/Crypto.rst:13 7d211e9cf2e64cab9b79c0173805334e +#: ../../source/Crypto/Crypto.rst:13 56667bb7a4554c1b8efc918c9593f950 msgid "AES-256-GCM authenticated encryption for ECDH sessions." msgstr "ECDH 세션에 대한 AES-256-GCM 인증 암호화." -#: ../../source/Crypto/Crypto.rst:14 d345fd729851496c82017971bdb55276 +#: ../../source/Crypto/Crypto.rst:14 8de85fb1a2f843ea91d0aa30df0a00c7 msgid "PEM key persistence and structured error reporting." msgstr "PEM 키 지속성 및 구조적 오류 보고." -#: ../../source/Crypto/Crypto.rst:16 d86187e532624ac49492cca1b064a89b +#: ../../source/Crypto/Crypto.rst:16 564b1d414738498791d9083f279330fe msgid "" "The library version is 1.0.0 (``PF_CRYPTO_VERSION_MAJOR`` / " "``PF_CRYPTO_VERSION_MINOR`` / ``PF_CRYPTO_VERSION_PATCH`` and " "``PF_CRYPTO_VERSION_STRING`` in ``pf_crypto.h``)." msgstr "" -#: ../../source/Crypto/Crypto.rst:20 5e6c65799ec14fd8b67034bd1b3beb07 +#: ../../source/Crypto/Crypto.rst:20 10fda1fcea98430a8924fdfa8bbce2fa #, fuzzy msgid "The public headers are located in ``PyFlow/crypto_api/include``:" msgstr "공개 헤더는 ``src/crypto_api/include``에 있습니다:" -#: ../../source/Crypto/Crypto.rst:22 87305d509fc94f5186438e34d9583987 +#: ../../source/Crypto/Crypto.rst:22 86168d67fc8047ba8d4c61b2b9e23caf #, fuzzy msgid "``pf_crypto.h`` - common errors, OpenSSL diagnostics, and HKDF." msgstr "``ss_crypto.h`` - 일반적인 오류, OpenSSL 진단 및 HKDF." -#: ../../source/Crypto/Crypto.rst:23 5d221a05e5034eccadaec2206256a2af +#: ../../source/Crypto/Crypto.rst:23 ddfd841fba4b4045bb3fc84419010fe7 #, fuzzy msgid "``pf_rsa.h`` - RSA key and encryption APIs." msgstr "``ss_rsa.h`` - RSA 키 및 암호화 API." -#: ../../source/Crypto/Crypto.rst:24 e10e899ebf934a18a686d225d3f967d9 +#: ../../source/Crypto/Crypto.rst:24 eb2168817ac54389a35e194a444250f4 #, fuzzy msgid "``pf_ecdh.h`` - ECDH key agreement and seal/open APIs." msgstr "``ss_ecdh.h`` - ECDH 키 계약 및 봉인/공개 API." -#: ../../source/Crypto/Crypto.rst:27 09186509365444d4ac1ce145d76bcd28 +#: ../../source/Crypto/Crypto.rst:27 43fa12b668bb4dc389f2bbd9edaf9187 msgid "Build" msgstr "짓다" -#: ../../source/Crypto/Crypto.rst:29 ae41004303f342d2ac3e302fe5ff9b40 +#: ../../source/Crypto/Crypto.rst:29 35019410fade4c18b07d32d37c05ba0d msgid "" "The module requires OpenSSL 1.1.1 or newer and CMake 3.16 or newer. On " "Debian or Ubuntu, install the build dependencies with:" @@ -94,7 +94,7 @@ msgstr "" "모듈에는 OpenSSL 1.1.1 이상 및 CMake 3.16 이상이 필요합니다. Debian 또는 Ubuntu에서는 다음을 " "사용하여 빌드 종속성을 설치합니다." -#: ../../source/Crypto/Crypto.rst:37 7c534481ca81453b89692a8758bbeba0 +#: ../../source/Crypto/Crypto.rst:37 3834ad9e83c24331b03d264103f5cdad msgid "" "Installing the Python package builds it automatically: ``setup.py`` " "compiles the three sources and installs the result inside the package " @@ -102,19 +102,19 @@ msgid "" "pyflow-net`` needs only a C compiler and the OpenSSL development headers." msgstr "" -#: ../../source/Crypto/Crypto.rst:42 6abf3a2d83804b73b1bfd45add4322d8 +#: ../../source/Crypto/Crypto.rst:42 a72fb95d5d114cdca29347b18e2c1253 msgid "" "Build it from the repository root with CMake when the C test suite or the" " C API itself is wanted:" msgstr "" -#: ../../source/Crypto/Crypto.rst:51 6fbb49d9124649f1b387de2f0377a4af +#: ../../source/Crypto/Crypto.rst:51 96617bb44be2438ebbde9e9f750b3e09 msgid "" "``ctest --test-dir`` was added in CMake 3.20; with the 3.16 minimum the " "equivalent is ``ctest --output-on-failure`` run from inside ``build/``." msgstr "" -#: ../../source/Crypto/Crypto.rst:54 f42772e265ad4248b11c37141f4fb6e8 +#: ../../source/Crypto/Crypto.rst:54 244b7aff35aa4272a121b9fbbadae117 #, fuzzy msgid "" "The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, " @@ -125,27 +125,26 @@ msgstr "" "C 테스트 스위트는 ``test/crypto_api/``(``test_hkdf``, ``test_rsa``, " "``test_ecdh``)에 있으며 라이브러리와 함께 빌드되고 실행됩니다." -#: ../../source/Crypto/Crypto.rst:59 ed6b92c776ca441ab8629088ecd973bc +#: ../../source/Crypto/Crypto.rst:59 30ea804b8270411f8793908bdc7a2a97 #, fuzzy msgid "" "The library is built as a shared object (``libcrypto_api.so``) so it can " "be loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes " -"binding used by the TCP layer to encrypt messages with RSA-OAEP (see the " -"``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). " -"The binding also implements the TCP layer's anti-MITM identity check " -"(TOFU): peer public keys are exchanged on every connection, recorded " -"under the peer's ``(ip, port)`` in " -"``network_api/.Flow/pub_key/pub_key.json`` with the SHA-256 of the " -"received PEM text, and a changed key for a recorded endpoint rejects the " -"connection; a key already known under another endpoint is accepted and " -"re-registered under the new one. The encryption state machine is bounded:" -" three consecutive decode failures trip a circuit breaker " -"(``MAX_DECODE_FAILURES`` in ``connect_tcp.py``) that stops re-keying, and" -" a key that is stale or rotated makes the TCP layer reload its own key " -"and re-exchange. The binding looks for the library via " -"``ctypes.util.find_library`` and then next to the repository root in " -"``build/`` (``libcrypto_api.so``, ``libcrypto_api.dylib``, " -"``libcrypto_api.dll`` and ``build/Release/crypto_api.dll``)." +"binding used by the TCP layer. It exposes the RSA-OAEP message encryption" +" and the ECDH/AES-256-GCM sealing (``EcdhKeyPair`` / ``EcdhPubKey`` / " +"``hkdf_sha256``) that the framed TCP channel uses for its bulk and file " +"transfer payloads (see the ``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"encrypted channel sections). The binding also implements the TCP layer's " +"anti-MITM identity check (TOFU): endpoint rejects the connection; a key " +"already known under another endpoint is accepted and re-registered under " +"the new one. The encryption state machine is bounded: three consecutive " +"decode failures trip a circuit breaker (``MAX_DECODE_FAILURES`` in " +"``connect_tcp.py``) that stops re-keying, and a key that is stale or " +"rotated makes the TCP layer reload its own key and re-exchange. The " +"binding looks for the library via ``ctypes.util.find_library`` and then " +"next to the repository root in ``build/`` (``libcrypto_api.so``, " +"``libcrypto_api.dylib``, ``libcrypto_api.dll`` and " +"``build/Release/crypto_api.dll``)." msgstr "" "라이브러리는 공유 객체(``libcrypto_api.so``)로 구축되어 Python에서 로드할 수 있습니다. " "``src/network_api/rsa_crypto.py``는 RSA-OAEP로 메시지를 암호화하기 위해 TCP 계층에서 사용하는 " @@ -156,13 +155,13 @@ msgstr "" "``ctypes.util.find_library``를 통해 그리고 저장소 루트 옆에 있는 ``build/``에서 라이브러리를 " "찾습니다." -#: ../../source/Crypto/Crypto.rst:77 ad993af85f8f45f5a3661448f69961bf +#: ../../source/Crypto/Crypto.rst:77 9594680fce33464f9ff9cb9590bb5d0a msgid "" "The build produces the SOVERSIONed names ``libcrypto_api.so.1`` / " "``libcrypto_api.so.1.0.0`` plus the ``libcrypto_api.so`` loader symlink." msgstr "" -#: ../../source/Crypto/Crypto.rst:80 7ea41df5c6644e8197d587e03642123f +#: ../../source/Crypto/Crypto.rst:80 80c24657a4c9445088459fff264379b2 #, fuzzy msgid "" "CMake install rules export the ``crypto_api`` library, its public " @@ -178,11 +177,11 @@ msgstr "" "CMake 콘텐츠는 저장소 루트에 있습니다. CMake 패키지 템플릿과 pkg-config 템플릿은 " "``cmake/crypto_apiConfig.cmake.in`` 및 ``crypto_api.pc.in``입니다." -#: ../../source/Crypto/Crypto.rst:89 0d7e08f1e07445dfa77b47a85a25def7 +#: ../../source/Crypto/Crypto.rst:89 dccd3901c8024859b9a9753e818d6692 msgid "Common API" msgstr "공통 API" -#: ../../source/Crypto/Crypto.rst:91 1c9b38b493964582875d168e61ccf829 +#: ../../source/Crypto/Crypto.rst:91 c1b71e19c8f6422eabd99bd0997daae8 msgid "" "Most public functions return ``pf_err_t``; ``PF_OK`` indicates success. " "Functions that report a size or a string instead have their own return " @@ -194,12 +193,15 @@ msgid "" "pending OpenSSL error queue." msgstr "" -#: ../../source/Crypto/Crypto.rst:114 07ac67f777704ad9822023430f0109c4 +#: ../../source/Crypto/Crypto.rst:114 67ae5556635e43a487c38bf8011e1c5b #, fuzzy msgid "" "The library uses caller-provided output buffers for fixed-size results. " "Functions that return allocated buffers document that the caller must " -"release them with ``free``. Opaque key handles must be released with " +"release them with ``pf_crypto_free`` — the library's own ``free``, so the" +" allocation and the deallocation always run on the same C runtime (a host" +" such as CPython on Windows may use a different one, and freeing across " +"runtimes corrupts the heap). Opaque key handles must be released with " "their corresponding ``*_free`` function. HKDF output is capped at " "``PF_CRYPTO_HKDF_SHA256_MAX_OUT`` (8160 bytes) by both " "``pf_crypto_hkdf_sha256`` and ``pf_ecdh_derive_key``." @@ -207,11 +209,11 @@ msgstr "" "라이브러리는 고정 크기 결과를 위해 호출자가 제공한 출력 버퍼를 사용합니다. 할당된 버퍼를 반환하는 함수는 호출자가 이를 " "``free``로 해제해야 함을 문서화합니다. 불투명 키 핸들은 해당 ``*_free`` 함수를 사용하여 해제해야 합니다." -#: ../../source/Crypto/Crypto.rst:122 619e39d223d54a48ba983a3b30bd7d9d +#: ../../source/Crypto/Crypto.rst:125 69248ac47e7e47f18e953dee857db239 msgid "RSA API" msgstr "RSA API" -#: ../../source/Crypto/Crypto.rst:124 5eeaa87820f941dd8e171c973269036e +#: ../../source/Crypto/Crypto.rst:127 a770dcc04e2c42d1be50fe30d298df4b #, fuzzy msgid "" "RSA keys are generated with ``pf_rsa_keygen``. The implementation uses " @@ -221,7 +223,7 @@ msgstr "" "RSA 키는 ``ss_rsa_keygen``을 사용하여 생성됩니다. 구현에서는 암호화 및 암호 해독을 위해 SHA-256과 함께 " "RSA-OAEP를 사용합니다. 2048~16384비트의 키 크기가 허용됩니다. 2048, 3072 또는 4096비트가 권장됩니다." -#: ../../source/Crypto/Crypto.rst:148 f85a46b466ef47ee9d195f439ba3b153 +#: ../../source/Crypto/Crypto.rst:151 e7b876b8fb354b2da45d3c13f50ededf msgid "" "The first encryption call with ``out == NULL`` queries the required " "output size; ``pf_rsa_decrypt`` supports the same query pattern. RSA " @@ -233,34 +235,34 @@ msgid "" "handle." msgstr "" -#: ../../source/Crypto/Crypto.rst:156 ff9d2472cf614dd0827d0887f195ed43 +#: ../../source/Crypto/Crypto.rst:159 6af957980305426e915b3f62d9eb1ed4 msgid "Public and private keys can be stored as PEM files:" msgstr "공개 및 개인 키는 PEM 파일로 저장할 수 있습니다." -#: ../../source/Crypto/Crypto.rst:167 a3f163de660b4d49a36a8aedead555da +#: ../../source/Crypto/Crypto.rst:170 6bf9df3c51d540b69680723a4845de2d msgid "ECDH API" msgstr "ECDH API" -#: ../../source/Crypto/Crypto.rst:169 4535e8f410a742f38d32ff53d404c37b +#: ../../source/Crypto/Crypto.rst:172 3c69950828364df49bbf0b37313f9987 #, fuzzy msgid "" "ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The " "supported curve names are:" msgstr "ECDH 키 쌍은 ``ss_ecdh_keypair_generate``를 사용하여 생성됩니다. 지원되는 곡선 이름은 다음과 같습니다." -#: ../../source/Crypto/Crypto.rst:172 9624f8475c8d4618a7054e7c18ae5e1f +#: ../../source/Crypto/Crypto.rst:175 6a4d2171568847d4984c8705818c4bf9 msgid "``PF_ECDH_CURVE_P256``" msgstr "``PF_ECDH_CURVE_P256``" -#: ../../source/Crypto/Crypto.rst:173 4585a2433d684621a5f90805b74cef6c +#: ../../source/Crypto/Crypto.rst:176 c0da017a21dc46ed93b3da0727454dc3 msgid "``PF_ECDH_CURVE_P384``" msgstr "``PF_ECDH_CURVE_P384``" -#: ../../source/Crypto/Crypto.rst:174 14dde8ddd1b44ae1a4cb64179caa5aa5 +#: ../../source/Crypto/Crypto.rst:177 b2019f9f782b48dc85c5e3b24647fd94 msgid "``PF_ECDH_CURVE_P521``" msgstr "``PF_ECDH_CURVE_P521``" -#: ../../source/Crypto/Crypto.rst:176 43b77941f20d44958205bea666a208d5 +#: ../../source/Crypto/Crypto.rst:179 0962e1bca8da48d1835cbe8facb8a0ea #, fuzzy msgid "" "An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` " @@ -268,7 +270,7 @@ msgid "" "strings. Parsed peer keys are checked to lie on the curve before use." msgstr "공개 키는 PEM SubjectPublicKeyInfo 문자열로 교환됩니다. 구문 분석된 피어 키는 사용 전에 확인됩니다." -#: ../../source/Crypto/Crypto.rst:200 ac2db67c049d4f55a2fc2f9972c6d57c +#: ../../source/Crypto/Crypto.rst:203 c5c15560992c48beb7637c19a517f07f #, fuzzy msgid "" "The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are " @@ -281,23 +283,23 @@ msgstr "" "애플리케이션 페이로드에는 더 높은 수준의 ``ss_ecdh_seal`` 및 ``ss_ecdh_open`` API가 권장됩니다. " "HKDF-SHA256을 사용하여 AES-256-GCM 키를 파생하고 임의의 솔트와 IV를 포함하며 선택적 AAD를 인증합니다." -#: ../../source/Crypto/Crypto.rst:207 70a8e3f511f34359974c9152d60500b2 +#: ../../source/Crypto/Crypto.rst:210 f794a8f7227443e381d5337e9fe95677 #, fuzzy msgid "The ``pf_ecdh_seal`` output format is:" msgstr "``ss_ecdh_seal`` 출력 형식은 다음과 같습니다:" -#: ../../source/Crypto/Crypto.rst:213 28f1933678854354b8ef357adcfdd380 +#: ../../source/Crypto/Crypto.rst:216 ee4a7ea6853249a7a137f949e3b9d7cc #, fuzzy msgid "" "The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty " "plaintext is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` " "and no plaintext is returned. On success the output buffer is " -"``malloc``-ed and the caller frees it." +"``malloc``-ed and the caller releases it with ``pf_crypto_free``." msgstr "" "고정 오버헤드는 ``SS_ECDH_SEAL_OVERHEAD``(44바이트)입니다. 빈 일반 텍스트가 허용됩니다. 실패한 태그 확인은" " ``SS_ERR_AUTH_FAILED``를 반환하고 일반 텍스트는 반환되지 않습니다." -#: ../../source/Crypto/Crypto.rst:218 9a7c6cc7b5a94e5fac26bc6802310183 +#: ../../source/Crypto/Crypto.rst:221 212039cbe4b74827b643af47aaaf9970 msgid "" "ECDH key pairs can be persisted with ``pf_ecdh_keypair_write_priv`` and " "``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-" @@ -305,11 +307,11 @@ msgid "" "``pf_ecdh_pubkey_free`` release the handles." msgstr "" -#: ../../source/Crypto/Crypto.rst:224 7f05214ee91a478581014c39643d7bfb +#: ../../source/Crypto/Crypto.rst:227 a84d53d68554474fbb2beaa2146cee86 msgid "Security Notes" msgstr "보안 참고사항" -#: ../../source/Crypto/Crypto.rst:226 a6482f5940d1469088bb376b1d25d31c +#: ../../source/Crypto/Crypto.rst:229 5e398f6a7ace4aeea29bcd40e75a59b1 msgid "" "ECDH provides key agreement, but it does not authenticate public-key " "ownership by itself. Public keys must be exchanged over an authenticated " @@ -318,7 +320,7 @@ msgstr "" "ECDH는 키 계약을 제공하지만 공개 키 소유권을 자체적으로 인증하지는 않습니다. 공개 키는 인증된 채널을 통해 교환되거나 외부 " "서명/인증서 메커니즘을 통해 확인되어야 합니다." -#: ../../source/Crypto/Crypto.rst:230 fb49962bd1f0474c91610fa9dd020584 +#: ../../source/Crypto/Crypto.rst:233 df43fe66482c4e0fb896ab598ce43c7d #, fuzzy msgid "" "Private key files may be protected with a passphrase: " @@ -331,64 +333,64 @@ msgstr "" "개인 키 파일은 암호로 보호될 수 있습니다. 애플리케이션은 파일 권한을 제한하고 암호, 개인 키 또는 일반 텍스트 세션 키를 " "기록하지 않아야 합니다." -#: ../../source/Crypto/Crypto.rst:238 e09bc96e058a4b14b135a1430b8a3ad9 +#: ../../source/Crypto/Crypto.rst:241 02cb264ad6c747d29b37bfa1f1cc6362 msgid "Error Handling" msgstr "오류 처리" -#: ../../source/Crypto/Crypto.rst:240 8246aab2cf7d4913a7345684940c9220 +#: ../../source/Crypto/Crypto.rst:243 60786ad51ea444da97922957e670ea90 msgid "The main error codes are:" msgstr "주요 오류 코드는 다음과 같습니다." -#: ../../source/Crypto/Crypto.rst:242 45059d6bf45c42c2bc8e8c6f023836f4 +#: ../../source/Crypto/Crypto.rst:245 8c1b057428f2445889d1159d6636b097 msgid "" "``PF_ERR_INVALID_ARG`` - NULL argument, illegal length or bad parameter " "combination (e.g. out-of-range RSA key size, a NULL salt/info with a non-" "zero length, or a plaintext longer than the key allows)." msgstr "" -#: ../../source/Crypto/Crypto.rst:245 daed84defdb64065849a0ef880b22eea +#: ../../source/Crypto/Crypto.rst:248 27e26e555ee24ce68ab7943b4117a57d #, fuzzy msgid "``PF_ERR_NOMEM`` - allocation failure." msgstr "``SS_ERR_NOMEM`` - 할당 실패." -#: ../../source/Crypto/Crypto.rst:246 788a5b4b06714adcab5aeb36b81757e4 +#: ../../source/Crypto/Crypto.rst:249 2b3828e4bfa04329a60b479be7f0dfe5 #, fuzzy msgid "``PF_ERR_OPENSSL`` - OpenSSL operation failure." msgstr "``SS_ERR_IO`` - 파일 작업 실패." -#: ../../source/Crypto/Crypto.rst:247 0e06a2169f5d445cab788910aaee188a +#: ../../source/Crypto/Crypto.rst:250 2c3c9ab09d294be8911f4fb31c335db6 #, fuzzy msgid "``PF_ERR_IO`` - file operation failure." msgstr "``SS_ERR_IO`` - 파일 작업 실패." -#: ../../source/Crypto/Crypto.rst:248 0d1b17cc4e744efd891efe2d292f6dd8 +#: ../../source/Crypto/Crypto.rst:251 a928f8b90e154bdaa43ef4e4ee7d578d #, fuzzy msgid "" "``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key " "passphrase." msgstr "``SS_ERR_PARSE`` - 잘못된 PEM/DER 입력 또는 잘못된 개인 키 암호." -#: ../../source/Crypto/Crypto.rst:249 8d5f6adfe3b24ecebb6ed2d84cece394 +#: ../../source/Crypto/Crypto.rst:252 9cd41d63123d49caa946160465dda70f #, fuzzy msgid "``PF_ERR_BUFFER_TOO_SMALL`` - caller output buffer is insufficient." msgstr "``SS_ERR_BUFFER_TOO_SMALL`` - 호출자 출력 버퍼가 부족합니다." -#: ../../source/Crypto/Crypto.rst:250 7a88e3913e8948edbcf645b5097b47b3 +#: ../../source/Crypto/Crypto.rst:253 78532f0a764249178076a4adcc032f7f #, fuzzy msgid "``PF_ERR_AUTH_FAILED`` - AES-GCM authentication failed." msgstr "``SS_ERR_AUTH_FAILED`` - AES-GCM 인증에 실패했습니다." -#: ../../source/Crypto/Crypto.rst:251 1182998c4b164675a840d89b3a8e994b +#: ../../source/Crypto/Crypto.rst:254 5e5f5421333e4382ae5e700d7570648b #, fuzzy msgid "``PF_ERR_UNSUPPORTED`` - unsupported curve or key type." msgstr "``SS_ERR_UNSUPPORTED`` - 지원되지 않는 곡선 또는 키 유형입니다." -#: ../../source/Crypto/Crypto.rst:252 0af6413bc92a46a48a1ea044a6b4f05b +#: ../../source/Crypto/Crypto.rst:255 d1fea86be03940d097132b112b6f14f2 #, fuzzy msgid "``PF_ERR_DECRYPT`` - RSA decryption failed." msgstr "``SS_ERR_DECRYPT`` - RSA 암호 해독에 실패했습니다." -#: ../../source/Crypto/Crypto.rst:254 b425983151054505a243c1d65c68a2b8 +#: ../../source/Crypto/Crypto.rst:257 9b1c2b2d3f48459bbedee21c92aafe31 msgid "For detailed OpenSSL diagnostics:" msgstr "자세한 OpenSSL 진단:" diff --git a/docs/source/locale/ko/LC_MESSAGES/File_Transfer/File_Transfer.po b/docs/source/locale/ko/LC_MESSAGES/File_Transfer/File_Transfer.po index a4eec09..0d09bfe 100644 --- a/docs/source/locale/ko/LC_MESSAGES/File_Transfer/File_Transfer.po +++ b/docs/source/locale/ko/LC_MESSAGES/File_Transfer/File_Transfer.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -20,12 +20,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/File_Transfer/File_Transfer.rst:2 -#: 2d215e70ec1e43988343e3d32392d8aa +#: d9c92006bc3e49c9a5d184d74f2e7824 msgid "TCP File Transfer Mechanism" msgstr "TCP 파일 전송 메커니즘" #: ../../source/File_Transfer/File_Transfer.rst:4 -#: f603ff252cb64bea9b7c9034d2d46221 +#: b32ed3356f814a369d9d4bc153c017fa msgid "" "This document describes the file transfer subsystem implemented in both " "the ``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file " @@ -39,35 +39,36 @@ msgstr "" "보내고 받을 수 있습니다. 또한 서버 콘솔에서 서버가 시작한 전송도 지원합니다." #: ../../source/File_Transfer/File_Transfer.rst:14 -#: f28ca12001c24b1c954e10fdb63aa493 +#: ad6d3cd551694899ba6998e43167bb10 msgid "The design follows a **two-phase handshake** pattern:" msgstr "디자인은 **2단계 핸드셰이크** 패턴을 따릅니다." #: ../../source/File_Transfer/File_Transfer.rst:16 -#: b348421cfc6d4267a58231db041e7d67 +#: f67e58b5ae8b4e2a8f9a9021efba0b5c msgid "A transfer command is exchanged over the main control connection." msgstr "전송 명령은 주 제어 연결을 통해 교환됩니다." #: ../../source/File_Transfer/File_Transfer.rst:18 -#: 0483543fb8f0497a9ee256fee509e4fc +#: 4d267488a6cf4911bc2c3cb7801dce8d msgid "" "A separate TCP connection is established on a dynamically allocated port " "to transfer the actual file data (metadata + payload)." msgstr "실제 파일 데이터(메타데이터 + 페이로드)를 전송하기 위해 동적으로 할당된 포트에 별도의 TCP 연결이 설정됩니다." #: ../../source/File_Transfer/File_Transfer.rst:22 -#: 0e13d1b8b6ef46ce855c8949ef36f219 +#: a0490aac6cc74a8f9de5e9872378b87c #, fuzzy msgid "" -"All file transfers use **stream-oriented reading/writing** with fixed-" -"size chunks (65536 bytes, hardcoded in both directions) to avoid blocking" -" and to handle large files efficiently." +"All file transfers use **stream-oriented reading/writing** with a " +"configurable chunk size (``file_transfer_chunk_len``, 65536 bytes by " +"default, in both directions) to avoid blocking and to handle large files " +"efficiently." msgstr "" "모든 파일 전송에서는 차단을 방지하고 대용량 파일을 효율적으로 처리하기 위해 고정 크기 청크(기본적으로 64KiB)가 포함된 " "**스트림 지향 읽기/쓰기**를 사용합니다." #: ../../source/File_Transfer/File_Transfer.rst:28 -#: a8c11b500a31468aa10fc4d6537c691c +#: 9ad33f3c1a2e4164b384a71388b895f5 msgid "" "*Note: For a high-level overview of the server and client classes, please" " refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" @@ -76,12 +77,12 @@ msgstr "" ":doc:`TCP_Client_APIs`를 참조하세요.*" #: ../../source/File_Transfer/File_Transfer.rst:35 -#: aeba1deb576440f29ab1d507d38fb22d +#: 2c31714fc81743fa9fbb8701d87347ac msgid "File Transfer Protocol" msgstr "파일 전송 프로토콜" #: ../../source/File_Transfer/File_Transfer.rst:37 -#: a97e5fe0762d4d2d8ffef8527985c9e7 +#: 61af0fc38ea74fcfae8b2a1316d2e6ea msgid "" "The protocol is symmetric: the same low-level exchange is used regardless" " of whether the server sends to a client or the client sends to the " @@ -94,7 +95,7 @@ msgstr "" " 합니다." #: ../../source/File_Transfer/File_Transfer.rst:46 -#: 1a2e27611ea0452d99cd3e8ac299683c +#: 2ef019fa21e74d26873cb1da802747ac msgid "" "The low-level wire markers are stored in " "``PyFlow/network_api/decode_command_table.json``, which each instance " @@ -103,7 +104,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:52 -#: ebc9fc6492964c47b4744d8e2faf6ffd +#: be499b6571974e1a87d5c471578ac79b #, fuzzy msgid "" "``server_start_file_transfer_sign`` — from " @@ -113,7 +114,7 @@ msgid "" msgstr "``server_start_file_transfer_sign`` - 수신자가 발신자에게 전송하여 수신자가 준비되었음을 나타냅니다." #: ../../source/File_Transfer/File_Transfer.rst:57 -#: d23e35d928494417918b1e9e1810d2e9 +#: 3c9a4f28914742dab2a8175df58f9419 msgid "" "``send_file_header_sign`` / ``send_file_data_sign`` — from " "``file_send_server_header`` / ``file_send_server_data``; both attributes " @@ -121,7 +122,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:60 -#: 07ce10ba9a534d2db23cb3505f3d9ad7 +#: 2035637777a449768450196f0fec1397 msgid "" "``server_received_file_header_sign`` / ``server_received_file_data_sign``" " — from ``file_receive_client_header`` / ``file_receive_client_data``; " @@ -131,7 +132,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:67 -#: a2c795d996c4491e9c90f46871d655b0 +#: 0fc372ae19be49029aa105a95e480640 #, fuzzy msgid "" "``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by " @@ -140,7 +141,7 @@ msgid "" msgstr "``error_sign`` - 오류가 발생하면 양쪽에서 전송되어 전송 소켓이 닫힙니다." #: ../../source/File_Transfer/File_Transfer.rst:72 -#: b95751f788c044d69f86a067e221a340 +#: 41f6d3d6e0e848bc8f6aecb995223622 msgid "" "The remaining keys of the table cover the other three direction/phase " "combinations. Protocol control lines that are not part of this table " @@ -151,47 +152,49 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:80 -#: c481ce301cdc4dddba6f392dc6de4e6a +#: 45a36aa9239d4caba8752e4dc4fd551b msgid "### Metadata Exchange" msgstr "### 메타데이터 교환" #: ../../source/File_Transfer/File_Transfer.rst:82 -#: a6fea134d58a457ab825ec59930e0c48 +#: d4ace80bc05f4bafb8144e1de31060dc msgid "" "The sender performs the following steps after the dedicated file-transfer" " socket is connected:" msgstr "송신자는 전용 파일 전송 소켓이 연결된 후 다음 단계를 수행합니다." #: ../../source/File_Transfer/File_Transfer.rst:86 -#: e18ac26158444f719667794153f422d8 +#: 5df80a71cd274a92975e8d010f564872 msgid "" "Wait for the receiver's start signal " "(``server_start_file_transfer_sign``) with a 10-second timeout." msgstr "10초 제한 시간으로 수신기의 시작 신호(``server_start_file_transfer_sign``)를 기다립니다." #: ../../source/File_Transfer/File_Transfer.rst:89 -#: fb269796ce6d45cbb73b0201dce1cec9 +#: d68741e000fe48d3857ec0b0363d4182 msgid "Send the filename length as a 4-byte unsigned integer (big-endian)." msgstr "파일 이름 길이를 4바이트 부호 없는 정수(빅 엔디안)로 보냅니다." #: ../../source/File_Transfer/File_Transfer.rst:91 -#: c48725bc3ac54f16bef68243c780831d +#: 95260b76f4524ddb8700ca05352f294d msgid "Send the filename encoded in UTF-8." msgstr "UTF-8로 인코딩된 파일 이름을 보냅니다." #: ../../source/File_Transfer/File_Transfer.rst:92 -#: 951751cbb7ab400dbfd8ac2e574d2bf0 +#: 7efa294dbe7e4921974628e8fb08cc00 msgid "Send the file size as an 8-byte unsigned integer (big-endian)." msgstr "파일 크기를 8바이트 부호 없는 정수(빅 엔디안)로 보냅니다." #: ../../source/File_Transfer/File_Transfer.rst:94 -#: db806fd98e8b48dabcd3fa755f1d6567 +#: 065d4ab3bf384d81a22df89aeba09349 #, fuzzy -msgid "Send the file content in 65536-byte chunks until EOF." +msgid "" +"Send the file content in ``file_transfer_chunk_len``-byte chunks (65536 " +"by default) until EOF." msgstr "EOF까지 64KiB 청크로 파일 콘텐츠를 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:95 -#: 265efb19bd5c46569983bb4156bc195c +#: ../../source/File_Transfer/File_Transfer.rst:96 +#: aeec7f8ff0ab424cbc5b7c1a32ff9433 msgid "" "Wait for the completion acknowledgement " "(``server_received_file_data_sign``) with a dynamic timeout (base 30 " @@ -200,38 +203,38 @@ msgstr "" "동적 시간 제한(기본 30초 + 100MiB당 10초)을 사용하여 완료 " "확인(``server_received_file_data_sign``)을 기다립니다." -#: ../../source/File_Transfer/File_Transfer.rst:100 -#: b2944c94e7a9468daf924f021a5f0bab +#: ../../source/File_Transfer/File_Transfer.rst:101 +#: b80094b922a24c409f10eb9c8b05373b msgid "The receiver performs the complementary steps:" msgstr "수신기는 보완적인 단계를 수행합니다." -#: ../../source/File_Transfer/File_Transfer.rst:102 -#: 1353e95158fc496db86676f544168584 +#: ../../source/File_Transfer/File_Transfer.rst:103 +#: 5f71fc707ffe4b06a275b3db9f77178d msgid "Send the start signal." msgstr "시작 신호를 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:103 -#: e32e19b7ac2e4a20a76a7c5640212835 +#: ../../source/File_Transfer/File_Transfer.rst:104 +#: 7132d6fe15ce42a3bef64e0073e9baff msgid "Read the 4-byte length, then the filename, then the 8-byte size." msgstr "4바이트 길이, 파일 이름, 8바이트 크기를 차례로 읽습니다." -#: ../../source/File_Transfer/File_Transfer.rst:105 -#: 1bbea38ba8ec4f84970f408827ba1be4 +#: ../../source/File_Transfer/File_Transfer.rst:106 +#: 7e0fcaec6d704455b94fc9f7defbef55 msgid "Acknowledge the header with ``server_received_file_header_sign``." msgstr "``server_received_file_header_sign``으로 헤더를 확인합니다." -#: ../../source/File_Transfer/File_Transfer.rst:107 -#: ef7144f2c0c94c9fa25c2a5bad6ed5e8 +#: ../../source/File_Transfer/File_Transfer.rst:108 +#: d6a854d18d404082bdec0e2cf355ea62 msgid "Receive the file data in chunks and write to disk." msgstr "파일 데이터를 청크로 받아 디스크에 씁니다." -#: ../../source/File_Transfer/File_Transfer.rst:108 -#: bb81c955e5024b6d9b6042fa3eb4c13f +#: ../../source/File_Transfer/File_Transfer.rst:109 +#: 69981b7e399e4de89858906b286aaf06 msgid "Acknowledge completion with ``server_received_file_data_sign``." msgstr "``server_received_file_data_sign``으로 완료를 확인합니다." -#: ../../source/File_Transfer/File_Transfer.rst:111 -#: cd24d3a3f8704419889c764cf5812a99 +#: ../../source/File_Transfer/File_Transfer.rst:112 +#: b98957309caf49eba2657154bffbaf90 msgid "" "Any error during the exchange causes the failing side to send " "``error_sign``, and both sides close the transfer socket. The main " @@ -240,25 +243,25 @@ msgstr "" "교환 중 오류가 발생하면 실패한 쪽에서 ``error_sign``을 보내고 양쪽 모두 전송 소켓을 닫습니다. 메인 제어 연결은 " "영향을 받지 않습니다." -#: ../../source/File_Transfer/File_Transfer.rst:120 -#: 0313763b7bc6427cb80da39d09a94be1 +#: ../../source/File_Transfer/File_Transfer.rst:121 +#: f289e3c6e5b445f48eda6ed3434c9de8 msgid "Client-Initiated Transfer (Client → Server)" msgstr "클라이언트 시작 전송(클라이언트 → 서버)" -#: ../../source/File_Transfer/File_Transfer.rst:122 -#: 155d9f3383cf42fe8fa0e4fe095fbae7 +#: ../../source/File_Transfer/File_Transfer.rst:123 +#: 17e1ddd91efe4690ad00f85f54875eda msgid "" "When the user types a file-related command in the client's interactive " "console, the call chain proceeds as follows." msgstr "사용자가 클라이언트의 대화형 콘솔에 파일 관련 명령을 입력하면 콜 체인은 다음과 같이 진행됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:126 -#: ab7df52a36c742a0be4924b613ddebd4 +#: ../../source/File_Transfer/File_Transfer.rst:127 +#: 9cacd6ea79a14ff6ae602d7ed47926c8 msgid "### Console Input Handling" msgstr "### 콘솔 입력 처리" -#: ../../source/File_Transfer/File_Transfer.rst:128 -#: 42cde8d25ccd4424b5c871c7adf3af91 +#: ../../source/File_Transfer/File_Transfer.rst:129 +#: 07a7b69b45d04950877f071f25ad7c2c #, fuzzy msgid "" "In ``TCP_Client_Base.interactive_mode()``, user input is read line by " @@ -272,19 +275,19 @@ msgstr "" "명령이 인식됩니다. 이러한 각 명령에 대해 클라이언트는 해당 스레드로부터 안전한 진입점(``_thread``로 끝나는 메서드)을 " "호출합니다." -#: ../../source/File_Transfer/File_Transfer.rst:136 -#: 08d0c910eba54d3cb8447d3cea15064f +#: ../../source/File_Transfer/File_Transfer.rst:137 +#: 250bb94df2a14d339b150a70e8fed215 #, fuzzy msgid "### Entry Points" msgstr "### 스레드로부터 안전한 진입점" -#: ../../source/File_Transfer/File_Transfer.rst:138 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:139 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "The console dispatches to these methods:" msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:140 -#: 3ddbfd1b9e454342aa47f388d5bc7263 +#: ../../source/File_Transfer/File_Transfer.rst:141 +#: a0f0599853724ff9a15c501c154f52ea #, fuzzy msgid "" "``file_transfer_client_recv_client_start_thread(message, " @@ -294,23 +297,23 @@ msgstr "" "``file_transfer_client_recv_client_start_thread(메시지, " "file_folder_abspath=None)``" -#: ../../source/File_Transfer/File_Transfer.rst:143 -#: 4db440e1419b4ce895c7e03b85b070c1 +#: ../../source/File_Transfer/File_Transfer.rst:144 +#: 9d60213404014fbe8bee542f67d80398 msgid "``folder_file_transfer_client_recv_client_start(message)``" msgstr "``folder_file_transfer_client_recv_client_start(메시지)``" -#: ../../source/File_Transfer/File_Transfer.rst:144 -#: 936c7a26041045da8e4e20ec45d3959d +#: ../../source/File_Transfer/File_Transfer.rst:145 +#: 2e6c7b2b820349ebac90f27d835477d0 msgid "``multiple_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_file_transfer_client_recv_client_start(메시지)``" -#: ../../source/File_Transfer/File_Transfer.rst:145 -#: 972ecc6300354468b126961a483ecf2c +#: ../../source/File_Transfer/File_Transfer.rst:146 +#: bdee0e9084194b45b5fad3a44e9aaf85 msgid "``multiple_folder_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_folder_file_transfer_client_recv_client_start(메시지)``" -#: ../../source/File_Transfer/File_Transfer.rst:147 -#: fef1e1b2a2024f89abd300268004380d +#: ../../source/File_Transfer/File_Transfer.rst:148 +#: ae9108b44e304198a7d0bff6bae8ab60 msgid "" "The last three run synchronously on the console thread; they walk the " "tree or the file list and spawn one worker thread per file themselves, so" @@ -319,13 +322,13 @@ msgid "" "``max_thread_num`` of them run at once." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:153 -#: f5919b72c7ec40e2a1b1d49cf57c9021 +#: ../../source/File_Transfer/File_Transfer.rst:154 +#: 8e945e4bdc124e749ee0a5976249a787 msgid "### Worker Function (Client Side)" msgstr "### 작업자 함수(클라이언트 측)" -#: ../../source/File_Transfer/File_Transfer.rst:155 -#: 70bed6a3ccbd47e89653ab1b2d62fb9d +#: ../../source/File_Transfer/File_Transfer.rst:156 +#: cc8b9fc35bfb4cf395a2114786c01718 msgid "" "The core worker function for a single file is " "``file_transfer_client_recv_client_start(message, " @@ -334,13 +337,13 @@ msgstr "" "단일 파일에 대한 핵심 작업자 함수는 ``file_transfer_client_recv_client_start(message, " "file_folder_abspath=None)``입니다. 그 논리는 다음과 같습니다." -#: ../../source/File_Transfer/File_Transfer.rst:160 -#: f7103ca89460442ba018095bf48ae23c +#: ../../source/File_Transfer/File_Transfer.rst:161 +#: e3d81c4f4e724d81b426fdbfedb9c062 msgid "Allocate a unique client ID using the lock ``file_client_id_lock``." msgstr "``file_client_id_lock`` 잠금을 사용하여 고유한 클라이언트 ID를 할당합니다." -#: ../../source/File_Transfer/File_Transfer.rst:162 -#: ea5fe1051d864a3caccc15bf2373b03e +#: ../../source/File_Transfer/File_Transfer.rst:163 +#: 81b9ac67e27341c0a17468f3b6787d14 msgid "" "Extend the original command string with the client ID (e.g., ``/file " "mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server " @@ -349,15 +352,15 @@ msgstr "" "원래 명령 문자열을 클라이언트 ID로 확장하고(예: ``/file mydoc.txt``는 ``/file mydoc.txt 42``가" " 됨) ``send_message()``를 사용하여 기본 제어 연결을 통해 서버로 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:168 -#: b56d7f67a1844b0cb893a3939ed8ed70 +#: ../../source/File_Transfer/File_Transfer.rst:169 +#: af07c5ef546a4102bbb836b65b2fd3be msgid "" "Obtain a local port for the outgoing file transfer socket by calling " "``palloc()``." msgstr "``palloc()``을 호출하여 나가는 파일 전송 소켓에 대한 로컬 포트를 얻습니다." -#: ../../source/File_Transfer/File_Transfer.rst:171 -#: 83314b464667496cb415f119beb0dc31 +#: ../../source/File_Transfer/File_Transfer.rst:172 +#: 37226a4f2e1e4a878ba325fca05df9bf msgid "" "Wait (up to 20 seconds) for the server to reply with a port number. The " "server's reply (``/server_file_transfer_port ``) is " @@ -368,8 +371,8 @@ msgstr "" " ``)은 기본 연결에서 수신되어 ``file_server_port_list``에 저장됩니다. " "일치하는 항목이 발견되면 포트가 추출됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:179 -#: bd938c291cbe44aa913d35413fc76a6b +#: ../../source/File_Transfer/File_Transfer.rst:180 +#: e9cd68239fe3498597f07ccfa774ae22 msgid "" "Call the low-level send function ``file_transfer_mode(filename, " "server_host, server_port, client_port)``." @@ -377,8 +380,8 @@ msgstr "" "하위 수준 전송 함수 ``file_transfer_mode(filename, server_host, server_port, " "client_port)``를 호출합니다." -#: ../../source/File_Transfer/File_Transfer.rst:183 -#: 75779fa321754e05adc2ee87ac490f07 +#: ../../source/File_Transfer/File_Transfer.rst:184 +#: 145c524c53654e84a0bb45d3a065733e #, fuzzy msgid "" "For folder transfers, the worker function " @@ -399,8 +402,8 @@ msgstr "" "``file_transfer_client_recv_client_start_thread``를 호출합니다. " "세마포어(``file_semaphore``)는 동시 파일 전송 수를 ``max_thread_num``으로 제한합니다." -#: ../../source/File_Transfer/File_Transfer.rst:198 -#: bbb76713d93e4920a87d1551cbdf9999 +#: ../../source/File_Transfer/File_Transfer.rst:199 +#: 5a7d502137c8442eafae448cee95a72a msgid "" "``multiple_file_transfer_client_recv_client_start`` loops over the given " "files and starts one worker thread per file, each holding " @@ -408,13 +411,13 @@ msgid "" "are capped by ``max_thread_num`` on that path too." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:203 -#: d9634b910f4f4509a717a6e7cb8445e2 +#: ../../source/File_Transfer/File_Transfer.rst:204 +#: 4ae4777e086a48558cbe3dda0ecdb3fb msgid "### Server-Side Handler (Receiving)" msgstr "### 서버측 핸들러(수신)" -#: ../../source/File_Transfer/File_Transfer.rst:205 -#: ecf51220b2924da78e59cd7118a5d976 +#: ../../source/File_Transfer/File_Transfer.rst:206 +#: 66a812ac1ac84ad2b912deb843f3c059 msgid "" "When the server receives an extended command like ``/file mydoc.txt 42`` " "on the main control connection, ``handle_command`` detects it and calls:" @@ -422,8 +425,8 @@ msgstr "" "서버가 주 제어 연결에서 ``/file mydoc.txt 42``와 같은 확장 명령을 수신하면 ``handle_command``가 " "이를 감지하고 다음을 호출합니다." -#: ../../source/File_Transfer/File_Transfer.rst:210 -#: 7437faffb1f7433faaea35c296c7ab96 +#: ../../source/File_Transfer/File_Transfer.rst:211 +#: 081e020d3e674d01bfde15c0922aa25c msgid "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " command)``" @@ -431,13 +434,13 @@ msgstr "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " 명령)``" -#: ../../source/File_Transfer/File_Transfer.rst:213 -#: 1ff4d8b0423b490db4a9b179d745dcb7 +#: ../../source/File_Transfer/File_Transfer.rst:214 +#: 4b5b5057002a457db83aed00c6148a7f msgid "The server then:" msgstr "그러면 서버는 다음을 수행합니다." -#: ../../source/File_Transfer/File_Transfer.rst:215 -#: 988de890b2fc4ebfbe68944b368ce5b8 +#: ../../source/File_Transfer/File_Transfer.rst:216 +#: e2ad0e97b7854be4a3dded6cf7d602b7 msgid "" "Creates a new thread via " "``file_transfer_server_recv_server_start(client_id, client_socket, " @@ -446,13 +449,13 @@ msgstr "" "``file_transfer_server_recv_server_start(client_id, client_socket, " "command, new_save_path=None, file_name=None)``을 통해 새 스레드를 생성합니다." -#: ../../source/File_Transfer/File_Transfer.rst:219 -#: 47e1493ecf784674924778f581e6a71a +#: ../../source/File_Transfer/File_Transfer.rst:220 +#: ee8cdc9ae93c4579a05e37b32c86f705 msgid "Allocates a transfer port with ``palloc()``." msgstr "``palloc()``으로 전송 포트를 할당합니다." -#: ../../source/File_Transfer/File_Transfer.rst:220 -#: b19bd45b30ee42178dab7b9aafa79e5e +#: ../../source/File_Transfer/File_Transfer.rst:221 +#: ac8a87e1e481417284d90ba8cb843415 msgid "" "Calls ``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``." @@ -460,8 +463,8 @@ msgstr "" "``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``를 호출합니다." -#: ../../source/File_Transfer/File_Transfer.rst:223 -#: a2f55cc995c14ec1ac34545e458dccb2 +#: ../../source/File_Transfer/File_Transfer.rst:224 +#: 2f6675b7698c41938542b09cbfb482e8 msgid "" "This low-level receive function sets up a listening socket on the " "allocated port, sends the port number back to the client (as " @@ -475,20 +478,20 @@ msgstr "" ":ref:`file-transfer-protocol`에 설명된 프로토콜 단계를 수행합니다. 수신된 파일은 " "``received_files/``(또는 폴더 전송이 요청된 경우 하위 디렉터리)에 저장됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:233 -#: da7e5a1f96b3422bbfd8f056eb28dae3 +#: ../../source/File_Transfer/File_Transfer.rst:234 +#: 9fe861572b8746aeaa8266d8d30f963f msgid "" "After the transfer completes (or fails), the port is released with " "``pfree()``." msgstr "전송이 완료(또는 실패)된 후 ``pfree()``를 사용하여 포트가 해제됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:240 -#: e9956de8dffe4d898caed46c0e78c93b +#: ../../source/File_Transfer/File_Transfer.rst:241 +#: 3e4e81fa8cea4ef5ab2a39602eb29355 msgid "Server-Initiated Transfer (Server → Client)" msgstr "서버 시작 전송(서버 → 클라이언트)" -#: ../../source/File_Transfer/File_Transfer.rst:242 -#: 5e8dbd4b351d467cb809c3182feac0a2 +#: ../../source/File_Transfer/File_Transfer.rst:243 +#: 3ab21d4beefb41be83651eec10fd3899 msgid "" "When the server administrator types a command in the server console, for " "example ``/file /path/to/file.txt (127.0.0.1,54321)``, the console input " @@ -498,13 +501,13 @@ msgstr "" "서버 관리자가 서버 콘솔에 명령(예: ``/file /path/to/file.txt (127.0.0.1,54321)``)을 입력하면" " 콘솔 입력 스레드(``console_input``)가 명령을 구문 분석하고 적절한 서버측 파일 전송 API를 호출합니다." -#: ../../source/File_Transfer/File_Transfer.rst:250 -#: 3bec81e76a2c4bf3b37386e180cc4fc1 +#: ../../source/File_Transfer/File_Transfer.rst:251 +#: fa019410dca84c04b24bf9334131aa8d msgid "The recommended entry points for server-to-client transfers are:" msgstr "서버-클라이언트 전송에 권장되는 진입점은 다음과 같습니다." -#: ../../source/File_Transfer/File_Transfer.rst:253 -#: 585d149b4b3f47f09176b4b61d3baeaa +#: ../../source/File_Transfer/File_Transfer.rst:254 +#: 99103b4e1f234e2dac2ffc955ab5b23e msgid "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` for a single file." @@ -512,13 +515,13 @@ msgstr "" "단일 파일의 경우 ``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)``." -#: ../../source/File_Transfer/File_Transfer.rst:256 -#: 81935504645c451b844d109037b46ae0 +#: ../../source/File_Transfer/File_Transfer.rst:257 +#: a1560a9b45c043618778f38beb1c3cb2 msgid "``folder_file_transfer_server_recv_client_start(message)`` for a folder." msgstr "폴더에 대한 ``folder_file_transfer_server_recv_client_start(message)``." -#: ../../source/File_Transfer/File_Transfer.rst:258 -#: 4ca3cac907c04414925f5219b700d0e5 +#: ../../source/File_Transfer/File_Transfer.rst:259 +#: c18cb827a52f48d6b2883b708e2c871e msgid "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " for multiple files to multiple clients." @@ -526,8 +529,8 @@ msgstr "" "여러 클라이언트에 대한 여러 파일의 경우 " "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``." -#: ../../source/File_Transfer/File_Transfer.rst:260 -#: 536f30cc03f84b218a5ca9b84deb9f88 +#: ../../source/File_Transfer/File_Transfer.rst:261 +#: 1b9fd8eea75e46899f68c6ca1312e896 msgid "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " for different file lists to different clients." @@ -535,8 +538,8 @@ msgstr "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " 다른 파일 목록에 대해 다른 클라이언트로." -#: ../../source/File_Transfer/File_Transfer.rst:263 -#: 92500d9fd7124d9ca7b648f03df90141 +#: ../../source/File_Transfer/File_Transfer.rst:264 +#: d34ac75777c74fe4bc63e1a100fd2aa3 msgid "" "The worker function ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` performs the following steps:" @@ -544,8 +547,8 @@ msgstr "" "작업자 함수 ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)``는 다음 단계를 수행합니다." -#: ../../source/File_Transfer/File_Transfer.rst:268 -#: 583e8c89824f46ae839d233ab9e70e1a +#: ../../source/File_Transfer/File_Transfer.rst:269 +#: 29d03e172fd346e2a7928b55510df4f1 msgid "" "Extract the target client address from the last part of the command " "(e.g., ``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the " @@ -554,20 +557,20 @@ msgstr "" "``ast.literal_eval()``을 사용하여 명령의 마지막 부분(예: ``(127.0.0.1,54321)``)에서 대상 " "클라이언트 주소를 추출합니다. ``self.clients``에서 클라이언트 소켓을 얻습니다." -#: ../../source/File_Transfer/File_Transfer.rst:273 -#: fd63ce90d3794b2181cdaa927e1a7a38 +#: ../../source/File_Transfer/File_Transfer.rst:274 +#: 7a8d8ed423524d6e91a311a3aa3d5a9a msgid "" "Allocate a unique client ID and extend the command with it, then send the" " extended command to the client over the main connection." msgstr "고유한 클라이언트 ID를 할당하고 이를 사용하여 명령을 확장한 다음 기본 연결을 통해 확장된 명령을 클라이언트에 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:277 -#: 6138738f134b48b2a98d05d3569172c7 +#: ../../source/File_Transfer/File_Transfer.rst:278 +#: 94b6c1f8a6a240e4ba4be8cf20f87c7f msgid "Allocate a local port with ``palloc()``." msgstr "``palloc()``을 사용하여 로컬 포트를 할당합니다." -#: ../../source/File_Transfer/File_Transfer.rst:278 -#: 26fa94f94e1841f6845765f4fd65949d +#: ../../source/File_Transfer/File_Transfer.rst:279 +#: 723a05b6c3974b65a539af723f1e0872 msgid "" "Wait for the client to reply with its own port number (via " "``/server_file_transfer_port``), which is stored in " @@ -576,8 +579,8 @@ msgstr "" "클라이언트가 기본 연결의 메시지 핸들러에 의해 ``file_server_port_list``에 저장된 자체 포트 " "번호(``/server_file_transfer_port``를 통해)로 응답할 때까지 기다립니다." -#: ../../source/File_Transfer/File_Transfer.rst:283 -#: 4bd913210d8945ffb7312070e070f252 +#: ../../source/File_Transfer/File_Transfer.rst:284 +#: 878572ca3d2948a9acbb6741f00ddd62 msgid "" "Call ``file_transfer_mode(filename, client_host, client_port, " "local_port)`` to send the file." @@ -585,8 +588,8 @@ msgstr "" "``file_transfer_mode(filename, client_host, client_port, local_port)``를 " "호출하여 파일을 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:287 -#: 39d0bdae658241a0a8205977cccd0395 +#: ../../source/File_Transfer/File_Transfer.rst:288 +#: ca517571b2d34c0497fcf5d5b12c93a1 msgid "" "On the client side, when it receives a command like ``/file " "/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls" @@ -603,13 +606,13 @@ msgstr "" " 할당하고, ``/server_file_transfer_port``로 응답하고, ``file_transfer_mode_recv``를" " 호출하여 파일을 수신하고 저장합니다." -#: ../../source/File_Transfer/File_Transfer.rst:303 -#: 014166967bb14b20a2782598b535575a +#: ../../source/File_Transfer/File_Transfer.rst:304 +#: cb7bdf5091e54e039de9d5578c273b93 msgid "Folder Transfer Mechanism (Detailed)" msgstr "폴더 전송 메커니즘(상세)" -#: ../../source/File_Transfer/File_Transfer.rst:305 -#: 38eff5e62e844c0e94d587ba7132d26c +#: ../../source/File_Transfer/File_Transfer.rst:306 +#: b282df0b45bd4bb087ae10816fd3f06d msgid "" "Transferring a folder is implemented as a **recursive walk** that sends " "separate commands for subdirectories and files. The logic is symmetric on" @@ -618,25 +621,25 @@ msgstr "" "폴더 전송은 하위 디렉터리와 파일에 대해 별도의 명령을 보내는 **재귀적 탐색**으로 구현됩니다. 논리는 클라이언트와 서버 모두에서" " 대칭입니다." -#: ../../source/File_Transfer/File_Transfer.rst:311 -#: 7319cca2fbef48679002d3bf0469d842 +#: ../../source/File_Transfer/File_Transfer.rst:312 +#: fb34b1f5d8a4488b9aef8b71dcb764ec msgid "### Creating Directories" msgstr "### 디렉터리 만들기" -#: ../../source/File_Transfer/File_Transfer.rst:313 -#: ad592f4510c34ecca1cba340caa2710e +#: ../../source/File_Transfer/File_Transfer.rst:314 +#: 6b67f2390d914745a253523cef9a2e0b msgid "" "For a directory that needs to be created on the receiver side, the sender" " sends a command of the form:" msgstr "수신자 측에서 생성해야 하는 디렉터리의 경우 발신자는 다음 형식의 명령을 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:317 -#: 114e36ce42e940cc8f0ec8c64c1db031 +#: ../../source/File_Transfer/File_Transfer.rst:318 +#: 7aaf85bf38fa4621a760dc56b6f99ad6 msgid "``/file_folder ``" msgstr "``/파일_폴더 <상대_경로>``" -#: ../../source/File_Transfer/File_Transfer.rst:319 -#: a120552b93294a059a34132ab935068a +#: ../../source/File_Transfer/File_Transfer.rst:320 +#: 046f125a1f6e41e4808a9cd703e34ee4 msgid "" "The receiver's handler for this command (in either " "``file_folder_transfer_server_recv_server_start_thread`` or " @@ -651,23 +654,23 @@ msgstr "" " 경우 ``received_files/``, 클라이언트의 경우 동일한 디렉터리) 아래에 해당 디렉터리를 생성합니다. 상대 경로는 " "슬래시를 사용하여 플랫폼 독립적입니다." -#: ../../source/File_Transfer/File_Transfer.rst:330 -#: 2743fec0a2434e2b96ea3c49fecf268c +#: ../../source/File_Transfer/File_Transfer.rst:331 +#: 3fb5d6322ccd47f79e601e38684fe234 msgid "### Sending Files Inside a Folder" msgstr "### 폴더 내에서 파일 보내기" -#: ../../source/File_Transfer/File_Transfer.rst:332 -#: fb31b657a05547109dea51165844a632 +#: ../../source/File_Transfer/File_Transfer.rst:333 +#: c9f77546ed49407fa57c57f0b0a76acf msgid "For each file, the sender sends a command of the form:" msgstr "각 파일에 대해 보낸 사람은 다음 형식의 명령을 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:334 -#: 2da676ce8dd649169ba224f6d29cbbc9 +#: ../../source/File_Transfer/File_Transfer.rst:335 +#: f5a164466b0d4d4382b7d880bd320e3d msgid "``/file_folder ``" msgstr "``/파일_폴더 <상대_경로> <파일_이름>``" -#: ../../source/File_Transfer/File_Transfer.rst:336 -#: 8972f356722148e3b34cbaa95390d700 +#: ../../source/File_Transfer/File_Transfer.rst:337 +#: c507cca92d1c463ea9f4d429a38a9b6a msgid "" "The receiver treats this as a file transfer request. The second argument " "(``file_name``) is used as the final filename, and the relative path " @@ -681,13 +684,13 @@ msgstr "" "따라 ``file_transfer_client_recv_client_start`` 또는 " "``file_transfer_server_recv_client_start``를 통해)." -#: ../../source/File_Transfer/File_Transfer.rst:347 -#: a0ded05fd7f2406abb0ee41fcc33b53b +#: ../../source/File_Transfer/File_Transfer.rst:348 +#: e1e2b8dd57524ecfabd47c2c8386dfea msgid "### Concurrency Control for Folders" msgstr "### 폴더 동시성 제어" -#: ../../source/File_Transfer/File_Transfer.rst:349 -#: 14b0ec4d109c448198db41c196df8a70 +#: ../../source/File_Transfer/File_Transfer.rst:350 +#: 32b26f72bba4482490f38968dcee5837 msgid "" "Because a folder can contain many files, the sender uses a semaphore " "(``file_semaphore``) to limit the number of concurrently active file " @@ -700,13 +703,13 @@ msgstr "" "전송 수를 제한합니다. 세마포어는 각 파일 전송을 시작하기 전에 획득되어 ``finally`` 블록에서 해제됩니다. 최대 동시성은 " "클라이언트의 ``max_thread_num``과 서버의 ``max_file_transfer_thread_num``으로 설정됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:362 -#: 2c7d84b855df4587bfb110f525299e39 +#: ../../source/File_Transfer/File_Transfer.rst:363 +#: 8ce424a7f1de4933b3113a0e3ab98155 msgid "Custom Destination Directory" msgstr "사용자 정의 대상 디렉토리" -#: ../../source/File_Transfer/File_Transfer.rst:364 -#: b972e019f10143a99af9de9b7a8e371a +#: ../../source/File_Transfer/File_Transfer.rst:365 +#: 6ca8ee9f021842939f446e999c067dfb msgid "" "Every transfer family accepts an optional trailing " "``destination_file_path`` argument that replaces the receiver's default " @@ -718,8 +721,8 @@ msgstr "" "``file_transfer_dir``)를 대체하는 선택적 후행 ``destination_file_path`` 인수를 허용합니다. " "생략하면 이전과 동일하게 기본 위치로 전송됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:372 -#: 1e801c2a599e4595b5f883ada1a63fc6 +#: ../../source/File_Transfer/File_Transfer.rst:373 +#: 6291da89ffa542dfbd94f599a9321216 msgid "" "The destination is **always the last argument** of the command and names " "a *directory* on the receiving machine: the received file keeps its own " @@ -733,59 +736,59 @@ msgstr "" "대상(``//...``) 아래의 구조를 유지합니다. 절대 경로는 있는 그대로 " "사용됩니다. 상대 경로는 기본 저장 디렉터리에서 확인됩니다. 누락된 디렉터리가 생성됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:384 -#: 6b85151737b64a3e90154ba763b205d2 +#: ../../source/File_Transfer/File_Transfer.rst:385 +#: 76243e0349c1474bbdf14e1ef2a8e52b msgid "Command syntax:" msgstr "명령 구문:" -#: ../../source/File_Transfer/File_Transfer.rst:386 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:387 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "Client console (the receiver is the server):" msgstr "클라이언트 콘솔(수신자는 서버임):" -#: ../../source/File_Transfer/File_Transfer.rst:388 -#: bac62d5b11c84f96b2b3841af7fc7a85 +#: ../../source/File_Transfer/File_Transfer.rst:389 +#: c9fa612895bc4f92839d2de77b6cbc7f msgid "``/file [destination_file_path]``" msgstr "``/파일 <파일_경로> [대상_파일_경로]``" -#: ../../source/File_Transfer/File_Transfer.rst:390 -#: aa07623d0b4048be944b30c6fc07cc1b +#: ../../source/File_Transfer/File_Transfer.rst:391 +#: 2d34a030a1804d299a0b56c14984b1b5 msgid "``/multiple_file ... [destination_file_path]``" msgstr "``/다중_파일 <파일1> <파일2> ... [대상_파일_경로]``" -#: ../../source/File_Transfer/File_Transfer.rst:392 -#: 1a9cfb266bb24df6ac2ddeb286a212d0 +#: ../../source/File_Transfer/File_Transfer.rst:393 +#: a7dd1e241a4346d4b873072c5948f187 #, fuzzy msgid "``/file_folder [destination_file_path]``" msgstr "``/파일_폴더 <상대_경로>``" -#: ../../source/File_Transfer/File_Transfer.rst:394 -#: 46f89a56ef594dec945f21425306e2de +#: ../../source/File_Transfer/File_Transfer.rst:395 +#: 953993d920eb4959987d98423440ce61 msgid "``/multiple_file_folder ... [destination_file_path]``" msgstr "``/다중_파일_폴더 <폴더1> <폴더2> ... [대상_파일_경로]``" -#: ../../source/File_Transfer/File_Transfer.rst:396 -#: 085ba670e149450a8b385d68c8f9d366 +#: ../../source/File_Transfer/File_Transfer.rst:397 +#: 886c8b7d760044cabe48ce044412ca64 #, fuzzy msgid "" "Server console (the receiver is the target client, given as a quoted " "``(ip, port)`` address tuple, not as a client id):" msgstr "서버 콘솔(수신자는 인용된 주소 튜플로 지정된 대상 클라이언트입니다):" -#: ../../source/File_Transfer/File_Transfer.rst:400 -#: abc0fb96992e4b09aaa9714ba73a094b +#: ../../source/File_Transfer/File_Transfer.rst:401 +#: 48d3bf6084224062867313a9597044d7 #, fuzzy msgid "``/file <(ip, port)> [destination_file_path]``" msgstr "``/파일 <파일_경로> [대상_파일_경로]``" -#: ../../source/File_Transfer/File_Transfer.rst:402 -#: d9329c72161247bf8d5f0a609178c488 +#: ../../source/File_Transfer/File_Transfer.rst:403 +#: 684fa9b22136418b94cbb4202f702cd2 #, fuzzy msgid "``/file_folder <(ip, port)> [destination_file_path]``" msgstr "``/파일_폴더 <상대_경로>``" -#: ../../source/File_Transfer/File_Transfer.rst:404 -#: af78c6ec2f3e4072aaac19d2d131cf5d +#: ../../source/File_Transfer/File_Transfer.rst:405 +#: 9380dc31685947e3a835107f435deed2 #, fuzzy msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -794,16 +797,16 @@ msgstr "" "``/multiple_file_multiple_client ... " " ... [대상_파일_경로]``" -#: ../../source/File_Transfer/File_Transfer.rst:406 -#: 2fdbf92caa6a46df9dae793592be802d +#: ../../source/File_Transfer/File_Transfer.rst:407 +#: 62488b8bb4e149be86c1d655bd80b6a8 #, fuzzy msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, port)1> ... " "[destination_file_path]``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:408 -#: abc1dac22b594c54a22b03d59e1a8338 +#: ../../source/File_Transfer/File_Transfer.rst:409 +#: d6a0c51014c9403fb82ebdf5c93928bc msgid "" "For the multiple-item commands the destination is the last argument; when" " the last argument is not a ``(ip, port)`` tuple it is treated as the " @@ -813,13 +816,13 @@ msgid "" "destination)." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:418 -#: 0c7fa56659f543ed93adacd874dd2e8b +#: ../../source/File_Transfer/File_Transfer.rst:419 +#: 373c2a5a23334df7a25d23f8d94abd66 msgid "Native In-Memory Forwarding" msgstr "네이티브 메모리 내 전달" -#: ../../source/File_Transfer/File_Transfer.rst:420 -#: 133205c62a0846318b30f5f5fe0dc296 +#: ../../source/File_Transfer/File_Transfer.rst:421 +#: dd57639b3e0e4068bd9533fc039597cd #, fuzzy msgid "" "The main protocol also provides a native, client-side forwarding feature " @@ -834,30 +837,30 @@ msgstr "" " 클라이언트 측 전달 기능을 제공합니다. 디스크에 업로드한 다음 디스크에서 다운로드하는 순방향 확장과 달리 서버는 데이터를 " "메모리에만 보유하고 대상 클라이언트로 직접 스트리밍합니다. 이렇게 하면 이중 전송 시간과 디스크 읽기/쓰기 오버헤드가 방지됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:432 -#: b177ec0385be4e9da692646b88cd3ed8 +#: ../../source/File_Transfer/File_Transfer.rst:433 +#: 982c4c9538914821a07887fb8ab9b95d #, fuzzy msgid "Commands (client console only; rejected on the server console):" msgstr "클라이언트 콘솔(수신자는 서버임):" -#: ../../source/File_Transfer/File_Transfer.rst:435 -#: 789bd7878891443fa43ec5111b3a028b +#: ../../source/File_Transfer/File_Transfer.rst:436 +#: 14406316555743359a854540ab6937c8 #, fuzzy msgid "" "``/forward_file ... ... " "[destination_file_path]``" msgstr "``/forward_file <파일1> <파일2> ... ...``" -#: ../../source/File_Transfer/File_Transfer.rst:436 -#: 04d9ece635c94b8c9257e0cb41bd5b81 +#: ../../source/File_Transfer/File_Transfer.rst:437 +#: 4dc576898177404da124649f7ce9ac28 #, fuzzy msgid "" "``/forward_folder ... ... " "[destination_file_path]``" msgstr "``/forward_folder <폴더1> <폴더2> ... ...``" -#: ../../source/File_Transfer/File_Transfer.rst:438 -#: 2f7b628a4e0246e385e9e8817b8d7a87 +#: ../../source/File_Transfer/File_Transfer.rst:439 +#: 220dfbf0a0d84559a8befb4eee500ba0 msgid "" "The number of files/folders and the number of target clients (written as " "quoted address tuples) is unlimited. Target addresses that are " @@ -867,8 +870,8 @@ msgstr "" "파일/폴더 수와 대상 클라이언트 수(따옴표로 묶인 주소 튜플로 작성됨)는 무제한입니다. 연결할 수 없거나(서버에 연결되지 않음) " "서버 자체와 동일한 대상 주소는 건너뛰고 나머지 대상은 계속 제공됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:446 -#: 84f3e0acf89e4767bbb572cc6edc81aa +#: ../../source/File_Transfer/File_Transfer.rst:447 +#: 6137bf9406784c6f82d9f41560a52566 msgid "" "Like every transfer family, both commands accept an optional trailing " "``destination_file_path`` that replaces the default save directory on " @@ -882,24 +885,24 @@ msgstr "" "있고 전달된 폴더는 ''//... `` 아래에 구조를 유지합니다. 인수를 생략하면 " "대상은 기본 `` file_transfer_dir `` 에 쓸 수 있습니다." -#: ../../source/File_Transfer/File_Transfer.rst:457 -#: 6b31e93335824fe1bfdb83b84f42f08c +#: ../../source/File_Transfer/File_Transfer.rst:458 +#: f6697695e9ef4e3694fa9046e41578e0 msgid "The data path reuses the protocol's own transfer machinery:" msgstr "데이터 경로는 프로토콜의 자체 전송 메커니즘을 재사용합니다." -#: ../../source/File_Transfer/File_Transfer.rst:460 -#: 469812eff1874189a000989c9260cf1b +#: ../../source/File_Transfer/File_Transfer.rst:461 +#: 6ee037f0e4024d2988fcb2ccf3deef70 #, fuzzy msgid "" "The forwarding client streams the file with the standard file-transfer " -"byte stream (metadata header + 65536-byte chunks) to a transfer socket on" -" the server." +"byte stream (metadata header + ``file_transfer_chunk_len``-byte chunks, " +"default 65536) to a transfer socket on the server." msgstr "" "전달 클라이언트는 표준 파일 전송 바이트 스트림(메타데이터 헤더 + 64KiB 청크)을 사용하여 파일을 서버의 전송 소켓으로 " "스트리밍합니다." -#: ../../source/File_Transfer/File_Transfer.rst:465 -#: 42efd096a6744f489dc623a6ee503666 +#: ../../source/File_Transfer/File_Transfer.rst:467 +#: 43c94e746a5c46748846d0dc18a4e0ff msgid "" "The server acts as a pure relay: it reads the stream into per-target " "memory queues and writes each chunk to every target's transfer socket. " @@ -909,8 +912,8 @@ msgstr "" "서버는 순수 릴레이 역할을 합니다. 즉, 스트림을 대상별 메모리 대기열로 읽고 각 청크를 모든 대상의 전송 소켓에 씁니다. 서버는 " "크기 헤더를 초과하는 파일 내용을 구문 분석하지 않으며 디스크에 쓰지 않습니다." -#: ../../source/File_Transfer/File_Transfer.rst:472 -#: f43cb20c7bc648018f6f77ea09c8d538 +#: ../../source/File_Transfer/File_Transfer.rst:474 +#: 9dec57916af34e109bee7ce1e0bae2d4 msgid "" "Every target client receives the stream with the ordinary receive path " "(``file_transfer_mode_recv``) and writes it to its own local disk, " @@ -919,13 +922,13 @@ msgstr "" "모든 대상 클라이언트는 일반 수신 경로(``file_transfer_mode_recv``)로 스트림을 수신하고 서버가 파일을 직접 " "푸시한 것처럼 이를 자체 로컬 디스크에 씁니다." -#: ../../source/File_Transfer/File_Transfer.rst:478 -#: 3885df70422e4306ac80be623aa9581f +#: ../../source/File_Transfer/File_Transfer.rst:480 +#: a095abaf821e41a6a66adbb776bc35ef msgid "### Memory Bounding and Flow Control" msgstr "### 메모리 경계 및 흐름 제어" -#: ../../source/File_Transfer/File_Transfer.rst:480 -#: e371e5b793824e3386b43cb07a4222fd +#: ../../source/File_Transfer/File_Transfer.rst:482 +#: 244214dd675345f8a72b1088ad99fea0 #, fuzzy msgid "" "Because uploader, server and targets may have different bandwidths, data " @@ -950,30 +953,30 @@ msgstr "" "``/pause_trans``/``/start_trans`` 핸들러는 양쪽에 존재하므로 어느 쪽이든 데이터를 버퍼링할 때 전송을 " "조절할 수 있습니다." -#: ../../source/File_Transfer/File_Transfer.rst:504 -#: b737bf957d354491b30903bfb0f89a3b +#: ../../source/File_Transfer/File_Transfer.rst:506 +#: 0aa14deaf6474437b421a65e21fce7d8 msgid "Concurrency and Threading" msgstr "동시성과 스레딩" -#: ../../source/File_Transfer/File_Transfer.rst:506 -#: 505576a3522748318a95cd3937a96834 +#: ../../source/File_Transfer/File_Transfer.rst:508 +#: 825c5e1a8b9b405c967ca49a1861e258 msgid "" "Both the server and the client use multiple levels of concurrency control" " to ensure stability during file transfers." msgstr "서버와 클라이언트 모두 여러 수준의 동시성 제어를 사용하여 파일 전송 중 안정성을 보장합니다." -#: ../../source/File_Transfer/File_Transfer.rst:510 -#: 1d1a7b2ee1434530ae6abb411b0175cc +#: ../../source/File_Transfer/File_Transfer.rst:512 +#: 0d48b1245cd54597928cfc28d5b3c248 msgid "### File Transfer Semaphore" msgstr "### 파일 전송 세마포어" -#: ../../source/File_Transfer/File_Transfer.rst:512 -#: 078680d22b10410db9f7f21fe0e1a91d +#: ../../source/File_Transfer/File_Transfer.rst:514 +#: e2674ee9e0584513bc53aa815603fd24 msgid "Client: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" msgstr "클라이언트: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:514 -#: 777a1dcc1258459d89dacbbb7b946c11 +#: ../../source/File_Transfer/File_Transfer.rst:516 +#: 1c0d27d13ad844159d29c6e662d51d09 msgid "" "Server: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" @@ -981,8 +984,8 @@ msgstr "" "서버: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:517 -#: 315a82a6dd1a420bbe819a806f3b8292 +#: ../../source/File_Transfer/File_Transfer.rst:519 +#: cb65901904c8411ba53fc629023f732d #, fuzzy msgid "" "This semaphore limits the number of simultaneous file transfers (used " @@ -994,13 +997,13 @@ msgstr "" "이 세마포어는 동시 파일 전송 수를 제한합니다(폴더 또는 여러 파일을 보낼 때 주로 사용됨). 각 전송은 자체 스레드에서 실행되며 " "스레드가 시작되기 전에 세마포어를 획득합니다." -#: ../../source/File_Transfer/File_Transfer.rst:524 -#: b39cfe74f74b4b568221d23addc55da3 +#: ../../source/File_Transfer/File_Transfer.rst:526 +#: 6d93783b298e4ce98b999ff890d4a5f4 msgid "### Threading Model" msgstr "### 스레딩 모델" -#: ../../source/File_Transfer/File_Transfer.rst:526 -#: 5586d5cc13a940bb92877b1fed3d03fd +#: ../../source/File_Transfer/File_Transfer.rst:528 +#: 036a972600e645119d8a523fa08a52db msgid "" "Each file transfer runs in a dedicated daemon thread, created by the " "``_thread`` wrapper functions (e.g., " @@ -1011,8 +1014,8 @@ msgstr "" "``file_transfer_client_recv_client_start_thread``)에 의해 생성된 전용 데몬 스레드에서 " "실행됩니다. 이는 느린 전송으로 인해 주 제어 루프가 차단되는 것을 방지합니다." -#: ../../source/File_Transfer/File_Transfer.rst:532 -#: 7b1cceca816c426b865265e0c302c425 +#: ../../source/File_Transfer/File_Transfer.rst:534 +#: a84aaf5f9fb64d92b97c32185a1e7cb5 msgid "" "The thread that receives the transfer command (e.g., the server's " "``handle_command`` thread) does not wait for the transfer to complete; it" @@ -1021,8 +1024,8 @@ msgstr "" "전송 명령을 받는 스레드(예: 서버의 ``handle_command`` 스레드)는 전송이 완료될 때까지 기다리지 않습니다. 작업자 " "스레드를 생성한 후 즉시 반환됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:537 -#: 2d25f2be19fb467bb222d3780e2be853 +#: ../../source/File_Transfer/File_Transfer.rst:539 +#: 669fb6da8e7444dd829a6e14295648b1 msgid "" "The low-level receive function (``file_transfer_mode_recv``) blocks while" " reading from the transfer socket, but because it runs in a dedicated " @@ -1031,13 +1034,13 @@ msgstr "" "낮은 수준의 수신 기능(``file_transfer_mode_recv``)은 전송 소켓에서 읽는 동안 차단되지만 전용 스레드에서 " "실행되기 때문에 기본 연결은 계속 응답합니다." -#: ../../source/File_Transfer/File_Transfer.rst:543 -#: 641bce0854274c369c0b915a1c3d964a +#: ../../source/File_Transfer/File_Transfer.rst:545 +#: e39f8ae06ae84a6b84de8a3008ca17cb msgid "### Thread Pool for Custom Commands" msgstr "### 사용자 정의 명령을 위한 스레드 풀" -#: ../../source/File_Transfer/File_Transfer.rst:545 -#: c41d6414ad5542aa8bbeaa67d28730d5 +#: ../../source/File_Transfer/File_Transfer.rst:547 +#: 3ad49853529d4563bacdfb4ca6eee115 msgid "" "Both classes also provide a ``ThreadPoolExecutor`` " "(``self._custom_executor``) for custom command handlers. When a handler " @@ -1053,13 +1056,13 @@ msgstr "" "``max_custom_workers``로 제한하기 위해 세마포어도 사용합니다. 이 메커니즘은 파일 전송 세마포어와 " "**독립적**이며 범용 명령 처리를 위한 것입니다." -#: ../../source/File_Transfer/File_Transfer.rst:560 -#: adfe7eb4ec4942e9979652f98b3beed9 +#: ../../source/File_Transfer/File_Transfer.rst:562 +#: 1862d74da28a40219f82cfd7af89c126 msgid "Port Allocation and Management" msgstr "포트 할당 및 관리" -#: ../../source/File_Transfer/File_Transfer.rst:562 -#: 845beb63ef9c47ba8379637a1b0662fb +#: ../../source/File_Transfer/File_Transfer.rst:564 +#: bd53ec8aa4ef498aa0815db16ed03140 msgid "" "File transfers require ephemeral ports for the secondary data " "connections. The ``palloc()`` and ``pfree()`` methods are used to obtain " @@ -1068,8 +1071,8 @@ msgstr "" "파일 전송에는 보조 데이터 연결을 위한 임시 포트가 필요합니다. ``palloc()`` 및 ``pfree()`` 메소드는 이러한 " "포트를 획득하고 해제하는 데 사용됩니다. 두 가지 모드를 사용할 수 있습니다:" -#: ../../source/File_Transfer/File_Transfer.rst:568 -#: 8195ea505bdf43a2a0f68b78d958c709 +#: ../../source/File_Transfer/File_Transfer.rst:570 +#: eeaa9379d7d941159ac34f30ff6bb5f9 msgid "" "**Automatic mode** (``is_hand_alloc_port=False``): ``palloc()`` returns " "``0``, and the operating system assigns a free port when the socket is " @@ -1078,8 +1081,8 @@ msgstr "" "**자동 모드** (``is_hand_alloc_port=False``): ``palloc()``은 ``0``을 반환하고, 소켓이 " "바인딩될 때 운영 체제는 사용 가능한 포트를 할당합니다. 이는 대부분의 사용 사례에 권장되는 모드입니다." -#: ../../source/File_Transfer/File_Transfer.rst:573 -#: 9a796b6e464d4d9e8e131401d5022e1f +#: ../../source/File_Transfer/File_Transfer.rst:575 +#: e3dc324e81734bd4bc768174caf200bf #, fuzzy msgid "" "**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; " @@ -1096,8 +1099,8 @@ msgstr "" "``/client_alloc_port_range``를 통해 허용 범위를 클라이언트에 브로드캐스트하고 클라이언트는 동일한 수동 할당 " "논리를 사용합니다." -#: ../../source/File_Transfer/File_Transfer.rst:588 -#: 7d275701519c4d60ba94cf086010e92d +#: ../../source/File_Transfer/File_Transfer.rst:590 +#: 29cfdab183eb4f9f83de41ef62a60785 msgid "" "*Note: For more details about port allocation, please visit the Port " "Allocation API sections in :doc:`TCP_Server_APIs` and " @@ -1106,18 +1109,18 @@ msgstr "" "*참고: 포트 할당에 대한 자세한 내용은 :doc:`TCP_Server_APIs` 및 :doc:`TCP_Client_APIs`의 " "포트 할당 API 섹션을 참조하세요.*" -#: ../../source/File_Transfer/File_Transfer.rst:596 -#: e92794553f6f4189978c5486f4d09fce +#: ../../source/File_Transfer/File_Transfer.rst:598 +#: 189736d8d1f8464b8d301f219700fda4 msgid "Error Handling and Timeouts" msgstr "오류 처리 및 시간 초과" -#: ../../source/File_Transfer/File_Transfer.rst:598 -#: 6ef0c4c7a91a42d0acc6b0a387247432 +#: ../../source/File_Transfer/File_Transfer.rst:600 +#: bcc373777989436f9df3657446d1a7f2 msgid "### Timeout Values" msgstr "### 시간 초과 값" -#: ../../source/File_Transfer/File_Transfer.rst:600 -#: 2b8dea32ffe04d4988e44fca72384271 +#: ../../source/File_Transfer/File_Transfer.rst:602 +#: 27d75d097a804ec28ebec5c67469c9c6 msgid "" "**Start signal timeout**: 10 seconds. If the receiver does not send " "``server_start_file_transfer_sign`` within this time, the sender aborts." @@ -1125,15 +1128,15 @@ msgstr "" "**시작 신호 시간 초과**: 10초. 수신자가 이 시간 내에 ``server_start_file_transfer_sign``을 " "보내지 않으면 발신자가 중단됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:604 -#: 2d19f71ef52b4f3097bf0c2f3e64be7b +#: ../../source/File_Transfer/File_Transfer.rst:606 +#: 93e877c411eb4c96bd7861ff61f35e7a msgid "" "**Port negotiation timeout**: 20 seconds. The initiator waits for the " "peer's ``/server_file_transfer_port`` response." msgstr "**포트 협상 시간 초과**: 20초. 개시자는 피어의 ``/server_file_transfer_port`` 응답을 기다립니다." -#: ../../source/File_Transfer/File_Transfer.rst:607 -#: 67dba14dcd534ae484df410cb48c8e53 +#: ../../source/File_Transfer/File_Transfer.rst:609 +#: 9e1d395bb59540a49393bebe6630e5eb msgid "" "**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 " "* 1024)) * 10`` seconds. Larger files get proportionally more time." @@ -1141,39 +1144,39 @@ msgstr "" "**완료 확인 시간 초과**: ``30 + (file_size // (100 * 1024 * 1024)) * 10``초. 파일이 " "클수록 비례적으로 더 많은 시간이 소요됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:611 -#: f175db3ace1448068c029d1527feb065 +#: ../../source/File_Transfer/File_Transfer.rst:613 +#: 6b4e6135669b41178fdbb47ea5975381 msgid "### Error Signalling" msgstr "### 오류 신호" -#: ../../source/File_Transfer/File_Transfer.rst:613 -#: 988d9d4636944c0abc8d186178d2a4f7 +#: ../../source/File_Transfer/File_Transfer.rst:615 +#: 448fdc6ba3dd4d9eae925e7e241f8cb8 msgid "" "Any error during the handshake or data transfer causes the failing side " "to send ``error_sign`` over the transfer socket." msgstr "핸드셰이크나 데이터 전송 중 오류가 발생하면 실패한 쪽에서 전송 소켓을 통해 ``error_sign``을 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:616 -#: d171618e798b46d0a6ac7473b4a787ba +#: ../../source/File_Transfer/File_Transfer.rst:618 +#: 5b4c23a93e984ce0af2e43cf4752225b msgid "" "The other side, upon receiving the error sign, closes the transfer socket" " and aborts the transfer." msgstr "상대방은 오류 신호를 받으면 전송 소켓을 닫고 전송을 중단합니다." -#: ../../source/File_Transfer/File_Transfer.rst:619 -#: c712f2f5e1794c528d4816a761030029 +#: ../../source/File_Transfer/File_Transfer.rst:621 +#: b337a2726ded4d619c5e8026bef3f6ea msgid "" "The main control connection remains unaffected; only the transfer socket " "is closed." msgstr "메인 제어 연결은 영향을 받지 않습니다. 전송 소켓만 닫혀 있습니다." -#: ../../source/File_Transfer/File_Transfer.rst:623 -#: 9d55f6049713415794e53bd6a476e11f +#: ../../source/File_Transfer/File_Transfer.rst:625 +#: 68be52c8e5ce447a9c5ec51a661229cf msgid "### Exception Handling" msgstr "### 예외 처리" -#: ../../source/File_Transfer/File_Transfer.rst:625 -#: a45a6eaec53b4699a7e61d4e422ace85 +#: ../../source/File_Transfer/File_Transfer.rst:627 +#: 036db9bc1858417ca589816028b83f80 #, fuzzy msgid "" "All socket operations are wrapped in try-except blocks. When an exception" @@ -1187,13 +1190,172 @@ msgstr "" "``traceback.print_exc()``를 사용하여 오류가 기록되고 전송이 정상적으로 중단됩니다. 가능한 경우 " "``error_sign``을 전송하고 전송 소켓을 닫습니다." -#: ../../source/File_Transfer/File_Transfer.rst:638 -#: 00af57a759ec4845b5810bb85ac1f485 +#: ../../source/File_Transfer/File_Transfer.rst:640 +#: ba1f05134dd24afa9867881cc45ed14a +msgid "Transfer Progress and Network Speed" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:642 +#: 5c7b182bb5214dd2ad49e5b171876e95 +msgid "Both classes record every running file transfer:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:644 +#: 8adbb686d9b04c97b5a7314ec4a5d1fd +msgid "``file_recv_progress`` — the files being received (downloads);" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:645 +#: 3d2d981185624b5498121d82b12d44ba +msgid "``file_upload_progress`` — the files being sent (uploads)." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:647 +#: e59132f2790d4b4fb2aa707e1d3b43b6 +msgid "" +"The keys are the transfers' fids: the transfer id the sender stamps on " +"the transfer command (``/file ``), which also identifies the " +"relay leg of a forwarded file. The protocol-internal public-key push is " +"not tracked. Each value is a five-item list:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:652 +#: bf66e7dae7e24cf3a3687ffd30f547ec +msgid "``[0]``: bytes transferred so far;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:653 +#: 2652aa8074764124b520d4e84b7667d5 +msgid "``[1]``: total size of the file, in bytes;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:654 +#: 8b09fc93700d4b6ca7a517700649c289 +msgid "" +"``[2]``: the current network speed of that direction — ``None`` until the" +" transfer has moved its first chunk, and while " +"``is_enable_real_time_network_speed`` is ``False``;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:657 +#: 311adcc13bd441a985ebcd8c775b152f +msgid "" +"``[3]``: local path of the file: the source of an outbound transfer, the " +"file being written for an inbound one;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:659 +#: 7a1f875aeb8b497ab7785620e402ff97 +msgid "" +"``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender " +"in a download's entry, the receiver in an upload's. A forwarded transfer " +"stores the original peer on both sides, never the relaying server." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:663 +#: da38fbed94114f10b6f7366e43906dd8 +msgid "" +"An entry appears when a transfer starts and is removed when it ends, so " +"the stores hold exactly the transfers that are in flight at that moment " +"(iterate over a copy while transfers are running). With " +"``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is " +"ever recorded — and, since the stores are the state a reconnect resumes " +"from, no transfer can be resumed either." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:670 +#: edbdd37cf5a04d42bf01f6bff5aa3307 +msgid "" +"``is_enable_real_time_network_speed`` (``True`` by default) measures the " +"protocol's current traffic — the control layer and every temporary " +"connection, file transfers included — into ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With the flag ``False`` nothing is " +"sampled and every speed value is ``None``." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:677 +#: c60e3cb78c8d48faace7569bdb50f8f5 +msgid "" +"The web tool (``transfer_web``) reads these stores: both backends serve " +"``/api/transfers`` (the rows plus the two speed attributes), and the " +"shared frontend renders the live speed readout in the topbar and one " +"progress bar per running transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:685 +#: ce90e0b6082e4d37a79346aa7b2763f9 +msgid "Pausing, Reconnecting and Resuming Transfers" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:687 +#: 5fbf414617474bd79978360043f149a3 +msgid "" +"An outbound transfer can be held and released at any time with the " +"``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or " +"from the peer with the ``/pause_trans `` and ``/start_trans `` " +"lines: ``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, " +"fid)`` send them. The leg stops before its next chunk and stays open; a " +"leg that is paused keeps its socket, so nothing is torn down. Every " +"outbound transfer honours its own fid — a plain upload as much as the " +"upload leg of a forwarded file — so the flow control the server uses on a" +" relay works on any transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:696 +#: d4ace80bc05f4bafb8144e1de31060dc +msgid "The temporary connections of a transfer are resumed after a disconnect:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:698 +#: d7d49609832d4c5bb2d7cecb059805eb +msgid "" +"when a connection drops, both sides write their transfer stores to " +"``.Flow/server_file_trans_progress.json`` / " +"``.Flow/client_file_trans_progress.json`` (the " +"``file_trans_progress_file`` attribute) — every upload, every download " +"and, on the server, the relay records a disconnected forward is re-driven" +" from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:703 +#: 353cf50d60014cceb4c5a36bf5b98b83 +msgid "" +"an interrupted transfer keeps its progress entry and its partial file " +"instead of dropping them, so the file on disk is exactly the state to " +"continue from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:706 +#: c7017b370d4147128e54a94458a7b536 +msgid "" +"after a reconnect the receiver drives the resume (`resume_transfers`): it" +" opens a fresh transfer listener, announces it and sends ``/resume_trans " +" `` with the byte offset its partial file holds. The sender " +"re-establishes the leg, reads its source from that offset and only the " +"remainder of the file travels. A forwarded transfer is asked for through " +"the server, which routes ``/forward_resume`` to the originating client so" +" it re-forwards just the missing part." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:714 +#: ee858a76e93f44d5934cb2d89f6709a5 +msgid "" +"The server resumes a peer's transfers when it reconnects, and a client " +"with ``is_auto_reconnect=True`` reconnects on its own and resumes every " +"transfer it can reach; `resume_transfers` is public, so an application " +"can also drive the resume itself. Legs the previous session left behind " +"are closed before the resume runs, so two legs never write the same " +"transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:723 +#: fe9377db9cf04b9da0dbe4d07c730adf msgid "Related API Definitions" msgstr "관련 API 정의" -#: ../../source/File_Transfer/File_Transfer.rst:640 -#: 92c3b5d713cb49cfb144026af574a0b4 +#: ../../source/File_Transfer/File_Transfer.rst:725 +#: cc71cb9b1d6642a2acc89d45a49022cc msgid "" "This section lists all public file-transfer related methods in " "``TCP_Server_Base`` and ``TCP_Client_Base``. For a complete list of all " @@ -1202,13 +1364,13 @@ msgstr "" "이 섹션에는 ``TCP_Server_Base`` 및 ``TCP_Client_Base``의 모든 공용 파일 전송 관련 방법이 나열되어" " 있습니다. 모든 공개 API의 전체 목록을 보려면 이 문서 끝에 있는 표를 참조하세요." -#: ../../source/File_Transfer/File_Transfer.rst:646 -#: bbc49149589d43719bc774a99b84ce6e +#: ../../source/File_Transfer/File_Transfer.rst:731 +#: d6683e415f794c5bb693f8c24370e7f9 msgid "### Server-Side File Transfer APIs" msgstr "### 서버측 파일 전송 API" -#: ../../source/File_Transfer/File_Transfer.rst:652 -#: 59386d051c734452801f4bd00d5dd654 +#: ../../source/File_Transfer/File_Transfer.rst:737 +#: 9123c69197c34d93bb68d088897ebeca msgid "" "Initiates a server-to-client file transfer. ``message`` is the command " "string (e.g., ``/file /path/to/file.txt (127.0.0.1,54321)``). If " @@ -1219,13 +1381,13 @@ msgstr "" "/path/to/file.txt (127.0.0.1,54321)``). ``file_folder_abspath``가 제공되면(폴더 " "전송의 경우) 상위 폴더의 절대 경로를 지정합니다." -#: ../../source/File_Transfer/File_Transfer.rst:663 -#: 431a043a77bc4d82a206650afde47b86 +#: ../../source/File_Transfer/File_Transfer.rst:748 +#: 367dfd82c95c413d963a15152469fc44 msgid "Thread-safe version that starts a new thread for the transfer." msgstr "전송을 위해 새 스레드를 시작하는 스레드 안전 버전입니다." -#: ../../source/File_Transfer/File_Transfer.rst:669 -#: e17536344cb444b699c7465d8bcbdded +#: ../../source/File_Transfer/File_Transfer.rst:754 +#: d4aa76b7eb2c46c29adee0120a939b66 #, fuzzy msgid "" "Sends an entire folder from server to client. ``message`` should be of " @@ -1235,8 +1397,8 @@ msgstr "" "서버에서 클라이언트로 전체 폴더를 보냅니다. ``메시지``는 ``/file_folder " "`` 형식이어야 합니다." -#: ../../source/File_Transfer/File_Transfer.rst:676 -#: 88f9df0240054009a6957b13ee08f2ef +#: ../../source/File_Transfer/File_Transfer.rst:761 +#: 29f2a5e19bf04a09a8711ac1c892a4ad msgid "" "Sends multiple items to multiple clients. The message format is " "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -1247,8 +1409,8 @@ msgid "" "destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:688 -#: 39b67f1d0e6b438386eb04c6d44da6b8 +#: ../../source/File_Transfer/File_Transfer.rst:773 +#: ff8bc5c8969b45c1bbcf1eba5b77485a msgid "" "Sends different file lists to different clients. Files that appear before" " a group of client addresses are sent to that group; a new group starts " @@ -1259,34 +1421,37 @@ msgid "" "optional trailing destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:701 -#: 37108379b0b9495584bb135d5860ea4a +#: ../../source/File_Transfer/File_Transfer.rst:786 +#: f8a880287b7b49d4bdc2239ecf4a0577 msgid "" "Receives a file from a client. Called internally when the server receives" " a ``/file`` command from a client." msgstr "클라이언트로부터 파일을 받습니다. 서버가 클라이언트로부터 ``/file`` 명령을 수신하면 내부적으로 호출됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:710 -#: adeb784cb6b24d6cbf143a7a50eba80a +#: ../../source/File_Transfer/File_Transfer.rst:795 +#: 97bfaa9c24ae47c39328707b8f17a91a msgid "" "Low-level receive function that performs the handshake and writes the " "incoming file to disk." msgstr "핸드셰이크를 수행하고 수신 파일을 디스크에 쓰는 낮은 수준의 수신 기능입니다." -#: ../../source/File_Transfer/File_Transfer.rst:718 -#: 0bb492f5335d426d8dc715847665b3f4 +#: ../../source/File_Transfer/File_Transfer.rst:804 +#: c7be9703e0454f7f96586642bc8f6a22 msgid "" "Low-level send function that connects to the receiver and transmits the " -"file." -msgstr "수신자와 연결하여 파일을 전송하는 저수준 전송 기능입니다." +"file. ``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's" +" original receiver and ``resume_offset`` continues an interrupted file " +"from the byte the receiver already holds." +msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:720 -#: 29189fe72c61456ba2d5aa1ece75145e +#: ../../source/File_Transfer/File_Transfer.rst:810 +#: 3e7b689215e840bebd368b4d29104ebc msgid "### Client-Side File Transfer APIs" msgstr "### 클라이언트측 파일 전송 API" -#: ../../source/File_Transfer/File_Transfer.rst:726 -#: 6c2f54ee2660441291a3fbbcaa95262c +#: ../../source/File_Transfer/File_Transfer.rst:816 +#: 1e97e492d6504579a9a265eb1242395e msgid "" "Initiates a client-to-server file transfer. ``message`` is the user " "command (e.g., ``/file mydoc.txt``). Used internally by the interactive " @@ -1295,103 +1460,120 @@ msgstr "" "클라이언트-서버 파일 전송을 시작합니다. ``message``는 사용자 명령입니다(예: ``/file mydoc.txt``). " "대화형 콘솔에서 내부적으로 사용됩니다." -#: ../../source/File_Transfer/File_Transfer.rst:734 -#: ../../source/File_Transfer/File_Transfer.rst:765 -#: 07c4ae801fb54cbcb508af4b208f75dd +#: ../../source/File_Transfer/File_Transfer.rst:824 +#: ../../source/File_Transfer/File_Transfer.rst:855 +#: 0cd2695763114a0b831df0bfa80a3d56 msgid "Thread-safe version." msgstr "스레드로부터 안전한 버전." -#: ../../source/File_Transfer/File_Transfer.rst:740 -#: 0d66d4aac681414fb7b8a46117571fe9 +#: ../../source/File_Transfer/File_Transfer.rst:830 +#: 261399ca508d463eafa7f03a00bfc658 msgid "Sends a folder from client to server." msgstr "클라이언트에서 서버로 폴더를 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:746 -#: 2818655cecfc49f7ab1c9800b9418018 +#: ../../source/File_Transfer/File_Transfer.rst:836 +#: ef5e3b92b11c4530960c1c344a51c73b msgid "Sends multiple files from client to server." msgstr "클라이언트에서 서버로 여러 파일을 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:752 -#: 6ee08a69dbc5486a94fe2f616f0899e2 +#: ../../source/File_Transfer/File_Transfer.rst:842 +#: f2c90ee949d7484480cbb2cd5310bf26 msgid "Sends multiple folders from client to server." msgstr "클라이언트에서 서버로 여러 폴더를 보냅니다." -#: ../../source/File_Transfer/File_Transfer.rst:759 -#: 5a88c3508e074cff9ae445d00193f212 +#: ../../source/File_Transfer/File_Transfer.rst:849 +#: 0b13d26a40174243a15698b4bfcbb69f msgid "" "Receives a file from the server (called when the server initiates a " "transfer)." msgstr "서버로부터 파일을 수신합니다(서버가 전송을 시작할 때 호출됨)." -#: ../../source/File_Transfer/File_Transfer.rst:771 -#: 42db9f7f09c044c8a58243854644adfb +#: ../../source/File_Transfer/File_Transfer.rst:861 +#: 3b78a4355d7f4ee2bbbe6bf934a962c0 msgid "Receives a folder from the server." msgstr "서버로부터 폴더를 받습니다." -#: ../../source/File_Transfer/File_Transfer.rst:779 -#: 0a051d591bb54e529c771345409ec7df +#: ../../source/File_Transfer/File_Transfer.rst:869 +#: 3d044e0754b94d1289b491502ce83610 msgid "Low-level receive function on the client side." msgstr "클라이언트 측의 낮은 수준 수신 기능." -#: ../../source/File_Transfer/File_Transfer.rst:786 -#: e0149bdd716249289f6ba260e3c3f053 +#: ../../source/File_Transfer/File_Transfer.rst:877 +#: 7311023a7fa644ed9b57a2873cd3bca8 msgid "" "Low‑level send function on the client side (identical to server's " "version)." msgstr "클라이언트 측의 낮은 수준 전송 기능(서버 버전과 동일)" -#: ../../source/File_Transfer/File_Transfer.rst:791 -#: e612d36affc0456b9314f39816bf62f3 +#: ../../source/File_Transfer/File_Transfer.rst:882 +#: 7e74e9a09a8a4cf2a8a372a50b1ee51b msgid "Public API Summary" msgstr "공개 API 요약" -#: ../../source/File_Transfer/File_Transfer.rst:793 -#: 8347c97393fe47ea83c13f6777faa36c +#: ../../source/File_Transfer/File_Transfer.rst:884 +#: 87aaf0a5d3b44f41a419d97b6567f6d0 msgid "" "All public APIs (including non-file-transfer methods) are listed below " "for reference." msgstr "모든 공개 API(비파일 전송 방법 포함)는 참조용으로 아래에 나열되어 있습니다." -#: ../../source/File_Transfer/File_Transfer.rst:797 -#: 5ac025a5e948425a9a430c7c75b045f9 +#: ../../source/File_Transfer/File_Transfer.rst:888 +#: a195ee393f2a442c810e59811a6ae126 msgid "### TCP_Server_Base Public APIs" msgstr "### TCP_Server_Base 공개 API" -#: ../../source/File_Transfer/File_Transfer.rst:799 -#: ddf4d1d8e04e40659404ebb55c843c41 +#: ../../source/File_Transfer/File_Transfer.rst:890 +#: 0408d74a9140472e9a774143a60e5749 msgid "``file_transfer_server_recv_client_start``" msgstr "``file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:800 -#: 052d49abc8514ed19346f7b023783fa9 +#: ../../source/File_Transfer/File_Transfer.rst:891 +#: 24a33cb212844e04a8a271ada32412f0 msgid "``file_transfer_server_recv_client_start_thread``" msgstr "``file_transfer_server_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:801 -#: 6db2d78cc0b94b4b93d6080164897079 +#: ../../source/File_Transfer/File_Transfer.rst:892 +#: 7e286d1ece6940868bea6b937486e617 msgid "``folder_file_transfer_server_recv_client_start``" msgstr "``folder_file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:802 -#: ec1b13e6e07449ec820d5cdc7a983048 +#: ../../source/File_Transfer/File_Transfer.rst:893 +#: 37fc5bd346c84415bb15138a42508fbe msgid "``multiple_file_multiple_client_transfer_server_recv_client_start``" msgstr "``multiple_file_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:803 -#: 7d780de964e543a8b703dd413d331c43 +#: ../../source/File_Transfer/File_Transfer.rst:894 +#: 38a2b16e3ab648688cf7e8d1cae8be72 msgid "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:804 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:895 +#: ad39bc6b71f048b09bca3b895e9d32f8 #, fuzzy msgid "" "``file_folder_transfer_server_recv_server_start_thread`` (folder " "receiving)" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:806 -#: 02e685a79bc64a32ad888008a9dde074 +#: ../../source/File_Transfer/File_Transfer.rst:896 +#: ../../source/File_Transfer/File_Transfer.rst:916 +#: 37aeb9835435434881f94eb9951370d6 660ac3b979cc43d0beece659b9b0935f +msgid "``pause_trans`` / ``start_trans`` (hold and release an outbound transfer)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:897 +#: 7641e3ece9314197863d872836635218 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:898 +#: ../../source/File_Transfer/File_Transfer.rst:918 +#: 9c62709c2c06456dbfddee1f1ce6871e de496a0be32c490585ae0cbafc931a71 +msgid "``resume_transfers`` / ``resume_trans`` (continue interrupted transfers)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:900 +#: 11476e0eaa3b4a4286612812e4e2c004 msgid "" "(The low-level helpers ``file_transfer_server_recv_server_start``, " "``file_transfer_mode_recv``, and ``file_transfer_mode`` are not " @@ -1401,80 +1583,85 @@ msgstr "" "``file_transfer_mode_recv`` 및 ``file_transfer_mode``는 공개로 간주되지 않지만 완전성을 " "위해 문서화되어 있습니다.)" -#: ../../source/File_Transfer/File_Transfer.rst:812 -#: 5193d200c3f245caae4095ab4114a467 +#: ../../source/File_Transfer/File_Transfer.rst:906 +#: 907e861cebe648fbacb799bae8bb15e0 msgid "### TCP_Client_Base Public APIs" msgstr "### TCP_Client_Base 공개 API" -#: ../../source/File_Transfer/File_Transfer.rst:814 -#: df25f04d660046669347072182ca0bde +#: ../../source/File_Transfer/File_Transfer.rst:908 +#: 88bd80083f754caeb026f9ce1b8c6b55 msgid "``file_transfer_client_recv_client_start``" msgstr "``file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:815 -#: 2a43c7e5134b4a64af241547e798bdf3 +#: ../../source/File_Transfer/File_Transfer.rst:909 +#: 3b21ff73da694465906482412b4fb4e3 msgid "``file_transfer_client_recv_client_start_thread``" msgstr "``file_transfer_client_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:816 -#: 6a88ac28f634410ab54d999291b5b309 +#: ../../source/File_Transfer/File_Transfer.rst:910 +#: c8af43896a2443a5b14bd29863731c2c msgid "``folder_file_transfer_client_recv_client_start``" msgstr "``folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:817 -#: 6d47f6da5f54475989d93fca0c141f2d +#: ../../source/File_Transfer/File_Transfer.rst:911 +#: 7a3d3e4a52334b169a62d3b30d7a3190 msgid "``multiple_file_transfer_client_recv_client_start``" msgstr "``multiple_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:818 -#: 06e20b477a9744de9f2d2efcf0fbf57f +#: ../../source/File_Transfer/File_Transfer.rst:912 +#: 19e18754c4674842ad5116f709588e03 msgid "``multiple_folder_file_transfer_client_recv_client_start``" msgstr "``multiple_folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:819 -#: a8dd89a54e0f498b88185761dc4c0f46 +#: ../../source/File_Transfer/File_Transfer.rst:913 +#: 4cf80f9f34e045c59a680d0450c9103a msgid "``file_transfer_client_recv_server_start``" msgstr "``file_transfer_client_recv_server_start``" -#: ../../source/File_Transfer/File_Transfer.rst:820 -#: 0811953096e94bd887990bb58d2de56a +#: ../../source/File_Transfer/File_Transfer.rst:914 +#: c09f5fcba03f461f89238dd31abf6e88 msgid "``file_transfer_client_recv_server_start_thread``" msgstr "``file_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:821 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:915 +#: ad39bc6b71f048b09bca3b895e9d32f8 msgid "``file_folder_transfer_client_recv_server_start_thread``" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:823 -#: bbbea73553dd4dfd98e0ee4076c1d42b +#: ../../source/File_Transfer/File_Transfer.rst:917 +#: 4b82ae9a067f46d5bb297431468a67a4 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:920 +#: 99140d0be72649199911a57a26e2f2cf msgid "(The low-level helpers are documented but not part of the public API.)" msgstr "(저수준 도우미는 문서화되어 있지만 공개 API의 일부는 아닙니다.)" -#: ../../source/File_Transfer/File_Transfer.rst:827 -#: 56f1214838224007ade30eb34009810c +#: ../../source/File_Transfer/File_Transfer.rst:924 +#: 60355543ac904504af8529431ce2c1fa msgid "See Also" msgstr "참조" -#: ../../source/File_Transfer/File_Transfer.rst:829 -#: d513a2ce6fdf40eca5746ea840b4314f +#: ../../source/File_Transfer/File_Transfer.rst:926 +#: 7a5902ad3de64bf79d54d7f2f83ecbfb msgid "" "For more information about the TCP server and client base classes, please" " refer to:" msgstr "TCP 서버 및 클라이언트 기본 클래스에 대한 자세한 내용은 다음을 참조하세요." -#: ../../source/File_Transfer/File_Transfer.rst:833 -#: 66b9f83c47d848779de9019a6f33c9a4 +#: ../../source/File_Transfer/File_Transfer.rst:930 +#: f10c29f467b849e8b4254998b44f99ba msgid ":doc:`../Network_APIs/TCP_Server_APIs`" msgstr ":doc:`../Network_APIs/TCP_Server_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:834 -#: 5cfe4f734d2043c2afe489c53c4ce963 +#: ../../source/File_Transfer/File_Transfer.rst:931 +#: 335ba244d28342449db065c252d7e14c msgid ":doc:`../Network_APIs/TCP_Client_APIs`" msgstr ":doc:`../Network_APIs/TCP_Client_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:836 -#: 47b4292bf8754c389fccf965d9b417d8 +#: ../../source/File_Transfer/File_Transfer.rst:933 +#: 92d0227c356447a098cba072d5b43c98 msgid "" "For details on port allocation, see the Port Allocation API sections in " "those documents." @@ -1563,3 +1750,9 @@ msgstr "포트 할당에 대한 자세한 내용은 해당 문서의 포트 할 #~ "``/diff_multiple_file_diff_multiple_client a.txt b.txt " #~ "(ip1,port1) (ip2,port2) c.txt (ip3,port3)``" +#~ msgid "" +#~ "Low-level send function that connects" +#~ " to the receiver and transmits the" +#~ " file." +#~ msgstr "수신자와 연결하여 파일을 전송하는 저수준 전송 기능입니다." + diff --git a/docs/source/locale/ko/LC_MESSAGES/Instance_Setup/Instance_Setup.po b/docs/source/locale/ko/LC_MESSAGES/Instance_Setup/Instance_Setup.po index 38c86e6..94e8d2a 100644 --- a/docs/source/locale/ko/LC_MESSAGES/Instance_Setup/Instance_Setup.po +++ b/docs/source/locale/ko/LC_MESSAGES/Instance_Setup/Instance_Setup.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,12 +18,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Instance_Setup/Instance_Setup.rst:3 -#: b4877074f48944ef95449bad6b451f04 +#: 552b0fbec3774a638b0029ce5fd72949 msgid "Flow Setup Launcher" msgstr "흐름 설정 실행기" #: ../../source/Instance_Setup/Instance_Setup.rst:5 -#: 745aff08935b4042b2885b7f10d524f1 +#: 31952c3324264ea28368c7725796ff63 #, fuzzy msgid "" "The ``flow_setup.py`` script is a launcher for the TCP server/client " @@ -37,12 +37,12 @@ msgstr "" "시작된 각 인스턴스는 별도의 터미널 창(또는 헤드리스 시스템의 백그라운드 프로세스)에서 실행됩니다." #: ../../source/Instance_Setup/Instance_Setup.rst:13 -#: 5cfe71ed904f4f24bef1210b411ee40d +#: c8f9652279de42bb983523a15048596e msgid "Features" msgstr "특징" #: ../../source/Instance_Setup/Instance_Setup.rst:15 -#: d5544e89cd884c938e1bfed52fdaf35a +#: 2bd321903dd94d9985805a44d9ef3d94 #, fuzzy msgid "" "**Interactive mode** – step-by-step creation of server and client " @@ -51,7 +51,7 @@ msgid "" msgstr "**대화형 모드** – 서버 또는 클라이언트 인스턴스를 단계별로 생성합니다." #: ../../source/Instance_Setup/Instance_Setup.rst:18 -#: a3239003782944f1aceb438c4b164657 +#: df9cbf9e1d024f9386a4b6278c82249e #, fuzzy msgid "" "**Command-line mode** – launch one server or one client with all " @@ -59,14 +59,14 @@ msgid "" msgstr "**명령줄 모드** – 하나의 명령으로 모든 매개변수를 사용하여 실행합니다." #: ../../source/Instance_Setup/Instance_Setup.rst:20 -#: 6c36fb284a4b4984bd220e047e26ed37 +#: b3406e8f62894233be438b7988e444da msgid "" "**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser" " UI of the ``transfer_web`` web tool." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:22 -#: 1a357d61f62b41dd91e150d24c323a98 +#: e359866c167e4e7ca5bf0791fd471ac4 msgid "" "**Extension registration** – ``--add`` / ``--delete`` register or " "unregister extension protocol files; the registered files are loaded on " @@ -74,7 +74,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:25 -#: 0deeeb0bc12644eaab437361d69dbe77 +#: 5f7cba6df26144e9840d140f94065b33 #, fuzzy msgid "" "**Persistent configuration** – stores the latest instance definitions in " @@ -85,7 +85,7 @@ msgstr "" "유형(서버/클라이언트)에는 **하나의** 구성만 포함되며 업데이트할 때마다 덮어쓰여집니다." #: ../../source/Instance_Setup/Instance_Setup.rst:29 -#: 0b60fca4ab384444a03750dcb790150f +#: b93809688cb74986ac64e4baceb9f0f6 msgid "" "**Multiple instances** – the ``servers`` and ``clients`` lists may hold " "any number of entries. Adding an entry identical to an existing one of " @@ -93,7 +93,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:33 -#: af8b8bdd4c994728a0bf4a7b358976b7 +#: be9bc008af594306be21e731d6aefee3 #, fuzzy msgid "" "**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, " @@ -104,7 +104,7 @@ msgstr "" "macOS(Terminal.app)를 지원합니다." #: ../../source/Instance_Setup/Instance_Setup.rst:36 -#: 4696d04613af4a1ea055df8be236adc3 +#: 57005cb0d04f47b2a8f10ad0bc9c7b43 #, fuzzy msgid "" "**Complete parameter support** – all parameters accepted by " @@ -115,22 +115,22 @@ msgstr "" "매개변수는 미세 조정을 위해 ``setup.json``에 저장할 수 있습니다." #: ../../source/Instance_Setup/Instance_Setup.rst:41 -#: 343fcd49c74b4cfd9d351f93c60e59bc +#: 2ff27919a6f64e8fb610158de5ffdf69 msgid "Usage" msgstr "용법" #: ../../source/Instance_Setup/Instance_Setup.rst:44 -#: 7e39ebc551894366b757ddfb5c406753 +#: dddde4f2d7084bc48efa1296cfd3f22c msgid "Interactive Mode" msgstr "대화형 모드" #: ../../source/Instance_Setup/Instance_Setup.rst:46 -#: 5f7b3715a9524fa2a0aed70bbefc5008 +#: f060e64959674f52b223bbc4b01d568c msgid "Run the script without any arguments:" msgstr "인수 없이 스크립트를 실행합니다." #: ../../source/Instance_Setup/Instance_Setup.rst:52 -#: a17a608e2ac24987b6c4a428acd770e9 +#: 6bb60d44328244d4ab20f3ae5ba2b827 msgid "" "When ``setup.json`` already exists, the launcher first asks whether to " "overwrite it, and the interactive collection itself asks whether the " @@ -138,7 +138,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:56 -#: 7fe4792645644307bf450194c2d98fa7 +#: d247a8d3c3f1430c8dfa6dccad66da0a msgid "" "``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` " "launches every stored instance and exits; ``Y`` (or no existing file) " @@ -146,7 +146,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:59 -#: e60cbc55c5834e8ab8ce55e696159e9a +#: 96169445a67545178cdd4b68ce5faae3 msgid "" "``Delete or change existing instances or configs? (Y/N):`` – asked only " "when stored instances exist. ``Y`` opens the instance editor (see below);" @@ -154,23 +154,23 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:63 -#: eaf7134992f44c58aa4181664a3bc638 +#: 80847dcc3e404a779b2e693cf8de50d5 #, fuzzy msgid "``Choose the type (0 for Server, 1 for Client)``." msgstr "유형을 선택합니다(서버의 경우 0, 클라이언트의 경우 1)." #: ../../source/Instance_Setup/Instance_Setup.rst:64 -#: 6a5569dd541a4043802c5d85f125db64 +#: cebc8ba62d1a48a69d8019c3862dc18b msgid "Enter the bind address and port (``host:port``)." msgstr "바인딩 주소와 포트(``host:port``)를 입력하세요." #: ../../source/Instance_Setup/Instance_Setup.rst:65 -#: e70e2b6322a04c748193e1cec4b0ee2c +#: 4311b66e1b974b4596f2693908ba3109 msgid "If Client, also enter the server address and port to connect to." msgstr "클라이언트인 경우 연결할 서버 주소와 포트도 입력합니다." #: ../../source/Instance_Setup/Instance_Setup.rst:67 -#: df73da29736d4b878bef8427a95945aa +#: 3a5cff8b854c40939873ad57b060d9c3 msgid "" "Decide whether to add another instance. An entry that already exists in " "the list is not added again; a new one is appended, so several instances " @@ -178,14 +178,14 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:71 -#: 8e0df08f751f46deb43ba1006ed04b20 +#: 7c893e0f8399455ba1b14d9c796d75a8 msgid "" "After editing, the launcher asks ``Add new instances? (Y/N)`` before " "returning to the add flow." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:74 -#: 237874cb10d040cf86074695574daf32 +#: 49c58d9bb0b1440485f3cbecdb2843d6 msgid "" "When the editor is left with changes, ``setup.json`` is rewritten with " "every instance, and all stored instances (reused plus newly added) are " @@ -193,97 +193,97 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:79 -#: c81a1dba5f224291a56257375f84a1a0 +#: a1e74fd1f7f04e548b268c3dc0d6763e msgid "Global commands" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:81 -#: 8247157dfc0b4a32aa9ae300813386c6 +#: b8ede51e5254499e9dd613bc93db15ca msgid "" "The following words can be typed at **every** prompt, including field-" "value prompts:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: c29ffb659bf3446490bc9eaac6f2e7ea +#: c2b850e77d9b44559be9b25d93611a70 msgid "Effect" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``Help``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 886877e3eb7d407fa62b16a4fc968f62 +#: 200a2a3be7ea46b291882aef0b8d9031 msgid "Print the usage text of the current prompt." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: c569666357334b05ba4189c122bbeaaf +#: a6ce48cd04e04b3ea42ad16e04e37359 msgid "``Fix_Config``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: 0a5c8bdb9c1d4f7eb8a41fce85acf0b4 +#: fcd62172378d4da498de2a21a03f97a0 msgid "Jump to the instance editor (or, inside it, save and return to the list)." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 #, fuzzy msgid "``Setup``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "" "Launch every instance configured in ``setup.json`` and exit the setup " "program." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: cc2a8285cba3495db468d5f007f3ecfc +#: 85343de947b74e3b97e4c59109ebcd9e msgid "``Add_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: a6c3fac6c8f44d75a7a266bae3c54729 +#: 6b8af44d732b4673afbc2f9cbec357d3 msgid "Prompt for extension file path(s) and register them." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 4febe01e668f4cc1aa1b92e328780ebe +#: a35baf4ca7d949eba92cf6c6279c9cd2 msgid "``Delete_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 5e54a7238b604a5fbe930ff4c5fd05d5 +#: d6f9495c1ad046d5877eb8159799ae88 msgid "Prompt for registered extension path(s) to remove." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 88bb1def13564b809d980ac0d7f22832 +#: 7c985bf621ba4fbeaa8f25042d47ed95 msgid "``Quit``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 22644327258c472aab543baf2ee08784 +#: 18f32c4c66094837a84906ba56ef236d msgid "Exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:103 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Instance editor" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:105 -#: 5832e770c51e4e61b0a372086616ad57 +#: 021cb4d2e2234dff8a9b206826926e33 msgid "" "The editor is reached by typing ``Fix_Config`` (at any prompt) or by " "answering ``Y`` to the \"Delete or change existing instances\" question. " @@ -296,37 +296,37 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:115 -#: 36e871e8b76b4e6f8ab3d41c6e58e053 +#: be9f3fe33bf943419ada71d457c635e1 msgid "Vim-style commands:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:117 -#: bf18c8047500461486e3bc05c6154ecc +#: f11526b8f13f4f6eabba91f7543c7120 msgid "``:w`` – write ``setup.json`` without leaving the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:118 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "``:wq`` – write ``setup.json`` and leave the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:119 -#: 8e54b99375e441308cd3dc8ec4cd5d3a +#: 740d1745df7841a59959dbdab98a73b4 msgid "``:q`` – leave; refused while there are unsaved changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:120 -#: 32cdc0d2f2f34602a77b692202f56b24 +#: 944a89864f5c46c488287ee0740d83d5 msgid "``:q!`` – leave and discard all changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:121 -#: 7360415b19b04c13ab167e500f3437ac +#: 927b5a52f9454d65af949f5cc188e33d msgid "``Quit`` – exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:123 -#: aea22c0686c64df8bc842a51fbd2d67e +#: d4163489911a454f9e4fd1b6cdd1de5a msgid "" "Inside the config editor, ``j``/``k`` move between fields, ``Esc`` or " "``back`` returns to the list, and a field index or ``Enter`` edits the " @@ -337,170 +337,170 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:132 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command‑line Mode" msgstr "명령줄 모드" #: ../../source/Instance_Setup/Instance_Setup.rst:134 -#: 19ffa2fc838a441786de354b2a574153 +#: d798ec606de2454da5f10e9d0a7e677c msgid "Use the following options:" msgstr "다음 옵션을 사용하세요." #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: c6dc291839964e119fb50574caedfd9c +#: 4d5c1aebbede473c8598cbc45f8deb20 msgid "Option" msgstr "옵션" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: 4a498223c2cb4e45914dcd53bb7f2f12 +#: a50ba126b168482997fae00497252fd4 msgid "Description" msgstr "설명" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: 649f1c33bb9d4afa89d1796bef081ddf +#: 7755904907ee46f6a34144360ed876f7 #, python-brace-format msgid "``--type {0,1}``" msgstr "`` --type {0,1} ``" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: f0793c0f15584b42bc66b82e672854b5 +#: 0175b3fbf31e44829a685a07be420436 msgid "" "0 = Server, 1 = Client. Required for a plain command-line launch; without" " it the launcher runs interactively." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--setup_addr_port``" msgstr "`` --setup_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 58e47d807455460fb6e76d76b836bc30 +#: b7962f6d3a194e3eb91915d5681a2b7b #, fuzzy msgid "Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." msgstr "바인딩 주소와 포트(``host:port``)를 입력하세요." #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 31efc70f958b4608b07bc24eb1ec633b +#: 388a3dd952ac47a78598792ef7d587bc msgid "``--connect_addr_port``" msgstr "`` --connect_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 041b4144717b4f54ad1b24d06726293b +#: 7d96425a64374a36a457a9167fc6d39c msgid "" "Server address and port to connect to. Required for Client; rejected in " "Server mode." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``--setup_num``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 139258adce2844a28d57733bb973ec1e +#: 26698837fb26457ba9674e8ccf0cf881 msgid "" "Number of instances to launch. Only 1 is allowed; a larger value is " "accepted but ignored with a warning." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_server``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 108977e4c89b442488c39cad5378e8e5 +#: 9b1821de6d0f4c4d9af6c4e47eab4e5d msgid "" "Launch the ``transfer_web`` server tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_client``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 99410d7adbc749e2bee7ff014945d19b +#: 91fa396110c94aa9a29f0a569763e030 msgid "" "Launch the ``transfer_web`` client tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: 5de4064738ce4d529c9df9d1da98a556 +#: 118dce4ec3934bd4b5bb6e7b1aa31bf0 msgid "``--add PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: be6adb7451d84f9f934044d2891cc4db +#: 2a630e280d3040d6a78cd865dd3e2ae7 msgid "Register extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 58e2f444f8394dd5a5c41b400675c736 +#: c505cbcf44104e6799bfcb83251c2f72 msgid "``--delete PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 638774f6e42549ad88f930e50a2c3cad +#: 74b797d0ddf046d3b1dda4eea01013b7 msgid "Unregister extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:167 -#: e9b3cc31339a4f318337e8c68cc61fd5 +#: 54c5d51b3cb841ceaefda13a7613a8ae msgid "" "A command-line launch replaces ``setup.json`` with the single launching " "instance, so any other stored instance is dropped." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:171 -#: 327a63e83b8f4df9af4a5e6a32e2ce6e +#: 99952fa68b694654b82a309a26419152 msgid "Examples" msgstr "예" #: ../../source/Instance_Setup/Instance_Setup.rst:173 -#: c03b73272d554d1a885a04e6470d43c9 +#: 9c77e76f40a940e99e754d27e3bc1b05 msgid "**Launch a single server** on ``127.0.0.1:8000``:" msgstr "**127.0.0.1:8000``에서 단일 서버 실행**:" #: ../../source/Instance_Setup/Instance_Setup.rst:179 -#: 69edc9f7ea534c00bdaab2a4c84ef2cf +#: 37df8730dce9408a87ba48b775eb2b0a msgid "" "**Launch a client** bound to port ``9000``, connecting to a server at " "``127.0.0.1:8000``:" msgstr "``127.0.0.1:8000``에서 서버에 연결하여 ``9000`` 포트에 바인딩된 **클라이언트 실행**:" #: ../../source/Instance_Setup/Instance_Setup.rst:186 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "**Launch from an existing configuration** (if ``setup.json`` is present):" msgstr "**기존 구성에서 실행**(``setup.json``이 있는 경우):" #: ../../source/Instance_Setup/Instance_Setup.rst:193 -#: f2fd3c19413a4e6abb4b18037a347443 +#: 0538ca5ad181412c9136f318be43dfa0 msgid "**Launch the web tool** instead of a TCP instance:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:200 -#: 71feceacd5b94bd98ce1973f45c16df1 +#: 4a43a3b821764068aaa05c153037208f msgid "**Register an extension protocol file**:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:207 -#: 00dff5a17f42419585f498c51f7fcc97 +#: ff45af42eb7d4d3faa8640a18bfd61f6 msgid "Configuration File" msgstr "구성 파일" #: ../../source/Instance_Setup/Instance_Setup.rst:209 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "" "The script writes a file named ``setup.json`` in the same directory. Its " "structure is:" msgstr "스크립트는 동일한 디렉터리에 ``setup.json``이라는 파일을 작성합니다. 그 구조는 다음과 같습니다:" #: ../../source/Instance_Setup/Instance_Setup.rst:233 -#: 82c31bcb59fc481eaa532d1a0696ed8d +#: b0129978b1a9468188663a40126df876 msgid "" "**Both lists may contain any number of objects.** Every entry is " "completed with the default value of each parameter that the entry does " @@ -509,21 +509,23 @@ msgid "" "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " "``is_input_command_in_console``, ``max_custom_workers``, " "``is_extend_command``, ``is_enable_encrypto``, ``is_custom_keys``, " -"``max_mem_buff``, ``is_asynic_clients_io``, ``is_debug`` and " +"``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_asynic_clients_io``, ``is_debug`` and " "``is_print_log``; the client entry carries ``host``, ``client_host``, " "``port``, ``client_port``, ``timeout``, ``port_add_step``, " "``max_thread_num``, ``is_input_command_in_console``, ``is_wait_server``, " "``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_debug`` and ``is_print_log``." +"``is_custom_keys``, ``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_debug`` and ``is_print_log``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:251 -#: 8ffd3b4e6719464cbd48a2b20d5764f2 +#: ../../source/Instance_Setup/Instance_Setup.rst:252 +#: 8731a083a201487bb579beb4a238a0db msgid "Custom Parameters" msgstr "맞춤 매개변수" -#: ../../source/Instance_Setup/Instance_Setup.rst:253 -#: 284b4f1899d94269a530dec33958d0c8 +#: ../../source/Instance_Setup/Instance_Setup.rst:254 +#: 8910f94645f54874893c20f724780cbd msgid "" "You may edit ``setup.json`` by hand (or change the same fields in the " "instance editor) to give any parameter accepted by ``TCP_Server_Base`` or" @@ -535,13 +537,13 @@ msgid "" "``setup.json`` from that, so hand-written extra keys are lost." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:264 -#: 3746b90215c84dc38c8ca2bb20d396f6 +#: ../../source/Instance_Setup/Instance_Setup.rst:265 +#: c62b1bfe8ceb40f8865a34ac87b4ba18 msgid "Extension Protocols and Startup Mode" msgstr "확장 프로토콜 및 시작 모드" -#: ../../source/Instance_Setup/Instance_Setup.rst:266 -#: 4c6e6cc80e9c4ce3afe79fad55a2815a +#: ../../source/Instance_Setup/Instance_Setup.rst:267 +#: e6a7dcb4ea184e828e6667ae6505d872 msgid "" "Two extension protocols ship with the launcher and are loaded " "automatically for every instance whose ``setup.json`` entry sets " @@ -550,8 +552,8 @@ msgstr "" "두 가지 확장 프로토콜이 런처와 함께 제공되며 ``setup.json`` 항목이 ``is_extend_command=True``로 " "설정된 모든 인스턴스에 대해 자동으로 로드됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:270 -#: 2d05270538524347899b403011286dcc +#: ../../source/Instance_Setup/Instance_Setup.rst:271 +#: 7159f768fc9a4ac199bfe0a4d8478fba #, fuzzy msgid "" "``command_control_extension_tcp.py`` – remote command execution with per-" @@ -559,8 +561,8 @@ msgid "" "completion report)." msgstr "``command_control_extension_tcp.py`` – 원격 명령" -#: ../../source/Instance_Setup/Instance_Setup.rst:273 -#: 1540ce3848be4d519034dd90e1d27fdd +#: ../../source/Instance_Setup/Instance_Setup.rst:274 +#: d2d277053c74470abc949b891493a5f0 #, fuzzy msgid "" "``forward_extension_tcp.py`` – forwarding messages, files, multiple " @@ -574,8 +576,8 @@ msgstr "" "``/file_forward``, ``/multiple_file_forward``, ``/folder_forward``, " "``/multiple_folder_forward``)에 전달합니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:281 -#: 92e914da56f1402e85ef75819caf5b3f +#: ../../source/Instance_Setup/Instance_Setup.rst:282 +#: a8194174e5fd4dcf87ede716eaada9a4 msgid "" "Plain-message forwarding is native to the TCP protocol (no extension " "needed): the client-only command ``/forward_send_msg`` relays messages to" @@ -584,16 +586,16 @@ msgstr "" "일반 메시지 전달은 TCP 프로토콜에서 기본입니다 (확장 필요 없음). 클라이언트 전용 명령 ``/forward_send_msg " "`` 는 서버를 통해 나열된 대상 클라이언트에 메시지를 전달합니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:286 -#: 836d703843ed4940a42f3b7a0c36b78e +#: ../../source/Instance_Setup/Instance_Setup.rst:287 +#: 98297b76f3404736b92b6c507726a50a #, fuzzy msgid "" "With ``is_extend_command=False`` (the default) the raw TCP protocol is " "started without these two built-in extensions." msgstr "``is_extend_command=False``(기본값)를 사용하면 원시 TCP 프로토콜만 시작됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:289 -#: 3849c157ba79441e8406bcf9a4fc7695 +#: ../../source/Instance_Setup/Instance_Setup.rst:290 +#: fbbe2f02d9174359baca2c685704b475 msgid "" "Independently of ``is_extend_command``, every launch also loads the " "extension protocol files registered in ``PyFlow/added_extensions.json`` " @@ -601,15 +603,15 @@ msgid "" "``add_extension.load_registered_extensions``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:295 -#: fef96f9c96c64f6690b54175c7e7830d +#: ../../source/Instance_Setup/Instance_Setup.rst:296 +#: 9b5ab0319a9843f1b39721d3a96d1777 msgid "" "The ``is_input_command_in_console`` flag selects how the instance is " "started:" msgstr "``is_input_command_in_console`` 플래그는 인스턴스가 시작되는 방법을 선택합니다:" -#: ../../source/Instance_Setup/Instance_Setup.rst:298 -#: 407ae406135b42b3a6efd4ba5242b296 +#: ../../source/Instance_Setup/Instance_Setup.rst:299 +#: 1ec730c995b1454da1b208331d9ca8fe #, fuzzy msgid "" "``True`` (default) – the instance's own start method " @@ -619,8 +621,8 @@ msgstr "" "`` True `` (기본값) – `` start_TCP_Server () ``/`` start_TCP_client () `` 가 " "직접 호출되고 콘솔 입력 루프가 자체 스레드에서 실행됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:301 -#: 1e10d27ee5c04d69ac9de20031a68b31 +#: ../../source/Instance_Setup/Instance_Setup.rst:302 +#: 3cfb2eba312943cea85388f4e9faf40d #, fuzzy msgid "" "``False`` – the instance is started in a background thread and the " @@ -631,8 +633,8 @@ msgstr "" "인스턴스가 백그라운드 스레드에서 실행되고 실행 프로그램은 인스턴스가 중지될 때까지 프로세스를 활성 상태로 유지합니다(헤드리스 배포에" " 유용함)." -#: ../../source/Instance_Setup/Instance_Setup.rst:305 -#: 3743e0549b4449008324f68e282a0d81 +#: ../../source/Instance_Setup/Instance_Setup.rst:306 +#: 3b3482fa903f4afd81234e588a229c1f #, fuzzy msgid "" "Both extensions also expose injectable registration " @@ -648,48 +650,48 @@ msgstr "" "is_input_command_in_console=True)``를 허용하는 편의 기능을 제공합니다. 인스턴스이므로 코드에서 동일한 " "인스턴스에 여러 확장을 로드할 수 있습니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:314 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: ../../source/Instance_Setup/Instance_Setup.rst:315 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Internal Operation" msgstr "내부 운영" -#: ../../source/Instance_Setup/Instance_Setup.rst:316 -#: 4ca266ef495b4a61bce44251b65f8c91 +#: ../../source/Instance_Setup/Instance_Setup.rst:317 +#: 8870bc6b731d40a095a40faed0c8f16d #, fuzzy msgid "" "Each instance is launched in a new terminal window (or background " "process)." msgstr "각 인스턴스는 새 터미널 창에서 시작됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:318 -#: 2b6246012ce84ec0945a9245b208ae95 +#: ../../source/Instance_Setup/Instance_Setup.rst:319 +#: 13c720a93ba54e8ca330fce3a078bb5b #, fuzzy msgid "" "The configuration is passed via a temporary JSON file to avoid shell " "escaping issues." msgstr "구성은 임시 JSON을 통해 전달됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:320 -#: e40392b9adef407ca3ade4bf2d252190 +#: ../../source/Instance_Setup/Instance_Setup.rst:321 +#: 9566eb3cb70e4b77bcbdb584f7e0b6fc #, fuzzy msgid "" "If an instance fails to start, the error is displayed and the window " "pauses for inspection." msgstr "표시되고 검사를 위해 창이 일시 중지됩니다." -#: ../../source/Instance_Setup/Instance_Setup.rst:324 -#: 2d7f7f35978a449995958b44730759d3 +#: ../../source/Instance_Setup/Instance_Setup.rst:325 +#: 5f0f0f6a41384356986a1182f14a0a4c msgid "Requirements" msgstr "요구사항" -#: ../../source/Instance_Setup/Instance_Setup.rst:326 -#: ddf48eb8fc2d48f9adbc38a39965ec22 +#: ../../source/Instance_Setup/Instance_Setup.rst:327 +#: 49ceb74e41104b00971cd9edecef08ae #, fuzzy msgid "Python 3.10+" msgstr "파이썬 3.6+" -#: ../../source/Instance_Setup/Instance_Setup.rst:327 -#: 9bc8a330f1384ade97e4ee55efa58e6b +#: ../../source/Instance_Setup/Instance_Setup.rst:328 +#: 1d80811611c944f9bf772364ab45d1e4 msgid "" "The ``PyFlow.network_api.connect_tcp`` module must be importable (the " "script imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." @@ -809,3 +811,26 @@ msgstr "" #~ msgid "and ``TCP_Client_Base`` from there)." #~ msgstr "및 거기에서 ``TCP_Client_Base``)." +#~ msgid "" +#~ "**Both lists may contain any number " +#~ "of objects.** Every entry is completed" +#~ " with the default value of each " +#~ "parameter that the entry does not " +#~ "set. The stored server entry therefore" +#~ " carries ``host``, ``port``, ``max_clients``, " +#~ "``port_add_step``, ``port_range_num``, " +#~ "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " +#~ "``is_input_command_in_console``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, " +#~ "``is_asynic_clients_io``, ``is_debug`` and " +#~ "``is_print_log``; the client entry carries " +#~ "``host``, ``client_host``, ``port``, " +#~ "``client_port``, ``timeout``, ``port_add_step``, " +#~ "``max_thread_num``, ``is_input_command_in_console``, " +#~ "``is_wait_server``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, ``is_debug`` " +#~ "and ``is_print_log``." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po b/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po index a8db57a..c7c7608 100644 --- a/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po +++ b/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -20,17 +20,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Client_APIs.rst:2 -#: 6dd11dd380344faabc9dea6d41655b1c +#: 596423c8d92e4592b221947ca5595ea7 msgid "The TCP Client APIs" msgstr "TCP 클라이언트 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:5 -#: 2d8b31ea476c498188b1d3df403c2402 +#: bf347a93657146d6b019250273bc439c msgid "TCP Client setup API" msgstr "TCP 클라이언트 설정 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:7 -#: d699c50b2310495bb2521c5da6d30543 +#: 7e3dc9343f554fc181d2c2853898916c msgid "" "The TCP Client Setup API is used to create a TCP client. The client in " "the protocol is usually used to connect to the TCP server and exchange " @@ -39,8 +39,8 @@ msgstr "" "TCP 클라이언트 설정 API는 TCP 클라이언트를 생성하는 데 사용됩니다. 프로토콜의 클라이언트는 일반적으로 TCP 서버에 " "연결하고 서버와 데이터를 교환하는 데 사용됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:34 -#: 5505d653e132458686537e957323bb9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 +#: fb61c59ca5e646f3b749359b2ea13a40 msgid "" "The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The" " parameters of the ``__init__`` method are as follows:" @@ -48,23 +48,23 @@ msgstr "" "TCP 클라이언트 설정 API는 ``TCP_Client_Base`` 클래스에 정의되어 있습니다. ``__init__`` 메소드의 " "매개변수는 다음과 같습니다:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:37 -#: 6a41dd3d0f00421b914a6ae9e588d6b8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 +#: d8b55d105dd144198594dd4f454fe5c5 msgid "``host``: The server host IP address to connect to." msgstr "``host``: 연결할 서버 호스트 IP 주소입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 -#: cc6ddd6c80bb46f3b393c9882e096a0a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 +#: ee9f5f584e6643529cdca91384562ebf msgid "``client_host``: The local host IP address to bind the client socket to." msgstr "``client_host``: 클라이언트 소켓을 바인딩할 로컬 호스트 IP 주소입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:39 -#: 949c21452bb94effa6c13959868ac90f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 +#: 03357b8c2f974a419c6933d68976b6eb msgid "``port``: The server port number to connect to." msgstr "``port``: 연결할 서버 포트 번호입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:40 -#: 97c56df67b0c435aaf8ee89bea56266b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 +#: cd50ed1b09934f3bae2a4c615187d157 msgid "" "``client_port``: The local port number to bind the client socket to " "(``None`` means let the OS choose)." @@ -72,8 +72,8 @@ msgstr "" "``client_port``: 클라이언트 소켓을 바인딩할 로컬 포트 ​​번호입니다(``None``은 OS가 선택하도록 함을 " "의미합니다)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 -#: 309676fc53ff4cd39a8d9e200c54f1bf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 +#: f8cdf36b87834ea7a95209d2ca048332 msgid "" "``timeout``: The socket timeout in seconds for connection and receive " "operations. ``None`` (the default) is not \"no timeout\": the socket then" @@ -81,41 +81,41 @@ msgid "" " receive loop (it simply continues)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 -#: 9bf924fa535a44e78c98664e8d2b304f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 +#: 20c7ea1afac14f80a2b739cb6ae1957f msgid "" "``port_add_step``: The step size for incrementing the port number (used " "only in manual allocation mode)." msgstr "``port_add_step``: 포트 번호를 증가시키는 단계 크기(수동 할당 모드에서만 사용됨)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 -#: 5abb7f5137714757b6957a177747d1e5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 +#: eb06f09e560543e5ba0abb3627a63585 msgid "" "``max_thread_num``: The maximum number of threads for concurrent file " "transfer operations." msgstr "``max_thread_num``: 동시 파일 전송 작업을 위한 최대 스레드 수입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 -#: e71bd35480184667a6390f2a28c0894a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:48 +#: 5ff72dc0ec90411bb0d20f618d015093 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console (interactive mode)." msgstr "``is_input_command_in_console``: 콘솔(대화형 모드)에 명령을 입력할지 여부를 나타내는 플래그입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 -#: f4dd649db47842fdb7b64e39d5887cdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:49 +#: 5e12aa05eb854b15b0b6779b40b5a302 msgid "" "``is_wait_server``: A flag indicating whether to keep retrying connection" " until the server is available." msgstr "``is_wait_server``: 서버를 사용할 수 있을 때까지 계속 연결을 재시도할지 여부를 나타내는 플래그입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 -#: 69c7bfb0cc784e9a817d98096357d9d6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:50 +#: b3232047b364478caad5b3e5361e71be msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``: 사용자 정의 작업자 스레드의 최대 수입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 -#: 892ac76eabb04f90b9c95f29009b6c11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 +#: a951c5564286432082b3e6a06aae8a48 msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the client itself by calling " @@ -123,8 +123,8 @@ msgid "" "register its commands first and connect later." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 -#: 0cfe21e428fd45f08a9d8c080c285535 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:55 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-" @@ -133,8 +133,8 @@ msgstr "" "``is_enable_encrypto``: 서버와 주고받는 메시지가 RSA 암호화되었는지 여부를 나타내는 플래그입니다(:ref" ":`tcp-client-encrypted-channel-api` 참조)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:53 -#: 353688102eb6441ebf87384e57f0c661 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 +#: 8ac8a71ca8564a89bb52f882c4fedefc msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -145,86 +145,132 @@ msgstr "" "쌍입니다. 두 파일이 모두 존재하고 PEM으로 구문 분석되고 서로 쌍을 이루어야 합니다. 유효하지 않은 쌍은 자동으로 무시되고 기본" " 키 조회가 대신 사용됩니다(``None``은 기본 조회를 유지합니다)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 -#: 0176e8b8b8ea44c396d55657d74a91cd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:61 +#: c01569233a864bf0b106a877fb924c27 msgid "" "``max_mem_buff``: The buffering ceiling in MiB, stored as bytes " "(``self.max_mem_buff``). It is kept for parity with the server class; the" " client's forward path does not read it today. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:60 -#: 276f7755eaea4b808ad6cfe985eaa8aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:64 +#: 10fb41da1af34a539a962083252bdf55 +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 +#: 1b569fa80b59490dacc6bcdf3a924d60 +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 +#: ac73e6da7c3044f1bf68aff504142765 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the client logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:63 -#: 58a790ecb724454298659bf9831fb2ae +#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_print_log``: A flag indicating whether the client logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 -#: 36eebcb4edbb4f1e96862b64762c4d6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 +#: fa251d2893fa413aac9d5e525df18209 +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when the " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:85 +#: 3a9f1a8e8b8f45dbb9011b3b0e28cd92 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:93 +#: 3272388be97643f98bada0a995516141 msgid "Every parameter has default values:" msgstr "모든 매개변수에는 기본값이 있습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 -#: 4a2b0f17cb4f47669a8dcb3734c17468 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:95 +#: 9fd3d516d31841fd9054a2a3dfcb1ac4 msgid "``host``: Default is ``None`` (must be provided before connecting)" msgstr "``host``: 기본값은 ``None``입니다(연결하기 전에 제공해야 함)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:69 -#: 7dea100856734d3ba4ee6352d45cc554 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:96 +#: ece6c7a48ae74f86b6e207d960c6daa2 msgid "``client_host``: Default is ``'127.0.0.1'``" msgstr "``client_host``: 기본값은 ``'127.0.0.1'``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:70 -#: e646757cb9d1425fa72970698c2938e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 +#: 8a9d85bb281e43e69ea0ae48363fb8da msgid "``port``: Default is ``65432``" msgstr "``포트``: 기본값은 ``65432``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 -#: 4c232543227544acae211825b01a795a -msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" -msgstr "``client_port``: 기본값은 ``None``입니다(OS가 임시 포트를 할당함)." +#: ../../source/Network_APIs/TCP_Client_APIs.rst:98 +#: 4653721a3e8143fea8a43899bb0e6437 +msgid "" +"``client_port``: Default is ``None`` (OS assigns ephemeral port). A " +"configured port that cannot be bound — a session that just ended can hold" +" it in the operating system's ``TIME_WAIT`` — is reported and the " +"connection is made from an OS-assigned port instead." +msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:72 -#: 3c772d5ab49243b993d5dfea9af5d472 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:102 +#: 4439e99a222744a9bca762b5f14b4d74 msgid "``timeout``: Default is ``None``" msgstr "``timeout``: 기본값은 ``None``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:73 -#: 501a6c2966d2470cbf9ce2a8909ef130 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 +#: 0b0f6a9551ff4bf28ad02095893db9d8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: 기본값은 ``1``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 -#: 697656b4cb24453c89b1a848299e4167 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:104 +#: bcb1ee681a0f47319338faf71a99adf7 msgid "``max_thread_num``: Default is ``10``" msgstr "``max_thread_num``: 기본값은 ``10``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:75 -#: 632284d8c9b349f89018f8a19ce9662e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:105 +#: 08471d033b174cf395292c36068d4cb8 msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: 기본값은 ``True``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:76 -#: ec7a8bd80ad2471d9208999fc34792f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:106 +#: bbf2ad3b5e4340c9b481f8af135281e2 msgid "``is_wait_server``: Default is ``True``" msgstr "``is_wait_server``: 기본값은 ``True``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:77 -#: c036a352181d422894b56b0c14167bdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:107 +#: 63f2004d0c5b4fef8cf23eaa7be020b1 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: 기본값은 ``10``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:78 -#: 64df1f8395ca45d497875fb232c71b0e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:108 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_client()`` automatically)" @@ -232,8 +278,8 @@ msgstr "" "``is_extend_command``: 기본값은 ``False``입니다(``True``인 경우 ``__init__``는 " "``start_TCP_client()``를 자동으로 호출하지 않습니다)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:80 -#: ca18c257b4054fad931a19b59a8a4606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:110 +#: c723e855f50a4ec3abf45aaae2e02f45 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, the client " "performs an RSA public-key exchange with the server right after " @@ -242,8 +288,8 @@ msgstr "" "``is_enable_encrypto``: 기본값은 ``True``입니다(``True``인 경우 클라이언트는 연결 직후 서버와 " "RSA 공개 키 교환을 수행하고 모든 후속 메시지가 암호화됩니다)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:83 -#: 0c6ecb6d7f504ef8a9a666bc2659a009 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:113 +#: 16c586bc40d94d6b9624812993e12579 msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -252,36 +298,71 @@ msgstr "" "``is_custom_keys``: 기본값은 ``None``입니다(``[pub_key_path, pvt_key_path]`` 목록은" " 기본 ``~/.ssh`` / 생성된 키 대신 사용자가 제공한 키 쌍을 사용합니다)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:86 -#: 96c8a6add16d4a999f8910133dad83b4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:116 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:88 -#: 4ea3ee5f013c46c98a380ed9fa7b6e64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:118 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "client would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:90 -#: a1d9d8ceda754443aef4e9dd2031e754 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:120 +#: 58fc5a7851094fcba7903d9e6cd4e8e7 msgid "" "``max_mem_buff``: Default is ``2048`` (kept for parity with the server " "class; the client's forward path does not read it today)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:94 -#: 930f7b1c90474a16b2dc7d13c41c238c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:123 +#: 08471d033b174cf395292c36068d4cb8 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_custom_workers``: 기본값은 ``10``입니다." + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 +#: ff70e67852154092b227e2f05357a78d +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:125 +#: bd7d9bb9bbe14bc38eed56c574fc0987 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:127 +#: 5282067c345342d4872377ec83b3ba95 +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 +#: d10be044603c42e9a26b3164dcb7cb51 +msgid "" +"``is_auto_reconnect``: Default is ``False`` (``True`` makes " +"`start_TCP_client` reconnect after the connection drops and resume the " +"interrupted transfers, see :ref:`transfer-pause-and-reconnect`. The dead " +"session's socket is closed abortively first, so a configured " +"``client_port`` can be bound again — Windows refuses it otherwise)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:135 +#: 4b99048b2ec14a988fd9b83b23284d25 msgid "" "The TCP Client Setup API will initialize all the necessary parameters and" " resources for the TCP client." msgstr "TCP 클라이언트 설정 API는 TCP 클라이언트에 필요한 모든 매개변수와 리소스를 초기화합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 -#: 221e218700a34372ae96eae9189831aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 +#: b7da2a334a9543aa96178bddc8b6855c msgid "" "*Note: In the main class of the TCP client setup API, we initialize the " "`start_TCP_client` method to set up all functions which are needed in the" @@ -291,8 +372,8 @@ msgstr "" "*참고: TCP 클라이언트 설정 API의 메인 클래스에서는 `start_TCP_client` 메소드를 초기화하여 서버 연결, 수신 " "메시지 처리, 사용자 입력 관리 등 TCP 클라이언트에 필요한 모든 기능을 설정합니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 -#: 00cb8ca5027d464f88e778a8f2a4faec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 +#: 0aa6b4133bf54878ad5d35aa8523ae88 msgid "" "*Note: By default ``TCP_Client_Base.__init__`` calls " "``start_TCP_client()`` to connect and enter interactive mode. If you set " @@ -303,8 +384,8 @@ msgstr "" "연결하고 대화형 모드로 들어갑니다. ``is_extend_command=True``를 설정하면 인스턴스가 자동 시작되지 않으며 " "준비가 되면 수동으로 ``start_TCP_client()``를 호출해야 합니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:109 -#: 4d8f352fa0be45e1b75d44727035e828 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 +#: 7a35992f8c7c410da60029bb06fb054a msgid "" "*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must" " be ``None``. The constructor will raise a ``ValueError`` if " @@ -314,8 +395,8 @@ msgstr "" "``is_wait_server``가 ``True``이고 ``timeout``이 ``None``이 아니면 생성자는 " "``ValueError``를 발생시킵니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:119 -#: 92cea23fb57c482cb1199cabd89af968 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 +#: 35b6f81f408041c4a7e650d3b92957d1 msgid "" "In the `start_TCP_client` method, we first attempt to connect to the " "server by calling the `connect` method. If the connection fails and " @@ -325,8 +406,8 @@ msgstr "" "`start_TCP_client` 메소드에서는 먼저 `connect` 메소드를 호출하여 서버에 연결을 시도합니다. 연결이 실패하고 " "``is_wait_server``가 ``True``이면 클라이언트는 계속 재시도합니다. 그렇지 않으면 종료됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 -#: 2e529671abf848fd87771801ae4a3763 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:165 +#: d8e70dde1c62462cb4954eb1ceb50f3a #, fuzzy msgid "" "*Note: The client socket is created in the `connect` method (called by " @@ -337,8 +418,8 @@ msgstr "" "*참고: `start_TCP_client` 메소드로 생성된 클라이언트 소켓은 IPv4 기반으로 클라이언트 인스턴스 생성 시 제공되는" " ``self.host`` 및 ``self.port`` 매개변수를 사용합니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 -#: abe7c8d5d59b4a589ec6537a06a7333b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:170 +#: 80f69db837ec4e1d9bb90bc821019532 msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will either start the interactive input loop " @@ -348,16 +429,16 @@ msgstr "" "둘째, ``self.is_input_command_in_console`` 매개변수에 따라 대화형 입력 " "루프(``interactive_mode')를 시작하거나 단순히 연결을 활성 상태로 유지합니다(콘솔 입력 없음)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:134 -#: e6ad1c25ef6e409aa4dba10b44fbe7a4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 +#: 445af010e93f421099da8d8dd5212210 msgid "" "After that, if the interactive mode is enabled, the client will read user" " input from the console and send messages to the server until the " "connection is closed." msgstr "그 후 대화형 모드가 활성화되면 클라이언트는 연결이 닫힐 때까지 콘솔에서 사용자 입력을 읽고 서버에 메시지를 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 -#: c957271185064b21a0bc78265e007969 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:179 +#: 2d4020f99c3c4a4485815c383a0a4bfe msgid "" "*Note: There is a global variable ``self.running`` which is set to " "``True`` after the client successfully connects to the server. The " @@ -368,8 +449,8 @@ msgstr "" "``self.running`` 변수는 메인 수신 루프를 제어하는 ​​데 사용되며, 클라이언트가 종료되면 ``False``로 " "전환됩니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 -#: d055f0b3b19940be8b0549705d6cd3b5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:185 +#: e4de5ae390fc4c1c9a50703299f80356 msgid "" "The `connect` method will try to establish a TCP connection to the " "server. If a ``client_port`` is specified, the client will bind to that " @@ -381,20 +462,20 @@ msgstr "" " 전에 해당 로컬 포트에 바인딩됩니다. 이 메소드는 특히 ``is_wait_server``가 활성화된 경우 시간 초과 및 연결 거부" " 오류를 적절하게 처리합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 -#: 4615e65c81854301ac43f16a4d7e16b1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 +#: 17315c7599be4d2e8d8f62ad4c866eb3 msgid "" "When the connection is established, a background thread " "`receive_messages` is started to continuously read data from the server." msgstr "연결이 설정되면 백그라운드 스레드 `receive_messages`가 시작되어 서버에서 지속적으로 데이터를 읽습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:154 -#: bace28ef9c5841ffac04669beeb4e56a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:195 +#: 26bc6f1cf62947c88fd9de780337d225 msgid "So what can the setup function do if the connection fails?" msgstr "그렇다면 연결이 실패하면 설정 기능은 무엇을 할 수 있습니까?" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:156 -#: f89e08eff4f84bfba70ee321e26e218b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:197 +#: e7519cc6a4124a008a804ecbe9b10453 msgid "" "First, if the connection attempt times out, the client will either wait " "and retry (if ``is_wait_server`` is ``True``) or exit with an error." @@ -402,8 +483,8 @@ msgstr "" "첫째, 연결 시도 시간이 초과되면 클라이언트는 기다렸다가 다시 시도하거나(``is_wait_server``가 ``True``인 " "경우) 오류와 함께 종료됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 -#: fe3484d9a2b04f29944bc0d412d73536 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:201 +#: 2bcc61a302d34c7dbc18f9bcc7beba5a msgid "" "Secondly, if the server is not running (connection refused), the " "behaviour is the same: retry or exit based on ``is_wait_server``." @@ -411,8 +492,8 @@ msgstr "" "둘째, 서버가 실행 중이 아닌 경우(연결 거부) 동작은 동일합니다. 즉, ``is_wait_server``에 따라 다시 시도하거나 " "종료합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:164 -#: 18131d4fd10c42d09e1eca9697bda2fb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:205 +#: c33c7409acd94d6b8f69e0f718e50c1f msgid "" "If any other socket error occurs, the client will print the error message" " and return ``False``, and the `start_TCP_client` method will call " @@ -421,13 +502,13 @@ msgstr "" "다른 소켓 오류가 발생하면 클라이언트는 오류 메시지를 인쇄하고 ``False``를 반환하며 `start_TCP_client` " "메서드는 ``sys.exit(1)``을 호출합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:168 -#: 050d63fcb50c4053aba93e3d05dae63c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:209 +#: d78f849334b6404d8840b12839d05b8c msgid "For shutting down the client, the `close` method is defined as:" msgstr "클라이언트를 종료하기 위해 `close` 메소드는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 -#: c0860fa6e2c240e5a2a56b278f3369f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 +#: 4b23bb29324b408ca1a3c06128ede442 #, fuzzy msgid "" "In the `close` method, we set ``self.running`` to ``False``, free any " @@ -438,8 +519,8 @@ msgstr "" "`close` 메소드에서 ``self.running``을 ``False``로 설정하고 `free_port`를 호출하여 할당된 포트를" " 해제한 다음 클라이언트 소켓을 닫습니다. 이렇게 하면 깔끔한 연결 해제가 보장됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:180 -#: 6a703de12132431982451a11b661b4d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:221 +#: 510de5709a444a0c8296717f1e8bed2b msgid "" "``close`` also wins against a connection attempt that is still in flight:" " if it runs before ``connect`` puts the socket up, that call closes the " @@ -447,8 +528,8 @@ msgid "" "client." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:184 -#: ae54449f52b0491aaeb0c11de7749e4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:225 +#: c67deae0af3b4ab9bf572198122cc09d msgid "" "*Note: The `free_port` method works similarly to the server side, " "releasing any manually allocated ports if manual allocation mode is " @@ -457,13 +538,13 @@ msgstr "" "*참고: `free_port` 방법은 서버 측과 유사하게 작동하며 수동 할당 모드가 활성화된 경우 수동으로 할당된 포트를 " "해제합니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 +#: fbb5ed3c54a34df4bc6bf8f9688e295c msgid "TCP Client handling information API" msgstr "TCP 클라이언트 처리 정보 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:193 -#: 57895cdce9c1426289087c4448ac2325 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 +#: 7c21a424a7774ad6b4a257c5ad645db4 msgid "" "The client handling information API documents the core TCP client methods" " that manage the server connection, receive raw data, and send messages." @@ -471,8 +552,8 @@ msgstr "" "클라이언트 처리 정보 API는 서버 연결을 관리하고 원시 데이터를 수신하고 메시지를 보내는 핵심 TCP 클라이언트 메서드를 " "문서화합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:198 -#: f9294ef58d274a9ba6b8edbec8c07606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:239 +#: b0fc366cad48412999e75faf81120a6e msgid "" "Unlike the server, the client maintains only a single connection and does" " not provide broadcast or ``send_msg_to_specific_client`` methods." @@ -480,8 +561,8 @@ msgstr "" "서버와 달리 클라이언트는 단일 연결만 유지하며 브로드캐스트 또는 ``send_msg_to_특이적_client`` 메소드를 제공하지 " "않습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:208 -#: 67e867cdfba84730bef1ad32d859ea24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:249 +#: ff50f500c3804fdb9562b5e9ae1a3482 msgid "" "`receive_messages` is the main background thread function in " "``TCP_Client_Base``. It is started after a successful connection and is " @@ -490,83 +571,83 @@ msgstr "" "`receive_messages`는 ``TCP_Client_Base``의 주요 백그라운드 스레드 함수입니다. 성공적인 연결 후에 " "시작되며 다음을 담당합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:212 -#: 17684d40e43543e88db7135b66b26e09 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 +#: 364f1d2b080843518fee4bcc0e74a8ca msgid "" "continuously receiving raw bytes from the server socket using " "`receive_message`" msgstr "`receive_message`를 사용하여 서버 소켓에서 원시 바이트를 지속적으로 수신합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:213 -#: dc882668c1244dc3b7e57b07ad08612a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:254 +#: cf3b7cf194ec42919b87199c4586dfc4 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "개행 문자로 끝나는 메시지가 완료될 때까지 들어오는 데이터 버퍼링" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:214 -#: 707313e8051245478059aa883da7459f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:255 +#: ad695c0a732a4ad78cdd07c79f2d5dc3 msgid "splitting and processing each message line-by-line" msgstr "각 메시지를 한 줄씩 분할하고 처리" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:215 -#: e9edeedb0eb64a278e03efa5169a36f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:256 +#: 387a605c25f8407d86b77c452ded00f7 msgid "" "routing special commands (starting with ``/``) that come from the server " "to `handle_server_command`" msgstr "서버에서 오는 특수 명령(``/``으로 시작)을 `handle_server_command`로 라우팅" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 -#: 0ab735831831448a88f60538f859ce4e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:257 +#: d1729cfa1e314df68d3e7ce7e553f3a5 msgid "" "printing every received line to the console with a ``[server]`` prefix " "(command lines included, after ``handle_server_command`` has processed " "them)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:218 -#: e09f439632994d0fadb0ae8f58eef0cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:259 +#: 083b077c5c1845338f11ae62bace15b5 msgid "" "unwrapping forwarded lines (``/send_msg_from``) so a message another " "client forwarded here is attributed to its author" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:220 -#: 166f9028c1cc41ff94be560b77e17504 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:261 +#: 1dd20cbdeac3480bbaec2f7ae6f1f1ed msgid "" "handling connection resets and other socket errors, and cleaning up when " "the server closes the connection" msgstr "연결 재설정 및 기타 소켓 오류 처리 및 서버가 연결을 닫을 때 정리" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:229 -#: db2e058412bc44d6ba39131b3b40a7ac +#: ../../source/Network_APIs/TCP_Client_APIs.rst:270 +#: e890dee4fb944eeaa9e6b2cf3cd9047a msgid "" "In `handle_server_command`, the client processes built-in commands sent " "by the server, such as:" msgstr "`handle_server_command`에서 클라이언트는 다음과 같이 서버에서 보낸 내장 명령을 처리합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:273 +#: b957ec8457f34618802ea0441634a894 #, fuzzy msgid "" "``/client_alloc_port_range``: configures the client's manual port " "allocation range from the line the server sends it on connect." msgstr "``/client_alloc_port_range``: 서버 브로드캐스트를 기반으로 클라이언트 수동 포트 할당 범위를 구성합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 -#: 2558e50f505a4b6ca51c7a44fa9ad957 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:275 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/server_file_transfer_port``: receives the file transfer port assigned " "by the server for an ongoing file operation." msgstr "``/server_file_transfer_port``: 진행 중인 파일 작업을 위해 서버에서 할당한 파일 전송 포트를 받습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:236 -#: 5147df6f2f794cf2949b7cef1ed24791 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:277 +#: 4eb4fe22d5db4b56b622dfd29459c3b7 msgid "" "``/file`` and ``/file_folder``: handle file transfer requests initiated " "by the server (server-to-client transfers)." msgstr "``/file`` 및 ``/file_folder``: 서버에서 시작한 파일 전송 요청(서버에서 클라이언트로의 전송)을 처리합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:238 -#: 4755bb63eb0e4f8cbf481633417fc3c7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:279 +#: 3c550345aa484cb8bc44681842864044 msgid "" "``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``," " ``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the " @@ -574,15 +655,15 @@ msgid "" "the connection." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:242 -#: f7cbe268c5e84987aec0bb18a0a81aa7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 +#: 31a62335177b49a19f708aee2aa5b0b1 msgid "" "``/forward_upload``, ``/pause_trans``, ``/start_trans``, " "``/forward_error``: forwarding and transfer-control messages." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:245 -#: d89b63a85c3d402fbb0df0f75edc4736 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:286 +#: b4c3c6ea61f344b8a3d3baf6b659d9c7 msgid "" "If you have registered custom commands using the command extension API, " "`handle_server_command` will also check if the incoming command matches " @@ -591,23 +672,23 @@ msgstr "" "명령 확장 API를 사용하여 사용자 정의 명령을 등록한 경우 `handle_server_command`는 수신 명령이 등록된 " "핸들러와 일치하는지 확인하고 그에 따라 실행합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:250 -#: 943d4fb64bad477f969403f360288769 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 +#: 4b6cc84b10d34254b7e6e0d7ae226ddc msgid "" "*Note: For more details of the command extension API, see the :ref:`tcp-" "client-command-api` section.*" msgstr "*참고: 명령 확장 API에 대한 자세한 내용은 :ref:`tcp-client-command-api` 섹션을 참조하세요.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 -#: c2b4ba39cca64ea7ab62a59d016f0544 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:294 +#: b9ff85e2f76d4c1697602ebf69fed3a8 msgid "" "Closing the connection when the server goes away is not part of " "`handle_server_command`: it is `receive_messages` that reports the " "disconnect and clears ``self.running``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:265 -#: 9312fc5109a547d588d98c16a9b79c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:306 +#: 4376aa47bf63490998e7008547d0c86f msgid "" "`receive_message` is identical to the server version: it reads up to " "``msg_length`` bytes from the given socket and returns the raw byte " @@ -616,8 +697,8 @@ msgstr "" "`receive_message`는 서버 버전과 동일합니다. 지정된 소켓에서 최대 ``msg_length`` 바이트를 읽고 원시 " "바이트 페이로드를 반환합니다. 메시지 디코딩 및 개행 프레이밍은 호출자가 처리합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:278 -#: 7a64cec6a8084261a443f57f7032a5bb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:319 +#: 29b51f413be748e4b101bf498e593ef2 msgid "" "`send_message` sends data from the client to the server. It verifies the " "client is still running and the socket is valid, then:" @@ -625,18 +706,18 @@ msgstr "" "`send_message`는 클라이언트에서 서버로 데이터를 보냅니다. 클라이언트가 여전히 실행 중이고 소켓이 유효한지 확인한 후 " "다음을 수행합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:281 -#: 9a5d3a7c041b47d68b80186e09492467 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 +#: e4158824d7b04b37a0f75c9ff67eab45 msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "``str`` 및 ``bytes`` 메시지 페이로드를 모두 허용합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:282 -#: c4247339bf084481af72ba498d8f9bcd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:323 +#: ea9158c1798941cb9df13f5a01b14f69 msgid "trims string payloads and appends a newline if missing" msgstr "문자열 페이로드를 자르고 누락된 경우 개행을 추가합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 -#: 55c0dfde024b4bdea57da54d86297dbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:324 +#: 0fb0befad2844821a59b8c5c686e1c39 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -646,25 +727,25 @@ msgstr "" "소켓이 암호화 모드에 있을 때(공개 키 교환이 완료됨) 일반 텍스트는 ``_VALID`` 마커로 서명되고 RSA-OAEP는 서버의 " "공개 키로 암호화되며 base64로 인코딩되고 일반 텍스트로 전송되는 대신 개행 문자로 종료됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:287 -#: 6e2bbc8edbad40568dfe3eae781ab27c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:328 +#: e8d7a04011e74da18b274e1ad3ca3ab8 msgid "encodes string payloads as UTF-8" msgstr "문자열 페이로드를 UTF-8로 인코딩합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:288 -#: 40b2936e9c6b4325b19b27f83932cf83 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:329 +#: 08c9e9aca2334e67b5051b42cc7dbad0 msgid "sends the complete message with ``client_socket.sendall(data)``" msgstr "``client_socket.sendall(data)``를 사용하여 완전한 메시지를 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:289 -#: 9ab8a09e5ca4416abd843cf1612f20a2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:330 +#: 99b4f8d523b2406499891c514befc372 msgid "" "returns ``True`` on success, otherwise logs the error and returns " "``False``" msgstr "성공하면 ``True``를 반환하고, 그렇지 않으면 오류를 기록하고 ``False``를 반환합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 -#: 0eb535b8380441869c432950417def80 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:332 +#: 18101652b1e34996866324fce0aa8a4d msgid "" "The client also provides an interactive input loop (`interactive_mode`) " "that reads user input from the console and sends messages to the server." @@ -672,35 +753,36 @@ msgstr "" "클라이언트는 또한 콘솔에서 사용자 입력을 읽고 서버에 메시지를 보내는 대화형 입력 루프('interactive_mode')를 " "제공합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:298 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:339 +#: fbb5ed3c54a34df4bc6bf8f9688e295c #, fuzzy msgid "TCP Client inbound event listener API" msgstr "TCP 클라이언트 파일 전송 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:300 -#: 8b78c521249c4604933d30cfc99cc7a9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:341 +#: 15461ca186ed497083b901e65a3b33d1 msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:310 -#: 2f13976d605042919a1a19e346d85bd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:351 +#: 0d916f8d3eaf4336b5be87a5faf153a3 msgid "" "``add_message_listener`` registers ``listener(sender_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to `handle_server_command` instead). ``sender_id`` is the author's " -"``\"ip:port\"`` — for a message another client forwarded here through the" -" ``/send_msg_from`` envelope it is the forwarding client, and it is " -"``None`` for a direct push from the server. ``add_file_listener`` " -"registers ``listener(client_id, full_path, name, size, command)`` and " -"fires after a file sent by the server has been fully written to disk. " -"Both listeners run on a protocol thread, so they must not block, and an " -"exception inside a listener is logged and swallowed. The ``remove_*`` " -"counterparts unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 -#: 75d993e34b944014be1b88aee03a4f9c +"every inbound line, commands included, so a listener observes all inbound" +" traffic; a message another client forwarded here through the " +"``/send_msg_from`` envelope is reported as its payload. ``sender_id`` is " +"the author's ``\"ip:port\"`` — the forwarding client for such a forwarded" +" message, and it is ``None`` for a direct push from the server. " +"``add_file_listener`` registers ``listener(client_id, full_path, name, " +"size, command)`` and fires after a file sent by the server has been fully" +" written to disk. Both listeners run on a protocol thread, so they must " +"not block, and an exception inside a listener is logged and swallowed. " +"The ``remove_*`` counterparts unregister a listener and ignore unknown " +"ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:364 +#: 196be233dc00497a94ee87f9999a9897 msgid "" "Received messages and events are also stored per sender socket in " "``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -709,13 +791,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``close`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:331 -#: 6535dcf4080e4090bf82df637e452cc6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:373 +#: 6d52a0605748445694e0f4b1a6c52ea7 msgid "TCP Client encrypted channel API" msgstr "TCP 클라이언트 암호화 채널 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:333 -#: e2dbda95b2ff4483b8b71394ae4b83c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:375 +#: 14a20833906f4e18b92856c3e98a8886 msgid "" "When the client is created with ``is_enable_encrypto=True`` (the " "default), it performs an RSA public-key exchange with the server " @@ -724,13 +806,13 @@ msgstr "" "클라이언트가 ``is_enable_encrypto=True``(기본값)로 생성되면 연결 직후 메시지 내용이 암호화되기 전에 서버와 " "RSA 공개 키 교환을 수행합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:338 -#: 411e33f708ba4961aaf9073beffe7404 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:380 +#: 46166a685e064cd29ad7701d3a352fc4 msgid "Key material" msgstr "주요자료" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:340 -#: 89d96a4b9abe4ccd98bdd72682b94a56 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:382 +#: ffdef9bf79aa41e6a401b0a16c24a674 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -742,8 +824,8 @@ msgstr "" "``network_api/.Flow/pvt_key`` (``client_priv.pem`` / ``client_pub.pem``)에" " 생성됩니다. 교환된 공개 키는 항상 개인 키에서 파생되므로 회전된 ``~/.ssh`` 쌍이 자동으로 선택됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:345 -#: 74eb9aca2b1849e48138cbea3e76a39d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 +#: 2c27cfc2e8ce47fb8732aec1e00d3479 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -754,8 +836,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:352 -#: e935794dae5f4c2682336e72732afec3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:394 +#: 425ba3d582c3490b9375d99baa9b61e6 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -767,8 +849,8 @@ msgstr "" " 있습니다. 두 파일이 모두 존재해야 하며 PEM으로 구문 분석하고 서로 쌍을 이루어야 합니다(공개 키로 암호화된 프로브는 개인 " "키로 해독해야 함). 유효하지 않은 쌍은 무시되고 기본 조회가 사용됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:357 -#: 72a43fff94f04914848603d6ede43cfd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:399 +#: 696441cc5dd44fc4af958c547c8b6b90 msgid "" "Public keys received from the server are cached in " "``network_api/.Flow/pub_key`` as ``server__.pem`` (the server " @@ -779,13 +861,13 @@ msgstr "" " 캐시됩니다(키가 나온 서버 엔드포인트; ``:``는 ``_``으로 대체되므로 IPv6 리터럴은 Windows를 포함한 모든 " "플랫폼에서 안전합니다)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:363 -#: a4903fbcbc6f4c9d93c8fc3066fcc1c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:405 +#: 2a81e756d1c947d384d20dbbbe5d6d52 msgid "Anti-MITM identity check (TOFU)" msgstr "MITM 신원 확인(TOFU) 방지" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:365 -#: e30dc3b276654ea2b6ec48793d8df984 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:407 +#: 7a915eef76594c3ea715adb845fcabc6 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -800,15 +882,15 @@ msgstr "" "port)``(피어가 도달할 수 있는 엔드포인트의 Python 튜플)이고 값은 ``[<공개 키의 sha256>, <공개 키 " "PEM>]``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:372 -#: 247a92c41f0d45ed9a5f8ad2d12bca2e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:414 +#: 4d56fbd290604113a600a56d8e89cdfb msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "엔드포인트에서의 첫 번째 연결: 키가 기록되고 신뢰됩니다(처음 사용할 때 신뢰)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:374 -#: 7adc6b725e7244df8bc1b861b4cec80c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:416 +#: a6be8828e0594ddc8aa71229934cc73d msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -817,8 +899,8 @@ msgstr "" "*동일한* 키를 나타내는 나중에 연결: 허용됩니다. 엔드포인트가 변경된 경우(동적 IP / 사용자 변경 포트) 레코드가 중복되지 " "않고 새로운 ``(ip, port)``로 이동됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:377 -#: ba6d10fef7fb42cd8dd6518c415762d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 +#: fda350faac9a4efd82575a386fc929c0 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is received and " @@ -827,8 +909,8 @@ msgstr "" "이미 기록된 엔드포인트에 대해 *다른* 키를 나타내는 이후 연결: 연결이 거부됩니다(``/crypto_reject``가 수신되고 " "클라이언트가 닫힙니다)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:381 -#: 7f2ec5e5c2604098906635697130c4fd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:423 +#: 9d62655e00324c518633c6c1d615d515 msgid "" "The client-side record is keyed by the fixed server address, so a server " "that changes its public key (for example a MITM substitution) is always " @@ -838,13 +920,13 @@ msgstr "" "클라이언트 측 레코드는 고정 서버 주소로 입력되므로 공개 키(예: MITM 대체)를 변경하는 서버는 이후 연결에서 항상 거부됩니다." " 신뢰를 재설정하려면(교체된 키, 새 서버) ``pub_key.json`` 항목(또는 전체 파일)을 삭제하세요." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 -#: 9a08bf51aea742de8d0a0f351d055b3a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:429 +#: 799c58ee59b0416688562166f58a14c1 msgid "Handshake" msgstr "악수" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:389 -#: 879e1be6d2de4859bc0777d1cd1682f8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:431 +#: 6f92afe3b8314a9985b62fe55cdeee70 #, fuzzy msgid "" "Right after connecting, the client announces its encryption mode with a " @@ -852,15 +934,17 @@ msgid "" "server's answer; a mode mismatch closes the connection. It then sends a " "plaintext ``/crypto_key_exchange `` greeting; the server " "replies with ``/crypto_key_exchange_ack " -"``. Both sides then push their public key files over the file-" -"transfer mechanism (plaintext) and TOFU-check the received key. Both " -"sides switch to encrypted mode only after ``/crypto_ready`` has been " -"received from the peer (so plaintext and ciphertext never interleave on a" -" connection). On later connections the keys are re-exchanged and TOFU-" -"checked again; the exchange is never skipped, only the identity check " -"short-circuits for known keys. Public-key pushes are only accepted while " -"a handshake is in progress, so an arbitrary unauthenticated server cannot" -" poison the registry." +"``. Both (plaintext) and TOFU-check the received key. Both sides " +"switch to encrypted mode only after ``/crypto_ready`` has been received " +"from the peer (so plaintext and framed traffic never interleave on a " +"connection), then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted while a handshake is in progress, so an " +"arbitrary unauthenticated server cannot poison the registry." msgstr "" "클라이언트는 연결 직후 일반 텍스트 ``/crypto_key_exchange`` 인사말을 보냅니다. 서버는 " "``/crypto_key_exchange_ack ``로 응답합니다. 그런 다음 양측은 " @@ -869,34 +953,58 @@ msgstr "" "절대로 인터리브되지 않습니다). 이후 연결에서는 키가 다시 교환되고 TOFU가 다시 확인됩니다. 교환은 절대 건너뛰지 않으며, " "알려진 키에 대한 신원 확인만 단락됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:406 -#: a36303a34b174e6a8c4a421f297e4452 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:451 +#: a501267a3c9848e6aac40eb13359da87 msgid "Replay protection" msgstr "재생 보호" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:408 -#: dd11c43faac347858ff85f846d7af6d1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 +#: cde1f1712c904c89aa5838bc54c715b6 msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." msgstr "" -"핸드셰이크는 무작위 세션 nonce를 교환하고, 유선의 모든 암호화된 라인은 이를 연결당 시퀀스 번호(``||``)와 함께 전달합니다. 수신자는 nonce가 현재 세션과 일치하지 않거나(이전 " -"연결에서 재생된 암호문) 시퀀스 번호가 예상한 것과 다른(세션 내에서 재생된 암호문/순서가 틀린) 줄을 삭제합니다. (재)교환 후 " -"소켓이 암호화 모드로 전환되면 두 카운터가 모두 재설정됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:417 -#: ddfd9d5832b541ba81de53f2f9abd91b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:469 +#: 51478387b6dd4b2e9f7a3d10f72a8b90 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 +#: a47f9db0c3674a12ab6d3ab5d056a8c4 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:483 +#: 6740137a28b84e5dbb3f85e8d58d32b5 msgid "Decode verification and key rotation" msgstr "디코드 검증 및 키 순환" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 -#: 2f8d9ddc0f434f0b98331fc3c14f710b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 +#: 8445bf9265124e38a642f9d46fc43c36 msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -916,24 +1024,30 @@ msgstr "" "참조). 의도적으로 키 쌍을 교체하는 사용자는 새 키를 다시 신뢰하기 위해 피어 측에서 오래된 ``pub_key.json`` " "항목(또는 전체 파일)을 삭제해야 합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:430 -#: 3b373e99ee2c4aff93e808c206dfb3f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:496 +#: 5698fde8f08b4be3a059d92a69ae3459 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures the connection is closed instead of re-" "exchanging, so a garbage-injection or persistent-mismatch storm cannot " -"spin the loop forever. A successful decryption resets the counter." +"spin the loop forever. Genuine peer traffic (messages and commands other " +"than the protocol's own handshake/coordination lines) resets the counter." +" Frames the peer had already sent when this side dropped out of encrypted" +" mode are stale: they cannot be authenticated any more, so they are " +"consumed and dropped — they neither surface as messages nor reset the " +"counter." msgstr "" "재교환은 회로 차단됩니다. ``MAX_DECODE_FAILURES`` (3) 연속 디코드 실패 후 재교환 대신 연결이 닫히므로 " "가비지 주입 또는 지속적인 불일치 폭풍으로 인해 루프가 영원히 회전할 수 없습니다. 암호 해독이 성공하면 카운터가 재설정됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:438 -#: aaefbbdc89554770aebdf60c16950f0f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:508 +#: 6569277ee0b644488685204e70c3e425 msgid "TCP Client command API" msgstr "TCP 클라이언트 명령 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:440 -#: 22612be28f9d4da5b01258de1c7520f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:510 +#: b2ab9f46d6b14c8eaa97512fd117c6db msgid "" "The client supports both built-in commands that the user can type in the " "console, and a command extension API similar to the server. The main " @@ -944,8 +1058,8 @@ msgstr "" "주요 진입점은 'handle_server_command'이며, 사용자가 입력한 명령은 'interactive_mode'에서 " "처리됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:446 -#: 5607f70cfddc4466946bc9082ce494ab +#: ../../source/Network_APIs/TCP_Client_APIs.rst:516 +#: 5e296796f3694cdfbf48c8538979bb7f msgid "" "The client supports two modes of operation: interactive console input " "(when ``is_input_command_in_console`` is ``True``) or programmatic " @@ -954,31 +1068,31 @@ msgstr "" "클라이언트는 대화형 콘솔 입력(``is_input_command_in_console``이 ``True``인 경우) 또는 프로그래밍 " "방식 제어(``False``인 경우)의 두 가지 작동 모드를 지원합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:450 -#: bfa689507e214d7a961f1042698850ce +#: ../../source/Network_APIs/TCP_Client_APIs.rst:520 +#: 0261c3323c4248e3bfb846d5751da36f msgid "Built-in client console commands (user-typed) include:" msgstr "내장 클라이언트 콘솔 명령(사용자 입력)은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:452 -#: 9a2bcb83868f473aae1fa0090af2dd49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:522 +#: d466b066b3654e7183cf72f86523bcd1 msgid "``/quit``: sends a quit message to the server and closes the connection." msgstr "``/quit``: 서버에 종료 메시지를 보내고 연결을 닫습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 -#: 84be485738544bd98d7e0d2f49415cda +#: ../../source/Network_APIs/TCP_Client_APIs.rst:523 +#: 3d22aacfa1914a879be55a3518fb2a7e msgid "" "``/send_msg ``: sends the second token of the line as a chat " "message (``send_message_to_server`` drops the command name and sends only" " the next token)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:456 -#: 6bb0b49ebc5743fe9332f66948330822 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 +#: 16b438ba77f945d2a68bb24f97a69ef5 msgid "``/file ``: starts a file transfer from client to server." msgstr "``/file ``: 클라이언트에서 서버로 파일 전송을 시작합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:457 -#: eb7e88c4607340ba8795bacb617ae98a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:527 +#: 65a2f7cca5684f21ae85deaf2675b2fa #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files from client " @@ -988,15 +1102,15 @@ msgstr "" "``/multiple_file ...``: 클라이언트에서 서버로 여러 파일을 보냅니다(각 파일은 " "세마포어 제한을 고려하여 자체 스레드에 있음)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:460 -#: 98dda85c8e2a4623a9dc2d39643cddbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:530 +#: 0cb1732f55e8499ab36b6923ed56a8ec msgid "" "``/file_folder ``: sends an entire folder from client to " "server, preserving the directory structure." msgstr "``/file_folder ``: 디렉토리 구조를 유지하면서 클라이언트에서 서버로 전체 폴더를 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:462 -#: 1f2e6b52be7f4875aa8434ff22117ee0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:532 +#: f8d95f978af24a0d8056fc369d555f5f msgid "" "``/multiple_file_folder ...``: sends multiple folders" " from client to server." @@ -1004,23 +1118,23 @@ msgstr "" "``/multiple_file_folder ...``: 클라이언트에서 서버로 여러 폴더를 " "보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:464 -#: 48811f3665104578b8921efe71ada53a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:534 +#: c3477f2df53d499db3c6a9b41f8bdedf msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands (client-only; the server refuses " "them)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:468 -#: 3fe8e4c73ecc42e98bde402ff3858c64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:538 +#: d6c13262c84f4ae2a43371ee4e09cfad msgid "" "Ctrl-C and EOF close the connection, send a final ``/quit`` and wait 0.5 " "seconds before the process ends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 -#: c330e7622ffc46a19b41f3e6394c3dc8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 +#: 7971066cb1de4bc2b8047248fa93d58e msgid "" "*Note: Unlike the server, the client does not have built-in ``/help``, " "``/time``, or ``/clients`` commands because those are typically handled " @@ -1031,8 +1145,8 @@ msgstr "" "않습니다. 이러한 명령은 일반적으로 서버에서 처리되기 때문입니다. 클라이언트의 ``/help`` 명령은 구현되지 않았습니다. " "사용자는 사용 가능한 명령에 대해 서버 설명서를 참조해야 합니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:477 -#: f7ea97482c86419cb7e1e5db99cd79c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:547 +#: 44cf1d07758f4fa89eb47d9aad2369a5 msgid "" "A user-typed line that is not built-in and not a registered custom " "command is sent to the server as a chat message, and the client logs " @@ -1040,35 +1154,35 @@ msgid "" "with that wording too)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:482 -#: 677fc4a9eabd4d5ab97bf0e2e73b05ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:552 +#: 7f463379f38f44558c3121e202f9343b msgid "" "*Note: a custom command is matched against the first token of the line, " "so a handler registered for ``/mycmd`` runs when the user types ``/mycmd " "...``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 -#: 1325358de66e4303bb8f9ff817415890 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:555 +#: ae962d51828a4e859fd9080b6eb9ec88 msgid "The command extension API for the client is defined as:" msgstr "클라이언트의 명령 확장 API는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:494 -#: 24f976022e4245e0aa95c2cf112854c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:565 +#: cfa1714f672d4103bae0af84db5a1d63 msgid "" "The arguments of the `register_command` function are the same as on the " "server side:" msgstr "`register_command` 함수의 인수는 서버측과 동일합니다:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:497 -#: 087de666d0cb46b39328508976a7dc92 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:568 +#: 2f936e153d6f4587b918adf94d6ba438 msgid "" "``command_name``: The name of the command to register (should start with " "a slash, e.g., ``/mycmd``)." msgstr "``command_name``: 등록할 명령의 이름(슬래시로 시작해야 함, 예: ``/mycmd``)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:499 -#: 3acea6e2461e40f9b02b90154cb62c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 +#: c19aa473ddf5488cbe8b5039b68e08cf msgid "" "``handler``: The function to call when the command is received. The " "handler must accept three parameters: ``client_socket``, " @@ -1077,8 +1191,8 @@ msgstr "" "``handler``: 명령이 수신될 때 호출할 함수입니다. 핸들러는 ``client_socket``, " "``client_address`` 및 ``command``라는 세 가지 매개변수를 허용해야 합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:501 -#: 60a8ef01850843b48c37e1ce0248d247 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 +#: d327d91dee274ac1951b18ee3700c15a msgid "" "``where_to_run``: Specifies where the command should be executed. Valid " "values are ``\"server\"`` (command sent from the server) or " @@ -1087,23 +1201,31 @@ msgstr "" "``where_to_run``: 명령이 실행되어야 하는 위치를 지정합니다. 유효한 값은 ``\"server\"``(서버에서 전송된 " "명령) 또는 ``\"client\"``(클라이언트 콘솔에 입력된 명령)입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:503 -#: 0a59b9453a5145ffa92a1e91741cfa49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:574 +#: 17b9e2d9c50344bdb8e704423df3c4c8 msgid "" "``run_in_thread``: A boolean indicating whether to run the handler in a " "separate thread from the thread pool." msgstr "``run_in_thread``: 스레드 풀과 별도의 스레드에서 핸들러를 실행할지 여부를 나타내는 부울입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:506 -#: 73925e7106344a879ba8a7e1f4ea6408 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:577 +#: a4fcfb0b0f89415fa269eccf366b2539 msgid "" "It returns ``False`` when ``where_to_run`` is neither ``\"server\"`` nor " "``\"client\"`` (nothing is registered then); on success it returns " "``None``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:509 -#: e9b4b0ddbfd143759ab38205955ff2de +#: ../../source/Network_APIs/TCP_Client_APIs.rst:580 +#: 55e17f10381d4c6e9c13c484a6d7b2f7 +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code, on the client as on the server; the command's first token " +"selects it, exactly as it does for a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 +#: 889fe9598c0045ccaee7de4e93d59f8e #, python-brace-format msgid "" "*Note: The client stores registered commands in the same structure as the" @@ -1114,8 +1236,8 @@ msgstr "" "*참고: 클라이언트는 등록된 명령을 서버와 동일한 구조로 저장합니다: ``self._custom_handlers = [{}, " "{}]``. 여기서 인덱스 0은 서버에서 들어오는 명령이고 인덱스 1은 클라이언트 콘솔에 입력된 명령입니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:514 -#: 87c31576643d4e328b32b14b69b4f818 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:589 +#: 9a244a7eb66d4c0c9666537c17e6f3ac msgid "" "The client also provides the `submit_task` method to submit functions to " "its internal thread pool executor, and `_execute_custom_handler` to " @@ -1124,8 +1246,8 @@ msgstr "" "클라이언트는 또한 내부 스레드 풀 실행기에 함수를 제출하기 위한 `submit_task` 메소드와 오류 처리와 함께 등록된 핸들러를" " 안전하게 실행하기 위한 `_execute_custom_handler` 메소드를 제공합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:519 -#: e64628a99ba249f8acef54a08b182c79 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:594 +#: 4cbf4048c25443dda40d622c49a8e26e #, fuzzy msgid "" "The `submit_task` method works identically to the server version: it " @@ -1137,13 +1259,13 @@ msgstr "" "`submit_task` 메소드는 서버 버전과 동일하게 작동합니다. 이는 동시성을 ``max_custom_workers``로 " "제한하기 위해 세마포어를 사용하여 클라이언트의 스레드 풀에 콜러블을 제출합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 -#: e8f3baf910cb4b2497cb6f6eab9053e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:601 +#: 3a2bd1984dd14769b92c6e40c6ad357c msgid "Temporary server and client creation" msgstr "임시 서버 및 클라이언트 생성" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:528 -#: 26cf9b3fd35d4af993c53f9a8e4bffb6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:603 +#: 0c9b9ad8c6ca4f679f8e54fb58940d3e msgid "" "The client also includes temporary TCP server and client creation APIs. " "They are similar to those in the server class but use `self.client_host` " @@ -1152,8 +1274,8 @@ msgstr "" "클라이언트에는 임시 TCP 서버 및 클라이언트 생성 API도 포함되어 있습니다. 이는 서버 클래스의 것과 유사하지만 " "'self.client_host'를 로컬 바인딩 주소로 사용합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 -#: 6fb3cae805964394bf0864814b4b8ecd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:616 +#: 03e3fc356d234c01a0bd94bad68b8ddc #, fuzzy msgid "" "`create_temporary_server` binds to ``(self.client_host, port)``. If " @@ -1166,8 +1288,8 @@ msgstr "" "``port``가 ``None``이면 ``self.palloc()``을 호출하여 포트를 얻거나(수동 모드에서) ``0``(OS " "할당)을 반환합니다. ``(port, server_thread, stop_event)`` 튜플을 반환합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:558 -#: 8ab44b7d114a4eca8079a87b61ca219f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:633 +#: 61b63d2c156f4512aead02cbbfe0569e #, fuzzy msgid "" "`create_temporary_client` connects to the specified server. If " @@ -1181,8 +1303,8 @@ msgstr "" "``self.palloc()``을 통해 포트를 얻어 자동으로 바인딩됩니다. ``(client_sock, recv_thread, " "stop_event)`` 튜플을 반환합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:564 -#: d5a66d0848e24412a1e121fba226cff8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 +#: a528285ae2714861bf6162938ad1aa0a msgid "" "These methods allow the client to act as a temporary server or to spawn a" " separate client connection for auxiliary tasks (such as file transfers)," @@ -1191,13 +1313,13 @@ msgstr "" "이러한 방법을 사용하면 클라이언트가 임시 서버로 작동하거나 기본 연결을 방해하지 않고 보조 작업(예: 파일 전송)을 위한 별도의 " "클라이언트 연결을 생성할 수 있습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 -#: 16bd0374c6194f4b9bd2db749597217f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:645 +#: 46a7a0338f5040f38903a61af8ff8ae5 msgid "TCP Client console commands (interactive mode)" msgstr "TCP 클라이언트 콘솔 명령(대화형 모드)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 -#: dbe05db8944f49818decf56adb4855b6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:647 +#: 8a93646c1be14bb8bfcb5be5140f1572 msgid "" "When the client is started with ``is_input_command_in_console=True`` (the" " default), the `interactive_mode` method is invoked. This method reads " @@ -1206,30 +1328,30 @@ msgstr "" "클라이언트가 ``is_input_command_in_console=True``(기본값)로 시작되면 `interactive_mode`" " 메서드가 호출됩니다. 이 방법은 표준 입력에서 행을 읽고 처리합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:576 -#: eea6d19cd2f44de6ae2bd67081f49b5a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:651 +#: 5370ea52c70741728cc72ae1618e65e8 msgid "Supported console commands (user-typed) include:" msgstr "지원되는 콘솔 명령(사용자 입력)은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:578 -#: 3d1b84c153974f14bdd57c17a892a158 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 +#: 3ee645c39b844b1e8b14a1eb54bef876 msgid "``/quit``: closes the connection and exits the client." msgstr "``/quit``: 연결을 닫고 클라이언트를 종료합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:579 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:654 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/send_msg ``: sends the second token of the line to the " "server as a chat message." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:581 -#: 50b34e795f4a4d1595f8a2f6c1ebfad5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:656 +#: c34b32925f024797841232729eca131e msgid "``/file ``: sends a single file to the server." msgstr "``/file ``: 단일 파일을 서버로 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:582 -#: d90b52a3886c48c1b86fe1d4a08adb11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:657 +#: 739e72b7a06a4eefa6cdd1a952d3d781 #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files to the " @@ -1238,36 +1360,36 @@ msgstr "" "``/multiple_file ...``: 여러 파일을 서버에 동시에 " "보냅니다(``max_thread_num``으로 제한됨)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:583 -#: 66d2f7d1d87847e39e4172ae789b6a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:658 +#: d9421edab02e4b33850db50a0011ad16 msgid "" "``/file_folder ``: sends an entire folder to the server, " "recursively." msgstr "``/file_folder ``: 전체 폴더를 서버에 재귀적으로 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 -#: 321bde30af944560b349b5dd6a162a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:659 +#: efd08f6cefcd4f44bcd4ff0687cee8bc msgid "" "``/multiple_file_folder ...``: sends multiple folders" " to the server." msgstr "``/multiple_file_folder ...``: 여러 폴더를 서버로 보냅니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:585 -#: 9feff7033be8445599773701f51926df +#: ../../source/Network_APIs/TCP_Client_APIs.rst:660 +#: ed70094fabb34d46afadb56fd5c7c37d msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:587 -#: 6489b5a0fb2948748f0f1bd5f303c779 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:662 +#: 1dc2bd43fd56402785fb76b3895b03b2 msgid "" "Any other non-empty line is sent as-is to the server — the same path chat" " text takes." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:591 -#: 3295a0d774d0473da7c5d7405d72abd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:666 +#: d72b6516a43b4f26bb5750604f41ff74 msgid "" "The client does not have a built-in ``/help`` command. Please refer to " "the server's help for available commands (e.g., by typing ``/help`` after" @@ -1276,8 +1398,8 @@ msgstr "" "클라이언트에는 내장된 ``/help`` 명령이 없습니다. 사용 가능한 명령은 서버의 도움말을 참조하세요(예: 서버에 연결한 후 " "``/help`` 입력)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:595 -#: dd63bf8cfd3641c0be9adad9b06aa8e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:670 +#: e6081a66251a4a57bc5724dccb8c852b msgid "" "A line registered with ``register_command(..., where_to_run=\"client\")``" " runs when its first token matches a registered name; handlers registered" @@ -1285,26 +1407,26 @@ msgid "" "server sends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:600 -#: 7efd09ba06ba4067b03810eb838caa24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:675 +#: 4befe76529e04e859f9422d8ebe3921a msgid "" "*Note: The client logs ``Unknown server command: `` for any line it" " did not recognise, including plain chat text, because those lines take " "the same fallback path.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:604 -#: 8cd9357ee0494a20b9ba9d4b8ed3514b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:679 +#: 2cbc548821b84721b1aea4f88573f02f msgid "Example interactive session::" msgstr "대화형 세션 예시::" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:617 -#: 45b4cc10dbab4342a2653adafcad5e63 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:692 +#: bd36c89659694280b349cc621b598254 msgid "TCP Client file transfer API" msgstr "TCP 클라이언트 파일 전송 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:619 -#: 2476ecf352184c39a27da75545ff67b9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 +#: 0f20edbf8203493aa579cb5a1195712b msgid "" "The TCP client contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers, using the same " @@ -1313,58 +1435,61 @@ msgstr "" "TCP 클라이언트에는 서버와 동일한 기본 프로토콜을 사용하여 클라이언트-서버 및 서버-클라이언트 전송을 모두 지원하는 파일 전송 " "하위 시스템이 포함되어 있습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:623 -#: 37c359049bd04adcbcde988494c16efa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:698 +#: 02806a329fba478293ef172f63bfb93d msgid "" "As with the server documentation, only the list of APIs is provided here." " For detailed internal flow, please refer to the server documentation or " "the source code." msgstr "서버 설명서와 마찬가지로 여기에는 API 목록만 제공됩니다. 자세한 내부 흐름은 서버 문서나 소스코드를 참고하세요." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:627 -#: a0aef36e6c984775b79dc1c35e39cd61 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 +#: 2a7f8a3995cf4e2b81a3bf5c3c85b0fa msgid "The file transfer API for the client includes:" msgstr "클라이언트용 파일 전송 API에는 다음이 포함됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:629 -#: e340f1fe00774c58bc70b398a745589d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:704 +#: dc5da9cf7ac441c8842cc97d904582ba msgid "The basic function for client-to-server file transfer is:" msgstr "클라이언트-서버 파일 전송의 기본 기능은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 -#: 3cfc45f71fac4d49b0c188b84068d5b7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:714 +#: db4145949f7a42aab5ff42bf72d6ff2e msgid "" "The non-``_thread`` versions take the destination folder as a required " "argument (the ``_thread`` wrappers default it to ``None``, which means " "the default transfer folder)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:643 -#: 6058cc068109448faaad1e4936bb7863 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:718 +#: 743dd6f0cdba49678277c1d19c178f20 msgid "" "For server-initiated transfers (server-to-client), the client provides " "these handlers:" msgstr "서버에서 시작된 전송(서버에서 클라이언트로)의 경우 클라이언트는 다음 핸들러를 제공합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 -#: 1e596cb7ccd942aeb30e335c53e1afa1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:728 +#: 72f8a6d975094c7984fbef810a422975 msgid "The low-level receive mode function is:" msgstr "낮은 수준의 수신 모드 기능은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:661 -#: 885c49e37dd94f2bb3aca9d95dc72222 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:736 +#: b04d81d08ea941b3b6beea16e4a05bc0 msgid "And the low-level send mode function is:" msgstr "낮은 수준의 전송 모드 기능은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:668 -#: 17759b30b9ae4c68b00432ae33741a99 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:744 +#: 724cadb0ca764d9aaafd664c63b858d6 msgid "" -"``pause_fid`` is the forwarding id used to pause/resume the transfer with" -" ``/pause_trans`` / ``/start_trans``." +"``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) " +"addresses; ``peer`` is the transfer's original receiver and " +"``resume_offset`` continues an interrupted file from the byte the " +"receiver already holds." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:671 -#: 4dc07ef115aa4712807fede2f2040e12 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 +#: f5823da74e1a4879a65624511d10e0cb msgid "" "We recommend that for client-to-server file transfers, you use the " "console commands (``/file``, ``/file_folder``, etc.) rather than calling " @@ -1379,8 +1504,8 @@ msgstr "" " `_thread` 버전(예: `file_transfer_client_recv_client_start_thread`)을 사용하여 " "메인 스레드를 차단하지 마세요." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:680 -#: 1165a3c7f2bc470da7c706aead0fc73f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 +#: 2d0ea3d6726e43a3b3b551bf23c5ce00 msgid "" "*Note: The file transfer API functions follow the same handshake protocol" " as the server: the initiator sends a command over the main connection, " @@ -1390,13 +1515,13 @@ msgstr "" "*참고: 파일 전송 API 기능은 서버와 동일한 핸드셰이크 프로토콜을 따릅니다. 즉, 개시자가 기본 연결을 통해 명령을 보낸 다음 " "임시 포트가 협상되고 실제 파일 데이터가 별도의 TCP 연결을 통해 전송됩니다.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:687 -#: 95c14f0f60154aa3b15d0dd0dfe41a69 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 +#: 997f666f071d44499a4be946c3a808e5 msgid "Port allocation API" msgstr "포트 할당 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:689 -#: 9e3832473379404391011a22af4fb605 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 +#: 937556f090f74e86ab56041fbda5c543 msgid "" "The client port allocation APIs are nearly identical to those of the " "server. They allow you to allocate ephemeral ports either automatically " @@ -1406,8 +1531,8 @@ msgstr "" "클라이언트 포트 할당 API는 서버의 API와 거의 동일합니다. 이를 통해 자동으로(0을 반환하고 OS가 선택하도록 함) 구성된 " "범위 내에서 수동으로 임시 포트를 할당할 수 있습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 -#: 93aa2cdf7f3c49fb8ad14ad1b78415e4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 +#: a37e79b6f8e34e3ab589f9127a2fbaf2 msgid "" "To configure the port allocation mode, the client reads the " "``/client_alloc_port_range`` line the server sends it right after the " @@ -1417,8 +1542,8 @@ msgid "" "allocation (return 0 from allocation calls)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 -#: 3d693309e5ae4fbaa587212cf81bc16f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 +#: a29288d0ba7d46409b9fbc7e4b3ff7b0 msgid "" "In manual allocation mode, the port range is determined by the server's " "broadcast value. The client maintains its own range based on " @@ -1432,13 +1557,13 @@ msgstr "" "*each_client_port_range``이며, 최대값은 ``self.port + 1 + self.port_add_step " "*each_client_port_range``입니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:710 -#: ab3bb204b8f5402093e6d329cd98cd64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 +#: baf74c2478324ced80df912ff96e7baa msgid "The main methods for port allocation are:" msgstr "포트 할당의 주요 방법은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:717 -#: 93b31be2d4bf4e5ca9f8b4ab9b095a45 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 +#: c4170cd3e6844792b110dfba945f0298 msgid "" "`palloc` returns an available port (either 0 for automatic mode, or a " "concrete port number from the manual range). It internally calls " @@ -1448,8 +1573,8 @@ msgstr "" "`palloc`은 사용 가능한 포트를 반환합니다(자동 모드의 경우 0 또는 수동 범위의 구체적인 포트 번호). 내부적으로 루프에서 " "'file_palloc'(추가 할당) 및 'spy_palloc'(뺄셈 할당)을 호출합니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:729 -#: d54f0b635e194239932cf1bb5cace701 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:807 +#: 1c21e96227684b8998d8a6c6c595caf0 msgid "" "`pfree` releases a previously allocated port. In manual mode, it removes " "the port from the internal list and adjusts the latest port pointers. In " @@ -1458,8 +1583,8 @@ msgstr "" "`pfree`는 이전에 할당된 포트를 해제합니다. 수동 모드에서는 내부 목록에서 포트를 제거하고 최신 포트 포인터를 조정합니다. " "자동 모드에서는 아무 작업도 수행하지 않습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:734 -#: 60b2327bda49480fac483fb4ca52eb5d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:812 +#: e270023d96364a59a4436f846b296202 msgid "" "As with the server, the automatic mode (returning 0) is recommended for " "most use cases because it avoids port conflicts and simplifies code. " @@ -1469,251 +1594,276 @@ msgstr "" "서버와 마찬가지로 자동 모드(0 반환)는 포트 충돌을 방지하고 코드를 단순화하므로 대부분의 사용 사례에 권장됩니다. 포트 범위를 " "엄격하게 제어해야 하는 환경(예: 방화벽 또는 테스트)에는 수동 모드가 제공됩니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:741 -#: bade6122477d4a959b6f9a942b150ea0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:819 +#: 31a306a34d04473c85f2c36abe5747e7 msgid "TCP Client APIs table" msgstr "TCP 클라이언트 API 테이블" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:743 -#: be55c1d2020c4088ac45dcd1f2c6add4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:821 +#: e38b3c22a1e041be93c1b9133368dacb msgid "In short, the table of contents of the public APIs is as follows:" msgstr "간단히 말해서 공개 API의 목차는 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:746 -#: 8bb46aea2dff4e57853087e452fdca3f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:824 +#: 5c9291fc111d4f87a26c3b323d69bf27 msgid "The client setup APIs:" msgstr "클라이언트 설정 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:747 -#: 6c95cdbfa4634d9f9561908b316ab03e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:825 +#: dc26d3c73e994b2a89d83b6dc2b0ff20 msgid "`TCP_Client_Base`" msgstr "`TCP_클라이언트_베이스`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:748 -#: a5ab88edb0dd42dd81166dc614c4c353 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:826 +#: caab3a11f54d4540890a84cada3cecd3 msgid "`start_TCP_client`" msgstr "`시작_TCP_클라이언트`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 -#: 11f6500a3ac64b41ba44c22ef2069007 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:827 +#: c38e962856a84b6eaf6f0759e9a48ec4 msgid "`connect`" msgstr "'연결하다'" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:750 -#: 0263dd292461441192546c1f9237adaf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:828 +#: 411023a9191243338f22e59a33cb72c2 msgid "`close`" msgstr "'닫다'" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:752 -#: 11848e9f043f4952afaad4305b07486d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:830 +#: 982308344bc1464c982613021965e40f msgid "The client handling information APIs:" msgstr "클라이언트 처리 정보 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:753 -#: 6c2bd74a71a64468b3247862791409e1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:831 +#: 611645ffa9bb4259923b685f7389fab4 msgid "`receive_messages`" msgstr "`receive_messages`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:754 -#: a15228535750492caa9b3ebfba4d9901 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:832 +#: b5a951b6b0694dd7992bcb3d054bd2b3 msgid "`handle_server_command`" msgstr "`handle_server_command`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:755 -#: 47cb15f07d394f78a15345f254e42b0b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:833 +#: 334fb0ff014d4f418ac474db4c68d247 msgid "`receive_message`" msgstr "`receive_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:756 -#: f0074be846de4eef8d98f07a3fd153a7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:834 +#: df7b9a0f6c034b8ab9b1fb20b3bf879a msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:757 -#: ca1943c93c2048d9805e6c3494744d90 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:835 +#: ffb875c0ebd844368deedf382811f851 msgid "`interactive_mode`" msgstr "`대화형_모드`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:836 +#: 5630f1fb130842aba877cdb0c29e4ff1 #, fuzzy msgid "`send_message_to_server`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:760 -#: 1059c94b173f48aa9304663c6d74a805 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:838 +#: 494c8644a7254a7b81e9886d840813e8 msgid "2.1. The inbound event listener APIs:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:761 -#: 54202f3279bb4bb19457be283d4f5d75 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:839 +#: 6f15aa9d9fe142088b15a802e28823f5 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:762 -#: 88625c35b2ec49889b14309d8373c1ef +#: ../../source/Network_APIs/TCP_Client_APIs.rst:840 +#: d240527b31854c3eb36c83b57b838e5d msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:763 -#: eca517026718488aa026202ff440ce41 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:841 +#: fb735c656faa4a28983b3c90a8f9f452 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 -#: a5c242c6e4084aef98fa59f17778731d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:843 +#: 7299f59deb95485b9ce5f240b3318d86 msgid "" "The client encrypted channel APIs (see :ref:`tcp-client-encrypted-" "channel-api`):" msgstr "클라이언트 암호화 채널 API(:ref:`tcp-client-encrypted-channel-api` 참조):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:766 -#: c5006b19599d4a45bc86d5cfac770d94 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:844 +#: 51757de232d548c3b7c230b7e6456906 msgid "`_crypto_exchange_thread`" msgstr "`_crypto_exchange_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 -#: 3d8e73d09493460c845a98dabf5ad9f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:845 +#: ad3834da9c474029952e0043a46c2ed6 msgid "`_crypto_after_ack`" msgstr "`_crypto_after_ack`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:768 -#: 75bbad7153834bad9492a242fa26b789 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:846 +#: 0ca576944d8a497abeb39cdf5c4ccdb7 msgid "`_crypto_push_pub_key`" msgstr "`_crypto_push_pub_key`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:769 -#: 59aff25473e942eb9b11f6aa4c1ff235 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:847 +#: 11b6eacdaa484d689499dad3be56bd79 msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:771 -#: aeba48f8f86e45f199838191146c7f4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:849 +#: b71d430231c24a6995ba0b267f09f4bf msgid "The client command APIs:" msgstr "클라이언트 명령 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 -#: 0a25d8003bd64c63ad151aedf3fb15ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:850 +#: efb7ccdbabfd477d83af89aed1eb4c5d msgid "`register_command`" msgstr "`등록_명령`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:773 -#: c9e2f51101b942ef8e722216e59ed972 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:851 +#: 72f8a6d975094c7984fbef810a422975 +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:852 +#: d549ceac7407457f81c403d7be88aa99 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:774 -#: 92211b1c671c48ce8e0d14c9d12b71f1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:853 +#: c6fe8883469e47b88e0a4bb3be30c1a6 msgid "`submit_task`" msgstr "`제출_작업`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:775 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:854 +#: 5630f1fb130842aba877cdb0c29e4ff1 msgid "`create_temporary_server`" msgstr "`생성_임시_서버`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:776 -#: e23b2af57072452ab0fab0c5652bde72 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:855 +#: 9cf956cb593f4c758da50d45c684466b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:778 -#: 91270c73be944993a8751739a6ef133e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:857 +#: 55aa7c66f7a24443a58e108948608136 msgid "The client file transfer APIs:" msgstr "클라이언트 파일 전송 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:779 -#: 358e4cb2a7174129b65dc582f3b977f7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:858 +#: d79011e4d398480cbdb00e021f1461fe msgid "`file_transfer_client_recv_client_start`" msgstr "`file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 -#: f4971cf5af03413e9b0011378a57d487 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:859 +#: 300f91c72ed8400d85821a3e2a0ab1ec msgid "`file_transfer_client_recv_client_start_thread`" msgstr "`file_transfer_client_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:781 -#: 077b6550f3b8496fb4d8d8592eac5ca6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:860 +#: 1f3a30d9bf5d44baa9459a21df8f70d4 msgid "`folder_file_transfer_client_recv_client_start`" msgstr "`folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:782 -#: 194dd830cddc49acaad93077b41fb646 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:861 +#: 5619c7c126b14852ace1e5ed9a428e0a msgid "`multiple_file_transfer_client_recv_client_start`" msgstr "`multiple_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:783 -#: e6ea79e90d794733b2bb84b5799ab3ec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:862 +#: e1e3f53d8275406f9f2f31a406617843 msgid "`multiple_folder_file_transfer_client_recv_client_start`" msgstr "`multiple_folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:784 -#: ce228984911540d29bef2d0b7e73eabc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:863 +#: 0f3b14e3c193426191323ee76959278e msgid "`file_transfer_client_recv_server_start`" msgstr "`file_transfer_client_recv_server_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:785 -#: 7ff0717c8e504c869e36a3d9fd829652 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:864 +#: 4612a53ee9154895a8758a6cc45c0b76 msgid "`file_transfer_client_recv_server_start_thread`" msgstr "`file_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:786 -#: db7e615cfbd347359a6a683642049c31 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:865 +#: 5dff8ca27b7b40e6941b8190a136173c msgid "`file_folder_transfer_client_recv_server_start_thread`" msgstr "`file_folder_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:787 -#: 16a578b31e344b5d82b9935e56aafa02 -msgid "`file_transfer_mode_recv`" -msgstr "`파일_전송_모드_recv`" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 -#: 7659e4e26bef45e89e4659a045cd77cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:866 +#: c66340b3ef204af29e58170db0efc057 msgid "`file_transfer_mode`" msgstr "`파일_전송_모드`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:790 -#: 6a81df270092467db215985a9b0ea90e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:868 +#: 87af784aa34949379dc6a73c148a402d +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:869 +#: 9aa5be3d37804a5c8286d23160add073 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:870 +#: 4612a53ee9154895a8758a6cc45c0b76 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:871 +#: e340c2c825324df7b3aee14da0f9d919 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:872 +#: 0f3b14e3c193426191323ee76959278e +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:874 +#: 5bf1072901734d3d8d0b119e5f50627c msgid "The client console commands (interactive mode):" msgstr "클라이언트 콘솔 명령(대화형 모드):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:791 -#: c2174ab210464a2e82c298e0f70fee20 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:875 +#: cb2350fc1fd047f39fb9841ce78dd4ed msgid "`/quit`" msgstr "`/그만`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:792 -#: ffa9f9ef47ae46629a6fc29d29d9ab44 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:876 +#: 70b54395545d4421bd90e40acd8b28d5 msgid "`/file`" msgstr "`/파일`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:793 -#: 86990039800e4a999b76a431d6a6dd8a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:877 +#: bd2dec3b0774465d87ed9f3f853f30db msgid "`/multiple_file`" msgstr "`/다중_파일`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:794 -#: 6f26c82663494206964a6bb68ddcfe6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:878 +#: efe4930f9bd34df19b1ee98085605346 msgid "`/file_folder`" msgstr "`/파일_폴더`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 -#: 63d6611c586c46d3a9053712a112162d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:879 +#: acb8ceac4b5540aca3230cff6bfefa86 msgid "`/multiple_file_folder`" msgstr "`/다중_파일_폴더`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:798 -#: 7bb84bbf4494463d9e477ddce9f0fec2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:882 +#: 9db1c5c6b375448e80c2af32c0464023 msgid "See Also" msgstr "참조" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:800 -#: 5cc4da34c3dc479eb9af04123c8502f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:884 +#: 0c84c6f4e6e9450aa96935335c505122 msgid ":doc:`TCP_Server_APIs` — TCP server." msgstr ":doc:`TCP_Server_APIs` — TCP 서버." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:801 -#: 134b0d0b135c4e68a08b0d14959d6307 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:885 +#: efc25fa97296452199853b1bb3cc3f21 msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 끝점." @@ -1883,3 +2033,63 @@ msgstr ":doc:`UDP_APIs` — UDP 끝점." #~ msgid "The multiple folders transfer function is:" #~ msgstr "다중 폴더 전송 기능은 다음과 같습니다." +#~ msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" +#~ msgstr "``client_port``: 기본값은 ``None``입니다(OS가 임시 포트를 할당함)." + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(sender_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to " +#~ "`handle_server_command` instead). ``sender_id`` is" +#~ " the author's ``\"ip:port\"`` — for a" +#~ " message another client forwarded here " +#~ "through the ``/send_msg_from`` envelope it " +#~ "is the forwarding client, and it " +#~ "is ``None`` for a direct push from" +#~ " the server. ``add_file_listener`` registers " +#~ "``listener(client_id, full_path, name, size, " +#~ "command)`` and fires after a file " +#~ "sent by the server has been fully" +#~ " written to disk. Both listeners run" +#~ " on a protocol thread, so they " +#~ "must not block, and an exception " +#~ "inside a listener is logged and " +#~ "swallowed. The ``remove_*`` counterparts " +#~ "unregister a listener and ignore unknown" +#~ " ones." +#~ msgstr "" + +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "핸드셰이크는 무작위 세션 nonce를 교환하고, 유선의 모든" +#~ " 암호화된 라인은 이를 연결당 시퀀스 번호(``||``)와 함께 전달합니다. 수신자는 " +#~ "nonce가 현재 세션과 일치하지 않거나(이전 연결에서 재생된" +#~ " 암호문) 시퀀스 번호가 예상한 것과 다른(세션 내에서" +#~ " 재생된 암호문/순서가 틀린) 줄을 삭제합니다. (재)교환 " +#~ "후 소켓이 암호화 모드로 전환되면 두 카운터가 모두" +#~ " 재설정됩니다." + +#~ msgid "" +#~ "``pause_fid`` is the forwarding id used" +#~ " to pause/resume the transfer with " +#~ "``/pause_trans`` / ``/start_trans``." +#~ msgstr "" + +#~ msgid "`file_transfer_mode_recv`" +#~ msgstr "`파일_전송_모드_recv`" + diff --git a/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po b/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po index 8d29673..9c9323b 100644 --- a/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po +++ b/docs/source/locale/ko/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -20,17 +20,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Server_APIs.rst:2 -#: 6233736da6d8410985a7db552ebb0405 +#: c4332266e3f842cc912424ee842fcfe0 msgid "The TCP Server APIs" msgstr "TCP 서버 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:5 -#: 6e1c64d13b9e4deebc7c276d00bfca94 +#: 769ff5b424d54086a70b199663089327 msgid "TCP Server setup API" msgstr "TCP 서버 설정 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:7 -#: 05209d5966c24f19bcf70e93d016fe24 +#: 2d81aa6d8ba84a868113fd9e08fc5c60 msgid "" "The TCP Server Setup API is used to create a TCP server. The server in " "the protocol is usually used to connect and listen to the TCP clients and" @@ -39,8 +39,8 @@ msgstr "" "TCP 서버 설정 API는 TCP 서버를 생성하는 데 사용됩니다. 프로토콜의 서버는 일반적으로 TCP 클라이언트에 연결하고 수신하며" " 클라이언트의 데이터를 처리하는 데 사용됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:35 -#: c6d17d88ca43468cab262d7b50bb7d43 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 +#: ddc5d0f6bc1b4162af2bb49f6b25a031 msgid "" "The TCP Server Setup API is defined in the ``TCP_Server_Base`` class. The" " parameters of the ``__init__`` method are as follows:" @@ -48,62 +48,62 @@ msgstr "" "TCP 서버 설정 API는 ``TCP_Server_Base`` 클래스에 정의되어 있습니다. ``__init__`` 메소드의 " "매개변수는 다음과 같습니다:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:38 -#: 7c3b5b3185bb436bbaabf0aaea5f11fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 +#: f1ffcdd5c8e74b9cbdb5e5fc8eeb34ce msgid "``host``: The host IP address to bind the TCP server to." msgstr "``host``: TCP 서버를 바인딩할 호스트 IP 주소입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 -#: 8dbeeea956834b28a5d13a47b9eaf651 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 +#: 7e419c2e704a44228bd0bdeed976d861 msgid "``port``: The port number to bind the TCP server to." msgstr "``port``: TCP 서버를 바인딩할 포트 번호입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:40 -#: 3710af3c13574f088cd84d34ae8c83ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 +#: 854e298d71f140069b6ed51806224ca5 #, fuzzy msgid "" "``max_clients``: The maximum number of concurrent clients the server can " "handle (ignored when ``is_asynic_clients_io`` is ``True``)." msgstr "``max_clients``: 서버가 처리할 수 있는 최대 동시 클라이언트 수입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 -#: c92cda0f3bdb4f839ab24c2c65c926db +#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 +#: 203462f6b127478cb9bb0c2093362827 msgid "``port_add_step``: The step size for incrementing the port number." msgstr "``port_add_step``: 포트 번호를 증가시키는 단계 크기입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 -#: 43155638bb1344798a37f85065d411ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 +#: 3d0355b5c1924055a7d8b6acb907fad0 msgid "``port_range_num``: The number of ports to check in the range." msgstr "``port_range_num``: 범위에서 확인할 포트 수입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 -#: 0459f804445d47519971903bce3e36eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 +#: a7852ea136454a1298541e96cdece1bc msgid "" "``max_file_transfer_thread_num``: The maximum number of threads for file " "transfer operations." msgstr "``max_file_transfer_thread_num``: 파일 전송 작업을 위한 최대 스레드 수입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:45 -#: 3103e7d29cb647f9922e0b507d47a171 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:49 +#: 0f1b0f03ffe2472cb58725dc446f6f7c msgid "" "``is_hand_alloc_port``: A flag indicating whether to manually allocate " "the port." msgstr "``is_hand_alloc_port``: 포트를 수동으로 할당할지 여부를 나타내는 플래그입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 -#: ee86acb3489f408ca9ba116a66c5ea3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:50 +#: 969ca405744f4d57a8e70db30eada3f7 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console." msgstr "``is_input_command_in_console``: 콘솔에 명령을 입력할지 여부를 나타내는 플래그입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 -#: d593644fa1664037b99afd05ecbf9cf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:51 +#: 6b01091b3f124b8d87c9423eb6998be4 msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``: 사용자 정의 작업자 스레드의 최대 수입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 -#: b46e9e9d9066432bbe75dc461b0f951f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 +#: c9d16d29465a48779ee2a54e4b9cc66e msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the server itself by calling " @@ -111,8 +111,8 @@ msgid "" "register its commands first and start the server later." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 -#: 60e4bd55be9940a48d6ae6421561fdaf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:56 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with clients are RSA-encrypted (see :ref:`tcp-server-encrypted-channel-" @@ -121,8 +121,8 @@ msgstr "" "``is_enable_encrypto``: 클라이언트와 주고받는 메시지가 RSA 암호화되었는지 여부를 나타내는 플래그입니다(:ref" ":`tcp-server-encrypted-channel-api` 참조)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:54 -#: c6dcdd076b864336834f8490c0a25708 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 +#: 3558d7e8c52442818701d4eb794b3643 msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -133,16 +133,30 @@ msgstr "" "쌍입니다. 두 파일이 모두 존재하고 PEM으로 구문 분석되고 서로 쌍을 이루어야 합니다. 유효하지 않은 쌍은 자동으로 무시되고 기본" " 키 조회가 대신 사용됩니다(``None``은 기본 조회를 유지합니다)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 -#: d0e99e1bc78f40f7af7470a66315bb04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:62 +#: 86265e57f3aa48e58e3fb5d9de0a9277 msgid "" "``max_mem_buff``: The in-memory buffering ceiling of the forward pump, " "given in MiB and stored as bytes (``self.max_mem_buff``); past it the " "uploading peer is told to pause. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:61 -#: 970d44aa127b40c7854cfc4dee215dcf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 +#: 7d4dd6bf4eff4f4db8ce0187088f172c +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:67 +#: 8fb93ff5bf2f49b18f2f42c92e66123f +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:69 +#: f12bacde2a874840879a51af63eeefde msgid "" "``is_asynic_clients_io``: A flag indicating whether clients are served by" " asyncio coroutines on one event loop instead of one thread per client. " @@ -150,73 +164,101 @@ msgid "" " of concurrent connections." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 -#: 269ce1f748d942949c0c20017fdf4a9b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 +#: 3a36a9bba6004a41b358be9975788707 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the server logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:68 -#: 09d8448517374602938d9ca4872e0356 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_print_log``: A flag indicating whether the server logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:71 -#: dc30e9a1ba5044319a3ed5ad1842b348 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 +#: 2994b78415964ff0adc713a4daed1b6b +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when a " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 +#: 9f9de22b50a94553ac1113f290dff1b4 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 +#: 8b0a1bb7ed944884854a936968f3b4bd msgid "All parameters have default values:" msgstr "모든 매개변수에는 모두 기본값이 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 -#: 5774cd0576f349d18492b59a0b6d68bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:100 +#: 89299feb872b49758f7c9bf680114bbc msgid "``host``: Default is ``'127.0.0.1'``" msgstr "``호스트``: 기본값은 ``'127.0.0.1'``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:74 -#: 4437fda8aa004d7483cefd29ad594bca +#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 +#: 38b84b10fc4d492497c3e0b20cb9fe8c msgid "``port``: Default is ``65432``" msgstr "``포트``: 기본값은 ``65432``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:75 -#: 559c3b634b1043f2a6541f45eba488d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:102 +#: 3ccf25b3de4749a7ad73a1001fea86fb msgid "``max_clients``: Default is ``10``" msgstr "``max_clients``: 기본값은 ``10``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 -#: 8988cc48e66a472ebe8d505bdf8d6db9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:103 +#: 63455575485f4a25b4d2d2b83803e6b8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: 기본값은 ``1``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:77 -#: 063ec78e76b3439aafe539fad81a6036 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:104 +#: d8759c586e7143838c1ffe24c9fd6f62 msgid "``port_range_num``: Default is ``100``" msgstr "``port_range_num``: 기본값은 ``100``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:78 -#: 4a3115c33bd349fba0768f79f18c47c0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:105 +#: a8020929e0f14b5394b6dd502b7a7b67 msgid "``max_file_transfer_thread_num``: Default is ``10``" msgstr "``max_file_transfer_thread_num``: 기본값은 ``10``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 -#: fe7bf4015de045dcadc0024aef2bbdac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:106 +#: a9307e89f7cd471d96794bf7fbc9313c msgid "``is_hand_alloc_port``: Default is ``False``" msgstr "``is_hand_alloc_port``: 기본값은 ``False``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:80 -#: 2529e795d9b0401d930f3c09766c56d5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:107 +#: 76084a80a458455bb952e8acad677eba msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: 기본값은 ``True``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:81 -#: a95bee48d609469398e5a878b3d1e810 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:108 +#: f32a6549330a43f482e01def905e7415 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: 기본값은 ``10``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:82 -#: c825fae2eaaa4afeaa551e65e4ea1ff1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:109 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_Server()`` automatically)" @@ -224,8 +266,8 @@ msgstr "" "``is_extend_command``: 기본값은 ``False``입니다(``True``인 경우 ``__init__``는 " "``start_TCP_Server()``를 자동으로 호출하지 않습니다)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:84 -#: 0ab49ef330a94ecb80e160bbe0f00fe9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:111 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, client " "connections go through an RSA public-key exchange and all subsequent " @@ -234,8 +276,8 @@ msgstr "" "``is_enable_encrypto``: 기본값은 ``True``입니다(``True``인 경우 클라이언트 연결은 RSA 공개 키 " "교환을 거치고 모든 후속 메시지가 암호화됩니다)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:87 -#: 6087b88026574d56aa37a817f0fe790a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:114 +#: c259e80f53a14b79a94190bcded7b30d msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -244,37 +286,63 @@ msgstr "" "``is_custom_keys``: 기본값은 ``None``입니다(``[pub_key_path, pvt_key_path]`` 목록은" " 기본 ``~/.ssh`` / 생성된 키 대신 사용자가 제공한 키 쌍을 사용합니다)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 -#: 26758c8f847b47c9839124e86e042349 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:117 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_clients``: 기본값은 ``10``입니다." + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:118 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "``max_file_transfer_thread_num``: 기본값은 ``10``입니다." + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_asynic_clients_io``: Default is ``False`` (when ``True``, every " "accepted connection is served by a coroutine on one asyncio event loop, " "and ``max_clients`` is ignored)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:93 -#: 79dca8f502bb4401952542fb3dba6939 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:122 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:95 -#: 656b6904625a4ea0977c85a93e62fd84 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:124 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "server would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 -#: a3fd35f818f84d7399b7d41208ff9319 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:126 +#: abd7d3032e15468e92f96a0b5af1f926 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:128 +#: 9b2bfa874c4e4969905923bd7aa0f80c +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 +#: ff0d716f8c6344408337c57ab32bad28 msgid "" "The TCP Server Setup API will initialize all the necessary parameters and" " resources for the TCP server." msgstr "TCP 서버 설정 API는 TCP 서버에 필요한 모든 매개변수와 리소스를 초기화합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 -#: c38ba680fb704c4b9af31bcd33224c02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:134 +#: 06c57226c0e9415ab1618ae20a14f513 msgid "" "*Note: By default ``TCP_Server_Base.__init__`` calls " "``start_TCP_Server()`` to start the server automatically. If you set " @@ -285,8 +353,8 @@ msgstr "" " 자동으로 시작합니다. ``is_extend_command=True``를 설정하면 인스턴스가 자동으로 시작되지 않으며 준비가 되면 " "수동으로 ``start_TCP_Server()``를 호출해야 합니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:112 -#: a0900d8246aa4cda80638035485659e5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:145 +#: e473a54dc4534e29ac4361429d24cb63 msgid "" "In the `start_TCP_Server` method, we first create a TCP server socket and" " bind it to the ``self.host`` and ``self.port`` which are initialized in " @@ -295,15 +363,15 @@ msgstr "" "`start_TCP_Server` 메소드에서는 먼저 TCP 서버 소켓을 생성하고 이를 ``__init__`` 메소드에서 초기화되는 " "``self.host`` 및 ``self.port``에 바인딩합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:116 -#: 4b6e513817d44c1d93cf1c39866ecf18 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:149 +#: 68dff731e96c46788af52f9c536a6d2f msgid "" "*Note: The server socket which is set up in the `start_TCP_Server` method" " is based on IPv4 form.*" msgstr "*참고: `start_TCP_Server` 메소드에 설정되는 서버 소켓은 IPv4 형식을 기반으로 합니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 -#: b8a255c83b3346199c3197dd596427b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:152 +#: 1c6fc605850b4e988e7f5dac390f905e msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will start a thread to listen to the console input of the " @@ -312,13 +380,13 @@ msgstr "" "둘째, ``self.is_input_command_in_console`` 매개변수에 따라 서버의 콘솔 입력을 수신할지 여부를 " "결정하는 스레드를 시작합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:123 -#: bd35c2a4858f46ecb2f1ea1b7e987bb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 +#: 493d7ac50eb3446394da3c71f307b0a5 msgid "After that, a main loop to accept clients will be started." msgstr "그 후, 클라이언트를 받아들이는 메인 루프가 시작됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:125 -#: 8b06edd210564df19035b30b72121c82 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 +#: 46f0159fb9a84874959c103ac08656f5 msgid "" "*Note: there is another global variable ``self.running`` which is set to " "``True`` after the server socket is successfully created. The " @@ -330,8 +398,8 @@ msgstr "" "있습니다. ``self.running`` 변수는 TCP 서버의 메인 루프를 제어하는 ​​데 사용되며, 서버가 종료되면 " "``False``로 변경됩니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 -#: 0920728e22cf4fdcbd6b6a5f32b251d4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:164 +#: ed335af1339644a090d7fc4ebdc859f1 msgid "" "With ``is_asynic_clients_io=True`` the main loop is the asyncio event " "loop instead: it accepts clients in non-blocking mode and schedules one " @@ -339,8 +407,8 @@ msgid "" " `stop` releases it so the loop can end." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:136 -#: ca2a678a5119456daf70ba9c6bcfacf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:169 +#: 613624f457b847f994b739812b6e7aed msgid "" "The main loop of the TCP server setup function first checks whether the " "number of connected clients exceeds the maximum number of clients. The " @@ -351,8 +419,8 @@ msgstr "" "클라이언트 수는 ``__init__``에서 초기화되는 `TCP_Server_Base` 클래스의 ``self.max_clients``" " 인수에 의해 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:141 -#: 295d9fd021d94b94b5bb5e3290af9b94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:174 +#: d6142df9dee34a85a449a322bcfc5729 #, fuzzy msgid "" "If the number of the clients is already over the limit of the connect " @@ -364,8 +432,8 @@ msgstr "" "클라이언트 수가 이미 연결 수 제한을 초과한 경우 서버는 과부하 메시지를 보내고 연결을 닫습니다. 그러나 제한을 초과하지 않은 경우" " 서버는 클라이언트 핸들러 함수 `handle_client`를 설정하고 서버 핸들러 함수는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:153 -#: a15c83c5c9984e68b88602f6a3c56d16 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:186 +#: e0d97e64db41406aa120fbdcd2ee5bb3 msgid "" "*Note: For more details of the `handle_client` function, see the :ref" ":`tcp-server-handling-information-api` section.*" @@ -373,13 +441,13 @@ msgstr "" "*참고: `handle_client` 함수에 대한 자세한 내용은 :ref:`tcp-server-handling-" "information-api` 섹션을 참조하세요.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 -#: 4e4b61d041b24075b90f598ef42bbe78 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:189 +#: 686ed007e14d4a98b931c0c651bb7bf5 msgid "So what can the setup function do if it fails?" msgstr "그렇다면 실행이 실패한 경우 설정 기능은 무엇을 할 수 있습니까?" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 -#: bfc7899a0ec649d49c956d569bbad0bc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:191 +#: 189abee61a444611a486dec294da6561 #, fuzzy msgid "" "First, the try-except block in the main server loop checks whether the " @@ -388,8 +456,8 @@ msgstr "" "먼저, 메인 서버 루프의 try 및 Except 코드 블록은 오류가 ``OSError``인지 감지합니다. 그렇다면 메인 루프가 직접" " 종료됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:162 -#: 8a3a4854f3a3441b87d0257cb4eb4e52 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 +#: e4e1ba68f4b64dc280490157405acab9 #, fuzzy msgid "" "Secondly, if the error is from the network socket, it first logs the " @@ -399,8 +467,8 @@ msgstr "" "둘째, 오류가 네트워크 소켓에서 발생한 경우 먼저 오류 메시지를 출력하고 'stop' 함수를 호출하여 서버도 중지합니다. 그리고 " "정지 기능은 다음과 같이 정의되었습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:171 -#: 4eb334cfa82e4557b51ed511bb35fea1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:204 +#: 9eb5b6fb9d2e4394b3dbb4a1905767d0 msgid "" "To stop the TCP server, it first sets the ``self.running`` variable to " "False, to stop the main loop of the server. After that, it calls the " @@ -410,8 +478,8 @@ msgstr "" "TCP 서버를 중지하려면 먼저 ``self.running`` 변수를 False로 설정하여 서버의 메인 루프를 중지합니다. 그 후 " "`free_port` 함수를 호출하여 할당된 포트를 해제합니다. 그리고 `free_port`는 다음과 같이 정의되었습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:182 -#: 2d0515291a604c0996149873392657f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:215 +#: 18d7078902794d629ad9f4e92a334402 msgid "" "*Note: For more details of the `free_port` function, see the :ref:`tcp-" "server-port-allocation-api` section.*" @@ -419,8 +487,8 @@ msgstr "" "*참고: `free_port` 함수에 대한 자세한 내용은 :ref:`tcp-server-port-allocation-api` 섹션을" " 참조하세요.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:185 -#: ee8148b7ac254bbba148a8ad7a4ebb94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:218 +#: dc449dddb5014d40a50ff66277707822 #, fuzzy msgid "" "At the end of the operations, the TCP server closes all client sockets " @@ -428,8 +496,8 @@ msgid "" "socket." msgstr "작업이 끝나면 TCP 서버는 사전 변수 ``self.clients``에 포함된 클라이언트의 모든 소켓을 닫고 서버 소켓도 닫습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:188 -#: e3cce971756a4931af9b546a1e12aeb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:221 +#: 1d2d730ca10e484d9dadc386b02af66c msgid "" "Before closing the listening socket it shuts it down, which releases a " "thread that is blocked in ``accept()`` (closing alone would leave the " @@ -440,8 +508,8 @@ msgid "" "come up behind the caller's back." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 -#: eb7d0cdf9cb4455eab2a5ba068942fd5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:228 +#: 2975a8e2dfe646cc92f5b112afc6101f msgid "" "*Note: The ``self.clients`` variable is a dictionary that maps client " "address tuples to an info dictionary. The key is the client address tuple" @@ -455,13 +523,13 @@ msgstr "" "containing connection details such as ``'socket'``, ``'address'``, " "``'id'``, and ``'connected_time'``. 항목이 저장되는 방법을 보여주는 아래 예를 참조하세요.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:217 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 +#: 8936cbe70fcf44ac9cabec9e38c0195d msgid "TCP Server handling information API" msgstr "TCP 서버 처리 정보 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:219 -#: 45ece19ab8684f67b0f85203f442103e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 +#: 1bbc64aa745a4dc3a537c6c10fd9e3c5 msgid "" "The server handling information API documents the core TCP server methods" " that manage client sockets, receive raw data, and send messages." @@ -469,8 +537,8 @@ msgstr "" "서버 처리 정보 API는 클라이언트 소켓을 관리하고, 원시 데이터를 수신하고, 메시지를 보내는 핵심 TCP 서버 메서드를 " "문서화합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:231 -#: 4603ad1e2ffc400491456f7abf750937 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:264 +#: 8b1b042f66a243d9b9abd829a3fefcfe msgid "" "`handle_client` is the main per-client handler in ``TCP_Server_Base``. It" " is invoked after a client connection is accepted and is responsible for:" @@ -478,33 +546,33 @@ msgstr "" "`handle_client`는 ``TCP_Server_Base``의 주요 클라이언트별 핸들러입니다. 클라이언트 연결이 승인된 후에 " "호출되며 다음을 담당합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:235 -#: dbeed4ea23664ab298a9c5e356642ddc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:268 +#: 67121b0c979f421eb7ddbfb432dad873 msgid "" "adding the client entry into ``self.clients`` with socket, address, id, " "and connected time" msgstr "소켓, 주소, ID 및 연결 시간과 함께 클라이언트 항목을 ``self.clients``에 추가" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:236 -#: 98d885826d6743a0ad2c72f44e0e9944 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:269 +#: 65ac2e1844dd4a86a5e550063ee90460 msgid "printing connection information and current client count" msgstr "연결 정보 및 현재 클라이언트 수 인쇄" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:237 -#: f9a1536ee7a540d693a2f4f4b3ad690c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:270 +#: 21670e3d261c41b4a0cbf772ab3f0d73 msgid "sending a welcome message to the client" msgstr "클라이언트에게 환영 메시지 보내기" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:238 -#: e75d30ed5656490994353520e09cf789 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 +#: a48af59d8ef54c12929e843db0d51e01 #, fuzzy msgid "" "sending the ``/client_alloc_port_range`` information to that client " "depending on the port allocation mode" msgstr "포트 할당 모드에 따라 ``/client_alloc_port_range`` 정보를 모든 클라이언트에 브로드캐스트" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:241 -#: 0e3762f344ff4b88bbb6699610627b41 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 +#: 034082645d394f158d8927076c6b38e9 #, fuzzy msgid "" "*Note: You can specify the port allocation mode in the arguments which " @@ -515,33 +583,33 @@ msgstr "" "*참고: ``TCP_Server_Base`` 클래스에 정의된 인수에서 포트 할당 모드를 지정할 수 있습니다. 변경할 수 있는 인수는" " ``port_add_step``, ``port_range_num`` 및 ``is_hand_alloc_port``입니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:247 -#: 3a8f9b23f43a469ca5d7cea807598bd6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:280 +#: 2cb1bb2c2ed84122a479e562a1156bf3 msgid "receiving raw bytes from the socket using `receive_message`" msgstr "`receive_message`를 사용하여 소켓에서 원시 바이트 수신" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:248 -#: 8f1c9c44d13e41d1b4fdadac75fc4613 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:281 +#: f4db70de0d7d4b4f9f02a1fc2325b172 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "개행 문자로 끝나는 메시지가 완료될 때까지 들어오는 데이터 버퍼링" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:249 -#: 54fef48b6314483cbd813885b82ead02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:282 +#: c17ac3c5095746448b497f228eb10c88 msgid "splitting and processing each message line-by-line" msgstr "각 메시지를 한 줄씩 분할하고 처리" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 -#: f7728d56338d464cad635232865f9fb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:283 +#: ba1a3439be1d43af80a46d2ee3658ac8 msgid "routing special commands beginning with ``/`` to `handle_command`" msgstr "``/``로 시작하는 특수 명령을 `handle_command`로 라우팅" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 -#: f87fc68b008a4e06a719e9ab316016f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 +#: 37462f705b094332a79be9d2765c4796 msgid "The `handle_command` function is defined as:" msgstr "`handle_command` 함수는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:263 -#: 8b47f53ad413459393250da7b5f249eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:296 +#: d5bdce3eed0b4171882356d2b207f6d2 #, fuzzy msgid "" "In `handle_command`, there are variable conditional branches to handle " @@ -554,8 +622,8 @@ msgstr "" "전송 명령과 같은 내장 명령을 처리하기 위한 가변 조건 분기가 있습니다. 명령 확장 API를 통해 이미 더 많은 명령을 추가한 경우" " 함수는 입력된 메시지가 확장 명령과 일치하는지 확인합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 -#: 1b5f22ecb31f4b17bc31eeba617e9373 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 +#: 21bedf659c7c44a783ed367bebbec813 msgid "" "*Note: For more details of the command extension API and the built-in " "commands, see the :ref:`tcp-server-command-api` section.*" @@ -563,20 +631,20 @@ msgstr "" "*참고: 명령 확장 API 및 내장 명령에 대한 자세한 내용은 :ref:`tcp-server-command-api` 섹션을 " "참조하세요.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 -#: f4e3e8921f9c4825b54b7e26c77dfaa1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:307 +#: 85099f44cbb14013a55dcaf602370b51 msgid "logging normal chat messages and acknowledging receipt" msgstr "일반 채팅 메시지 기록 및 수신 확인" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:275 -#: e25f3746f80f4046a7aeb5f0b61bba85 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:308 +#: c4a9e9f9ccd74f0ca064b3fe6a95e739 msgid "" "removing the client from ``self.clients`` and closing the socket when the" " client disconnects or an error occurs" msgstr "``self.clients``에서 클라이언트를 제거하고 클라이언트 연결이 끊기거나 오류가 발생하면 소켓을 닫습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 -#: 21e6108f8c1243a39f017b806967fb1d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:318 +#: 5f6ae0695302473a8adf476a72c72d3a msgid "" "`receive_message` is a thin wrapper around socket receive operations. It " "reads up to ``msg_length`` bytes from the given ``client_socket`` and " @@ -587,8 +655,8 @@ msgstr "" "``msg_length`` 바이트를 읽고 원시 바이트 페이로드를 반환합니다. 메시지 디코딩 및 개행 메시지 프레이밍은 호출자가 " "처리합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:300 -#: b7e713b412334cc98292e1ca8abbf861 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:333 +#: 114485120bad452e8af2626995798eda msgid "" "`send_message` sends data back to a specific connected client. It " "verifies the server is running and the socket is valid, then:" @@ -596,18 +664,18 @@ msgstr "" "`send_message`는 연결된 특정 클라이언트로 데이터를 다시 보냅니다. 서버가 실행 중이고 소켓이 유효한지 확인한 후 다음을" " 수행합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:303 -#: 923c92c05c79407e841f3a5d6fefeb92 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:336 +#: 78639cd82b2f42db9ddd7d84bf06e9ee msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "``str`` 및 ``bytes`` 메시지 페이로드를 모두 허용합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 -#: f890eeb62bbc4b5ab359452c6dd40b17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:337 +#: bff4a398dec3443391a0c6e6a9fb00ee msgid "trims string payloads and appends a newline if missing" msgstr "문자열 페이로드를 자르고 누락된 경우 개행을 추가합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:305 -#: 21a1156ab51b4dc598f583c1d9f9defc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:338 +#: 033e533bc19f484bb0fe7d61fe01dc46 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -617,29 +685,29 @@ msgstr "" "소켓이 암호화 모드에 있을 때(공개 키 교환이 완료됨) 일반 텍스트는 ``_VALID' 마커로 서명되고, RSA-OAEP는 피어의 " "공개 키로 암호화되며, 일반 텍스트로 전송되는 대신 base64로 인코딩되고 개행 문자로 종료됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:309 -#: 94980e8ed8db4bfeb6bb4f4278c10d04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:342 +#: 1f1be9fb9dff4409aa040671a8e89013 msgid "encodes string payloads as UTF-8" msgstr "문자열 페이로드를 UTF-8로 인코딩합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:310 -#: ce93763396994dbabdc93a51b56ed8c3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:343 +#: 38c4b6970f644bf6b1dee52c1d6f7157 msgid "" "sends the message with ``client_socket.sendall(data)`` when the server " "serves clients with one thread each, or through a non-blocking ``send()``" " loop when ``is_asynic_clients_io`` is ``True``" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:313 -#: eb3454d6feb84ce1a3e00a573cf20972 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 +#: b3f2ff47fdc74a1fb5b599b1f3706a59 msgid "" "returns ``True`` on success; it returns ``False`` for an unsupported " "payload type, and an invalid/closed connection raises ``RuntimeError`` " "(other socket failures are logged and re-raised)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:317 -#: 62174575716644e69c0d479ff05a9df0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:350 +#: 042c1637a86c494ca7da9ba4299b08be msgid "" "And there are also some other functions which are used to send message in" " bulk to the clients, such as the `broadcast` function and the " @@ -648,13 +716,13 @@ msgstr "" "그리고 `broadcast` 함수와 `send_msg_to_special_client` 함수와 같이 클라이언트에 대량으로 메시지를 " "보내는 데 사용되는 다른 함수도 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:325 -#: 762f3bf7c5bb46e091ca12b1f0393624 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:358 +#: eeecf353189a46f8972335c059bef718 msgid "TCP Server encrypted channel API" msgstr "TCP 서버 암호화 채널 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:327 -#: 67ffdc91d9694e77ab33c0c60253430d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:360 +#: e5659287613a419dbbecdc491f57b514 msgid "" "When the server is created with ``is_enable_encrypto=True`` (the " "default), every connected client goes through an RSA public-key exchange " @@ -663,13 +731,13 @@ msgstr "" "``is_enable_encrypto=True``(기본값)로 서버가 생성되면 연결된 모든 클라이언트는 메시지 내용이 암호화되기 전에" " RSA 공개 키 교환을 거칩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:332 -#: 8de167f009be4406b25e0e3d3be6cb4b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:365 +#: a31863451ad94e828e4d5826811dc4e9 msgid "Key material" msgstr "주요자료" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:334 -#: 01312565566c4707b6d4b55a223882d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:367 +#: aae09222bb4b42dfb9db4c7ebc329d10 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -681,8 +749,8 @@ msgstr "" "``network_api/.Flow/pvt_key`` (``server_priv.pem`` / ``server_pub.pem``)에" " 생성됩니다. 교환된 공개 키는 항상 개인 키에서 파생되므로 회전된 ``~/.ssh`` 쌍이 자동으로 선택됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:339 -#: 5e641bcd12c44f73bd22b43332b12b91 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:372 +#: f4206182556e4cca9a9284905e3de143 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -693,8 +761,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 -#: 26f407b8ad29482ca30db4edd0f20abe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:379 +#: bab30142a34845e5b01353a55c4ba643 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -706,8 +774,8 @@ msgstr "" " 있습니다. 두 파일이 모두 존재해야 하며 PEM으로 구문 분석하고 서로 쌍을 이루어야 합니다(공개 키로 암호화된 프로브는 개인 " "키로 해독해야 함). 유효하지 않은 쌍은 무시되고 기본 조회가 사용됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:351 -#: 3af59fcb848044718426e6b9427c017d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 +#: 324dcdafcfa048218e102466956bd1a5 msgid "" "Public keys received from clients are cached in " "``network_api/.Flow/pub_key`` as ``client__.pem`` (the peer " @@ -718,13 +786,13 @@ msgstr "" "``client__.pem``으로 캐시됩니다(키가 나온 피어 엔드포인트; ``:``는 ``_``으로 대체되므로 " "IPv6 리터럴은 Windows를 포함한 모든 플랫폼에서 안전합니다)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:357 -#: 26ea5ad884b4402097ce3f800bb7e8d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:390 +#: aee5a1316ad24fab8db1dedeb6c95790 msgid "Anti-MITM identity check (TOFU)" msgstr "MITM 신원 확인(TOFU) 방지" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:359 -#: 69fe026672cc44c7b931a2a404468eb0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:392 +#: 8ceb7ab10998464e93c80c1609797ac7 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -739,15 +807,15 @@ msgstr "" "port)``(피어가 연결된 엔드포인트의 Python 튜플)이고 값은 ``[<공개 키의 sha256>, <공개 키 " "PEM>]``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:366 -#: f8e45fa616844ba287ea1d9a249d5157 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:399 +#: e63b24b8eded401fb82be09174963c1b msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "엔드포인트에서의 첫 번째 연결: 키가 기록되고 신뢰됩니다(처음 사용할 때 신뢰)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:368 -#: faa949fc11b74c9692009fba21d3a5f2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:401 +#: 9c091413145845f3b15fac0bdc9b583c msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -756,8 +824,8 @@ msgstr "" "*동일한* 키를 나타내는 나중에 연결: 허용됩니다. 엔드포인트가 변경된 경우(동적 IP / 사용자 변경 포트) 레코드가 중복되지 " "않고 새로운 ``(ip, port)``로 이동됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:371 -#: d80fbe47d78343d6a5ae8b7a7388b177 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:404 +#: d89337a304a24744a703acaa977b3290 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is sent and the " @@ -766,8 +834,8 @@ msgstr "" "이미 기록된 엔드포인트에 대해 *다른* 키를 나타내는 이후 연결: 연결이 거부됩니다(``/crypto_reject``가 전송되고 " "소켓이 닫힙니다)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:375 -#: c12761b71fbb40e9b5d9f17ce7389981 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:408 +#: ff44ccbece9b48ab8e86a12cba949078 msgid "" "Because the server-side record is keyed by the client's source port, a " "client that rotates its keypair is only detected when it reconnects from " @@ -782,13 +850,13 @@ msgstr "" "주소로 입력되므로 변경된 서버 키는 항상 거부됩니다. 신뢰를 재설정하려면(교체된 키, 새 서버) ``pub_key.json`` " "항목(또는 전체 파일)을 삭제하세요." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 -#: 160b797ceb5340aaa631e6a42ed052f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:417 +#: e011f68df76445d18659be173dba1877 msgid "Handshake" msgstr "악수" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:386 -#: 6f031912413e4e4b8b7105c3c59f1b99 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:419 +#: 700f2215924f4bfb92c3f90f37c3e514 #, fuzzy msgid "" "The client initiates the exchange by sending a plaintext " @@ -797,12 +865,16 @@ msgid "" "Both sides then push their public key files over the file-transfer " "mechanism (plaintext) and TOFU-check the received key. Both sides switch " "to encrypted mode only after ``/crypto_ready`` has been received from the" -" peer (so plaintext and ciphertext never interleave on a connection). On " -"later connections the keys are re-exchanged and TOFU-checked again; the " -"exchange is never skipped, only the identity check short-circuits for " -"known keys. Public-key pushes are only accepted from a connection that " -"actually started the handshake, so an arbitrary unauthenticated peer " -"cannot poison the registry." +" peer (so plaintext and framed traffic never interleave on a connection)," +" then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted from a connection that actually started the " +"handshake, so an arbitrary unauthenticated peer cannot poison the " +"registry." msgstr "" "클라이언트는 일반 텍스트 ``/crypto_key_exchange`` 인사말을 보내 교환을 시작합니다. 서버는 " "``/crypto_key_exchange_ack ``로 응답합니다. 그런 다음 양측은 " @@ -811,34 +883,58 @@ msgstr "" "절대로 인터리브되지 않습니다). 이후 연결에서는 키가 다시 교환되고 TOFU가 다시 확인됩니다. 교환은 절대 건너뛰지 않으며, " "알려진 키에 대한 신원 확인만 단락됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:400 -#: 1efd337c73d249a3b4b15394337e6307 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:437 +#: a9531ad5339a4633a1e6cc54fb8bb79b msgid "Replay protection" msgstr "재생 보호" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:402 -#: 28c8ec1c26d946a19bc02d6aacc9961b -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." -msgstr "" -"핸드셰이크는 무작위 세션 nonce를 교환하고, 유선의 모든 암호화된 라인은 이를 연결당 시퀀스 번호(``||``)와 함께 전달합니다. 수신자는 nonce가 현재 세션과 일치하지 않거나(이전 " -"연결에서 재생된 암호문) 시퀀스 번호가 예상한 것과 다른(세션 내에서 재생된 암호문/순서가 틀린) 줄을 삭제합니다. (재)교환 후 " -"소켓이 암호화 모드로 전환되면 두 카운터가 모두 재설정됩니다." - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:411 -#: c11de683c36c42c59ff73d0839f5afce +#: ../../source/Network_APIs/TCP_Server_APIs.rst:439 +#: e9505df5322640ce8671b5098d655374 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:455 +#: 3fd7ac4d381e41589a62998726dd22f7 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:457 +#: 8ca69d91005b459a8a56f21902eaa690 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:469 +#: b32b4fa4788d4f9d88926958c81ad73f msgid "Decode verification and key rotation" msgstr "디코드 검증 및 키 순환" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:413 -#: ba7b28826b9f4d0a85328f08be4a76e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:471 +#: d09ae3121b0f40fb85374589b851d45c msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -858,21 +954,26 @@ msgstr "" "참조). 의도적으로 키 쌍을 교체하는 사용자는 새 키를 다시 신뢰하기 위해 피어 측에서 오래된 ``pub_key.json`` " "항목(또는 전체 파일)을 삭제해야 합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:424 -#: 6f0160000f2b451a81771556bbc3b8e7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:482 +#: 7312fb4bd4c345ff9cec7ffe4245afb7 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures on one connection the connection is closed " "instead of re-exchanging, so a garbage-injection or persistent-mismatch " -"storm cannot spin the loop forever. A successful decryption resets the " -"counter." +"storm cannot spin the loop forever. Genuine peer traffic (messages and " +"commands other than the protocol's own handshake/coordination lines) " +"resets the counter. Frames the peer had already sent when this side " +"dropped out of encrypted mode are stale: they cannot be authenticated any" +" more, so they are consumed and dropped — they neither surface as " +"messages nor reset the counter." msgstr "" "재교환은 회로 차단됩니다. 한 연결에서 ``MAX_DECODE_FAILURES`` (3) 연속 디코드 실패 후 재교환 대신 연결이 " "닫히므로 가비지 주입 또는 지속적인 불일치 폭풍으로 인해 루프가 영원히 회전할 수 없습니다. 암호 해독이 성공하면 카운터가 " "재설정됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:438 -#: 850c5c67b6504551a3104a9cfa5710e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 +#: 4fb05c76f6734fd58aa33ee628ad933d #, fuzzy msgid "" "The `broadcast` function sends a message to all clients in the " @@ -885,8 +986,8 @@ msgstr "" "끊어진 클라이언트도 삭제합니다. 그리고 ``exclude_client`` 매개변수가 ``None``이 아닌 경우 서버는 메시지를 " "보낼 때 ``exclude_client`` 매개변수에 지정된 클라이언트를 제외합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:452 -#: 9ddd28be0e6b439891a25d79adbaf823 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:514 +#: 0b4f67331831429b85514fbbe3ce2602 #, fuzzy msgid "" "The `send_msg_to_specific_client` function sends one or more messages to " @@ -899,41 +1000,43 @@ msgstr "" "`send_msg_to_특이적_client` 함수는 클라이언트 ID를 통해 하나 이상의 특정 클라이언트에 하나 이상의 메시지를 " "보내는 데 사용됩니다. 그리고 ``message`` 인수는 메시지 전송 명령을 입력해야 합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:459 -#: 4f7cd128081c4062bffdacfb4b67137c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 +#: c8f357719cc548719792a5a2cade0c03 msgid "" "These methods form the server's client I/O loop and ensure reliable " "message exchange for connected TCP clients." msgstr "이러한 방법은 서버의 클라이언트 I/O 루프를 형성하고 연결된 TCP 클라이언트에 대한 안정적인 메시지 교환을 보장합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:466 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 +#: 8936cbe70fcf44ac9cabec9e38c0195d #, fuzzy msgid "TCP Server inbound event listener API" msgstr "TCP 서버 파일 전송 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:468 -#: f86e7c53407b43509932d19288024a54 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 +#: 583ef0a34dfc480da5b4fc87108cbf2f msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:478 -#: f59f2230d9f648ca99834633af460deb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:540 +#: 0a30ecd70b364968a892136d9bec809f msgid "" "``add_message_listener`` registers ``listener(client_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to the command handlers instead). ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a" -" file uploaded by a client has been fully written to the transfer " -"directory (``command`` is the wire command that triggered it, so protocol" -" pushes such as ``/crypto_pub_key`` can be recognised). Both listeners " -"run on a protocol thread, so they must not block, and an exception inside" -" a listener is logged and swallowed. The ``remove_*`` counterparts " -"unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:489 -#: a39677d08af4439989a6fced80cb12d1 +"every inbound line, commands included (``/help``, ``/file ...``, the " +"crypto handshake lines, ...), so a listener observes all inbound traffic;" +" line dispatch is unaffected, a command still goes to the command " +"handlers. ``add_file_listener`` registers ``listener(client_id, " +"full_path, name, size, command)`` and fires after a file uploaded by a " +"client has been fully written to the transfer directory (``command`` is " +"the wire command that triggered it, so protocol pushes such as " +"``/crypto_pub_key`` can be recognised). Both listeners run on a protocol " +"thread, so they must not block, and an exception inside a listener is " +"logged and swallowed. The ``remove_*`` counterparts unregister a listener" +" and ignore unknown ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:553 +#: a7bb1a9276bd4860882ffd43a680d6bf msgid "" "In addition, received messages and events are stored per sender socket in" " ``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -942,13 +1045,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``stop`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:498 -#: cdfe98e71ed34af9a2976b7e884b5201 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 +#: 403a3b0e938b4895be69267c66ecff98 msgid "TCP Server command API" msgstr "TCP 서버 명령 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 -#: 25c853b63e744fd6a370ecd365c58fd7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 +#: 9c016262f199458585bb12055da6d30d msgid "" "The server supports several built-in commands and a command extension " "API. The main entry point is the `handle_command` method, which is " @@ -957,19 +1060,20 @@ msgstr "" "서버는 여러 내장 명령과 명령 확장 API를 지원합니다. 주요 진입점은 '/'로 시작하는 모든 메시지에 대해 호출되는 " "'handle_command' 메서드입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:505 -#: d0e290f03c1242b580024033ffab5e04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 +#: b26b06ec49a644c9b034acf6930006bd #, fuzzy msgid "" "We support two solutions for command handling: inputting a command in the" " console or receiving a command from other clients. You can also call the" -" functions defined for each command in the code." +" functions defined for each command in the code via " +"`call_extension_functions`." msgstr "" "우리는 명령 처리를 위해 두 가지 솔루션을 지원합니다. 하나는 콘솔에 명령을 입력하는 것이고, 다른 하나는 다른 클라이언트로부터 " "명령을 수신하는 것이며, 코드에서 명령에 대해 정의된 함수를 호출할 수도 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:510 -#: aad12adb23334f4e9c5b6b7f7637dd3e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:575 +#: 5f20432236324511acfc720b1e616e49 #, fuzzy msgid "" "*Note: You can select the solution which you want to use by changing the " @@ -981,66 +1085,78 @@ msgstr "" "``is_input_command_in_console``입니다. ``True``는 서버가 콘솔에 명령을 입력하는 것을 허용하는 " "반면, ``False``는 허용하지 않습니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:517 -#: 88e051e4fef245c7a474a8478dc74b88 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:582 +#: cc5dd7cfa448466399da9463e53c1a08 msgid "Built-in client commands include:" msgstr "내장 클라이언트 명령은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:519 -#: c8a591e28fcf4243862e820e582e9127 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:584 +#: 989d1b29c70e4f9883b95523b0b420d9 msgid "``/help``: returns the available command list and usage hints." msgstr "``/help``: 사용 가능한 명령 목록과 사용법 힌트를 반환합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:520 -#: 453004b0bb914398a4d9a437f5d1b864 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:585 +#: a4795afd8b3249538f031ed27783f0a7 msgid "``/time``: returns the current server time." msgstr "``/time``: 현재 서버 시간을 반환합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 -#: 324cbdab33984517a498f1e2747a6387 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:586 +#: b2d813b2d8bb46c59195ed01431d150b msgid "``/clients``: returns the list of connected client IDs." msgstr "``/clients``: 연결된 클라이언트 ID 목록을 반환합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:522 -#: a4411c0f498c434fbe864ea1627384fb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:587 +#: d81ad6c5cbe44bd589f32ce7f3e36d31 msgid "" "``/quit``: writes a goodbye message (``Bye!``) and shuts the connection " "down, so a client that stays after sending ``/quit`` is disconnected by " "the server." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:525 -#: 1248e1b365da420e8d96182e8a237d57 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:590 +#: a9fbf429095b4483b18a247ef327b461 msgid "" "``/file [destination_file_path]``: starts a file transfer " "from the client to the server. The trailing token of the wire line is the" " sender's own transfer id, appended by the sending client." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 -#: c8de5282934945bab929e1084d7848f5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 +#: cef48a93703449f8813fab1d3fb199fb #, fuzzy msgid "" "``/file_folder [destination_file_path]``: starts a folder " "transfer from the client to the server (same trailing id)." msgstr "``/file_folder ``: 클라이언트에서 서버로 폴더 전송 요청을 시작합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 -#: d006c91db83f4404b7f7022cb9bb61c5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:595 +#: 92bf2736c9c14f1cb24ec110315f8caa msgid "" "``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``:" " internal handshake messages of the encrypted channel." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:532 -#: c026024882d44552a578b0fe4e096b34 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:597 +#: 38987654adbf4707b84c8048a9cdcbb3 msgid "" "``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, " -"``/start_trans``: internal forwarding/transfer-control messages." +"``/start_trans``: internal forwarding/transfer-control messages. " +"``/pause_trans `` and ``/start_trans `` hold and release the " +"outbound transfer with that fid (`pause_trans`/`start_trans` are the same" +" switch as a public API)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:534 -#: 5fb7405e0dae4344a58d3a61aa5f2779 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:601 +#: 7f3801d57ac34670bbe16736683db30e +msgid "" +"``/resume_trans `` and ``/forward_resume " +"``: internal transfer-reconnect messages: the receiver asks the " +"sender (or, for a forwarded transfer, the originator) to continue the " +"file from the bytes already on disk. See `resume_transfers`." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:605 +#: abd7d3032e15468e92f96a0b5af1f926 msgid "" "``/server_file_transfer_port ``: internal protocol " "message used to coordinate file transfer ports." @@ -1048,8 +1164,8 @@ msgstr "" "``/server_file_transfer_port ``: 파일 전송 포트를 조정하는 데 사용되는 " "내부 프로토콜 메시지입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:536 -#: 94f93b06051f4eebaf0b64ccf589160b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:607 +#: 1e9e32071bb1425b8617a419a7ef87f6 msgid "" "In `handle_command`, the server will first check if the command matches " "any built-in commands. If it does, the `handle_command` will call the " @@ -1058,8 +1174,8 @@ msgstr "" "`handle_command`에서 서버는 먼저 명령이 내장 명령과 일치하는지 확인합니다. 처리하는 경우 " "`handle_command`는 명령에 대해 정의된 함수를 호출합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:541 -#: 16991ef553344476af487507dc3a1a0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:612 +#: f08564b44ab0442788145105b1086bb8 msgid "" "If a command is not recognized by the built-in handler, `handle_command` " "will check if it matches any registered custom commands from the command " @@ -1071,30 +1187,38 @@ msgstr "" " 확인합니다. 명령이 이미 등록된 경우 `handle_command`는 해당 명령에 대해 정의된 함수를 호출합니다. 명령 확장 " "API는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:559 -#: 9c0334fe21e34b6ab8b1c941e1c62e2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:633 +#: ac06208b93d54ede93002123521d921b +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code; the command's first token selects it, exactly as it does for " +"a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:637 +#: 11c186c6375b4eeeb337ac755b136a94 msgid "The args of the `register_command` function are as follows:" msgstr "`register_command` 함수의 인수는 다음과 같습니다:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 -#: ac4db02fce3d492b81a094400f44b0a8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 +#: 6741d64e02414c1c8759b14d41ec69a1 msgid "``command_name``: The name of the command to register." msgstr "``command_name``: 등록할 명령어의 이름입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 -#: 8e250a4664ce40c89f0190ce7eb67848 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:642 +#: 21a28c492d33486a81f97ca3d8a32266 msgid "" "*Note: The ``command_name`` should start with a slash (e.g., " "``/my_command``) to be recognized as a command.*" msgstr "*참고: ``command_name``은 슬래시(예: ``/my_command``)로 시작해야 명령으로 인식됩니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:567 -#: f91cdc45f9ea4c35891b087f1097ba51 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:645 +#: 6deb6588265049cbbeaea615b7d6c2cf msgid "``handler``: The function to call when the command is received." msgstr "``handler``: 명령이 수신될 때 호출할 함수입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 -#: 1797ec404bbe45b380d46588adbb731f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:647 +#: 16d22c49f16d4430bfe740374d70705f #, fuzzy msgid "" "*Note: The ``handler`` function must have exactly three parameters: " @@ -1109,20 +1233,20 @@ msgstr "" "``client_address``는 명령을 보낸 클라이언트의 주소로 받아들여지며, ``command`` 매개변수에는 실제 명령 " "문자열이 포함됩니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:577 -#: 56b8f72098b84ccea4d1bf143a31e04c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:655 +#: 7605062541fa4d70ae37d67efdfd5fdf msgid "``where_to_run``: Specifies where the command should be executed." msgstr "``where_to_run``: 명령이 실행되어야 하는 위치를 지정합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:578 -#: 7572e9944acd4704b2c55643fb1fbcd4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:656 +#: f6ee42356212497ba468266c87e127d4 msgid "" "``run_in_thread``: A boolean indicating whether to run the command in a " "separate thread." msgstr "``run_in_thread``: 별도의 스레드에서 명령을 실행할지 여부를 나타내는 부울입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:580 -#: 0ac212e49ef54e77b5429272e05561aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:658 +#: 37adfd2db6af47bf995b271dd70ad293 msgid "" "This extension API allows server-side and console-side custom commands to" " be registered dynamically. Valid values for ``where_to_run`` are " @@ -1135,8 +1259,8 @@ msgstr "" "유효한 값은 ``\"server\"`` 및 ``\"client\"``입니다. \"서버\"는 클라이언트가 명령을 보낼 때 명령이 " "처리된다는 의미이고, \"클라이언트\"는 서버가 콘솔에 명령을 입력하면 명령이 처리된다는 의미입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:589 -#: c0201e2dd3fd4c7fa8d363060c5ff49a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:667 +#: 24c64499179b4f01a92ffd8e88515738 #, fuzzy msgid "" "*Note: It's true that the valid values for ``where_to_run`` are not " @@ -1145,8 +1269,8 @@ msgstr "" "*참고: ``where_to_run``에 대한 유효한 값이 너무 이상하다는 것은 사실이지만, 우리는 이를 정의하는 더 좋은 방법을 " "찾지 못했습니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 -#: ec3b9b188728413eb3cd5871542b83cd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:671 +#: fbdb162f54a64fd3b454ddbf85a6e5d4 #, fuzzy msgid "" "The ways to run the command will be different according to the args " @@ -1160,8 +1284,8 @@ msgstr "" " 명령 핸들러는 서버의 스레드 풀과 별도의 스레드에서 실행됩니다. ``run_in_thread``가 ``False``이면 명령 " "핸들러는 메인 서버 스레드에서 동기적으로 실행됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:603 -#: 0a62647e915e4e4c80071b3d7fb41464 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:681 +#: 9576b9601ddd48749947aa7b18bc2c82 #, fuzzy msgid "" "*Note: We store the registered commands in a list variable with two " @@ -1183,23 +1307,23 @@ msgstr "" " 메소드에서 초기화된 ``self._custom_handler_threaded``로 정의된 또 다른 목록 변수도 있는데, 여기에는 " "별도의 스레드에서 실행되어야 하는지 여부에 관계없이 모든 명령이 포함되어 있습니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:617 -#: eb202f79be654e5a8cccf56c79446b3d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:695 +#: b1f239408f354bf2bdc608ad523f233e msgid "" "*Note: ``register_command`` returns ``False`` when ``where_to_run`` is " "neither ``\"server\"`` nor ``\"client\"`` (nothing is registered then); " "on success it returns ``None``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:626 -#: 088dcc7ce39046a4afa6451d7e6369f9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:704 +#: b10dad811f9b444bb0a2e3642709b5d1 msgid "" "After that, the command handler will be called according to the command " "name, and run them by a command executor which is defined as:" msgstr "그 후 명령 핸들러는 명령 이름에 따라 호출되고 다음과 같이 정의된 명령 실행기에 의해 실행됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 -#: 0e56345aa429469cb44d7708b6af8711 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:718 +#: 7c0987568cf245b9b78d1db2f403717f msgid "" "In this executor function, there is a try-except code block to catch the " "error when running the command handler. If there is an error when running" @@ -1214,8 +1338,8 @@ msgstr "" "보냅니다. 그리고 try 코드 블록에서 명령 핸들러는 명령 인수를 사용하여 호출되며 명령이 클라이언트 측에서 오는 경우 클라이언트 " "소켓 및 클라이언트 주소도 호출됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:650 -#: 6467226e231c4e458bb78687c9da8659 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:728 +#: a98408c31eee4f3fbad1c3afdb2a036c #, fuzzy msgid "" "If the command doesn't run in the thread, the command executor will be " @@ -1228,8 +1352,8 @@ msgstr "" "스레드에서 실행되어야 하는 경우 명령 실행기는 다음과 같이 정의된 `submit_task` 메서드를 사용하여 서버의 스레드 풀에 " "제출됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:665 -#: fb9ac9433b8342dd9e90707a01990fd0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:743 +#: c3401f2293044a31a7e8e6d2e8407797 #, fuzzy msgid "" "The `submit_task` method is a helper function that submits a callable to " @@ -1244,8 +1368,8 @@ msgstr "" "받아들이고 별도의 스레드에서 실행되도록 예약합니다. 이를 통해 주 서버 루프를 차단하지 않고 장기 실행 또는 차단 명령 처리기를 " "실행할 수 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:675 -#: 711e7a3b8f114200857fc39218e2820f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 +#: 9a327fd5482b4575a777e49024f42f56 msgid "" "In this high-level TCP network protocol, a temporary TCP server and " "client can also be created very simply. The temporary TCP server or " @@ -1258,8 +1382,8 @@ msgstr "" "또는 클라이언트는 기본 서버 또는 클라이언트 루프와의 충돌을 피하기 위해 추가 소켓 또는 포트가 필요한 시나리오에 사용할 수 " "있습니다. 예를 들어 파일 전송 기능이 있습니다. 임시 TCP 서버 및 클라이언트를 생성하는 API는 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:688 -#: 7368e712e93f4be7aaeeae265b22e832 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:766 +#: b1e9ab095ed84ef8ae08333047df5b93 msgid "" "``create_temporary_server`` returns ``(port, thread, stop_event)``: the " "bound port (``palloc()`` picks one when ``port`` is None), the accept-" @@ -1268,21 +1392,21 @@ msgid "" " allocated." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:693 -#: 0750bd372cf6478eb8123ca0603de9c2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:771 +#: d23ff87180c44746b62528903a34cdb5 msgid "" "``create_temporary_client`` returns ``(client_socket, thread, " "stop_event)``: the connected socket, the receiver thread and an event " "whose ``set()`` ends that thread." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:700 -#: edf78b86ed664657adc2b46ab0f7efdd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:778 +#: c14e33129d3b41ee8c1dac7189f0408d msgid "TCP Server console commands" msgstr "TCP 서버 콘솔 명령" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:702 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:780 +#: 2ad09a3887894e01a67d31c28272f730 msgid "" "The server console input thread accepts administrative commands when " "``is_input_command_in_console`` is ``True``. Supported console commands " @@ -1291,23 +1415,23 @@ msgstr "" "서버 콘솔 입력 스레드는 ``is_input_command_in_console``이 ``True``일 때 관리 명령을 허용합니다. " "지원되는 콘솔 명령은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:706 -#: 5a059eb897914040873e954609c66c0c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:784 +#: 4d4368102eae41dbac5a8938a4726e1a msgid "``/stop``: stops the server and closes all active connections." msgstr "``/stop``: 서버를 중지하고 모든 활성 연결을 닫습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:707 -#: db67da00bf70423a9a3cf4a2fa3a01e1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:785 +#: 8035f922921f4301bbe4ca4936ea38b3 msgid "``/status``: prints the current connection count and running state." msgstr "``/status``: 현재 연결 수와 실행 상태를 인쇄합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:708 -#: 15ab35eecbd84e64b8dfc0ac50c3d173 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:786 +#: ce2138bd90784f1daffb39cc8d46d1f1 msgid "``/clients``: prints the connected clients and their connection times." msgstr "``/clients``: 연결된 클라이언트와 연결 시간을 인쇄합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:709 -#: 2d1d3fe9ee9f4d6899754d296f8ede75 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:787 +#: 8c9f96a3d0cd4fbcb311c201db9ff789 msgid "" "``/send_msg <(ip, port)> ...``: sends one or more messages " "to specific clients. Targets are literal ``(ip, port)`` tuples (its own " @@ -1315,24 +1439,24 @@ msgid "" "form)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:710 -#: 92d75f708fe642cf8a77f986f2d891b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:788 +#: 033fdbf663a04e12bfdff63da6e0f6c1 #, fuzzy msgid "" "``/file <(ip, port)> [destination_file_path]``: sends a file " "from the server to a specific client." msgstr "``/file ``: 서버에서 특정 클라이언트로 파일을 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:711 -#: 8b28ccd83c594ee5a0ccd126db3bb2dd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:789 +#: 49fea0c411844c689ea2cabaa11c70b3 #, fuzzy msgid "" "``/file_folder <(ip, port)> [destination_file_path]``: " "sends a folder from the server to a specific client." msgstr "``/file_folder ``: 서버에서 특정 클라이언트로 폴더를 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:712 -#: 585e54ca3b1545f49a347b69680d3cd2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:790 +#: d4c2a98b15c04214bfca54bd719f9ab4 msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " "port)2> ...``: sends multiple files to multiple clients. Tokens are " @@ -1340,8 +1464,8 @@ msgid "" "otherwise, so files and targets may be interleaved." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:713 -#: 60def6731a3a43d1a074374978801dbc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:791 +#: e6c9995a12a24a6ba5534e475f158d86 msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, " "port)1> <(ip, port)2> ...``: sends the files that precede a group of " @@ -1350,13 +1474,13 @@ msgid "" " that is not a tuple) is accepted and passed on." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:714 -#: 0f9a9437ddcd4894b6be7502e1303c6e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:792 +#: d8253e90b4fe4d8dbe0b2bbd23134dc0 msgid "``/help``: prints a help summary of console commands." msgstr "``/help``: 콘솔 명령의 도움말 요약을 인쇄합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:716 -#: 1e898bf6aeb54dcb8533615767d03791 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:794 +#: 8cf019297938433ebe65839a4513ae63 msgid "" "The forward commands (``/forward_send_msg``, ``/forward_file``, " "``/forward_folder``) are client-only and are refused on the server " @@ -1364,15 +1488,15 @@ msgid "" "``where_to_run=\"client\"``." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:721 -#: aff923b39d6843bb976f5bb40d38a71d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:799 +#: 43db2954705945c3b3b0742033f122b9 msgid "" "These console commands make it easy to manage the active server and " "perform server-initiated file transfers without modifying the code." msgstr "이러한 콘솔 명령을 사용하면 코드를 수정하지 않고도 활성 서버를 쉽게 관리하고 서버 시작 파일 전송을 수행할 수 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:725 -#: bcbb903def99415298bb7b29d21f31f6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:803 +#: 261fde939721476abba9b40f0290944f #, fuzzy msgid "" "*Note: It is too long to introduce all the console commands, so for more " @@ -1381,20 +1505,20 @@ msgstr "" "*참고: 모든 콘솔 명령을 소개하기에는 너무 길기 때문에 자세한 내용은 :ref:`tcp-server-console-" "commands` 섹션을 참조하세요.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:729 -#: c68a8d4ecb904da7980049abc5210fdf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 +#: 0e848b37570e4fc8b23ff7eb13a2ae3e msgid "TCP Server file transfer API" msgstr "TCP 서버 파일 전송 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:731 -#: 1e9d70417dbf4446bc8528cf692db8ed +#: ../../source/Network_APIs/TCP_Server_APIs.rst:809 +#: 27472ef4f13641ba9a08e6a97bb651dc msgid "" "The TCP server contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers." msgstr "TCP 서버에는 클라이언트-서버 전송과 서버-클라이언트 전송을 모두 지원하는 파일 전송 하위 시스템이 포함되어 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:735 -#: 695753d4c2bc4f15972565a20be6b6c8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 +#: eadd29678d8a449c9659c4792b5f2cb0 #, fuzzy msgid "" "It's too long to introduce all the file transfer functions, so there is " @@ -1404,40 +1528,40 @@ msgstr "" "파일 전송 기능을 모두 소개하기에는 너무 길어서 파일 전송 기능에 대한 API 목록만 있으며, 파일 전송 기능에 대한 자세한 내용은" " 다음 사이트를 방문하시기 바랍니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:740 -#: 5f303019ed3747a691e61b7f20cdb1cf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:818 +#: 1ca2a6ce0f124ebc87676b1155c4c022 msgid "The file transfer API for you to use includes:" msgstr "사용할 수 있는 파일 전송 API에는 다음이 포함됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:742 -#: 376da0b60e9641efa6a75ed7e52af8bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:820 +#: 63c118c7e7c4478fa14f3cb0950f6c1c msgid "The basic function for the server-to-client file transfer is defined as:" msgstr "서버-클라이언트 파일 전송의 기본 기능은 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 -#: 80a158519403430f8f7c43893634e6d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 +#: 4e3a0194c55744898eb3884b60d75672 msgid "The file transfer function which will run in the threads is defined as:" msgstr "스레드에서 실행될 파일 전송 기능은 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:764 -#: 771b5bd6acad467d92fbeebcacbc6dba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 +#: 3fd7ac4d381e41589a62998726dd22f7 msgid "The folder transfer function is defined as:" msgstr "폴더 전송 기능은 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:773 -#: da45b1e2fcc34c1a96c1d1f9e809f742 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 +#: 833a77a7c8fa480db0a0b6e8387132d3 msgid "The multiple files transfer to multiple clients function is defined as:" msgstr "여러 클라이언트로의 여러 파일 전송 기능은 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:783 -#: 15099b87947a4f08a34ca87734c23306 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:861 +#: 26032ba6212f443980c40351874b2139 msgid "" "The different multiple files transfer to the different multiple clients " "function is defined as:" msgstr "다양한 다중 클라이언트 기능으로의 다양한 다중 파일 전송은 다음과 같이 정의됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:793 -#: d93a80b4acca404f98faaf0a7f133079 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:871 +#: 0c9b95c194634285aade290fb17bef5b #, fuzzy msgid "" "We recommend that if you want to use the mono-file transfer function, use" @@ -1459,8 +1583,8 @@ msgstr "" "함수에 이미 일부 스레드 제어 메커니즘이 있으므로 동시 성능에 대해 걱정하지 마세요. 그리고 스레드에서 호출하면 예상치 못한 오류가" " 발생할 수도 있고 불필요하게 복잡해질 수도 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 -#: c3f69c0b152c44df91753c54cf94593f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:885 +#: 28c7d60dd34d48ababd9c06199091309 msgid "" "*Note: The file transfer API functions are designed to be called from the" " command handlers for both client-initiated and server-initiated " @@ -1470,18 +1594,18 @@ msgstr "" "*참고: 파일 전송 API 기능은 클라이언트 시작 및 서버 시작 전송 모두에 대해 명령 처리기에서 호출되도록 설계되었습니다. 전송 " "포트, 클라이언트 연결 및 실제 파일 데이터 전송 작업의 조정을 처리합니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 -#: 666eecd4aa974e2d8b5b9a1ff3acbc25 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:891 +#: 0fcf1a7def3e437d9ecbaf8d5d02470a msgid "Client-to-server transfer flow:" msgstr "클라이언트-서버 전송 흐름:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:815 -#: f6b96397ab484021974c50cf86144a12 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:893 +#: 740bd9ad4564417e8f76f28500d1da68 msgid "The client sends ``/file`` or ``/file_folder`` to request a transfer." msgstr "클라이언트는 전송을 요청하기 위해 ``/file`` 또는 ``/file_folder``를 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:817 -#: d6b57e1e1e6e4ea78d59d9a47a1a4ccc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:895 +#: e26bd8a6fb5a4977a3039fd2bdf22114 #, fuzzy msgid "" "``handle_command`` starts a dedicated file-server thread: " @@ -1492,8 +1616,8 @@ msgstr "" "``handle_command``는 ``file_transfer_server_recv_server_start_thread``를 " "사용하여 전용 파일 서버 스레드를 시작합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:821 -#: 3ba05b4bc071401d959f68b7019c7aa3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:899 +#: e5ef46040255421fa92c6de33d976671 msgid "" "The server allocates an ephemeral transfer port with ``palloc`` and sends" " ``/server_file_transfer_port `` back to the client." @@ -1501,25 +1625,25 @@ msgstr "" "서버는 ``palloc``으로 임시 전송 포트를 할당하고 ``/server_file_transfer_port " "``를 클라이언트로 다시 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:825 -#: 9f8b5c7e3b8048c9b9ded191ecd70d6b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:903 +#: 6eaa70d4d985489e8f0e683baa6b52a1 msgid "" "The client connects to that transfer port and sends file metadata, " "including length-prefixed filename and file size." msgstr "클라이언트는 해당 전송 포트에 연결하고 길이 접두사가 붙은 파일 이름 및 파일 크기를 포함한 파일 메타데이터를 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:828 -#: 95c2b39e285840678adb522483da672b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:906 +#: 245d5d51d72a41ee86c9925ec1872e35 msgid "The server receives the file and writes it under ``received_files``." msgstr "서버는 파일을 받아 ``received_files``에 씁니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 -#: 8254cf417a46471ea770e4917e96b05b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 +#: 5ad02fbb498f483580e470b2f5291a53 msgid "Server-to-client transfer flow:" msgstr "서버에서 클라이언트로의 전송 흐름:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:833 -#: 69032201d7254006b52a86961f08530a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:911 +#: 341ba310459442de906ec90ad72a16d9 msgid "" "``file_transfer_server_recv_client_start`` is used to initiate outgoing " "transfers from server to a connected client." @@ -1527,15 +1651,15 @@ msgstr "" "``file_transfer_server_recv_client_start``는 서버에서 연결된 클라이언트로 나가는 전송을 시작하는 " "데 사용됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:835 -#: 408f93d233f44860a854950b3e60f8f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:913 +#: c5f727be6f954b9d87c3ebf0b8ae32ce msgid "" "The server sends transfer commands to the client socket and waits for the" " client to establish the file transfer connection." msgstr "서버는 클라이언트 소켓에 전송 명령을 보내고 클라이언트가 파일 전송 연결을 설정할 때까지 기다립니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:837 -#: 718dadb723164e65a2eb6fdcfb7d8420 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:915 +#: 88151618a44849269aea215557a4ca1c msgid "" "Folder transfers are performed recursively, with each file transfer " "respecting ``self.max_file_transfer_thread_num`` and the configured " @@ -1544,26 +1668,26 @@ msgstr "" "폴더 전송은 ``self.max_file_transfer_thread_num`` 및 구성된 세마포어 제한을 준수하여 각 파일 전송을" " 통해 반복적으로 수행됩니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:840 -#: f23efbda41cb40289b93c954f6d051b0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:918 +#: 4734f1f535e7485ca5c91b06dec65f79 msgid "Common file transfer helper methods include:" msgstr "일반적인 파일 전송 도우미 방법은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 -#: b86c426b7c8a46b59735ef1a6a0da725 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:920 +#: aaa12a7a9d3f4adeb08d59d5fbc9d131 msgid "" "``file_transfer_server_recv_server_start``: receives file data from a " "client." msgstr "``file_transfer_server_recv_server_start``: 클라이언트로부터 파일 데이터를 받습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:843 -#: 74859cc9d4a745d99225f6522b4455c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:921 +#: 404a990c105247b09e2f2d1716527269 #, fuzzy msgid "``file_transfer_server_recv_client_start``: sends a file to a client." msgstr "``file_transfer_server_recv_client_start``: 파일이나 폴더를 클라이언트로 보냅니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:844 -#: 78042f93790547a8a844087d3daf81b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:922 +#: 0ec7dfbbfb1644f1ad5c42a1b2a04dc9 #, fuzzy msgid "" "``file_transfer_mode``: performs the low-level sender-side transfer " @@ -1571,28 +1695,28 @@ msgid "" "key to a client)." msgstr "``file_transfer_mode``: 낮은 수준의 클라이언트 측 전송 핸드셰이크를 수행합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:846 -#: a03a3b41f63c4c7d8e6800e6e42c215f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:924 +#: 6056cfcc5fa740e58986f2e8ce900042 msgid "" "``file_transfer_mode_recv``: performs the low-level receive-side transfer" " handshake." msgstr "``file_transfer_mode_recv``: 낮은 수준의 수신측 전송 핸드셰이크를 수행합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 -#: 82f418a15fbf4c009e188c0fe656a483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:929 +#: e0dc9b775fb94f0ab2728b56c57f88bd msgid "Port allocation API" msgstr "포트 할당 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:853 -#: c041090f476c4f37a46fc7a3f49653cb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:931 +#: 9711bca31e6b464e940739ba262f5153 #, fuzzy msgid "" "The server allocation APIs allow you to allocate a new port for other " "servers. There are two kinds of port allocation modes." msgstr "서버 할당 API를 사용하면 다른 서버에 새 포트를 할당할 수 있습니다. 포트 할당 모드에는 두 가지 종류가 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:857 -#: 4fa11de65ebc4b51b83ea26802b43e3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:935 +#: 30e2a47526db46b29ef31b8730b5dd8a msgid "" "To change the port allocation mode, you can set the " "``is_hand_alloc_port`` argument on the server instance. When set to " @@ -1602,8 +1726,8 @@ msgstr "" "포트 할당 모드를 변경하려면 서버 인스턴스에서 ``is_hand_alloc_port`` 인수를 설정하면 됩니다. ``False``로" " 설정하면 서버 인스턴스가 자동 포트 할당 모드를 선택하고, ``True``로 설정하면 수동 할당 모드를 선택합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:863 -#: aaa3428304234c0f81e2f83ab0481f17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 +#: 2a3a8472358240aea19de918a8d83602 #, fuzzy msgid "" "We strongly recommend using the automatic port allocation mode, which is " @@ -1615,8 +1739,8 @@ msgstr "" "자동 포트 할당 모드는 수동 포트 할당 모드보다 간편하고 안정적이므로 서버의 기본 모드인 자동 포트 할당 모드를 사용하는 것이 " "좋습니다. 이 모드에서는 할당 API를 호출하면 '0'을 반환합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:870 -#: f9fbfedba34e4c3386442a9425b52a44 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 +#: 29df017de0bc4b399ebbe204db974707 msgid "" "*Note: The `bind` function in standard lib `socket` of the python " "executor, when input ``0`` to the port parameter, will automatically " @@ -1625,8 +1749,8 @@ msgstr "" "*참고: Python 실행기의 표준 lib `socket`에 있는 `bind` 함수는 포트 매개변수에 `0`을 입력하면 운영 " "체제별로 사용 ​​가능한 포트를 자동으로 할당합니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:875 -#: 4a1a578af0b14571a4180ebfc88073d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 +#: df4b1b82912e444c89fd2ea7adbec615 #, fuzzy msgid "" "The other port allocation mode is the manual port allocation mode, there " @@ -1637,8 +1761,8 @@ msgstr "" "또 다른 포트 할당 모드는 수동 포트 할당 모드이며, 서버에 대한 포트 할당 범위가 있습니다. 기존 버전에서는 포트 할당 범위가 " "충돌하여 예상치 못한 오류가 발생할 수 있으므로 동일한 호스트에서 다른 서버를 열지 마십시오." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:882 -#: d9301928a8f643868d7cc5852f986e0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 +#: c835077f32f6478a8c0ad000340fd11f msgid "" "The range of the port allocation is configured in the server settings. " "The minimum allocatable port is ``self.port-" @@ -1649,8 +1773,8 @@ msgstr "" "self.port_add_step*self.port_range_num``이며, 최대 할당 가능 포트는 " "``self.port+1+self.port_add_step*self.port_range_num``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:888 -#: 17b2666361504a0d8f5e10eb5fc9056a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 +#: 5ad5c89c89a141f2bb5c56e49b94bf1a msgid "" "*Note: The ``self.port`` is the ``port`` argument of the server class. " "The ``self.port_add_step`` is the ``port_add_step`` argument. And the " @@ -1660,13 +1784,13 @@ msgstr "" "``port_add_step`` 인수입니다. 그리고 ``self.port_range_num``은 ``port_range_num`` " "인수입니다.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:894 -#: fefbe2307beb49d083c05018a96a2f3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 +#: 8ea7c9e4e1ad46efb978d3d466a53db6 msgid "There are some relevant methods that can be used:" msgstr "사용할 수 있는 몇 가지 관련 방법이 있습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 -#: 60738ce1224042aa9b39f5e5feec0e95 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 +#: f9525c162a254de4b11de650677ffd79 #, fuzzy msgid "" "The `palloc` method allows you to get a port. When using this function, " @@ -1680,8 +1804,8 @@ msgstr "" "`palloc` 메소드를 사용하면 포트를 얻을 수 있습니다. 이 기능을 사용할 때 할당 모드 감지기가 이 메서드에 이미 구현되어 " "있으므로 포트 할당 모드에 대해 걱정할 필요가 없습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:919 -#: 54ccf91661524b1487fb666243fb627a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:997 +#: dee22bb387e140e9ae43d6ebc9afbd58 #, fuzzy msgid "" "The `pfree` method allows you to free a port. Like the `palloc` method, " @@ -1691,8 +1815,8 @@ msgstr "" "`pfree` 방법을 사용하면 `palloc` 방법과 마찬가지로 포트를 해제할 수 있으므로 이 방법을 사용할 때 포트 할당 모드에 " "신경 쓸 필요가 없습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:923 -#: f4a62c2b675845148f52b3437e9c151e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1001 +#: 6bd53cf6dcea462fbad9ca450e42eec4 msgid "" "And there are the main functions for you to call, and for more " "information about the port allocation functions, see the :ref:`tcp-" @@ -1701,8 +1825,8 @@ msgstr "" "그리고 호출할 수 있는 주요 함수들이 있으며, 포트 할당 함수에 대한 자세한 내용은 :ref:`tcp-server-port-" "allocation-api` 섹션을 참조하세요." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:927 -#: 9aead9c3ede94037a42b4f83a45b3bb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1005 +#: d158c9d060c14aa39d042757684d6131 msgid "" "This mode is useful when you need an individual port for the server or " "must reserve a controlled range of ports for client-file transfers by " @@ -1712,251 +1836,291 @@ msgstr "" "이 모드는 서버에 대한 개별 포트가 필요하거나 테스트 환경이나 여러 서버 프로세스가 동일한 호스트를 공유하는 경우와 같이 수동 포트" " 할당을 통해 클라이언트 파일 전송을 위해 제어된 포트 범위를 예약해야 하는 경우에 유용합니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:934 -#: bad6d4dc4cdb4524b686b936a219637d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1012 +#: e51f806efbae4f9daf44365d182f21fa msgid "TCP Server APIs table" msgstr "TCP 서버 API 테이블" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:936 -#: 7d833bb126d34e528b706e8bf0e8a755 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1014 +#: c07f101dcc584239b2a4a7532c1ada42 msgid "In short, the table of contents of the public APIs are as follows:" msgstr "간단히 말해서 공개 API의 목차는 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:939 -#: 665b3f99a31a46a1af942df11ae56b08 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1017 +#: 66d85143ceff487f9620241fa1391d21 msgid "The server setup APIs:" msgstr "서버 설정 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:940 -#: fadd7d9d1d664608bca880a41e9ea51d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1018 +#: 904c44d78ca84c5cb7b595c6d360b2df msgid "`TCP_Server_Base`" msgstr "`TCP_서버_베이스`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 -#: 53e896a56ad44c29b03df161113e8d24 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1019 +#: 5da37cfc4922407dab0d65df73991067 msgid "`start_TCP_Server`" msgstr "`시작_TCP_서버`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:942 -#: 80dc73e7ae064470b60bf81cf731b1a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1020 +#: 6e0f0866c62749239469bceea81ae727 msgid "`stop`" msgstr "'그만'" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:944 -#: bad96f05bf9741c3a015b46ddb0c5485 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1022 +#: f84f11b7394147a9802c7de69d1d99e5 msgid "The server handling information APIs:" msgstr "서버 처리 정보 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:945 -#: c11c56f2f920425cb0f8a796ba8436ae +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1023 +#: 0ee5a3ad2c3643b9b85c813b5a5ba4be msgid "`handle_client`" msgstr "`handle_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:946 -#: 601d3f32dca44ce0aa8f90496fa82683 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1024 +#: 803b7f781de04d00ae128d89b0350cf5 msgid "`handle_command`" msgstr "`handle_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:947 -#: a95b98f525c44f8e99aa1ce37d14521c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1025 +#: cb9095dd05b24093984b4609ee0bb8b6 msgid "`receive_message`" msgstr "`receive_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 -#: b4d6756915c3424eac84ee276c68ec48 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1026 +#: c40a11b2d9b34f389fce8bc6d8076ab2 msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:949 -#: 5458006437d24bb68711e2523f7d7cba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1027 +#: 3c4a73128c044a38bac0b64d6551f512 msgid "`broadcast`" msgstr "'방송'" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:950 -#: e87f4ae0d0284a778641c6198ee918fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1028 +#: 16f4acaa490c4ec7afbd88fb3b50f62c msgid "`send_msg_to_specific_client`" msgstr "`send_msg_to_특정_클라이언트`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:951 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1029 +#: 2ad09a3887894e01a67d31c28272f730 #, fuzzy msgid "" "`console_input` (only started when ``is_input_command_in_console`` is " "``True``)" msgstr "``is_input_command_in_console``: 기본값은 ``True``입니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1031 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 #, fuzzy msgid "" "2.1. The inbound event listener APIs (see :ref:`tcp-server-event-" "listener-api`):" msgstr "서버 암호화 채널 API(:ref:`tcp-server-encrypted-channel-api` 참조):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:954 -#: e0409b880c784bc4a8cb876315709114 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1032 +#: 6f0e5784864d4f62b0fd68d41a8105c4 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:955 -#: 2dea82fdc0a04600801da255ef214a2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1033 +#: 647c22de04784b0c97bbc829edf1e2b3 msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:956 -#: d90982abe8e24aefb021d1bdb6cb8ca8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1034 +#: 8fc8a08031dd48eba706b833414ef995 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:958 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1036 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 msgid "" "The server encrypted channel APIs (see :ref:`tcp-server-encrypted-" "channel-api`):" msgstr "서버 암호화 채널 API(:ref:`tcp-server-encrypted-channel-api` 참조):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:959 -#: 0164b9a39ec64638b0951431e562f5c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1037 +#: 67ad7bf1d5754801a36a114c86e650f9 msgid "`_crypto_on_client_hello`" msgstr "`_crypto_on_client_hello`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 -#: 35472e2955b24167aadb9aa8587b2674 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1038 +#: e2ec1fc9abbc4a1389e8df768c33e7c8 msgid "`_crypto_wait_server_ready`" msgstr "`_crypto_wait_server_ready`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:961 -#: 2e8d4e8d8741462e8e6a6b36b36e0c07 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1039 +#: e3987c4ee8ae4d79b0aafb035a806494 msgid "`_crypto_push_pub_to_client`" msgstr "`_crypto_push_pub_to_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:962 -#: b7eb540259ae4240ba76640b6afd72b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1040 +#: b1829201e7fe4428b9689b03e50374bf msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:964 -#: 9265fbd06c8a43fc972c1010a348684d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1042 +#: c875b30243a24ac4923a442613a677e0 msgid "The server command APIs:" msgstr "서버 명령 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:965 -#: 6c53a87d79a749ffa1e2a93231037ac1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1043 +#: 5d011d31b13d446f814fd6bd5e63efce msgid "`register_command`" msgstr "`등록_명령`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 -#: 30a77ceac778437989abfaa0a23c1f4a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1044 +#: 2f117382a2154410989fb34342460f8b +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1045 +#: ffa5682de7884beb92ad1259ff1b8dd2 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:967 -#: 1940d4e8daf143e9ad1c971530233180 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1046 +#: cf39c195db7c41caa0f01bd982276547 msgid "`submit_task`" msgstr "`제출_작업`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:968 -#: f2448f5089ba44458298a4194c2795f0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1047 +#: 85f02dafa5374a7b89e8bd8a65e54b19 msgid "`create_temporary_server`" msgstr "`생성_임시_서버`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:969 -#: 097562a3555e413385ee95ded3a46118 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1048 +#: 2f117382a2154410989fb34342460f8b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:971 -#: af034155f20a44b79b9c6ec49fc189aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1050 +#: 0131ddf38e824d959a1d61148155ae0d msgid "The server file transfer APIs:" msgstr "서버 파일 전송 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 -#: 9cbb9edbc9574de99f8168bf2df7df03 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1051 +#: 7483d578f02a4babb71dda0efb204b61 msgid "`file_transfer_server_recv_client_start`" msgstr "`file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:973 -#: fc70c45345764fb2aa8bc3d71f927248 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1052 +#: c2cf0a257e2543478df2dccdf52fdb00 msgid "`file_transfer_server_recv_client_start_thread`" msgstr "`file_transfer_server_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:974 -#: c1918a177fcf47cbb881d7e14300776d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1053 +#: 187f0ce4a65e41adb7ee99b021de4d2b msgid "`folder_file_transfer_server_recv_client_start`" msgstr "`folder_file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:975 -#: 6f61085c3cb24ae298dc0eadbe113f6c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1054 +#: be99cf24a4ae4f03b5472d8ee3412889 msgid "`multiple_file_multiple_client_transfer_server_recv_client_start`" msgstr "`multiple_file_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:976 -#: 46d60103b77c4de19be1ac4a12d4331b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1055 +#: ea76c872d16c4a709ec52ab7415e40a0 msgid "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" msgstr "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:978 -#: 565a0271f5ed4b679a742f7677ed9e63 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1056 +#: 6056cfcc5fa740e58986f2e8ce900042 +msgid "`file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1057 +#: 8df3552dd5ae41a4b3020c15ebe8509d +msgid "`forward_item_to` / `forward_message_to`: single forward destinations" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1059 +#: ad8e7d49e5294f5b976ae225ccb67d22 +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1060 +#: 92ba3cd2c6004b60abe5976efa845d76 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1061 +#: 8cee01b7bbd1439b81f24891d7149fa4 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1062 +#: f5615a6934a141c9aa2bb01bcab9aea0 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1063 +#: 187f0ce4a65e41adb7ee99b021de4d2b +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1065 +#: 944bb0f890764ad7a62584cc73782927 msgid "The server console commands:" msgstr "서버 콘솔 명령은 다음과 같습니다." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:979 -#: e79a38bbae1d44e5b9e7b3e939b42e14 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1066 +#: e85b5444c86048cfa691dc42bb7c9f88 msgid "`/stop`" msgstr "`/그만`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:980 -#: 98cb7e67ddc64c7e91c8f445d3d7b601 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1067 +#: 7250fb98f32f47d4b6204ceb5f93f550 msgid "`/status`" msgstr "`/상태`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:981 -#: ec1899e60fc1456ba2117f7b0bf676e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1068 +#: 48237f11d42c41e392b282787896bd00 msgid "`/clients`" msgstr "`/클라이언트`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:982 -#: 0bb68238715a4e889bef60bf524c996a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1069 +#: 65fddabf6eec444fa89598e10a43f63f msgid "`/send_msg`" msgstr "`/send_msg`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:983 -#: 4c5dc721d573437385383ec46f76658a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1070 +#: c53a3810c2784772a6cb72f993ae8b4d msgid "`/file`" msgstr "`/파일`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:984 -#: 4fca7dce90044c119e5722297774fabe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1071 +#: 57d39ac1201f4866a57b5d291385d207 msgid "`/file_folder`" msgstr "`/파일_폴더`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:985 -#: 29fe035c678b49ef80321587017ba483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1072 +#: 2cbc4a81ca0548d4aa183c2ad034ab6a msgid "`/multiple_file_multiple_client`" msgstr "`/다중_파일_다중_클라이언트`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:986 -#: ba4e2c65e7034bd8a7a278697b76e8a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1073 +#: ce0f96a7a5e24b3cab89623df65ac40f msgid "`/diff_multiple_file_diff_multiple_client`" msgstr "`/diff_multiple_file_diff_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 -#: 97c3c838cb784a729fc52242a89f7156 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1074 +#: a9bffb7745c94e7cb45f4fc030c00da3 msgid "`/help`" msgstr "`/도움말`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:990 -#: 0b5cb5ab31e648b99f176a269cbad11e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1077 +#: 2d084d51c4c44ebda431944babb6c256 msgid "See Also" msgstr "참조" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:992 -#: d85e9537bf8e453ea2d533f25e659d2a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1079 +#: aa497d5f407a4e439cd10a4de1e24b05 msgid ":doc:`TCP_Client_APIs` — TCP client." msgstr ":doc:`TCP_Client_APIs` — TCP 클라이언트." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:993 -#: 1893e2b71add4e0ba8840ea169e0b102 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1080 +#: e1e5363e891e4e68855f9b021bbd4abf msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 끝점." @@ -2213,3 +2377,54 @@ msgstr ":doc:`UDP_APIs` — UDP 끝점." #~ " ... ...``: 다른 " #~ "클라이언트에 다른 파일 목록을 보냅니다." +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "핸드셰이크는 무작위 세션 nonce를 교환하고, 유선의 모든" +#~ " 암호화된 라인은 이를 연결당 시퀀스 번호(``||``)와 함께 전달합니다. 수신자는 " +#~ "nonce가 현재 세션과 일치하지 않거나(이전 연결에서 재생된" +#~ " 암호문) 시퀀스 번호가 예상한 것과 다른(세션 내에서" +#~ " 재생된 암호문/순서가 틀린) 줄을 삭제합니다. (재)교환 " +#~ "후 소켓이 암호화 모드로 전환되면 두 카운터가 모두" +#~ " 재설정됩니다." + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(client_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to the " +#~ "command handlers instead). ``add_file_listener`` " +#~ "registers ``listener(client_id, full_path, name, " +#~ "size, command)`` and fires after a " +#~ "file uploaded by a client has been" +#~ " fully written to the transfer " +#~ "directory (``command`` is the wire " +#~ "command that triggered it, so protocol" +#~ " pushes such as ``/crypto_pub_key`` can " +#~ "be recognised). Both listeners run on" +#~ " a protocol thread, so they must " +#~ "not block, and an exception inside " +#~ "a listener is logged and swallowed. " +#~ "The ``remove_*`` counterparts unregister a " +#~ "listener and ignore unknown ones." +#~ msgstr "" + +#~ msgid "" +#~ "``/forward_item``, ``/forward_send_msg``, " +#~ "``/pause_trans``, ``/start_trans``: internal " +#~ "forwarding/transfer-control messages." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po index 8b9998c..4129fca 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-16 11:10+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -19,11 +19,71 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../api/PyFlow.command_control_extension_tcp.rst:2 +#: ../../source/api/PyFlow.command_control_extension_tcp.rst:2 #: a6084f2941f34f579f28c55e9dfb768d msgid "PyFlow.command\\_control\\_extension\\_tcp module" msgstr "" +#: 9209095513ec402980427a0ddd988219 PyFlow.command_control_extension_tcp:1 of +msgid "Command-control extension for the TCP protocol." +msgstr "" + +#: 47d5c98c564241a6911eff0abea987ec PyFlow.command_control_extension_tcp:3 of +msgid "" +"One command batch, run by every listed client, with each client's output " +"collected on the server:" +msgstr "" + +#: PyFlow.command_control_extension_tcp:6 b14c7eec72b44dc1bd343997acf1cf44 of +msgid "/command ... ... " +msgstr "" + +#: PyFlow.command_control_extension_tcp:7 fe2fb5a737534088b175ea340c1763f9 of +msgid "" +"typed on the server console. Every client runs the whole command list in " +"a single shell session, in order, so state such as a changed working " +"directory carries over from one command to the next: ``/command \"cd " +"/path/to/search\" \"ls ./\" \"(ip, port)\"`` lists the files of " +"``/path/to/search``, while sending ``cd`` and ``ls`` as two separate " +"``/command`` lines does not." +msgstr "" + +#: 29a70dd76bf34e90a9ea54ac27202289 PyFlow.command_control_extension_tcp:14 of +msgid "" +"Commands come first and client addresses last; every address is written " +"as a Python address tuple, e.g. ``\"('127.0.0.1', 3000)\"``. There is no " +"limit on the number of commands or on the number of clients, and every " +"listed client receives the same command list. Two internal commands carry" +" the log back:" +msgstr "" + +#: 9ef58aea395a436382e23f39797e3e8e PyFlow.command_control_extension_tcp:19 of +msgid "/command_log_chunk " +msgstr "" + +#: 3361f3fb70584140989542af7c3361a7 PyFlow.command_control_extension_tcp:20 of +msgid "" +"sent by the client after it uploaded one log chunk through the file " +"transfer channel; the server appends the chunk's entries to that client's" +" log file" +msgstr "" + +#: 2563d4e4d9744c2fb16d84690c2e94e2 PyFlow.command_control_extension_tcp:24 of +msgid "" +"sent by the client when the batch is over; the server merges every " +"collected log file into ``merged_logs.json``" +msgstr "" + +#: PyFlow.command_control_extension_tcp:27 e40a302503cb4bdda5420aa79d0c57eb of +msgid "" +"A client captures the output of the running commands and uploads a chunk " +"every ``_LOG_CHUNK_BYTES`` of captured output (a smaller final chunk " +"closes each command), so a command that never stops is still tracked in " +"real time. Every chunk is appended to the same log file - " +"``logs__.json`` in the server's ``logs`` directory - which is " +"therefore never re-sent and never rewritten, only extended." +msgstr "" + #: 9209095513ec402980427a0ddd988219 #: PyFlow.command_control_extension_tcp.setup_server_commands:1 of msgid "Register the control-extension commands on a server instance." diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po index aed7f51..c2cec42 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -20,156 +20,155 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.connect_tcp.rst:2 -#: 59f41330dfa54a88831a20f4dc97c0f6 +#: 1e4cd09ce3ef45ceb95b8eb81eb7493b msgid "PyFlow.network\\_api.connect\\_tcp module" msgstr "" -#: PyFlow.network_api.connect_tcp:1 dca225f091cb4dd1810a8bd04c3a5004 of +#: 25b88cdb337c44539a843c674ba6825b PyFlow.network_api.connect_tcp:1 of msgid "" "TCP transport for PyFlow: the server and client base classes and the wire" " parsers." msgstr "" -#: PyFlow.network_api.connect_tcp:3 d5888d829f2e4850926eb364ede4678e of +#: 1f1482fc5c2849a68f34c74a8b55ab79 PyFlow.network_api.connect_tcp:3 of msgid "" "``TCP_Server_Base`` accepts connections and dispatches inbound lines; " "``TCP_Client_Base`` connects, sends and reads on the same conventions:" msgstr "" -#: PyFlow.network_api.connect_tcp:6 bd065af9d94b44298f9716ca96809b8c of +#: 104e5170c1c34bf9ad719f896e0c4226 PyFlow.network_api.connect_tcp:6 of msgid "" -"one message per line, terminated by a newline; a line that starts with " -"``/`` is a command and goes to the command handlers, anything else is a " -"plain message reported to the registered message listeners;" +"one message per line, terminated by a newline; every inbound line is " +"reported to the registered message listeners (commands included), and a " +"line that starts with ``/`` is then dispatched to the command handlers, " +"anything else treated as a plain message;" msgstr "" -#: 91ea1db95e554f2fbd2c1e92eb2d1353 PyFlow.network_api.connect_tcp:9 of +#: 6c6c01958e5741e080edcb804b4d12d1 PyFlow.network_api.connect_tcp:10 of msgid "" -"an RSA-encrypted channel is negotiated right after connect unless " -"``is_enable_encrypto`` is False;" +"unless ``is_enable_encrypto`` is False, an encrypted channel is " +"negotiated right after connect: the handshake lines and the public-key " +"pushes stay plaintext, then every later message travels as a frame (RSA-" +"OAEP for small text payloads, an ECDH-keyed AES-GCM seal for everything " +"else, including file data), and each file/folder transfer sub-connection " +"is framed the same way once both sides hold the session keys (see " +"`_SecureChannel`);" msgstr "" -#: PyFlow.network_api.connect_tcp:11 dfcece05b6774c5496b99d6c08039fce of +#: 9702905f1f8a4750905b2ffb96f99ec8 PyFlow.network_api.connect_tcp:16 of msgid "" "file/folder transfer, message forwarding and port allocation are layered " -"on the same socket and share its command namespace." +"on the same socket and share its command namespace;" msgstr "" -#: 89db462eaa88489c9390ddfa67a77a73 PyFlow.network_api.connect_tcp:14 of +#: 3488995e2a8349a58393d9f2d1155b99 PyFlow.network_api.connect_tcp:18 of +msgid "" +"an interrupted transfer is resumed after a disconnect: both sides persist" +" their transfer stores under the protocol's ``.Flow`` directory and the " +"receiver asks the sender to continue the file from the bytes already on " +"disk (``resume_transfers``; the wire lines are ``/resume_trans`` and " +"``/forward_resume``)." +msgstr "" + +#: 4cc5743bdfe54148ad38f54f10e688c9 PyFlow.network_api.connect_tcp:24 of msgid "" "The forwarding extensions use the module-level parsers " "`parse_forwarded_message`, `parse_forward_items_and_addrs`, " -"`parse_forward_originator` and `forward_skip_message`." +"`parse_forward_originator` and `forward_skip_message`; the reconnect " +"logic uses `parse_resume_command`, `parse_forward_resume_command` and " +"`_resume_offset_for`." msgstr "" -#: 98c270e82fa8468487e1b4d25bab8c0c PyFlow.network_api.connect_tcp:18 of +#: 49796529cb7f49ee8131b257212b5420 PyFlow.network_api.connect_tcp:30 of msgid "" "Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and " "``TCP_Client_APIs.rst``; argument, return and exception contracts live in" " the docstrings below." msgstr "" -#: 76126c02e928423b89dc4662d9a190f2 +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_resume_command:1 of +msgid "Split a ``/resume_trans `` line." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 14dcda8b059b480982e3fb03399e665b 99035a24f6e94207b84545f8c71a451e +#: cb62202c244d4c08974c674c13a02dca +msgid "Returns" +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_resume_command:3 of +msgid "``(fid, offset)``, or None when the line is malformed." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 19eb6fca79324b0791f8ec7488a5246c +msgid "Return type" +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:1 of +msgid "Split a ``/forward_resume `` line." +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:3 of +msgid "``(target, fid, offset)``, or None when the line is malformed." +msgstr "" + +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:5 of +msgid "``(target, fid, offset)``, or None when the line is" +msgstr "" + +#: 4ead8d8f93644adeb812150e760f7792 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:6 of +msgid "malformed." +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 #: PyFlow.network_api.connect_tcp.parse_forwarded_message:1 of msgid "Split a ``/send_msg_from `` relay envelope." msgstr "" #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0e9ae2e0bd0c44da835c0999abec5f08 1aaf58afc7f043919f411c02d435031d -#: 1c819a8207464e439fd4675d1b823409 1d2cff780d6642deb6ab5fbf32c34185 -#: 1e24bfa274504842b67c3cb0c7a37118 26160724c12740ecbe3cc707bc46c197 -#: 2edb81613e9c4bd0949f5d6efa1a542f 30a7ccf5e56e4640a7a6e592d13a4f7c -#: 3514f6292626456eb4b0c31a30e24cf5 38d82b9bc4414212a8458de940d3b69b -#: 406f1bd372c14cd897f0d2dc1fdc8fd7 4400798a6d9d41a89b686b015f53a454 -#: 54f261fe47134a9494f12b5053492006 5e9d8d1799714d389a6fd79edd0e5bac -#: 6239fd721a0f476aaf509ab580317c75 6658645eabff4ba6b0b326727f89a4f1 -#: 6f375e9a65e04034a4fd1475f3073e42 70b19bc5e5da467dbbae99d81fe54ed7 -#: 79e2d4be536b429cbbfe5016df915b72 7c3cf59acfe34a15a6c920a0f58ec56f -#: 822df543855349c2993aabd5596b5383 8245849b603f4313a3ea2423abd5c899 -#: 83eba13f6fae4ded929924151baa0c52 9449c184a2e145909d2e1f114534253d -#: 9a393c8c90d0446a97c34af1c173f83d 9cdc7d0b4bc2400498e9c57ed16ba459 -#: a2ddcff09d1641b5b269ec31031008f9 a5cbf7c6c5b0494b8652be7d28a7b3d1 -#: a9ec9ede7c8144ddb920261d29edc23d b5b42f99934e4b0b939671c6fb08f748 -#: b630deb98dea40c28f1cb88dcbfdb261 b6e3a01b0f044a15a7d322c63f58c262 -#: bb3b7e5558c74c8eb287944b93b9c664 bd95cc8d5960426e92ad149ce0ecaeb4 -#: be47c4f21d4d4515be0684c6c1215c0c cdebf66a7b714ef39236c1dc9773c8f7 -#: d02c1be3236b424f87b75728f76d672c d5b3f5bf790c4fc6aefb763d9c473474 -#: da6cef9244b1429881584994b097c71a e98998d054b74d0e820367ea5de54d02 -#: ea4e1b708c2f409f89bf4ca2a6e4fbf3 ebca3c62590345118f3fe5a8d85ce154 -#: ebcdb45484b64f7f9023808632316025 efca1ecd18f440db9489b40ae6480409 -#: f7766cda09fd4c0bb6b565f5fa4a3688 fe80dd07199943c784dd488826f958b7 +#: 4fa9ba6e763440b8ab00832520b4d305 501a0caef71d436e84469bc1ef9c1e5f +#: 70d6dae11a144ed7b7e9d8e16dbf478c acdf8b3b266f4eccb6ceca17a110603b msgid "Parameters" msgstr "" -#: 35b277cd5b2249dc8b38c36654b1f75a -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 +#: e42a6166c82d4861b25cb55f587db28c of msgid "Received line, e.g. ``/send_msg_from ('127.0.0.1', 3000) hello``." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0cd9914c895f4b308548863df6d8c13c 113c57937f6f402da7758e74266680ea -#: 139720899e024d348d0b43b9af2b2ef7 2cb731c57fb64497a6424e4e51fe17bb -#: 30c59afde30c44428a97266ca87baa21 3f574beaf02948d599ffd8c50922e530 -#: 40e4cbf377a94cf8803c13b2f01dbc77 4aa76ebde46243b18f2a5d811d902d1e -#: 4d5706674a0c40a99769b5cfba21b29d 5518a67cc7364710b2b0c03f6de9de1b -#: 564a8841a88d40e0a44b1b0d72a0b3a4 56e96f344ac14995adeb056f90d3e39a -#: 638d047aee4d45a689f4a54f8d2be451 6e5db10681f24a01a208604d8de1ecf4 -#: 6ea11f9fd50e46f8aef42a25872d8d47 833d97bdb57049979db335d24819041a -#: a00fef59262447aa931fe606e260a7ab a9795b94ba634cb8a7dc1fd6a7e6f326 -#: b1a77959b26540128ea564370170744f b1e2a43372ac48fe9a367121a736eaee -#: b2f18766a5ec40d69bfd15b13fa54aa2 b963bb66a63649d5b5cc0ce3d852aab4 -#: c1bd9b5e40e644e3a1f1198e5d2247c2 d558170070474bcb9d798b72d878f185 -#: d86bf79c265c42ec969d2c8058f20a3c d906d179eca24642883fb6ff991399b8 -#: ddfeae931eb14b529e08b61ae9de5aaf ecb12ada91914625a7c5e9894b67886f -#: f8e1381487764684b80cbc9d8f6a511c fa2587a106c540d1a870afc4a3ae97b7 -msgid "Returns" -msgstr "" - -#: 24de94d25531410aa507869ac615529b -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 +#: f25d1962656c4f339805427e2573f84f of msgid "" "``(sender_id, payload)`` where ``sender_id`` is the sender's " "``\"ip:port\"``, or None when the line is not a well-formed envelope." msgstr "" #: PyFlow.network_api.connect_tcp.parse_forwarded_message:9 -#: f4818c7037924b089072be17dbe65cda of +#: d0d7af37e4134902ae64e10b2e43b4c1 of msgid "``(sender_id, payload)`` where ``sender_id`` is the" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 -#: e4ce35611cb240c382217f2166803af1 of +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 of msgid "" "sender's ``\"ip:port\"``, or None when the line is not a well-formed " "envelope." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f2c39309f3e47aa9157bf244f35d1e6 126027ff5c8b494e8223688394767c35 -#: 15e8f6af90d84f4c99e9a9706f995a3f 18eed5a02c0346f6966237e6812afce0 -#: 208eff4f470f474395ac42a58f179feb 308f9ffcdfe2443cb6fe0f3a79e7d4b3 -#: 30fd0d7f7d9547149d06568b9ae4b217 34500bb5a5ea4428ba3ba1f34f8555f3 -#: 357fa966af0e4661a01d3a18b3686c63 38f178d3602f47bcbf100a047fc22ccc -#: 4268152920654e59975b69aed4638761 43cc49d0a3b2478f8a24fcdea7c2ce78 -#: 448b06753df84443af4aae1dcb008d56 4530cc6fc87d4dbcb79dd0e90ea83694 -#: 496c6102672e49fc96cd7210ed1ec602 502647c8224842608ded5058bf1c6748 -#: 574093f9f9054b898b9ab8b20a239a40 5882a32ac8a34ab7b568b256092e1aca -#: 73e564d3b91d42388f95effb067d6218 7f2f462183d442c98c624d6750d86319 -#: 8203a323a9af48edb0f9e91ca6260ed6 87a376020e0a47fb90cc4f2d9b045d7c -#: 8f12aa18be1a4aaf97b8db14f282a929 a61c3c1917b8486bad659991683c48cb -#: a9e445f3a3094e3bb7957551bcf7fd21 c0afcff99bfc47f3ba7a3f0b3e836444 -#: c4d251b617f2419cb1093f6896b14cb8 d4bc332ce5f34c61b3105fb392b302e5 -#: e9a98b5852d84cf4939d9ea0f17b038c f17ca1aa780b447cb305e1db1c181efb -msgid "Return type" -msgstr "" - -#: 1ad7def88bd34ce7accca28c4d123b79 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 +#: f22254d8ca2d47ad8bc9c98664369d61 of msgid "Split forward-command tokens into items and destination addresses." msgstr "" -#: 67578e526f0b4dfc924c46a44e7bea78 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 +#: b207f60051004834bab91ba392a88437 of msgid "" "A token of the form ``('ip', port)`` is a destination, everything else is" " a forwarded item (message text or a path). Used by the native message " @@ -177,252 +176,326 @@ msgid "" "extension." msgstr "" -#: 18a87e9cbc124ce5a6f91d61a72fc6de +#: 5329fb72f5954768a6cec05ff4cccfea #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:7 of msgid "Tokens after the command name." msgstr "" -#: 0e46577c966b41c4ad6f0aea95fd7e5c +#: 2aebf669048046ddb279a935bcfcfde4 #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:10 of msgid "" "``(items, addrs)`` in the order given; ``items`` holds texts and " "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 608bcdb865a94f869885cd560de7012e +#: 96b96bd19fe94312bddf340fad073cbc #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:12 of msgid "``(items, addrs)`` in the order given; ``items`` holds texts and" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 -#: e8c390dc356e4be9bb2f52cd0540e859 of +#: 8e82954621d748e2b412952a7fb2753b +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 of msgid "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 0e422066050d4ba18799efa53c6b771e -#: PyFlow.network_api.connect_tcp.forward_skip_message:1 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:1 +#: a51324658c7943158d90ed706cecc41d of msgid "Build the console notice for a forward destination that cannot be served." msgstr "" -#: 1eb2f924bcbc4e3783e3a4706c93052f -#: PyFlow.network_api.connect_tcp.forward_skip_message:3 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:3 +#: b541e8446e374bc8b38cd7912a1fa33c of msgid "Destination ``(ip, port)`` that is unreachable or is the server itself." msgstr "" -#: PyFlow.network_api.connect_tcp.forward_skip_message:7 -#: b7ceaa070f754fe88242c2b495b3ff9f of +#: 10e03f21d05e478d9cde0c7176f6e1b8 +#: PyFlow.network_api.connect_tcp.forward_skip_message:7 of msgid "One-line notice for the console." msgstr "" -#: 59d83fde0d964794ba76d45749bfc021 +#: 8005e532fe9d491ca8ddd996889d605d #: PyFlow.network_api.connect_tcp.parse_forward_originator:1 of msgid "Extract the originator's ``\"ip:port\"`` from a received transfer command." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 -#: b91ee97cb2574a19b8c87c99bf8ca181 of +#: 2cf3052a89c645e782430f1f05fb37a1 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 of msgid "" "The server's forward relay tags every pushed ``/file`` and " "``/file_folder`` command with the forwarding client's address tuple; a " "direct send carries the receiver's own address instead." msgstr "" -#: 20da4b9824cd4fd6bb0ef55ebc38158b +#: 335f6c1b16104395ba38a33188943d8a #: PyFlow.network_api.connect_tcp.parse_forward_originator:7 of msgid "Received transfer command." msgstr "" -#: 9f25fa22a7b14822b8cbc1fd929976b9 -#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 of +#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 +#: e5bd1024ad3f47f19cafc4c83a844b60 of msgid "" "This instance's own ``\"ip:port\"``; a command carrying it is a direct " "send and yields None." msgstr "" -#: 6455c3bb288d4239811cb0104086c0fa +#: 65469492f844448fab269b701cbdb704 #: PyFlow.network_api.connect_tcp.parse_forward_originator:13 of msgid "" "Originator ``\"ip:port\"``, or None when the command carries no " "originator (direct send or non-transfer command)." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 -#: a466d04757ec40f1a2888518b8fb1d9a of +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 of msgid "Originator ``\"ip:port\"``, or None when the command carries no" msgstr "" #: PyFlow.network_api.connect_tcp.parse_forward_originator:16 -#: da8c46fb38624c7d97d91970aee4667c of +#: a2d34276c4f54c69981f9b51f36cc31d of msgid "originator (direct send or non-transfer command)." msgstr "" -#: 201f6bd5376a4ebaa7488dd3b58197c0 +#: 31646cd2d4f049a38b7910ac6836d2f9 +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:1 of +msgid "A command passed to `call_extension_functions` is not registered." +msgstr "" + +#: 42bee6e5f57b43cba7c5b4c4a1769e9a +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:3 of +msgid "" +"Raised when the first token of the command matches no handler registered " +"with `register_command`, on either instance class." +msgstr "" + +#: 7297b41c47664243b9677b32e21de07e #: PyFlow.network_api.connect_tcp.TCP_Server_Base:1 of msgid "TCP server: accept clients, dispatch commands, relay messages and files." msgstr "" -#: 4f7013d76f9d447b974f22cca228ba0f +#: 0d632c9f5b234888a691b03ade8ff7da #: PyFlow.network_api.connect_tcp.TCP_Server_Base:3 of msgid "" "Each accepted connection is served by `handle_client`, either in its own " "thread (the default) or by a coroutine on an asyncio event loop when " -"``is_asynic_clients_io`` is True: a line starting with ``/`` goes to " -"`handle_command` (built-in commands plus the handlers registered with " -"`register_command`), any other line is a plain message delivered to the " -"listeners registered with `add_message_listener` and stored in " -"``messages_dict``." +"``is_asynic_clients_io`` is True: every inbound line is delivered to the " +"listeners registered with `add_message_listener` first; a line starting " +"with ``/`` then goes to `handle_command` (built-in commands plus the " +"handlers registered with `register_command`), any other line is a plain " +"message stored in ``messages_dict``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 -#: fd2aa2103a434e7b84e9f5300dfb2637 of +#: 2870b0163d68487daf7526e91eb49ff6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 of msgid "Address the server socket binds to." msgstr "" -#: 0887ce96e330478f83984d935911cd2b 13fa6bd77a314fcbae42aeef584d47b6 -#: 1d012f62b99a4b0d8802295d814667dd 1d5b594e02824d74b812b69dc7b34a88 -#: 3b8af6dc474d493eb9749cb07384c5d1 4916b5bac8044e249473dae03d0af5e5 -#: 6a138e9d5ed24b6b9a9f213ffa6d07bb 7c114dabd42344d790a98003f7d68a6a -#: 889f9fb97d4b483cbfd9ae6bbb3e1dbb 89e6193e8e8c45f3ba6d49b9ec578812 #: PyFlow.network_api.connect_tcp.TCP_Client_Base #: PyFlow.network_api.connect_tcp.TCP_Server_Base -#: a0a81405abb64b70834a292dfa52ea47 a32afd5e800648f08c2ed1582462900f -#: a4c849cfce9b4544a50162a1abd07ffc e953785e3c774cb783e506a118b6f5f9 -#: efd7bf86f2f3403a843bdc7079ed87ae f87fe645a0c846168779119b106eb83b of +#: cf754e752b6c445989b3301b807fc9eb of msgid "type" msgstr "" -#: 194d7e538b9142bb9cadf40639c7dfc2 8d779f308c7343fca45fb6b7c544b6f8 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: 568be916ae0340289a6569e718e7cbf2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:16 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:106 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:15 -#: a043713065174240b3b3cb2839829b42 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:100 of msgid "str" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 -#: eaf91e01d29744a4b66b30d163b14bd4 of +#: 6ac74cca7b0f443ca89f3d2c3bbe1aaa +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 of msgid "First port considered for binding and for allocation." msgstr "" -#: 143512a7a9624b79853380f79b9db5e0 6093b43271e041dfb256e660e61561c5 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 +#: 9ecf88c5193c470b98dc95d184c94f92 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:22 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:21 of msgid "int" msgstr "" -#: 0f4f0acdd1a64e9cb4eb06b5fc12103e +#: 6746407aac194c4880c7cbf82b7fa2fb #: PyFlow.network_api.connect_tcp.TCP_Server_Base:25 of msgid "" "Accepted connections keyed by ``(ip, port)``; each value holds " "``socket``, ``address``, ``id`` and ``connected_time``." msgstr "" -#: 6fcc166b59cb4ae7a6a6e30f2dbd2784 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 of +#: 7ba2aaf3fe4c42739121eb3ca2bcc79a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:89 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:98 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:92 of msgid "dict" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 -#: d85332af5e73403388989eacf82a251d of +#: 93556efee2aa445684af3fdc1532548a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 of msgid "True while the accept loop runs." msgstr "" -#: 0effb5fc02cf402ab9d27f4a51954fd1 168f4d3c8da74ebab98953585b27b866 -#: 21bd44747d4e4c9aa4a0afa0f559707d 3c8b6ad08eac44ba9eacbb2fb9752304 -#: 420ec28762864e58ad5f3a63f2811a0f 87eb97e54ef847398f653aa5b65b0191 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: 0ab0667a38254203929e173ab5024f1d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:40 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:46 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:52 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:58 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:65 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:72 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:79 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:34 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:41 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:47 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:53 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:59 -#: e1e2580e801a44cc962b509779f690fc f827c454ead24d7587ae4125b1f60fda -#: f8f0e0ce3c4841278a15e583a0ec5f92 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:66 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:73 of msgid "bool" msgstr "" -#: 62103bebe6fe47aa8a3830133baa0a70 +#: 9023ee78c5fe4680a3875c881abe3307 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:38 of msgid "" "Whether clients are served by coroutines on an event loop instead of one " "thread per client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:42 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 -#: c291fba3b400472996751ffdc24251b7 d0ade3e16cf044fca75a0e1bdf17038c of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 of msgid "Whether the RSA channel is negotiated." msgstr "" -#: 8bb4af4279e44eef8df452f4429780ff -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:48 +#: 3c5a67d3c5824c15b42b71fbadddf5d3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:51 -#: c9414c44325b4b5eaed34bf2a7e49ed4 of +#: a5ac1b25d44547ba836c5dc354438315 of msgid "Whether execution-process lines are logged as well." msgstr "" -#: 5bdaf96cd6894bc4a179ae3ddc66c29c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:54 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 -#: a50b56a084674a89bb56dd9791348a75 of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 of msgid "Whether the instance logs anything at all." msgstr "" -#: 75856a665d5045349622c29bee22fe17 +#: 3114d37d38af4cfcaa75397192202b93 62437fad8325442b91f177e93b8be7ef +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:62 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:63 of +msgid "" +"Whether every running file transfer is tracked in " +"``file_recv_progress``/``file_upload_progress``." +msgstr "" + +#: 58bd8f0892f044a583a276490dc2a7f5 855f8e2ee2a449398779d56b269628d6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:70 of +msgid "" +"Whether the real-time network speed is measured into " +"``upload_network_speed``/``recv_network_speed``." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:77 +#: afff1dd047f4479b84d46859c7da90b8 ce793576b862473cb130a29582aab5fd of +msgid "" +"Running downloads keyed by fid; each value is ``[received bytes, total " +"bytes, current speed, file path, peer]`` (the speed is None until the " +"transfer has moved its first chunk, and while speed measurement is off; " +"``peer`` is the sender's ``(ip, port)``)." +msgstr "" + +#: 36c2c0e7900d436a977b8895e671c9f0 659caaa0c8bc40d3a9ce8d0905787584 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:93 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:87 of +msgid "" +"Running uploads keyed by fid; each value is ``[sent bytes, total bytes, " +"current speed, file path, peer]``, with ``peer`` the receiver's ``(ip, " +"port)``. A forwarded transfer stores the original peer on both sides, " +"never the relay." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:96 +#: f9528e6c490d4807b949f6730c6ece8e of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when a connection drops and read back on the next reconnect " +"(``resume_transfers``)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:110 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:104 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second sent, or None when not measured." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:113 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:120 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:107 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:114 +#: d926b4f3eb4b40a4acb21f780a4dc227 of +msgid "float | None" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:117 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:111 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second received, or None when not measured." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:1 of msgid "Create the server and, unless extended, start accepting clients." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:3 -#: a2cce435d92d46e5b0b2cd59d43c8759 of +#: bf58d54a167d45de9a18641877ada912 of msgid "Address the server socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 -#: d4c7cd9cc01e4371961f0950fd861b12 of +#: 2f4d0c4bfd8246d4984d4c843510775d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 of msgid "First port to bind; also the base of the allocation range." msgstr "" -#: 716408a19bf349878edfd5f1948f57ec +#: 47138ce8f587467aa353e302f473df48 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:8 of msgid "" "Maximum concurrent clients served in thread mode; ignored when " "``is_asynic_clients_io`` is True. Defaults to 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 -#: c37fcc062f6947228f3dc0b85ec5a5ca of +#: 8786a9d2b6b449209be813778d785712 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 of msgid "Step between candidate ports. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 -#: e683b27a8b884c5b99511f99e20b6bf9 of +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 of msgid "Number of ports per step. Defaults to 100." msgstr "" -#: 6291e503f9bf4c78a9c226058a67bce1 +#: 973382c423524d44a569c318399e0b99 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:15 -#: e59cefed7c4e4148b863b89e4d17004e of +#: d5f8f341d98d478289d9a226f37c1003 of msgid "Concurrent file transfers allowed. Defaults to 10." msgstr "" -#: 792cebf4ce084bd9b222b9ee83eeb5f4 +#: 4fe9a7607dbc4eebbce4e62f9306c76f #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:18 of msgid "" "Reserve a port range across processes, so several instances on one host " "do not collide. Defaults to False." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 -#: befe96138f8544cbb8320f33af43af3e of +#: 8aa56addc6ae4a7790dc957d1e1c2b60 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 of msgid "Start the console command thread. Defaults to True." msgstr "" -#: 10c1ed53a097472297ade439439e218f 3bc54f27f3db4bce846f5ec756f0e68f +#: 242566ff64584fba88e4fed8bb189110 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:28 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:24 of msgid "" @@ -430,301 +503,440 @@ msgid "" " 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 -#: f0a3afe6bc0c4eb2ad2e9e5ae43e2d88 of +#: 87d1cd7d6569498b8af8bc7064235784 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 of msgid "" "When True, do not call `start_TCP_Server`; the caller starts the server " "when ready. Defaults to False." msgstr "" -#: 577dd2f594554ceab51324eaedf4b1b3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 +#: ac43634ddb1a4d15a9f3d0f58d011441 of msgid "" "Negotiate the RSA-encrypted channel for every connection. Defaults to " "True." msgstr "" -#: 1ea6dc3b1a34463881e1aa7e96a14525 +#: 1ffccca56902418ba98ee0c6776ad8fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:37 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 -#: ecd4aa80607e4f988ac59b64e85c8fbe of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 of msgid "" "``[pub_key_path, pvt_key_path]`` pair used instead of the default key " "lookup; an invalid pair is ignored." msgstr "" -#: 0b92e71977dc4312b9e31fab903eadf2 +#: 420bbdf8d6bb400fbd3548bea03354ac #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:36 of msgid "" "Buffering ceiling in MiB for the in-memory forward pump; past it the " "uploader is told to pause. Defaults to 2048." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 -#: e14dae3d183249e19a0f6cf671ead02b of +#: 94e4a7e67e3047fd9d565f9a5d8122ab 9dcb36b97a004812bbcf264efa812441 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 of +msgid "" +"Bytes read per receive on the control connection, covering commands and " +"messages. Defaults to 4096." +msgstr "" + +#: 116dc6d56dd44f4ebaab990a3658359d 397abb5fbc1a46db90a7829daac02465 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:42 of +msgid "" +"Chunk size in bytes streamed when sending or receiving a file or folder. " +"Defaults to 65536 (64 KiB)." +msgstr "" + +#: 446099293d824f27aed7245f3c77df69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:45 of msgid "" "Serve clients with asyncio coroutines on an event loop instead of one " "thread per client, so a single server can hold thousands of concurrent " "connections. Defaults to False." msgstr "" -#: 07311d6c7a2f4516a4209df5c7798be6 9f213be174d243d4af26f79ae9624945 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:44 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:50 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:50 of msgid "" "Log execution-process lines in addition to command and result lines. " "Defaults to False." msgstr "" -#: 28ea5071c3344615b114f12ad5be447c 497004294ca244138115a713c0ffed15 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:47 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:53 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:53 of msgid "" "Log at all; False silences every line this instance would print. Defaults" " to True." msgstr "" +#: 1608cb9ad7104c82a43f23bb929f7d84 744b24d9e233457fb87cc8faefc5a498 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:56 of +msgid "" +"Track every running file transfer in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads): each entry holds the bytes " +"transferred so far, the total size and the current speed (None while " +"``is_enable_real_time_network_speed`` is False). An entry appears when a " +"transfer starts and is dropped when it ends. Defaults to True." +msgstr "" + +#: 3658f6b3ec994d15b9321a10ae33b351 769ed811a0cb4b18aeacdd39e4b4bbe2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:64 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:64 of +msgid "" +"Measure the real-time network speed of every send and receive — the " +"control layer and every temporary connection (file transfers included) — " +"into ``upload_network_speed`` and ``recv_network_speed`` (bytes per " +"second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False " +"nothing is measured and every speed value is None. Defaults to True." +msgstr "" + #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f0e9eea68114cf3b085d08796aaf552 3f8c413bab284fb78ac0b2ef8b8fb44a -#: 4a7a4c0862a84c53b2ccf0de3b00d495 4c3773b74abf40118b9ed681d9bef66a -#: 9f4fa9dc8d5045e39702036409f07a5d aa175c9daeab453a848bb2ef9f2e3dcf -#: cf96ad3305794cd7b9578ecb55ecd8b9 fbbf706646e24207aaf3b2532903a31b +#: 63ab5a2f2327475ba324e245f8e6e2ac msgid "Raises" msgstr "" -#: 0c72321c656641a5b684299b915cbb39 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:52 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:51 -#: d72a9dcf6bc748e5898640448e229b3b of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:81 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:73 +#: ed59ec69b9a1430597e6d8758051aff5 of msgid "" "If the ``.Flow`` directories or ``decode_command_table.json`` cannot " "be created or read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 -#: e2bb545e7ee1419286f58495abc4bcd2 of +#: 031d3e96394c454093561375a377dcce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:1 of +msgid "Pause an outbound transfer of this instance." +msgstr "" + +#: 342e6dfc6f6a4399914bc72372aa5f2d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. A " +"forward relay's writer toward ``peer`` is paused the same way the " +"``/pause_trans`` line pauses it." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:3 of +msgid "Transfer id the outbound leg is keyed by." +msgstr "" + +#: 7ecc0c956c8b408688fca517eb6370fd +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:10 of +msgid "" +"Restrict the pause to the leg or relay writer toward this ``(ip, port)``;" +" None addresses every match." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:14 +#: bdee1944910b4ee3908cf225a151a5fd of +msgid "" +"True when a running leg (or relay writer) was marked paused; False " +"when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 99ba2aa702f74621ba4dd31b8c045467 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:16 of +msgid "True when a running leg (or relay writer) was marked paused;" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:17 +#: c85ed4c1a84443a98394146efcf04315 of +msgid "" +"False when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 2771724616054f628d60add2c7407e7b 3a0594b22c6849c88310243022e8ee23 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:1 of +msgid "Resume an outbound transfer paused with `pause_trans`." +msgstr "" + +#: 7a864ecc76fe40459eeff353522482fb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg or relay writer toward this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:9 of +msgid "True when a live leg (or relay writer) was resumed." +msgstr "" + +#: 364557403e3d480896c0ffc57a19df04 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:1 of +msgid "Ask a connected client to pause its transfer toward this server." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:3 +#: f13c2e0e5310443080b0f63c773d8497 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (see `pause_trans` on the receiving side)." +msgstr "" + +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:3 of +msgid "Connected client ``(ip, port)``." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:5 of +msgid "Transfer id of that client's outbound leg." +msgstr "" + +#: 5ea8eea489fc43108a439d54fba31068 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:8 of +msgid "True when the line was written; False when ``peer`` is not connected." +msgstr "" + +#: 38905ec7539d42e0839907c32dd8667f +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:13 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:10 of +msgid "True when the line was written; False when ``peer`` is not" +msgstr "" + +#: 1c7b88e29a0143a39e13441769186ef4 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:11 of +msgid "connected." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:1 +#: adfc486a05ae4063bda6a61f2a6f3c36 of +msgid "Ask a connected client to resume a transfer paused earlier." +msgstr "" + +#: 810bc26336b24ad1acba3f56d466f8e9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 of msgid "Reserve this server's port range under the cross-process lock." msgstr "" +#: 5540b6efb5864c188e080ec7aad5c3ca #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 -#: c9ae1464a03b44049e826b9b73e2aca2 d23fda91e3e645e081dd5bbd5332fc4c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 of msgid "No-op unless ``is_hand_alloc_port`` is True." msgstr "" -#: 0b8bb2090cd04385a9d960dd2808f5bc 55b8a82ae1ce4769a1c62b35d253810e -#: 6d17c5fb7b4d484ba017edb4c5d5535e +#: 356ed2e8333d49b98ed6834612b4b56d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 -#: c3818bbf57ac448cb073fb780326fdf7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 of msgid "Step between candidate ports." msgstr "" -#: 1080747700804d04ae169eef511d5bb5 45799e3c1b6e446a86b111e06365ca9b -#: 5bfd1aa496dc41b7ab2abd78f134c389 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:8 -#: efa8e8819eec4e1ba0d90562f34755b5 of +#: e18848eedc5d4d8abd97d73a0984a5d3 of msgid "Number of ports per step." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 -#: c1cf751ac2774558925ef1ffd1a6c3dc of +#: 11e0523d1b194702a07a92748468da25 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 of msgid "Release this server's reserved port range." msgstr "" +#: 801c063c5fa447bda1dbf7f5ccbc6a9a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_lock:1 -#: b2b2a77e9deb4423955004a9e3390aca of +#: of msgid "Create the lock file that reserves the server port range for this process." msgstr "" -#: 658bc1e35a794bf5a22c70ffbef94b87 +#: 672bb7a9496c43ac8b706a3d0062ddfd #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:1 #: of msgid "Report whether the server port range is reserved by some process." msgstr "" -#: 39bb21b4d3a0404fb64295a73c2ad5ba 5dc09f28266e4a3bb083923d8784f09c +#: 39423e052b70403ba07a713aa9e3cb4a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:3 #: of msgid "True while the lock file exists." msgstr "" -#: 6512b0b8da7041e8a917014e5562583c +#: 5b6cf828ffb24e098a0c86a09818da73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_unlock:1 #: of msgid "Remove the lock file that reserves the server port range." msgstr "" -#: 90520dc2f5704cdaba37211d6390b03d +#: 479bdf5518dc4a029ecf47ad44bdcd5d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:1 of msgid "Allocate the next free server port range and record it on disk." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 -#: cf0980ef8455426781e617a911f73732 of +#: 34c085a1bfca4dedafc749bfdcf14ad5 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 of msgid "" "``port`` is moved past the ranges already recorded by other servers, so " "the instance ends up with a range of its own." msgstr "" -#: 1e5f1ba9b8bf4d28971b92ef12f747f2 +#: 197b30e318d741c2b1f8afc925e91e5c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:11 of msgid "If the server port info file cannot be read or written." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 -#: bf4bb338fcf846a29910656081787945 of +#: 1c97c8ef484b42ab86d36b3742bf3879 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 of msgid "Drop this server's entry from the on-disk port range record." msgstr "" -#: 30208c231b534eedbe843d42a3cad90d +#: 9fc07e857fa048e2956e64bf78f6e386 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:1 of msgid "Allocate a transfer port, waiting until one is free." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 -#: f219ec3cd1d1448fb4e0171853a7d779 of +#: 505d7b9fb1024bc8ba886e5b0a38fbf2 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 of msgid "" "Allocated port, or 0 when allocation is disabled " "(``is_hand_alloc_port`` False)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:5 -#: af35fb0d306d447ca2a70b0f2b63ecee of +#: e85fdf7f7a594e0b9aed565b4a3ab42f of msgid "Allocated port, or 0 when allocation is disabled" msgstr "" -#: 94b2dff9085247fda189e063a4fa4a7f +#: 153357eb91794cb692467afe5e94b41c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:6 of msgid "(``is_hand_alloc_port`` False)." msgstr "" -#: 06c8b24821f94f48b265dd90995e10a9 57f02c9c5f32443e82feac04411b32ed +#: 26c5c3768e1446e78c9efc5f8038b23d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:1 of msgid "Release a port obtained from `palloc`." msgstr "" -#: 750aeace3a2043978210096a24199700 +#: 0e0379de669843778f6827973c29372e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 -#: a400ec85715c462e941f3f590f646046 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 of msgid "Port to release." msgstr "" +#: 6a8d4efd9f9a45e399525e2f169035ee #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 -#: c6c5882e52c74fb1a5aa68e621922150 e95eb44c45ea42a5b63026f73274f990 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 of msgid "Allocate the next port above the base, or the first free one in range." msgstr "" -#: 2aec0e66e9e44175a6d6a36917137cf9 +#: 73e9e2ddd451402a93d10dbac6ac9374 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 14bd404133c744e68356290e50c91f4c +#: 9d96a242eab8433ca750d670a5f63b82 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:5 of msgid "Allocated port; None when the upward range is exhausted; 0 when" msgstr "" +#: 7b05e18fccbe4ab081d3cd22d59a48e0 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 -#: a2a1781441e64797a0d7942463680610 bccdcb4c96de4d6a9f6c4318d0b1f55e of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 of msgid "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 9b0a4b0fa07b4f7e8e4476f99d191837 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:1 -#: a4c53c6cf9d24f1ca624f8ade02cfb07 of +#: f2d9abe435cf49f6825bb72a68013934 of msgid "Release a port obtained from `file_palloc` and step the cursor back." msgstr "" -#: 24467ee3998b40bd9563059c6610e4e9 2a1c562ca62f40158d89d6f16896ed18 +#: 6c1fb07a212d4bf19717407b0c7184d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 -#: ace99e97fef7403faf20dc5040a47bfa ba3e6daae9e34590bc0f2abc98c02da3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 of msgid "Port to release. Ignored when allocation is disabled." msgstr "" -#: 053f2e52a148421eb080c1df3d3de1cc 9052b949aa354df7968cacc9ed930921 +#: 1afd81c685234a20aa41c5cde93d327d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:1 of msgid "Allocate the next port below the base, or the first free one in range." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 -#: eb3a97b7706a47dda4cfb5e12930ba02 of +#: 3fc63f6d51aa4c0fb22fd0f945f9cfd7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 3c8cc24113bd420eb7f373cde6a27ef2 +#: 74a441ccfa5e421dadd215ef0725a25f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 -#: f70a4f056d6c49b2b953824ffab19db7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 of msgid "Allocated port; None when the downward range is exhausted; 0 when" msgstr "" -#: 383142a0285745bb8ef4b95b1d597151 9f78428fda474dffac2f3cdf4c3a2aeb +#: 9c4b9bddd98c463f9e140bd2d8425dad #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:1 of msgid "Release a port obtained from `spy_palloc` and step the cursor back." msgstr "" -#: 57c8111cd86f49c7af67d8e9a177a591 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:1 -#: e435af0f27b641168044b3cac4130ac5 of +#: c66c76cab8564da4b6b6cb855fd63fd5 of msgid "Register a custom command handler." msgstr "" -#: 39f637bfe6ff4822952d67419861841d 51f84d06854b4b96b7ce1fb2e778b5e5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of msgid "" "Command to intercept, e.g. \"/my_command\"; matched case-insensitively " "against the first token." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:6 -#: b53c2039d55947d689c2cfe09cac93c2 of +#: c7c29a3836c9493e9c8804cc5896144a of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back to the sender as the response." msgstr "" -#: 15398a9c312e459a897c07b18dc9fbaa +#: 7c64d0c0b9ac44b995811a0fdaa0dfaf #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:10 of msgid "" "\"server\" for commands arriving from clients, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 7ff63de06e854f88b1cebc42b464397d 8f139fd48e9c496287f9df897ccf01d6 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 +#: a0c074a9da664c5eb5fa63deb6765c36 of msgid "" "Run the handler on the worker pool instead of the reader thread. Defaults" " to False." msgstr "" -#: 1a0a724bef6140ceb235cbeaea95c1d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:17 -#: e73cb64f1ef544db8009b026ab5c376c of +#: e6c616f887334cb6925c03de2ad6f64c of msgid "" "False when ``where_to_run`` is neither \"server\" nor \"client\"; the" " handler is then not registered." @@ -732,60 +944,107 @@ msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:19 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:19 -#: e1cba64f5b384d169c366d8e16078683 eaab849e83884bd6be80fa08867ccde2 of +#: f125f1386b434f3a8199b1ceb8c44eca of msgid "False when ``where_to_run`` is neither \"server\" nor" msgstr "" -#: 4cbf71104b8544d18962b7a9adca8b7e 82c461f38cc44bc9914cb7009a5cf3e1 +#: 1a68dac068db434eb76e28015005f29c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:20 of msgid "\"client\"; the handler is then not registered." msgstr "" -#: 15aa55a075a64bb98f5819a8a5d37113 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 of -msgid "Register ``listener(client_id, message)`` for every inbound plain message." +#: 25c1023e97b64226a58cdf83f8ba07bf 9ebd0da560d747168cebc59ca93b1cb1 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:1 of +msgid "Call one registered extension command handler directly from code." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 -#: f914714947174f2298278112a91d82b0 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:3 +#: b14f4ed43e6c43c39579c1c16b169645 of msgid "" -"Plain messages are the lines received from clients that do not start with" -" ``/``; commands go through the registered command handlers instead." +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines clients send. " +"The handler runs on the calling thread — ``run_in_thread`` only affects " +"the console and inbound dispatch paths — and is called with ``None`` for " +"both ``client_socket`` and ``client_address``, since a direct call names " +"no peer." msgstr "" -#: 1b5e4524170242099c808039098d64c3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:11 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of +msgid "" +"Command line to run, e.g. ``\"/my_command arg\"``; the handler receives " +"it unchanged." +msgstr "" + +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:15 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:15 +#: of +msgid "Whatever the handler returns." +msgstr "" + +#: 0ab70b2e8ed040d4908d0900da96f6c2 0d85b81af0634a448e6a74d63c06045f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:18 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:18 +#: of +msgid "If no registered handler matches the first token of ``command``." +msgstr "" + +#: 1f5b21975ad2499a86fe21c69bfd7ca0 42f8d27a5499457da7302224dcc8a521 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:19 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:19 +#: of +msgid "If ``command`` cannot be split (unbalanced quotes)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 +#: ef5d20f1a16945368383a8cdbc3daa19 of +msgid "Register ``listener(client_id, message)`` for every inbound line." +msgstr "" + +#: 2459179e833b4e7db8e1d70571ac793a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 of +msgid "" +"Every line received from a client is reported, commands included " +"(``/help``, ``/file ...``, the crypto handshake lines, ...), so the " +"listener observes all inbound traffic; dispatch is unaffected, a command " +"still goes through the command handlers." +msgstr "" + +#: 9ec5fafe8ded489785400e3e489b8573 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:8 of msgid "" "``listener(client_id, message)`` where ``client_id`` is the sender's " "``\"ip:port\"``. It runs on the receive thread, so it must not block, and" " exceptions raised inside it are swallowed." msgstr "" -#: 2e65864bfdd2429298dbf86682b3be81 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:1 -#: e562b99848544a8cb47afb41478d1b66 of +#: edb8edc2eb3f433186b54807a8ac43ad of msgid "Unregister a listener previously added by `add_message_listener`." msgstr "" -#: 346bd1c9d44045868b59b7643f1cf09e 8ff591c39e334e1eab8d05267532faed +#: 6fd7bb75a29e4973ac2bd05119255039 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 -#: a0e48bdcb67e49498a113a58a504553c ab196c3b77b143069faa85a52626d946 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 of msgid "Listener to remove; an unknown one is ignored." msgstr "" -#: 46010db8ce4d4eb1b06348f29e115846 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 +#: cf95477e5794404fbdf4e877a132ba1c of msgid "" "Register ``listener(client_id, full_path, name, size, command)`` per " "saved file." msgstr "" -#: 72536042242c4ea9bd2e6efa63fc9336 +#: 9c57d09f6d3d437890ae3ad306071701 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:3 of msgid "" "Fired after a file uploaded by a client (a direct send, or a forwarded " @@ -793,8 +1052,8 @@ msgid "" "``file_transfer_dir``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 -#: f4ba3546e2b048d49d9c274ef8d8ac98 of +#: 6c938b7c8be3464f9925527b6deb4e1d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 of msgid "" "``listener(client_id, full_path, name, size, command)``; ``client_id`` is" " the uploader's ``\"ip:port\"`` and ``command`` the wire command that " @@ -803,196 +1062,185 @@ msgid "" "block." msgstr "" -#: 2e1706c637c54db9b8ed55ba98665535 3d6b3f43b6094b2e9776fcb9e4ce7bcb +#: 57b1e98125974187b986386da7991dd0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:1 of msgid "Unregister a listener previously added by `add_file_listener`." msgstr "" -#: 0a8d57625bba4ce4949fc23bce63f033 +#: 58f1ccd078ea406dab00d6d4be886a76 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 -#: c27185227a5f434f9641501d1d3bca2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 of msgid "Run a callable on the instance's worker pool." msgstr "" -#: 0c5aed09b63647cd87a3234ef9a4903c 40fade944d8d43b18599150134015443 +#: 6e05c7f46b244ae195c32ee52797fa37 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:3 of msgid "Callable to run." msgstr "" -#: 6bcb8f96e0584f66bbb94fe2573a7f61 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:5 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:5 -#: e959076fdf3843fc9c53ccb8492adfe6 of +#: e1c79706c9414895bdf7bf183bf5d41a of msgid "Positional arguments forwarded to ``func``." msgstr "" -#: 41d755cbd3cf48e7a0bc9d2b1aa3ab14 628a65eab1354dda83077715a47e63fb +#: 9221436fa83a4831942cf5be4e37e2cb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:7 of msgid "Keyword arguments forwarded to ``func``." msgstr "" -#: 1c03aa271c37431d974f08f11c93d7af 4b1078858cf64a1e92b36fa109fc1409 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 +#: a6b26d6cf54d4fafac2950cbe33ba56f of msgid "" "Handle for the submitted call; its worker slot is released when the " "call finishes." msgstr "" -#: 169f874c0ebb40d5aecd2549e60b4600 1e45486e3fd84627b015bf5a9a0a24b4 +#: 60f19983f7384aefbb6c97b84dd25f93 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:12 of msgid "Handle for the submitted call; its worker" msgstr "" -#: 037748a51dd94d43a3939fa8ec538d66 655c7802ef7c42a686c74d426531db8b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 +#: eadf6af0a0954798933dc427ba8e107e of msgid "slot is released when the call finishes." msgstr "" -#: 7b0b391fc53d42fb8f331d8e2da2be54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:1 -#: d6578909a33e4eef8afe892b33e0f70b of +#: fece61298a354d6db119309b29c6751d of msgid "Start a temporary listener for a side channel (not the main protocol)." msgstr "" -#: 1164584733744eb2aa574d6f61476c2d +#: 01d42ba32c2b41f482dd077cfb950f9b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 -#: c132c5365e7c487c92b4072a0020b52c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 of msgid "" "``handler(client_socket, address)`` started in its own thread for every " "accepted connection." msgstr "" -#: 03583460bc824965b9152433dfdfb097 +#: 5e1b84445ee34c9cac00e1a2c9ef297b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 -#: e81f361ea0fb46ee9c6760b0c6ef11c1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 of msgid "Port to bind; None allocates one with `palloc`." msgstr "" -#: 4f2f3f063e9c4834a77fbdb1a46d65dc +#: 9c69c4dd1d904078af48c6308ba35895 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 -#: b655787e48384873b4446ee1147bdedd of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 of msgid "Listen backlog. Defaults to 1." msgstr "" -#: 31cd65b92bb846f6b9c97b003fa00db5 +#: 47f98fd15e6144bd845d175cd039a6c2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 -#: ec56b80af0a843a991cbe77c5ee9ae45 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 of msgid "" "``(port, thread, stop_event)``; setting ``stop_event`` ends the loop," " which closes the socket and frees the port." msgstr "" -#: 7b73372b2ada4ce5b210b527015d925c 86cfce9d36f04328ba76e88df87fbcd8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 +#: ecf3d32c44db40a8a13545d623ffe2c9 of msgid "``(port, thread, stop_event)``; setting ``stop_event`` ends the" msgstr "" -#: 11b0347a0ebd4ae3931ed1f77c26a04e 9017aeb8480241f3a5f426c718bc4ee0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:14 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 +#: abce9546b7444c6383c9020c4133ec63 of msgid "loop, which closes the socket and frees the port." msgstr "" -#: 3c32a346019741da9aa2a3e409a7b0e2 82f16e3e9ba1468d8a87c91db28cc45e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 +#: a270cfabdac64296b8a33ad4d662896f of msgid "If ``port`` is None and no port can be allocated." msgstr "" +#: 031d3e96394c454093561375a377dcce #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 -#: d63b5db9eab6478ca088c9a5e90163fc f0869b5be0ab40e4a2a7eca275922557 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 of msgid "Open a temporary outbound connection for a side channel." msgstr "" -#: 3d194b9f95794116b17720aa74ce0878 +#: 112fda54e1eb4981b4272df61c5416e2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 -#: d0bb03d9590540fd980dd79c28d98e97 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 of msgid "Host to connect to." msgstr "" -#: 98a5441019de48258a099f2ec25751f5 +#: 59d3c414b4304673be5d3232d2291680 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 -#: b443afa67dc84e1a8ac501ad5c6b0ff1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 of msgid "Port to connect to." msgstr "" -#: 537482efdcc0447e81bd001ad2d4d85a -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 +#: c5766672f68f47c9908e68d2ed3be7f3 of msgid "Local port to bind; None lets the OS choose." msgstr "" -#: 2230b0e486fc4229acc03f78ec4b1e09 300e61efcfef4a2f8c87725e183ceda8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 +#: bfc1b713e9fc4fe797e50c357f472e76 of msgid "``on_data(data, client_socket)`` called for every received chunk." msgstr "" -#: 2f63095ce33849b78465729923d04ff0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:14 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:13 -#: e07d5e5deb1a4fb086664ed896076feb of +#: c563d04fcd7a41f1a2aeace42974430a of msgid "" "``(client_socket, thread, stop_event)``; setting ``stop_event`` ends " "the receiver thread." msgstr "" +#: 0e1b9679f3104a9caab601e6bc7c0905 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:16 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 -#: bf9994c99c8a48139d4c00d0dcfeca63 dbf60e58abd04e02b50316b1cb4b7b2f of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 of msgid "``(client_socket, thread, stop_event)``; setting ``stop_event``" msgstr "" -#: 6af1621f80734591950e545b955c4bbe #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:16 -#: e69a51e576e446c59185c2eceae72657 of +#: c76fce92c3f944c1857df89bbc134540 of msgid "ends the receiver thread." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 -#: c291ec3d31094e589a1bfc5713b47ee3 of +#: 5ea5fd66c3d3434292e4d8e1dd1da094 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 of msgid "Send one message to every connected client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 -#: c28f38641c704c1e912c602ced57fc9e of +#: 32945f04e0564f9d88495506f0ab4f90 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 of msgid "Clients whose send fails are disconnected and removed from ``clients``." msgstr "" -#: 3f3e7a6a5de746518e9ddd135983d073 +#: 00de0b1f60b14189b1629f8146db68a6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:5 of msgid "Payload passed to `send_message`." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:7 -#: cae2a2c29d96447d8b1056e36bbf5572 of +#: a91c8f6921c7435e990516c2134efcf8 of msgid "``(ip, port)`` to leave out, typically the client the message came from." msgstr "" -#: 9b2b7c4e77844a82bfd61276bf46f6d7 +#: 9d57c62f1fd94c1dacfe32aa50cc9665 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:1 #: of msgid "Send the messages of a console line to the clients named in it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:3 -#: cabc278e7f6a49e6bd6e533f632d0f99 of +#: e7fbf4bbd84b4920a2b9591fabcaf2d9 of msgid "" "``/send_msg`` line as typed: message text followed by one or more ``(ip, " "port)`` identifiers; each message is delivered to the identifiers that " @@ -1000,17 +1248,17 @@ msgid "" "notice." msgstr "" -#: 888e165ca1554b4db63e714e3adc63f1 +#: 9d4819fe4ca94a1b81c9e0423ff98212 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:1 of -msgid "Write one line to a client socket, encrypting when the channel is up." +msgid "Write one message to a client socket, framing it when the channel is up." msgstr "" -#: 64d6f6cc29de4d4290671afc59d808c7 +#: 1c7b88e29a0143a39e13441769186ef4 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:3 of msgid "Target connection." msgstr "" -#: 73953d67bcbf4bfabae7b0ff91bfce8c 7e2e221f6a6b43a08f534ca2d8cfb6e8 +#: 6f8bd9adaf2b4c44a9446b049144fe21 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:5 of msgid "" @@ -1018,62 +1266,73 @@ msgid "" " are." msgstr "" -#: 240dadd589af42e18e15d2c53b5c96b0 +#: 5c03983cb460497fb72f126c1d8a2bc1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:9 of msgid "" "True when the payload was written, False for an unsupported payload " "type." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 -#: dbfc49c3c67c48d5860a61f8ded20950 of +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 of msgid "True when the payload was written, False for an unsupported" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 -#: cab2f5321ba54adca315d34d921a09b5 of +#: 602950a9f5ad48ea92ab60aea3b26488 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 of msgid "payload type." msgstr "" -#: 4519dac81e714164a0edbf6ac75c9c19 +#: 149f767d72dc4da7b1d88fed768d2474 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:15 of msgid "If the server is not running or no socket was passed." msgstr "" -#: 7ea1b30273604db4854189502fdf734e +#: 07dac2d20d7041779c8b189d45ee2e64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:16 of msgid "If the socket write fails (the original error is re-raised)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:1 -#: b228437e9cb4461e9ceb078f084544eb of +#: caf2377ee7f348ab8c95bf2a27c44be4 of msgid "Read up to ``msg_length`` bytes from a client socket." msgstr "" -#: 292c2ed074e14a5eb184dceb245cab6f 58a8806cd0bb4dc9895b7f74a1b45765 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 +#: c702e4a63a5240ea97feb5bc393b4d09 e9256fbce5d848b59ae2e6d0ce88ce24 of +msgid "" +"A socket speaking frames (see `_SecureChannel`) returns decrypted " +"plaintext, served from the channel's buffer; a socket without one is read" +" raw. A read that started while the channel was raw is classified by the " +"channel when it returns, so bytes of a flip that landed during the read " +"never land in the line reader." +msgstr "" + +#: 214af2667d0f443eb16c0a4aaf723b2e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:9 of msgid "Connection to read from." msgstr "" -#: 547ccf662a6945738e8c761628807ab1 624220029a624009adb07a49140d8a2c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:5 of +#: 7c3eb31687804ba5a59acc140ba50230 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:11 of msgid "Maximum number of bytes to read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:8 -#: b0973e75b118425db7e7bfc966e5eb87 ff5195026f8143fea9240d4f21e81981 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:14 of msgid "Received bytes, empty when the peer closed the connection." msgstr "" -#: 7acd066bfa87415094144b0e0c1ea0d4 +#: 7103cfcec26c44999cb5464251ee461c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:1 of msgid "Serve one accepted client until it disconnects." msgstr "" -#: 53591274f0824492afab6874b284c33e +#: 65f9de7f44774aa6aef81fcbe4dc1c64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:3 of msgid "" "Registers the client, greets it, announces the encryption mode and reads " @@ -1083,8 +1342,8 @@ msgid "" "ends for any reason." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 -#: fba3167476a94b62af90bfc4101d1ed6 of +#: 87d5085c31a14ad38b060c48f8cf1262 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 of msgid "" "With ``is_asynic_clients_io`` False (the default) the call blocks and " "owns its thread; with it True the client is served by a coroutine on the " @@ -1093,22 +1352,22 @@ msgid "" "no event loop runs is closed with a console notice." msgstr "" -#: 72edaf343723458fb9b2fe0f40bc01b8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 +#: db3915757e2842c8afee97b2d471411e of msgid "Accepted connection." msgstr "" -#: 6a2427e7b7de4d609bf61e3fad46b413 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 +#: fae378e888be4821a14ed2483cfde1e0 of msgid "Peer ``(ip, port)``; used as the client id and as the key in ``clients``." msgstr "" -#: 061015c431a54fafb45ea722ae696003 +#: 32886e2babcf4283924034c600453c4a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:1 of msgid "Dispatch one command line received from a client." msgstr "" -#: 9cc9ee25bc464440a4ac2bca19e5a413 +#: 8972b8c4edf149fd9a4008832c85ed31 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:3 of msgid "" "Built-in commands (``/help``, ``/time``, ``/clients``, ``/quit``, " @@ -1119,24 +1378,23 @@ msgid "" "close the connection; an unknown command is only reported on the console." msgstr "" -#: 9a970df310fc4b59b113bb6160f24fd2 +#: 208294924333477a8e7d65aa3130777e #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:10 of msgid "Connection the line came from." msgstr "" -#: 8856eb18fd044b60b869be64e5f4576e +#: 306e5026cfc1441d8c754f0e02866cf3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:12 of msgid "Peer ``(ip, port)``." msgstr "" -#: 6ea3bacf1baf4eadb98d5e38236ecf90 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:14 -#: e212b51318ea4d46ab6354b818dc262b of +#: a2a3a1fd57e14260a53675457fdff0b4 of msgid "Line including its leading ``/``." msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:17 of msgid "" "Response for that client, or None when no response is due (crypto " @@ -1145,11 +1403,11 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:19 -#: b3f201060ae548098d8284d4c18c0560 of +#: ed04a3bf285b4f57bb6a5de0c4f7284f of msgid "Response for that client, or None when no response is due" msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:20 of msgid "" "(crypto lines, file transfers, ``/quit``, which answers on the socket " @@ -1157,114 +1415,108 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:1 -#: b4ee832e0ad64d189740b45a297d713d of +#: a784dfdc5ded411d985426e36f6e5435 of msgid "Send one plain message to a connected target, tagged with its origin." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:3 -#: ec8cc922a2ee4e70bdff9a8e81b74e98 of +#: b545977244dc402aa8586264d2d933f3 of msgid "" "Public API for forward extensions: the message is wrapped in a " "``/send_msg_from `` envelope so the receiver can " "attribute it to the originator (see `parse_forwarded_message`)." msgstr "" -#: 660b6f4493ec4c9994af44960900cb10 +#: 8ee5275fbf894581ade9e6f30d5d4aff #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:7 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 -#: b8a3838c85624f3dbe705afac78acc47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 of msgid "Destination ``(ip, port)``." msgstr "" -#: 1dfa946975cf4768891292e84a2bbc63 +#: 38ffd8a7079d4794811e3504c01052f8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:9 of msgid "Payload to deliver." msgstr "" -#: 09f6b3913160404b9927d5e70252d9bc 5251c2b3867b4dc1b8dd8d09ea570d90 +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:15 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 -#: a8ee713ff78b42bd8adb5743ab369aef of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 of msgid "Originating client ``(ip, port)``." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:14 -#: ad5e4419a1d04b27bec64cf1aee14c53 of +#: d2471a90e269464c977239f406051120 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the envelope was sent." msgstr "" -#: 2fd94dad15884a56b9657090a33988f9 9e706f8851a74b569ade8deb4f8f70ab +#: 320d99b8923f4eaa886ffe0a16bfc6d9 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:24 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:16 of msgid "False when ``target`` is not connected (a console notice is" msgstr "" -#: 59049e3514b74a7ba90fb8886ecca185 +#: 1a97f59b270f404096d9c2b37ab09a8c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:17 of msgid "printed); True when the envelope was sent." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 -#: b9019e7dae074d64a66ae1c81967b9b8 of +#: 6baab06dc12e4ecc80d1a16c26c2a19a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 of msgid "Build the tagged wire command that pushes one forwarded item." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 -#: fcde926ccf5640b2b2ac6aab009aa4d0 of +#: 0c3f9dcbcf8f413fbd5befefb960c402 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 of msgid "" "Public API for forward extensions. The originator tuple sits before the " "trailing transfer id, where the receiver's existing parsers ignore it and" " `parse_forward_originator` recovers it for attribution." msgstr "" -#: 3cee0d37a9e5460a90b7c9b1abe53a92 +#: 3cf58937a2d04172bf544119279d85c1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 -#: d5cb9e15787a435ab586217498d98e2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 of msgid "\"file\" or \"file_folder\"." msgstr "" -#: 8efbb4663727491e8ee77edc824ce1c0 +#: 621a93603c8549c0ba047bee6aae5a38 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 -#: e8aeb2b89d5f4969aeaf2244f06a1a47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 of msgid "Relative folder path (folders only)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:13 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:11 -#: b439157e6df44d7bac2a4367c5fb66ee b9cb86fb0ad642e18ec19debb44a2648 of +#: f0f56fb642874c3889fb0dacfed4f4ef of msgid "File or folder name." msgstr "" -#: 5f249d30e8934ed0ae07c1ca2666c6c6 +#: 72d2b6fdd324482eaea9803def1fe2da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 -#: df45d1036cb9437a853551afb3f31775 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 of msgid "Transfer id shared by the pushed item." msgstr "" -#: 9bc7aaf1a36a4311a736f5528525d33a +#: 0aa1bd5b053544e98ae4ab3ae1add5f7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:19 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 -#: f806614c8aeb428292d6ca51db8ca35b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 of msgid "Receiver-side destination directory." msgstr "" -#: 1f3c679edcf34e71a946e8668ca27a58 +#: 93e666db45e745619b90c744e1646b73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:20 of msgid "Command line to hand to `send_message`." msgstr "" -#: 3499106d953f41789e53f24bfcae3af5 +#: 56d8327bb7414a5e85292f8f2ace9d42 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:1 of msgid "Push one forwarded file or folder item to a connected target." msgstr "" -#: 959c24d8afff4486ad5f787311bf3c8b +#: 3098afa7f4ac43a184d081dda8faa6ba #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:3 of msgid "" "Public API for forward extensions: sends the line built by " @@ -1272,24 +1524,157 @@ msgid "" "`parse_forward_originator`." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 -#: cb11d22918824fb09fa82fd432aeb74a of +#: 9b9634061040430484cd2596f43a8feb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the command was sent." msgstr "" -#: 66262977fc014465964289448673a5b9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 +#: b8bb8c432f7649d5a35480fec0509a51 of msgid "printed); True when the command was sent." msgstr "" -#: 1df1cd85678d4149bdac92c3591c9e50 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:1 of +msgid "Receive one file over a transfer sub-connection." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:3 +#: d3367c6f97aa4bf4b9cb3d79b3117fce of +msgid "" +"``peer`` is the transfer's original sender (the sender for an inbound " +"transfer, never a relay): it is stored with the progress entry so a later" +" reconnect can ask that peer to continue the file." +msgstr "" + +#: 5c4faf52e8bb4808805bae58d30ac0cc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:7 +#: de641d48c530435bb4adc04755a47a6d of +msgid "" +"``resume_entry`` continues an interrupted transfer: the listener " +"announces itself, asks the sender to continue from the bytes already on " +"disk (``RESUME_LINE``) and appends the incoming chunks to the partial " +"file instead of truncating it." +msgstr "" + +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:1 of +msgid "Send one file over a transfer sub-connection." +msgstr "" + +#: 87862abb10ad423f820952355f5936bc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:3 +#: d6a618c007ec433fa10a44b0a7a90fe4 of +msgid "" +"``control_socket``/``crypto`` carry the listener's mode stamp (\"plain\" " +"or \"enc:\"): an encrypted leg aborts when the session key " +"material is missing rather than downgrading silently." +msgstr "" + +#: 97e1a0538f544c2a8e755c78805fda7c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:7 +#: a405431dfd62434b82c7052edc456123 of +msgid "" +"``fid`` is the transfer's id — the caller's own transfer id for a plain " +"send, the relay id for a forwarded upload — and keys this leg in " +"``file_upload_progress``; every leg with a fid can be paused with " +"``/pause_trans`` for that fid. None (a leg without a protocol transfer " +"id, such as a public-key push) tracks no progress." +msgstr "" + +#: 6cb58bfd1dde4b49ba3525af014e44c7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (never a relay): it is " +"stored with the progress entry so a later reconnect can be resumed. " +"``resume_offset`` continues an interrupted transfer from the byte the " +"receiver already holds: the file is read from there instead of its first " +"byte." +msgstr "" + +#: 1634dbe84a95421a92a660f7c6fdd10e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:1 of +msgid "Continue the interrupted transfers of a peer that is back." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:3 +#: eb46142fa4e44147ad3ad8c680d5bee0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and, for " +"every download this instance was receiving from ``peer``, opens a fresh " +"transfer listener and asks the sender to continue the file from the bytes" +" already on disk. Restored uploads need no action here: the peer drives " +"their resume from its own side." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:9 +#: b7d54977ca494a8b9968365dffd9bd3d of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer that is " +"connected right now." +msgstr "" + +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:13 of +msgid "Number of resumed receive legs started." +msgstr "" + +#: 52cb873f015542b6a94506cebfe735a1 737ed182911443bc8cfff3c4d094b9a9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:1 of +msgid "Continue one interrupted transfer this instance was sending." +msgstr "" + +#: 50f292ac853841c9b082eb3c3ff4d6f4 6c968a5b77b342ed891883336cfcc255 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:3 of +msgid "" +"Runs when a receiver asks to continue a transfer (``/resume_trans``, see " +"`resume_transfers` on the receiving side): the leg is re-established " +"against the receiver's fresh listener and the source file is read from " +"the byte offset the receiver already holds. Also the public API for " +"resuming one transfer on demand." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:9 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "Receiver ``(ip, port)`` the request came from; None skips the peer check." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:12 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:12 of +msgid "Transfer id of the interrupted transfer." +msgstr "" + +#: 7124e1ce01df4fcea9516bed4ca55dc7 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:14 +#: d94da1700d0e46028f7bf114d7c5da62 of +msgid "Byte offset the receiver already holds." +msgstr "" + +#: 1a97f59b270f404096d9c2b37ab09a8c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:17 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:17 of +msgid "True when the resume leg was started." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 +#: b03f4edeca5f4cc19f6d695aac3690de of msgid "Bind the server socket, then accept clients until `stop` runs." msgstr "" -#: 42bb4623926449f5b91a451bcac30a2f +#: 7e027ea659ab48e19ea346cb284fe144 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:3 of msgid "" "Blocks the calling thread. A console command thread is started when " @@ -1300,12 +1685,12 @@ msgid "" "Socket errors and the end of the accept loop both end in `stop`." msgstr "" -#: 3d3320ce03544f23ac6f43883e5a580c +#: 291f5a8cc4f648ee9910e5cd45074675 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:1 of msgid "Read console commands until the server stops." msgstr "" -#: 5f7369176edb4567b3eb5332588b8c57 +#: 1ba2e428d432496688ef23f1c07562da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:3 of msgid "" "Handles ``/stop``, ``/status``, ``/clients``, ``/send_msg``, ``/file``, " @@ -1317,12 +1702,12 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:1 -#: ccbb242b51984c9f8ce9fb519c202485 of +#: eb90f49c77e64006a0c9ae861ff849b1 of msgid "Stop the server and release everything it owns." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:3 -#: e379bbd3f7b249c6b296f371548a5b1e of +#: a059b1e71106487999c83c2e2042f509 of msgid "" "Closes the server socket and every client connection, flushes the message" " and event stores, releases the allocated port range, clears ``running`` " @@ -1330,152 +1715,192 @@ msgid "" " Safe to call more than once." msgstr "" -#: 06fe9e3a48914447af6464acedea1fa0 +#: 32b06ea315b3404caa3a05c4aed0ce64 #: PyFlow.network_api.connect_tcp.TCP_Client_Base:1 of msgid "" "TCP client: connect to a server, dispatch commands, send and receive " "messages." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 -#: ef04371450674badb666b7fb31c203da of +#: 2b30f5c9ecd24fc89cdcd58000ee1e99 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 of msgid "" -"Lines received from the server go through `receive_messages`: a line " -"starting with ``/`` is handled by `handle_server_command` (protocol " -"commands plus the handlers registered for the \"server\" side), any other" -" line is a plain message delivered to the listeners registered with " -"`add_message_listener` and stored in ``messages_dict``. With " -"``is_input_command_in_console`` the console thread `interactive_mode` " -"sends typed lines to the server." +"Lines received from the server go through `receive_messages`: every line " +"is delivered to the listeners registered with `add_message_listener` " +"first (commands included; a forwarded ``/send_msg_from`` envelope is " +"delivered as its payload), then a line starting with ``/`` is handled by " +"`handle_server_command` (protocol commands plus the handlers registered " +"for the \"server\" side), any other line is stored in ``messages_dict`` " +"as a plain message. With ``is_input_command_in_console`` the console " +"thread `interactive_mode` sends typed lines to the server." msgstr "" -#: 840ff55e5e444cfbb85251e9c4123178 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:12 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 +#: b9532c86786c43d5aea58b24157fefed of msgid "Server address this client connects to." msgstr "" -#: 1f65ef8a745743ebb31ebc5805c5b02f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:18 of +#: 2cfa1e3e1674407ba1e2683e76fef65d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 of msgid "Server port this client connects to." msgstr "" -#: 5956a034ca2347f384f682b52d927ee3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:24 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: af04fdee2c95431a9b0c17f96e50c18c of msgid "Local address the socket binds to." msgstr "" -#: 1d2b7be8ff994d15b9a3f63c0e4fab11 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:30 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 +#: b1d4b5606e1c48b6a915815527542758 of msgid "Local port, None when the OS chose one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 -#: d616019e80a741638b6ac020d6abb336 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:34 +#: d926b4f3eb4b40a4acb21f780a4dc227 of msgid "int | None" msgstr "" -#: 0a015a4f44194fe2b25bbd4dfe52d1eb -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:36 of +#: 500cfd177cf5453d887f6904b73b7851 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 of msgid "True while the connection is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 -#: da7ca1204aea47779bbaaa809f79da93 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:76 +#: fd832e1d72b642838382d529c3e1f22c of +msgid "" +"Whether `start_TCP_client` reconnects after the connection drops (and " +"resumes the interrupted transfers)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:102 +#: c194bbee7cf14d268c330e06f94ae973 of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when the connection drops and read back on the next reconnect " +"(`resume_transfers`)." +msgstr "" + +#: 40f2a9e1b730422db3dd58bc2a6046e3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 of msgid "Create the client and, unless extended, connect and start reading." msgstr "" -#: 9e0577d19b76432089a46a53a2bbf7be +#: 0552aa36b7b74474af8f43b380dbee54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:3 of msgid "Server address to connect to; required before `connect` is called." msgstr "" -#: 8400b2487cfb4cff8a72f452e3b4c83e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 +#: d246ff9aaf154bfa91b5c4c9d293afd5 of msgid "Local address the socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: 7cb2047b830c4996832b4623812a687b -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 +#: e981b68ebbea46e9b556b09f4b5cd44a of msgid "Server port. Defaults to 65432." msgstr "" -#: 7a0404b673f84a1191af5479097f8cf5 +#: 766bf4c138234fe081bbd2668dcb2a5d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:11 of msgid "Local port to bind; None lets the OS choose an ephemeral port." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 -#: df784379acc1474aba6566c969dbb7bc of +#: 5d661c0f91f64ef39cacb1a5466d752c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 of msgid "" "Socket timeout in seconds for connect and receive. Must be None when " "``is_wait_server`` is True." msgstr "" -#: 2b8bf92e3eb049ee8e994aa8b6d92fa5 +#: 9478d02062284ecaa7838f931ab80780 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:17 of msgid "Step between candidate ports in the allocation range. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 -#: fa74d746eefe4cb6862068fdbf384dd8 of +#: 2e1695ae510b43758793257124fd23c2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 of msgid "Enter interactive mode after connecting. Defaults to True." msgstr "" -#: 95ebbc90f84a41ada4b6edbec2c7a95e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 +#: e02da86957dd4f45bf84ede4e9c82cda of msgid "Keep retrying while the server is not reachable. Defaults to True." msgstr "" -#: 259f9e8d0d1547ae81e047e8ec24875d -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 +#: e1fb7f67e1714a61a9e8fe500555c700 of msgid "" "When True, do not call `start_TCP_client`; the caller connects when " "ready. Defaults to False." msgstr "" -#: 794bfe7ef8594729b0e87230d3ed9e49 +#: 1634dbe84a95421a92a660f7c6fdd10e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:34 of msgid "Negotiate the RSA-encrypted channel with the server. Defaults to True." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:40 -#: e3f9232109d34798af1f681b250ec7d5 of +#: cff66a7ac1ad410f96ed1ee03cb1cf53 of msgid "" "Buffer ceiling in MiB, kept for parity with the server class; the " "client's forward path does not read it today. Defaults to 2048." msgstr "" -#: 71b662106e594538b8a5fcb9bc190b1f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:51 of +#: 14c4889553fb42f7b0393a4a7ab46b4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:72 of +msgid "" +"Reconnect (and resume the interrupted transfers, see `resume_transfers`) " +"when the connection drops while `start_TCP_client` runs. The transfers " +"that died with the connection are persisted to the protocol's ``.Flow`` " +"directory and read back on the next connect. Defaults to False: a dropped" +" connection ends the client." +msgstr "" + +#: 0f06ff3b6db940da96ec09bee3dba526 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:80 of msgid "If ``is_wait_server`` is True and ``timeout`` is not None." msgstr "" -#: 4388cbc6302341adbdfa566d93526ef1 +#: 5dd677b9627d4b84b53dc7a6b2848b3f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:6 of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back as the response." msgstr "" -#: 14fcd0c8f3554ae983ac746cf3e58621 +#: 0a57a7875bb94767904ff8d93fa77eb8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:10 of msgid "" "\"server\" for commands pushed by the server, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 88087ef71067485dbd40d569a7b950d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:3 +#: acb1af86a6184624a47ac6cc3b7127d0 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines the server " +"sends. The handler runs on the calling thread — ``run_in_thread`` only " +"affects the console and inbound dispatch paths — and is called with this " +"client's socket and id, the context its dispatch paths give it." +msgstr "" + +#: 876e8fe2a6d645829ba12ddbad5006df #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:1 of -msgid "Register ``listener(sender_id, message)`` for every inbound plain message." +msgid "Register ``listener(sender_id, message)`` for every inbound line." msgstr "" -#: 50556c2d788d4e39a4a7cfed81ef6d6d +#: 2658650e027a4697b248f261903a4e29 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:3 of -msgid "Mirrors the server-side contract; commands are not reported here." +msgid "" +"Every line received from the server is reported, commands included, so " +"the listener observes all inbound traffic; a message another client " +"forwarded here is reported as its payload, attributed to the forwarder." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:5 -#: e6bec65449634cff953afd74d0e23e7a of +#: 412834182c9442adaf0b85e24c200ccc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:7 of msgid "" "``listener(sender_id, message)``; ``sender_id`` is the author's " "``\"ip:port\"`` — the forwarding client for a message another client " @@ -1485,21 +1910,21 @@ msgid "" "swallowed." msgstr "" -#: 38c576fe994b4a77830eaba36ca063b3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 +#: fc8a83e0b5f84273a8287b122c1a9a3e of msgid "" "Register ``listener(full_path, name, size, command)`` per saved inbound " "file." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 -#: e258540084d64816a08e0783810c4e3e of +#: 34e3386853564aab9a824e96438fc3e5 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 of msgid "" "Fired after a file pushed by the server (a direct send, or a forwarded " "file/folder item) has been fully written to ``file_transfer_dir``." msgstr "" -#: 4e10b4a74e9142e0868ab1b0b423f359 +#: 63f925709b83433e967610672b6fbc79 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:6 of msgid "" "``listener(full_path, name, size, command)``; ``command`` is the wire " @@ -1508,115 +1933,200 @@ msgid "" "it must not block." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 -#: afdf1e13067b4914a6aead736d7604e3 of +#: 4bc88415dfff40a3884ee0284b0ccc3f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. This " +"covers every outgoing transfer — a plain upload as much as a forward " +"upload — and is what the ``/pause_trans`` line does when it arrives from " +"a peer." +msgstr "" + +#: 7e190ff27df349ae90eb7bd98a0b6b5b +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:11 of +msgid "" +"Restrict the pause to the leg whose original receiver is this ``(ip, " +"port)``; None pauses whichever leg holds the fid." +msgstr "" + +#: 5479763134c04a418df6a9e5011a9dcf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:16 of +msgid "" +"True when a running leg was marked paused; False when nothing matched" +" — the switch is still armed, so a leg started later under this fid " +"starts paused." +msgstr "" + +#: 2bc5d7e5dfa94eb29b49f12562f57c88 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:18 of +msgid "True when a running leg was marked paused; False when" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:19 +#: a9c7cb3036f8409faad4c1db964d8a91 of +msgid "" +"nothing matched — the switch is still armed, so a leg started later under" +" this fid starts paused." +msgstr "" + +#: 59fa8126f08348bb9368c35b5d2336e2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg whose original receiver is this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:9 of +msgid "True when a running leg was resumed." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:1 of +msgid "Ask the server to pause its transfer toward this client." +msgstr "" + +#: 89fa1c905614496ea12a4cfde9eb3cce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:3 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (a forwarded upload this client relays is throttled this way)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:3 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "The server's ``(ip, port)``; None accepts the connected server." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:6 of +msgid "Transfer id of the server's outbound leg." +msgstr "" + +#: 39423e052b70403ba07a713aa9e3cb4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:12 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:9 of +msgid "True when the line was written." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:1 of +msgid "Ask the server to resume a transfer paused earlier." +msgstr "" + +#: 0e91f82d8856443497c399f97643b757 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 of msgid "Reserve this client's port range under the cross-process lock." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 -#: cd973d56799848ecbd65c434c9f5f0ae of +#: 6029a28126344e45b24394cb56b2f8f8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 of msgid "No-op until the server assigns a range (see ``/client_alloc_port_range``)." msgstr "" -#: 29e4db224e2d4208a5fc08a1523f9e6b +#: 32bed401c3574959ba5ed08fc9078401 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:1 of msgid "Release this client's reserved port range." msgstr "" -#: 7b0f2f6530984dcc888286f471f14747 +#: 9f86b7aac4f44886be9cd87b56072b63 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:3 of msgid "No-op unless a range was assigned (``is_hand_alloc_port`` True)." msgstr "" +#: 8154f96d9ec74bd588971a806d42f8c1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_lock:1 -#: c6e04e800074445da45886940c77a9f8 of +#: of msgid "Create the lock file that reserves the client port range for this process." msgstr "" -#: 2c7b09854c254d0bbfa62d2a356cfb24 +#: 69c2dd5d5d1d497c8bac1e62ab4fc30a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:1 #: of msgid "Report whether the client port range is reserved by some process." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_unlock:1 -#: b2cbf44d95154896ab2df64bf8be1a3d of +#: c88f37ef2d5c47bda346e804508d6ec0 of msgid "Remove the lock file that reserves the client port range." msgstr "" -#: 690717115cb64dfeb32f56302992451c +#: 478443e187814a6ca7ad798277db023f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:1 of msgid "Allocate the next free client port range and record it on disk." msgstr "" -#: 2e8d17873f8b4b419f2f6cd1f2000a62 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 +#: a8736540f4c3402fad9508e619d559d7 of msgid "" "``port`` is moved past the ranges already recorded by other clients on " "this host, so each instance ends up with a range of its own." msgstr "" -#: 2d7cb151d3bc4798914cbe3d73391c16 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 +#: bc44b1604e02467280b59cb8ad63d0af of msgid "If the client port info file cannot be read or written." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_free_port:1 -#: b6079f909975409c86477341dcf2990c of +#: e48dff576a074109a135db168b5dbe98 of msgid "Drop this client's entry from the on-disk port range record." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 -#: c7fc083bff234cb7b377bc7adbb65ca5 of +#: 3aa62e8843c6495c862f43fc6dda9d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 of msgid "Allocate a port, waiting until one is free." msgstr "" -#: 85129bb5393542e498835f3ba6dc981a +#: 2f7752fa51d946b1a4a566b38f046e80 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:3 of msgid "Allocated port, or 0 when no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 -#: e77dc25d62bc4eedbd153b7420d109f4 of +#: 503ab40fc32c4d548f65fa3272b2f4d2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:5 -#: c452f87d6e18446cbbb2f48b1dc47b9b of +#: b9fd549c95f24c2080d87cec92514db6 of msgid "Allocated port; None when the upward range is exhausted; 0 when no" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 -#: e195a16298f14417b95ed3dc3ad60fac of +#: 151a65f1c1984e4196c750108d0611cb +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 of msgid "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 -#: f7330894d1a041ca9a31ca1b390d5af7 of +#: 0c6201bb2d7e45d3a4916d7e50a21e10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 -#: a8d7d910fb874925acb423d08187908d of +#: 76c766a9c61f4075a762ccf55038a65e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 of msgid "no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 -#: c76dd143ea224bb69081222ac4228f8f of +#: 8d500513e8854ba4bb91c8905a9adb73 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 of msgid "Local port to bind; None allocates one with `palloc`." msgstr "" -#: 5a8b77d5b1e243d9b5b24039b6ff25d0 +#: 840360623c8a4c2bbafe8fe7bbf9209c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:1 of msgid "Connect to the server and start reading from it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:3 -#: b59d15dc7c7844a5bd0226eb081c9887 of +#: df94288e660b48f6809358b3dc234ec9 of msgid "" "Binds ``client_port`` when one was configured, then retries while " "``is_wait_server`` is True and the server is not reachable yet. Once the " @@ -1624,7 +2134,7 @@ msgid "" "negotiated, which closes the connection when the two sides disagree." msgstr "" -#: 8711ef70ac704a48b05e13ded3546471 +#: 22fccba0ab36499a9a7f4427abe5e9f4 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:8 of msgid "" "True when the connection is established (and, if encryption is " @@ -1632,105 +2142,107 @@ msgid "" "failed or the mode negotiation closed the connection." msgstr "" -#: 850616ca4a614020b9627a3c39a54555 +#: 0270d0a2d42740a9889106339d9f2dbb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:10 of msgid "True when the connection is established (and, if encryption is" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:11 -#: cd0e7073f18d4d2ba990f1bfda735fd4 of +#: c194691cedfb48c6bfd97d9bdc6f2246 of msgid "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 -#: b7b9e013f50348379a0208a7702b9b1f of +#: 4dc38e3ef3b74b8e8c27378242a1925a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 of msgid "Read from the server until the connection ends." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 -#: ae819668995f44878eaa9c4a8db02583 of +#: 431649a0d703476dadc6afa8adbe53d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 of msgid "" -"Runs on the receive thread: plain lines are reported to the message " -"listeners and stored in ``messages_dict`` (``/send_msg_from`` envelopes " -"are attributed to their sender first), other ``/`` lines go to " -"`handle_server_command`. Any end of the connection clears ``running`` and" -" releases the port range." +"Runs on the receive thread: every inbound line is reported to the message" +" listeners (commands included); a plain message is also stored in " +"``messages_dict``, while a ``/send_msg_from`` envelope is reported and " +"stored as its payload attributed to the forwarding client, and other " +"``/`` lines additionally go to `handle_server_command`. Any end of the " +"connection clears ``running`` and releases the port range." msgstr "" -#: 32feafb4504a473dbbe6b0957d3658f0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 +#: cf284b59f7f849039404ced20f8e12db of msgid "Write one line to a socket, encrypting when the channel is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 -#: c639152d8792432ba220c33c860f1211 of +#: 40ba2ede2d3f4666b82107af129d24d0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 of msgid "Target connection; the client passes ``self.client_socket``." msgstr "" -#: 5b421459787b4210b8bce3e7003cf35b +#: 2e663941eaf142cb96738add05f9ef4d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:10 of msgid "" "True when the payload was written; False when the client is not " "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 1684a06aa826439784ce149aece2f637 +#: 38905ec7539d42e0839907c32dd8667f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:12 of msgid "True when the payload was written; False when the client is not" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 -#: bc5ff108fa3d46afb45fd86d4106ac2f of +#: 3f7e2e6fedda476f996132c3f677f2f0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 of msgid "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 3b27239d40244e35817e0806e3363df0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 +#: a9220a130e694e0aba1d3b6320dff498 of msgid "Send the payload of a console line to the server." msgstr "" -#: 66bc43727101429bacd6a76534c53f7b +#: 2e208e83a89e4dac9793460a8808a042 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:3 of msgid "" "Console line such as ``/send_msg hello``; the first token (the command " "name) is dropped and the second one is sent." msgstr "" -#: 4cb6da8a7d464be983bf467e65fe55b0 +#: 39c8e70ca92b43b8ac687bc0aa7f4073 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:7 of msgid "If the line has fewer than two tokens." msgstr "" -#: 369743f21d0f4656aa801c8f29b4129b +#: 8d47f30ae7b0451f8ecfe207ec835ff3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:1 of msgid "Read up to ``msg_length`` bytes from a socket." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 -#: f6749336c57b4a82b5c0b19f27bd8906 of +#: 10a39005f45c46728ef9a000eeaf9109 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 of msgid "Dispatch one command line pushed by the server." msgstr "" -#: 510b3d71451048138e11fe92fdb160b4 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 +#: a7e781fde939475cb081204adac16ded of msgid "" "Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the" " connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange " "lines, and the transfer lines ``/file``, ``/file_folder``, " -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, " +"``/start_trans``, ``/resume_trans``, ``/forward_resume`` and " "``/forward_error``. Any other name goes to the handlers registered for " "the \"server\" side via `register_command`; an unknown command is only " "reported on the console." msgstr "" -#: 7724aab357eb408dbbf018c214f8eba0 +#: 91942d88960c4793b5eab8c3654c1400 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:1 of msgid "Forward plain messages to other connected clients through the server." msgstr "" -#: 12403f5be7704258849974d103865b9c +#: 75bb9147a7464a278e19af9d03b04ecb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:3 of msgid "" "The console command ``/forward_send_msg`` uses this; the client must be " @@ -1738,40 +2250,40 @@ msgid "" " so the receiving client can attribute it back to this one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 -#: fc0907a1c7484f66a7b2cc1a99d24dc0 of +#: 0f3c201936df45b687dc5532531b4a4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 of msgid "Message texts to forward." msgstr "" -#: 8d07efc16f6c45d7b9d1d4f85f945317 +#: 277bbcb2143943b5b983badb00c3f4fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:9 of msgid "Destination ``(ip, port)`` tuples." msgstr "" -#: 4afafed2326a42e391e3b098cfea4f06 +#: 5ea8eea489fc43108a439d54fba31068 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:12 of msgid "" "True when the request was written to the server; False when the " "client is not connected." msgstr "" -#: 85c761742fa5450f846373591e4af1ff +#: 2bc5d7e5dfa94eb29b49f12562f57c88 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:14 of msgid "True when the request was written to the server; False when the" msgstr "" -#: 6ae9ff84b7d64c30abd31cde1715b783 +#: 45d974ad946b408b91d41bcce65abcc8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:15 of msgid "client is not connected." msgstr "" -#: 7b79bd0e677c42fd921308a34e9a0929 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 +#: c9401da7c37e40e5978c80e4876b11a0 of msgid "Read console lines and act on them until the client stops." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 -#: d91a5c812cdb4705a2fa27ac33ef693a of +#: 793bcfd02c014200b0ec47f8e15b4d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 of msgid "" "``/quit`` closes the connection; ``/send_msg``, ``/file``, " "``/multiple_file``, ``/file_folder``, ``/multiple_file_folder``, " @@ -1781,38 +2293,77 @@ msgid "" "it stands. Ctrl-C and EOF close the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 -#: dc2c54034ec64b61a3af655e86bc81a2 of +#: 7ba721f9d59742b99e89e3b6e249e754 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (the target of a forward, " +"never the relay): it is stored with the progress entry so a later " +"reconnect can be resumed. ``resume_offset`` continues an interrupted " +"transfer from the byte the receiver already holds: the file is read from " +"there instead of its first byte." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:3 +#: a3c59554b8de41b280df7536b307bed0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and drives " +"every download that can be continued: a file the server was sending is" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:6 +#: fae378e888be4821a14ed2483cfde1e0 of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer the " +"client can reach." +msgstr "" + +#: 48061103ed9d4bcaae8a8a837b363557 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:10 of +msgid "Number of resumed transfers started or requested." +msgstr "" + +#: 6dbae803a56c442588b28af664b7a0e9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 of msgid "" "/forward_file ... ... [dest] (client " "only)." msgstr "" -#: 303ae7e9e20444e38b303177bef0fb36 +#: 05cad8b03e0747dc804ffbfda3122fe1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_folder_console:1 of msgid "" "/forward_folder ... ... [dest] " "(client only)." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 -#: ec2b9ff3c5cf4fb5a79e29242221fe67 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:3 +#: f6f606236f434f0287a969ccbe5ba2c5 of +msgid "" +"``peer`` is the transfer's original sender (the server for a pushed file," +" the originating client for a forwarded one — never the relay): it is " +"stored with the progress entry so a later reconnect can ask that peer to " +"continue the file." +msgstr "" + +#: 6e9a9717a782419baecca63fd1f46baf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 of msgid "Close the connection and release everything the client owns." msgstr "" -#: 43645acb6c524c348b870d288aafae5e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 +#: ba6c5badecf6465db6036735870ed305 of msgid "" "Stops the receive loop, releases the port range, flushes the message and " -"event stores and closes the socket. Safe to call more than once." +"event stores, persists the interrupted transfers and closes the socket. " +"Safe to call more than once." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:1 -#: afb1904037404a6c99f6b7ae2df119e2 of +#: c91a3245b93f46abbb49dbef7bcfeb1c of msgid "Connect to the server and start the client loop." msgstr "" -#: 6f912c76416e4f37a750eda0c126da35 +#: 0c83552867484ea780fcff8d34e5c2d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:3 of msgid "" "Enters `interactive_mode` when ``is_input_command_in_console`` is True, " @@ -1822,6 +2373,15 @@ msgid "" "while still connecting returns quietly, because that stop was asked for." msgstr "" +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:9 +#: eec663f58484446ebce460e6402d7b5f of +msgid "" +"With ``is_auto_reconnect`` True a dropped connection does not end the " +"client: it reconnects (waiting for the server when ``is_wait_server`` is " +"set) and every session carries the interrupted transfers of the previous " +"one (`resume_transfers`). A close or ``/quit`` still stops the client." +msgstr "" + #~ msgid "" #~ "Concepts live in " #~ "``docs/Network_APIs/TCP_Server_APIs.rst`` and " @@ -1917,3 +2477,117 @@ msgstr "" #~ " `close`." #~ msgstr "" +#~ msgid "" +#~ "one message per line, terminated by " +#~ "a newline; a line that starts with" +#~ " ``/`` is a command and goes to" +#~ " the command handlers, anything else " +#~ "is a plain message reported to the" +#~ " registered message listeners;" +#~ msgstr "" + +#~ msgid "" +#~ "an RSA-encrypted channel is negotiated" +#~ " right after connect unless " +#~ "``is_enable_encrypto`` is False;" +#~ msgstr "" + +#~ msgid "" +#~ "file/folder transfer, message forwarding and" +#~ " port allocation are layered on the" +#~ " same socket and share its command" +#~ " namespace." +#~ msgstr "" + +#~ msgid "" +#~ "The forwarding extensions use the " +#~ "module-level parsers `parse_forwarded_message`, " +#~ "`parse_forward_items_and_addrs`, `parse_forward_originator` " +#~ "and `forward_skip_message`." +#~ msgstr "" + +#~ msgid "" +#~ "Each accepted connection is served by" +#~ " `handle_client`, either in its own " +#~ "thread (the default) or by a " +#~ "coroutine on an asyncio event loop " +#~ "when ``is_asynic_clients_io`` is True: a " +#~ "line starting with ``/`` goes to " +#~ "`handle_command` (built-in commands plus " +#~ "the handlers registered with " +#~ "`register_command`), any other line is a" +#~ " plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(client_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "" +#~ "Plain messages are the lines received" +#~ " from clients that do not start " +#~ "with ``/``; commands go through the " +#~ "registered command handlers instead." +#~ msgstr "" + +#~ msgid "Write one line to a client socket, encrypting when the channel is up." +#~ msgstr "" + +#~ msgid "" +#~ "Lines received from the server go " +#~ "through `receive_messages`: a line starting" +#~ " with ``/`` is handled by " +#~ "`handle_server_command` (protocol commands plus " +#~ "the handlers registered for the " +#~ "\"server\" side), any other line is " +#~ "a plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``. With " +#~ "``is_input_command_in_console`` the console thread" +#~ " `interactive_mode` sends typed lines to" +#~ " the server." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(sender_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "Mirrors the server-side contract; commands are not reported here." +#~ msgstr "" + +#~ msgid "" +#~ "Runs on the receive thread: plain " +#~ "lines are reported to the message " +#~ "listeners and stored in ``messages_dict`` " +#~ "(``/send_msg_from`` envelopes are attributed " +#~ "to their sender first), other ``/`` " +#~ "lines go to `handle_server_command`. Any " +#~ "end of the connection clears ``running``" +#~ " and releases the port range." +#~ msgstr "" + +#~ msgid "" +#~ "Handles the protocol's own lines: " +#~ "``/crypto_mode`` (a mismatch closes the " +#~ "connection), ``/client_alloc_port_range``, the " +#~ "``/crypto_*`` exchange lines, and the " +#~ "transfer lines ``/file``, ``/file_folder``, " +#~ "``/forward_upload``, ``/pause_trans``, ``/start_trans``," +#~ " ``/forward_error``. Any other name goes" +#~ " to the handlers registered for the" +#~ " \"server\" side via `register_command`; an" +#~ " unknown command is only reported on" +#~ " the console." +#~ msgstr "" + +#~ msgid "" +#~ "Stops the receive loop, releases the " +#~ "port range, flushes the message and " +#~ "event stores and closes the socket. " +#~ "Safe to call more than once." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po index 3e80132..4899978 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -20,21 +20,21 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.rsa_crypto.rst:2 -#: a48a4f614e834981afd42e2cb723ce06 +#: def9740b5a2e4aaeb2aeed8b4f02c0ec msgid "PyFlow.network\\_api.rsa\\_crypto module" msgstr "" -#: PyFlow.network_api.rsa_crypto:1 e529881eccb0440c888d5c69244133f9 of +#: 46d3090efafd4504870cf72a4bea22ab PyFlow.network_api.rsa_crypto:1 of msgid "crypto_api (C/OpenSSL) RSA integration for PyFlow's TCP layer." msgstr "" -#: PyFlow.network_api.rsa_crypto:3 d9d01596a65340fb84c25298550845cf of +#: 5b1ff4a00b0f46258cda2e7440368de1 PyFlow.network_api.rsa_crypto:3 of msgid "" "A thin ctypes binding to the shared ``libcrypto_api`` plus the key " "lifecycle required by the encrypted TCP channel:" msgstr "" -#: 232e71aebc434fb6bece23f593557e9f PyFlow.network_api.rsa_crypto:6 of +#: PyFlow.network_api.rsa_crypto:6 a5a0d6d600604683990a92555a49a3fe of msgid "" "Reuse an existing RSA keypair from ``~/.ssh`` (PEM private key) when one " "is present and parseable, otherwise generate a fresh keypair into " @@ -42,7 +42,7 @@ msgid "" "honoured when both files parse and the pair matches." msgstr "" -#: 29d30af10f8c4180890f876bb14b00e3 PyFlow.network_api.rsa_crypto:10 of +#: PyFlow.network_api.rsa_crypto:10 bb413dc908624589a3e57f8a2c702728 of msgid "" "Anti-MITM identity check (TOFU): every connection exchanges public keys " "in plaintext. Each side records the peer in " @@ -52,14 +52,21 @@ msgid "" "endpoint is re-registered under the new ``(ip, port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto:16 d4873e3b840e4e7fbe4c6f85850dc2a7 of +#: PyFlow.network_api.rsa_crypto:16 aec1a7998276428881efcfac6fe4cebe of msgid "" "RSA-OAEP encrypt/decrypt with the ``_VALID`` plaintext signature so a " "stale key (for example a rotated ``~/.ssh`` pair) is detected and the " "peers re-exchange their public keys." msgstr "" -#: 49f63152bca249588cf98871d5bafa64 PyFlow.network_api.rsa_crypto:20 of +#: 392850c432f2466ab9ecfd64770e648d PyFlow.network_api.rsa_crypto:19 of +msgid "" +"ECDH key agreement (P-256/P-384/P-521) with HKDF-SHA256 session-key " +"derivation and AES-256-GCM ``seal``/``open`` (``EcdhKeyPair``, " +"``EcdhPubKey``, ``hkdf_sha256``)." +msgstr "" + +#: 55cfc03aeb3f4d6ba37b10a01dfcdccc PyFlow.network_api.rsa_crypto:23 of msgid "" "The C library is compiled into the installed package by ``setup.py`` (a C" " compiler and OpenSSL development headers are needed at install time); a " @@ -67,21 +74,33 @@ msgid "" "still supported. See ``load_library`` for the search paths." msgstr "" -#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 -#: a3ac757cc1fa4c73be13eaa020c8e60b of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 of msgid "Raised when the shared libcrypto_api cannot be loaded." msgstr "" -#: 9c5bbad270ac48cd997b23cd4f284152 PyFlow.network_api.rsa_crypto.RsaKey:1 of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:1 of +msgid "Raised when a ``pf_*`` call fails." +msgstr "" + +#: 2c3651ee5dc94886986aa9804b164e3d +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:3 of +msgid "" +"``code`` is the ``pf_err_t`` value (one of the ``PF_ERR_*`` module " +"constants), or ``None`` when the failing call returned no code." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.RsaKey:1 e620122ff0bc48dd985c4b6a0b3b41ce of msgid "Owns an ``pf_rsa_key_t*`` handle; frees it on GC." msgstr "" -#: 0eab5b9b31774196a46b7d400341a404 +#: 1a7d8e9db5a3435486d716b13f2a2a56 #: PyFlow.network_api.rsa_crypto.load_library:1 of msgid "Locate and load the shared crypto_api library (cached)." msgstr "" -#: 8bcac9994a6048e4920e23b8f94bb000 +#: 287fcfd81df2461d8e4bceebf61b7e40 #: PyFlow.network_api.rsa_crypto.load_library:3 of msgid "" "Search order: the library ``setup.py`` compiles into the installed " @@ -92,25 +111,98 @@ msgid "" "reported only if no other candidate works." msgstr "" -#: PyFlow.network_api.rsa_crypto.get_local_mac:1 -#: b555d90eff7c445a8a28cb3de88bd581 of +#: PyFlow.network_api.rsa_crypto.EcdhPubKey:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_pubkey_t*`` handle; frees it on GC." +msgstr "" + +#: 556fdf46d6c543e0ab06e2d4fabad7f1 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:1 of +msgid "Parse a peer public key from a PEM string." +msgstr "" + +#: 88cd040e91194a3785bf56d7c52d3543 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_PARSE`` for " +"malformed PEM or a point that is not on the curve (the C library verifies" +" the point)." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_keypair_t*`` handle; frees it on GC." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:3 f12b2d8d1d4846edbf60d64c34860558 +#: of +msgid "" +"``curve`` is one of ``\"P-256\"``/``\"P-384\"``/``\"P-521\"`` (``None`` " +"selects P-256). OpenSSL key objects are not safe for concurrent use, so " +"``public_pem``/``seal``/``open`` are serialised by an internal lock." +msgstr "" + +#: 07643e7c481f49cba8b4ab33bd4174e0 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.public_pem:1 of +msgid "Export our public key as a PEM SubjectPublicKeyInfo string." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:1 +#: ce09888aa11f4f01a8d4bdb80f94321f of +msgid "Encrypt ``plain`` to ``peer`` with an ECDH-derived AES-256-GCM key." +msgstr "" + +#: 965e41e97f5547c3a0bc77531ae3b3f9 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:3 of +msgid "" +"Returns the wire blob, exactly ``PF_ECDH_SEAL_OVERHEAD`` bytes longer " +"than ``plain``. Raises ``CryptoOperationError``." +msgstr "" + +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:1 of +msgid "Inverse of :meth:`seal`, using ``peer``'s public key." +msgstr "" + +#: 4212d23f4b14479b971145af1bc12fa5 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_AUTH_FAILED`` when" +" the tag does not verify (tampered ciphertext, wrong peer key or " +"mismatched AAD)." +msgstr "" + +#: 7fec5dc58def4bbc886ca30568df0661 PyFlow.network_api.rsa_crypto.hkdf_sha256:1 +#: of +msgid "HKDF-SHA256 (RFC 5869 extract-and-expand) over ``ikm``." +msgstr "" + +#: 462a97910aff4e9aae066e31f55d5233 PyFlow.network_api.rsa_crypto.hkdf_sha256:3 +#: of +msgid "" +"``salt`` and ``info`` may be empty. ``out_len`` must be in " +"``1.._HKDF_SHA256_MAX_OUT``. Raises ``CryptoOperationError``." +msgstr "" + +#: 670f4a719bf24c24b48ecb5d73b373ce +#: PyFlow.network_api.rsa_crypto.get_local_mac:1 of msgid "Return a stable 48-bit machine identifier as colon-separated hex." msgstr "" -#: 311d6e5bcdba40d1b05fd63528abcf74 -#: PyFlow.network_api.rsa_crypto.get_local_mac:3 of +#: PyFlow.network_api.rsa_crypto.get_local_mac:3 +#: f1306bb875d34b558f7418278fded413 of msgid "" "Uses ``uuid.getnode()`` (the real hardware MAC when one is available). " "Server and client on the same host share this value; the ``_`` " "prefix in the key file names keeps them apart." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto:1 b385913eca73436ab76b76787114e163 +#: 333763d798c54d52a9a56a3e4e3e2155 PyFlow.network_api.rsa_crypto.RsaCrypto:1 #: of msgid "Key lifecycle plus RSA-OAEP encrypt/decrypt for one role." msgstr "" -#: 7c2b4fafe779449a8245780da7a4ef91 PyFlow.network_api.rsa_crypto.RsaCrypto:3 +#: PyFlow.network_api.rsa_crypto.RsaCrypto:3 f52515121ac74575aaa36d45dd0341a2 #: of msgid "" "``role`` is ``\"server\"`` or ``\"client\"`` and is used to name the " @@ -119,13 +211,13 @@ msgid "" " in ``pub_key/pub_key.json`` (TOFU, see ``verify_peer_pub``)." msgstr "" -#: 1e24448b89684701a1fa13b02e9d0d84 +#: 56fed5bcfe194b7f90a0c662ae36d6c0 #: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:1 of msgid "Create the crypto wrapper for ``role`` (\"server\" or \"client\")." msgstr "" -#: 00101f4b9ef44a83b2e51f9974a3d92a -#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 +#: ca4e27664ccf40ce935d991db43f7c69 of msgid "" "``custom_keys`` may be a ``[pub_key_path, pvt_key_path]`` pair to use a " "user-supplied RSA keypair instead of the default lookup (``~/.ssh`` / " @@ -134,78 +226,78 @@ msgid "" "used instead." msgstr "" -#: 4e9b33835a9448bca28d9e2e3a782d77 +#: 7d89122ff0f54090b67209e3b08ae29c #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:1 of msgid "Load the RSA keypair (see module docstring) and cache handles." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:3 -#: e7fd217ab95d483084e4c7d58b715349 of +#: d5e494e00be44891b33cb8e0ecfb8081 of msgid "" "Runs under ``_key_lock``: the private-key handle must never be replaced " "(or freed on GC) while another thread is decrypting." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.reload_own_key:1 -#: c1e8b452b697431aaafee424e1edd3e2 of +#: f6f7d6ec8837464dad2dc647e6141a99 of msgid "Re-read the private key (e.g. after a ~/.ssh rotation)." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:1 -#: fabae86a23844d9cba130ff2f2adc080 of +#: e95d18da34d14376987a62f6cbbec778 of msgid "" "Path of the exchanged public key file for ``peer_role`` at ``(peer_ip, " "peer_port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 -#: fa9eee0dbc724d0bbfa8e36bcdd89ba4 of +#: 52dc6fb74f0c4175bfa2a2acc23cda0d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 of msgid "" "The IP is sanitized for the filesystem (``:`` -> ``_`` so IPv6 literals " "are safe on every platform, including Windows)." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 -#: ce570f7fdb834fc3982aa0ec0e98b896 of +#: 731d92a1b64342dfbf7c467af0a4c00e +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 of msgid "TOFU check-and-record for a peer public key." msgstr "" -#: 2879d5b42eed4eaca2af859a86db52e8 +#: 634283c14fb44424bf148a34d156fb71 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:3 of msgid "" "``peer_pem`` is the PEM text received on this connection, ``(peer_ip, " "peer_port)`` the endpoint it came from. Returns ``(ok, reason)``:" msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 -#: b6f7afce352240b8ba2cf6a4e38aa457 of +#: 6bb58c88f8454d7daca92b5a478ae788 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 of msgid "" "key already registered under any endpoint -> accept, and re-register it " "under the current endpoint when it moved (IPs are dynamic and ports are " "user-changeable);" msgstr "" -#: 014d219898a04debb9eace0ea28aaa83 +#: 74e2bcc89bae4fe5aecf99e6208e21d1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:10 of msgid "" "key unknown but the endpoint already holds a *different* key -> reject (a" " trusted endpoint suddenly presenting a new key);" msgstr "" -#: 5aabe21775144f3fb2e5b4ae5a190569 -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 +#: f856b875adc34f4a80c2b21cd506b143 of msgid "" "key and endpoint both unknown -> accept and record (first connection is " "trusted, TOFU)." msgstr "" -#: 2bcc3b43a6d54e91b48a51fdf715a346 +#: 556fdf46d6c543e0ab06e2d4fabad7f1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:1 of msgid "Move a freshly received public key file into the key cache." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:3 -#: a32f32a711ec453684a2fa927aaaa06e of +#: a47e84f5d21949bf98e24834f18bed76 of msgid "" "Idempotent under concurrency: several transfers may deliver the same peer" " key at once (multi-connection handshakes, several client processes " @@ -214,13 +306,13 @@ msgid "" "destination is in place." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 -#: c54c296562484982abff2e1436305b98 of +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 of msgid "Encrypt ``plaintext`` with the peer's public key file." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 -#: f7f5e3490fb44e85919611c0b3b9ecc7 of +#: 4b4dded0ad904ce2bb87c9a43c8f87e5 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 of msgid "" "Returns the ASCII wire body (no trailing newline): each chunk is RSA-OAEP" " encrypted and base64 encoded, chunks joined with ``|``. Raises if no " @@ -229,12 +321,12 @@ msgid "" "encrypt (no-GIL safe)." msgstr "" -#: 8860142532044e87aa78adc123c33d62 +#: 8f1687f4ab984c029859fd1f9cfb968c #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:1 of msgid "Decrypt a wire body with our private key." msgstr "" -#: 888f7928d8274beda354f5b657613fec +#: 8a1d1504bf4248fa9e1288776d19810b #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:3 of msgid "" "Returns ``(True, plaintext)`` on success, or ``(False, None)`` when the " diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po index 6da41af..656706f 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -17,30 +17,32 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_client.rst:2 -#: 8379b786205a4447995cf82b275ee87a +#: 09f60d1b11ac4e92b480fa6284489970 msgid "PyFlow.transfer\\_web.setup\\_client module" msgstr "" -#: 8412539bd9af49e8976ccf5c028061d4 PyFlow.transfer_web.setup_client:1 of +#: 2f786e174934474a93c6498878a68612 PyFlow.transfer_web.setup_client:1 of msgid "PyFlow TCP client web launcher." msgstr "" -#: PyFlow.transfer_web.setup_client:3 d2ed4df91a474301aee43eaf09e1ac87 of +#: 24fa9f33454d4afc9d15c80a0299922d PyFlow.transfer_web.setup_client:3 of msgid "" "Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI " "in the browser. The user enters the server address (an http/https domain" " or a bare IP); the backend asks the server's web backend for the TCP " "server address/port, starts the TCP client, and keeps the backend running" -" to relay the user's frontend actions. The account of the server logs in" -" from the same backend: saved credentials in " -"``.Flow_Web/client_login.json`` are replayed on every start, and the " -"login window appears whenever no session could be restored." +" to relay the user's frontend actions. A server that needs accounts (a " +"verification mailbox is configured) makes the same backend log in: saved " +"credentials in ``.Flow_Web/client_login.json`` are replayed on every " +"start, and the login window appears whenever no session could be " +"restored. A server without a mailbox needs no accounts, so the login " +"window and the account controls are skipped." msgstr "" -#: PyFlow.transfer_web.setup_client.main:1 fd5a9b075a2a4b9a97dbad26743e0403 of +#: PyFlow.transfer_web.setup_client.main:1 ca4ce7c686c84b44ae429e4de15b9afd of msgid "Start the client web backend and serve its UI." msgstr "" @@ -57,3 +59,21 @@ msgstr "" #~ " actions." #~ msgstr "" +#~ msgid "" +#~ "Starts a lightweight Flask backend on" +#~ " 127.0.0.1 and opens the connect UI" +#~ " in the browser. The user enters " +#~ "the server address (an http/https domain" +#~ " or a bare IP); the backend " +#~ "asks the server's web backend for " +#~ "the TCP server address/port, starts the" +#~ " TCP client, and keeps the backend" +#~ " running to relay the user's frontend" +#~ " actions. The account of the server" +#~ " logs in from the same backend: " +#~ "saved credentials in ``.Flow_Web/client_login.json``" +#~ " are replayed on every start, and " +#~ "the login window appears whenever no " +#~ "session could be restored." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po index bc91d75..ad88896 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -17,43 +17,45 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_server.rst:2 -#: 88492dfde47b4dbb914aaba07f359440 +#: e6642bb55a204188b0abd0b07207713e msgid "PyFlow.transfer\\_web.setup\\_server module" msgstr "" -#: 103789700f8d41aa80e1cb374abb02a3 PyFlow.transfer_web.setup_server:1 of +#: 5966876a4564470ea674311ddb3ef63e PyFlow.transfer_web.setup_server:1 of msgid "PyFlow TCP server web launcher." msgstr "" -#: 581fc0a8029c44f7998895401060a79b PyFlow.transfer_web.setup_server:3 of +#: 588fea0dc68a4a308f9a7cfb6fe5d819 PyFlow.transfer_web.setup_server:3 of msgid "Checks ``transfer_web/.Flow_Web/setup_server.json``:" msgstr "" -#: 60412e56b0d44018bbc88cd258e2c48b PyFlow.transfer_web.setup_server:5 of +#: PyFlow.transfer_web.setup_server:5 c3df4df524da40b18a58607efd9b5e4a of msgid "" "missing -> opens the server startup-configuration UI in the browser; the" " UI saves the config (same shape as ``flow_setup``'s ``setup.json``) and " "starts the TCP server class;" msgstr "" -#: 15dae71f4c1243ecb188218cd72eb7c2 PyFlow.transfer_web.setup_server:8 of +#: 211850fce6d34d50ae152bce6d1aa3af PyFlow.transfer_web.setup_server:8 of msgid "present -> starts the TCP server class directly from the saved config." msgstr "" -#: 921ebc855440467cacd9d366085db41a PyFlow.transfer_web.setup_server:10 of +#: 7170b50dcaf2462f918af2271f247c84 PyFlow.transfer_web.setup_server:10 of msgid "" "After the TCP server is up, the lightweight Flask backend serves the " "status page and the client-facing API (``/api/server_info`` etc.) on the " -"server's address. Anonymous visitors also get the landing page with the " -"registration and password-reset flows; accounts live in the SQLite store " -"``.Flow_Web/flow_web.db``, and the verification mails are sent through " -"the mailbox configured in ``.Flow_Web/email_config.json``." +"server's address. Anonymous visitors also get the landing page; its " +"registration and password-reset flows exist while a verification mailbox " +"is configured (settings in ``.Flow_Web/email_config.json``, accounts in " +"the SQLite store ``.Flow_Web/flow_web.db``). That mailbox is also the " +"switch of the client side: with it clients log in with an account, " +"without it they connect without any account at all." msgstr "" -#: 2f09f9248b0e47e3ba9c9792d83a622b PyFlow.transfer_web.setup_server.main:1 of +#: PyFlow.transfer_web.setup_server.main:1 cbf05c29afe74ebd84b898146c971457 of msgid "Start the server web backend and serve its UI." msgstr "" @@ -65,3 +67,17 @@ msgstr "" #~ "server's address." #~ msgstr "" +#~ msgid "" +#~ "After the TCP server is up, the" +#~ " lightweight Flask backend serves the " +#~ "status page and the client-facing " +#~ "API (``/api/server_info`` etc.) on the " +#~ "server's address. Anonymous visitors also " +#~ "get the landing page with the " +#~ "registration and password-reset flows; " +#~ "accounts live in the SQLite store " +#~ "``.Flow_Web/flow_web.db``, and the verification " +#~ "mails are sent through the mailbox " +#~ "configured in ``.Flow_Web/email_config.json``." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po index ff5009c..9f65a88 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po @@ -8,47 +8,49 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst:2 -#: 86d4061dc1f542ac95555aa2deab1101 +#: ffcd351a76b74899a0105947d1049e12 msgid "PyFlow.transfer\\_web.web\\_backend.mail\\_service module" msgstr "" -#: 99f2cb604d5c450c9cda427b22b2c8cb -#: PyFlow.transfer_web.web_backend.mail_service:1 of +#: PyFlow.transfer_web.web_backend.mail_service:1 +#: c6f6b5571d954e7b986a3355033cd30c of msgid "SMTP delivery of account verification codes for the web tool." msgstr "" -#: 1d2a4d079f6c44f182332c5b44d0705a +#: 9764afd408ca43ce829f03d7d4ca675b #: PyFlow.transfer_web.web_backend.mail_service:3 of msgid "" "The administrator configures the outgoing mailbox from the server's " "startup-configuration page. The settings are validated with a real SMTP " "login and only then written to ``.Flow_Web/email_config.json``; while no " "validated configuration is present the service refuses to send, so a " -"server can never silently drop verification codes." +"server can never silently drop verification codes. The same page takes " +"the mailbox away again (`disable`), which switches the server back to " +"internal use." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 -#: e0597ff2442b43dd87c4efaef6c574c5 of +#: 5fdca457edd340eab7c9f05558a37dc5 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 of msgid "Validate untrusted SMTP settings and return them in canonical form." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 069dae5e8fb0426e897adc279499319b 4c58519a459f4b9486f0a571939d4834 -#: 83045ebe35d54d76b13e40961c070d4f eb5501cac4f240b19f2d4f5e5443e3c6 +#: 1cad23766791477aa6fb46051363ef81 73b1f3a5025140ec8701e976293f7af0 +#: 817b9cde77bb4327ad3b9f8356d27f4c a9b0b41ab3fd438c8cb2551b61e1af31 msgid "Parameters" msgstr "" -#: 14138866fd924a0083c8e6562b3860ff +#: 1b2b400edc914a76977297cb9ef6da5d #: PyFlow.transfer_web.web_backend.mail_service.normalize_config:3 of msgid "" "Settings with ``host``, ``port``, ``username``, ``password``, ``from`` " @@ -57,152 +59,183 @@ msgid "" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 170588e452e5431e815fad88a5b5537b 887b6607974c4ea8b99b628ea3efbf45 -#: a16996418f0e4e5ab58b7244ded5e63b c0463031a23c4f799b6a8217f31cc1b1 +#: 097b6a08fc5548d1a5a4568b07bf4326 1388175dc5e64a8eb1a99affd4807d9f +#: 334d15f3b1264e0b8abfc34e8fee985e 8f894b6967fd4867b82c726e85c83dc9 msgid "Returns" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 -#: dafcbdb3cccc40fa89a38363dd5680b0 of +#: 4695369c64494340bb98d06f4029f854 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 of msgid "" "The same settings with a string host, an integer port, a lowercase " "encryption mode and an explicit sender." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 -#: a68a2cdaeea44ccdb70c8e49efbcb5dd of +#: 5c191d5d632a4a71a814aa300592c904 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 of msgid "The same settings with a string host, an integer port, a lowercase" msgstr "" -#: 2bd9bb82ad2749df9c60df8271733a8c -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 of +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 +#: f98ed07dd1474127973e40ea5d133476 of msgid "encryption mode and an explicit sender." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 24fb33faf10542c7a1d5bcd8bc20e135 53904db2f0da42c6ac410c40a9e555a0 -#: 59876b786ae244308cb80d0e15975404 a636a96a44754c789c671d6e95914aea +#: 2ceb9aabd15149e2a74ab44ffc0e7e3b 4f9ea7be9a9d4179b3371b7ffaaf9c64 +#: 75ab32112eb54385b832e99cc66c0f3b 951ba3e6400f48c2baaffe4aceb25ae3 msgid "Return type" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 4375f894dabe4fd49e5d470f602e7e4e 669fcb172313407fa0df09ca10280e22 -#: 9ce7848878e44efba62bd42bd640bdeb +#: 051ee4ae623e4c52aca28e50c43a8659 6c5929a2e83444a0b5026560f2c5af02 +#: 7d5aee61dcaa450790fdaa12bda90f1c b717337ce24a4644a8684f6c14ced1d5 msgid "Raises" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 -#: f6db2cc04ccd4bc0a06c34c8d5d00b29 of +#: 8e1b87a14fc44d6383f43b22bdb71770 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 of msgid "If a setting is missing, malformed or out of range." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 -#: a46df3ad1b4d47838e7d86646e5e45d4 of +#: 9104ff2767b4468db4119f0de6103975 +#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 of msgid "SMTP client delivering verification codes." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService:3 -#: a6a714e990194ee9b2c023afa0423ec6 of +#: b29996ad41f1488f8540e22a48f131fa of msgid "" "The stored configuration is read on construction, so a validated mailbox " "is available again after a restart." msgstr "" -#: 906ef645c3f0431c8d4f44bb661e3119 +#: 67ba292bfc8c40ee863f2bf892ff74cb #: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:1 of msgid "Create the service and load the stored configuration." msgstr "" -#: 886b800f093c4d758d14028b4233d623 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 +#: f7b0ac874bc34b408853f868c5c1a9cd of msgid "" "JSON file holding the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 10490a10be734ca58da591842794088d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 +#: cdbf836d9e9c4e2a948458972edbfbae of msgid "Report whether a validated configuration lets codes be sent." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 -#: a19f7729857a4995be526dded313b07d of +#: 6f529ae442fb4a4ba2e0fd72533d0e29 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 of msgid "True when the SMTP settings were validated and stored." msgstr "" -#: 646e8fd83be4421ab0d3b4d38fe2b1c8 +#: 93c564a9ccd64ebca089cbd00f434f9e #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:1 of msgid "Return the validated SMTP settings." msgstr "" -#: 1728b9dc41484d35851721b141e661be +#: 83356ba5ccea4bceae862cc0934959cf #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:3 of msgid "" "Copy of the stored settings, or ``None`` while the service is not " "configured." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 -#: cb61516a7cac473fa2ab322e29340899 of +#: 77ff24f402974e8681e2273634e17e4c +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 of msgid "Copy of the stored settings, or ``None`` while the" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 -#: ba7116251d3b4ce7b97a3e79808c4415 of +#: 383ba8fc4ed940f38097d10bfbc8ff84 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 of msgid "service is not configured." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:1 -#: a2161943624d40a39a45564117df6d9e of +#: c7110be43ff548edb573b0b645e49ef5 of msgid "Validate SMTP settings, store them and start the sending service." msgstr "" -#: 8d8686cd5b9b46d295719719f9b29929 +#: 99385960778b4785bb73f4db98d2dada #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:3 of msgid "Settings accepted by `normalize_config`." msgstr "" -#: 5aa35eba13e04367b7f99d754176a39d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 +#: d801399842874f19943e8d2eb6dd6e6d of msgid "The validated settings as stored." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:9 -#: ab75660bdd60437dbb05953445043ce0 of +#: c4c8574eb0634811a9fd71b2e00233a9 of msgid "" "If a setting is missing or malformed, or the server refuses the " "connection or the login." msgstr "" -#: 4ebf6576a62643d9910acdfba3fcd799 +#: 5c332d9d6242449f97b7bddbe36a20cd +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:1 of +msgid "Remove the stored mailbox so no verification code can be sent." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:3 +#: bc6f8bbf1f0047cebea68882e633945d of +msgid "" +"This is the switch back to internal mode: with no mailbox the server " +"serves its clients without accounts again." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:6 +#: f669f3bdc1f44730a90a6127ff7db331 of +msgid "" +"If the stored file cannot be removed; the service then keeps its " +"settings and stays enabled." +msgstr "" + +#: 7b942af00fc54d9d836170d61972977e #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:1 of msgid "Send one verification code by email." msgstr "" -#: 8f04bd37dc8b4483af595c5e66f8fbf4 +#: 6cdc276558b54671b93a8a839f34a682 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:3 of msgid "Recipient address." msgstr "" -#: 57f0544cdf234e00b9f03da47566354f +#: 60f83153ebac42eeb7ba36ed193d0eb1 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:5 of msgid "Verification code to deliver." msgstr "" -#: 627ee080c93e46679b0eb1dea17640f6 +#: 25f348d2347c4274a624e6d13eb6dfd3 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:7 of msgid "" "\"register\", \"login\" or \"reset_password\"; decides the wording of the" " message." msgstr "" -#: 6733b65d0a2347e1918c983503394f49 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 +#: f16d610fc9f14559af45cddea444add9 of msgid "Code lifetime in seconds, stated in the message." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 -#: ce7cf70f7a2d4deca8256ada1fc9b63d of +#: 134b78c9128942938629dd61e9048916 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 of msgid "If the service is not configured, or the message cannot be delivered." msgstr "" +#~ msgid "" +#~ "The administrator configures the outgoing " +#~ "mailbox from the server's startup-" +#~ "configuration page. The settings are " +#~ "validated with a real SMTP login " +#~ "and only then written to " +#~ "``.Flow_Web/email_config.json``; while no validated" +#~ " configuration is present the service " +#~ "refuses to send, so a server can" +#~ " never silently drop verification codes." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po index 9575285..af2798a 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -17,24 +17,24 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst:2 -#: 7bc35f7e619347e0b976ca49c973de8f +#: 4e16e69f9ae9491a95bfcab9c70cfe24 msgid "PyFlow.transfer\\_web.web\\_backend.server\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:1 -#: fd1d19a74e7a4e14a3863a4f2d4e6eef of +#: 15eb6d4006b3429a8fa230a2b460b1c5 +#: PyFlow.transfer_web.web_backend.server_backend:1 of msgid "Flask backend wrapping the PyFlow TCP server for the web tool." msgstr "" -#: 6fa9dfd64064447c82ade7290b523d5c +#: 3c413c9e37f94c7485dba6d4f96b9bf2 #: PyFlow.transfer_web.web_backend.server_backend:3 of msgid "Two modes, one process:" msgstr "" -#: 8e61412bb72d49b086f03a2245cd959d +#: 557b793ac8e441db86cf59cad5e85371 #: PyFlow.transfer_web.web_backend.server_backend:5 of msgid "" "``config`` mode: serves the server startup-configuration UI. The UI " @@ -45,7 +45,7 @@ msgid "" msgstr "" #: PyFlow.transfer_web.web_backend.server_backend:10 -#: b15a182866794bf7bfe71605fc47a301 of +#: cb922669795b42c6ad5587b527c4356a of msgid "" "``status`` mode: serves the minimal status page plus the same " "sidebar/input UI as the client frontend (forwarding disabled; native " @@ -53,93 +53,105 @@ msgid "" "clients use to discover the TCP server address/port." msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:15 -#: a297544539714d03afa00d1112541712 of +#: 0c6784517a194d65926c71b7ce7f4836 +#: PyFlow.transfer_web.web_backend.server_backend:15 of msgid "" "The backend monitors ``server.clients``: whenever a client connects or " "disconnects it broadcasts the current instance list to every connected " "client (``/web_clients_update``), and it re-checks the list every minute." msgstr "" -#: 9ad7bd78687141a8a282a951ddc57689 +#: 535e49236690482ebf574e6c65b10f39 #: PyFlow.transfer_web.web_backend.server_backend:20 of msgid "" "Inbound events (plain-text messages and file uploads arriving from " "clients) are captured on the TCP server's receive threads through " "``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` " -"APIs, queued here, and polled by the frontend via ``/api/events``." +"APIs, queued here, and polled by the frontend via ``/api/events``. The " +"message listener reports every inbound line, protocol commands included; " +"the commands are dropped here, so the queue carries user messages only. A" +" file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 69da06074d1141308bd12409e851f506 -#: PyFlow.transfer_web.web_backend.server_backend:25 of +#: 6ee75a9919554a3cb05d55c0f9dba653 +#: PyFlow.transfer_web.web_backend.server_backend:30 of msgid "" "Authentication: anonymous visitors get a white landing page (the server " -"addresses, a login button, a registration button and a password-reset " -"button); the configuration and status pages need a session. Accounts " -"live in the SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`);" -" the first run seeds the ``admin``/``admin`` administrator and the " -"frontend warns on every login until those default credentials are " -"changed. Registration, password reset and code-based client logins are " -"delivered by the mailbox configured from the startup-configuration page " -"(see `mail_service`)." -msgstr "" - -#: 1fb7feafe6ba447e992cd3ebd42801c8 -#: PyFlow.transfer_web.web_backend.server_backend:34 of +"addresses and a login button; while a verification mailbox is configured," +" also a registration button and a password-reset button); the " +"configuration and status pages need a session. Accounts live in the " +"SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the first " +"run seeds the ``admin``/``admin`` administrator and the frontend warns on" +" every login until those default credentials are changed. Registration, " +"password reset and code-based client logins are delivered by the mailbox " +"configured from the startup-configuration page (see `mail_service`)." +msgstr "" + +#: 14b91efc5192438eb9eb025aa4a50ef2 +#: PyFlow.transfer_web.web_backend.server_backend:40 of msgid "" -"Client accounts: the client web frontend logs in through " -"``/api/client_login`` with a username/email, the account password *and* a" -" mailed verification code — both factors are required — and receives a " -"session token. Re-entering the client web UI replays the saved " -"credentials and token through ``/api/client_verify``, which only accepts " -"them while they still open that account. The token binds the TCP " -"connection the client opens (``/web_bind``) to that account, and the " +"Client accounts: the verification mailbox is the switch of the whole " +"client side. While ``.Flow_Web/email_config.json`` holds a validated " +"mailbox the server is meant for public networks: the client web frontend " +"logs in through ``/api/client_login`` with a username/email, the account " +"password *and* a mailed verification code — both factors are required — " +"and receives a session token. Re-entering the client web UI replays the " +"saved credentials and token through ``/api/client_verify``, which only " +"accepts them while they still open that account. The token binds the TCP" +" connection the client opens (``/web_bind``) to that account, and the " "instance list pushed to a client is limited to its contacts, so accounts " -"that never exchanged a contact request cannot see each other." +"that never exchanged a contact request cannot see each other. Without a " +"mailbox the server is an internal tool: clients connect without " +"registration or login, every client sees every other connected instance, " +"and the client account routes are closed — only the console administrator" +" keeps an account." msgstr "" -#: 123122acd40847679e349c6e3b8d9c5e -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 of +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 +#: ab4c37912c524489a26700248a06704c of msgid "Flask app + TCP_Server_Base wrapper for the web tool." msgstr "" #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:1 -#: b7ccb1c765d744b988819d0afbbab22d of +#: fb6d7d555b47497fa6861b7f8a6a5f5d of msgid "Create the Flask app and its stores." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst -#: b841315945d14f34a8ef0541284d23e3 +#: 0fb91f29d163495c8c5e4b758c29cf92 msgid "Parameters" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 -#: c8c0a79297824242960049876ebd3e56 of +#: 79acd75ba91d4388972788215a4dcde7 +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 of msgid "" "Port of this web backend; defaults to ``DEFAULT_WEB_PORT``. A busy port " "falls back to the next free one." msgstr "" -#: 652d75ee0a3d4dd18396a8e2b5aa315e +#: 7dd94be740ee476ea378e766ecf5640b #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:6 of msgid "SQLite account database; defaults to ``.Flow_Web/flow_web.db``." msgstr "" -#: 34f17ede4f7c4556a62f8cc47f3c399d +#: 1db79ba202e74aeebefe1de0df4f3f3f #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:9 of msgid "" "JSON file with the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 011de011008f44dc9c247510315a2341 +#: 7e707a76895243cbb7e49d4a943df5f2 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:1 #: of msgid "Read ``.Flow_Web/setup_server.json`` and start the TCP server." msgstr "" +#: 7a3de044fc304747a1be4161fe0f2e51 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:3 -#: baae3df9217643d0a41c83324c8f035d of +#: of msgid "" "The saved \"ftp\" share is restored as well, so a folder shared before " "the restart keeps being served." @@ -180,3 +192,52 @@ msgstr "" #~ msgid "Rename ``username`` and set its password (self-service)." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " file uploads arriving from clients) " +#~ "are captured on the TCP server's " +#~ "receive threads through ``TCP_Server_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Authentication: anonymous visitors get a " +#~ "white landing page (the server " +#~ "addresses, a login button, a " +#~ "registration button and a password-reset" +#~ " button); the configuration and status " +#~ "pages need a session. Accounts live " +#~ "in the SQLite store ``.Flow_Web/flow_web.db``" +#~ " (see `user_database`); the first run " +#~ "seeds the ``admin``/``admin`` administrator " +#~ "and the frontend warns on every " +#~ "login until those default credentials " +#~ "are changed. Registration, password reset " +#~ "and code-based client logins are " +#~ "delivered by the mailbox configured from" +#~ " the startup-configuration page (see " +#~ "`mail_service`)." +#~ msgstr "" + +#~ msgid "" +#~ "Client accounts: the client web frontend" +#~ " logs in through ``/api/client_login`` with" +#~ " a username/email, the account password " +#~ "*and* a mailed verification code — " +#~ "both factors are required — and " +#~ "receives a session token. Re-entering" +#~ " the client web UI replays the " +#~ "saved credentials and token through " +#~ "``/api/client_verify``, which only accepts " +#~ "them while they still open that " +#~ "account. The token binds the TCP " +#~ "connection the client opens (``/web_bind``)" +#~ " to that account, and the instance" +#~ " list pushed to a client is " +#~ "limited to its contacts, so accounts " +#~ "that never exchanged a contact request" +#~ " cannot see each other." +#~ msgstr "" + diff --git a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po index a63dc02..e5df18e 100644 --- a/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po +++ b/docs/source/locale/ko/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ko\n" @@ -17,19 +17,19 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_front.client_backend.rst:2 -#: 411a61682c95447192de34eca6a7b40c +#: a7e084a5059341aa9b7419059c4fa4b0 msgid "PyFlow.transfer\\_web.web\\_front.client\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:1 -#: c5b03318abd74b32b6ffba1696f8b20b of +#: 22485674cb53445a86703fb118698523 +#: PyFlow.transfer_web.web_front.client_backend:1 of msgid "Flask backend wrapping the PyFlow TCP client for the web tool." msgstr "" -#: 13a2da9087074258858c4dd7a697671e +#: 31862d77d7184e55a1e729d7e72baed0 #: PyFlow.transfer_web.web_front.client_backend:3 of msgid "" "The launcher (``setup_client.py``) starts this backend and opens the " @@ -40,70 +40,123 @@ msgid "" "relay the user's frontend actions:" msgstr "" -#: 95d3503d45ac47ba8c8a9522aceb4764 +#: 1a028258cda844ee945b9522d51afb9d #: PyFlow.transfer_web.web_front.client_backend:10 of msgid "messages/files/folders to the server use the native transfer methods;" msgstr "" #: PyFlow.transfer_web.web_front.client_backend:11 -#: be1496ab996044798cfc05692616cd8a of +#: e160c2a0daf9498cbe2041a8e964ff47 of msgid "" "messages to other clients use the native ``/forward_send_msg`` forwarding" " (a client-only command relayed by the server);" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:13 -#: a59ab775ca734b828f09313089028a9f of +#: 16da18234f0a499893b711e7b555b42a +#: PyFlow.transfer_web.web_front.client_backend:13 of msgid "" "files/folders to other clients are forwarded through the built-in " "``forward_extension_tcp`` extension." msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:16 -#: ea807a0c324b430c8731aa632d099643 of +#: 79dee862a03f4d0c9bc9403f8d461465 +#: PyFlow.transfer_web.web_front.client_backend:16 of msgid "" "The sidebar instance list is kept fresh by the server's " "``/web_clients_update`` broadcasts; a reload button re-requests the list " "via ``/web_sync_clients``." msgstr "" -#: 3656f3e4bded46b596db7d1bdc666b90 +#: 13d20ecd894c4e26a28266b7ac128dfd #: PyFlow.transfer_web.web_front.client_backend:20 of msgid "" "Inbound events (plain-text messages and files pushed by the server, " "whether direct sends or client forwards) are captured on the TCP client's" " receive threads through ``TCP_Client_Base``'s " "``add_message_listener``/``add_file_listener`` APIs, queued here, and " -"polled by the frontend via ``/api/events``." +"polled by the frontend via ``/api/events``. The message listener reports" +" every inbound line, protocol commands included; a direct command from " +"the server is dropped here, so the queue carries user messages only. A " +"file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 565c32267ec64ccbb0904ef2ec5609df -#: PyFlow.transfer_web.web_front.client_backend:26 of +#: 5c1c2971ea0e45d8a56544972cdc4ff4 +#: PyFlow.transfer_web.web_front.client_backend:31 of msgid "" -"Accounts: a connected client logs in with a server account before the " -"instance list is usable. A forced login needs both factors — the account" -" password and a verification code mailed to the account address — while a" -" client that starts again replays the saved credentials and session token" -" through ``/api/client_verify``. ``/api/login`` opens the session, the " +"Accounts: the connected server decides whether its clients need accounts." +" A server with a verification mailbox is public, so this backend forces " +"the account login before the instance list is usable; a server without " +"one is internal and everything account-related is skipped — no login " +"window, no contacts, and every client sees every other instance. A " +"forced login needs both factors — the account password and a verification" +" code mailed to the account address — while a client that starts again " +"replays the saved credentials and session token through " +"``/api/client_verify``. ``/api/login`` opens the session, the " "``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the " "contact management to the server, and the session token is sent over TCP " "with ``/web_bind`` so the server can push the contact list of that " "account. The credentials are remembered in " -"``.Flow_Web/client_login.json`` (owner-readable only) and the login " -"window is shown whenever no session could be restored." +"``.Flow_Web/client_login.json`` (owner-readable only)." msgstr "" -#: 1e6c10d599f046398e16a7b47e0b8dab +#: 0913e15917534119b775fb5c545c439d #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp:1 of msgid "Flask app + TCP_Client_Base wrapper for the web tool." msgstr "" -#: 6c87b744956640d682bef32158496990 #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:1 +#: bc85ca281f4e4df5a0f10290029fca34 of +msgid "Start the TCP client from ``.Flow_Web/setup_client.json``." +msgstr "" + +#: 612871943a7e45a2bacdc377aec78b77 +#: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:3 #: of -msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +msgid "" +"The connected server reports whether its clients log in; only then is a " +"saved session replayed, and the login window is only shown then." msgstr "" #~ msgid "Read ``.Flow_Web/setup_client.json`` and start the TCP client." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " files pushed by the server, whether" +#~ " direct sends or client forwards) are" +#~ " captured on the TCP client's receive" +#~ " threads through ``TCP_Client_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Accounts: a connected client logs in " +#~ "with a server account before the " +#~ "instance list is usable. A forced " +#~ "login needs both factors — the " +#~ "account password and a verification code" +#~ " mailed to the account address — " +#~ "while a client that starts again " +#~ "replays the saved credentials and " +#~ "session token through ``/api/client_verify``. " +#~ "``/api/login`` opens the session, the " +#~ "``/api/contacts/*`` and ``/api/contact_requests`` " +#~ "routes proxy the contact management to" +#~ " the server, and the session token" +#~ " is sent over TCP with ``/web_bind``" +#~ " so the server can push the " +#~ "contact list of that account. The " +#~ "credentials are remembered in " +#~ "``.Flow_Web/client_login.json`` (owner-readable " +#~ "only) and the login window is " +#~ "shown whenever no session could be " +#~ "restored." +#~ msgstr "" + +#~ msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/Crypto/Crypto.po b/docs/source/locale/ru/LC_MESSAGES/Crypto/Crypto.po index 435eab5..0f90936 100644 --- a/docs/source/locale/ru/LC_MESSAGES/Crypto/Crypto.po +++ b/docs/source/locale/ru/LC_MESSAGES/Crypto/Crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../source/Crypto/Crypto.rst:2 bb50e4f310ea43d9ba55e4b367ed7740 +#: ../../source/Crypto/Crypto.rst:2 9878b2fb3d9d4d6ba3cd00002ed6f0b7 msgid "C/OpenSSL Crypto Module" msgstr "Крипто-модуль C/OpenSSL" -#: ../../source/Crypto/Crypto.rst:4 2838c629d37d42ef92dbabeab8d33801 +#: ../../source/Crypto/Crypto.rst:4 aa824d3e127240b0928431af3dd8c831 #, fuzzy msgid "" "The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL " @@ -32,62 +32,62 @@ msgstr "" "C/OpenSSL ServSpy. Библиотека независима от среды выполнения Python и " "собирается из корня репозитория с помощью CMake." -#: ../../source/Crypto/Crypto.rst:8 2c028ead37a24eb98321135f22f3673d +#: ../../source/Crypto/Crypto.rst:8 294667df2a20495887126b808c7d9706 msgid "The module provides:" msgstr "Модуль обеспечивает:" -#: ../../source/Crypto/Crypto.rst:10 e290cfffb80140899093170eda086e61 +#: ../../source/Crypto/Crypto.rst:10 472d4f3082db42f198b7f13fdbf041f2 msgid "RSA-OAEP encryption and decryption with SHA-256." msgstr "Шифрование и дешифрование RSA-OAEP с помощью SHA-256." -#: ../../source/Crypto/Crypto.rst:11 125f1968eba34f6896b44b6406f0e6c2 +#: ../../source/Crypto/Crypto.rst:11 0eb3f7206503452ca2229a1d7c323390 msgid "ECDH key agreement on P-256, P-384, and P-521." msgstr "Ключевое соглашение ECDH по P-256, P-384 и P-521." -#: ../../source/Crypto/Crypto.rst:12 cee735932767478e95a96b9a59ddcdd2 +#: ../../source/Crypto/Crypto.rst:12 ab0be16cfbca493a88c6eb4a2ef1bb07 msgid "HKDF-SHA256 session-key derivation." msgstr "Получение сеансового ключа HKDF-SHA256." -#: ../../source/Crypto/Crypto.rst:13 7d211e9cf2e64cab9b79c0173805334e +#: ../../source/Crypto/Crypto.rst:13 56667bb7a4554c1b8efc918c9593f950 msgid "AES-256-GCM authenticated encryption for ECDH sessions." msgstr "Шифрование с аутентификацией AES-256-GCM для сеансов ECDH." -#: ../../source/Crypto/Crypto.rst:14 d345fd729851496c82017971bdb55276 +#: ../../source/Crypto/Crypto.rst:14 8de85fb1a2f843ea91d0aa30df0a00c7 msgid "PEM key persistence and structured error reporting." msgstr "Сохранение ключей PEM и структурированные отчеты об ошибках." -#: ../../source/Crypto/Crypto.rst:16 d86187e532624ac49492cca1b064a89b +#: ../../source/Crypto/Crypto.rst:16 564b1d414738498791d9083f279330fe msgid "" "The library version is 1.0.0 (``PF_CRYPTO_VERSION_MAJOR`` / " "``PF_CRYPTO_VERSION_MINOR`` / ``PF_CRYPTO_VERSION_PATCH`` and " "``PF_CRYPTO_VERSION_STRING`` in ``pf_crypto.h``)." msgstr "" -#: ../../source/Crypto/Crypto.rst:20 5e6c65799ec14fd8b67034bd1b3beb07 +#: ../../source/Crypto/Crypto.rst:20 10fda1fcea98430a8924fdfa8bbce2fa #, fuzzy msgid "The public headers are located in ``PyFlow/crypto_api/include``:" msgstr "Публичные заголовки расположены в ``src/crypto_api/include``:" -#: ../../source/Crypto/Crypto.rst:22 87305d509fc94f5186438e34d9583987 +#: ../../source/Crypto/Crypto.rst:22 86168d67fc8047ba8d4c61b2b9e23caf #, fuzzy msgid "``pf_crypto.h`` - common errors, OpenSSL diagnostics, and HKDF." msgstr "``ss_crypto.h`` — распространенные ошибки, диагностика OpenSSL и HKDF." -#: ../../source/Crypto/Crypto.rst:23 5d221a05e5034eccadaec2206256a2af +#: ../../source/Crypto/Crypto.rst:23 ddfd841fba4b4045bb3fc84419010fe7 #, fuzzy msgid "``pf_rsa.h`` - RSA key and encryption APIs." msgstr "``ss_rsa.h`` — ключ RSA и API шифрования." -#: ../../source/Crypto/Crypto.rst:24 e10e899ebf934a18a686d225d3f967d9 +#: ../../source/Crypto/Crypto.rst:24 eb2168817ac54389a35e194a444250f4 #, fuzzy msgid "``pf_ecdh.h`` - ECDH key agreement and seal/open APIs." msgstr "``ss_ecdh.h`` — соглашение о ключах ECDH и API-интерфейсы печати/открытия." -#: ../../source/Crypto/Crypto.rst:27 09186509365444d4ac1ce145d76bcd28 +#: ../../source/Crypto/Crypto.rst:27 43fa12b668bb4dc389f2bbd9edaf9187 msgid "Build" msgstr "Строить" -#: ../../source/Crypto/Crypto.rst:29 ae41004303f342d2ac3e302fe5ff9b40 +#: ../../source/Crypto/Crypto.rst:29 35019410fade4c18b07d32d37c05ba0d msgid "" "The module requires OpenSSL 1.1.1 or newer and CMake 3.16 or newer. On " "Debian or Ubuntu, install the build dependencies with:" @@ -95,7 +95,7 @@ msgstr "" "Для модуля требуется OpenSSL 1.1.1 или новее и CMake 3.16 или новее. В " "Debian или Ubuntu установите зависимости сборки с помощью:" -#: ../../source/Crypto/Crypto.rst:37 7c534481ca81453b89692a8758bbeba0 +#: ../../source/Crypto/Crypto.rst:37 3834ad9e83c24331b03d264103f5cdad msgid "" "Installing the Python package builds it automatically: ``setup.py`` " "compiles the three sources and installs the result inside the package " @@ -103,19 +103,19 @@ msgid "" "pyflow-net`` needs only a C compiler and the OpenSSL development headers." msgstr "" -#: ../../source/Crypto/Crypto.rst:42 6abf3a2d83804b73b1bfd45add4322d8 +#: ../../source/Crypto/Crypto.rst:42 a72fb95d5d114cdca29347b18e2c1253 msgid "" "Build it from the repository root with CMake when the C test suite or the" " C API itself is wanted:" msgstr "" -#: ../../source/Crypto/Crypto.rst:51 6fbb49d9124649f1b387de2f0377a4af +#: ../../source/Crypto/Crypto.rst:51 96617bb44be2438ebbde9e9f750b3e09 msgid "" "``ctest --test-dir`` was added in CMake 3.20; with the 3.16 minimum the " "equivalent is ``ctest --output-on-failure`` run from inside ``build/``." msgstr "" -#: ../../source/Crypto/Crypto.rst:54 f42772e265ad4248b11c37141f4fb6e8 +#: ../../source/Crypto/Crypto.rst:54 244b7aff35aa4272a121b9fbbadae117 #, fuzzy msgid "" "The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, " @@ -127,27 +127,26 @@ msgstr "" "``test_rsa``, ``test_ecdh``) и собирается и запускается вместе с " "библиотекой." -#: ../../source/Crypto/Crypto.rst:59 ed6b92c776ca441ab8629088ecd973bc +#: ../../source/Crypto/Crypto.rst:59 30ea804b8270411f8793908bdc7a2a97 #, fuzzy msgid "" "The library is built as a shared object (``libcrypto_api.so``) so it can " "be loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes " -"binding used by the TCP layer to encrypt messages with RSA-OAEP (see the " -"``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). " -"The binding also implements the TCP layer's anti-MITM identity check " -"(TOFU): peer public keys are exchanged on every connection, recorded " -"under the peer's ``(ip, port)`` in " -"``network_api/.Flow/pub_key/pub_key.json`` with the SHA-256 of the " -"received PEM text, and a changed key for a recorded endpoint rejects the " -"connection; a key already known under another endpoint is accepted and " -"re-registered under the new one. The encryption state machine is bounded:" -" three consecutive decode failures trip a circuit breaker " -"(``MAX_DECODE_FAILURES`` in ``connect_tcp.py``) that stops re-keying, and" -" a key that is stale or rotated makes the TCP layer reload its own key " -"and re-exchange. The binding looks for the library via " -"``ctypes.util.find_library`` and then next to the repository root in " -"``build/`` (``libcrypto_api.so``, ``libcrypto_api.dylib``, " -"``libcrypto_api.dll`` and ``build/Release/crypto_api.dll``)." +"binding used by the TCP layer. It exposes the RSA-OAEP message encryption" +" and the ECDH/AES-256-GCM sealing (``EcdhKeyPair`` / ``EcdhPubKey`` / " +"``hkdf_sha256``) that the framed TCP channel uses for its bulk and file " +"transfer payloads (see the ``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"encrypted channel sections). The binding also implements the TCP layer's " +"anti-MITM identity check (TOFU): endpoint rejects the connection; a key " +"already known under another endpoint is accepted and re-registered under " +"the new one. The encryption state machine is bounded: three consecutive " +"decode failures trip a circuit breaker (``MAX_DECODE_FAILURES`` in " +"``connect_tcp.py``) that stops re-keying, and a key that is stale or " +"rotated makes the TCP layer reload its own key and re-exchange. The " +"binding looks for the library via ``ctypes.util.find_library`` and then " +"next to the repository root in ``build/`` (``libcrypto_api.so``, " +"``libcrypto_api.dylib``, ``libcrypto_api.dll`` and " +"``build/Release/crypto_api.dll``)." msgstr "" "Библиотека создана как общий объект (``libcrypto_api.so``), поэтому ее " "можно загрузить из Python: ``src/network_api/rsa_crypto.py`` — это " @@ -161,13 +160,13 @@ msgstr "" "соединение. Привязка ищет библиотеку через ``ctypes.util.find_library`` и" " в ``build/`` рядом с корнем репозитория." -#: ../../source/Crypto/Crypto.rst:77 ad993af85f8f45f5a3661448f69961bf +#: ../../source/Crypto/Crypto.rst:77 9594680fce33464f9ff9cb9590bb5d0a msgid "" "The build produces the SOVERSIONed names ``libcrypto_api.so.1`` / " "``libcrypto_api.so.1.0.0`` plus the ``libcrypto_api.so`` loader symlink." msgstr "" -#: ../../source/Crypto/Crypto.rst:80 7ea41df5c6644e8197d587e03642123f +#: ../../source/Crypto/Crypto.rst:80 80c24657a4c9445088459fff264379b2 #, fuzzy msgid "" "CMake install rules export the ``crypto_api`` library, its public " @@ -184,11 +183,11 @@ msgstr "" " находится в корне репозитория: шаблон пакета CMake и шаблон pkg-config —" " это ``cmake/crypto_apiConfig.cmake.in`` и ``crypto_api.pc.in``." -#: ../../source/Crypto/Crypto.rst:89 0d7e08f1e07445dfa77b47a85a25def7 +#: ../../source/Crypto/Crypto.rst:89 dccd3901c8024859b9a9753e818d6692 msgid "Common API" msgstr "Общий API" -#: ../../source/Crypto/Crypto.rst:91 1c9b38b493964582875d168e61ccf829 +#: ../../source/Crypto/Crypto.rst:91 c1b71e19c8f6422eabd99bd0997daae8 msgid "" "Most public functions return ``pf_err_t``; ``PF_OK`` indicates success. " "Functions that report a size or a string instead have their own return " @@ -200,12 +199,15 @@ msgid "" "pending OpenSSL error queue." msgstr "" -#: ../../source/Crypto/Crypto.rst:114 07ac67f777704ad9822023430f0109c4 +#: ../../source/Crypto/Crypto.rst:114 67ae5556635e43a487c38bf8011e1c5b #, fuzzy msgid "" "The library uses caller-provided output buffers for fixed-size results. " "Functions that return allocated buffers document that the caller must " -"release them with ``free``. Opaque key handles must be released with " +"release them with ``pf_crypto_free`` — the library's own ``free``, so the" +" allocation and the deallocation always run on the same C runtime (a host" +" such as CPython on Windows may use a different one, and freeing across " +"runtimes corrupts the heap). Opaque key handles must be released with " "their corresponding ``*_free`` function. HKDF output is capped at " "``PF_CRYPTO_HKDF_SHA256_MAX_OUT`` (8160 bytes) by both " "``pf_crypto_hkdf_sha256`` and ``pf_ecdh_derive_key``." @@ -216,11 +218,11 @@ msgstr "" "освободить их со статусом «свободно». Непрозрачные дескрипторы клавиш " "должны быть освобождены с помощью соответствующей функции ``*_free``." -#: ../../source/Crypto/Crypto.rst:122 619e39d223d54a48ba983a3b30bd7d9d +#: ../../source/Crypto/Crypto.rst:125 69248ac47e7e47f18e953dee857db239 msgid "RSA API" msgstr "API RSA" -#: ../../source/Crypto/Crypto.rst:124 5eeaa87820f941dd8e171c973269036e +#: ../../source/Crypto/Crypto.rst:127 a770dcc04e2c42d1be50fe30d298df4b #, fuzzy msgid "" "RSA keys are generated with ``pf_rsa_keygen``. The implementation uses " @@ -231,7 +233,7 @@ msgstr "" "RSA-OAEP с SHA-256 для шифрования и дешифрования. Принимаются размеры " "ключей от 2048 до 16384 бит; Рекомендуется 2048, 3072 или 4096 бит." -#: ../../source/Crypto/Crypto.rst:148 f85a46b466ef47ee9d195f439ba3b153 +#: ../../source/Crypto/Crypto.rst:151 e7b876b8fb354b2da45d3c13f50ededf msgid "" "The first encryption call with ``out == NULL`` queries the required " "output size; ``pf_rsa_decrypt`` supports the same query pattern. RSA " @@ -243,15 +245,15 @@ msgid "" "handle." msgstr "" -#: ../../source/Crypto/Crypto.rst:156 ff9d2472cf614dd0827d0887f195ed43 +#: ../../source/Crypto/Crypto.rst:159 6af957980305426e915b3f62d9eb1ed4 msgid "Public and private keys can be stored as PEM files:" msgstr "Открытые и закрытые ключи можно хранить в виде файлов PEM:" -#: ../../source/Crypto/Crypto.rst:167 a3f163de660b4d49a36a8aedead555da +#: ../../source/Crypto/Crypto.rst:170 6bf9df3c51d540b69680723a4845de2d msgid "ECDH API" msgstr "ECDH API" -#: ../../source/Crypto/Crypto.rst:169 4535e8f410a742f38d32ff53d404c37b +#: ../../source/Crypto/Crypto.rst:172 3c69950828364df49bbf0b37313f9987 #, fuzzy msgid "" "ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The " @@ -260,19 +262,19 @@ msgstr "" "Пары ключей ECDH создаются с помощью ss_ecdh_keypair_generate. " "Поддерживаемые имена кривых:" -#: ../../source/Crypto/Crypto.rst:172 9624f8475c8d4618a7054e7c18ae5e1f +#: ../../source/Crypto/Crypto.rst:175 6a4d2171568847d4984c8705818c4bf9 msgid "``PF_ECDH_CURVE_P256``" msgstr "``PF_ECDH_CURVE_P256``" -#: ../../source/Crypto/Crypto.rst:173 4585a2433d684621a5f90805b74cef6c +#: ../../source/Crypto/Crypto.rst:176 c0da017a21dc46ed93b3da0727454dc3 msgid "``PF_ECDH_CURVE_P384``" msgstr "``PF_ECDH_CURVE_P384``" -#: ../../source/Crypto/Crypto.rst:174 14dde8ddd1b44ae1a4cb64179caa5aa5 +#: ../../source/Crypto/Crypto.rst:177 b2019f9f782b48dc85c5e3b24647fd94 msgid "``PF_ECDH_CURVE_P521``" msgstr "``PF_ECDH_CURVE_P521``" -#: ../../source/Crypto/Crypto.rst:176 43b77941f20d44958205bea666a208d5 +#: ../../source/Crypto/Crypto.rst:179 0962e1bca8da48d1835cbe8facb8a0ea #, fuzzy msgid "" "An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` " @@ -282,7 +284,7 @@ msgstr "" "Открытые ключи передаются в виде строк PEM subjectPublicKeyInfo. " "Разобранные ключи одноранговых узлов проверяются перед использованием." -#: ../../source/Crypto/Crypto.rst:200 ac2db67c049d4f55a2fc2f9972c6d57c +#: ../../source/Crypto/Crypto.rst:203 c5c15560992c48beb7637c19a517f07f #, fuzzy msgid "" "The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are " @@ -297,24 +299,24 @@ msgstr "" "AES-256-GCM с помощью HKDF-SHA256, включают случайную соль и IV и " "аутентифицируют дополнительный AAD." -#: ../../source/Crypto/Crypto.rst:207 70a8e3f511f34359974c9152d60500b2 +#: ../../source/Crypto/Crypto.rst:210 f794a8f7227443e381d5337e9fe95677 #, fuzzy msgid "The ``pf_ecdh_seal`` output format is:" msgstr "Формат вывода ss_ecdh_seal:" -#: ../../source/Crypto/Crypto.rst:213 28f1933678854354b8ef357adcfdd380 +#: ../../source/Crypto/Crypto.rst:216 ee4a7ea6853249a7a137f949e3b9d7cc #, fuzzy msgid "" "The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty " "plaintext is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` " "and no plaintext is returned. On success the output buffer is " -"``malloc``-ed and the caller frees it." +"``malloc``-ed and the caller releases it with ``pf_crypto_free``." msgstr "" "Фиксированные служебные данные составляют ``SS_ECDH_SEAL_OVERHEAD`` (44 " "байта). Допускается пустой открытый текст. Неудачная проверка тега " "возвращает ``SS_ERR_AUTH_FAILED`` и открытый текст не возвращается." -#: ../../source/Crypto/Crypto.rst:218 9a7c6cc7b5a94e5fac26bc6802310183 +#: ../../source/Crypto/Crypto.rst:221 212039cbe4b74827b643af47aaaf9970 msgid "" "ECDH key pairs can be persisted with ``pf_ecdh_keypair_write_priv`` and " "``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-" @@ -322,11 +324,11 @@ msgid "" "``pf_ecdh_pubkey_free`` release the handles." msgstr "" -#: ../../source/Crypto/Crypto.rst:224 7f05214ee91a478581014c39643d7bfb +#: ../../source/Crypto/Crypto.rst:227 a84d53d68554474fbb2beaa2146cee86 msgid "Security Notes" msgstr "Примечания по безопасности" -#: ../../source/Crypto/Crypto.rst:226 a6482f5940d1469088bb376b1d25d31c +#: ../../source/Crypto/Crypto.rst:229 5e398f6a7ace4aeea29bcd40e75a59b1 msgid "" "ECDH provides key agreement, but it does not authenticate public-key " "ownership by itself. Public keys must be exchanged over an authenticated " @@ -337,7 +339,7 @@ msgstr "" "по аутентифицированному каналу или проверяться с помощью внешнего " "механизма подписи/сертификата." -#: ../../source/Crypto/Crypto.rst:230 fb49962bd1f0474c91610fa9dd020584 +#: ../../source/Crypto/Crypto.rst:233 df43fe66482c4e0fb896ab598ce43c7d #, fuzzy msgid "" "Private key files may be protected with a passphrase: " @@ -352,37 +354,37 @@ msgstr "" "регистрации парольных фраз, закрытых ключей или ключей сеанса в виде " "открытого текста." -#: ../../source/Crypto/Crypto.rst:238 e09bc96e058a4b14b135a1430b8a3ad9 +#: ../../source/Crypto/Crypto.rst:241 02cb264ad6c747d29b37bfa1f1cc6362 msgid "Error Handling" msgstr "Обработка ошибок" -#: ../../source/Crypto/Crypto.rst:240 8246aab2cf7d4913a7345684940c9220 +#: ../../source/Crypto/Crypto.rst:243 60786ad51ea444da97922957e670ea90 msgid "The main error codes are:" msgstr "Основные коды ошибок:" -#: ../../source/Crypto/Crypto.rst:242 45059d6bf45c42c2bc8e8c6f023836f4 +#: ../../source/Crypto/Crypto.rst:245 8c1b057428f2445889d1159d6636b097 msgid "" "``PF_ERR_INVALID_ARG`` - NULL argument, illegal length or bad parameter " "combination (e.g. out-of-range RSA key size, a NULL salt/info with a non-" "zero length, or a plaintext longer than the key allows)." msgstr "" -#: ../../source/Crypto/Crypto.rst:245 daed84defdb64065849a0ef880b22eea +#: ../../source/Crypto/Crypto.rst:248 27e26e555ee24ce68ab7943b4117a57d #, fuzzy msgid "``PF_ERR_NOMEM`` - allocation failure." msgstr "``SS_ERR_NOMEM`` - ошибка выделения." -#: ../../source/Crypto/Crypto.rst:246 788a5b4b06714adcab5aeb36b81757e4 +#: ../../source/Crypto/Crypto.rst:249 2b3828e4bfa04329a60b479be7f0dfe5 #, fuzzy msgid "``PF_ERR_OPENSSL`` - OpenSSL operation failure." msgstr "``SS_ERR_IO`` - сбой файловой операции." -#: ../../source/Crypto/Crypto.rst:247 0e06a2169f5d445cab788910aaee188a +#: ../../source/Crypto/Crypto.rst:250 2c3c9ab09d294be8911f4fb31c335db6 #, fuzzy msgid "``PF_ERR_IO`` - file operation failure." msgstr "``SS_ERR_IO`` - сбой файловой операции." -#: ../../source/Crypto/Crypto.rst:248 0d1b17cc4e744efd891efe2d292f6dd8 +#: ../../source/Crypto/Crypto.rst:251 a928f8b90e154bdaa43ef4e4ee7d578d #, fuzzy msgid "" "``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key " @@ -391,29 +393,29 @@ msgstr "" "``SS_ERR_PARSE`` — неверный ввод PEM/DER или неверная парольная фраза " "закрытого ключа." -#: ../../source/Crypto/Crypto.rst:249 8d5f6adfe3b24ecebb6ed2d84cece394 +#: ../../source/Crypto/Crypto.rst:252 9cd41d63123d49caa946160465dda70f #, fuzzy msgid "``PF_ERR_BUFFER_TOO_SMALL`` - caller output buffer is insufficient." msgstr "" "``SS_ERR_BUFFER_TOO_SMALL`` - буфер вывода вызывающего абонента " "недостаточен." -#: ../../source/Crypto/Crypto.rst:250 7a88e3913e8948edbcf645b5097b47b3 +#: ../../source/Crypto/Crypto.rst:253 78532f0a764249178076a4adcc032f7f #, fuzzy msgid "``PF_ERR_AUTH_FAILED`` - AES-GCM authentication failed." msgstr "``SS_ERR_AUTH_FAILED`` — аутентификация AES-GCM не удалась." -#: ../../source/Crypto/Crypto.rst:251 1182998c4b164675a840d89b3a8e994b +#: ../../source/Crypto/Crypto.rst:254 5e5f5421333e4382ae5e700d7570648b #, fuzzy msgid "``PF_ERR_UNSUPPORTED`` - unsupported curve or key type." msgstr "``SS_ERR_UNSUPPORTED`` - неподдерживаемый тип кривой или ключа." -#: ../../source/Crypto/Crypto.rst:252 0af6413bc92a46a48a1ea044a6b4f05b +#: ../../source/Crypto/Crypto.rst:255 d1fea86be03940d097132b112b6f14f2 #, fuzzy msgid "``PF_ERR_DECRYPT`` - RSA decryption failed." msgstr "``SS_ERR_DECRYPT`` — расшифровка RSA не удалась." -#: ../../source/Crypto/Crypto.rst:254 b425983151054505a243c1d65c68a2b8 +#: ../../source/Crypto/Crypto.rst:257 9b1c2b2d3f48459bbedee21c92aafe31 msgid "For detailed OpenSSL diagnostics:" msgstr "Для подробной диагностики OpenSSL:" diff --git a/docs/source/locale/ru/LC_MESSAGES/File_Transfer/File_Transfer.po b/docs/source/locale/ru/LC_MESSAGES/File_Transfer/File_Transfer.po index 83263ff..b36e10c 100644 --- a/docs/source/locale/ru/LC_MESSAGES/File_Transfer/File_Transfer.po +++ b/docs/source/locale/ru/LC_MESSAGES/File_Transfer/File_Transfer.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -21,12 +21,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/File_Transfer/File_Transfer.rst:2 -#: 2d215e70ec1e43988343e3d32392d8aa +#: d9c92006bc3e49c9a5d184d74f2e7824 msgid "TCP File Transfer Mechanism" msgstr "Механизм передачи файлов TCP" #: ../../source/File_Transfer/File_Transfer.rst:4 -#: f603ff252cb64bea9b7c9034d2d46221 +#: b32ed3356f814a369d9d4bc153c017fa msgid "" "This document describes the file transfer subsystem implemented in both " "the ``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file " @@ -43,19 +43,19 @@ msgstr "" "консоли сервера." #: ../../source/File_Transfer/File_Transfer.rst:14 -#: f28ca12001c24b1c954e10fdb63aa493 +#: ad6d3cd551694899ba6998e43167bb10 msgid "The design follows a **two-phase handshake** pattern:" msgstr "Конструкция соответствует схеме **двухфазного рукопожатия**:" #: ../../source/File_Transfer/File_Transfer.rst:16 -#: b348421cfc6d4267a58231db041e7d67 +#: f67e58b5ae8b4e2a8f9a9021efba0b5c msgid "A transfer command is exchanged over the main control connection." msgstr "" "Обмен командой передачи осуществляется через главное соединение " "управления." #: ../../source/File_Transfer/File_Transfer.rst:18 -#: 0483543fb8f0497a9ee256fee509e4fc +#: 4d267488a6cf4911bc2c3cb7801dce8d msgid "" "A separate TCP connection is established on a dynamically allocated port " "to transfer the actual file data (metadata + payload)." @@ -64,19 +64,20 @@ msgstr "" "для передачи фактических данных файла (метаданные + полезная нагрузка)." #: ../../source/File_Transfer/File_Transfer.rst:22 -#: 0e13d1b8b6ef46ce855c8949ef36f219 +#: a0490aac6cc74a8f9de5e9872378b87c #, fuzzy msgid "" -"All file transfers use **stream-oriented reading/writing** with fixed-" -"size chunks (65536 bytes, hardcoded in both directions) to avoid blocking" -" and to handle large files efficiently." +"All file transfers use **stream-oriented reading/writing** with a " +"configurable chunk size (``file_transfer_chunk_len``, 65536 bytes by " +"default, in both directions) to avoid blocking and to handle large files " +"efficiently." msgstr "" "При любой передаче файлов используется **потоковое чтение/запись** с " "фрагментами фиксированного размера (по умолчанию 64 КБ), чтобы избежать " "блокировки и эффективно обрабатывать большие файлы." #: ../../source/File_Transfer/File_Transfer.rst:28 -#: a8c11b500a31468aa10fc4d6537c691c +#: 9ad33f3c1a2e4164b384a71388b895f5 msgid "" "*Note: For a high-level overview of the server and client classes, please" " refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" @@ -85,12 +86,12 @@ msgstr "" ":doc:`TCP_Server_APIs` и :doc:`TCP_Client_APIs`.*" #: ../../source/File_Transfer/File_Transfer.rst:35 -#: aeba1deb576440f29ab1d507d38fb22d +#: 2c31714fc81743fa9fbb8701d87347ac msgid "File Transfer Protocol" msgstr "Протокол передачи файлов" #: ../../source/File_Transfer/File_Transfer.rst:37 -#: a97e5fe0762d4d2d8ffef8527985c9e7 +#: 61af0fc38ea74fcfae8b2a1316d2e6ea msgid "" "The protocol is symmetric: the same low-level exchange is used regardless" " of whether the server sends to a client or the client sends to the " @@ -105,7 +106,7 @@ msgstr "" " роли **получателя**." #: ../../source/File_Transfer/File_Transfer.rst:46 -#: 1a2e27611ea0452d99cd3e8ac299683c +#: 2ef019fa21e74d26873cb1da802747ac msgid "" "The low-level wire markers are stored in " "``PyFlow/network_api/decode_command_table.json``, which each instance " @@ -114,7 +115,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:52 -#: ebc9fc6492964c47b4744d8e2faf6ffd +#: be499b6571974e1a87d5c471578ac79b #, fuzzy msgid "" "``server_start_file_transfer_sign`` — from " @@ -126,7 +127,7 @@ msgstr "" "отправителю, указывая, что получатель готов." #: ../../source/File_Transfer/File_Transfer.rst:57 -#: d23e35d928494417918b1e9e1810d2e9 +#: 3c9a4f28914742dab2a8175df58f9419 msgid "" "``send_file_header_sign`` / ``send_file_data_sign`` — from " "``file_send_server_header`` / ``file_send_server_data``; both attributes " @@ -134,7 +135,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:60 -#: 07ce10ba9a534d2db23cb3505f3d9ad7 +#: 2035637777a449768450196f0fec1397 msgid "" "``server_received_file_header_sign`` / ``server_received_file_data_sign``" " — from ``file_receive_client_header`` / ``file_receive_client_data``; " @@ -144,7 +145,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:67 -#: a2c795d996c4491e9c90f46871d655b0 +#: 0fc372ae19be49029aa105a95e480640 #, fuzzy msgid "" "``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by " @@ -155,7 +156,7 @@ msgstr "" "приводящей к закрытию сокета передачи." #: ../../source/File_Transfer/File_Transfer.rst:72 -#: b95751f788c044d69f86a067e221a340 +#: 41f6d3d6e0e848bc8f6aecb995223622 msgid "" "The remaining keys of the table cover the other three direction/phase " "combinations. Protocol control lines that are not part of this table " @@ -166,12 +167,12 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:80 -#: c481ce301cdc4dddba6f392dc6de4e6a +#: 45a36aa9239d4caba8752e4dc4fd551b msgid "### Metadata Exchange" msgstr "### Обмен метаданными" #: ../../source/File_Transfer/File_Transfer.rst:82 -#: a6fea134d58a457ab825ec59930e0c48 +#: d4ace80bc05f4bafb8144e1de31060dc msgid "" "The sender performs the following steps after the dedicated file-transfer" " socket is connected:" @@ -180,7 +181,7 @@ msgstr "" "выполняет следующие шаги:" #: ../../source/File_Transfer/File_Transfer.rst:86 -#: e18ac26158444f719667794153f422d8 +#: 5df80a71cd274a92975e8d010f564872 msgid "" "Wait for the receiver's start signal " "(``server_start_file_transfer_sign``) with a 10-second timeout." @@ -189,32 +190,34 @@ msgstr "" " с таймаутом 10 секунд." #: ../../source/File_Transfer/File_Transfer.rst:89 -#: fb269796ce6d45cbb73b0201dce1cec9 +#: d68741e000fe48d3857ec0b0363d4182 msgid "Send the filename length as a 4-byte unsigned integer (big-endian)." msgstr "" "Отправьте длину имени файла как 4-байтовое целое число без знака (с " "обратным порядком байтов)." #: ../../source/File_Transfer/File_Transfer.rst:91 -#: c48725bc3ac54f16bef68243c780831d +#: 95260b76f4524ddb8700ca05352f294d msgid "Send the filename encoded in UTF-8." msgstr "Отправьте имя файла в кодировке UTF-8." #: ../../source/File_Transfer/File_Transfer.rst:92 -#: 951751cbb7ab400dbfd8ac2e574d2bf0 +#: 7efa294dbe7e4921974628e8fb08cc00 msgid "Send the file size as an 8-byte unsigned integer (big-endian)." msgstr "" "Отправьте размер файла как 8-байтовое целое число без знака (с обратным " "порядком байтов)." #: ../../source/File_Transfer/File_Transfer.rst:94 -#: db806fd98e8b48dabcd3fa755f1d6567 +#: 065d4ab3bf384d81a22df89aeba09349 #, fuzzy -msgid "Send the file content in 65536-byte chunks until EOF." +msgid "" +"Send the file content in ``file_transfer_chunk_len``-byte chunks (65536 " +"by default) until EOF." msgstr "Отправляйте содержимое файла частями по 64 КиБ до EOF." -#: ../../source/File_Transfer/File_Transfer.rst:95 -#: 265efb19bd5c46569983bb4156bc195c +#: ../../source/File_Transfer/File_Transfer.rst:96 +#: aeec7f8ff0ab424cbc5b7c1a32ff9433 msgid "" "Wait for the completion acknowledgement " "(``server_received_file_data_sign``) with a dynamic timeout (base 30 " @@ -224,38 +227,38 @@ msgstr "" "динамическим таймаутом (базовое значение 30 секунд плюс 10 секунд на 100 " "МБ)." -#: ../../source/File_Transfer/File_Transfer.rst:100 -#: b2944c94e7a9468daf924f021a5f0bab +#: ../../source/File_Transfer/File_Transfer.rst:101 +#: b80094b922a24c409f10eb9c8b05373b msgid "The receiver performs the complementary steps:" msgstr "Приемник выполняет дополнительные шаги:" -#: ../../source/File_Transfer/File_Transfer.rst:102 -#: 1353e95158fc496db86676f544168584 +#: ../../source/File_Transfer/File_Transfer.rst:103 +#: 5f71fc707ffe4b06a275b3db9f77178d msgid "Send the start signal." msgstr "Подайте сигнал старта." -#: ../../source/File_Transfer/File_Transfer.rst:103 -#: e32e19b7ac2e4a20a76a7c5640212835 +#: ../../source/File_Transfer/File_Transfer.rst:104 +#: 7132d6fe15ce42a3bef64e0073e9baff msgid "Read the 4-byte length, then the filename, then the 8-byte size." msgstr "Прочитайте длину 4 байта, затем имя файла, затем размер 8 байт." -#: ../../source/File_Transfer/File_Transfer.rst:105 -#: 1bbea38ba8ec4f84970f408827ba1be4 +#: ../../source/File_Transfer/File_Transfer.rst:106 +#: 7e0fcaec6d704455b94fc9f7defbef55 msgid "Acknowledge the header with ``server_received_file_header_sign``." msgstr "Подтвердите заголовок с помощью ``server_received_file_header_sign``." -#: ../../source/File_Transfer/File_Transfer.rst:107 -#: ef7144f2c0c94c9fa25c2a5bad6ed5e8 +#: ../../source/File_Transfer/File_Transfer.rst:108 +#: d6a854d18d404082bdec0e2cf355ea62 msgid "Receive the file data in chunks and write to disk." msgstr "Получайте данные файла частями и записывайте на диск." -#: ../../source/File_Transfer/File_Transfer.rst:108 -#: bb81c955e5024b6d9b6042fa3eb4c13f +#: ../../source/File_Transfer/File_Transfer.rst:109 +#: 69981b7e399e4de89858906b286aaf06 msgid "Acknowledge completion with ``server_received_file_data_sign``." msgstr "Подтвердите завершение с помощью ``server_received_file_data_sign``." -#: ../../source/File_Transfer/File_Transfer.rst:111 -#: cd24d3a3f8704419889c764cf5812a99 +#: ../../source/File_Transfer/File_Transfer.rst:112 +#: b98957309caf49eba2657154bffbaf90 msgid "" "Any error during the exchange causes the failing side to send " "``error_sign``, and both sides close the transfer socket. The main " @@ -265,13 +268,13 @@ msgstr "" "отправляет ``error_sign``, и обе стороны закрывают сокет передачи. " "Основное соединение управления остается неизменным." -#: ../../source/File_Transfer/File_Transfer.rst:120 -#: 0313763b7bc6427cb80da39d09a94be1 +#: ../../source/File_Transfer/File_Transfer.rst:121 +#: f289e3c6e5b445f48eda6ed3434c9de8 msgid "Client-Initiated Transfer (Client → Server)" msgstr "Передача, инициированная клиентом (Клиент → Сервер)" -#: ../../source/File_Transfer/File_Transfer.rst:122 -#: 155d9f3383cf42fe8fa0e4fe095fbae7 +#: ../../source/File_Transfer/File_Transfer.rst:123 +#: 17e1ddd91efe4690ad00f85f54875eda msgid "" "When the user types a file-related command in the client's interactive " "console, the call chain proceeds as follows." @@ -279,13 +282,13 @@ msgstr "" "Когда пользователь вводит команду, связанную с файлом, в интерактивной " "консоли клиента, цепочка вызовов выполняется следующим образом." -#: ../../source/File_Transfer/File_Transfer.rst:126 -#: ab7df52a36c742a0be4924b613ddebd4 +#: ../../source/File_Transfer/File_Transfer.rst:127 +#: 9cacd6ea79a14ff6ae602d7ed47926c8 msgid "### Console Input Handling" msgstr "### Обработка ввода в консоль" -#: ../../source/File_Transfer/File_Transfer.rst:128 -#: 42cde8d25ccd4424b5c871c7adf3af91 +#: ../../source/File_Transfer/File_Transfer.rst:129 +#: 07a7b69b45d04950877f071f25ad7c2c #, fuzzy msgid "" "In ``TCP_Client_Base.interactive_mode()``, user input is read line by " @@ -300,19 +303,19 @@ msgstr "" "каждой такой команды клиент вызывает соответствующую потокобезопасную " "точку входа (методы, заканчивающиеся на ``_thread``)." -#: ../../source/File_Transfer/File_Transfer.rst:136 -#: 08d0c910eba54d3cb8447d3cea15064f +#: ../../source/File_Transfer/File_Transfer.rst:137 +#: 250bb94df2a14d339b150a70e8fed215 #, fuzzy msgid "### Entry Points" msgstr "### Потокобезопасные точки входа" -#: ../../source/File_Transfer/File_Transfer.rst:138 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:139 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "The console dispatches to these methods:" msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:140 -#: 3ddbfd1b9e454342aa47f388d5bc7263 +#: ../../source/File_Transfer/File_Transfer.rst:141 +#: a0f0599853724ff9a15c501c154f52ea #, fuzzy msgid "" "``file_transfer_client_recv_client_start_thread(message, " @@ -322,23 +325,23 @@ msgstr "" "``file_transfer_client_recv_client_start_thread(сообщение, " "file_folder_abspath=None)``" -#: ../../source/File_Transfer/File_Transfer.rst:143 -#: 4db440e1419b4ce895c7e03b85b070c1 +#: ../../source/File_Transfer/File_Transfer.rst:144 +#: 9d60213404014fbe8bee542f67d80398 msgid "``folder_file_transfer_client_recv_client_start(message)``" msgstr "``folder_file_transfer_client_recv_client_start(сообщение)``" -#: ../../source/File_Transfer/File_Transfer.rst:144 -#: 936c7a26041045da8e4e20ec45d3959d +#: ../../source/File_Transfer/File_Transfer.rst:145 +#: 2e6c7b2b820349ebac90f27d835477d0 msgid "``multiple_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_file_transfer_client_recv_client_start(сообщение)``" -#: ../../source/File_Transfer/File_Transfer.rst:145 -#: 972ecc6300354468b126961a483ecf2c +#: ../../source/File_Transfer/File_Transfer.rst:146 +#: bdee0e9084194b45b5fad3a44e9aaf85 msgid "``multiple_folder_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_folder_file_transfer_client_recv_client_start(сообщение)``" -#: ../../source/File_Transfer/File_Transfer.rst:147 -#: fef1e1b2a2024f89abd300268004380d +#: ../../source/File_Transfer/File_Transfer.rst:148 +#: ae9108b44e304198a7d0bff6bae8ab60 msgid "" "The last three run synchronously on the console thread; they walk the " "tree or the file list and spawn one worker thread per file themselves, so" @@ -347,13 +350,13 @@ msgid "" "``max_thread_num`` of them run at once." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:153 -#: f5919b72c7ec40e2a1b1d49cf57c9021 +#: ../../source/File_Transfer/File_Transfer.rst:154 +#: 8e945e4bdc124e749ee0a5976249a787 msgid "### Worker Function (Client Side)" msgstr "### Рабочая функция (клиентская сторона)" -#: ../../source/File_Transfer/File_Transfer.rst:155 -#: 70bed6a3ccbd47e89653ab1b2d62fb9d +#: ../../source/File_Transfer/File_Transfer.rst:156 +#: cc8b9fc35bfb4cf395a2114786c01718 msgid "" "The core worker function for a single file is " "``file_transfer_client_recv_client_start(message, " @@ -363,15 +366,15 @@ msgstr "" "``file_transfer_client_recv_client_start(message, " "file_folder_abspath=None)``. Ее логика следующая:" -#: ../../source/File_Transfer/File_Transfer.rst:160 -#: f7103ca89460442ba018095bf48ae23c +#: ../../source/File_Transfer/File_Transfer.rst:161 +#: e3d81c4f4e724d81b426fdbfedb9c062 msgid "Allocate a unique client ID using the lock ``file_client_id_lock``." msgstr "" "Выделите уникальный идентификатор клиента, используя блокировку " "file_client_id_lock." -#: ../../source/File_Transfer/File_Transfer.rst:162 -#: ea5fe1051d864a3caccc15bf2373b03e +#: ../../source/File_Transfer/File_Transfer.rst:163 +#: 81b9ac67e27341c0a17468f3b6787d14 msgid "" "Extend the original command string with the client ID (e.g., ``/file " "mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server " @@ -382,8 +385,8 @@ msgstr "" "сервер через основное управляющее соединение с помощью " "``send_message()``." -#: ../../source/File_Transfer/File_Transfer.rst:168 -#: b56d7f67a1844b0cb893a3939ed8ed70 +#: ../../source/File_Transfer/File_Transfer.rst:169 +#: af07c5ef546a4102bbb836b65b2fd3be msgid "" "Obtain a local port for the outgoing file transfer socket by calling " "``palloc()``." @@ -391,8 +394,8 @@ msgstr "" "Получите локальный порт для исходящего сокета передачи файлов, вызвав " "``palloc()``." -#: ../../source/File_Transfer/File_Transfer.rst:171 -#: 83314b464667496cb415f119beb0dc31 +#: ../../source/File_Transfer/File_Transfer.rst:172 +#: 37226a4f2e1e4a878ba325fca05df9bf msgid "" "Wait (up to 20 seconds) for the server to reply with a port number. The " "server's reply (``/server_file_transfer_port ``) is " @@ -404,8 +407,8 @@ msgstr "" "основным соединением и сохраняется в ``file_server_port_list``. Когда " "соответствующая запись найдена, порт извлекается." -#: ../../source/File_Transfer/File_Transfer.rst:179 -#: bd938c291cbe44aa913d35413fc76a6b +#: ../../source/File_Transfer/File_Transfer.rst:180 +#: e9cd68239fe3498597f07ccfa774ae22 msgid "" "Call the low-level send function ``file_transfer_mode(filename, " "server_host, server_port, client_port)``." @@ -413,8 +416,8 @@ msgstr "" "Вызовите низкоуровневую функцию отправки ``file_transfer_mode(filename, " "server_host, server_port, client_port)``." -#: ../../source/File_Transfer/File_Transfer.rst:183 -#: 75779fa321754e05adc2ee87ac490f07 +#: ../../source/File_Transfer/File_Transfer.rst:184 +#: 145c524c53654e84a0bb45d3a065733e #, fuzzy msgid "" "For folder transfers, the worker function " @@ -437,8 +440,8 @@ msgstr "" "Семафор (file_semaphore) ограничивает количество одновременных передач " "файлов до max_thread_num." -#: ../../source/File_Transfer/File_Transfer.rst:198 -#: bbb76713d93e4920a87d1551cbdf9999 +#: ../../source/File_Transfer/File_Transfer.rst:199 +#: 5a7d502137c8442eafae448cee95a72a msgid "" "``multiple_file_transfer_client_recv_client_start`` loops over the given " "files and starts one worker thread per file, each holding " @@ -446,13 +449,13 @@ msgid "" "are capped by ``max_thread_num`` on that path too." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:203 -#: d9634b910f4f4509a717a6e7cb8445e2 +#: ../../source/File_Transfer/File_Transfer.rst:204 +#: 4ae4777e086a48558cbe3dda0ecdb3fb msgid "### Server-Side Handler (Receiving)" msgstr "### Серверный обработчик (прием)" -#: ../../source/File_Transfer/File_Transfer.rst:205 -#: ecf51220b2924da78e59cd7118a5d976 +#: ../../source/File_Transfer/File_Transfer.rst:206 +#: 66a812ac1ac84ad2b912deb843f3c059 msgid "" "When the server receives an extended command like ``/file mydoc.txt 42`` " "on the main control connection, ``handle_command`` detects it and calls:" @@ -461,8 +464,8 @@ msgstr "" "главному управляющему соединению, ``handle_command`` обнаруживает ее и " "вызывает:" -#: ../../source/File_Transfer/File_Transfer.rst:210 -#: 7437faffb1f7433faaea35c296c7ab96 +#: ../../source/File_Transfer/File_Transfer.rst:211 +#: 081e020d3e674d01bfde15c0922aa25c msgid "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " command)``" @@ -470,13 +473,13 @@ msgstr "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " команда)``" -#: ../../source/File_Transfer/File_Transfer.rst:213 -#: 1ff4d8b0423b490db4a9b179d745dcb7 +#: ../../source/File_Transfer/File_Transfer.rst:214 +#: 4b5b5057002a457db83aed00c6148a7f msgid "The server then:" msgstr "Затем сервер:" -#: ../../source/File_Transfer/File_Transfer.rst:215 -#: 988de890b2fc4ebfbe68944b368ce5b8 +#: ../../source/File_Transfer/File_Transfer.rst:216 +#: e2ad0e97b7854be4a3dded6cf7d602b7 msgid "" "Creates a new thread via " "``file_transfer_server_recv_server_start(client_id, client_socket, " @@ -486,13 +489,13 @@ msgstr "" "``file_transfer_server_recv_server_start(client_id, client_socket, " "команда, new_save_path=None, file_name=None)``." -#: ../../source/File_Transfer/File_Transfer.rst:219 -#: 47e1493ecf784674924778f581e6a71a +#: ../../source/File_Transfer/File_Transfer.rst:220 +#: ee8cdc9ae93c4579a05e37b32c86f705 msgid "Allocates a transfer port with ``palloc()``." msgstr "Выделяет порт передачи с помощью palloc()." -#: ../../source/File_Transfer/File_Transfer.rst:220 -#: b19bd45b30ee42178dab7b9aafa79e5e +#: ../../source/File_Transfer/File_Transfer.rst:221 +#: ac8a87e1e481417284d90ba8cb843415 msgid "" "Calls ``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``." @@ -500,8 +503,8 @@ msgstr "" "Вызывает ``file_transfer_mode_recv(хост, порт, client_socket, client_id, " "new_save_path, file_name, команда)``." -#: ../../source/File_Transfer/File_Transfer.rst:223 -#: a2f55cc995c14ec1ac34545e458dccb2 +#: ../../source/File_Transfer/File_Transfer.rst:224 +#: 2f6675b7698c41938542b09cbfb482e8 msgid "" "This low-level receive function sets up a listening socket on the " "allocated port, sends the port number back to the client (as " @@ -517,8 +520,8 @@ msgstr "" "protocol`. Полученный файл сохраняется в папке ``received_files/`` (или в" " подкаталоге, если была запрошена передача папки)." -#: ../../source/File_Transfer/File_Transfer.rst:233 -#: da7e5a1f96b3422bbfd8f056eb28dae3 +#: ../../source/File_Transfer/File_Transfer.rst:234 +#: 9fe861572b8746aeaa8266d8d30f963f msgid "" "After the transfer completes (or fails), the port is released with " "``pfree()``." @@ -526,13 +529,13 @@ msgstr "" "После завершения передачи (или неудачи) порт освобождается с помощью " "``pfree()``." -#: ../../source/File_Transfer/File_Transfer.rst:240 -#: e9956de8dffe4d898caed46c0e78c93b +#: ../../source/File_Transfer/File_Transfer.rst:241 +#: 3e4e81fa8cea4ef5ab2a39602eb29355 msgid "Server-Initiated Transfer (Server → Client)" msgstr "Передача, инициированная сервером (Сервер → Клиент)" -#: ../../source/File_Transfer/File_Transfer.rst:242 -#: 5e8dbd4b351d467cb809c3182feac0a2 +#: ../../source/File_Transfer/File_Transfer.rst:243 +#: 3ab21d4beefb41be83651eec10fd3899 msgid "" "When the server administrator types a command in the server console, for " "example ``/file /path/to/file.txt (127.0.0.1,54321)``, the console input " @@ -544,13 +547,13 @@ msgstr "" "(``console_input``) анализирует команду и вызывает соответствующий API " "передачи файлов на стороне сервера." -#: ../../source/File_Transfer/File_Transfer.rst:250 -#: 3bec81e76a2c4bf3b37386e180cc4fc1 +#: ../../source/File_Transfer/File_Transfer.rst:251 +#: fa019410dca84c04b24bf9334131aa8d msgid "The recommended entry points for server-to-client transfers are:" msgstr "Рекомендуемые точки входа для передачи данных с сервера на клиент:" -#: ../../source/File_Transfer/File_Transfer.rst:253 -#: 585d149b4b3f47f09176b4b61d3baeaa +#: ../../source/File_Transfer/File_Transfer.rst:254 +#: 99103b4e1f234e2dac2ffc955ab5b23e msgid "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` for a single file." @@ -558,13 +561,13 @@ msgstr "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` для одного файла." -#: ../../source/File_Transfer/File_Transfer.rst:256 -#: 81935504645c451b844d109037b46ae0 +#: ../../source/File_Transfer/File_Transfer.rst:257 +#: a1560a9b45c043618778f38beb1c3cb2 msgid "``folder_file_transfer_server_recv_client_start(message)`` for a folder." msgstr "``folder_file_transfer_server_recv_client_start(message)`` для папки." -#: ../../source/File_Transfer/File_Transfer.rst:258 -#: 4ca3cac907c04414925f5219b700d0e5 +#: ../../source/File_Transfer/File_Transfer.rst:259 +#: c18cb827a52f48d6b2883b708e2c871e msgid "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " for multiple files to multiple clients." @@ -572,8 +575,8 @@ msgstr "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " для нескольких файлов нескольким клиентам." -#: ../../source/File_Transfer/File_Transfer.rst:260 -#: 536f30cc03f84b218a5ca9b84deb9f88 +#: ../../source/File_Transfer/File_Transfer.rst:261 +#: 1b9fd8eea75e46899f68c6ca1312e896 msgid "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " for different file lists to different clients." @@ -581,8 +584,8 @@ msgstr "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " для разных списков файлов разным клиентам." -#: ../../source/File_Transfer/File_Transfer.rst:263 -#: 92500d9fd7124d9ca7b648f03df90141 +#: ../../source/File_Transfer/File_Transfer.rst:264 +#: d34ac75777c74fe4bc63e1a100fd2aa3 msgid "" "The worker function ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` performs the following steps:" @@ -590,8 +593,8 @@ msgstr "" "Рабочая функция file_transfer_server_recv_client_start(message, " "file_folder_abspath=None) выполняет следующие шаги:" -#: ../../source/File_Transfer/File_Transfer.rst:268 -#: 583e8c89824f46ae839d233ab9e70e1a +#: ../../source/File_Transfer/File_Transfer.rst:269 +#: 29d03e172fd346e2a7928b55510df4f1 msgid "" "Extract the target client address from the last part of the command " "(e.g., ``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the " @@ -601,8 +604,8 @@ msgstr "" "``(127.0.0.1,54321)``), используя ``ast.literal_eval()``. Получите сокет " "клиента из self.clients." -#: ../../source/File_Transfer/File_Transfer.rst:273 -#: fd63ce90d3794b2181cdaa927e1a7a38 +#: ../../source/File_Transfer/File_Transfer.rst:274 +#: 7a8d8ed423524d6e91a311a3aa3d5a9a msgid "" "Allocate a unique client ID and extend the command with it, then send the" " extended command to the client over the main connection." @@ -610,13 +613,13 @@ msgstr "" "Выделите уникальный идентификатор клиента и дополните им команду, а затем" " отправьте расширенную команду клиенту через основное соединение." -#: ../../source/File_Transfer/File_Transfer.rst:277 -#: 6138738f134b48b2a98d05d3569172c7 +#: ../../source/File_Transfer/File_Transfer.rst:278 +#: 94b6c1f8a6a240e4ba4be8cf20f87c7f msgid "Allocate a local port with ``palloc()``." msgstr "Выделите локальный порт с помощью palloc()." -#: ../../source/File_Transfer/File_Transfer.rst:278 -#: 26fa94f94e1841f6845765f4fd65949d +#: ../../source/File_Transfer/File_Transfer.rst:279 +#: 723a05b6c3974b65a539af723f1e0872 msgid "" "Wait for the client to reply with its own port number (via " "``/server_file_transfer_port``), which is stored in " @@ -626,8 +629,8 @@ msgstr "" "``/server_file_transfer_port``), который хранится в " "``file_server_port_list`` обработчиком сообщений основного соединения." -#: ../../source/File_Transfer/File_Transfer.rst:283 -#: 4bd913210d8945ffb7312070e070f252 +#: ../../source/File_Transfer/File_Transfer.rst:284 +#: 878572ca3d2948a9acbb6741f00ddd62 msgid "" "Call ``file_transfer_mode(filename, client_host, client_port, " "local_port)`` to send the file." @@ -635,8 +638,8 @@ msgstr "" "Вызовите ``file_transfer_mode(filename, client_host, client_port, " "local_port)``, чтобы отправить файл." -#: ../../source/File_Transfer/File_Transfer.rst:287 -#: 39d0bdae658241a0a8205977cccd0395 +#: ../../source/File_Transfer/File_Transfer.rst:288 +#: ca517571b2d34c0497fcf5d5b12c93a1 msgid "" "On the client side, when it receives a command like ``/file " "/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls" @@ -654,13 +657,13 @@ msgstr "" "порт, отвечает ``/server_file_transfer_port`` и вызывает " "``file_transfer_mode_recv`` для получения и сохранения файла." -#: ../../source/File_Transfer/File_Transfer.rst:303 -#: 014166967bb14b20a2782598b535575a +#: ../../source/File_Transfer/File_Transfer.rst:304 +#: cb7bdf5091e54e039de9d5578c273b93 msgid "Folder Transfer Mechanism (Detailed)" msgstr "Механизм передачи папок (подробно)" -#: ../../source/File_Transfer/File_Transfer.rst:305 -#: 38eff5e62e844c0e94d587ba7132d26c +#: ../../source/File_Transfer/File_Transfer.rst:306 +#: b282df0b45bd4bb087ae10816fd3f06d msgid "" "Transferring a folder is implemented as a **recursive walk** that sends " "separate commands for subdirectories and files. The logic is symmetric on" @@ -670,13 +673,13 @@ msgstr "" "отдельные команды для подкаталогов и файлов. Логика симметрична как на " "клиенте, так и на сервере." -#: ../../source/File_Transfer/File_Transfer.rst:311 -#: 7319cca2fbef48679002d3bf0469d842 +#: ../../source/File_Transfer/File_Transfer.rst:312 +#: fb34b1f5d8a4488b9aef8b71dcb764ec msgid "### Creating Directories" msgstr "### Создание каталогов" -#: ../../source/File_Transfer/File_Transfer.rst:313 -#: ad592f4510c34ecca1cba340caa2710e +#: ../../source/File_Transfer/File_Transfer.rst:314 +#: 6b67f2390d914745a253523cef9a2e0b msgid "" "For a directory that needs to be created on the receiver side, the sender" " sends a command of the form:" @@ -684,13 +687,13 @@ msgstr "" "Для каталога, который необходимо создать на стороне получателя, " "отправитель отправляет команду вида:" -#: ../../source/File_Transfer/File_Transfer.rst:317 -#: 114e36ce42e940cc8f0ec8c64c1db031 +#: ../../source/File_Transfer/File_Transfer.rst:318 +#: 7aaf85bf38fa4621a760dc56b6f99ad6 msgid "``/file_folder ``" msgstr "``/file_folder <относительный_путь>``" -#: ../../source/File_Transfer/File_Transfer.rst:319 -#: a120552b93294a059a34132ab935068a +#: ../../source/File_Transfer/File_Transfer.rst:320 +#: 046f125a1f6e41e4808a9cd703e34ee4 msgid "" "The receiver's handler for this command (in either " "``file_folder_transfer_server_recv_server_start_thread`` or " @@ -706,23 +709,23 @@ msgstr "" "для сервера, тот же каталог для клиента). Относительный путь использует " "косую черту, чтобы быть независимым от платформы." -#: ../../source/File_Transfer/File_Transfer.rst:330 -#: 2743fec0a2434e2b96ea3c49fecf268c +#: ../../source/File_Transfer/File_Transfer.rst:331 +#: 3fb5d6322ccd47f79e601e38684fe234 msgid "### Sending Files Inside a Folder" msgstr "### Отправка файлов внутри папки" -#: ../../source/File_Transfer/File_Transfer.rst:332 -#: fb31b657a05547109dea51165844a632 +#: ../../source/File_Transfer/File_Transfer.rst:333 +#: c9f77546ed49407fa57c57f0b0a76acf msgid "For each file, the sender sends a command of the form:" msgstr "Для каждого файла отправитель отправляет команду вида:" -#: ../../source/File_Transfer/File_Transfer.rst:334 -#: 2da676ce8dd649169ba224f6d29cbbc9 +#: ../../source/File_Transfer/File_Transfer.rst:335 +#: f5a164466b0d4d4382b7d880bd320e3d msgid "``/file_folder ``" msgstr "``/file_folder <относительный_путь> <имя_файла>``" -#: ../../source/File_Transfer/File_Transfer.rst:336 -#: 8972f356722148e3b34cbaa95390d700 +#: ../../source/File_Transfer/File_Transfer.rst:337 +#: c507cca92d1c463ea9f4d429a38a9b6a msgid "" "The receiver treats this as a file transfer request. The second argument " "(``file_name``) is used as the final filename, and the relative path " @@ -739,13 +742,13 @@ msgstr "" " или ``file_transfer_server_recv_client_start``, в зависимости от " "направления)." -#: ../../source/File_Transfer/File_Transfer.rst:347 -#: a0ded05fd7f2406abb0ee41fcc33b53b +#: ../../source/File_Transfer/File_Transfer.rst:348 +#: e1e2b8dd57524ecfabd47c2c8386dfea msgid "### Concurrency Control for Folders" msgstr "### Управление параллелизмом для папок" -#: ../../source/File_Transfer/File_Transfer.rst:349 -#: 14b0ec4d109c448198db41c196df8a70 +#: ../../source/File_Transfer/File_Transfer.rst:350 +#: 32b26f72bba4482490f38968dcee5837 msgid "" "Because a folder can contain many files, the sender uses a semaphore " "(``file_semaphore``) to limit the number of concurrently active file " @@ -761,13 +764,13 @@ msgstr "" "параллелизм устанавливается параметром max_thread_num на клиенте и " "max_file_transfer_thread_num на сервере." -#: ../../source/File_Transfer/File_Transfer.rst:362 -#: 2c7d84b855df4587bfb110f525299e39 +#: ../../source/File_Transfer/File_Transfer.rst:363 +#: 8ce424a7f1de4933b3113a0e3ab98155 msgid "Custom Destination Directory" msgstr "Пользовательский целевой каталог" -#: ../../source/File_Transfer/File_Transfer.rst:364 -#: b972e019f10143a99af9de9b7a8e371a +#: ../../source/File_Transfer/File_Transfer.rst:365 +#: 6ca8ee9f021842939f446e999c067dfb msgid "" "Every transfer family accepts an optional trailing " "``destination_file_path`` argument that replaces the receiver's default " @@ -781,8 +784,8 @@ msgstr "" "Если он опущен, передача осуществляется в местоположение по умолчанию " "точно так же, как и раньше." -#: ../../source/File_Transfer/File_Transfer.rst:372 -#: 1e801c2a599e4595b5f883ada1a63fc6 +#: ../../source/File_Transfer/File_Transfer.rst:373 +#: 6291da89ffa542dfbd94f599a9321216 msgid "" "The destination is **always the last argument** of the command and names " "a *directory* on the receiving machine: the received file keeps its own " @@ -799,39 +802,39 @@ msgstr "" "есть; относительный путь определяется в каталоге сохранения по умолчанию." " Отсутствующие каталоги создаются." -#: ../../source/File_Transfer/File_Transfer.rst:384 -#: 6b85151737b64a3e90154ba763b205d2 +#: ../../source/File_Transfer/File_Transfer.rst:385 +#: 76243e0349c1474bbdf14e1ef2a8e52b msgid "Command syntax:" msgstr "Синтаксис команды:" -#: ../../source/File_Transfer/File_Transfer.rst:386 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:387 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "Client console (the receiver is the server):" msgstr "Клиентская консоль (приемник — сервер):" -#: ../../source/File_Transfer/File_Transfer.rst:388 -#: bac62d5b11c84f96b2b3841af7fc7a85 +#: ../../source/File_Transfer/File_Transfer.rst:389 +#: c9fa612895bc4f92839d2de77b6cbc7f msgid "``/file [destination_file_path]``" msgstr "``/file <путь_файла> [путь_назначающего_файла]``" -#: ../../source/File_Transfer/File_Transfer.rst:390 -#: aa07623d0b4048be944b30c6fc07cc1b +#: ../../source/File_Transfer/File_Transfer.rst:391 +#: 2d34a030a1804d299a0b56c14984b1b5 msgid "``/multiple_file ... [destination_file_path]``" msgstr "``/multiple_file <файл1> <файл2> ... [путь_файла_назначения]``" -#: ../../source/File_Transfer/File_Transfer.rst:392 -#: 1a9cfb266bb24df6ac2ddeb286a212d0 +#: ../../source/File_Transfer/File_Transfer.rst:393 +#: a7dd1e241a4346d4b873072c5948f187 #, fuzzy msgid "``/file_folder [destination_file_path]``" msgstr "``/file_folder <относительный_путь>``" -#: ../../source/File_Transfer/File_Transfer.rst:394 -#: 46f89a56ef594dec945f21425306e2de +#: ../../source/File_Transfer/File_Transfer.rst:395 +#: 953993d920eb4959987d98423440ce61 msgid "``/multiple_file_folder ... [destination_file_path]``" msgstr "``/multiple_file_folder <папка1> <папка2> ... [путь_файла_назначения]``" -#: ../../source/File_Transfer/File_Transfer.rst:396 -#: 085ba670e149450a8b385d68c8f9d366 +#: ../../source/File_Transfer/File_Transfer.rst:397 +#: 886c8b7d760044cabe48ce044412ca64 #, fuzzy msgid "" "Server console (the receiver is the target client, given as a quoted " @@ -840,20 +843,20 @@ msgstr "" "Консоль сервера (получателем является целевой клиент, заданный в виде " "кортежа адресов в кавычках):" -#: ../../source/File_Transfer/File_Transfer.rst:400 -#: abc0fb96992e4b09aaa9714ba73a094b +#: ../../source/File_Transfer/File_Transfer.rst:401 +#: 48d3bf6084224062867313a9597044d7 #, fuzzy msgid "``/file <(ip, port)> [destination_file_path]``" msgstr "``/file <путь_файла> [путь_назначающего_файла]``" -#: ../../source/File_Transfer/File_Transfer.rst:402 -#: d9329c72161247bf8d5f0a609178c488 +#: ../../source/File_Transfer/File_Transfer.rst:403 +#: 684fa9b22136418b94cbb4202f702cd2 #, fuzzy msgid "``/file_folder <(ip, port)> [destination_file_path]``" msgstr "``/file_folder <относительный_путь>``" -#: ../../source/File_Transfer/File_Transfer.rst:404 -#: af78c6ec2f3e4072aaac19d2d131cf5d +#: ../../source/File_Transfer/File_Transfer.rst:405 +#: 9380dc31685947e3a835107f435deed2 #, fuzzy msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -862,16 +865,16 @@ msgstr "" "``/multiple_file_multiple_client <файл1> <файл2> ... " " ... [destination_file_path]``" -#: ../../source/File_Transfer/File_Transfer.rst:406 -#: 2fdbf92caa6a46df9dae793592be802d +#: ../../source/File_Transfer/File_Transfer.rst:407 +#: 62488b8bb4e149be86c1d655bd80b6a8 #, fuzzy msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, port)1> ... " "[destination_file_path]``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:408 -#: abc1dac22b594c54a22b03d59e1a8338 +#: ../../source/File_Transfer/File_Transfer.rst:409 +#: d6a0c51014c9403fb82ebdf5c93928bc msgid "" "For the multiple-item commands the destination is the last argument; when" " the last argument is not a ``(ip, port)`` tuple it is treated as the " @@ -881,13 +884,13 @@ msgid "" "destination)." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:418 -#: 0c7fa56659f543ed93adacd874dd2e8b +#: ../../source/File_Transfer/File_Transfer.rst:419 +#: 373c2a5a23334df7a25d23f8d94abd66 msgid "Native In-Memory Forwarding" msgstr "Собственная пересылка в памяти" -#: ../../source/File_Transfer/File_Transfer.rst:420 -#: 133205c62a0846318b30f5f5fe0dc296 +#: ../../source/File_Transfer/File_Transfer.rst:421 +#: dd57639b3e0e4068bd9533fc039597cd #, fuzzy msgid "" "The main protocol also provides a native, client-side forwarding feature " @@ -906,30 +909,30 @@ msgstr "" " их прямо целевым клиентам. Это позволяет избежать двойного времени " "передачи и накладных расходов на чтение/запись на диск." -#: ../../source/File_Transfer/File_Transfer.rst:432 -#: b177ec0385be4e9da692646b88cd3ed8 +#: ../../source/File_Transfer/File_Transfer.rst:433 +#: 982c4c9538914821a07887fb8ab9b95d #, fuzzy msgid "Commands (client console only; rejected on the server console):" msgstr "Клиентская консоль (приемник — сервер):" -#: ../../source/File_Transfer/File_Transfer.rst:435 -#: 789bd7878891443fa43ec5111b3a028b +#: ../../source/File_Transfer/File_Transfer.rst:436 +#: 14406316555743359a854540ab6937c8 #, fuzzy msgid "" "``/forward_file ... ... " "[destination_file_path]``" msgstr "``/forward_file <файл1> <файл2> ... <адрес1> <адрес2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:436 -#: 04d9ece635c94b8c9257e0cb41bd5b81 +#: ../../source/File_Transfer/File_Transfer.rst:437 +#: 4dc576898177404da124649f7ce9ac28 #, fuzzy msgid "" "``/forward_folder ... ... " "[destination_file_path]``" msgstr "``/forward_folder <папка1> <папка2> ... <адрес1> <адрес2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:438 -#: 2f7b628a4e0246e385e9e8817b8d7a87 +#: ../../source/File_Transfer/File_Transfer.rst:439 +#: 220dfbf0a0d84559a8befb4eee500ba0 msgid "" "The number of files/folders and the number of target clients (written as " "quoted address tuples) is unlimited. Target addresses that are " @@ -941,8 +944,8 @@ msgstr "" "недоступны (не подключены к серверу) или равны самому серверу, " "пропускаются, а остальные цели по-прежнему обслуживаются." -#: ../../source/File_Transfer/File_Transfer.rst:446 -#: 84f3e0acf89e4767bbb572cc6edc81aa +#: ../../source/File_Transfer/File_Transfer.rst:447 +#: 6137bf9406784c6f82d9f41560a52566 msgid "" "Like every transfer family, both commands accept an optional trailing " "``destination_file_path`` that replaces the default save directory on " @@ -959,25 +962,25 @@ msgstr "" "аргумент опущен, конечные объекты записывают в файл по умолчанию " "``file_transfer_dir``." -#: ../../source/File_Transfer/File_Transfer.rst:457 -#: 6b31e93335824fe1bfdb83b84f42f08c +#: ../../source/File_Transfer/File_Transfer.rst:458 +#: f6697695e9ef4e3694fa9046e41578e0 msgid "The data path reuses the protocol's own transfer machinery:" msgstr "Путь к данным повторно использует собственный механизм передачи протокола:" -#: ../../source/File_Transfer/File_Transfer.rst:460 -#: 469812eff1874189a000989c9260cf1b +#: ../../source/File_Transfer/File_Transfer.rst:461 +#: 6ee037f0e4024d2988fcb2ccf3deef70 #, fuzzy msgid "" "The forwarding client streams the file with the standard file-transfer " -"byte stream (metadata header + 65536-byte chunks) to a transfer socket on" -" the server." +"byte stream (metadata header + ``file_transfer_chunk_len``-byte chunks, " +"default 65536) to a transfer socket on the server." msgstr "" "Клиент пересылки передает файл со стандартным потоком байтов для передачи" " файлов (заголовок метаданных + фрагменты по 64 КиБ) в сокет передачи на " "сервере." -#: ../../source/File_Transfer/File_Transfer.rst:465 -#: 42efd096a6744f489dc623a6ee503666 +#: ../../source/File_Transfer/File_Transfer.rst:467 +#: 43c94e746a5c46748846d0dc18a4e0ff msgid "" "The server acts as a pure relay: it reads the stream into per-target " "memory queues and writes each chunk to every target's transfer socket. " @@ -989,8 +992,8 @@ msgstr "" "каждой цели. Сервер никогда не анализирует содержимое файла за пределами " "заголовка размера и никогда не записывает на диск." -#: ../../source/File_Transfer/File_Transfer.rst:472 -#: f43cb20c7bc648018f6f77ea09c8d538 +#: ../../source/File_Transfer/File_Transfer.rst:474 +#: 9dec57916af34e109bee7ce1e0bae2d4 msgid "" "Every target client receives the stream with the ordinary receive path " "(``file_transfer_mode_recv``) and writes it to its own local disk, " @@ -1000,13 +1003,13 @@ msgstr "" "(file_transfer_mode_recv) и записывает его на свой локальный диск, точно " "так же, как если бы сервер отправил файл напрямую." -#: ../../source/File_Transfer/File_Transfer.rst:478 -#: 3885df70422e4306ac80be623aa9581f +#: ../../source/File_Transfer/File_Transfer.rst:480 +#: a095abaf821e41a6a66adbb776bc35ef msgid "### Memory Bounding and Flow Control" msgstr "### Ограничение памяти и управление потоком" -#: ../../source/File_Transfer/File_Transfer.rst:480 -#: e371e5b793824e3386b43cb07a4222fd +#: ../../source/File_Transfer/File_Transfer.rst:482 +#: 244214dd675345f8a72b1088ad99fea0 #, fuzzy msgid "" "Because uploader, server and targets may have different bandwidths, data " @@ -1036,13 +1039,13 @@ msgstr "" "``/pause_trans``/``/start_trans`` существуют на обеих сторонах, поэтому " "любая сторона может регулировать передачу при буферизации данных." -#: ../../source/File_Transfer/File_Transfer.rst:504 -#: b737bf957d354491b30903bfb0f89a3b +#: ../../source/File_Transfer/File_Transfer.rst:506 +#: 0aa14deaf6474437b421a65e21fce7d8 msgid "Concurrency and Threading" msgstr "Параллелизм и многопоточность" -#: ../../source/File_Transfer/File_Transfer.rst:506 -#: 505576a3522748318a95cd3937a96834 +#: ../../source/File_Transfer/File_Transfer.rst:508 +#: 825c5e1a8b9b405c967ca49a1861e258 msgid "" "Both the server and the client use multiple levels of concurrency control" " to ensure stability during file transfers." @@ -1050,18 +1053,18 @@ msgstr "" "И сервер, и клиент используют несколько уровней управления параллелизмом " "для обеспечения стабильности во время передачи файлов." -#: ../../source/File_Transfer/File_Transfer.rst:510 -#: 1d1a7b2ee1434530ae6abb411b0175cc +#: ../../source/File_Transfer/File_Transfer.rst:512 +#: 0d48b1245cd54597928cfc28d5b3c248 msgid "### File Transfer Semaphore" msgstr "### Семафор передачи файлов" -#: ../../source/File_Transfer/File_Transfer.rst:512 -#: 078680d22b10410db9f7f21fe0e1a91d +#: ../../source/File_Transfer/File_Transfer.rst:514 +#: e2674ee9e0584513bc53aa815603fd24 msgid "Client: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" msgstr "Клиент: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:514 -#: 777a1dcc1258459d89dacbbb7b946c11 +#: ../../source/File_Transfer/File_Transfer.rst:516 +#: 1c0d27d13ad844159d29c6e662d51d09 msgid "" "Server: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" @@ -1069,8 +1072,8 @@ msgstr "" "Сервер: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:517 -#: 315a82a6dd1a420bbe819a806f3b8292 +#: ../../source/File_Transfer/File_Transfer.rst:519 +#: cb65901904c8411ba53fc629023f732d #, fuzzy msgid "" "This semaphore limits the number of simultaneous file transfers (used " @@ -1084,13 +1087,13 @@ msgstr "" "Каждая передача выполняется в своем собственном потоке, и семафор " "получается до запуска потока." -#: ../../source/File_Transfer/File_Transfer.rst:524 -#: b39cfe74f74b4b568221d23addc55da3 +#: ../../source/File_Transfer/File_Transfer.rst:526 +#: 6d93783b298e4ce98b999ff890d4a5f4 msgid "### Threading Model" msgstr "### Модель потоков" -#: ../../source/File_Transfer/File_Transfer.rst:526 -#: 5586d5cc13a940bb92877b1fed3d03fd +#: ../../source/File_Transfer/File_Transfer.rst:528 +#: 036a972600e645119d8a523fa08a52db msgid "" "Each file transfer runs in a dedicated daemon thread, created by the " "``_thread`` wrapper functions (e.g., " @@ -1102,8 +1105,8 @@ msgstr "" "``file_transfer_client_recv_client_start_thread``). Это предотвращает " "блокировку основного контура управления при медленной передаче." -#: ../../source/File_Transfer/File_Transfer.rst:532 -#: 7b1cceca816c426b865265e0c302c425 +#: ../../source/File_Transfer/File_Transfer.rst:534 +#: a84aaf5f9fb64d92b97c32185a1e7cb5 msgid "" "The thread that receives the transfer command (e.g., the server's " "``handle_command`` thread) does not wait for the transfer to complete; it" @@ -1113,8 +1116,8 @@ msgstr "" "«handle_command» сервера), не ждет завершения передачи; он возвращается " "сразу после создания рабочего потока." -#: ../../source/File_Transfer/File_Transfer.rst:537 -#: 2d25f2be19fb467bb222d3780e2be853 +#: ../../source/File_Transfer/File_Transfer.rst:539 +#: 669fb6da8e7444dd829a6e14295648b1 msgid "" "The low-level receive function (``file_transfer_mode_recv``) blocks while" " reading from the transfer socket, but because it runs in a dedicated " @@ -1124,13 +1127,13 @@ msgstr "" "чтении из сокета передачи, но поскольку она выполняется в выделенном " "потоке, основное соединение остается отзывчивым." -#: ../../source/File_Transfer/File_Transfer.rst:543 -#: 641bce0854274c369c0b915a1c3d964a +#: ../../source/File_Transfer/File_Transfer.rst:545 +#: e39f8ae06ae84a6b84de8a3008ca17cb msgid "### Thread Pool for Custom Commands" msgstr "### Пул потоков для пользовательских команд" -#: ../../source/File_Transfer/File_Transfer.rst:545 -#: c41d6414ad5542aa8bbeaa67d28730d5 +#: ../../source/File_Transfer/File_Transfer.rst:547 +#: 3ad49853529d4563bacdfb4ca6eee115 msgid "" "Both classes also provide a ``ThreadPoolExecutor`` " "(``self._custom_executor``) for custom command handlers. When a handler " @@ -1148,13 +1151,13 @@ msgstr "" "семафора передачи файлов и предназначен для обработки команд общего " "назначения." -#: ../../source/File_Transfer/File_Transfer.rst:560 -#: adfe7eb4ec4942e9979652f98b3beed9 +#: ../../source/File_Transfer/File_Transfer.rst:562 +#: 1862d74da28a40219f82cfd7af89c126 msgid "Port Allocation and Management" msgstr "Распределение портов и управление ими" -#: ../../source/File_Transfer/File_Transfer.rst:562 -#: 845beb63ef9c47ba8379637a1b0662fb +#: ../../source/File_Transfer/File_Transfer.rst:564 +#: bd53ec8aa4ef498aa0815db16ed03140 msgid "" "File transfers require ephemeral ports for the secondary data " "connections. The ``palloc()`` and ``pfree()`` methods are used to obtain " @@ -1164,8 +1167,8 @@ msgstr "" " данным. Методы palloc() и pfree() используются для получения и " "освобождения этих портов. Доступны два режима:" -#: ../../source/File_Transfer/File_Transfer.rst:568 -#: 8195ea505bdf43a2a0f68b78d958c709 +#: ../../source/File_Transfer/File_Transfer.rst:570 +#: eeaa9379d7d941159ac34f30ff6bb5f9 msgid "" "**Automatic mode** (``is_hand_alloc_port=False``): ``palloc()`` returns " "``0``, and the operating system assigns a free port when the socket is " @@ -1176,8 +1179,8 @@ msgstr "" "сокет привязан. Это рекомендуемый режим для большинства случаев " "использования." -#: ../../source/File_Transfer/File_Transfer.rst:573 -#: 9a796b6e464d4d9e8e131401d5022e1f +#: ../../source/File_Transfer/File_Transfer.rst:575 +#: e3dc324e81734bd4bc768174caf200bf #, fuzzy msgid "" "**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; " @@ -1195,8 +1198,8 @@ msgstr "" "через ``/client_alloc_port_range``, и клиенты затем используют ту же " "логику ручного выделения." -#: ../../source/File_Transfer/File_Transfer.rst:588 -#: 7d275701519c4d60ba94cf086010e92d +#: ../../source/File_Transfer/File_Transfer.rst:590 +#: 29cfdab183eb4f9f83de41ef62a60785 msgid "" "*Note: For more details about port allocation, please visit the Port " "Allocation API sections in :doc:`TCP_Server_APIs` and " @@ -1206,18 +1209,18 @@ msgstr "" "портов посетите разделы API распределения портов в документах " ":doc:`TCP_Server_APIs` и :doc:`TCP_Client_APIs`.*" -#: ../../source/File_Transfer/File_Transfer.rst:596 -#: e92794553f6f4189978c5486f4d09fce +#: ../../source/File_Transfer/File_Transfer.rst:598 +#: 189736d8d1f8464b8d301f219700fda4 msgid "Error Handling and Timeouts" msgstr "Обработка ошибок и тайм-ауты" -#: ../../source/File_Transfer/File_Transfer.rst:598 -#: 6ef0c4c7a91a42d0acc6b0a387247432 +#: ../../source/File_Transfer/File_Transfer.rst:600 +#: bcc373777989436f9df3657446d1a7f2 msgid "### Timeout Values" msgstr "### Значения тайм-аута" -#: ../../source/File_Transfer/File_Transfer.rst:600 -#: 2b8dea32ffe04d4988e44fca72384271 +#: ../../source/File_Transfer/File_Transfer.rst:602 +#: 27d75d097a804ec28ebec5c67469c9c6 msgid "" "**Start signal timeout**: 10 seconds. If the receiver does not send " "``server_start_file_transfer_sign`` within this time, the sender aborts." @@ -1226,8 +1229,8 @@ msgstr "" " ``server_start_file_transfer_sign`` в течение этого времени, отправитель" " прерывает работу." -#: ../../source/File_Transfer/File_Transfer.rst:604 -#: 2d19f71ef52b4f3097bf0c2f3e64be7b +#: ../../source/File_Transfer/File_Transfer.rst:606 +#: 93e877c411eb4c96bd7861ff61f35e7a msgid "" "**Port negotiation timeout**: 20 seconds. The initiator waits for the " "peer's ``/server_file_transfer_port`` response." @@ -1235,8 +1238,8 @@ msgstr "" "**Тайм-аут согласования порта**: 20 секунд. Инициатор ожидает ответа узла" " ``/server_file_transfer_port``." -#: ../../source/File_Transfer/File_Transfer.rst:607 -#: 67dba14dcd534ae484df410cb48c8e53 +#: ../../source/File_Transfer/File_Transfer.rst:609 +#: 9e1d395bb59540a49393bebe6630e5eb msgid "" "**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 " "* 1024)) * 10`` seconds. Larger files get proportionally more time." @@ -1245,13 +1248,13 @@ msgstr "" " 1024)) * 10`` секунд. Файлам большего размера требуется пропорционально " "больше времени." -#: ../../source/File_Transfer/File_Transfer.rst:611 -#: f175db3ace1448068c029d1527feb065 +#: ../../source/File_Transfer/File_Transfer.rst:613 +#: 6b4e6135669b41178fdbb47ea5975381 msgid "### Error Signalling" msgstr "### Сигнализация об ошибках" -#: ../../source/File_Transfer/File_Transfer.rst:613 -#: 988d9d4636944c0abc8d186178d2a4f7 +#: ../../source/File_Transfer/File_Transfer.rst:615 +#: 448fdc6ba3dd4d9eae925e7e241f8cb8 msgid "" "Any error during the handshake or data transfer causes the failing side " "to send ``error_sign`` over the transfer socket." @@ -1259,8 +1262,8 @@ msgstr "" "Любая ошибка во время установления связи или передачи данных приводит к " "тому, что сбойная сторона отправляет ``error_sign`` через сокет передачи." -#: ../../source/File_Transfer/File_Transfer.rst:616 -#: d171618e798b46d0a6ac7473b4a787ba +#: ../../source/File_Transfer/File_Transfer.rst:618 +#: 5b4c23a93e984ce0af2e43cf4752225b msgid "" "The other side, upon receiving the error sign, closes the transfer socket" " and aborts the transfer." @@ -1268,8 +1271,8 @@ msgstr "" "Другая сторона, получив знак ошибки, закрывает сокет передачи и прерывает" " передачу." -#: ../../source/File_Transfer/File_Transfer.rst:619 -#: c712f2f5e1794c528d4816a761030029 +#: ../../source/File_Transfer/File_Transfer.rst:621 +#: b337a2726ded4d619c5e8026bef3f6ea msgid "" "The main control connection remains unaffected; only the transfer socket " "is closed." @@ -1277,13 +1280,13 @@ msgstr "" "Главное соединение управления остается неизменным; закрыт только " "передаточный сокет." -#: ../../source/File_Transfer/File_Transfer.rst:623 -#: 9d55f6049713415794e53bd6a476e11f +#: ../../source/File_Transfer/File_Transfer.rst:625 +#: 68be52c8e5ce447a9c5ec51a661229cf msgid "### Exception Handling" msgstr "### Обработка исключений" -#: ../../source/File_Transfer/File_Transfer.rst:625 -#: a45a6eaec53b4699a7e61d4e422ace85 +#: ../../source/File_Transfer/File_Transfer.rst:627 +#: 036db9bc1858417ca589816028b83f80 #, fuzzy msgid "" "All socket operations are wrapped in try-except blocks. When an exception" @@ -1299,13 +1302,172 @@ msgstr "" "прерывается. Если возможно, отправляется ``error_sign``, и сокет передачи" " закрывается." -#: ../../source/File_Transfer/File_Transfer.rst:638 -#: 00af57a759ec4845b5810bb85ac1f485 +#: ../../source/File_Transfer/File_Transfer.rst:640 +#: ba1f05134dd24afa9867881cc45ed14a +msgid "Transfer Progress and Network Speed" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:642 +#: 5c7b182bb5214dd2ad49e5b171876e95 +msgid "Both classes record every running file transfer:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:644 +#: 8adbb686d9b04c97b5a7314ec4a5d1fd +msgid "``file_recv_progress`` — the files being received (downloads);" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:645 +#: 3d2d981185624b5498121d82b12d44ba +msgid "``file_upload_progress`` — the files being sent (uploads)." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:647 +#: e59132f2790d4b4fb2aa707e1d3b43b6 +msgid "" +"The keys are the transfers' fids: the transfer id the sender stamps on " +"the transfer command (``/file ``), which also identifies the " +"relay leg of a forwarded file. The protocol-internal public-key push is " +"not tracked. Each value is a five-item list:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:652 +#: bf66e7dae7e24cf3a3687ffd30f547ec +msgid "``[0]``: bytes transferred so far;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:653 +#: 2652aa8074764124b520d4e84b7667d5 +msgid "``[1]``: total size of the file, in bytes;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:654 +#: 8b09fc93700d4b6ca7a517700649c289 +msgid "" +"``[2]``: the current network speed of that direction — ``None`` until the" +" transfer has moved its first chunk, and while " +"``is_enable_real_time_network_speed`` is ``False``;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:657 +#: 311adcc13bd441a985ebcd8c775b152f +msgid "" +"``[3]``: local path of the file: the source of an outbound transfer, the " +"file being written for an inbound one;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:659 +#: 7a1f875aeb8b497ab7785620e402ff97 +msgid "" +"``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender " +"in a download's entry, the receiver in an upload's. A forwarded transfer " +"stores the original peer on both sides, never the relaying server." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:663 +#: da38fbed94114f10b6f7366e43906dd8 +msgid "" +"An entry appears when a transfer starts and is removed when it ends, so " +"the stores hold exactly the transfers that are in flight at that moment " +"(iterate over a copy while transfers are running). With " +"``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is " +"ever recorded — and, since the stores are the state a reconnect resumes " +"from, no transfer can be resumed either." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:670 +#: edbdd37cf5a04d42bf01f6bff5aa3307 +msgid "" +"``is_enable_real_time_network_speed`` (``True`` by default) measures the " +"protocol's current traffic — the control layer and every temporary " +"connection, file transfers included — into ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With the flag ``False`` nothing is " +"sampled and every speed value is ``None``." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:677 +#: c60e3cb78c8d48faace7569bdb50f8f5 +msgid "" +"The web tool (``transfer_web``) reads these stores: both backends serve " +"``/api/transfers`` (the rows plus the two speed attributes), and the " +"shared frontend renders the live speed readout in the topbar and one " +"progress bar per running transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:685 +#: ce90e0b6082e4d37a79346aa7b2763f9 +msgid "Pausing, Reconnecting and Resuming Transfers" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:687 +#: 5fbf414617474bd79978360043f149a3 +msgid "" +"An outbound transfer can be held and released at any time with the " +"``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or " +"from the peer with the ``/pause_trans `` and ``/start_trans `` " +"lines: ``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, " +"fid)`` send them. The leg stops before its next chunk and stays open; a " +"leg that is paused keeps its socket, so nothing is torn down. Every " +"outbound transfer honours its own fid — a plain upload as much as the " +"upload leg of a forwarded file — so the flow control the server uses on a" +" relay works on any transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:696 +#: d4ace80bc05f4bafb8144e1de31060dc +msgid "The temporary connections of a transfer are resumed after a disconnect:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:698 +#: d7d49609832d4c5bb2d7cecb059805eb +msgid "" +"when a connection drops, both sides write their transfer stores to " +"``.Flow/server_file_trans_progress.json`` / " +"``.Flow/client_file_trans_progress.json`` (the " +"``file_trans_progress_file`` attribute) — every upload, every download " +"and, on the server, the relay records a disconnected forward is re-driven" +" from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:703 +#: 353cf50d60014cceb4c5a36bf5b98b83 +msgid "" +"an interrupted transfer keeps its progress entry and its partial file " +"instead of dropping them, so the file on disk is exactly the state to " +"continue from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:706 +#: c7017b370d4147128e54a94458a7b536 +msgid "" +"after a reconnect the receiver drives the resume (`resume_transfers`): it" +" opens a fresh transfer listener, announces it and sends ``/resume_trans " +" `` with the byte offset its partial file holds. The sender " +"re-establishes the leg, reads its source from that offset and only the " +"remainder of the file travels. A forwarded transfer is asked for through " +"the server, which routes ``/forward_resume`` to the originating client so" +" it re-forwards just the missing part." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:714 +#: ee858a76e93f44d5934cb2d89f6709a5 +msgid "" +"The server resumes a peer's transfers when it reconnects, and a client " +"with ``is_auto_reconnect=True`` reconnects on its own and resumes every " +"transfer it can reach; `resume_transfers` is public, so an application " +"can also drive the resume itself. Legs the previous session left behind " +"are closed before the resume runs, so two legs never write the same " +"transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:723 +#: fe9377db9cf04b9da0dbe4d07c730adf msgid "Related API Definitions" msgstr "Связанные определения API" -#: ../../source/File_Transfer/File_Transfer.rst:640 -#: 92c3b5d713cb49cfb144026af574a0b4 +#: ../../source/File_Transfer/File_Transfer.rst:725 +#: cc71cb9b1d6642a2acc89d45a49022cc msgid "" "This section lists all public file-transfer related methods in " "``TCP_Server_Base`` and ``TCP_Client_Base``. For a complete list of all " @@ -1315,13 +1477,13 @@ msgstr "" "передачей файлов, в TCP_Server_Base и TCP_Client_Base. Полный список всех" " общедоступных API см. в таблицах в конце этого документа." -#: ../../source/File_Transfer/File_Transfer.rst:646 -#: bbc49149589d43719bc774a99b84ce6e +#: ../../source/File_Transfer/File_Transfer.rst:731 +#: d6683e415f794c5bb693f8c24370e7f9 msgid "### Server-Side File Transfer APIs" msgstr "### API-интерфейсы передачи файлов на стороне сервера" -#: ../../source/File_Transfer/File_Transfer.rst:652 -#: 59386d051c734452801f4bd00d5dd654 +#: ../../source/File_Transfer/File_Transfer.rst:737 +#: 9123c69197c34d93bb68d088897ebeca msgid "" "Initiates a server-to-client file transfer. ``message`` is the command " "string (e.g., ``/file /path/to/file.txt (127.0.0.1,54321)``). If " @@ -1333,13 +1495,13 @@ msgstr "" "(127.0.0.1,54321)``). Если указан ``file_folder_abspath`` (для передачи " "папок), он указывает абсолютный путь к родительской папке." -#: ../../source/File_Transfer/File_Transfer.rst:663 -#: 431a043a77bc4d82a206650afde47b86 +#: ../../source/File_Transfer/File_Transfer.rst:748 +#: 367dfd82c95c413d963a15152469fc44 msgid "Thread-safe version that starts a new thread for the transfer." msgstr "Потокобезопасная версия, запускающая новый поток для передачи." -#: ../../source/File_Transfer/File_Transfer.rst:669 -#: e17536344cb444b699c7465d8bcbdded +#: ../../source/File_Transfer/File_Transfer.rst:754 +#: d4aa76b7eb2c46c29adee0120a939b66 #, fuzzy msgid "" "Sends an entire folder from server to client. ``message`` should be of " @@ -1349,8 +1511,8 @@ msgstr "" "Отправляет всю папку с сервера клиенту. ``сообщение`` должно иметь форму " "``/папка_файла <путь_к папке> <адрес_клиента>``." -#: ../../source/File_Transfer/File_Transfer.rst:676 -#: 88f9df0240054009a6957b13ee08f2ef +#: ../../source/File_Transfer/File_Transfer.rst:761 +#: 29f2a5e19bf04a09a8711ac1c892a4ad msgid "" "Sends multiple items to multiple clients. The message format is " "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -1361,8 +1523,8 @@ msgid "" "destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:688 -#: 39b67f1d0e6b438386eb04c6d44da6b8 +#: ../../source/File_Transfer/File_Transfer.rst:773 +#: ff8bc5c8969b45c1bbcf1eba5b77485a msgid "" "Sends different file lists to different clients. Files that appear before" " a group of client addresses are sent to that group; a new group starts " @@ -1373,8 +1535,8 @@ msgid "" "optional trailing destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:701 -#: 37108379b0b9495584bb135d5860ea4a +#: ../../source/File_Transfer/File_Transfer.rst:786 +#: f8a880287b7b49d4bdc2239ecf4a0577 msgid "" "Receives a file from a client. Called internally when the server receives" " a ``/file`` command from a client." @@ -1382,8 +1544,8 @@ msgstr "" "Получает файл от клиента. Вызывается внутренне, когда сервер получает " "команду ``/file`` от клиента." -#: ../../source/File_Transfer/File_Transfer.rst:710 -#: adeb784cb6b24d6cbf143a7a50eba80a +#: ../../source/File_Transfer/File_Transfer.rst:795 +#: 97bfaa9c24ae47c39328707b8f17a91a msgid "" "Low-level receive function that performs the handshake and writes the " "incoming file to disk." @@ -1391,22 +1553,23 @@ msgstr "" "Функция приема низкого уровня, которая выполняет подтверждение связи и " "записывает входящий файл на диск." -#: ../../source/File_Transfer/File_Transfer.rst:718 -#: 0bb492f5335d426d8dc715847665b3f4 +#: ../../source/File_Transfer/File_Transfer.rst:804 +#: c7be9703e0454f7f96586642bc8f6a22 msgid "" "Low-level send function that connects to the receiver and transmits the " -"file." +"file. ``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's" +" original receiver and ``resume_offset`` continues an interrupted file " +"from the byte the receiver already holds." msgstr "" -"Функция отправки низкого уровня, которая подключается к получателю и " -"передает файл." -#: ../../source/File_Transfer/File_Transfer.rst:720 -#: 29189fe72c61456ba2d5aa1ece75145e +#: ../../source/File_Transfer/File_Transfer.rst:810 +#: 3e7b689215e840bebd368b4d29104ebc msgid "### Client-Side File Transfer APIs" msgstr "### API передачи файлов на стороне клиента" -#: ../../source/File_Transfer/File_Transfer.rst:726 -#: 6c2f54ee2660441291a3fbbcaa95262c +#: ../../source/File_Transfer/File_Transfer.rst:816 +#: 1e97e492d6504579a9a265eb1242395e msgid "" "Initiates a client-to-server file transfer. ``message`` is the user " "command (e.g., ``/file mydoc.txt``). Used internally by the interactive " @@ -1416,46 +1579,46 @@ msgstr "" "пользователя (например, ``/file mydoc.txt``). Используется внутри " "интерактивной консоли." -#: ../../source/File_Transfer/File_Transfer.rst:734 -#: ../../source/File_Transfer/File_Transfer.rst:765 -#: 07c4ae801fb54cbcb508af4b208f75dd +#: ../../source/File_Transfer/File_Transfer.rst:824 +#: ../../source/File_Transfer/File_Transfer.rst:855 +#: 0cd2695763114a0b831df0bfa80a3d56 msgid "Thread-safe version." msgstr "Потокобезопасная версия." -#: ../../source/File_Transfer/File_Transfer.rst:740 -#: 0d66d4aac681414fb7b8a46117571fe9 +#: ../../source/File_Transfer/File_Transfer.rst:830 +#: 261399ca508d463eafa7f03a00bfc658 msgid "Sends a folder from client to server." msgstr "Отправляет папку с клиента на сервер." -#: ../../source/File_Transfer/File_Transfer.rst:746 -#: 2818655cecfc49f7ab1c9800b9418018 +#: ../../source/File_Transfer/File_Transfer.rst:836 +#: ef5e3b92b11c4530960c1c344a51c73b msgid "Sends multiple files from client to server." msgstr "Отправляет несколько файлов с клиента на сервер." -#: ../../source/File_Transfer/File_Transfer.rst:752 -#: 6ee08a69dbc5486a94fe2f616f0899e2 +#: ../../source/File_Transfer/File_Transfer.rst:842 +#: f2c90ee949d7484480cbb2cd5310bf26 msgid "Sends multiple folders from client to server." msgstr "Отправляет несколько папок с клиента на сервер." -#: ../../source/File_Transfer/File_Transfer.rst:759 -#: 5a88c3508e074cff9ae445d00193f212 +#: ../../source/File_Transfer/File_Transfer.rst:849 +#: 0b13d26a40174243a15698b4bfcbb69f msgid "" "Receives a file from the server (called when the server initiates a " "transfer)." msgstr "Получает файл с сервера (вызывается, когда сервер инициирует передачу)." -#: ../../source/File_Transfer/File_Transfer.rst:771 -#: 42db9f7f09c044c8a58243854644adfb +#: ../../source/File_Transfer/File_Transfer.rst:861 +#: 3b78a4355d7f4ee2bbbe6bf934a962c0 msgid "Receives a folder from the server." msgstr "Получает папку с сервера." -#: ../../source/File_Transfer/File_Transfer.rst:779 -#: 0a051d591bb54e529c771345409ec7df +#: ../../source/File_Transfer/File_Transfer.rst:869 +#: 3d044e0754b94d1289b491502ce83610 msgid "Low-level receive function on the client side." msgstr "Низкоуровневая функция приема на стороне клиента." -#: ../../source/File_Transfer/File_Transfer.rst:786 -#: e0149bdd716249289f6ba260e3c3f053 +#: ../../source/File_Transfer/File_Transfer.rst:877 +#: 7311023a7fa644ed9b57a2873cd3bca8 msgid "" "Low‑level send function on the client side (identical to server's " "version)." @@ -1463,13 +1626,13 @@ msgstr "" "Функция отправки низкого уровня на стороне клиента (идентична серверной " "версии)." -#: ../../source/File_Transfer/File_Transfer.rst:791 -#: e612d36affc0456b9314f39816bf62f3 +#: ../../source/File_Transfer/File_Transfer.rst:882 +#: 7e74e9a09a8a4cf2a8a372a50b1ee51b msgid "Public API Summary" msgstr "Сводка общедоступного API" -#: ../../source/File_Transfer/File_Transfer.rst:793 -#: 8347c97393fe47ea83c13f6777faa36c +#: ../../source/File_Transfer/File_Transfer.rst:884 +#: 87aaf0a5d3b44f41a419d97b6567f6d0 msgid "" "All public APIs (including non-file-transfer methods) are listed below " "for reference." @@ -1477,46 +1640,63 @@ msgstr "" "Все общедоступные API (включая методы, не связанные с передачей файлов) " "перечислены ниже для справки." -#: ../../source/File_Transfer/File_Transfer.rst:797 -#: 5ac025a5e948425a9a430c7c75b045f9 +#: ../../source/File_Transfer/File_Transfer.rst:888 +#: a195ee393f2a442c810e59811a6ae126 msgid "### TCP_Server_Base Public APIs" msgstr "### Общедоступные API TCP_Server_Base" -#: ../../source/File_Transfer/File_Transfer.rst:799 -#: ddf4d1d8e04e40659404ebb55c843c41 +#: ../../source/File_Transfer/File_Transfer.rst:890 +#: 0408d74a9140472e9a774143a60e5749 msgid "``file_transfer_server_recv_client_start``" msgstr "``file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:800 -#: 052d49abc8514ed19346f7b023783fa9 +#: ../../source/File_Transfer/File_Transfer.rst:891 +#: 24a33cb212844e04a8a271ada32412f0 msgid "``file_transfer_server_recv_client_start_thread``" msgstr "``file_transfer_server_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:801 -#: 6db2d78cc0b94b4b93d6080164897079 +#: ../../source/File_Transfer/File_Transfer.rst:892 +#: 7e286d1ece6940868bea6b937486e617 msgid "``folder_file_transfer_server_recv_client_start``" msgstr "``folder_file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:802 -#: ec1b13e6e07449ec820d5cdc7a983048 +#: ../../source/File_Transfer/File_Transfer.rst:893 +#: 37fc5bd346c84415bb15138a42508fbe msgid "``multiple_file_multiple_client_transfer_server_recv_client_start``" msgstr "``multiple_file_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:803 -#: 7d780de964e543a8b703dd413d331c43 +#: ../../source/File_Transfer/File_Transfer.rst:894 +#: 38a2b16e3ab648688cf7e8d1cae8be72 msgid "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:804 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:895 +#: ad39bc6b71f048b09bca3b895e9d32f8 #, fuzzy msgid "" "``file_folder_transfer_server_recv_server_start_thread`` (folder " "receiving)" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:806 -#: 02e685a79bc64a32ad888008a9dde074 +#: ../../source/File_Transfer/File_Transfer.rst:896 +#: ../../source/File_Transfer/File_Transfer.rst:916 +#: 37aeb9835435434881f94eb9951370d6 660ac3b979cc43d0beece659b9b0935f +msgid "``pause_trans`` / ``start_trans`` (hold and release an outbound transfer)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:897 +#: 7641e3ece9314197863d872836635218 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:898 +#: ../../source/File_Transfer/File_Transfer.rst:918 +#: 9c62709c2c06456dbfddee1f1ce6871e de496a0be32c490585ae0cbafc931a71 +msgid "``resume_transfers`` / ``resume_trans`` (continue interrupted transfers)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:900 +#: 11476e0eaa3b4a4286612812e4e2c004 msgid "" "(The low-level helpers ``file_transfer_server_recv_server_start``, " "``file_transfer_mode_recv``, and ``file_transfer_mode`` are not " @@ -1526,65 +1706,70 @@ msgstr "" "``file_transfer_mode_recv`` и ``file_transfer_mode`` не считаются " "общедоступными, но для полноты документированы.)" -#: ../../source/File_Transfer/File_Transfer.rst:812 -#: 5193d200c3f245caae4095ab4114a467 +#: ../../source/File_Transfer/File_Transfer.rst:906 +#: 907e861cebe648fbacb799bae8bb15e0 msgid "### TCP_Client_Base Public APIs" msgstr "### Публичные API TCP_Client_Base" -#: ../../source/File_Transfer/File_Transfer.rst:814 -#: df25f04d660046669347072182ca0bde +#: ../../source/File_Transfer/File_Transfer.rst:908 +#: 88bd80083f754caeb026f9ce1b8c6b55 msgid "``file_transfer_client_recv_client_start``" msgstr "``file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:815 -#: 2a43c7e5134b4a64af241547e798bdf3 +#: ../../source/File_Transfer/File_Transfer.rst:909 +#: 3b21ff73da694465906482412b4fb4e3 msgid "``file_transfer_client_recv_client_start_thread``" msgstr "``file_transfer_client_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:816 -#: 6a88ac28f634410ab54d999291b5b309 +#: ../../source/File_Transfer/File_Transfer.rst:910 +#: c8af43896a2443a5b14bd29863731c2c msgid "``folder_file_transfer_client_recv_client_start``" msgstr "``folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:817 -#: 6d47f6da5f54475989d93fca0c141f2d +#: ../../source/File_Transfer/File_Transfer.rst:911 +#: 7a3d3e4a52334b169a62d3b30d7a3190 msgid "``multiple_file_transfer_client_recv_client_start``" msgstr "``multiple_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:818 -#: 06e20b477a9744de9f2d2efcf0fbf57f +#: ../../source/File_Transfer/File_Transfer.rst:912 +#: 19e18754c4674842ad5116f709588e03 msgid "``multiple_folder_file_transfer_client_recv_client_start``" msgstr "``multiple_folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:819 -#: a8dd89a54e0f498b88185761dc4c0f46 +#: ../../source/File_Transfer/File_Transfer.rst:913 +#: 4cf80f9f34e045c59a680d0450c9103a msgid "``file_transfer_client_recv_server_start``" msgstr "``file_transfer_client_recv_server_start``" -#: ../../source/File_Transfer/File_Transfer.rst:820 -#: 0811953096e94bd887990bb58d2de56a +#: ../../source/File_Transfer/File_Transfer.rst:914 +#: c09f5fcba03f461f89238dd31abf6e88 msgid "``file_transfer_client_recv_server_start_thread``" msgstr "``file_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:821 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:915 +#: ad39bc6b71f048b09bca3b895e9d32f8 msgid "``file_folder_transfer_client_recv_server_start_thread``" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:823 -#: bbbea73553dd4dfd98e0ee4076c1d42b +#: ../../source/File_Transfer/File_Transfer.rst:917 +#: 4b82ae9a067f46d5bb297431468a67a4 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:920 +#: 99140d0be72649199911a57a26e2f2cf msgid "(The low-level helpers are documented but not part of the public API.)" msgstr "" "(Помощники низкого уровня документированы, но не являются частью " "общедоступного API.)" -#: ../../source/File_Transfer/File_Transfer.rst:827 -#: 56f1214838224007ade30eb34009810c +#: ../../source/File_Transfer/File_Transfer.rst:924 +#: 60355543ac904504af8529431ce2c1fa msgid "See Also" msgstr "См. также" -#: ../../source/File_Transfer/File_Transfer.rst:829 -#: d513a2ce6fdf40eca5746ea840b4314f +#: ../../source/File_Transfer/File_Transfer.rst:926 +#: 7a5902ad3de64bf79d54d7f2f83ecbfb msgid "" "For more information about the TCP server and client base classes, please" " refer to:" @@ -1592,18 +1777,18 @@ msgstr "" "Дополнительные сведения о базовых классах TCP-сервера и клиента см. по " "адресу:" -#: ../../source/File_Transfer/File_Transfer.rst:833 -#: 66b9f83c47d848779de9019a6f33c9a4 +#: ../../source/File_Transfer/File_Transfer.rst:930 +#: f10c29f467b849e8b4254998b44f99ba msgid ":doc:`../Network_APIs/TCP_Server_APIs`" msgstr ":doc:`../Network_APIs/TCP_Server_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:834 -#: 5cfe4f734d2043c2afe489c53c4ce963 +#: ../../source/File_Transfer/File_Transfer.rst:931 +#: 335ba244d28342449db065c252d7e14c msgid ":doc:`../Network_APIs/TCP_Client_APIs`" msgstr ":doc:`../Network_APIs/TCP_Client_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:836 -#: 47b4292bf8754c389fccf965d9b417d8 +#: ../../source/File_Transfer/File_Transfer.rst:933 +#: 92d0227c356447a098cba072d5b43c98 msgid "" "For details on port allocation, see the Port Allocation API sections in " "those documents." @@ -1710,3 +1895,12 @@ msgstr "" #~ "``/diff_multiple_file_diff_multiple_client a.txt b.txt " #~ "(ip1,port1) (ip2,port2) c.txt (ip3,port3)``" +#~ msgid "" +#~ "Low-level send function that connects" +#~ " to the receiver and transmits the" +#~ " file." +#~ msgstr "" +#~ "Функция отправки низкого уровня, которая " +#~ "подключается к получателю и передает " +#~ "файл." + diff --git a/docs/source/locale/ru/LC_MESSAGES/Instance_Setup/Instance_Setup.po b/docs/source/locale/ru/LC_MESSAGES/Instance_Setup/Instance_Setup.po index ada4088..e812440 100644 --- a/docs/source/locale/ru/LC_MESSAGES/Instance_Setup/Instance_Setup.po +++ b/docs/source/locale/ru/LC_MESSAGES/Instance_Setup/Instance_Setup.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,12 +18,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Instance_Setup/Instance_Setup.rst:3 -#: b4877074f48944ef95449bad6b451f04 +#: 552b0fbec3774a638b0029ce5fd72949 msgid "Flow Setup Launcher" msgstr "Панель запуска настройки потока" #: ../../source/Instance_Setup/Instance_Setup.rst:5 -#: 745aff08935b4042b2885b7f10d524f1 +#: 31952c3324264ea28368c7725796ff63 #, fuzzy msgid "" "The ``flow_setup.py`` script is a launcher for the TCP server/client " @@ -40,12 +40,12 @@ msgstr "" "фоновом процессе в автономных системах)." #: ../../source/Instance_Setup/Instance_Setup.rst:13 -#: 5cfe71ed904f4f24bef1210b411ee40d +#: c8f9652279de42bb983523a15048596e msgid "Features" msgstr "Функции" #: ../../source/Instance_Setup/Instance_Setup.rst:15 -#: d5544e89cd884c938e1bfed52fdaf35a +#: 2bd321903dd94d9985805a44d9ef3d94 #, fuzzy msgid "" "**Interactive mode** – step-by-step creation of server and client " @@ -56,7 +56,7 @@ msgstr "" "клиента." #: ../../source/Instance_Setup/Instance_Setup.rst:18 -#: a3239003782944f1aceb438c4b164657 +#: df9cbf9e1d024f9386a4b6278c82249e #, fuzzy msgid "" "**Command-line mode** – launch one server or one client with all " @@ -64,14 +64,14 @@ msgid "" msgstr "**Режим командной строки** — запуск со всеми параметрами одной командой." #: ../../source/Instance_Setup/Instance_Setup.rst:20 -#: 6c36fb284a4b4984bd220e047e26ed37 +#: b3406e8f62894233be438b7988e444da msgid "" "**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser" " UI of the ``transfer_web`` web tool." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:22 -#: 1a357d61f62b41dd91e150d24c323a98 +#: e359866c167e4e7ca5bf0791fd471ac4 msgid "" "**Extension registration** – ``--add`` / ``--delete`` register or " "unregister extension protocol files; the registered files are loaded on " @@ -79,7 +79,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:25 -#: 0deeeb0bc12644eaab437361d69dbe77 +#: 5f7cba6df26144e9840d140f94065b33 #, fuzzy msgid "" "**Persistent configuration** – stores the latest instance definitions in " @@ -92,7 +92,7 @@ msgstr "" "перезаписывается при каждом обновлении." #: ../../source/Instance_Setup/Instance_Setup.rst:29 -#: 0b60fca4ab384444a03750dcb790150f +#: b93809688cb74986ac64e4baceb9f0f6 msgid "" "**Multiple instances** – the ``servers`` and ``clients`` lists may hold " "any number of entries. Adding an entry identical to an existing one of " @@ -100,7 +100,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:33 -#: af8b8bdd4c994728a0bf4a7b358976b7 +#: be9bc008af594306be21e731d6aefee3 #, fuzzy msgid "" "**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, " @@ -111,7 +111,7 @@ msgstr "" "terminal, xterm или фоновый режим) и macOS (Terminal.app)." #: ../../source/Instance_Setup/Instance_Setup.rst:36 -#: 4696d04613af4a1ea055df8be236adc3 +#: 57005cb0d04f47b2a8f10ad0bc9c7b43 #, fuzzy msgid "" "**Complete parameter support** – all parameters accepted by " @@ -123,22 +123,22 @@ msgstr "" "``setup.json`` для точной настройки." #: ../../source/Instance_Setup/Instance_Setup.rst:41 -#: 343fcd49c74b4cfd9d351f93c60e59bc +#: 2ff27919a6f64e8fb610158de5ffdf69 msgid "Usage" msgstr "Использование" #: ../../source/Instance_Setup/Instance_Setup.rst:44 -#: 7e39ebc551894366b757ddfb5c406753 +#: dddde4f2d7084bc48efa1296cfd3f22c msgid "Interactive Mode" msgstr "Интерактивный режим" #: ../../source/Instance_Setup/Instance_Setup.rst:46 -#: 5f7b3715a9524fa2a0aed70bbefc5008 +#: f060e64959674f52b223bbc4b01d568c msgid "Run the script without any arguments:" msgstr "Запустите скрипт без аргументов:" #: ../../source/Instance_Setup/Instance_Setup.rst:52 -#: a17a608e2ac24987b6c4a428acd770e9 +#: 6bb60d44328244d4ab20f3ae5ba2b827 msgid "" "When ``setup.json`` already exists, the launcher first asks whether to " "overwrite it, and the interactive collection itself asks whether the " @@ -146,7 +146,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:56 -#: 7fe4792645644307bf450194c2d98fa7 +#: d247a8d3c3f1430c8dfa6dccad66da0a msgid "" "``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` " "launches every stored instance and exits; ``Y`` (or no existing file) " @@ -154,7 +154,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:59 -#: e60cbc55c5834e8ab8ce55e696159e9a +#: 96169445a67545178cdd4b68ce5faae3 msgid "" "``Delete or change existing instances or configs? (Y/N):`` – asked only " "when stored instances exist. ``Y`` opens the instance editor (see below);" @@ -162,23 +162,23 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:63 -#: eaf7134992f44c58aa4181664a3bc638 +#: 80847dcc3e404a779b2e693cf8de50d5 #, fuzzy msgid "``Choose the type (0 for Server, 1 for Client)``." msgstr "Выберите тип (0 для сервера, 1 для клиента)." #: ../../source/Instance_Setup/Instance_Setup.rst:64 -#: 6a5569dd541a4043802c5d85f125db64 +#: cebc8ba62d1a48a69d8019c3862dc18b msgid "Enter the bind address and port (``host:port``)." msgstr "Введите адрес привязки и порт («хост:порт»)." #: ../../source/Instance_Setup/Instance_Setup.rst:65 -#: e70e2b6322a04c748193e1cec4b0ee2c +#: 4311b66e1b974b4596f2693908ba3109 msgid "If Client, also enter the server address and port to connect to." msgstr "Если Клиент, также введите адрес сервера и порт для подключения." #: ../../source/Instance_Setup/Instance_Setup.rst:67 -#: df73da29736d4b878bef8427a95945aa +#: 3a5cff8b854c40939873ad57b060d9c3 msgid "" "Decide whether to add another instance. An entry that already exists in " "the list is not added again; a new one is appended, so several instances " @@ -186,14 +186,14 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:71 -#: 8e0df08f751f46deb43ba1006ed04b20 +#: 7c893e0f8399455ba1b14d9c796d75a8 msgid "" "After editing, the launcher asks ``Add new instances? (Y/N)`` before " "returning to the add flow." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:74 -#: 237874cb10d040cf86074695574daf32 +#: 49c58d9bb0b1440485f3cbecdb2843d6 msgid "" "When the editor is left with changes, ``setup.json`` is rewritten with " "every instance, and all stored instances (reused plus newly added) are " @@ -201,97 +201,97 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:79 -#: c81a1dba5f224291a56257375f84a1a0 +#: a1e74fd1f7f04e548b268c3dc0d6763e msgid "Global commands" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:81 -#: 8247157dfc0b4a32aa9ae300813386c6 +#: b8ede51e5254499e9dd613bc93db15ca msgid "" "The following words can be typed at **every** prompt, including field-" "value prompts:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: c29ffb659bf3446490bc9eaac6f2e7ea +#: c2b850e77d9b44559be9b25d93611a70 msgid "Effect" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``Help``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 886877e3eb7d407fa62b16a4fc968f62 +#: 200a2a3be7ea46b291882aef0b8d9031 msgid "Print the usage text of the current prompt." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: c569666357334b05ba4189c122bbeaaf +#: a6ce48cd04e04b3ea42ad16e04e37359 msgid "``Fix_Config``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: 0a5c8bdb9c1d4f7eb8a41fce85acf0b4 +#: fcd62172378d4da498de2a21a03f97a0 msgid "Jump to the instance editor (or, inside it, save and return to the list)." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 #, fuzzy msgid "``Setup``" msgstr "``--setup_num``" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "" "Launch every instance configured in ``setup.json`` and exit the setup " "program." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: cc2a8285cba3495db468d5f007f3ecfc +#: 85343de947b74e3b97e4c59109ebcd9e msgid "``Add_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: a6c3fac6c8f44d75a7a266bae3c54729 +#: 6b8af44d732b4673afbc2f9cbec357d3 msgid "Prompt for extension file path(s) and register them." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 4febe01e668f4cc1aa1b92e328780ebe +#: a35baf4ca7d949eba92cf6c6279c9cd2 msgid "``Delete_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 5e54a7238b604a5fbe930ff4c5fd05d5 +#: d6f9495c1ad046d5877eb8159799ae88 msgid "Prompt for registered extension path(s) to remove." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 88bb1def13564b809d980ac0d7f22832 +#: 7c985bf621ba4fbeaa8f25042d47ed95 msgid "``Quit``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 22644327258c472aab543baf2ee08784 +#: 18f32c4c66094837a84906ba56ef236d msgid "Exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:103 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Instance editor" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:105 -#: 5832e770c51e4e61b0a372086616ad57 +#: 021cb4d2e2234dff8a9b206826926e33 msgid "" "The editor is reached by typing ``Fix_Config`` (at any prompt) or by " "answering ``Y`` to the \"Delete or change existing instances\" question. " @@ -304,37 +304,37 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:115 -#: 36e871e8b76b4e6f8ab3d41c6e58e053 +#: be9f3fe33bf943419ada71d457c635e1 msgid "Vim-style commands:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:117 -#: bf18c8047500461486e3bc05c6154ecc +#: f11526b8f13f4f6eabba91f7543c7120 msgid "``:w`` – write ``setup.json`` without leaving the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:118 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "``:wq`` – write ``setup.json`` and leave the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:119 -#: 8e54b99375e441308cd3dc8ec4cd5d3a +#: 740d1745df7841a59959dbdab98a73b4 msgid "``:q`` – leave; refused while there are unsaved changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:120 -#: 32cdc0d2f2f34602a77b692202f56b24 +#: 944a89864f5c46c488287ee0740d83d5 msgid "``:q!`` – leave and discard all changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:121 -#: 7360415b19b04c13ab167e500f3437ac +#: 927b5a52f9454d65af949f5cc188e33d msgid "``Quit`` – exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:123 -#: aea22c0686c64df8bc842a51fbd2d67e +#: d4163489911a454f9e4fd1b6cdd1de5a msgid "" "Inside the config editor, ``j``/``k`` move between fields, ``Esc`` or " "``back`` returns to the list, and a field index or ``Enter`` edits the " @@ -345,136 +345,136 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:132 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command‑line Mode" msgstr "Режим командной строки" #: ../../source/Instance_Setup/Instance_Setup.rst:134 -#: 19ffa2fc838a441786de354b2a574153 +#: d798ec606de2454da5f10e9d0a7e677c msgid "Use the following options:" msgstr "Используйте следующие параметры:" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: c6dc291839964e119fb50574caedfd9c +#: 4d5c1aebbede473c8598cbc45f8deb20 msgid "Option" msgstr "Вариант" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: 4a498223c2cb4e45914dcd53bb7f2f12 +#: a50ba126b168482997fae00497252fd4 msgid "Description" msgstr "Описание" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: 649f1c33bb9d4afa89d1796bef081ddf +#: 7755904907ee46f6a34144360ed876f7 #, python-brace-format msgid "``--type {0,1}``" msgstr "``--type {0,1}``" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: f0793c0f15584b42bc66b82e672854b5 +#: 0175b3fbf31e44829a685a07be420436 msgid "" "0 = Server, 1 = Client. Required for a plain command-line launch; without" " it the launcher runs interactively." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--setup_addr_port``" msgstr "``--setup_addr_port``" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 58e47d807455460fb6e76d76b836bc30 +#: b7962f6d3a194e3eb91915d5681a2b7b #, fuzzy msgid "Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." msgstr "Введите адрес привязки и порт («хост:порт»)." #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 31efc70f958b4608b07bc24eb1ec633b +#: 388a3dd952ac47a78598792ef7d587bc msgid "``--connect_addr_port``" msgstr "``--connect_ADDR_Port``" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 041b4144717b4f54ad1b24d06726293b +#: 7d96425a64374a36a457a9167fc6d39c msgid "" "Server address and port to connect to. Required for Client; rejected in " "Server mode." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``--setup_num``" msgstr "``--setup_num``" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 139258adce2844a28d57733bb973ec1e +#: 26698837fb26457ba9674e8ccf0cf881 msgid "" "Number of instances to launch. Only 1 is allowed; a larger value is " "accepted but ignored with a warning." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_server``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 108977e4c89b442488c39cad5378e8e5 +#: 9b1821de6d0f4c4d9af6c4e47eab4e5d msgid "" "Launch the ``transfer_web`` server tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_client``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 99410d7adbc749e2bee7ff014945d19b +#: 91fa396110c94aa9a29f0a569763e030 msgid "" "Launch the ``transfer_web`` client tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: 5de4064738ce4d529c9df9d1da98a556 +#: 118dce4ec3934bd4b5bb6e7b1aa31bf0 msgid "``--add PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: be6adb7451d84f9f934044d2891cc4db +#: 2a630e280d3040d6a78cd865dd3e2ae7 msgid "Register extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 58e2f444f8394dd5a5c41b400675c736 +#: c505cbcf44104e6799bfcb83251c2f72 msgid "``--delete PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 638774f6e42549ad88f930e50a2c3cad +#: 74b797d0ddf046d3b1dda4eea01013b7 msgid "Unregister extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:167 -#: e9b3cc31339a4f318337e8c68cc61fd5 +#: 54c5d51b3cb841ceaefda13a7613a8ae msgid "" "A command-line launch replaces ``setup.json`` with the single launching " "instance, so any other stored instance is dropped." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:171 -#: 327a63e83b8f4df9af4a5e6a32e2ce6e +#: 99952fa68b694654b82a309a26419152 msgid "Examples" msgstr "Примеры" #: ../../source/Instance_Setup/Instance_Setup.rst:173 -#: c03b73272d554d1a885a04e6470d43c9 +#: 9c77e76f40a940e99e754d27e3bc1b05 msgid "**Launch a single server** on ``127.0.0.1:8000``:" msgstr "**Запустите один сервер** на ``127.0.0.1:8000``:" #: ../../source/Instance_Setup/Instance_Setup.rst:179 -#: 69edc9f7ea534c00bdaab2a4c84ef2cf +#: 37df8730dce9408a87ba48b775eb2b0a msgid "" "**Launch a client** bound to port ``9000``, connecting to a server at " "``127.0.0.1:8000``:" @@ -483,29 +483,29 @@ msgstr "" "серверу по адресу ``127.0.0.1:8000``:" #: ../../source/Instance_Setup/Instance_Setup.rst:186 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "**Launch from an existing configuration** (if ``setup.json`` is present):" msgstr "" "**Запуск из существующей конфигурации** (если присутствует " "``setup.json``):" #: ../../source/Instance_Setup/Instance_Setup.rst:193 -#: f2fd3c19413a4e6abb4b18037a347443 +#: 0538ca5ad181412c9136f318be43dfa0 msgid "**Launch the web tool** instead of a TCP instance:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:200 -#: 71feceacd5b94bd98ce1973f45c16df1 +#: 4a43a3b821764068aaa05c153037208f msgid "**Register an extension protocol file**:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:207 -#: 00dff5a17f42419585f498c51f7fcc97 +#: ff45af42eb7d4d3faa8640a18bfd61f6 msgid "Configuration File" msgstr "Файл конфигурации" #: ../../source/Instance_Setup/Instance_Setup.rst:209 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "" "The script writes a file named ``setup.json`` in the same directory. Its " "structure is:" @@ -514,7 +514,7 @@ msgstr "" "структура:" #: ../../source/Instance_Setup/Instance_Setup.rst:233 -#: 82c31bcb59fc481eaa532d1a0696ed8d +#: b0129978b1a9468188663a40126df876 msgid "" "**Both lists may contain any number of objects.** Every entry is " "completed with the default value of each parameter that the entry does " @@ -523,21 +523,23 @@ msgid "" "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " "``is_input_command_in_console``, ``max_custom_workers``, " "``is_extend_command``, ``is_enable_encrypto``, ``is_custom_keys``, " -"``max_mem_buff``, ``is_asynic_clients_io``, ``is_debug`` and " +"``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_asynic_clients_io``, ``is_debug`` and " "``is_print_log``; the client entry carries ``host``, ``client_host``, " "``port``, ``client_port``, ``timeout``, ``port_add_step``, " "``max_thread_num``, ``is_input_command_in_console``, ``is_wait_server``, " "``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_debug`` and ``is_print_log``." +"``is_custom_keys``, ``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_debug`` and ``is_print_log``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:251 -#: 8ffd3b4e6719464cbd48a2b20d5764f2 +#: ../../source/Instance_Setup/Instance_Setup.rst:252 +#: 8731a083a201487bb579beb4a238a0db msgid "Custom Parameters" msgstr "Пользовательские параметры" -#: ../../source/Instance_Setup/Instance_Setup.rst:253 -#: 284b4f1899d94269a530dec33958d0c8 +#: ../../source/Instance_Setup/Instance_Setup.rst:254 +#: 8910f94645f54874893c20f724780cbd msgid "" "You may edit ``setup.json`` by hand (or change the same fields in the " "instance editor) to give any parameter accepted by ``TCP_Server_Base`` or" @@ -549,13 +551,13 @@ msgid "" "``setup.json`` from that, so hand-written extra keys are lost." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:264 -#: 3746b90215c84dc38c8ca2bb20d396f6 +#: ../../source/Instance_Setup/Instance_Setup.rst:265 +#: c62b1bfe8ceb40f8865a34ac87b4ba18 msgid "Extension Protocols and Startup Mode" msgstr "Протоколы расширения и режим запуска" -#: ../../source/Instance_Setup/Instance_Setup.rst:266 -#: 4c6e6cc80e9c4ce3afe79fad55a2815a +#: ../../source/Instance_Setup/Instance_Setup.rst:267 +#: e6a7dcb4ea184e828e6667ae6505d872 msgid "" "Two extension protocols ship with the launcher and are loaded " "automatically for every instance whose ``setup.json`` entry sets " @@ -565,8 +567,8 @@ msgstr "" "загружаются автоматически для каждого экземпляра, запись в ``setup.json``" " которого устанавливает ``is_extend_command=True``:" -#: ../../source/Instance_Setup/Instance_Setup.rst:270 -#: 2d05270538524347899b403011286dcc +#: ../../source/Instance_Setup/Instance_Setup.rst:271 +#: 7159f768fc9a4ac199bfe0a4d8478fba #, fuzzy msgid "" "``command_control_extension_tcp.py`` – remote command execution with per-" @@ -574,8 +576,8 @@ msgid "" "completion report)." msgstr "``command_control_extension_tcp.py`` – удаленная команда" -#: ../../source/Instance_Setup/Instance_Setup.rst:273 -#: 1540ce3848be4d519034dd90e1d27fdd +#: ../../source/Instance_Setup/Instance_Setup.rst:274 +#: d2d277053c74470abc949b891493a5f0 #, fuzzy msgid "" "``forward_extension_tcp.py`` – forwarding messages, files, multiple " @@ -590,8 +592,8 @@ msgstr "" "(``/send_msg_forward``, ``/file_forward``, ``/multiple_file_forward``, " "``/folder_forward``, ``/multiple_folder_forward``)." -#: ../../source/Instance_Setup/Instance_Setup.rst:281 -#: 92e914da56f1402e85ef75819caf5b3f +#: ../../source/Instance_Setup/Instance_Setup.rst:282 +#: a8194174e5fd4dcf87ede716eaada9a4 msgid "" "Plain-message forwarding is native to the TCP protocol (no extension " "needed): the client-only command ``/forward_send_msg`` relays messages to" @@ -602,8 +604,8 @@ msgstr "" "``/forward_send_msg`` ретранслирует сообщения перечисленным целевым " "клиентам через сервер." -#: ../../source/Instance_Setup/Instance_Setup.rst:286 -#: 836d703843ed4940a42f3b7a0c36b78e +#: ../../source/Instance_Setup/Instance_Setup.rst:287 +#: 98297b76f3404736b92b6c507726a50a #, fuzzy msgid "" "With ``is_extend_command=False`` (the default) the raw TCP protocol is " @@ -612,8 +614,8 @@ msgstr "" "При значении is_extend_command=False (по умолчанию) запускается только " "необработанный протокол TCP." -#: ../../source/Instance_Setup/Instance_Setup.rst:289 -#: 3849c157ba79441e8406bcf9a4fc7695 +#: ../../source/Instance_Setup/Instance_Setup.rst:290 +#: fbbe2f02d9174359baca2c685704b475 msgid "" "Independently of ``is_extend_command``, every launch also loads the " "extension protocol files registered in ``PyFlow/added_extensions.json`` " @@ -621,15 +623,15 @@ msgid "" "``add_extension.load_registered_extensions``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:295 -#: fef96f9c96c64f6690b54175c7e7830d +#: ../../source/Instance_Setup/Instance_Setup.rst:296 +#: 9b5ab0319a9843f1b39721d3a96d1777 msgid "" "The ``is_input_command_in_console`` flag selects how the instance is " "started:" msgstr "Флаг ``is_input_command_in_console`` выбирает способ запуска экземпляра:" -#: ../../source/Instance_Setup/Instance_Setup.rst:298 -#: 407ae406135b42b3a6efd4ba5242b296 +#: ../../source/Instance_Setup/Instance_Setup.rst:299 +#: 1ec730c995b1454da1b208331d9ca8fe #, fuzzy msgid "" "``True`` (default) – the instance's own start method " @@ -640,8 +642,8 @@ msgstr "" "вызывается напрямую, и входной цикл консоли запускается в своем " "собственном потоке." -#: ../../source/Instance_Setup/Instance_Setup.rst:301 -#: 1e10d27ee5c04d69ac9de20031a68b31 +#: ../../source/Instance_Setup/Instance_Setup.rst:302 +#: 3cfb2eba312943cea85388f4e9faf40d #, fuzzy msgid "" "``False`` – the instance is started in a background thread and the " @@ -653,8 +655,8 @@ msgstr "" "в фоновом потоке, и средство запуска поддерживает процесс до тех пор, " "пока экземпляр не остановится (полезно для автономного развертывания)." -#: ../../source/Instance_Setup/Instance_Setup.rst:305 -#: 3743e0549b4449008324f68e282a0d81 +#: ../../source/Instance_Setup/Instance_Setup.rst:306 +#: 3b3482fa903f4afd81234e588a229c1f #, fuzzy msgid "" "Both extensions also expose injectable registration " @@ -672,48 +674,48 @@ msgstr "" "который принимает существующий экземпляр, поэтому несколько расширений " "можно загрузить в один и тот же экземпляр из кода." -#: ../../source/Instance_Setup/Instance_Setup.rst:314 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: ../../source/Instance_Setup/Instance_Setup.rst:315 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Internal Operation" msgstr "Внутренняя операция" -#: ../../source/Instance_Setup/Instance_Setup.rst:316 -#: 4ca266ef495b4a61bce44251b65f8c91 +#: ../../source/Instance_Setup/Instance_Setup.rst:317 +#: 8870bc6b731d40a095a40faed0c8f16d #, fuzzy msgid "" "Each instance is launched in a new terminal window (or background " "process)." msgstr "Каждый экземпляр запускается в новом окне терминала." -#: ../../source/Instance_Setup/Instance_Setup.rst:318 -#: 2b6246012ce84ec0945a9245b208ae95 +#: ../../source/Instance_Setup/Instance_Setup.rst:319 +#: 13c720a93ba54e8ca330fce3a078bb5b #, fuzzy msgid "" "The configuration is passed via a temporary JSON file to avoid shell " "escaping issues." msgstr "Конфигурация передается через временный JSON." -#: ../../source/Instance_Setup/Instance_Setup.rst:320 -#: e40392b9adef407ca3ade4bf2d252190 +#: ../../source/Instance_Setup/Instance_Setup.rst:321 +#: 9566eb3cb70e4b77bcbdb584f7e0b6fc #, fuzzy msgid "" "If an instance fails to start, the error is displayed and the window " "pauses for inspection." msgstr "отображается, и окно приостанавливается для проверки." -#: ../../source/Instance_Setup/Instance_Setup.rst:324 -#: 2d7f7f35978a449995958b44730759d3 +#: ../../source/Instance_Setup/Instance_Setup.rst:325 +#: 5f0f0f6a41384356986a1182f14a0a4c msgid "Requirements" msgstr "Требования" -#: ../../source/Instance_Setup/Instance_Setup.rst:326 -#: ddf48eb8fc2d48f9adbc38a39965ec22 +#: ../../source/Instance_Setup/Instance_Setup.rst:327 +#: 49ceb74e41104b00971cd9edecef08ae #, fuzzy msgid "Python 3.10+" msgstr "Питон 3.6+" -#: ../../source/Instance_Setup/Instance_Setup.rst:327 -#: 9bc8a330f1384ade97e4ee55efa58e6b +#: ../../source/Instance_Setup/Instance_Setup.rst:328 +#: 1d80811611c944f9bf772364ab45d1e4 msgid "" "The ``PyFlow.network_api.connect_tcp`` module must be importable (the " "script imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." @@ -854,3 +856,26 @@ msgstr "" #~ msgid "and ``TCP_Client_Base`` from there)." #~ msgstr "и ``TCP_Client_Base`` оттуда)." +#~ msgid "" +#~ "**Both lists may contain any number " +#~ "of objects.** Every entry is completed" +#~ " with the default value of each " +#~ "parameter that the entry does not " +#~ "set. The stored server entry therefore" +#~ " carries ``host``, ``port``, ``max_clients``, " +#~ "``port_add_step``, ``port_range_num``, " +#~ "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " +#~ "``is_input_command_in_console``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, " +#~ "``is_asynic_clients_io``, ``is_debug`` and " +#~ "``is_print_log``; the client entry carries " +#~ "``host``, ``client_host``, ``port``, " +#~ "``client_port``, ``timeout``, ``port_add_step``, " +#~ "``max_thread_num``, ``is_input_command_in_console``, " +#~ "``is_wait_server``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, ``is_debug`` " +#~ "and ``is_print_log``." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po b/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po index 9f02acc..bad9800 100644 --- a/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po +++ b/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -21,17 +21,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Client_APIs.rst:2 -#: 6dd11dd380344faabc9dea6d41655b1c +#: 596423c8d92e4592b221947ca5595ea7 msgid "The TCP Client APIs" msgstr "API-интерфейсы TCP-клиента" #: ../../source/Network_APIs/TCP_Client_APIs.rst:5 -#: 2d8b31ea476c498188b1d3df403c2402 +#: bf347a93657146d6b019250273bc439c msgid "TCP Client setup API" msgstr "API настройки TCP-клиента" #: ../../source/Network_APIs/TCP_Client_APIs.rst:7 -#: d699c50b2310495bb2521c5da6d30543 +#: 7e3dc9343f554fc181d2c2853898916c msgid "" "The TCP Client Setup API is used to create a TCP client. The client in " "the protocol is usually used to connect to the TCP server and exchange " @@ -41,8 +41,8 @@ msgstr "" " протоколе обычно используется для подключения к TCP-серверу и обмена " "данными с сервером." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:34 -#: 5505d653e132458686537e957323bb9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 +#: fb61c59ca5e646f3b749359b2ea13a40 msgid "" "The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The" " parameters of the ``__init__`` method are as follows:" @@ -50,25 +50,25 @@ msgstr "" "API настройки TCP-клиента определен в классе TCP_Client_Base. Параметры " "метода ``__init__`` следующие:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:37 -#: 6a41dd3d0f00421b914a6ae9e588d6b8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 +#: d8b55d105dd144198594dd4f454fe5c5 msgid "``host``: The server host IP address to connect to." msgstr "``host``: IP-адрес хоста сервера для подключения." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 -#: cc6ddd6c80bb46f3b393c9882e096a0a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 +#: ee9f5f584e6643529cdca91384562ebf msgid "``client_host``: The local host IP address to bind the client socket to." msgstr "" "``client_host``: IP-адрес локального хоста, к которому будет привязан " "клиентский сокет." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:39 -#: 949c21452bb94effa6c13959868ac90f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 +#: 03357b8c2f974a419c6933d68976b6eb msgid "``port``: The server port number to connect to." msgstr "``port``: номер порта сервера для подключения." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:40 -#: 97c56df67b0c435aaf8ee89bea56266b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 +#: cd50ed1b09934f3bae2a4c615187d157 msgid "" "``client_port``: The local port number to bind the client socket to " "(``None`` means let the OS choose)." @@ -76,8 +76,8 @@ msgstr "" "``client_port``: номер локального порта, к которому будет привязан " "клиентский сокет («Нет» означает, что ОС может выбирать)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 -#: 309676fc53ff4cd39a8d9e200c54f1bf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 +#: f8cdf36b87834ea7a95209d2ca048332 msgid "" "``timeout``: The socket timeout in seconds for connection and receive " "operations. ``None`` (the default) is not \"no timeout\": the socket then" @@ -85,8 +85,8 @@ msgid "" " receive loop (it simply continues)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 -#: 9bf924fa535a44e78c98664e8d2b304f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 +#: 20c7ea1afac14f80a2b739cb6ae1957f msgid "" "``port_add_step``: The step size for incrementing the port number (used " "only in manual allocation mode)." @@ -94,8 +94,8 @@ msgstr "" "``port_add_step``: Размер шага для увеличения номера порта (используется " "только в режиме ручного выделения)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 -#: 5abb7f5137714757b6957a177747d1e5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 +#: eb06f09e560543e5ba0abb3627a63585 msgid "" "``max_thread_num``: The maximum number of threads for concurrent file " "transfer operations." @@ -103,8 +103,8 @@ msgstr "" "``max_thread_num``: максимальное количество потоков для одновременных " "операций передачи файлов." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 -#: e71bd35480184667a6390f2a28c0894a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:48 +#: 5ff72dc0ec90411bb0d20f618d015093 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console (interactive mode)." @@ -112,8 +112,8 @@ msgstr "" "``is_input_command_in_console``: Флаг, указывающий, следует ли вводить " "команды в консоли (интерактивный режим)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 -#: f4dd649db47842fdb7b64e39d5887cdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:49 +#: 5e12aa05eb854b15b0b6779b40b5a302 msgid "" "``is_wait_server``: A flag indicating whether to keep retrying connection" " until the server is available." @@ -121,15 +121,15 @@ msgstr "" "``is_wait_server``: Флаг, указывающий, следует ли продолжать повторную " "попытку подключения, пока сервер не станет доступен." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 -#: 69c7bfb0cc784e9a817d98096357d9d6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:50 +#: b3232047b364478caad5b3e5361e71be msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "" "``max_custom_workers``: максимальное количество пользовательских рабочих " "потоков." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 -#: 892ac76eabb04f90b9c95f29009b6c11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 +#: a951c5564286432082b3e6a06aae8a48 msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the client itself by calling " @@ -137,8 +137,8 @@ msgid "" "register its commands first and connect later." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 -#: 0cfe21e428fd45f08a9d8c080c285535 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:55 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-" @@ -148,8 +148,8 @@ msgstr "" "которыми обмениваются с сервером, RSA (см. :ref:`tcp-client-encrypted-" "channel-api`)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:53 -#: 353688102eb6441ebf87384e57f0c661 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 +#: 8ac8a71ca8564a89bb52f882c4fedefc msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -162,86 +162,132 @@ msgstr "" "игнорируется и вместо нее используется поиск по ключу по умолчанию («Нет»" " сохраняет поиск по умолчанию)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 -#: 0176e8b8b8ea44c396d55657d74a91cd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:61 +#: c01569233a864bf0b106a877fb924c27 msgid "" "``max_mem_buff``: The buffering ceiling in MiB, stored as bytes " "(``self.max_mem_buff``). It is kept for parity with the server class; the" " client's forward path does not read it today. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:60 -#: 276f7755eaea4b808ad6cfe985eaa8aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:64 +#: 10fb41da1af34a539a962083252bdf55 +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 +#: 1b569fa80b59490dacc6bcdf3a924d60 +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 +#: ac73e6da7c3044f1bf68aff504142765 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the client logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:63 -#: 58a790ecb724454298659bf9831fb2ae +#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_print_log``: A flag indicating whether the client logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 -#: 36eebcb4edbb4f1e96862b64762c4d6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 +#: fa251d2893fa413aac9d5e525df18209 +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when the " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:85 +#: 3a9f1a8e8b8f45dbb9011b3b0e28cd92 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:93 +#: 3272388be97643f98bada0a995516141 msgid "Every parameter has default values:" msgstr "Каждый параметр имеет значения по умолчанию:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 -#: 4a2b0f17cb4f47669a8dcb3734c17468 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:95 +#: 9fd3d516d31841fd9054a2a3dfcb1ac4 msgid "``host``: Default is ``None`` (must be provided before connecting)" msgstr "``хост``: по умолчанию — ``Нет`` (необходимо указать перед подключением)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:69 -#: 7dea100856734d3ba4ee6352d45cc554 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:96 +#: ece6c7a48ae74f86b6e207d960c6daa2 msgid "``client_host``: Default is ``'127.0.0.1'``" msgstr "``client_host``: по умолчанию ``'127.0.0.1'``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:70 -#: e646757cb9d1425fa72970698c2938e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 +#: 8a9d85bb281e43e69ea0ae48363fb8da msgid "``port``: Default is ``65432``" msgstr "``port``: по умолчанию ``65432``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 -#: 4c232543227544acae211825b01a795a -msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" -msgstr "``client_port``: по умолчанию — ``Нет`` (ОС назначает временный порт)" +#: ../../source/Network_APIs/TCP_Client_APIs.rst:98 +#: 4653721a3e8143fea8a43899bb0e6437 +msgid "" +"``client_port``: Default is ``None`` (OS assigns ephemeral port). A " +"configured port that cannot be bound — a session that just ended can hold" +" it in the operating system's ``TIME_WAIT`` — is reported and the " +"connection is made from an OS-assigned port instead." +msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:72 -#: 3c772d5ab49243b993d5dfea9af5d472 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:102 +#: 4439e99a222744a9bca762b5f14b4d74 msgid "``timeout``: Default is ``None``" msgstr "``timeout``: по умолчанию — ``Нет``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:73 -#: 501a6c2966d2470cbf9ce2a8909ef130 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 +#: 0b0f6a9551ff4bf28ad02095893db9d8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: по умолчанию ``1``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 -#: 697656b4cb24453c89b1a848299e4167 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:104 +#: bcb1ee681a0f47319338faf71a99adf7 msgid "``max_thread_num``: Default is ``10``" msgstr "``max_thread_num``: по умолчанию ``10``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:75 -#: 632284d8c9b349f89018f8a19ce9662e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:105 +#: 08471d033b174cf395292c36068d4cb8 msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: по умолчанию установлено ``True``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:76 -#: ec7a8bd80ad2471d9208999fc34792f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:106 +#: bbf2ad3b5e4340c9b481f8af135281e2 msgid "``is_wait_server``: Default is ``True``" msgstr "``is_wait_server``: по умолчанию ``True``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:77 -#: c036a352181d422894b56b0c14167bdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:107 +#: 63f2004d0c5b4fef8cf23eaa7be020b1 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: по умолчанию ``10``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:78 -#: 64df1f8395ca45d497875fb232c71b0e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:108 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_client()`` automatically)" @@ -250,8 +296,8 @@ msgstr "" "``True``, ``__init__`` не будет вызывать ``start_TCP_client()`` " "автоматически)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:80 -#: ca18c257b4054fad931a19b59a8a4606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:110 +#: c723e855f50a4ec3abf45aaae2e02f45 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, the client " "performs an RSA public-key exchange with the server right after " @@ -261,8 +307,8 @@ msgstr "" "``True``, клиент выполняет обмен открытым ключом RSA с сервером сразу " "после подключения, и все последующие сообщения шифруются." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:83 -#: 0c6ecb6d7f504ef8a9a666bc2659a009 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:113 +#: 16c586bc40d94d6b9624812993e12579 msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -273,29 +319,64 @@ msgstr "" "предоставленная пользователем, вместо ``~/.ssh`` / сгенерированных ключей" " по умолчанию)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:86 -#: 96c8a6add16d4a999f8910133dad83b4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:116 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:88 -#: 4ea3ee5f013c46c98a380ed9fa7b6e64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:118 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "client would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:90 -#: a1d9d8ceda754443aef4e9dd2031e754 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:120 +#: 58fc5a7851094fcba7903d9e6cd4e8e7 msgid "" "``max_mem_buff``: Default is ``2048`` (kept for parity with the server " "class; the client's forward path does not read it today)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:94 -#: 930f7b1c90474a16b2dc7d13c41c238c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:123 +#: 08471d033b174cf395292c36068d4cb8 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_custom_workers``: по умолчанию ``10``." + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 +#: ff70e67852154092b227e2f05357a78d +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:125 +#: bd7d9bb9bbe14bc38eed56c574fc0987 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:127 +#: 5282067c345342d4872377ec83b3ba95 +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 +#: d10be044603c42e9a26b3164dcb7cb51 +msgid "" +"``is_auto_reconnect``: Default is ``False`` (``True`` makes " +"`start_TCP_client` reconnect after the connection drops and resume the " +"interrupted transfers, see :ref:`transfer-pause-and-reconnect`. The dead " +"session's socket is closed abortively first, so a configured " +"``client_port`` can be bound again — Windows refuses it otherwise)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:135 +#: 4b99048b2ec14a988fd9b83b23284d25 msgid "" "The TCP Client Setup API will initialize all the necessary parameters and" " resources for the TCP client." @@ -303,8 +384,8 @@ msgstr "" "API настройки TCP-клиента инициализирует все необходимые параметры и " "ресурсы для TCP-клиента." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 -#: 221e218700a34372ae96eae9189831aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 +#: b7da2a334a9543aa96178bddc8b6855c msgid "" "*Note: In the main class of the TCP client setup API, we initialize the " "`start_TCP_client` method to set up all functions which are needed in the" @@ -316,8 +397,8 @@ msgstr "" "необходимых в TCP-клиенте, включая подключение к серверу, обработку " "входящих сообщений и управление пользовательским вводом.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 -#: 00cb8ca5027d464f88e778a8f2a4faec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 +#: 0aa6b4133bf54878ad5d35aa8523ae88 msgid "" "*Note: By default ``TCP_Client_Base.__init__`` calls " "``start_TCP_client()`` to connect and enter interactive mode. If you set " @@ -330,8 +411,8 @@ msgstr "" "автоматически, и вам придется вызвать ``start_TCP_client()`` вручную, " "когда будете готовы.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:109 -#: 4d8f352fa0be45e1b75d44727035e828 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 +#: 7a35992f8c7c410da60029bb06fb054a msgid "" "*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must" " be ``None``. The constructor will raise a ``ValueError`` if " @@ -341,8 +422,8 @@ msgstr "" "``timeout`` должен быть ``None``. Конструктор вызовет ValueError, если " "is_wait_server имеет значение True, а timeout не равен None.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:119 -#: 92cea23fb57c482cb1199cabd89af968 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 +#: 35b6f81f408041c4a7e650d3b92957d1 msgid "" "In the `start_TCP_client` method, we first attempt to connect to the " "server by calling the `connect` method. If the connection fails and " @@ -354,8 +435,8 @@ msgstr "" "имеет значение ``True``, клиент продолжит повторять попытки; в противном " "случае он выйдет." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 -#: 2e529671abf848fd87771801ae4a3763 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:165 +#: d8e70dde1c62462cb4954eb1ceb50f3a #, fuzzy msgid "" "*Note: The client socket is created in the `connect` method (called by " @@ -367,8 +448,8 @@ msgstr "" "основан на IPv4 и использует параметры self.host и self.port, которые " "предоставляются при создании экземпляра клиента.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 -#: abe7c8d5d59b4a589ec6537a06a7333b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:170 +#: 80f69db837ec4e1d9bb90bc821019532 msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will either start the interactive input loop " @@ -379,8 +460,8 @@ msgstr "" "мы либо запустим цикл интерактивного ввода («interactive_mode»), либо " "просто сохраним соединение (без консольного ввода)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:134 -#: e6ad1c25ef6e409aa4dba10b44fbe7a4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 +#: 445af010e93f421099da8d8dd5212210 msgid "" "After that, if the interactive mode is enabled, the client will read user" " input from the console and send messages to the server until the " @@ -390,8 +471,8 @@ msgstr "" "пользовательский ввод из консоли и отправлять сообщения на сервер до тех " "пор, пока соединение не будет закрыто." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 -#: c957271185064b21a0bc78265e007969 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:179 +#: 2d4020f99c3c4a4485815c383a0a4bfe msgid "" "*Note: There is a global variable ``self.running`` which is set to " "``True`` after the client successfully connects to the server. The " @@ -404,8 +485,8 @@ msgstr "" "приема, и ей будет присвоено значение False при завершении работы " "клиента.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 -#: d055f0b3b19940be8b0549705d6cd3b5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:185 +#: e4de5ae390fc4c1c9a50703299f80356 msgid "" "The `connect` method will try to establish a TCP connection to the " "server. If a ``client_port`` is specified, the client will bind to that " @@ -418,8 +499,8 @@ msgstr "" "локальному порту. Этот метод корректно обрабатывает таймауты и ошибки " "отказа в соединении, особенно если включен ``is_wait_server``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 -#: 4615e65c81854301ac43f16a4d7e16b1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 +#: 17315c7599be4d2e8d8f62ad4c866eb3 msgid "" "When the connection is established, a background thread " "`receive_messages` is started to continuously read data from the server." @@ -427,13 +508,13 @@ msgstr "" "Когда соединение установлено, запускается фоновый поток " "«receive_messages» для непрерывного чтения данных с сервера." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:154 -#: bace28ef9c5841ffac04669beeb4e56a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:195 +#: 26bc6f1cf62947c88fd9de780337d225 msgid "So what can the setup function do if the connection fails?" msgstr "Так что же может сделать функция настройки в случае сбоя соединения?" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:156 -#: f89e08eff4f84bfba70ee321e26e218b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:197 +#: e7519cc6a4124a008a804ecbe9b10453 msgid "" "First, if the connection attempt times out, the client will either wait " "and retry (if ``is_wait_server`` is ``True``) or exit with an error." @@ -442,8 +523,8 @@ msgstr "" " повторит попытку (если ``is_wait_server`` имеет значение ``True``), либо" " завершит работу с ошибкой." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 -#: fe3484d9a2b04f29944bc0d412d73536 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:201 +#: 2bcc61a302d34c7dbc18f9bcc7beba5a msgid "" "Secondly, if the server is not running (connection refused), the " "behaviour is the same: retry or exit based on ``is_wait_server``." @@ -451,8 +532,8 @@ msgstr "" "Во-вторых, если сервер не запущен (в соединении отказано), поведение " "такое же: повторите попытку или выйдите на основе is_wait_server." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:164 -#: 18131d4fd10c42d09e1eca9697bda2fb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:205 +#: c33c7409acd94d6b8f69e0f718e50c1f msgid "" "If any other socket error occurs, the client will print the error message" " and return ``False``, and the `start_TCP_client` method will call " @@ -462,13 +543,13 @@ msgstr "" "сообщение об ошибке и вернет «False», а метод «start_TCP_client» вызовет " "«sys.exit(1)»." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:168 -#: 050d63fcb50c4053aba93e3d05dae63c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:209 +#: d78f849334b6404d8840b12839d05b8c msgid "For shutting down the client, the `close` method is defined as:" msgstr "Для завершения работы клиента метод close определяется как:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 -#: c0860fa6e2c240e5a2a56b278f3369f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 +#: 4b23bb29324b408ca1a3c06128ede442 #, fuzzy msgid "" "In the `close` method, we set ``self.running`` to ``False``, free any " @@ -480,8 +561,8 @@ msgstr "" "освобождаем все выделенные порты, вызывая free_port, а затем закрываем " "клиентский сокет. Это обеспечивает чистое отключение." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:180 -#: 6a703de12132431982451a11b661b4d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:221 +#: 510de5709a444a0c8296717f1e8bed2b msgid "" "``close`` also wins against a connection attempt that is still in flight:" " if it runs before ``connect`` puts the socket up, that call closes the " @@ -489,8 +570,8 @@ msgid "" "client." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:184 -#: ae54449f52b0491aaeb0c11de7749e4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:225 +#: c67deae0af3b4ab9bf572198122cc09d msgid "" "*Note: The `free_port` method works similarly to the server side, " "releasing any manually allocated ports if manual allocation mode is " @@ -500,13 +581,13 @@ msgstr "" "освобождая все порты, выделенные вручную, если включен режим ручного " "выделения.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 +#: fbb5ed3c54a34df4bc6bf8f9688e295c msgid "TCP Client handling information API" msgstr "API обработки информации TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:193 -#: 57895cdce9c1426289087c4448ac2325 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 +#: 7c21a424a7774ad6b4a257c5ad645db4 msgid "" "The client handling information API documents the core TCP client methods" " that manage the server connection, receive raw data, and send messages." @@ -515,8 +596,8 @@ msgstr "" "TCP-клиента, которые управляют соединением с сервером, получают " "необработанные данные и отправляют сообщения." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:198 -#: f9294ef58d274a9ba6b8edbec8c07606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:239 +#: b0fc366cad48412999e75faf81120a6e msgid "" "Unlike the server, the client maintains only a single connection and does" " not provide broadcast or ``send_msg_to_specific_client`` methods." @@ -525,8 +606,8 @@ msgstr "" "предоставляет методы широковещательной рассылки или " "send_msg_to_specified_client." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:208 -#: 67e867cdfba84730bef1ad32d859ea24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:249 +#: ff50f500c3804fdb9562b5e9ae1a3482 msgid "" "`receive_messages` is the main background thread function in " "``TCP_Client_Base``. It is started after a successful connection and is " @@ -536,8 +617,8 @@ msgstr "" "``TCP_Client_Base``. Он запускается после успешного подключения и " "отвечает за:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:212 -#: 17684d40e43543e88db7135b66b26e09 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 +#: 364f1d2b080843518fee4bcc0e74a8ca msgid "" "continuously receiving raw bytes from the server socket using " "`receive_message`" @@ -545,20 +626,20 @@ msgstr "" "непрерывное получение необработанных байтов из сокета сервера с " "использованием `receive_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:213 -#: dc882668c1244dc3b7e57b07ad08612a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:254 +#: cf3b7cf194ec42919b87199c4586dfc4 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "" "буферизация входящих данных до тех пор, пока сообщения, завершающиеся " "новой строкой, не будут завершены" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:214 -#: 707313e8051245478059aa883da7459f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:255 +#: ad695c0a732a4ad78cdd07c79f2d5dc3 msgid "splitting and processing each message line-by-line" msgstr "разделение и обработка каждого сообщения построчно" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:215 -#: e9edeedb0eb64a278e03efa5169a36f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:256 +#: 387a605c25f8407d86b77c452ded00f7 msgid "" "routing special commands (starting with ``/``) that come from the server " "to `handle_server_command`" @@ -566,23 +647,23 @@ msgstr "" "маршрутизация специальных команд (начинающихся с ``/``), поступающих с " "сервера, в `handle_server_command`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 -#: 0ab735831831448a88f60538f859ce4e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:257 +#: d1729cfa1e314df68d3e7ce7e553f3a5 msgid "" "printing every received line to the console with a ``[server]`` prefix " "(command lines included, after ``handle_server_command`` has processed " "them)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:218 -#: e09f439632994d0fadb0ae8f58eef0cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:259 +#: 083b077c5c1845338f11ae62bace15b5 msgid "" "unwrapping forwarded lines (``/send_msg_from``) so a message another " "client forwarded here is attributed to its author" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:220 -#: 166f9028c1cc41ff94be560b77e17504 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:261 +#: 1dd20cbdeac3480bbaec2f7ae6f1f1ed msgid "" "handling connection resets and other socket errors, and cleaning up when " "the server closes the connection" @@ -590,8 +671,8 @@ msgstr "" "обработка сбросов соединений и других ошибок сокетов, а также очистка, " "когда сервер закрывает соединение." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:229 -#: db2e058412bc44d6ba39131b3b40a7ac +#: ../../source/Network_APIs/TCP_Client_APIs.rst:270 +#: e890dee4fb944eeaa9e6b2cf3cd9047a msgid "" "In `handle_server_command`, the client processes built-in commands sent " "by the server, such as:" @@ -599,8 +680,8 @@ msgstr "" "В `handle_server_command` клиент обрабатывает встроенные команды, " "отправленные сервером, например:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:273 +#: b957ec8457f34618802ea0441634a894 #, fuzzy msgid "" "``/client_alloc_port_range``: configures the client's manual port " @@ -609,8 +690,8 @@ msgstr "" "``/client_alloc_port_range``: настраивает диапазон ручного выделения " "портов клиентам на основе широковещательной рассылки сервера." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 -#: 2558e50f505a4b6ca51c7a44fa9ad957 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:275 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/server_file_transfer_port``: receives the file transfer port assigned " "by the server for an ongoing file operation." @@ -618,8 +699,8 @@ msgstr "" "``/server_file_transfer_port``: получает порт передачи файлов, " "назначенный сервером для текущей файловой операции." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:236 -#: 5147df6f2f794cf2949b7cef1ed24791 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:277 +#: 4eb4fe22d5db4b56b622dfd29459c3b7 msgid "" "``/file`` and ``/file_folder``: handle file transfer requests initiated " "by the server (server-to-client transfers)." @@ -627,8 +708,8 @@ msgstr "" "``/file`` и ``/file_folder``: обрабатывают запросы на передачу файлов, " "инициированные сервером (передача от сервера к клиенту)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:238 -#: 4755bb63eb0e4f8cbf481633417fc3c7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:279 +#: 3c550345aa484cb8bc44681842864044 msgid "" "``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``," " ``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the " @@ -636,15 +717,15 @@ msgid "" "the connection." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:242 -#: f7cbe268c5e84987aec0bb18a0a81aa7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 +#: 31a62335177b49a19f708aee2aa5b0b1 msgid "" "``/forward_upload``, ``/pause_trans``, ``/start_trans``, " "``/forward_error``: forwarding and transfer-control messages." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:245 -#: d89b63a85c3d402fbb0df0f75edc4736 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:286 +#: b4c3c6ea61f344b8a3d3baf6b659d9c7 msgid "" "If you have registered custom commands using the command extension API, " "`handle_server_command` will also check if the incoming command matches " @@ -655,8 +736,8 @@ msgstr "" "ли входящая команда какому-либо зарегистрированному обработчику, и " "выполнит ее соответствующим образом." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:250 -#: 943d4fb64bad477f969403f360288769 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 +#: 4b6cc84b10d34254b7e6e0d7ae226ddc msgid "" "*Note: For more details of the command extension API, see the :ref:`tcp-" "client-command-api` section.*" @@ -664,16 +745,16 @@ msgstr "" "*Примечание. Более подробную информацию об API расширения команд см. в " "разделе :ref:`tcp-client-command-api`.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 -#: c2b4ba39cca64ea7ab62a59d016f0544 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:294 +#: b9ff85e2f76d4c1697602ebf69fed3a8 msgid "" "Closing the connection when the server goes away is not part of " "`handle_server_command`: it is `receive_messages` that reports the " "disconnect and clears ``self.running``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:265 -#: 9312fc5109a547d588d98c16a9b79c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:306 +#: 4376aa47bf63490998e7008547d0c86f msgid "" "`receive_message` is identical to the server version: it reads up to " "``msg_length`` bytes from the given socket and returns the raw byte " @@ -684,8 +765,8 @@ msgstr "" "байтовые полезные данные. Декодирование сообщения и кадрирование новой " "строки обрабатываются вызывающей стороной." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:278 -#: 7a64cec6a8084261a443f57f7032a5bb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:319 +#: 29b51f413be748e4b101bf498e593ef2 msgid "" "`send_message` sends data from the client to the server. It verifies the " "client is still running and the socket is valid, then:" @@ -693,20 +774,20 @@ msgstr "" "send_message отправляет данные от клиента на сервер. Он проверяет, что " "клиент все еще работает и сокет действителен, затем:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:281 -#: 9a5d3a7c041b47d68b80186e09492467 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 +#: e4158824d7b04b37a0f75c9ff67eab45 msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "принимает полезную нагрузку сообщений как ``str``, так и ``bytes``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:282 -#: c4247339bf084481af72ba498d8f9bcd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:323 +#: ea9158c1798941cb9df13f5a01b14f69 msgid "trims string payloads and appends a newline if missing" msgstr "" "обрезает полезные данные строки и добавляет новую строку, если она " "отсутствует" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 -#: 55c0dfde024b4bdea57da54d86297dbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:324 +#: 0fb0befad2844821a59b8c5c686e1c39 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -718,18 +799,18 @@ msgstr "" "шифруется открытым ключом сервера, кодируется в формате Base64 и " "завершается новой строкой вместо отправки в открытом виде." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:287 -#: 6e2bbc8edbad40568dfe3eae781ab27c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:328 +#: e8d7a04011e74da18b274e1ad3ca3ab8 msgid "encodes string payloads as UTF-8" msgstr "кодирует строковые полезные данные как UTF-8" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:288 -#: 40b2936e9c6b4325b19b27f83932cf83 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:329 +#: 08c9e9aca2334e67b5051b42cc7dbad0 msgid "sends the complete message with ``client_socket.sendall(data)``" msgstr "отправляет полное сообщение с помощью ``client_socket.sendall(data)``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:289 -#: 9ab8a09e5ca4416abd843cf1612f20a2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:330 +#: 99b4f8d523b2406499891c514befc372 msgid "" "returns ``True`` on success, otherwise logs the error and returns " "``False``" @@ -737,8 +818,8 @@ msgstr "" "возвращает ``True`` в случае успеха, в противном случае регистрирует " "ошибку и возвращает ``False``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 -#: 0eb535b8380441869c432950417def80 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:332 +#: 18101652b1e34996866324fce0aa8a4d msgid "" "The client also provides an interactive input loop (`interactive_mode`) " "that reads user input from the console and sends messages to the server." @@ -747,35 +828,36 @@ msgstr "" " который считывает вводимые пользователем данные с консоли и отправляет " "сообщения на сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:298 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:339 +#: fbb5ed3c54a34df4bc6bf8f9688e295c #, fuzzy msgid "TCP Client inbound event listener API" msgstr "API передачи файлов TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:300 -#: 8b78c521249c4604933d30cfc99cc7a9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:341 +#: 15461ca186ed497083b901e65a3b33d1 msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:310 -#: 2f13976d605042919a1a19e346d85bd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:351 +#: 0d916f8d3eaf4336b5be87a5faf153a3 msgid "" "``add_message_listener`` registers ``listener(sender_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to `handle_server_command` instead). ``sender_id`` is the author's " -"``\"ip:port\"`` — for a message another client forwarded here through the" -" ``/send_msg_from`` envelope it is the forwarding client, and it is " -"``None`` for a direct push from the server. ``add_file_listener`` " -"registers ``listener(client_id, full_path, name, size, command)`` and " -"fires after a file sent by the server has been fully written to disk. " -"Both listeners run on a protocol thread, so they must not block, and an " -"exception inside a listener is logged and swallowed. The ``remove_*`` " -"counterparts unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 -#: 75d993e34b944014be1b88aee03a4f9c +"every inbound line, commands included, so a listener observes all inbound" +" traffic; a message another client forwarded here through the " +"``/send_msg_from`` envelope is reported as its payload. ``sender_id`` is " +"the author's ``\"ip:port\"`` — the forwarding client for such a forwarded" +" message, and it is ``None`` for a direct push from the server. " +"``add_file_listener`` registers ``listener(client_id, full_path, name, " +"size, command)`` and fires after a file sent by the server has been fully" +" written to disk. Both listeners run on a protocol thread, so they must " +"not block, and an exception inside a listener is logged and swallowed. " +"The ``remove_*`` counterparts unregister a listener and ignore unknown " +"ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:364 +#: 196be233dc00497a94ee87f9999a9897 msgid "" "Received messages and events are also stored per sender socket in " "``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -784,13 +866,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``close`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:331 -#: 6535dcf4080e4090bf82df637e452cc6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:373 +#: 6d52a0605748445694e0f4b1a6c52ea7 msgid "TCP Client encrypted channel API" msgstr "API зашифрованного канала TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:333 -#: e2dbda95b2ff4483b8b71394ae4b83c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:375 +#: 14a20833906f4e18b92856c3e98a8886 msgid "" "When the client is created with ``is_enable_encrypto=True`` (the " "default), it performs an RSA public-key exchange with the server " @@ -801,13 +883,13 @@ msgstr "" " подключения, прежде чем какое-либо содержимое сообщения будет " "зашифровано." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:338 -#: 411e33f708ba4961aaf9073beffe7404 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:380 +#: 46166a685e064cd29ad7701d3a352fc4 msgid "Key material" msgstr "Ключевой материал" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:340 -#: 89d96a4b9abe4ccd98bdd72682b94a56 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:382 +#: ffdef9bf79aa41e6a401b0a16c24a674 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -822,8 +904,8 @@ msgstr "" "закрытого ключа, поэтому повернутая пара ``~/.ssh`` подбирается " "автоматически." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:345 -#: 74eb9aca2b1849e48138cbea3e76a39d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 +#: 2c27cfc2e8ce47fb8732aec1e00d3479 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -834,8 +916,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:352 -#: e935794dae5f4c2682336e72732afec3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:394 +#: 425ba3d582c3490b9375d99baa9b61e6 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -850,8 +932,8 @@ msgstr "" "закрытого ключа); недопустимая пара игнорируется и используется поиск по " "умолчанию." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:357 -#: 72a43fff94f04914848603d6ede43cfd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:399 +#: 696441cc5dd44fc4af958c547c8b6b90 msgid "" "Public keys received from the server are cached in " "``network_api/.Flow/pub_key`` as ``server__.pem`` (the server " @@ -863,13 +945,13 @@ msgstr "" "точка сервера, откуда пришел ключ; ``:`` заменяется на ``_``, поэтому " "литералы IPv6 безопасны на любой платформе, включая Windows)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:363 -#: a4903fbcbc6f4c9d93c8fc3066fcc1c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:405 +#: 2a81e756d1c947d384d20dbbbe5d6d52 msgid "Anti-MITM identity check (TOFU)" msgstr "Проверка личности Anti-MITM (TOFU)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:365 -#: e30dc3b276654ea2b6ec48793d8df984 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:407 +#: 7a915eef76594c3ea715adb845fcabc6 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -885,8 +967,8 @@ msgstr "" " Python конечной точки, в которой доступен одноранговый узел), значение -" " ``[, <открытый ключ PEM>]``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:372 -#: 247a92c41f0d45ed9a5f8ad2d12bca2e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:414 +#: 4d56fbd290604113a600a56d8e89cdfb msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." @@ -894,8 +976,8 @@ msgstr "" "Первое соединение с конечной точки: ключ записан и ему доверяют (доверие " "при первом использовании)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:374 -#: 7adc6b725e7244df8bc1b861b4cec80c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:416 +#: a6be8828e0594ddc8aa71229934cc73d msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -906,8 +988,8 @@ msgstr "" "пользователем), запись перемещается в новый ``(ip, порт)`` вместо " "дублирования." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:377 -#: ba6d10fef7fb42cd8dd6518c415762d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 +#: fda350faac9a4efd82575a386fc929c0 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is received and " @@ -917,8 +999,8 @@ msgstr "" " точки: соединение отклоняется (получается ``/crypto_reject`` и клиент " "закрывается)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:381 -#: 7f2ec5e5c2604098906635697130c4fd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:423 +#: 9d62655e00324c518633c6c1d615d515 msgid "" "The client-side record is keyed by the fixed server address, so a server " "that changes its public key (for example a MITM substitution) is always " @@ -931,13 +1013,13 @@ msgstr "" "доверие (смененные ключи, новый сервер), удалите запись ``pub_key.json`` " "(или весь файл)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 -#: 9a08bf51aea742de8d0a0f351d055b3a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:429 +#: 799c58ee59b0416688562166f58a14c1 msgid "Handshake" msgstr "Рукопожатие" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:389 -#: 879e1be6d2de4859bc0777d1cd1682f8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:431 +#: 6f92afe3b8314a9985b62fe55cdeee70 #, fuzzy msgid "" "Right after connecting, the client announces its encryption mode with a " @@ -945,15 +1027,17 @@ msgid "" "server's answer; a mode mismatch closes the connection. It then sends a " "plaintext ``/crypto_key_exchange `` greeting; the server " "replies with ``/crypto_key_exchange_ack " -"``. Both sides then push their public key files over the file-" -"transfer mechanism (plaintext) and TOFU-check the received key. Both " -"sides switch to encrypted mode only after ``/crypto_ready`` has been " -"received from the peer (so plaintext and ciphertext never interleave on a" -" connection). On later connections the keys are re-exchanged and TOFU-" -"checked again; the exchange is never skipped, only the identity check " -"short-circuits for known keys. Public-key pushes are only accepted while " -"a handshake is in progress, so an arbitrary unauthenticated server cannot" -" poison the registry." +"``. Both (plaintext) and TOFU-check the received key. Both sides " +"switch to encrypted mode only after ``/crypto_ready`` has been received " +"from the peer (so plaintext and framed traffic never interleave on a " +"connection), then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted while a handshake is in progress, so an " +"arbitrary unauthenticated server cannot poison the registry." msgstr "" "Клиент отправляет открытое текстовое приветствие ``/crypto_key_exchange``" " сразу после подключения; сервер отвечает ``/crypto_key_exchange_ack " @@ -966,39 +1050,58 @@ msgstr "" "повторно обмениваются и снова проверяются TOFU; обмен никогда не " "пропускается, только проверка личности сокращает известные ключи." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:406 -#: a36303a34b174e6a8c4a421f297e4452 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:451 +#: a501267a3c9848e6aac40eb13359da87 msgid "Replay protection" msgstr "Защита от повтора" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:408 -#: dd11c43faac347858ff85f846d7af6d1 -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." -msgstr "" -"При рукопожатии происходит обмен случайным одноразовым номером сеанса, и " -"каждая зашифрованная строка в сети содержит его плюс порядковый номер для" -" каждого соединения: ``||``. Получатель " -"удаляет строку, nonce которой не соответствует текущему сеансу " -"(зашифрованный текст воспроизводится из более старого соединения) или чей" -" порядковый номер не является ожидаемым (зашифрованный текст " -"воспроизводится внутри сеанса/не в порядке); оба счетчика сбрасываются, " -"когда сокет переключается в зашифрованный режим после (повторного) " -"обмена." - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:417 -#: ddfd9d5832b541ba81de53f2f9abd91b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 +#: cde1f1712c904c89aa5838bc54c715b6 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:469 +#: 51478387b6dd4b2e9f7a3d10f72a8b90 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 +#: a47f9db0c3674a12ab6d3ab5d056a8c4 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:483 +#: 6740137a28b84e5dbb3f85e8d58d32b5 msgid "Decode verification and key rotation" msgstr "Проверка декодирования и ротация ключей" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 -#: 2f8d9ddc0f434f0b98331fc3c14f710b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 +#: 8445bf9265124e38a642f9d46fc43c36 msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -1024,13 +1127,19 @@ msgstr "" "(или весь файл) на стороне однорангового узла, чтобы повторно доверять " "новому ключу." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:430 -#: 3b373e99ee2c4aff93e808c206dfb3f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:496 +#: 5698fde8f08b4be3a059d92a69ae3459 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures the connection is closed instead of re-" "exchanging, so a garbage-injection or persistent-mismatch storm cannot " -"spin the loop forever. A successful decryption resets the counter." +"spin the loop forever. Genuine peer traffic (messages and commands other " +"than the protocol's own handshake/coordination lines) resets the counter." +" Frames the peer had already sent when this side dropped out of encrypted" +" mode are stale: they cannot be authenticated any more, so they are " +"consumed and dropped — they neither surface as messages nor reset the " +"counter." msgstr "" "При повторном обмене происходит разрыв цепи: после " "``MAX_DECODE_FAILURES`` (3) последовательных неудач декодирования " @@ -1038,13 +1147,13 @@ msgstr "" "или шторм постоянного несоответствия не могут вращать цикл вечно. " "Успешная расшифровка сбрасывает счетчик." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:438 -#: aaefbbdc89554770aebdf60c16950f0f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:508 +#: 6569277ee0b644488685204e70c3e425 msgid "TCP Client command API" msgstr "Командный API TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:440 -#: 22612be28f9d4da5b01258de1c7520f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:510 +#: b2ab9f46d6b14c8eaa97512fd117c6db msgid "" "The client supports both built-in commands that the user can type in the " "console, and a command extension API similar to the server. The main " @@ -1057,8 +1166,8 @@ msgstr "" "«handle_server_command», а команды, вводимые пользователем, " "обрабатываются в «interactive_mode»." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:446 -#: 5607f70cfddc4466946bc9082ce494ab +#: ../../source/Network_APIs/TCP_Client_APIs.rst:516 +#: 5e296796f3694cdfbf48c8538979bb7f msgid "" "The client supports two modes of operation: interactive console input " "(when ``is_input_command_in_console`` is ``True``) or programmatic " @@ -1068,33 +1177,33 @@ msgstr "" "(когда is_input_command_in_console имеет значение True) или программное " "управление (когда значение False)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:450 -#: bfa689507e214d7a961f1042698850ce +#: ../../source/Network_APIs/TCP_Client_APIs.rst:520 +#: 0261c3323c4248e3bfb846d5751da36f msgid "Built-in client console commands (user-typed) include:" msgstr "" "Встроенные клиентские консольные команды (вводимые пользователем) " "включают в себя:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:452 -#: 9a2bcb83868f473aae1fa0090af2dd49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:522 +#: d466b066b3654e7183cf72f86523bcd1 msgid "``/quit``: sends a quit message to the server and closes the connection." msgstr "``/quit``: отправляет на сервер сообщение о выходе и закрывает соединение." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 -#: 84be485738544bd98d7e0d2f49415cda +#: ../../source/Network_APIs/TCP_Client_APIs.rst:523 +#: 3d22aacfa1914a879be55a3518fb2a7e msgid "" "``/send_msg ``: sends the second token of the line as a chat " "message (``send_message_to_server`` drops the command name and sends only" " the next token)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:456 -#: 6bb0b49ebc5743fe9332f66948330822 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 +#: 16b438ba77f945d2a68bb24f97a69ef5 msgid "``/file ``: starts a file transfer from client to server." msgstr "``/file ``: запускает передачу файла от клиента к серверу." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:457 -#: eb7e88c4607340ba8795bacb617ae98a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:527 +#: 65a2f7cca5684f21ae85deaf2675b2fa #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files from client " @@ -1105,8 +1214,8 @@ msgstr "" "клиента к серверу (каждый в своем собственном потоке, соблюдая " "ограничение семафора)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:460 -#: 98dda85c8e2a4623a9dc2d39643cddbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:530 +#: 0cb1732f55e8499ab36b6923ed56a8ec msgid "" "``/file_folder ``: sends an entire folder from client to " "server, preserving the directory structure." @@ -1114,8 +1223,8 @@ msgstr "" "``/file_folder ``: отправляет всю папку с клиента на сервер," " сохраняя структуру каталогов." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:462 -#: 1f2e6b52be7f4875aa8434ff22117ee0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:532 +#: f8d95f978af24a0d8056fc369d555f5f msgid "" "``/multiple_file_folder ...``: sends multiple folders" " from client to server." @@ -1123,23 +1232,23 @@ msgstr "" "``/multiple_file_folder ...``: отправляет несколько " "папок с клиента на сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:464 -#: 48811f3665104578b8921efe71ada53a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:534 +#: c3477f2df53d499db3c6a9b41f8bdedf msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands (client-only; the server refuses " "them)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:468 -#: 3fe8e4c73ecc42e98bde402ff3858c64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:538 +#: d6c13262c84f4ae2a43371ee4e09cfad msgid "" "Ctrl-C and EOF close the connection, send a final ``/quit`` and wait 0.5 " "seconds before the process ends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 -#: c330e7622ffc46a19b41f3e6394c3dc8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 +#: 7971066cb1de4bc2b8047248fa93d58e msgid "" "*Note: Unlike the server, the client does not have built-in ``/help``, " "``/time``, or ``/clients`` commands because those are typically handled " @@ -1152,8 +1261,8 @@ msgstr "" "пользователям следует обратиться к документации сервера за доступными " "командами.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:477 -#: f7ea97482c86419cb7e1e5db99cd79c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:547 +#: 44cf1d07758f4fa89eb47d9aad2369a5 msgid "" "A user-typed line that is not built-in and not a registered custom " "command is sent to the server as a chat message, and the client logs " @@ -1161,28 +1270,28 @@ msgid "" "with that wording too)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:482 -#: 677fc4a9eabd4d5ab97bf0e2e73b05ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:552 +#: 7f463379f38f44558c3121e202f9343b msgid "" "*Note: a custom command is matched against the first token of the line, " "so a handler registered for ``/mycmd`` runs when the user types ``/mycmd " "...``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 -#: 1325358de66e4303bb8f9ff817415890 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:555 +#: ae962d51828a4e859fd9080b6eb9ec88 msgid "The command extension API for the client is defined as:" msgstr "API расширения команд для клиента определяется как:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:494 -#: 24f976022e4245e0aa95c2cf112854c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:565 +#: cfa1714f672d4103bae0af84db5a1d63 msgid "" "The arguments of the `register_command` function are the same as on the " "server side:" msgstr "Аргументы функции `register_command` такие же, как и на стороне сервера:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:497 -#: 087de666d0cb46b39328508976a7dc92 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:568 +#: 2f936e153d6f4587b918adf94d6ba438 msgid "" "``command_name``: The name of the command to register (should start with " "a slash, e.g., ``/mycmd``)." @@ -1190,8 +1299,8 @@ msgstr "" "``command_name``: имя регистрируемой команды (должно начинаться с косой " "черты, например, ``/mycmd``)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:499 -#: 3acea6e2461e40f9b02b90154cb62c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 +#: c19aa473ddf5488cbe8b5039b68e08cf msgid "" "``handler``: The function to call when the command is received. The " "handler must accept three parameters: ``client_socket``, " @@ -1201,8 +1310,8 @@ msgstr "" " принимать три параметра: ``client_socket``, ``client_address`` и " "``command``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:501 -#: 60a8ef01850843b48c37e1ce0248d247 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 +#: d327d91dee274ac1951b18ee3700c15a msgid "" "``where_to_run``: Specifies where the command should be executed. Valid " "values are ``\"server\"`` (command sent from the server) or " @@ -1212,8 +1321,8 @@ msgstr "" "Допустимые значения: ``\"server\"`` (команда, отправленная с сервера) или" " ``\"client\"`` (команда, введенная в консоли клиента)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:503 -#: 0a59b9453a5145ffa92a1e91741cfa49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:574 +#: 17b9e2d9c50344bdb8e704423df3c4c8 msgid "" "``run_in_thread``: A boolean indicating whether to run the handler in a " "separate thread from the thread pool." @@ -1221,16 +1330,24 @@ msgstr "" "``run_in_thread``: логическое значение, указывающее, запускать ли " "обработчик в отдельном потоке из пула потоков." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:506 -#: 73925e7106344a879ba8a7e1f4ea6408 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:577 +#: a4fcfb0b0f89415fa269eccf366b2539 msgid "" "It returns ``False`` when ``where_to_run`` is neither ``\"server\"`` nor " "``\"client\"`` (nothing is registered then); on success it returns " "``None``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:509 -#: e9b4b0ddbfd143759ab38205955ff2de +#: ../../source/Network_APIs/TCP_Client_APIs.rst:580 +#: 55e17f10381d4c6e9c13c484a6d7b2f7 +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code, on the client as on the server; the command's first token " +"selects it, exactly as it does for a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 +#: 889fe9598c0045ccaee7de4e93d59f8e #, python-brace-format msgid "" "*Note: The client stores registered commands in the same structure as the" @@ -1243,8 +1360,8 @@ msgstr "" "команд, поступающих с сервера, а индекс 1 — для команд, вводимых в " "консоли клиента.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:514 -#: 87c31576643d4e328b32b14b69b4f818 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:589 +#: 9a244a7eb66d4c0c9666537c17e6f3ac msgid "" "The client also provides the `submit_task` method to submit functions to " "its internal thread pool executor, and `_execute_custom_handler` to " @@ -1255,8 +1372,8 @@ msgstr "" "безопасного выполнения зарегистрированных обработчиков с обработкой " "ошибок." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:519 -#: e64628a99ba249f8acef54a08b182c79 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:594 +#: 4cbf4048c25443dda40d622c49a8e26e #, fuzzy msgid "" "The `submit_task` method works identically to the server version: it " @@ -1269,13 +1386,13 @@ msgstr "" "вызываемый объект в пул потоков клиента, используя семафор для " "ограничения параллелизма до max_custom_workers." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 -#: e8f3baf910cb4b2497cb6f6eab9053e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:601 +#: 3a2bd1984dd14769b92c6e40c6ad357c msgid "Temporary server and client creation" msgstr "Создание временного сервера и клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:528 -#: 26cf9b3fd35d4af993c53f9a8e4bffb6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:603 +#: 0c9b9ad8c6ca4f679f8e54fb58940d3e msgid "" "The client also includes temporary TCP server and client creation APIs. " "They are similar to those in the server class but use `self.client_host` " @@ -1285,8 +1402,8 @@ msgstr "" "аналогичны классам серверов, но используют self.client_host в качестве " "адреса локальной привязки." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 -#: 6fb3cae805964394bf0864814b4b8ecd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:616 +#: 03e3fc356d234c01a0bd94bad68b8ddc #, fuzzy msgid "" "`create_temporary_server` binds to ``(self.client_host, port)``. If " @@ -1300,8 +1417,8 @@ msgstr "" "ручном режиме) или возвращает 0 (назначается ОС). Он возвращает кортеж " "``(port, server_thread, stop_event)``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:558 -#: 8ab44b7d114a4eca8079a87b61ca219f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:633 +#: 61b63d2c156f4512aead02cbbfe0569e #, fuzzy msgid "" "`create_temporary_client` connects to the specified server. If " @@ -1316,8 +1433,8 @@ msgstr "" "``self.palloc()`` и привязывается автоматически. Он возвращает кортеж " "(client_sock, Recv_thread, stop_event)``." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:564 -#: d5a66d0848e24412a1e121fba226cff8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 +#: a528285ae2714861bf6162938ad1aa0a msgid "" "These methods allow the client to act as a temporary server or to spawn a" " separate client connection for auxiliary tasks (such as file transfers)," @@ -1327,13 +1444,13 @@ msgstr "" "создавать отдельное клиентское соединение для вспомогательных задач " "(например, передачи файлов), не мешая основному соединению." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 -#: 16bd0374c6194f4b9bd2db749597217f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:645 +#: 46a7a0338f5040f38903a61af8ff8ae5 msgid "TCP Client console commands (interactive mode)" msgstr "Команды консоли TCP-клиента (интерактивный режим)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 -#: dbe05db8944f49818decf56adb4855b6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:647 +#: 8a93646c1be14bb8bfcb5be5140f1572 msgid "" "When the client is started with ``is_input_command_in_console=True`` (the" " default), the `interactive_mode` method is invoked. This method reads " @@ -1343,30 +1460,30 @@ msgstr "" "(по умолчанию), вызывается метод interactive_mode. Этот метод читает " "строки из стандартного ввода и обрабатывает их." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:576 -#: eea6d19cd2f44de6ae2bd67081f49b5a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:651 +#: 5370ea52c70741728cc72ae1618e65e8 msgid "Supported console commands (user-typed) include:" msgstr "Поддерживаемые консольные команды (вводимые пользователем):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:578 -#: 3d1b84c153974f14bdd57c17a892a158 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 +#: 3ee645c39b844b1e8b14a1eb54bef876 msgid "``/quit``: closes the connection and exits the client." msgstr "``/quit``: закрывает соединение и выходит из клиента." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:579 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:654 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/send_msg ``: sends the second token of the line to the " "server as a chat message." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:581 -#: 50b34e795f4a4d1595f8a2f6c1ebfad5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:656 +#: c34b32925f024797841232729eca131e msgid "``/file ``: sends a single file to the server." msgstr "``/file ``: отправляет один файл на сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:582 -#: d90b52a3886c48c1b86fe1d4a08adb11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:657 +#: 739e72b7a06a4eefa6cdd1a952d3d781 #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files to the " @@ -1375,15 +1492,15 @@ msgstr "" "``/multiple_file ...``: отправляет несколько файлов на " "сервер одновременно (ограничено ``max_thread_num``)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:583 -#: 66d2f7d1d87847e39e4172ae789b6a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:658 +#: d9421edab02e4b33850db50a0011ad16 msgid "" "``/file_folder ``: sends an entire folder to the server, " "recursively." msgstr "``/file_folder ``: рекурсивно отправляет всю папку на сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 -#: 321bde30af944560b349b5dd6a162a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:659 +#: efd08f6cefcd4f44bcd4ff0687cee8bc msgid "" "``/multiple_file_folder ...``: sends multiple folders" " to the server." @@ -1391,22 +1508,22 @@ msgstr "" "``/multiple_file_folder ...``: отправляет на сервер " "несколько папок." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:585 -#: 9feff7033be8445599773701f51926df +#: ../../source/Network_APIs/TCP_Client_APIs.rst:660 +#: ed70094fabb34d46afadb56fd5c7c37d msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:587 -#: 6489b5a0fb2948748f0f1bd5f303c779 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:662 +#: 1dc2bd43fd56402785fb76b3895b03b2 msgid "" "Any other non-empty line is sent as-is to the server — the same path chat" " text takes." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:591 -#: 3295a0d774d0473da7c5d7405d72abd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:666 +#: d72b6516a43b4f26bb5750604f41ff74 msgid "" "The client does not have a built-in ``/help`` command. Please refer to " "the server's help for available commands (e.g., by typing ``/help`` after" @@ -1416,8 +1533,8 @@ msgstr "" "справке сервера за доступными командами (например, набрав ``/help`` после" " подключения к серверу)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:595 -#: dd63bf8cfd3641c0be9adad9b06aa8e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:670 +#: e6081a66251a4a57bc5724dccb8c852b msgid "" "A line registered with ``register_command(..., where_to_run=\"client\")``" " runs when its first token matches a registered name; handlers registered" @@ -1425,26 +1542,26 @@ msgid "" "server sends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:600 -#: 7efd09ba06ba4067b03810eb838caa24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:675 +#: 4befe76529e04e859f9422d8ebe3921a msgid "" "*Note: The client logs ``Unknown server command: `` for any line it" " did not recognise, including plain chat text, because those lines take " "the same fallback path.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:604 -#: 8cd9357ee0494a20b9ba9d4b8ed3514b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:679 +#: 2cbc548821b84721b1aea4f88573f02f msgid "Example interactive session::" msgstr "Пример интерактивной сессии::" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:617 -#: 45b4cc10dbab4342a2653adafcad5e63 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:692 +#: bd36c89659694280b349cc621b598254 msgid "TCP Client file transfer API" msgstr "API передачи файлов TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:619 -#: 2476ecf352184c39a27da75545ff67b9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 +#: 0f20edbf8203493aa579cb5a1195712b msgid "" "The TCP client contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers, using the same " @@ -1454,8 +1571,8 @@ msgstr "" "передачу как от клиента к серверу, так и от сервера к клиенту, используя " "тот же базовый протокол, что и сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:623 -#: 37c359049bd04adcbcde988494c16efa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:698 +#: 02806a329fba478293ef172f63bfb93d msgid "" "As with the server documentation, only the list of APIs is provided here." " For detailed internal flow, please refer to the server documentation or " @@ -1465,26 +1582,26 @@ msgstr "" "Подробную информацию о внутреннем процессе см. в документации сервера или" " исходном коде." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:627 -#: a0aef36e6c984775b79dc1c35e39cd61 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 +#: 2a7f8a3995cf4e2b81a3bf5c3c85b0fa msgid "The file transfer API for the client includes:" msgstr "API передачи файлов для клиента включает в себя:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:629 -#: e340f1fe00774c58bc70b398a745589d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:704 +#: dc5da9cf7ac441c8842cc97d904582ba msgid "The basic function for client-to-server file transfer is:" msgstr "Основная функция передачи файлов с клиента на сервер:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 -#: 3cfc45f71fac4d49b0c188b84068d5b7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:714 +#: db4145949f7a42aab5ff42bf72d6ff2e msgid "" "The non-``_thread`` versions take the destination folder as a required " "argument (the ``_thread`` wrappers default it to ``None``, which means " "the default transfer folder)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:643 -#: 6058cc068109448faaad1e4936bb7863 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:718 +#: 743dd6f0cdba49678277c1d19c178f20 msgid "" "For server-initiated transfers (server-to-client), the client provides " "these handlers:" @@ -1492,25 +1609,28 @@ msgstr "" "Для передачи, инициируемой сервером (от сервера к клиенту), клиент " "предоставляет следующие обработчики:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 -#: 1e596cb7ccd942aeb30e335c53e1afa1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:728 +#: 72f8a6d975094c7984fbef810a422975 msgid "The low-level receive mode function is:" msgstr "Функция режима приема низкого уровня:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:661 -#: 885c49e37dd94f2bb3aca9d95dc72222 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:736 +#: b04d81d08ea941b3b6beea16e4a05bc0 msgid "And the low-level send mode function is:" msgstr "И функция режима отправки низкого уровня:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:668 -#: 17759b30b9ae4c68b00432ae33741a99 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:744 +#: 724cadb0ca764d9aaafd664c63b858d6 msgid "" -"``pause_fid`` is the forwarding id used to pause/resume the transfer with" -" ``/pause_trans`` / ``/start_trans``." +"``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) " +"addresses; ``peer`` is the transfer's original receiver and " +"``resume_offset`` continues an interrupted file from the byte the " +"receiver already holds." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:671 -#: 4dc07ef115aa4712807fede2f2040e12 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 +#: f5823da74e1a4879a65624511d10e0cb msgid "" "We recommend that for client-to-server file transfers, you use the " "console commands (``/file``, ``/file_folder``, etc.) rather than calling " @@ -1528,8 +1648,8 @@ msgstr "" "`file_transfer_client_recv_client_start_thread`), чтобы избежать " "блокировки основного потока." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:680 -#: 1165a3c7f2bc470da7c706aead0fc73f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 +#: 2d0ea3d6726e43a3b3b551bf23c5ce00 msgid "" "*Note: The file transfer API functions follow the same handshake protocol" " as the server: the initiator sends a command over the main connection, " @@ -1541,13 +1661,13 @@ msgstr "" "соединению, затем согласовывается временный порт, и фактические данные " "файла передаются по отдельному TCP-соединению.*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:687 -#: 95c14f0f60154aa3b15d0dd0dfe41a69 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 +#: 997f666f071d44499a4be946c3a808e5 msgid "Port allocation API" msgstr "API распределения портов" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:689 -#: 9e3832473379404391011a22af4fb605 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 +#: 937556f090f74e86ab56041fbda5c543 msgid "" "The client port allocation APIs are nearly identical to those of the " "server. They allow you to allocate ephemeral ports either automatically " @@ -1559,8 +1679,8 @@ msgstr "" "(возвращая 0, позволяя ОС выбирать), либо вручную в пределах настроенного" " диапазона." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 -#: 93aa2cdf7f3c49fb8ad14ad1b78415e4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 +#: a37e79b6f8e34e3ab589f9127a2fbaf2 msgid "" "To configure the port allocation mode, the client reads the " "``/client_alloc_port_range`` line the server sends it right after the " @@ -1570,8 +1690,8 @@ msgid "" "allocation (return 0 from allocation calls)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 -#: 3d693309e5ae4fbaa587212cf81bc16f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 +#: a29288d0ba7d46409b9fbc7e4b3ff7b0 msgid "" "In manual allocation mode, the port range is determined by the server's " "broadcast value. The client maintains its own range based on " @@ -1587,13 +1707,13 @@ msgstr "" "*each_client_port_range», а максимальный — «self.port + 1 + " "self.port_add_step *each_client_port_range»." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:710 -#: ab3bb204b8f5402093e6d329cd98cd64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 +#: baf74c2478324ced80df912ff96e7baa msgid "The main methods for port allocation are:" msgstr "Основными методами распределения портов являются:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:717 -#: 93b31be2d4bf4e5ca9f8b4ab9b095a45 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 +#: c4170cd3e6844792b110dfba945f0298 msgid "" "`palloc` returns an available port (either 0 for automatic mode, or a " "concrete port number from the manual range). It internally calls " @@ -1605,8 +1725,8 @@ msgstr "" " вызывает в цикле `file_palloc` (аддитивное распределение) и `spy_palloc`" " (вычитающее распределение)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:729 -#: d54f0b635e194239932cf1bb5cace701 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:807 +#: 1c21e96227684b8998d8a6c6c595caf0 msgid "" "`pfree` releases a previously allocated port. In manual mode, it removes " "the port from the internal list and adjusts the latest port pointers. In " @@ -1616,8 +1736,8 @@ msgstr "" "порт из внутреннего списка и настраивает последние указатели портов. В " "автоматическом режиме ничего не происходит." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:734 -#: 60b2327bda49480fac483fb4ca52eb5d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:812 +#: e270023d96364a59a4436f846b296202 msgid "" "As with the server, the automatic mode (returning 0) is recommended for " "most use cases because it avoids port conflicts and simplifies code. " @@ -1630,99 +1750,99 @@ msgstr "" "предусмотрен для сред, где диапазоны портов должны строго " "контролироваться (например, брандмауэры или тестирование)." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:741 -#: bade6122477d4a959b6f9a942b150ea0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:819 +#: 31a306a34d04473c85f2c36abe5747e7 msgid "TCP Client APIs table" msgstr "Таблица API-интерфейсов TCP-клиента" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:743 -#: be55c1d2020c4088ac45dcd1f2c6add4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:821 +#: e38b3c22a1e041be93c1b9133368dacb msgid "In short, the table of contents of the public APIs is as follows:" msgstr "Вкратце, содержание общедоступных API выглядит следующим образом:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:746 -#: 8bb46aea2dff4e57853087e452fdca3f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:824 +#: 5c9291fc111d4f87a26c3b323d69bf27 msgid "The client setup APIs:" msgstr "API настройки клиента:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:747 -#: 6c95cdbfa4634d9f9561908b316ab03e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:825 +#: dc26d3c73e994b2a89d83b6dc2b0ff20 msgid "`TCP_Client_Base`" msgstr "`TCP_Client_Base`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:748 -#: a5ab88edb0dd42dd81166dc614c4c353 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:826 +#: caab3a11f54d4540890a84cada3cecd3 msgid "`start_TCP_client`" msgstr "`start_TCP_client`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 -#: 11f6500a3ac64b41ba44c22ef2069007 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:827 +#: c38e962856a84b6eaf6f0759e9a48ec4 msgid "`connect`" msgstr "`подключить`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:750 -#: 0263dd292461441192546c1f9237adaf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:828 +#: 411023a9191243338f22e59a33cb72c2 msgid "`close`" msgstr "`закрыть`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:752 -#: 11848e9f043f4952afaad4305b07486d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:830 +#: 982308344bc1464c982613021965e40f msgid "The client handling information APIs:" msgstr "Клиентские API-интерфейсы обработки информации:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:753 -#: 6c2bd74a71a64468b3247862791409e1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:831 +#: 611645ffa9bb4259923b685f7389fab4 msgid "`receive_messages`" msgstr "`receive_messages`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:754 -#: a15228535750492caa9b3ebfba4d9901 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:832 +#: b5a951b6b0694dd7992bcb3d054bd2b3 msgid "`handle_server_command`" msgstr "`handle_server_command`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:755 -#: 47cb15f07d394f78a15345f254e42b0b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:833 +#: 334fb0ff014d4f418ac474db4c68d247 msgid "`receive_message`" msgstr "`receive_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:756 -#: f0074be846de4eef8d98f07a3fd153a7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:834 +#: df7b9a0f6c034b8ab9b1fb20b3bf879a msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:757 -#: ca1943c93c2048d9805e6c3494744d90 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:835 +#: ffb875c0ebd844368deedf382811f851 msgid "`interactive_mode`" msgstr "`interactive_mode`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:836 +#: 5630f1fb130842aba877cdb0c29e4ff1 #, fuzzy msgid "`send_message_to_server`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:760 -#: 1059c94b173f48aa9304663c6d74a805 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:838 +#: 494c8644a7254a7b81e9886d840813e8 msgid "2.1. The inbound event listener APIs:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:761 -#: 54202f3279bb4bb19457be283d4f5d75 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:839 +#: 6f15aa9d9fe142088b15a802e28823f5 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:762 -#: 88625c35b2ec49889b14309d8373c1ef +#: ../../source/Network_APIs/TCP_Client_APIs.rst:840 +#: d240527b31854c3eb36c83b57b838e5d msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:763 -#: eca517026718488aa026202ff440ce41 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:841 +#: fb735c656faa4a28983b3c90a8f9f452 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 -#: a5c242c6e4084aef98fa59f17778731d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:843 +#: 7299f59deb95485b9ce5f240b3318d86 msgid "" "The client encrypted channel APIs (see :ref:`tcp-client-encrypted-" "channel-api`):" @@ -1730,153 +1850,178 @@ msgstr "" "API-интерфейсы зашифрованного канала клиента (см. :ref:`tcp-client-" "encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:766 -#: c5006b19599d4a45bc86d5cfac770d94 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:844 +#: 51757de232d548c3b7c230b7e6456906 msgid "`_crypto_exchange_thread`" msgstr "`_crypto_exchange_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 -#: 3d8e73d09493460c845a98dabf5ad9f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:845 +#: ad3834da9c474029952e0043a46c2ed6 msgid "`_crypto_after_ack`" msgstr "`_crypto_after_ack`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:768 -#: 75bbad7153834bad9492a242fa26b789 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:846 +#: 0ca576944d8a497abeb39cdf5c4ccdb7 msgid "`_crypto_push_pub_key`" msgstr "`_crypto_push_pub_key`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:769 -#: 59aff25473e942eb9b11f6aa4c1ff235 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:847 +#: 11b6eacdaa484d689499dad3be56bd79 msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:771 -#: aeba48f8f86e45f199838191146c7f4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:849 +#: b71d430231c24a6995ba0b267f09f4bf msgid "The client command APIs:" msgstr "Клиентские командные API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 -#: 0a25d8003bd64c63ad151aedf3fb15ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:850 +#: efb7ccdbabfd477d83af89aed1eb4c5d msgid "`register_command`" msgstr "`register_command`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:773 -#: c9e2f51101b942ef8e722216e59ed972 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:851 +#: 72f8a6d975094c7984fbef810a422975 +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:852 +#: d549ceac7407457f81c403d7be88aa99 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:774 -#: 92211b1c671c48ce8e0d14c9d12b71f1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:853 +#: c6fe8883469e47b88e0a4bb3be30c1a6 msgid "`submit_task`" msgstr "`submit_task`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:775 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:854 +#: 5630f1fb130842aba877cdb0c29e4ff1 msgid "`create_temporary_server`" msgstr "`create_temporary_server`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:776 -#: e23b2af57072452ab0fab0c5652bde72 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:855 +#: 9cf956cb593f4c758da50d45c684466b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:778 -#: 91270c73be944993a8751739a6ef133e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:857 +#: 55aa7c66f7a24443a58e108948608136 msgid "The client file transfer APIs:" msgstr "Клиентские API передачи файлов:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:779 -#: 358e4cb2a7174129b65dc582f3b977f7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:858 +#: d79011e4d398480cbdb00e021f1461fe msgid "`file_transfer_client_recv_client_start`" msgstr "`file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 -#: f4971cf5af03413e9b0011378a57d487 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:859 +#: 300f91c72ed8400d85821a3e2a0ab1ec msgid "`file_transfer_client_recv_client_start_thread`" msgstr "`file_transfer_client_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:781 -#: 077b6550f3b8496fb4d8d8592eac5ca6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:860 +#: 1f3a30d9bf5d44baa9459a21df8f70d4 msgid "`folder_file_transfer_client_recv_client_start`" msgstr "`folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:782 -#: 194dd830cddc49acaad93077b41fb646 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:861 +#: 5619c7c126b14852ace1e5ed9a428e0a msgid "`multiple_file_transfer_client_recv_client_start`" msgstr "`multiple_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:783 -#: e6ea79e90d794733b2bb84b5799ab3ec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:862 +#: e1e3f53d8275406f9f2f31a406617843 msgid "`multiple_folder_file_transfer_client_recv_client_start`" msgstr "`multiple_folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:784 -#: ce228984911540d29bef2d0b7e73eabc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:863 +#: 0f3b14e3c193426191323ee76959278e msgid "`file_transfer_client_recv_server_start`" msgstr "`file_transfer_client_recv_server_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:785 -#: 7ff0717c8e504c869e36a3d9fd829652 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:864 +#: 4612a53ee9154895a8758a6cc45c0b76 msgid "`file_transfer_client_recv_server_start_thread`" msgstr "`file_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:786 -#: db7e615cfbd347359a6a683642049c31 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:865 +#: 5dff8ca27b7b40e6941b8190a136173c msgid "`file_folder_transfer_client_recv_server_start_thread`" msgstr "`file_folder_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:787 -#: 16a578b31e344b5d82b9935e56aafa02 -msgid "`file_transfer_mode_recv`" -msgstr "`file_transfer_mode_recv`" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 -#: 7659e4e26bef45e89e4659a045cd77cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:866 +#: c66340b3ef204af29e58170db0efc057 msgid "`file_transfer_mode`" msgstr "`file_transfer_mode`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:790 -#: 6a81df270092467db215985a9b0ea90e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:868 +#: 87af784aa34949379dc6a73c148a402d +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:869 +#: 9aa5be3d37804a5c8286d23160add073 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:870 +#: 4612a53ee9154895a8758a6cc45c0b76 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:871 +#: e340c2c825324df7b3aee14da0f9d919 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:872 +#: 0f3b14e3c193426191323ee76959278e +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:874 +#: 5bf1072901734d3d8d0b119e5f50627c msgid "The client console commands (interactive mode):" msgstr "Команды консоли клиента (интерактивный режим):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:791 -#: c2174ab210464a2e82c298e0f70fee20 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:875 +#: cb2350fc1fd047f39fb9841ce78dd4ed msgid "`/quit`" msgstr "`/выйти`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:792 -#: ffa9f9ef47ae46629a6fc29d29d9ab44 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:876 +#: 70b54395545d4421bd90e40acd8b28d5 msgid "`/file`" msgstr "`/файл`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:793 -#: 86990039800e4a999b76a431d6a6dd8a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:877 +#: bd2dec3b0774465d87ed9f3f853f30db msgid "`/multiple_file`" msgstr "`/несколько_файлов`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:794 -#: 6f26c82663494206964a6bb68ddcfe6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:878 +#: efe4930f9bd34df19b1ee98085605346 msgid "`/file_folder`" msgstr "`/папка_файла`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 -#: 63d6611c586c46d3a9053712a112162d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:879 +#: acb8ceac4b5540aca3230cff6bfefa86 msgid "`/multiple_file_folder`" msgstr "`/multiple_file_folder`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:798 -#: 7bb84bbf4494463d9e477ddce9f0fec2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:882 +#: 9db1c5c6b375448e80c2af32c0464023 msgid "See Also" msgstr "См. также" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:800 -#: 5cc4da34c3dc479eb9af04123c8502f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:884 +#: 0c84c6f4e6e9450aa96935335c505122 msgid ":doc:`TCP_Server_APIs` — TCP server." msgstr ":doc:`TCP_Server_APIs` — TCP-сервер." -#: ../../source/Network_APIs/TCP_Client_APIs.rst:801 -#: 134b0d0b135c4e68a08b0d14959d6307 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:885 +#: efc25fa97296452199853b1bb3cc3f21 msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — конечная точка UDP." @@ -2081,3 +2226,69 @@ msgstr ":doc:`UDP_APIs` — конечная точка UDP." #~ msgid "The multiple folders transfer function is:" #~ msgstr "Функция передачи нескольких папок:" +#~ msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" +#~ msgstr "``client_port``: по умолчанию — ``Нет`` (ОС назначает временный порт)" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(sender_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to " +#~ "`handle_server_command` instead). ``sender_id`` is" +#~ " the author's ``\"ip:port\"`` — for a" +#~ " message another client forwarded here " +#~ "through the ``/send_msg_from`` envelope it " +#~ "is the forwarding client, and it " +#~ "is ``None`` for a direct push from" +#~ " the server. ``add_file_listener`` registers " +#~ "``listener(client_id, full_path, name, size, " +#~ "command)`` and fires after a file " +#~ "sent by the server has been fully" +#~ " written to disk. Both listeners run" +#~ " on a protocol thread, so they " +#~ "must not block, and an exception " +#~ "inside a listener is logged and " +#~ "swallowed. The ``remove_*`` counterparts " +#~ "unregister a listener and ignore unknown" +#~ " ones." +#~ msgstr "" + +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "При рукопожатии происходит обмен случайным " +#~ "одноразовым номером сеанса, и каждая " +#~ "зашифрованная строка в сети содержит его" +#~ " плюс порядковый номер для каждого " +#~ "соединения: ``||``. " +#~ "Получатель удаляет строку, nonce которой " +#~ "не соответствует текущему сеансу " +#~ "(зашифрованный текст воспроизводится из более" +#~ " старого соединения) или чей порядковый " +#~ "номер не является ожидаемым (зашифрованный " +#~ "текст воспроизводится внутри сеанса/не в " +#~ "порядке); оба счетчика сбрасываются, когда " +#~ "сокет переключается в зашифрованный режим " +#~ "после (повторного) обмена." + +#~ msgid "" +#~ "``pause_fid`` is the forwarding id used" +#~ " to pause/resume the transfer with " +#~ "``/pause_trans`` / ``/start_trans``." +#~ msgstr "" + +#~ msgid "`file_transfer_mode_recv`" +#~ msgstr "`file_transfer_mode_recv`" + diff --git a/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po b/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po index 2797445..0604428 100644 --- a/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po +++ b/docs/source/locale/ru/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -21,17 +21,17 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Server_APIs.rst:2 -#: 6233736da6d8410985a7db552ebb0405 +#: c4332266e3f842cc912424ee842fcfe0 msgid "The TCP Server APIs" msgstr "API-интерфейсы TCP-сервера" #: ../../source/Network_APIs/TCP_Server_APIs.rst:5 -#: 6e1c64d13b9e4deebc7c276d00bfca94 +#: 769ff5b424d54086a70b199663089327 msgid "TCP Server setup API" msgstr "API настройки TCP-сервера" #: ../../source/Network_APIs/TCP_Server_APIs.rst:7 -#: 05209d5966c24f19bcf70e93d016fe24 +#: 2d81aa6d8ba84a868113fd9e08fc5c60 msgid "" "The TCP Server Setup API is used to create a TCP server. The server in " "the protocol is usually used to connect and listen to the TCP clients and" @@ -41,8 +41,8 @@ msgstr "" " протоколе обычно используется для подключения и прослушивания клиентов " "TCP, а также для обработки данных от клиентов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:35 -#: c6d17d88ca43468cab262d7b50bb7d43 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 +#: ddc5d0f6bc1b4162af2bb49f6b25a031 msgid "" "The TCP Server Setup API is defined in the ``TCP_Server_Base`` class. The" " parameters of the ``__init__`` method are as follows:" @@ -50,18 +50,18 @@ msgstr "" "API настройки TCP-сервера определен в классе TCP_Server_Base. Параметры " "метода ``__init__`` следующие:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:38 -#: 7c3b5b3185bb436bbaabf0aaea5f11fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 +#: f1ffcdd5c8e74b9cbdb5e5fc8eeb34ce msgid "``host``: The host IP address to bind the TCP server to." msgstr "``host``: IP-адрес хоста, к которому будет привязан TCP-сервер." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 -#: 8dbeeea956834b28a5d13a47b9eaf651 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 +#: 7e419c2e704a44228bd0bdeed976d861 msgid "``port``: The port number to bind the TCP server to." msgstr "``port``: номер порта, к которому будет привязан TCP-сервер." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:40 -#: 3710af3c13574f088cd84d34ae8c83ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 +#: 854e298d71f140069b6ed51806224ca5 #, fuzzy msgid "" "``max_clients``: The maximum number of concurrent clients the server can " @@ -70,20 +70,20 @@ msgstr "" "``max_clients``: максимальное количество одновременных клиентов, которые " "может обслуживать сервер." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 -#: c92cda0f3bdb4f839ab24c2c65c926db +#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 +#: 203462f6b127478cb9bb0c2093362827 msgid "``port_add_step``: The step size for incrementing the port number." msgstr "``port_add_step``: Размер шага для увеличения номера порта." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 -#: 43155638bb1344798a37f85065d411ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 +#: 3d0355b5c1924055a7d8b6acb907fad0 msgid "``port_range_num``: The number of ports to check in the range." msgstr "" "``port_range_num``: количество портов в диапазоне, которые необходимо " "проверить." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 -#: 0459f804445d47519971903bce3e36eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 +#: a7852ea136454a1298541e96cdece1bc msgid "" "``max_file_transfer_thread_num``: The maximum number of threads for file " "transfer operations." @@ -91,8 +91,8 @@ msgstr "" "``max_file_transfer_thread_num``: Максимальное количество потоков для " "операций передачи файлов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:45 -#: 3103e7d29cb647f9922e0b507d47a171 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:49 +#: 0f1b0f03ffe2472cb58725dc446f6f7c msgid "" "``is_hand_alloc_port``: A flag indicating whether to manually allocate " "the port." @@ -100,8 +100,8 @@ msgstr "" "``is_hand_alloc_port``: флаг, указывающий, следует ли выделять порт " "вручную." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 -#: ee86acb3489f408ca9ba116a66c5ea3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:50 +#: 969ca405744f4d57a8e70db30eada3f7 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console." @@ -109,15 +109,15 @@ msgstr "" "``is_input_command_in_console``: флаг, указывающий, вводить ли команды в " "консоль." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 -#: d593644fa1664037b99afd05ecbf9cf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:51 +#: 6b01091b3f124b8d87c9423eb6998be4 msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "" "``max_custom_workers``: максимальное количество пользовательских рабочих " "потоков." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 -#: b46e9e9d9066432bbe75dc461b0f951f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 +#: c9d16d29465a48779ee2a54e4b9cc66e msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the server itself by calling " @@ -125,8 +125,8 @@ msgid "" "register its commands first and start the server later." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 -#: 60e4bd55be9940a48d6ae6421561fdaf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:56 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with clients are RSA-encrypted (see :ref:`tcp-server-encrypted-channel-" @@ -136,8 +136,8 @@ msgstr "" "которыми обмениваются клиенты, с помощью RSA (см. :ref:`tcp-server-" "encrypted-channel-api`)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:54 -#: c6dcdd076b864336834f8490c0a25708 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 +#: 3558d7e8c52442818701d4eb794b3643 msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -150,16 +150,30 @@ msgstr "" "игнорируется и вместо нее используется поиск по ключу по умолчанию («Нет»" " сохраняет поиск по умолчанию)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 -#: d0e99e1bc78f40f7af7470a66315bb04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:62 +#: 86265e57f3aa48e58e3fb5d9de0a9277 msgid "" "``max_mem_buff``: The in-memory buffering ceiling of the forward pump, " "given in MiB and stored as bytes (``self.max_mem_buff``); past it the " "uploading peer is told to pause. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:61 -#: 970d44aa127b40c7854cfc4dee215dcf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 +#: 7d4dd6bf4eff4f4db8ce0187088f172c +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:67 +#: 8fb93ff5bf2f49b18f2f42c92e66123f +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:69 +#: f12bacde2a874840879a51af63eeefde msgid "" "``is_asynic_clients_io``: A flag indicating whether clients are served by" " asyncio coroutines on one event loop instead of one thread per client. " @@ -167,73 +181,101 @@ msgid "" " of concurrent connections." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 -#: 269ce1f748d942949c0c20017fdf4a9b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 +#: 3a36a9bba6004a41b358be9975788707 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the server logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:68 -#: 09d8448517374602938d9ca4872e0356 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_print_log``: A flag indicating whether the server logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:71 -#: dc30e9a1ba5044319a3ed5ad1842b348 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 +#: 2994b78415964ff0adc713a4daed1b6b +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when a " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 +#: 9f9de22b50a94553ac1113f290dff1b4 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 +#: 8b0a1bb7ed944884854a936968f3b4bd msgid "All parameters have default values:" msgstr "Все параметры имеют значения по умолчанию:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 -#: 5774cd0576f349d18492b59a0b6d68bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:100 +#: 89299feb872b49758f7c9bf680114bbc msgid "``host``: Default is ``'127.0.0.1'``" msgstr "``хост``: по умолчанию ``'127.0.0.1'``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:74 -#: 4437fda8aa004d7483cefd29ad594bca +#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 +#: 38b84b10fc4d492497c3e0b20cb9fe8c msgid "``port``: Default is ``65432``" msgstr "``port``: по умолчанию ``65432``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:75 -#: 559c3b634b1043f2a6541f45eba488d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:102 +#: 3ccf25b3de4749a7ad73a1001fea86fb msgid "``max_clients``: Default is ``10``" msgstr "``max_clients``: по умолчанию ``10``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 -#: 8988cc48e66a472ebe8d505bdf8d6db9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:103 +#: 63455575485f4a25b4d2d2b83803e6b8 msgid "``port_add_step``: Default is ``1``" msgstr "``port_add_step``: по умолчанию ``1``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:77 -#: 063ec78e76b3439aafe539fad81a6036 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:104 +#: d8759c586e7143838c1ffe24c9fd6f62 msgid "``port_range_num``: Default is ``100``" msgstr "``port_range_num``: по умолчанию – ``100``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:78 -#: 4a3115c33bd349fba0768f79f18c47c0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:105 +#: a8020929e0f14b5394b6dd502b7a7b67 msgid "``max_file_transfer_thread_num``: Default is ``10``" msgstr "``max_file_transfer_thread_num``: по умолчанию – ``10``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 -#: fe7bf4015de045dcadc0024aef2bbdac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:106 +#: a9307e89f7cd471d96794bf7fbc9313c msgid "``is_hand_alloc_port``: Default is ``False``" msgstr "``is_hand_alloc_port``: по умолчанию установлено ``False``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:80 -#: 2529e795d9b0401d930f3c09766c56d5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:107 +#: 76084a80a458455bb952e8acad677eba msgid "``is_input_command_in_console``: Default is ``True``" msgstr "``is_input_command_in_console``: по умолчанию установлено ``True``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:81 -#: a95bee48d609469398e5a878b3d1e810 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:108 +#: f32a6549330a43f482e01def905e7415 msgid "``max_custom_workers``: Default is ``10``" msgstr "``max_custom_workers``: по умолчанию ``10``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:82 -#: c825fae2eaaa4afeaa551e65e4ea1ff1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:109 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_Server()`` automatically)" @@ -242,8 +284,8 @@ msgstr "" "``True``, ``__init__`` не будет вызывать ``start_TCP_Server()`` " "автоматически)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:84 -#: 0ab49ef330a94ecb80e160bbe0f00fe9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:111 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, client " "connections go through an RSA public-key exchange and all subsequent " @@ -253,8 +295,8 @@ msgstr "" "``True``, клиентские соединения проходят через обмен открытым ключом RSA," " и все последующие сообщения шифруются)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:87 -#: 6087b88026574d56aa37a817f0fe790a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:114 +#: c259e80f53a14b79a94190bcded7b30d msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -265,30 +307,56 @@ msgstr "" "предоставленная пользователем, вместо ``~/.ssh`` / сгенерированных ключей" " по умолчанию)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 -#: 26758c8f847b47c9839124e86e042349 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:117 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "``max_clients``: по умолчанию ``10``." + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:118 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "``max_file_transfer_thread_num``: по умолчанию – ``10``." + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_asynic_clients_io``: Default is ``False`` (when ``True``, every " "accepted connection is served by a coroutine on one asyncio event loop, " "and ``max_clients`` is ignored)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:93 -#: 79dca8f502bb4401952542fb3dba6939 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:122 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:95 -#: 656b6904625a4ea0977c85a93e62fd84 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:124 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "server would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 -#: a3fd35f818f84d7399b7d41208ff9319 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:126 +#: abd7d3032e15468e92f96a0b5af1f926 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:128 +#: 9b2bfa874c4e4969905923bd7aa0f80c +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 +#: ff0d716f8c6344408337c57ab32bad28 msgid "" "The TCP Server Setup API will initialize all the necessary parameters and" " resources for the TCP server." @@ -296,8 +364,8 @@ msgstr "" "API настройки TCP-сервера инициализирует все необходимые параметры и " "ресурсы TCP-сервера." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 -#: c38ba680fb704c4b9af31bcd33224c02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:134 +#: 06c57226c0e9415ab1618ae20a14f513 msgid "" "*Note: By default ``TCP_Server_Base.__init__`` calls " "``start_TCP_Server()`` to start the server automatically. If you set " @@ -310,8 +378,8 @@ msgstr "" "автоматически, и вам придется вызывать ``start_TCP_Server()`` вручную, " "когда будете готовы.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:112 -#: a0900d8246aa4cda80638035485659e5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:145 +#: e473a54dc4534e29ac4361429d24cb63 msgid "" "In the `start_TCP_Server` method, we first create a TCP server socket and" " bind it to the ``self.host`` and ``self.port`` which are initialized in " @@ -321,8 +389,8 @@ msgstr "" "привязываем его к self.host и self.port, которые инициализируются в " "методе __init__." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:116 -#: 4b6e513817d44c1d93cf1c39866ecf18 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:149 +#: 68dff731e96c46788af52f9c536a6d2f msgid "" "*Note: The server socket which is set up in the `start_TCP_Server` method" " is based on IPv4 form.*" @@ -330,8 +398,8 @@ msgstr "" "*Примечание. Серверный сокет, настроенный в методе start_TCP_Server, " "основан на форме IPv4.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 -#: b8a255c83b3346199c3197dd596427b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:152 +#: 1c6fc605850b4e988e7f5dac390f905e msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will start a thread to listen to the console input of the " @@ -340,13 +408,13 @@ msgstr "" "Во-вторых, согласно параметру self.is_input_command_in_console мы " "запустим поток, чтобы прослушивать консольный ввод сервера или нет." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:123 -#: bd35c2a4858f46ecb2f1ea1b7e987bb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 +#: 493d7ac50eb3446394da3c71f307b0a5 msgid "After that, a main loop to accept clients will be started." msgstr "После этого будет запущен основной цикл приема клиентов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:125 -#: 8b06edd210564df19035b30b72121c82 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 +#: 46f0159fb9a84874959c103ac08656f5 msgid "" "*Note: there is another global variable ``self.running`` which is set to " "``True`` after the server socket is successfully created. The " @@ -360,8 +428,8 @@ msgstr "" " циклом TCP-сервера, и ей будет присвоено значение ``False``, когда " "сервер выключается.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 -#: 0920728e22cf4fdcbd6b6a5f32b251d4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:164 +#: ed335af1339644a090d7fc4ebdc859f1 msgid "" "With ``is_asynic_clients_io=True`` the main loop is the asyncio event " "loop instead: it accepts clients in non-blocking mode and schedules one " @@ -369,8 +437,8 @@ msgid "" " `stop` releases it so the loop can end." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:136 -#: ca2a678a5119456daf70ba9c6bcfacf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:169 +#: 613624f457b847f994b739812b6e7aed msgid "" "The main loop of the TCP server setup function first checks whether the " "number of connected clients exceeds the maximum number of clients. The " @@ -382,8 +450,8 @@ msgstr "" "Максимальное количество клиентов определяется аргументом self.max_clients" " класса TCP_Server_Base, который инициализируется в ``__init__``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:141 -#: 295d9fd021d94b94b5bb5e3290af9b94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:174 +#: d6142df9dee34a85a449a322bcfc5729 #, fuzzy msgid "" "If the number of the clients is already over the limit of the connect " @@ -397,8 +465,8 @@ msgstr "" "превышен, сервер настроит функцию обработчика клиентов handle_client, а " "функция обработчика сервера определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:153 -#: a15c83c5c9984e68b88602f6a3c56d16 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:186 +#: e0d97e64db41406aa120fbdcd2ee5bb3 msgid "" "*Note: For more details of the `handle_client` function, see the :ref" ":`tcp-server-handling-information-api` section.*" @@ -406,13 +474,13 @@ msgstr "" "*Примечание. Более подробную информацию о функции handle_client см. в " "разделе :ref:`tcp-server-handling-information-api`.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 -#: 4e4b61d041b24075b90f598ef42bbe78 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:189 +#: 686ed007e14d4a98b931c0c651bb7bf5 msgid "So what can the setup function do if it fails?" msgstr "Так что же может сделать функция настройки, если ее запуск не удался?" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 -#: bfc7899a0ec649d49c956d569bbad0bc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:191 +#: 189abee61a444611a486dec294da6561 #, fuzzy msgid "" "First, the try-except block in the main server loop checks whether the " @@ -422,8 +490,8 @@ msgstr "" "является ли ошибка ``OSError``. Если это так, основной цикл завершится " "напрямую." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:162 -#: 8a3a4854f3a3441b87d0257cb4eb4e52 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 +#: e4e1ba68f4b64dc280490157405acab9 #, fuzzy msgid "" "Secondly, if the error is from the network socket, it first logs the " @@ -434,8 +502,8 @@ msgstr "" "сообщение об ошибке, а также остановит сервер, вызвав функцию «stop». И " "функция остановки была определена как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:171 -#: 4eb334cfa82e4557b51ed511bb35fea1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:204 +#: 9eb5b6fb9d2e4394b3dbb4a1905767d0 msgid "" "To stop the TCP server, it first sets the ``self.running`` variable to " "False, to stop the main loop of the server. After that, it calls the " @@ -447,8 +515,8 @@ msgstr "" "После этого он вызывает функцию free_port, чтобы освободить выделенный " "порт. И `free_port` был определен как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:182 -#: 2d0515291a604c0996149873392657f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:215 +#: 18d7078902794d629ad9f4e92a334402 msgid "" "*Note: For more details of the `free_port` function, see the :ref:`tcp-" "server-port-allocation-api` section.*" @@ -456,8 +524,8 @@ msgstr "" "*Примечание. Более подробную информацию о функции `free_port` см. в " "разделе :ref:`tcp-server-port-allocation-api`.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:185 -#: ee8148b7ac254bbba148a8ad7a4ebb94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:218 +#: dc449dddb5014d40a50ff66277707822 #, fuzzy msgid "" "At the end of the operations, the TCP server closes all client sockets " @@ -468,8 +536,8 @@ msgstr "" "учтены в словарной переменной self.clients, а также закроет сокет " "сервера." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:188 -#: e3cce971756a4931af9b546a1e12aeb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:221 +#: 1d2d730ca10e484d9dadc386b02af66c msgid "" "Before closing the listening socket it shuts it down, which releases a " "thread that is blocked in ``accept()`` (closing alone would leave the " @@ -480,8 +548,8 @@ msgid "" "come up behind the caller's back." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 -#: eb7d0cdf9cb4455eab2a5ba068942fd5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:228 +#: 2975a8e2dfe646cc92f5b112afc6101f msgid "" "*Note: The ``self.clients`` variable is a dictionary that maps client " "address tuples to an info dictionary. The key is the client address tuple" @@ -497,13 +565,13 @@ msgstr "" "``'address'``, ``'id'`` и ``'connected_time'``. См. пример ниже, " "показывающий, как хранятся записи.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:217 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 +#: 8936cbe70fcf44ac9cabec9e38c0195d msgid "TCP Server handling information API" msgstr "API обработки информации TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:219 -#: 45ece19ab8684f67b0f85203f442103e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 +#: 1bbc64aa745a4dc3a537c6c10fd9e3c5 msgid "" "The server handling information API documents the core TCP server methods" " that manage client sockets, receive raw data, and send messages." @@ -512,8 +580,8 @@ msgstr "" "TCP-сервера, которые управляют клиентскими сокетами, получают " "необработанные данные и отправляют сообщения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:231 -#: 4603ad1e2ffc400491456f7abf750937 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:264 +#: 8b1b042f66a243d9b9abd829a3fefcfe msgid "" "`handle_client` is the main per-client handler in ``TCP_Server_Base``. It" " is invoked after a client connection is accepted and is responsible for:" @@ -522,8 +590,8 @@ msgstr "" "«TCP_Server_Base». Он вызывается после принятия клиентского соединения и " "отвечает за:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:235 -#: dbeed4ea23664ab298a9c5e356642ddc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:268 +#: 67121b0c979f421eb7ddbfb432dad873 msgid "" "adding the client entry into ``self.clients`` with socket, address, id, " "and connected time" @@ -531,18 +599,18 @@ msgstr "" "добавление записи клиента в self.clients с указанием сокета, адреса, " "идентификатора и времени подключения" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:236 -#: 98d885826d6743a0ad2c72f44e0e9944 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:269 +#: 65ac2e1844dd4a86a5e550063ee90460 msgid "printing connection information and current client count" msgstr "распечатка информации о соединении и текущего количества клиентов" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:237 -#: f9a1536ee7a540d693a2f4f4b3ad690c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:270 +#: 21670e3d261c41b4a0cbf772ab3f0d73 msgid "sending a welcome message to the client" msgstr "отправка приветственного сообщения клиенту" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:238 -#: e75d30ed5656490994353520e09cf789 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 +#: a48af59d8ef54c12929e843db0d51e01 #, fuzzy msgid "" "sending the ``/client_alloc_port_range`` information to that client " @@ -551,8 +619,8 @@ msgstr "" "широковещательная рассылка информации ``/client_alloc_port_range`` всем " "клиентам в зависимости от режима выделения портов" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:241 -#: 0e3762f344ff4b88bbb6699610627b41 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 +#: 034082645d394f158d8927076c6b38e9 #, fuzzy msgid "" "*Note: You can specify the port allocation mode in the arguments which " @@ -565,37 +633,37 @@ msgstr "" " можете изменить, являются ``port_add_step``, ``port_range_num`` и " "``is_hand_alloc_port``.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:247 -#: 3a8f9b23f43a469ca5d7cea807598bd6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:280 +#: 2cb1bb2c2ed84122a479e562a1156bf3 msgid "receiving raw bytes from the socket using `receive_message`" msgstr "получение необработанных байтов из сокета с помощью `receive_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:248 -#: 8f1c9c44d13e41d1b4fdadac75fc4613 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:281 +#: f4db70de0d7d4b4f9f02a1fc2325b172 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "" "буферизация входящих данных до тех пор, пока сообщения, завершающиеся " "новой строкой, не будут завершены" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:249 -#: 54fef48b6314483cbd813885b82ead02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:282 +#: c17ac3c5095746448b497f228eb10c88 msgid "splitting and processing each message line-by-line" msgstr "разделение и обработка каждого сообщения построчно" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 -#: f7728d56338d464cad635232865f9fb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:283 +#: ba1a3439be1d43af80a46d2ee3658ac8 msgid "routing special commands beginning with ``/`` to `handle_command`" msgstr "" "маршрутизация специальных команд, начинающихся с ``/``, в " "``handle_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 -#: f87fc68b008a4e06a719e9ab316016f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 +#: 37462f705b094332a79be9d2765c4796 msgid "The `handle_command` function is defined as:" msgstr "Функция handle_command определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:263 -#: 8b47f53ad413459393250da7b5f249eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:296 +#: d5bdce3eed0b4171882356d2b207f6d2 #, fuzzy msgid "" "In `handle_command`, there are variable conditional branches to handle " @@ -610,8 +678,8 @@ msgstr "" "дополнительные команды с помощью API расширения команд, функция " "определит, соответствует ли введенное сообщение командам расширения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 -#: 1b5f22ecb31f4b17bc31eeba617e9373 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 +#: 21bedf659c7c44a783ed367bebbec813 msgid "" "*Note: For more details of the command extension API and the built-in " "commands, see the :ref:`tcp-server-command-api` section.*" @@ -619,13 +687,13 @@ msgstr "" "*Примечание. Более подробную информацию об API расширения команд и " "встроенных командах см. в разделе :ref:`tcp-server-command-api`.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 -#: f4e3e8921f9c4825b54b7e26c77dfaa1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:307 +#: 85099f44cbb14013a55dcaf602370b51 msgid "logging normal chat messages and acknowledging receipt" msgstr "регистрация обычных сообщений чата и подтверждение получения" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:275 -#: e25f3746f80f4046a7aeb5f0b61bba85 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:308 +#: c4a9e9f9ccd74f0ca064b3fe6a95e739 msgid "" "removing the client from ``self.clients`` and closing the socket when the" " client disconnects or an error occurs" @@ -633,8 +701,8 @@ msgstr "" "удаление клиента из self.clients и закрытие сокета при отключении клиента" " или возникновении ошибки" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 -#: 21e6108f8c1243a39f017b806967fb1d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:318 +#: 5f6ae0695302473a8adf476a72c72d3a msgid "" "`receive_message` is a thin wrapper around socket receive operations. It " "reads up to ``msg_length`` bytes from the given ``client_socket`` and " @@ -646,8 +714,8 @@ msgstr "" "необработанные полезные данные. Декодирование сообщения и кадрирование " "сообщения новой строки обрабатываются вызывающей стороной." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:300 -#: b7e713b412334cc98292e1ca8abbf861 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:333 +#: 114485120bad452e8af2626995798eda msgid "" "`send_message` sends data back to a specific connected client. It " "verifies the server is running and the socket is valid, then:" @@ -655,20 +723,20 @@ msgstr "" "`send_message` отправляет данные обратно определенному подключенному " "клиенту. Он проверяет, что сервер работает и сокет действителен, затем:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:303 -#: 923c92c05c79407e841f3a5d6fefeb92 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:336 +#: 78639cd82b2f42db9ddd7d84bf06e9ee msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "принимает полезную нагрузку сообщений как ``str``, так и ``bytes``" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 -#: f890eeb62bbc4b5ab359452c6dd40b17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:337 +#: bff4a398dec3443391a0c6e6a9fb00ee msgid "trims string payloads and appends a newline if missing" msgstr "" "обрезает полезные данные строки и добавляет новую строку, если она " "отсутствует" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:305 -#: 21a1156ab51b4dc598f583c1d9f9defc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:338 +#: 033e533bc19f484bb0fe7d61fe01dc46 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -680,29 +748,29 @@ msgstr "" "шифруется с помощью открытого ключа партнера, кодируется в формате Base64" " и заканчивается новой строкой вместо отправки в открытом виде." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:309 -#: 94980e8ed8db4bfeb6bb4f4278c10d04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:342 +#: 1f1be9fb9dff4409aa040671a8e89013 msgid "encodes string payloads as UTF-8" msgstr "кодирует строковые полезные данные как UTF-8" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:310 -#: ce93763396994dbabdc93a51b56ed8c3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:343 +#: 38c4b6970f644bf6b1dee52c1d6f7157 msgid "" "sends the message with ``client_socket.sendall(data)`` when the server " "serves clients with one thread each, or through a non-blocking ``send()``" " loop when ``is_asynic_clients_io`` is ``True``" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:313 -#: eb3454d6feb84ce1a3e00a573cf20972 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 +#: b3f2ff47fdc74a1fb5b599b1f3706a59 msgid "" "returns ``True`` on success; it returns ``False`` for an unsupported " "payload type, and an invalid/closed connection raises ``RuntimeError`` " "(other socket failures are logged and re-raised)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:317 -#: 62174575716644e69c0d479ff05a9df0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:350 +#: 042c1637a86c494ca7da9ba4299b08be msgid "" "And there are also some other functions which are used to send message in" " bulk to the clients, such as the `broadcast` function and the " @@ -712,13 +780,13 @@ msgstr "" "отправки сообщений клиентам, такие как функция Broadcast и функция " "send_msg_to_specific_client." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:325 -#: 762f3bf7c5bb46e091ca12b1f0393624 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:358 +#: eeecf353189a46f8972335c059bef718 msgid "TCP Server encrypted channel API" msgstr "API зашифрованного канала TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:327 -#: 67ffdc91d9694e77ab33c0c60253430d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:360 +#: e5659287613a419dbbecdc491f57b514 msgid "" "When the server is created with ``is_enable_encrypto=True`` (the " "default), every connected client goes through an RSA public-key exchange " @@ -728,13 +796,13 @@ msgstr "" "умолчанию), каждый подключенный клиент проходит обмен открытыми ключами " "RSA, прежде чем какое-либо содержимое сообщения будет зашифровано." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:332 -#: 8de167f009be4406b25e0e3d3be6cb4b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:365 +#: a31863451ad94e828e4d5826811dc4e9 msgid "Key material" msgstr "Ключевой материал" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:334 -#: 01312565566c4707b6d4b55a223882d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:367 +#: aae09222bb4b42dfb9db4c7ebc329d10 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -749,8 +817,8 @@ msgstr "" "закрытого ключа, поэтому повернутая пара ``~/.ssh`` подбирается " "автоматически." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:339 -#: 5e641bcd12c44f73bd22b43332b12b91 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:372 +#: f4206182556e4cca9a9284905e3de143 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -761,8 +829,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 -#: 26f407b8ad29482ca30db4edd0f20abe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:379 +#: bab30142a34845e5b01353a55c4ba643 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -777,8 +845,8 @@ msgstr "" "закрытого ключа); недопустимая пара игнорируется и используется поиск по " "умолчанию." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:351 -#: 3af59fcb848044718426e6b9427c017d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 +#: 324dcdafcfa048218e102466956bd1a5 msgid "" "Public keys received from clients are cached in " "``network_api/.Flow/pub_key`` as ``client__.pem`` (the peer " @@ -791,13 +859,13 @@ msgstr "" "``_``, поэтому литералы IPv6 безопасны на любой платформе, включая " "Windows)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:357 -#: 26ea5ad884b4402097ce3f800bb7e8d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:390 +#: aee5a1316ad24fab8db1dedeb6c95790 msgid "Anti-MITM identity check (TOFU)" msgstr "Проверка личности Anti-MITM (TOFU)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:359 -#: 69fe026672cc44c7b931a2a404468eb0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:392 +#: 8ceb7ab10998464e93c80c1609797ac7 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -813,8 +881,8 @@ msgstr "" " Python конечной точки, из которой подключен одноранговый узел), значение" " - ``[, <открытый ключ PEM>]``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:366 -#: f8e45fa616844ba287ea1d9a249d5157 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:399 +#: e63b24b8eded401fb82be09174963c1b msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." @@ -822,8 +890,8 @@ msgstr "" "Первое соединение с конечной точки: ключ записан и ему доверяют (доверие " "при первом использовании)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:368 -#: faa949fc11b74c9692009fba21d3a5f2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:401 +#: 9c091413145845f3b15fac0bdc9b583c msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " @@ -834,8 +902,8 @@ msgstr "" "пользователем), запись перемещается в новый ``(ip, порт)`` вместо " "дублирования." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:371 -#: d80fbe47d78343d6a5ae8b7a7388b177 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:404 +#: d89337a304a24744a703acaa977b3290 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is sent and the " @@ -845,8 +913,8 @@ msgstr "" " точки: соединение отклоняется (отправляется ``/crypto_reject`` и сокет " "закрывается)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:375 -#: c12761b71fbb40e9b5d9f17ce7389981 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:408 +#: ff44ccbece9b48ab8e86a12cba949078 msgid "" "Because the server-side record is keyed by the client's source port, a " "client that rotates its keypair is only detected when it reconnects from " @@ -865,13 +933,13 @@ msgstr "" "Чтобы сбросить доверие (смененные ключи, новый сервер), удалите запись " "``pub_key.json`` (или весь файл)." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 -#: 160b797ceb5340aaa631e6a42ed052f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:417 +#: e011f68df76445d18659be173dba1877 msgid "Handshake" msgstr "Рукопожатие" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:386 -#: 6f031912413e4e4b8b7105c3c59f1b99 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:419 +#: 700f2215924f4bfb92c3f90f37c3e514 #, fuzzy msgid "" "The client initiates the exchange by sending a plaintext " @@ -880,12 +948,16 @@ msgid "" "Both sides then push their public key files over the file-transfer " "mechanism (plaintext) and TOFU-check the received key. Both sides switch " "to encrypted mode only after ``/crypto_ready`` has been received from the" -" peer (so plaintext and ciphertext never interleave on a connection). On " -"later connections the keys are re-exchanged and TOFU-checked again; the " -"exchange is never skipped, only the identity check short-circuits for " -"known keys. Public-key pushes are only accepted from a connection that " -"actually started the handshake, so an arbitrary unauthenticated peer " -"cannot poison the registry." +" peer (so plaintext and framed traffic never interleave on a connection)," +" then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted from a connection that actually started the " +"handshake, so an arbitrary unauthenticated peer cannot poison the " +"registry." msgstr "" "Клиент инициирует обмен, отправляя открытое текстовое приветствие " "``/crypto_key_exchange``; сервер отвечает ``/crypto_key_exchange_ack " @@ -898,39 +970,58 @@ msgstr "" "повторно обмениваются и снова проверяются TOFU; обмен никогда не " "пропускается, только проверка личности сокращает известные ключи." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:400 -#: 1efd337c73d249a3b4b15394337e6307 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:437 +#: a9531ad5339a4633a1e6cc54fb8bb79b msgid "Replay protection" msgstr "Защита от повтора" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:402 -#: 28c8ec1c26d946a19bc02d6aacc9961b -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." -msgstr "" -"При рукопожатии происходит обмен случайным одноразовым номером сеанса, и " -"каждая зашифрованная строка в сети содержит его плюс порядковый номер для" -" каждого соединения: ``||``. Получатель " -"удаляет строку, nonce которой не соответствует текущему сеансу " -"(зашифрованный текст воспроизводится из более старого соединения) или чей" -" порядковый номер не является ожидаемым (зашифрованный текст " -"воспроизводится внутри сеанса/не в порядке); оба счетчика сбрасываются, " -"когда сокет переключается в зашифрованный режим после (повторного) " -"обмена." - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:411 -#: c11de683c36c42c59ff73d0839f5afce +#: ../../source/Network_APIs/TCP_Server_APIs.rst:439 +#: e9505df5322640ce8671b5098d655374 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:455 +#: 3fd7ac4d381e41589a62998726dd22f7 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:457 +#: 8ca69d91005b459a8a56f21902eaa690 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:469 +#: b32b4fa4788d4f9d88926958c81ad73f msgid "Decode verification and key rotation" msgstr "Проверка декодирования и ротация ключей" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:413 -#: ba7b28826b9f4d0a85328f08be4a76e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:471 +#: d09ae3121b0f40fb85374589b851d45c msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -956,14 +1047,19 @@ msgstr "" "(или весь файл) на стороне однорангового узла, чтобы повторно доверять " "новому ключу." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:424 -#: 6f0160000f2b451a81771556bbc3b8e7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:482 +#: 7312fb4bd4c345ff9cec7ffe4245afb7 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures on one connection the connection is closed " "instead of re-exchanging, so a garbage-injection or persistent-mismatch " -"storm cannot spin the loop forever. A successful decryption resets the " -"counter." +"storm cannot spin the loop forever. Genuine peer traffic (messages and " +"commands other than the protocol's own handshake/coordination lines) " +"resets the counter. Frames the peer had already sent when this side " +"dropped out of encrypted mode are stale: they cannot be authenticated any" +" more, so they are consumed and dropped — they neither surface as " +"messages nor reset the counter." msgstr "" "Повторный обмен является разрывом цепи: после ``MAX_DECODE_FAILURES`` (3)" " последовательных ошибок декодирования в одном соединении соединение " @@ -971,8 +1067,8 @@ msgstr "" "постоянного несоответствия не могут вращать цикл вечно. Успешная " "расшифровка сбрасывает счетчик." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:438 -#: 850c5c67b6504551a3104a9cfa5710e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 +#: 4fb05c76f6734fd58aa33ee628ad933d #, fuzzy msgid "" "The `broadcast` function sends a message to all clients in the " @@ -987,8 +1083,8 @@ msgstr "" "сервер исключит клиента, указанного параметром exclude_client, при " "отправке сообщения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:452 -#: 9ddd28be0e6b439891a25d79adbaf823 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:514 +#: 0b4f67331831429b85514fbbe3ce2602 #, fuzzy msgid "" "The `send_msg_to_specific_client` function sends one or more messages to " @@ -1003,8 +1099,8 @@ msgstr "" "идентификаторам клиентов. И в аргументы ``message`` следует ввести " "команду отправки сообщения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:459 -#: 4f7cd128081c4062bffdacfb4b67137c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 +#: c8f357719cc548719792a5a2cade0c03 msgid "" "These methods form the server's client I/O loop and ensure reliable " "message exchange for connected TCP clients." @@ -1012,34 +1108,36 @@ msgstr "" "Эти методы образуют цикл клиентского ввода-вывода сервера и обеспечивают " "надежный обмен сообщениями для подключенных TCP-клиентов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:466 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 +#: 8936cbe70fcf44ac9cabec9e38c0195d #, fuzzy msgid "TCP Server inbound event listener API" msgstr "API передачи файлов TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:468 -#: f86e7c53407b43509932d19288024a54 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 +#: 583ef0a34dfc480da5b4fc87108cbf2f msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:478 -#: f59f2230d9f648ca99834633af460deb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:540 +#: 0a30ecd70b364968a892136d9bec809f msgid "" "``add_message_listener`` registers ``listener(client_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to the command handlers instead). ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a" -" file uploaded by a client has been fully written to the transfer " -"directory (``command`` is the wire command that triggered it, so protocol" -" pushes such as ``/crypto_pub_key`` can be recognised). Both listeners " -"run on a protocol thread, so they must not block, and an exception inside" -" a listener is logged and swallowed. The ``remove_*`` counterparts " -"unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:489 -#: a39677d08af4439989a6fced80cb12d1 +"every inbound line, commands included (``/help``, ``/file ...``, the " +"crypto handshake lines, ...), so a listener observes all inbound traffic;" +" line dispatch is unaffected, a command still goes to the command " +"handlers. ``add_file_listener`` registers ``listener(client_id, " +"full_path, name, size, command)`` and fires after a file uploaded by a " +"client has been fully written to the transfer directory (``command`` is " +"the wire command that triggered it, so protocol pushes such as " +"``/crypto_pub_key`` can be recognised). Both listeners run on a protocol " +"thread, so they must not block, and an exception inside a listener is " +"logged and swallowed. The ``remove_*`` counterparts unregister a listener" +" and ignore unknown ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:553 +#: a7bb1a9276bd4860882ffd43a680d6bf msgid "" "In addition, received messages and events are stored per sender socket in" " ``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -1048,13 +1146,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``stop`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:498 -#: cdfe98e71ed34af9a2976b7e884b5201 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 +#: 403a3b0e938b4895be69267c66ecff98 msgid "TCP Server command API" msgstr "Командный API TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 -#: 25c853b63e744fd6a370ecd365c58fd7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 +#: 9c016262f199458585bb12055da6d30d msgid "" "The server supports several built-in commands and a command extension " "API. The main entry point is the `handle_command` method, which is " @@ -1064,20 +1162,21 @@ msgstr "" "Основной точкой входа является метод handle_command, который вызывается " "для любого сообщения, начинающегося с ``/``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:505 -#: d0e290f03c1242b580024033ffab5e04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 +#: b26b06ec49a644c9b034acf6930006bd #, fuzzy msgid "" "We support two solutions for command handling: inputting a command in the" " console or receiving a command from other clients. You can also call the" -" functions defined for each command in the code." +" functions defined for each command in the code via " +"`call_extension_functions`." msgstr "" "Мы поддерживаем два решения для обработки команд: одно — ввод команды в " "консоль, а другое — получение команды от других клиентов. Вы также можете" " вызывать функции, определенные для команд в коде." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:510 -#: aad12adb23334f4e9c5b6b7f7637dd3e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:575 +#: 5f20432236324511acfc720b1e616e49 #, fuzzy msgid "" "*Note: You can select the solution which you want to use by changing the " @@ -1090,46 +1189,46 @@ msgstr "" "is_input_command_in_console. ``True`` разрешает серверу вводить команду в" " консоли, а ``False`` запрещает.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:517 -#: 88e051e4fef245c7a474a8478dc74b88 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:582 +#: cc5dd7cfa448466399da9463e53c1a08 msgid "Built-in client commands include:" msgstr "Встроенные клиентские команды включают в себя:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:519 -#: c8a591e28fcf4243862e820e582e9127 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:584 +#: 989d1b29c70e4f9883b95523b0b420d9 msgid "``/help``: returns the available command list and usage hints." msgstr "" "``/help``: возвращает список доступных команд и подсказки по " "использованию." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:520 -#: 453004b0bb914398a4d9a437f5d1b864 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:585 +#: a4795afd8b3249538f031ed27783f0a7 msgid "``/time``: returns the current server time." msgstr "``/time``: возвращает текущее время сервера." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 -#: 324cbdab33984517a498f1e2747a6387 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:586 +#: b2d813b2d8bb46c59195ed01431d150b msgid "``/clients``: returns the list of connected client IDs." msgstr "``/clients``: возвращает список идентификаторов подключенных клиентов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:522 -#: a4411c0f498c434fbe864ea1627384fb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:587 +#: d81ad6c5cbe44bd589f32ce7f3e36d31 msgid "" "``/quit``: writes a goodbye message (``Bye!``) and shuts the connection " "down, so a client that stays after sending ``/quit`` is disconnected by " "the server." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:525 -#: 1248e1b365da420e8d96182e8a237d57 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:590 +#: a9fbf429095b4483b18a247ef327b461 msgid "" "``/file [destination_file_path]``: starts a file transfer " "from the client to the server. The trailing token of the wire line is the" " sender's own transfer id, appended by the sending client." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 -#: c8de5282934945bab929e1084d7848f5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 +#: cef48a93703449f8813fab1d3fb199fb #, fuzzy msgid "" "``/file_folder [destination_file_path]``: starts a folder " @@ -1138,22 +1237,34 @@ msgstr "" "``/file_folder ``: запускает запрос на передачу " "папки с клиента на сервер." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 -#: d006c91db83f4404b7f7022cb9bb61c5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:595 +#: 92bf2736c9c14f1cb24ec110315f8caa msgid "" "``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``:" " internal handshake messages of the encrypted channel." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:532 -#: c026024882d44552a578b0fe4e096b34 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:597 +#: 38987654adbf4707b84c8048a9cdcbb3 msgid "" "``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, " -"``/start_trans``: internal forwarding/transfer-control messages." +"``/start_trans``: internal forwarding/transfer-control messages. " +"``/pause_trans `` and ``/start_trans `` hold and release the " +"outbound transfer with that fid (`pause_trans`/`start_trans` are the same" +" switch as a public API)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:534 -#: 5fb7405e0dae4344a58d3a61aa5f2779 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:601 +#: 7f3801d57ac34670bbe16736683db30e +msgid "" +"``/resume_trans `` and ``/forward_resume " +"``: internal transfer-reconnect messages: the receiver asks the " +"sender (or, for a forwarded transfer, the originator) to continue the " +"file from the bytes already on disk. See `resume_transfers`." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:605 +#: abd7d3032e15468e92f96a0b5af1f926 msgid "" "``/server_file_transfer_port ``: internal protocol " "message used to coordinate file transfer ports." @@ -1161,8 +1272,8 @@ msgstr "" "``/server_file_transfer_port <порт> ``: сообщение внутреннего " "протокола, используемое для координации портов передачи файлов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:536 -#: 94f93b06051f4eebaf0b64ccf589160b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:607 +#: 1e9e32071bb1425b8617a419a7ef87f6 msgid "" "In `handle_command`, the server will first check if the command matches " "any built-in commands. If it does, the `handle_command` will call the " @@ -1172,8 +1283,8 @@ msgstr "" "каким-либо встроенным командам. Если это произойдет, `handle_command` " "вызовет функции, определенные для команд." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:541 -#: 16991ef553344476af487507dc3a1a0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:612 +#: f08564b44ab0442788145105b1086bb8 msgid "" "If a command is not recognized by the built-in handler, `handle_command` " "will check if it matches any registered custom commands from the command " @@ -1187,18 +1298,26 @@ msgstr "" "зарегистрирована, «handle_command» вызовет функцию, определенную для этой" " команды. API расширения команд определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:559 -#: 9c0334fe21e34b6ab8b1c941e1c62e2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:633 +#: ac06208b93d54ede93002123521d921b +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code; the command's first token selects it, exactly as it does for " +"a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:637 +#: 11c186c6375b4eeeb337ac755b136a94 msgid "The args of the `register_command` function are as follows:" msgstr "Аргументы функции `register_command` следующие:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 -#: ac4db02fce3d492b81a094400f44b0a8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 +#: 6741d64e02414c1c8759b14d41ec69a1 msgid "``command_name``: The name of the command to register." msgstr "``command_name``: имя регистрируемой команды." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 -#: 8e250a4664ce40c89f0190ce7eb67848 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:642 +#: 21a28c492d33486a81f97ca3d8a32266 msgid "" "*Note: The ``command_name`` should start with a slash (e.g., " "``/my_command``) to be recognized as a command.*" @@ -1206,13 +1325,13 @@ msgstr "" "*Примечание: ``имя_команды`` должно начинаться с косой черты (например, " "``/my_command``), чтобы его можно было распознать как команду.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:567 -#: f91cdc45f9ea4c35891b087f1097ba51 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:645 +#: 6deb6588265049cbbeaea615b7d6c2cf msgid "``handler``: The function to call when the command is received." msgstr "``handler``: функция, вызываемая при получении команды." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 -#: 1797ec404bbe45b380d46588adbb731f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:647 +#: 16d22c49f16d4430bfe740374d70705f #, fuzzy msgid "" "*Note: The ``handler`` function must have exactly three parameters: " @@ -1229,13 +1348,13 @@ msgstr "" "команду, а параметр ``command`` будет содержать фактическую командную " "строку.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:577 -#: 56b8f72098b84ccea4d1bf143a31e04c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:655 +#: 7605062541fa4d70ae37d67efdfd5fdf msgid "``where_to_run``: Specifies where the command should be executed." msgstr "``where_to_run``: указывает, где должна быть выполнена команда." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:578 -#: 7572e9944acd4704b2c55643fb1fbcd4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:656 +#: f6ee42356212497ba468266c87e127d4 msgid "" "``run_in_thread``: A boolean indicating whether to run the command in a " "separate thread." @@ -1243,8 +1362,8 @@ msgstr "" "``run_in_thread``: логическое значение, указывающее, следует ли запускать" " команду в отдельном потоке." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:580 -#: 0ac212e49ef54e77b5429272e05561aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:658 +#: 37adfd2db6af47bf995b271dd70ad293 msgid "" "This extension API allows server-side and console-side custom commands to" " be registered dynamically. Valid values for ``where_to_run`` are " @@ -1260,8 +1379,8 @@ msgstr "" "означает, что команда будет обработана, когда сервер введет команду в " "консоль." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:589 -#: c0201e2dd3fd4c7fa8d363060c5ff49a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:667 +#: 24c64499179b4f01a92ffd8e88515738 #, fuzzy msgid "" "*Note: It's true that the valid values for ``where_to_run`` are not " @@ -1270,8 +1389,8 @@ msgstr "" "*Примечание: это правда, что допустимые значения для ``where_to_run`` " "слишком странные, но мы не нашли лучшего способа определить это.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 -#: ec3b9b188728413eb3cd5871542b83cd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:671 +#: fbdb162f54a64fd3b454ddbf85a6e5d4 #, fuzzy msgid "" "The ways to run the command will be different according to the args " @@ -1287,8 +1406,8 @@ msgstr "" "сервера. Если ``run_in_thread`` имеет значение ``False``, обработчик " "команд будет выполняться синхронно в главном потоке сервера." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:603 -#: 0a62647e915e4e4c80071b3d7fb41464 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:681 +#: 9576b9601ddd48749947aa7b18bc2c82 #, fuzzy msgid "" "*Note: We store the registered commands in a list variable with two " @@ -1315,16 +1434,16 @@ msgstr "" "инициализируется в методе __init__. Она содержит все команды, которые " "должны выполняться в отдельном потоке или нет.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:617 -#: eb202f79be654e5a8cccf56c79446b3d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:695 +#: b1f239408f354bf2bdc608ad523f233e msgid "" "*Note: ``register_command`` returns ``False`` when ``where_to_run`` is " "neither ``\"server\"`` nor ``\"client\"`` (nothing is registered then); " "on success it returns ``None``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:626 -#: 088dcc7ce39046a4afa6451d7e6369f9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:704 +#: b10dad811f9b444bb0a2e3642709b5d1 msgid "" "After that, the command handler will be called according to the command " "name, and run them by a command executor which is defined as:" @@ -1332,8 +1451,8 @@ msgstr "" "После этого обработчик команд будет вызываться в соответствии с именем " "команды и запускать их исполнителем команды, который определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 -#: 0e56345aa429469cb44d7708b6af8711 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:718 +#: 7c0987568cf245b9b78d1db2f403717f msgid "" "In this executor function, there is a try-except code block to catch the " "error when running the command handler. If there is an error when running" @@ -1351,8 +1470,8 @@ msgstr "" "обработчик команды с аргументами команды, а также сокетом клиента и " "адресом клиента, если команда поступает со стороны клиента." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:650 -#: 6467226e231c4e458bb78687c9da8659 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:728 +#: a98408c31eee4f3fbad1c3afdb2a036c #, fuzzy msgid "" "If the command doesn't run in the thread, the command executor will be " @@ -1367,8 +1486,8 @@ msgstr "" " потоков сервера с использованием метода submit_task, который " "определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:665 -#: fb9ac9433b8342dd9e90707a01990fd0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:743 +#: c3401f2293044a31a7e8e6d2e8407797 #, fuzzy msgid "" "The `submit_task` method is a helper function that submits a callable to " @@ -1385,8 +1504,8 @@ msgstr "" "потоке. Это позволяет запускать длительные или блокирующие обработчики " "команд без блокировки основного цикла сервера." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:675 -#: 711e7a3b8f114200857fc39218e2820f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 +#: 9a327fd5482b4575a777e49024f42f56 msgid "" "In this high-level TCP network protocol, a temporary TCP server and " "client can also be created very simply. The temporary TCP server or " @@ -1402,8 +1521,8 @@ msgstr "" "клиентским циклом. Например, функции передачи файлов. API для создания " "временного TCP-сервера и клиента определяются как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:688 -#: 7368e712e93f4be7aaeeae265b22e832 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:766 +#: b1e9ab095ed84ef8ae08333047df5b93 msgid "" "``create_temporary_server`` returns ``(port, thread, stop_event)``: the " "bound port (``palloc()`` picks one when ``port`` is None), the accept-" @@ -1412,21 +1531,21 @@ msgid "" " allocated." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:693 -#: 0750bd372cf6478eb8123ca0603de9c2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:771 +#: d23ff87180c44746b62528903a34cdb5 msgid "" "``create_temporary_client`` returns ``(client_socket, thread, " "stop_event)``: the connected socket, the receiver thread and an event " "whose ``set()`` ends that thread." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:700 -#: edf78b86ed664657adc2b46ab0f7efdd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:778 +#: c14e33129d3b41ee8c1dac7189f0408d msgid "TCP Server console commands" msgstr "Консольные команды TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:702 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:780 +#: 2ad09a3887894e01a67d31c28272f730 msgid "" "The server console input thread accepts administrative commands when " "``is_input_command_in_console`` is ``True``. Supported console commands " @@ -1436,23 +1555,23 @@ msgstr "" "``is_input_command_in_console`` имеет значение ``True``. Поддерживаемые " "консольные команды включают:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:706 -#: 5a059eb897914040873e954609c66c0c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:784 +#: 4d4368102eae41dbac5a8938a4726e1a msgid "``/stop``: stops the server and closes all active connections." msgstr "``/stop``: останавливает сервер и закрывает все активные соединения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:707 -#: db67da00bf70423a9a3cf4a2fa3a01e1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:785 +#: 8035f922921f4301bbe4ca4936ea38b3 msgid "``/status``: prints the current connection count and running state." msgstr "``/status``: печатает текущее количество подключений и состояние работы." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:708 -#: 15ab35eecbd84e64b8dfc0ac50c3d173 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:786 +#: ce2138bd90784f1daffb39cc8d46d1f1 msgid "``/clients``: prints the connected clients and their connection times." msgstr "``/clients``: печатает подключенных клиентов и время их подключения." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:709 -#: 2d1d3fe9ee9f4d6899754d296f8ede75 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:787 +#: 8c9f96a3d0cd4fbcb311c201db9ff789 msgid "" "``/send_msg <(ip, port)> ...``: sends one or more messages " "to specific clients. Targets are literal ``(ip, port)`` tuples (its own " @@ -1460,8 +1579,8 @@ msgid "" "form)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:710 -#: 92d75f708fe642cf8a77f986f2d891b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:788 +#: 033fdbf663a04e12bfdff63da6e0f6c1 #, fuzzy msgid "" "``/file <(ip, port)> [destination_file_path]``: sends a file " @@ -1470,8 +1589,8 @@ msgstr "" "``/file <путь_файла> ``: отправляет файл с сервера " "определенному клиенту." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:711 -#: 8b28ccd83c594ee5a0ccd126db3bb2dd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:789 +#: 49fea0c411844c689ea2cabaa11c70b3 #, fuzzy msgid "" "``/file_folder <(ip, port)> [destination_file_path]``: " @@ -1480,8 +1599,8 @@ msgstr "" "``/file_folder ``: отправляет папку с сервера " "конкретному клиенту." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:712 -#: 585e54ca3b1545f49a347b69680d3cd2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:790 +#: d4c2a98b15c04214bfca54bd719f9ab4 msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " "port)2> ...``: sends multiple files to multiple clients. Tokens are " @@ -1489,8 +1608,8 @@ msgid "" "otherwise, so files and targets may be interleaved." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:713 -#: 60def6731a3a43d1a074374978801dbc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:791 +#: e6c9995a12a24a6ba5534e475f158d86 msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, " "port)1> <(ip, port)2> ...``: sends the files that precede a group of " @@ -1499,13 +1618,13 @@ msgid "" " that is not a tuple) is accepted and passed on." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:714 -#: 0f9a9437ddcd4894b6be7502e1303c6e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:792 +#: d8253e90b4fe4d8dbe0b2bbd23134dc0 msgid "``/help``: prints a help summary of console commands." msgstr "``/help``: печатает справку по консольным командам." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:716 -#: 1e898bf6aeb54dcb8533615767d03791 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:794 +#: 8cf019297938433ebe65839a4513ae63 msgid "" "The forward commands (``/forward_send_msg``, ``/forward_file``, " "``/forward_folder``) are client-only and are refused on the server " @@ -1513,8 +1632,8 @@ msgid "" "``where_to_run=\"client\"``." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:721 -#: aff923b39d6843bb976f5bb40d38a71d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:799 +#: 43db2954705945c3b3b0742033f122b9 msgid "" "These console commands make it easy to manage the active server and " "perform server-initiated file transfers without modifying the code." @@ -1522,8 +1641,8 @@ msgstr "" "Эти консольные команды упрощают управление активным сервером и выполнение" " инициируемой сервером передачи файлов без изменения кода." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:725 -#: bcbb903def99415298bb7b29d21f31f6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:803 +#: 261fde939721476abba9b40f0290944f #, fuzzy msgid "" "*Note: It is too long to introduce all the console commands, so for more " @@ -1533,13 +1652,13 @@ msgstr "" " получения более подробной информации см. раздел :ref:`tcp-server-" "console-commands`.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:729 -#: c68a8d4ecb904da7980049abc5210fdf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 +#: 0e848b37570e4fc8b23ff7eb13a2ae3e msgid "TCP Server file transfer API" msgstr "API передачи файлов TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:731 -#: 1e9d70417dbf4446bc8528cf692db8ed +#: ../../source/Network_APIs/TCP_Server_APIs.rst:809 +#: 27472ef4f13641ba9a08e6a97bb651dc msgid "" "The TCP server contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers." @@ -1547,8 +1666,8 @@ msgstr "" "TCP-сервер содержит подсистему передачи файлов, которая поддерживает " "передачу как от клиента к серверу, так и от сервера к клиенту." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:735 -#: 695753d4c2bc4f15972565a20be6b6c8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 +#: eadd29678d8a449c9659c4792b5f2cb0 #, fuzzy msgid "" "It's too long to introduce all the file transfer functions, so there is " @@ -1559,35 +1678,35 @@ msgstr "" "список API для функций передачи файлов. Для получения более подробной " "информации о функциях передачи файлов посетите..." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:740 -#: 5f303019ed3747a691e61b7f20cdb1cf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:818 +#: 1ca2a6ce0f124ebc87676b1155c4c022 msgid "The file transfer API for you to use includes:" msgstr "API передачи файлов, который вы можете использовать, включает в себя:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:742 -#: 376da0b60e9641efa6a75ed7e52af8bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:820 +#: 63c118c7e7c4478fa14f3cb0950f6c1c msgid "The basic function for the server-to-client file transfer is defined as:" msgstr "Основная функция передачи файлов от сервера к клиенту определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 -#: 80a158519403430f8f7c43893634e6d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 +#: 4e3a0194c55744898eb3884b60d75672 msgid "The file transfer function which will run in the threads is defined as:" msgstr "" "Функция передачи файлов, которая будет выполняться в потоках, " "определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:764 -#: 771b5bd6acad467d92fbeebcacbc6dba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 +#: 3fd7ac4d381e41589a62998726dd22f7 msgid "The folder transfer function is defined as:" msgstr "Функция передачи папки определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:773 -#: da45b1e2fcc34c1a96c1d1f9e809f742 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 +#: 833a77a7c8fa480db0a0b6e8387132d3 msgid "The multiple files transfer to multiple clients function is defined as:" msgstr "Функция передачи нескольких файлов нескольким клиентам определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:783 -#: 15099b87947a4f08a34ca87734c23306 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:861 +#: 26032ba6212f443980c40351874b2139 msgid "" "The different multiple files transfer to the different multiple clients " "function is defined as:" @@ -1595,8 +1714,8 @@ msgstr "" "Передача нескольких файлов различным функциям нескольких клиентов " "определяется как:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:793 -#: d93a80b4acca404f98faaf0a7f133079 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:871 +#: 0c9b95c194634285aade290fb17bef5b #, fuzzy msgid "" "We recommend that if you want to use the mono-file transfer function, use" @@ -1624,8 +1743,8 @@ msgstr "" "вызывать их в потоках, то могут возникнуть неожиданные ошибки и ненужная " "сложность." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 -#: c3f69c0b152c44df91753c54cf94593f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:885 +#: 28c7d60dd34d48ababd9c06199091309 msgid "" "*Note: The file transfer API functions are designed to be called from the" " command handlers for both client-initiated and server-initiated " @@ -1638,18 +1757,18 @@ msgstr "" "передачи, клиентских подключений и фактические операции передачи файловых" " данных.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 -#: 666eecd4aa974e2d8b5b9a1ff3acbc25 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:891 +#: 0fcf1a7def3e437d9ecbaf8d5d02470a msgid "Client-to-server transfer flow:" msgstr "Поток передачи данных между клиентом и сервером:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:815 -#: f6b96397ab484021974c50cf86144a12 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:893 +#: 740bd9ad4564417e8f76f28500d1da68 msgid "The client sends ``/file`` or ``/file_folder`` to request a transfer." msgstr "Клиент отправляет ``/file`` или ``/file_folder`` для запроса передачи." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:817 -#: d6b57e1e1e6e4ea78d59d9a47a1a4ccc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:895 +#: e26bd8a6fb5a4977a3039fd2bdf22114 #, fuzzy msgid "" "``handle_command`` starts a dedicated file-server thread: " @@ -1660,8 +1779,8 @@ msgstr "" "``handle_command`` запускает выделенный поток файлового сервера, " "используя ``file_transfer_server_recv_server_start_thread``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:821 -#: 3ba05b4bc071401d959f68b7019c7aa3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:899 +#: e5ef46040255421fa92c6de33d976671 msgid "" "The server allocates an ephemeral transfer port with ``palloc`` and sends" " ``/server_file_transfer_port `` back to the client." @@ -1669,8 +1788,8 @@ msgstr "" "Сервер выделяет временный порт передачи с помощью palloc и отправляет " "``/server_file_transfer_port `` обратно клиенту." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:825 -#: 9f8b5c7e3b8048c9b9ded191ecd70d6b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:903 +#: 6eaa70d4d985489e8f0e683baa6b52a1 msgid "" "The client connects to that transfer port and sends file metadata, " "including length-prefixed filename and file size." @@ -1678,18 +1797,18 @@ msgstr "" "Клиент подключается к этому порту передачи и отправляет метаданные файла," " включая имя файла с префиксом длины и размер файла." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:828 -#: 95c2b39e285840678adb522483da672b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:906 +#: 245d5d51d72a41ee86c9925ec1872e35 msgid "The server receives the file and writes it under ``received_files``." msgstr "Сервер получает файл и записывает его в ``received_files``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 -#: 8254cf417a46471ea770e4917e96b05b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 +#: 5ad02fbb498f483580e470b2f5291a53 msgid "Server-to-client transfer flow:" msgstr "Поток передачи от сервера к клиенту:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:833 -#: 69032201d7254006b52a86961f08530a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:911 +#: 341ba310459442de906ec90ad72a16d9 msgid "" "``file_transfer_server_recv_client_start`` is used to initiate outgoing " "transfers from server to a connected client." @@ -1697,8 +1816,8 @@ msgstr "" "``file_transfer_server_recv_client_start`` используется для инициации " "исходящей передачи с сервера на подключенный клиент." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:835 -#: 408f93d233f44860a854950b3e60f8f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:913 +#: c5f727be6f954b9d87c3ebf0b8ae32ce msgid "" "The server sends transfer commands to the client socket and waits for the" " client to establish the file transfer connection." @@ -1706,8 +1825,8 @@ msgstr "" "Сервер отправляет команды передачи в клиентский сокет и ждет, пока клиент" " установит соединение для передачи файлов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:837 -#: 718dadb723164e65a2eb6fdcfb7d8420 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:915 +#: 88151618a44849269aea215557a4ca1c msgid "" "Folder transfers are performed recursively, with each file transfer " "respecting ``self.max_file_transfer_thread_num`` and the configured " @@ -1717,13 +1836,13 @@ msgstr "" "учитывает ``self.max_file_transfer_thread_num`` и настроенный предел " "семафора." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:840 -#: f23efbda41cb40289b93c954f6d051b0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:918 +#: 4734f1f535e7485ca5c91b06dec65f79 msgid "Common file transfer helper methods include:" msgstr "Общие вспомогательные методы передачи файлов включают в себя:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 -#: b86c426b7c8a46b59735ef1a6a0da725 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:920 +#: aaa12a7a9d3f4adeb08d59d5fbc9d131 msgid "" "``file_transfer_server_recv_server_start``: receives file data from a " "client." @@ -1731,16 +1850,16 @@ msgstr "" "``file_transfer_server_recv_server_start``: получает данные файла от " "клиента." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:843 -#: 74859cc9d4a745d99225f6522b4455c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:921 +#: 404a990c105247b09e2f2d1716527269 #, fuzzy msgid "``file_transfer_server_recv_client_start``: sends a file to a client." msgstr "" "``file_transfer_server_recv_client_start``: отправляет файл или папку " "клиенту." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:844 -#: 78042f93790547a8a844087d3daf81b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:922 +#: 0ec7dfbbfb1644f1ad5c42a1b2a04dc9 #, fuzzy msgid "" "``file_transfer_mode``: performs the low-level sender-side transfer " @@ -1750,8 +1869,8 @@ msgstr "" "``file_transfer_mode``: выполняет низкоуровневое подтверждение передачи " "на стороне клиента." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:846 -#: a03a3b41f63c4c7d8e6800e6e42c215f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:924 +#: 6056cfcc5fa740e58986f2e8ce900042 msgid "" "``file_transfer_mode_recv``: performs the low-level receive-side transfer" " handshake." @@ -1759,13 +1878,13 @@ msgstr "" "``file_transfer_mode_recv``: выполняет низкоуровневое подтверждение " "передачи на стороне приема." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 -#: 82f418a15fbf4c009e188c0fe656a483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:929 +#: e0dc9b775fb94f0ab2728b56c57f88bd msgid "Port allocation API" msgstr "API распределения портов" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:853 -#: c041090f476c4f37a46fc7a3f49653cb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:931 +#: 9711bca31e6b464e940739ba262f5153 #, fuzzy msgid "" "The server allocation APIs allow you to allocate a new port for other " @@ -1774,8 +1893,8 @@ msgstr "" "API выделения серверов позволяют вам выделить новый порт для других " "серверов. Существует два типа режимов распределения портов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:857 -#: 4fa11de65ebc4b51b83ea26802b43e3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:935 +#: 30e2a47526db46b29ef31b8730b5dd8a msgid "" "To change the port allocation mode, you can set the " "``is_hand_alloc_port`` argument on the server instance. When set to " @@ -1788,8 +1907,8 @@ msgstr "" "портов, если установлено значение «True», он выберет режим ручного " "выделения портов." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:863 -#: aaa3428304234c0f81e2f83ab0481f17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 +#: 2a3a8472358240aea19de918a8d83602 #, fuzzy msgid "" "We strongly recommend using the automatic port allocation mode, which is " @@ -1804,8 +1923,8 @@ msgstr "" "стабилен, чем режим ручного выделения портов. В этом режиме при вызове " "API распределения возвращается ``0``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:870 -#: f9fbfedba34e4c3386442a9425b52a44 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 +#: 29df017de0bc4b399ebbe204db974707 msgid "" "*Note: The `bind` function in standard lib `socket` of the python " "executor, when input ``0`` to the port parameter, will automatically " @@ -1815,8 +1934,8 @@ msgstr "" " Python при вводе «0» в параметр порта автоматически назначит доступный " "порт операционной системой.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:875 -#: 4a1a578af0b14571a4180ebfc88073d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 +#: df4b1b82912e444c89fd2ea7adbec615 #, fuzzy msgid "" "The other port allocation mode is the manual port allocation mode, there " @@ -1830,8 +1949,8 @@ msgstr "" " диапазон выделения портов будет конфликтовать и могут возникнуть " "некоторые непредвиденные ошибки." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:882 -#: d9301928a8f643868d7cc5852f986e0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 +#: c835077f32f6478a8c0ad000340fd11f msgid "" "The range of the port allocation is configured in the server settings. " "The minimum allocatable port is ``self.port-" @@ -1843,8 +1962,8 @@ msgstr "" "максимальный выделяемый порт — " "«self.port+1+self.port_add_step*self.port_range_num»." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:888 -#: 17b2666361504a0d8f5e10eb5fc9056a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 +#: 5ad5c89c89a141f2bb5c56e49b94bf1a msgid "" "*Note: The ``self.port`` is the ``port`` argument of the server class. " "The ``self.port_add_step`` is the ``port_add_step`` argument. And the " @@ -1854,13 +1973,13 @@ msgstr "" "Self.port_add_step — это аргумент port_add_step. А " "``self.port_range_num`` — это аргумент ``port_range_num``.*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:894 -#: fefbe2307beb49d083c05018a96a2f3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 +#: 8ea7c9e4e1ad46efb978d3d466a53db6 msgid "There are some relevant methods that can be used:" msgstr "Можно использовать несколько соответствующих методов:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 -#: 60738ce1224042aa9b39f5e5feec0e95 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 +#: f9525c162a254de4b11de650677ffd79 #, fuzzy msgid "" "The `palloc` method allows you to get a port. When using this function, " @@ -1875,8 +1994,8 @@ msgstr "" "не нужно беспокоиться о режиме выделения портов, поскольку детектор " "режима выделения уже реализован в этом методе." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:919 -#: 54ccf91661524b1487fb666243fb627a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:997 +#: dee22bb387e140e9ae43d6ebc9afbd58 #, fuzzy msgid "" "The `pfree` method allows you to free a port. Like the `palloc` method, " @@ -1887,8 +2006,8 @@ msgstr "" "`palloc`, вам не нужно заботиться о режиме выделения портов при " "использовании этого метода." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:923 -#: f4a62c2b675845148f52b3437e9c151e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1001 +#: 6bd53cf6dcea462fbad9ca450e42eec4 msgid "" "And there are the main functions for you to call, and for more " "information about the port allocation functions, see the :ref:`tcp-" @@ -1898,8 +2017,8 @@ msgstr "" "информацию о функциях выделения портов см. в разделе :ref:`tcp-server-" "port-allocation-api`." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:927 -#: 9aead9c3ede94037a42b4f83a45b3bb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1005 +#: d158c9d060c14aa39d042757684d6131 msgid "" "This mode is useful when you need an individual port for the server or " "must reserve a controlled range of ports for client-file transfers by " @@ -1912,81 +2031,81 @@ msgstr "" "тестирования или когда несколько серверных процессов используют один и " "тот же хост." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:934 -#: bad6d4dc4cdb4524b686b936a219637d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1012 +#: e51f806efbae4f9daf44365d182f21fa msgid "TCP Server APIs table" msgstr "Таблица API TCP-сервера" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:936 -#: 7d833bb126d34e528b706e8bf0e8a755 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1014 +#: c07f101dcc584239b2a4a7532c1ada42 msgid "In short, the table of contents of the public APIs are as follows:" msgstr "Короче говоря, содержание общедоступных API выглядит следующим образом:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:939 -#: 665b3f99a31a46a1af942df11ae56b08 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1017 +#: 66d85143ceff487f9620241fa1391d21 msgid "The server setup APIs:" msgstr "API настройки сервера:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:940 -#: fadd7d9d1d664608bca880a41e9ea51d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1018 +#: 904c44d78ca84c5cb7b595c6d360b2df msgid "`TCP_Server_Base`" msgstr "`TCP_Server_Base`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 -#: 53e896a56ad44c29b03df161113e8d24 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1019 +#: 5da37cfc4922407dab0d65df73991067 msgid "`start_TCP_Server`" msgstr "`start_TCP_Server`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:942 -#: 80dc73e7ae064470b60bf81cf731b1a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1020 +#: 6e0f0866c62749239469bceea81ae727 msgid "`stop`" msgstr "`стоп`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:944 -#: bad96f05bf9741c3a015b46ddb0c5485 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1022 +#: f84f11b7394147a9802c7de69d1d99e5 msgid "The server handling information APIs:" msgstr "Серверные API-интерфейсы обработки информации:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:945 -#: c11c56f2f920425cb0f8a796ba8436ae +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1023 +#: 0ee5a3ad2c3643b9b85c813b5a5ba4be msgid "`handle_client`" msgstr "`handle_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:946 -#: 601d3f32dca44ce0aa8f90496fa82683 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1024 +#: 803b7f781de04d00ae128d89b0350cf5 msgid "`handle_command`" msgstr "`handle_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:947 -#: a95b98f525c44f8e99aa1ce37d14521c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1025 +#: cb9095dd05b24093984b4609ee0bb8b6 msgid "`receive_message`" msgstr "`receive_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 -#: b4d6756915c3424eac84ee276c68ec48 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1026 +#: c40a11b2d9b34f389fce8bc6d8076ab2 msgid "`send_message`" msgstr "`send_message`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:949 -#: 5458006437d24bb68711e2523f7d7cba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1027 +#: 3c4a73128c044a38bac0b64d6551f512 msgid "`broadcast`" msgstr "`трансляция`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:950 -#: e87f4ae0d0284a778641c6198ee918fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1028 +#: 16f4acaa490c4ec7afbd88fb3b50f62c msgid "`send_msg_to_specific_client`" msgstr "`send_msg_to_specified_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:951 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1029 +#: 2ad09a3887894e01a67d31c28272f730 #, fuzzy msgid "" "`console_input` (only started when ``is_input_command_in_console`` is " "``True``)" msgstr "``is_input_command_in_console``: по умолчанию установлено ``True``." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1031 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 #, fuzzy msgid "" "2.1. The inbound event listener APIs (see :ref:`tcp-server-event-" @@ -1995,23 +2114,23 @@ msgstr "" "API-интерфейсы зашифрованного канала сервера (см. :ref:`tcp-server-" "encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:954 -#: e0409b880c784bc4a8cb876315709114 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1032 +#: 6f0e5784864d4f62b0fd68d41a8105c4 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:955 -#: 2dea82fdc0a04600801da255ef214a2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1033 +#: 647c22de04784b0c97bbc829edf1e2b3 msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:956 -#: d90982abe8e24aefb021d1bdb6cb8ca8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1034 +#: 8fc8a08031dd48eba706b833414ef995 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:958 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1036 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 msgid "" "The server encrypted channel APIs (see :ref:`tcp-server-encrypted-" "channel-api`):" @@ -2019,148 +2138,188 @@ msgstr "" "API-интерфейсы зашифрованного канала сервера (см. :ref:`tcp-server-" "encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:959 -#: 0164b9a39ec64638b0951431e562f5c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1037 +#: 67ad7bf1d5754801a36a114c86e650f9 msgid "`_crypto_on_client_hello`" msgstr "`_crypto_on_client_hello`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 -#: 35472e2955b24167aadb9aa8587b2674 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1038 +#: e2ec1fc9abbc4a1389e8df768c33e7c8 msgid "`_crypto_wait_server_ready`" msgstr "`_crypto_wait_server_ready`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:961 -#: 2e8d4e8d8741462e8e6a6b36b36e0c07 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1039 +#: e3987c4ee8ae4d79b0aafb035a806494 msgid "`_crypto_push_pub_to_client`" msgstr "`_crypto_push_pub_to_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:962 -#: b7eb540259ae4240ba76640b6afd72b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1040 +#: b1829201e7fe4428b9689b03e50374bf msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:964 -#: 9265fbd06c8a43fc972c1010a348684d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1042 +#: c875b30243a24ac4923a442613a677e0 msgid "The server command APIs:" msgstr "Командные API сервера:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:965 -#: 6c53a87d79a749ffa1e2a93231037ac1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1043 +#: 5d011d31b13d446f814fd6bd5e63efce msgid "`register_command`" msgstr "`register_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 -#: 30a77ceac778437989abfaa0a23c1f4a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1044 +#: 2f117382a2154410989fb34342460f8b +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1045 +#: ffa5682de7884beb92ad1259ff1b8dd2 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:967 -#: 1940d4e8daf143e9ad1c971530233180 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1046 +#: cf39c195db7c41caa0f01bd982276547 msgid "`submit_task`" msgstr "`submit_task`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:968 -#: f2448f5089ba44458298a4194c2795f0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1047 +#: 85f02dafa5374a7b89e8bd8a65e54b19 msgid "`create_temporary_server`" msgstr "`create_temporary_server`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:969 -#: 097562a3555e413385ee95ded3a46118 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1048 +#: 2f117382a2154410989fb34342460f8b msgid "`create_temporary_client`" msgstr "`create_temporary_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:971 -#: af034155f20a44b79b9c6ec49fc189aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1050 +#: 0131ddf38e824d959a1d61148155ae0d msgid "The server file transfer APIs:" msgstr "API-интерфейсы передачи файлов сервера:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 -#: 9cbb9edbc9574de99f8168bf2df7df03 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1051 +#: 7483d578f02a4babb71dda0efb204b61 msgid "`file_transfer_server_recv_client_start`" msgstr "`file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:973 -#: fc70c45345764fb2aa8bc3d71f927248 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1052 +#: c2cf0a257e2543478df2dccdf52fdb00 msgid "`file_transfer_server_recv_client_start_thread`" msgstr "`file_transfer_server_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:974 -#: c1918a177fcf47cbb881d7e14300776d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1053 +#: 187f0ce4a65e41adb7ee99b021de4d2b msgid "`folder_file_transfer_server_recv_client_start`" msgstr "`folder_file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:975 -#: 6f61085c3cb24ae298dc0eadbe113f6c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1054 +#: be99cf24a4ae4f03b5472d8ee3412889 msgid "`multiple_file_multiple_client_transfer_server_recv_client_start`" msgstr "`multiple_file_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:976 -#: 46d60103b77c4de19be1ac4a12d4331b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1055 +#: ea76c872d16c4a709ec52ab7415e40a0 msgid "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" msgstr "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:978 -#: 565a0271f5ed4b679a742f7677ed9e63 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1056 +#: 6056cfcc5fa740e58986f2e8ce900042 +msgid "`file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1057 +#: 8df3552dd5ae41a4b3020c15ebe8509d +msgid "`forward_item_to` / `forward_message_to`: single forward destinations" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1059 +#: ad8e7d49e5294f5b976ae225ccb67d22 +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1060 +#: 92ba3cd2c6004b60abe5976efa845d76 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1061 +#: 8cee01b7bbd1439b81f24891d7149fa4 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1062 +#: f5615a6934a141c9aa2bb01bcab9aea0 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1063 +#: 187f0ce4a65e41adb7ee99b021de4d2b +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1065 +#: 944bb0f890764ad7a62584cc73782927 msgid "The server console commands:" msgstr "Команды консоли сервера:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:979 -#: e79a38bbae1d44e5b9e7b3e939b42e14 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1066 +#: e85b5444c86048cfa691dc42bb7c9f88 msgid "`/stop`" msgstr "`/стоп`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:980 -#: 98cb7e67ddc64c7e91c8f445d3d7b601 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1067 +#: 7250fb98f32f47d4b6204ceb5f93f550 msgid "`/status`" msgstr "`/статус`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:981 -#: ec1899e60fc1456ba2117f7b0bf676e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1068 +#: 48237f11d42c41e392b282787896bd00 msgid "`/clients`" msgstr "`/клиенты`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:982 -#: 0bb68238715a4e889bef60bf524c996a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1069 +#: 65fddabf6eec444fa89598e10a43f63f msgid "`/send_msg`" msgstr "`/send_msg`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:983 -#: 4c5dc721d573437385383ec46f76658a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1070 +#: c53a3810c2784772a6cb72f993ae8b4d msgid "`/file`" msgstr "`/файл`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:984 -#: 4fca7dce90044c119e5722297774fabe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1071 +#: 57d39ac1201f4866a57b5d291385d207 msgid "`/file_folder`" msgstr "`/папка_файла`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:985 -#: 29fe035c678b49ef80321587017ba483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1072 +#: 2cbc4a81ca0548d4aa183c2ad034ab6a msgid "`/multiple_file_multiple_client`" msgstr "`/multiple_file_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:986 -#: ba4e2c65e7034bd8a7a278697b76e8a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1073 +#: ce0f96a7a5e24b3cab89623df65ac40f msgid "`/diff_multiple_file_diff_multiple_client`" msgstr "`/diff_multiple_file_diff_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 -#: 97c3c838cb784a729fc52242a89f7156 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1074 +#: a9bffb7745c94e7cb45f4fc030c00da3 msgid "`/help`" msgstr "`/помощь`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:990 -#: 0b5cb5ab31e648b99f176a269cbad11e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1077 +#: 2d084d51c4c44ebda431944babb6c256 msgid "See Also" msgstr "См. также" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:992 -#: d85e9537bf8e453ea2d533f25e659d2a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1079 +#: aa497d5f407a4e439cd10a4de1e24b05 msgid ":doc:`TCP_Client_APIs` — TCP client." msgstr ":doc:`TCP_Client_APIs` — TCP-клиент." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:993 -#: 1893e2b71add4e0ba8840ea169e0b102 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1080 +#: e1e5363e891e4e68855f9b021bbd4abf msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — конечная точка UDP." @@ -2459,3 +2618,60 @@ msgstr ":doc:`UDP_APIs` — конечная точка UDP." #~ " ... ...``: отправляет" #~ " разные списки файлов разным клиентам." +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "При рукопожатии происходит обмен случайным " +#~ "одноразовым номером сеанса, и каждая " +#~ "зашифрованная строка в сети содержит его" +#~ " плюс порядковый номер для каждого " +#~ "соединения: ``||``. " +#~ "Получатель удаляет строку, nonce которой " +#~ "не соответствует текущему сеансу " +#~ "(зашифрованный текст воспроизводится из более" +#~ " старого соединения) или чей порядковый " +#~ "номер не является ожидаемым (зашифрованный " +#~ "текст воспроизводится внутри сеанса/не в " +#~ "порядке); оба счетчика сбрасываются, когда " +#~ "сокет переключается в зашифрованный режим " +#~ "после (повторного) обмена." + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(client_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to the " +#~ "command handlers instead). ``add_file_listener`` " +#~ "registers ``listener(client_id, full_path, name, " +#~ "size, command)`` and fires after a " +#~ "file uploaded by a client has been" +#~ " fully written to the transfer " +#~ "directory (``command`` is the wire " +#~ "command that triggered it, so protocol" +#~ " pushes such as ``/crypto_pub_key`` can " +#~ "be recognised). Both listeners run on" +#~ " a protocol thread, so they must " +#~ "not block, and an exception inside " +#~ "a listener is logged and swallowed. " +#~ "The ``remove_*`` counterparts unregister a " +#~ "listener and ignore unknown ones." +#~ msgstr "" + +#~ msgid "" +#~ "``/forward_item``, ``/forward_send_msg``, " +#~ "``/pause_trans``, ``/start_trans``: internal " +#~ "forwarding/transfer-control messages." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po index 0173b3c..fd614cb 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-16 11:10+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -20,11 +20,71 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../api/PyFlow.command_control_extension_tcp.rst:2 +#: ../../source/api/PyFlow.command_control_extension_tcp.rst:2 #: a6084f2941f34f579f28c55e9dfb768d msgid "PyFlow.command\\_control\\_extension\\_tcp module" msgstr "" +#: 9209095513ec402980427a0ddd988219 PyFlow.command_control_extension_tcp:1 of +msgid "Command-control extension for the TCP protocol." +msgstr "" + +#: 47d5c98c564241a6911eff0abea987ec PyFlow.command_control_extension_tcp:3 of +msgid "" +"One command batch, run by every listed client, with each client's output " +"collected on the server:" +msgstr "" + +#: PyFlow.command_control_extension_tcp:6 b14c7eec72b44dc1bd343997acf1cf44 of +msgid "/command ... ... " +msgstr "" + +#: PyFlow.command_control_extension_tcp:7 fe2fb5a737534088b175ea340c1763f9 of +msgid "" +"typed on the server console. Every client runs the whole command list in " +"a single shell session, in order, so state such as a changed working " +"directory carries over from one command to the next: ``/command \"cd " +"/path/to/search\" \"ls ./\" \"(ip, port)\"`` lists the files of " +"``/path/to/search``, while sending ``cd`` and ``ls`` as two separate " +"``/command`` lines does not." +msgstr "" + +#: 29a70dd76bf34e90a9ea54ac27202289 PyFlow.command_control_extension_tcp:14 of +msgid "" +"Commands come first and client addresses last; every address is written " +"as a Python address tuple, e.g. ``\"('127.0.0.1', 3000)\"``. There is no " +"limit on the number of commands or on the number of clients, and every " +"listed client receives the same command list. Two internal commands carry" +" the log back:" +msgstr "" + +#: 9ef58aea395a436382e23f39797e3e8e PyFlow.command_control_extension_tcp:19 of +msgid "/command_log_chunk " +msgstr "" + +#: 3361f3fb70584140989542af7c3361a7 PyFlow.command_control_extension_tcp:20 of +msgid "" +"sent by the client after it uploaded one log chunk through the file " +"transfer channel; the server appends the chunk's entries to that client's" +" log file" +msgstr "" + +#: 2563d4e4d9744c2fb16d84690c2e94e2 PyFlow.command_control_extension_tcp:24 of +msgid "" +"sent by the client when the batch is over; the server merges every " +"collected log file into ``merged_logs.json``" +msgstr "" + +#: PyFlow.command_control_extension_tcp:27 e40a302503cb4bdda5420aa79d0c57eb of +msgid "" +"A client captures the output of the running commands and uploads a chunk " +"every ``_LOG_CHUNK_BYTES`` of captured output (a smaller final chunk " +"closes each command), so a command that never stops is still tracked in " +"real time. Every chunk is appended to the same log file - " +"``logs__.json`` in the server's ``logs`` directory - which is " +"therefore never re-sent and never rewritten, only extended." +msgstr "" + #: 9209095513ec402980427a0ddd988219 #: PyFlow.command_control_extension_tcp.setup_server_commands:1 of msgid "Register the control-extension commands on a server instance." diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po index 017de32..30ceecb 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -21,156 +21,155 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.connect_tcp.rst:2 -#: 59f41330dfa54a88831a20f4dc97c0f6 +#: 1e4cd09ce3ef45ceb95b8eb81eb7493b msgid "PyFlow.network\\_api.connect\\_tcp module" msgstr "" -#: PyFlow.network_api.connect_tcp:1 dca225f091cb4dd1810a8bd04c3a5004 of +#: 25b88cdb337c44539a843c674ba6825b PyFlow.network_api.connect_tcp:1 of msgid "" "TCP transport for PyFlow: the server and client base classes and the wire" " parsers." msgstr "" -#: PyFlow.network_api.connect_tcp:3 d5888d829f2e4850926eb364ede4678e of +#: 1f1482fc5c2849a68f34c74a8b55ab79 PyFlow.network_api.connect_tcp:3 of msgid "" "``TCP_Server_Base`` accepts connections and dispatches inbound lines; " "``TCP_Client_Base`` connects, sends and reads on the same conventions:" msgstr "" -#: PyFlow.network_api.connect_tcp:6 bd065af9d94b44298f9716ca96809b8c of +#: 104e5170c1c34bf9ad719f896e0c4226 PyFlow.network_api.connect_tcp:6 of msgid "" -"one message per line, terminated by a newline; a line that starts with " -"``/`` is a command and goes to the command handlers, anything else is a " -"plain message reported to the registered message listeners;" +"one message per line, terminated by a newline; every inbound line is " +"reported to the registered message listeners (commands included), and a " +"line that starts with ``/`` is then dispatched to the command handlers, " +"anything else treated as a plain message;" msgstr "" -#: 91ea1db95e554f2fbd2c1e92eb2d1353 PyFlow.network_api.connect_tcp:9 of +#: 6c6c01958e5741e080edcb804b4d12d1 PyFlow.network_api.connect_tcp:10 of msgid "" -"an RSA-encrypted channel is negotiated right after connect unless " -"``is_enable_encrypto`` is False;" +"unless ``is_enable_encrypto`` is False, an encrypted channel is " +"negotiated right after connect: the handshake lines and the public-key " +"pushes stay plaintext, then every later message travels as a frame (RSA-" +"OAEP for small text payloads, an ECDH-keyed AES-GCM seal for everything " +"else, including file data), and each file/folder transfer sub-connection " +"is framed the same way once both sides hold the session keys (see " +"`_SecureChannel`);" msgstr "" -#: PyFlow.network_api.connect_tcp:11 dfcece05b6774c5496b99d6c08039fce of +#: 9702905f1f8a4750905b2ffb96f99ec8 PyFlow.network_api.connect_tcp:16 of msgid "" "file/folder transfer, message forwarding and port allocation are layered " -"on the same socket and share its command namespace." +"on the same socket and share its command namespace;" msgstr "" -#: 89db462eaa88489c9390ddfa67a77a73 PyFlow.network_api.connect_tcp:14 of +#: 3488995e2a8349a58393d9f2d1155b99 PyFlow.network_api.connect_tcp:18 of +msgid "" +"an interrupted transfer is resumed after a disconnect: both sides persist" +" their transfer stores under the protocol's ``.Flow`` directory and the " +"receiver asks the sender to continue the file from the bytes already on " +"disk (``resume_transfers``; the wire lines are ``/resume_trans`` and " +"``/forward_resume``)." +msgstr "" + +#: 4cc5743bdfe54148ad38f54f10e688c9 PyFlow.network_api.connect_tcp:24 of msgid "" "The forwarding extensions use the module-level parsers " "`parse_forwarded_message`, `parse_forward_items_and_addrs`, " -"`parse_forward_originator` and `forward_skip_message`." +"`parse_forward_originator` and `forward_skip_message`; the reconnect " +"logic uses `parse_resume_command`, `parse_forward_resume_command` and " +"`_resume_offset_for`." msgstr "" -#: 98c270e82fa8468487e1b4d25bab8c0c PyFlow.network_api.connect_tcp:18 of +#: 49796529cb7f49ee8131b257212b5420 PyFlow.network_api.connect_tcp:30 of msgid "" "Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and " "``TCP_Client_APIs.rst``; argument, return and exception contracts live in" " the docstrings below." msgstr "" -#: 76126c02e928423b89dc4662d9a190f2 +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_resume_command:1 of +msgid "Split a ``/resume_trans `` line." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 14dcda8b059b480982e3fb03399e665b 99035a24f6e94207b84545f8c71a451e +#: cb62202c244d4c08974c674c13a02dca +msgid "Returns" +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_resume_command:3 of +msgid "``(fid, offset)``, or None when the line is malformed." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 19eb6fca79324b0791f8ec7488a5246c +msgid "Return type" +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:1 of +msgid "Split a ``/forward_resume `` line." +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:3 of +msgid "``(target, fid, offset)``, or None when the line is malformed." +msgstr "" + +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:5 of +msgid "``(target, fid, offset)``, or None when the line is" +msgstr "" + +#: 4ead8d8f93644adeb812150e760f7792 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:6 of +msgid "malformed." +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 #: PyFlow.network_api.connect_tcp.parse_forwarded_message:1 of msgid "Split a ``/send_msg_from `` relay envelope." msgstr "" #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0e9ae2e0bd0c44da835c0999abec5f08 1aaf58afc7f043919f411c02d435031d -#: 1c819a8207464e439fd4675d1b823409 1d2cff780d6642deb6ab5fbf32c34185 -#: 1e24bfa274504842b67c3cb0c7a37118 26160724c12740ecbe3cc707bc46c197 -#: 2edb81613e9c4bd0949f5d6efa1a542f 30a7ccf5e56e4640a7a6e592d13a4f7c -#: 3514f6292626456eb4b0c31a30e24cf5 38d82b9bc4414212a8458de940d3b69b -#: 406f1bd372c14cd897f0d2dc1fdc8fd7 4400798a6d9d41a89b686b015f53a454 -#: 54f261fe47134a9494f12b5053492006 5e9d8d1799714d389a6fd79edd0e5bac -#: 6239fd721a0f476aaf509ab580317c75 6658645eabff4ba6b0b326727f89a4f1 -#: 6f375e9a65e04034a4fd1475f3073e42 70b19bc5e5da467dbbae99d81fe54ed7 -#: 79e2d4be536b429cbbfe5016df915b72 7c3cf59acfe34a15a6c920a0f58ec56f -#: 822df543855349c2993aabd5596b5383 8245849b603f4313a3ea2423abd5c899 -#: 83eba13f6fae4ded929924151baa0c52 9449c184a2e145909d2e1f114534253d -#: 9a393c8c90d0446a97c34af1c173f83d 9cdc7d0b4bc2400498e9c57ed16ba459 -#: a2ddcff09d1641b5b269ec31031008f9 a5cbf7c6c5b0494b8652be7d28a7b3d1 -#: a9ec9ede7c8144ddb920261d29edc23d b5b42f99934e4b0b939671c6fb08f748 -#: b630deb98dea40c28f1cb88dcbfdb261 b6e3a01b0f044a15a7d322c63f58c262 -#: bb3b7e5558c74c8eb287944b93b9c664 bd95cc8d5960426e92ad149ce0ecaeb4 -#: be47c4f21d4d4515be0684c6c1215c0c cdebf66a7b714ef39236c1dc9773c8f7 -#: d02c1be3236b424f87b75728f76d672c d5b3f5bf790c4fc6aefb763d9c473474 -#: da6cef9244b1429881584994b097c71a e98998d054b74d0e820367ea5de54d02 -#: ea4e1b708c2f409f89bf4ca2a6e4fbf3 ebca3c62590345118f3fe5a8d85ce154 -#: ebcdb45484b64f7f9023808632316025 efca1ecd18f440db9489b40ae6480409 -#: f7766cda09fd4c0bb6b565f5fa4a3688 fe80dd07199943c784dd488826f958b7 +#: 4fa9ba6e763440b8ab00832520b4d305 501a0caef71d436e84469bc1ef9c1e5f +#: 70d6dae11a144ed7b7e9d8e16dbf478c acdf8b3b266f4eccb6ceca17a110603b msgid "Parameters" msgstr "" -#: 35b277cd5b2249dc8b38c36654b1f75a -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 +#: e42a6166c82d4861b25cb55f587db28c of msgid "Received line, e.g. ``/send_msg_from ('127.0.0.1', 3000) hello``." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0cd9914c895f4b308548863df6d8c13c 113c57937f6f402da7758e74266680ea -#: 139720899e024d348d0b43b9af2b2ef7 2cb731c57fb64497a6424e4e51fe17bb -#: 30c59afde30c44428a97266ca87baa21 3f574beaf02948d599ffd8c50922e530 -#: 40e4cbf377a94cf8803c13b2f01dbc77 4aa76ebde46243b18f2a5d811d902d1e -#: 4d5706674a0c40a99769b5cfba21b29d 5518a67cc7364710b2b0c03f6de9de1b -#: 564a8841a88d40e0a44b1b0d72a0b3a4 56e96f344ac14995adeb056f90d3e39a -#: 638d047aee4d45a689f4a54f8d2be451 6e5db10681f24a01a208604d8de1ecf4 -#: 6ea11f9fd50e46f8aef42a25872d8d47 833d97bdb57049979db335d24819041a -#: a00fef59262447aa931fe606e260a7ab a9795b94ba634cb8a7dc1fd6a7e6f326 -#: b1a77959b26540128ea564370170744f b1e2a43372ac48fe9a367121a736eaee -#: b2f18766a5ec40d69bfd15b13fa54aa2 b963bb66a63649d5b5cc0ce3d852aab4 -#: c1bd9b5e40e644e3a1f1198e5d2247c2 d558170070474bcb9d798b72d878f185 -#: d86bf79c265c42ec969d2c8058f20a3c d906d179eca24642883fb6ff991399b8 -#: ddfeae931eb14b529e08b61ae9de5aaf ecb12ada91914625a7c5e9894b67886f -#: f8e1381487764684b80cbc9d8f6a511c fa2587a106c540d1a870afc4a3ae97b7 -msgid "Returns" -msgstr "" - -#: 24de94d25531410aa507869ac615529b -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 +#: f25d1962656c4f339805427e2573f84f of msgid "" "``(sender_id, payload)`` where ``sender_id`` is the sender's " "``\"ip:port\"``, or None when the line is not a well-formed envelope." msgstr "" #: PyFlow.network_api.connect_tcp.parse_forwarded_message:9 -#: f4818c7037924b089072be17dbe65cda of +#: d0d7af37e4134902ae64e10b2e43b4c1 of msgid "``(sender_id, payload)`` where ``sender_id`` is the" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 -#: e4ce35611cb240c382217f2166803af1 of +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 of msgid "" "sender's ``\"ip:port\"``, or None when the line is not a well-formed " "envelope." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f2c39309f3e47aa9157bf244f35d1e6 126027ff5c8b494e8223688394767c35 -#: 15e8f6af90d84f4c99e9a9706f995a3f 18eed5a02c0346f6966237e6812afce0 -#: 208eff4f470f474395ac42a58f179feb 308f9ffcdfe2443cb6fe0f3a79e7d4b3 -#: 30fd0d7f7d9547149d06568b9ae4b217 34500bb5a5ea4428ba3ba1f34f8555f3 -#: 357fa966af0e4661a01d3a18b3686c63 38f178d3602f47bcbf100a047fc22ccc -#: 4268152920654e59975b69aed4638761 43cc49d0a3b2478f8a24fcdea7c2ce78 -#: 448b06753df84443af4aae1dcb008d56 4530cc6fc87d4dbcb79dd0e90ea83694 -#: 496c6102672e49fc96cd7210ed1ec602 502647c8224842608ded5058bf1c6748 -#: 574093f9f9054b898b9ab8b20a239a40 5882a32ac8a34ab7b568b256092e1aca -#: 73e564d3b91d42388f95effb067d6218 7f2f462183d442c98c624d6750d86319 -#: 8203a323a9af48edb0f9e91ca6260ed6 87a376020e0a47fb90cc4f2d9b045d7c -#: 8f12aa18be1a4aaf97b8db14f282a929 a61c3c1917b8486bad659991683c48cb -#: a9e445f3a3094e3bb7957551bcf7fd21 c0afcff99bfc47f3ba7a3f0b3e836444 -#: c4d251b617f2419cb1093f6896b14cb8 d4bc332ce5f34c61b3105fb392b302e5 -#: e9a98b5852d84cf4939d9ea0f17b038c f17ca1aa780b447cb305e1db1c181efb -msgid "Return type" -msgstr "" - -#: 1ad7def88bd34ce7accca28c4d123b79 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 +#: f22254d8ca2d47ad8bc9c98664369d61 of msgid "Split forward-command tokens into items and destination addresses." msgstr "" -#: 67578e526f0b4dfc924c46a44e7bea78 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 +#: b207f60051004834bab91ba392a88437 of msgid "" "A token of the form ``('ip', port)`` is a destination, everything else is" " a forwarded item (message text or a path). Used by the native message " @@ -178,252 +177,326 @@ msgid "" "extension." msgstr "" -#: 18a87e9cbc124ce5a6f91d61a72fc6de +#: 5329fb72f5954768a6cec05ff4cccfea #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:7 of msgid "Tokens after the command name." msgstr "" -#: 0e46577c966b41c4ad6f0aea95fd7e5c +#: 2aebf669048046ddb279a935bcfcfde4 #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:10 of msgid "" "``(items, addrs)`` in the order given; ``items`` holds texts and " "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 608bcdb865a94f869885cd560de7012e +#: 96b96bd19fe94312bddf340fad073cbc #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:12 of msgid "``(items, addrs)`` in the order given; ``items`` holds texts and" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 -#: e8c390dc356e4be9bb2f52cd0540e859 of +#: 8e82954621d748e2b412952a7fb2753b +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 of msgid "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 0e422066050d4ba18799efa53c6b771e -#: PyFlow.network_api.connect_tcp.forward_skip_message:1 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:1 +#: a51324658c7943158d90ed706cecc41d of msgid "Build the console notice for a forward destination that cannot be served." msgstr "" -#: 1eb2f924bcbc4e3783e3a4706c93052f -#: PyFlow.network_api.connect_tcp.forward_skip_message:3 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:3 +#: b541e8446e374bc8b38cd7912a1fa33c of msgid "Destination ``(ip, port)`` that is unreachable or is the server itself." msgstr "" -#: PyFlow.network_api.connect_tcp.forward_skip_message:7 -#: b7ceaa070f754fe88242c2b495b3ff9f of +#: 10e03f21d05e478d9cde0c7176f6e1b8 +#: PyFlow.network_api.connect_tcp.forward_skip_message:7 of msgid "One-line notice for the console." msgstr "" -#: 59d83fde0d964794ba76d45749bfc021 +#: 8005e532fe9d491ca8ddd996889d605d #: PyFlow.network_api.connect_tcp.parse_forward_originator:1 of msgid "Extract the originator's ``\"ip:port\"`` from a received transfer command." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 -#: b91ee97cb2574a19b8c87c99bf8ca181 of +#: 2cf3052a89c645e782430f1f05fb37a1 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 of msgid "" "The server's forward relay tags every pushed ``/file`` and " "``/file_folder`` command with the forwarding client's address tuple; a " "direct send carries the receiver's own address instead." msgstr "" -#: 20da4b9824cd4fd6bb0ef55ebc38158b +#: 335f6c1b16104395ba38a33188943d8a #: PyFlow.network_api.connect_tcp.parse_forward_originator:7 of msgid "Received transfer command." msgstr "" -#: 9f25fa22a7b14822b8cbc1fd929976b9 -#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 of +#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 +#: e5bd1024ad3f47f19cafc4c83a844b60 of msgid "" "This instance's own ``\"ip:port\"``; a command carrying it is a direct " "send and yields None." msgstr "" -#: 6455c3bb288d4239811cb0104086c0fa +#: 65469492f844448fab269b701cbdb704 #: PyFlow.network_api.connect_tcp.parse_forward_originator:13 of msgid "" "Originator ``\"ip:port\"``, or None when the command carries no " "originator (direct send or non-transfer command)." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 -#: a466d04757ec40f1a2888518b8fb1d9a of +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 of msgid "Originator ``\"ip:port\"``, or None when the command carries no" msgstr "" #: PyFlow.network_api.connect_tcp.parse_forward_originator:16 -#: da8c46fb38624c7d97d91970aee4667c of +#: a2d34276c4f54c69981f9b51f36cc31d of msgid "originator (direct send or non-transfer command)." msgstr "" -#: 201f6bd5376a4ebaa7488dd3b58197c0 +#: 31646cd2d4f049a38b7910ac6836d2f9 +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:1 of +msgid "A command passed to `call_extension_functions` is not registered." +msgstr "" + +#: 42bee6e5f57b43cba7c5b4c4a1769e9a +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:3 of +msgid "" +"Raised when the first token of the command matches no handler registered " +"with `register_command`, on either instance class." +msgstr "" + +#: 7297b41c47664243b9677b32e21de07e #: PyFlow.network_api.connect_tcp.TCP_Server_Base:1 of msgid "TCP server: accept clients, dispatch commands, relay messages and files." msgstr "" -#: 4f7013d76f9d447b974f22cca228ba0f +#: 0d632c9f5b234888a691b03ade8ff7da #: PyFlow.network_api.connect_tcp.TCP_Server_Base:3 of msgid "" "Each accepted connection is served by `handle_client`, either in its own " "thread (the default) or by a coroutine on an asyncio event loop when " -"``is_asynic_clients_io`` is True: a line starting with ``/`` goes to " -"`handle_command` (built-in commands plus the handlers registered with " -"`register_command`), any other line is a plain message delivered to the " -"listeners registered with `add_message_listener` and stored in " -"``messages_dict``." +"``is_asynic_clients_io`` is True: every inbound line is delivered to the " +"listeners registered with `add_message_listener` first; a line starting " +"with ``/`` then goes to `handle_command` (built-in commands plus the " +"handlers registered with `register_command`), any other line is a plain " +"message stored in ``messages_dict``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 -#: fd2aa2103a434e7b84e9f5300dfb2637 of +#: 2870b0163d68487daf7526e91eb49ff6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 of msgid "Address the server socket binds to." msgstr "" -#: 0887ce96e330478f83984d935911cd2b 13fa6bd77a314fcbae42aeef584d47b6 -#: 1d012f62b99a4b0d8802295d814667dd 1d5b594e02824d74b812b69dc7b34a88 -#: 3b8af6dc474d493eb9749cb07384c5d1 4916b5bac8044e249473dae03d0af5e5 -#: 6a138e9d5ed24b6b9a9f213ffa6d07bb 7c114dabd42344d790a98003f7d68a6a -#: 889f9fb97d4b483cbfd9ae6bbb3e1dbb 89e6193e8e8c45f3ba6d49b9ec578812 #: PyFlow.network_api.connect_tcp.TCP_Client_Base #: PyFlow.network_api.connect_tcp.TCP_Server_Base -#: a0a81405abb64b70834a292dfa52ea47 a32afd5e800648f08c2ed1582462900f -#: a4c849cfce9b4544a50162a1abd07ffc e953785e3c774cb783e506a118b6f5f9 -#: efd7bf86f2f3403a843bdc7079ed87ae f87fe645a0c846168779119b106eb83b of +#: cf754e752b6c445989b3301b807fc9eb of msgid "type" msgstr "" -#: 194d7e538b9142bb9cadf40639c7dfc2 8d779f308c7343fca45fb6b7c544b6f8 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: 568be916ae0340289a6569e718e7cbf2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:16 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:106 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:15 -#: a043713065174240b3b3cb2839829b42 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:100 of msgid "str" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 -#: eaf91e01d29744a4b66b30d163b14bd4 of +#: 6ac74cca7b0f443ca89f3d2c3bbe1aaa +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 of msgid "First port considered for binding and for allocation." msgstr "" -#: 143512a7a9624b79853380f79b9db5e0 6093b43271e041dfb256e660e61561c5 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 +#: 9ecf88c5193c470b98dc95d184c94f92 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:22 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:21 of msgid "int" msgstr "" -#: 0f4f0acdd1a64e9cb4eb06b5fc12103e +#: 6746407aac194c4880c7cbf82b7fa2fb #: PyFlow.network_api.connect_tcp.TCP_Server_Base:25 of msgid "" "Accepted connections keyed by ``(ip, port)``; each value holds " "``socket``, ``address``, ``id`` and ``connected_time``." msgstr "" -#: 6fcc166b59cb4ae7a6a6e30f2dbd2784 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 of +#: 7ba2aaf3fe4c42739121eb3ca2bcc79a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:89 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:98 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:92 of msgid "dict" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 -#: d85332af5e73403388989eacf82a251d of +#: 93556efee2aa445684af3fdc1532548a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 of msgid "True while the accept loop runs." msgstr "" -#: 0effb5fc02cf402ab9d27f4a51954fd1 168f4d3c8da74ebab98953585b27b866 -#: 21bd44747d4e4c9aa4a0afa0f559707d 3c8b6ad08eac44ba9eacbb2fb9752304 -#: 420ec28762864e58ad5f3a63f2811a0f 87eb97e54ef847398f653aa5b65b0191 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: 0ab0667a38254203929e173ab5024f1d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:40 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:46 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:52 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:58 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:65 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:72 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:79 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:34 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:41 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:47 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:53 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:59 -#: e1e2580e801a44cc962b509779f690fc f827c454ead24d7587ae4125b1f60fda -#: f8f0e0ce3c4841278a15e583a0ec5f92 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:66 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:73 of msgid "bool" msgstr "" -#: 62103bebe6fe47aa8a3830133baa0a70 +#: 9023ee78c5fe4680a3875c881abe3307 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:38 of msgid "" "Whether clients are served by coroutines on an event loop instead of one " "thread per client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:42 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 -#: c291fba3b400472996751ffdc24251b7 d0ade3e16cf044fca75a0e1bdf17038c of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 of msgid "Whether the RSA channel is negotiated." msgstr "" -#: 8bb4af4279e44eef8df452f4429780ff -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:48 +#: 3c5a67d3c5824c15b42b71fbadddf5d3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:51 -#: c9414c44325b4b5eaed34bf2a7e49ed4 of +#: a5ac1b25d44547ba836c5dc354438315 of msgid "Whether execution-process lines are logged as well." msgstr "" -#: 5bdaf96cd6894bc4a179ae3ddc66c29c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:54 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 -#: a50b56a084674a89bb56dd9791348a75 of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 of msgid "Whether the instance logs anything at all." msgstr "" -#: 75856a665d5045349622c29bee22fe17 +#: 3114d37d38af4cfcaa75397192202b93 62437fad8325442b91f177e93b8be7ef +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:62 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:63 of +msgid "" +"Whether every running file transfer is tracked in " +"``file_recv_progress``/``file_upload_progress``." +msgstr "" + +#: 58bd8f0892f044a583a276490dc2a7f5 855f8e2ee2a449398779d56b269628d6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:70 of +msgid "" +"Whether the real-time network speed is measured into " +"``upload_network_speed``/``recv_network_speed``." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:77 +#: afff1dd047f4479b84d46859c7da90b8 ce793576b862473cb130a29582aab5fd of +msgid "" +"Running downloads keyed by fid; each value is ``[received bytes, total " +"bytes, current speed, file path, peer]`` (the speed is None until the " +"transfer has moved its first chunk, and while speed measurement is off; " +"``peer`` is the sender's ``(ip, port)``)." +msgstr "" + +#: 36c2c0e7900d436a977b8895e671c9f0 659caaa0c8bc40d3a9ce8d0905787584 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:93 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:87 of +msgid "" +"Running uploads keyed by fid; each value is ``[sent bytes, total bytes, " +"current speed, file path, peer]``, with ``peer`` the receiver's ``(ip, " +"port)``. A forwarded transfer stores the original peer on both sides, " +"never the relay." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:96 +#: f9528e6c490d4807b949f6730c6ece8e of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when a connection drops and read back on the next reconnect " +"(``resume_transfers``)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:110 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:104 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second sent, or None when not measured." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:113 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:120 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:107 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:114 +#: d926b4f3eb4b40a4acb21f780a4dc227 of +msgid "float | None" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:117 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:111 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second received, or None when not measured." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:1 of msgid "Create the server and, unless extended, start accepting clients." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:3 -#: a2cce435d92d46e5b0b2cd59d43c8759 of +#: bf58d54a167d45de9a18641877ada912 of msgid "Address the server socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 -#: d4c7cd9cc01e4371961f0950fd861b12 of +#: 2f4d0c4bfd8246d4984d4c843510775d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 of msgid "First port to bind; also the base of the allocation range." msgstr "" -#: 716408a19bf349878edfd5f1948f57ec +#: 47138ce8f587467aa353e302f473df48 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:8 of msgid "" "Maximum concurrent clients served in thread mode; ignored when " "``is_asynic_clients_io`` is True. Defaults to 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 -#: c37fcc062f6947228f3dc0b85ec5a5ca of +#: 8786a9d2b6b449209be813778d785712 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 of msgid "Step between candidate ports. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 -#: e683b27a8b884c5b99511f99e20b6bf9 of +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 of msgid "Number of ports per step. Defaults to 100." msgstr "" -#: 6291e503f9bf4c78a9c226058a67bce1 +#: 973382c423524d44a569c318399e0b99 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:15 -#: e59cefed7c4e4148b863b89e4d17004e of +#: d5f8f341d98d478289d9a226f37c1003 of msgid "Concurrent file transfers allowed. Defaults to 10." msgstr "" -#: 792cebf4ce084bd9b222b9ee83eeb5f4 +#: 4fe9a7607dbc4eebbce4e62f9306c76f #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:18 of msgid "" "Reserve a port range across processes, so several instances on one host " "do not collide. Defaults to False." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 -#: befe96138f8544cbb8320f33af43af3e of +#: 8aa56addc6ae4a7790dc957d1e1c2b60 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 of msgid "Start the console command thread. Defaults to True." msgstr "" -#: 10c1ed53a097472297ade439439e218f 3bc54f27f3db4bce846f5ec756f0e68f +#: 242566ff64584fba88e4fed8bb189110 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:28 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:24 of msgid "" @@ -431,301 +504,440 @@ msgid "" " 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 -#: f0a3afe6bc0c4eb2ad2e9e5ae43e2d88 of +#: 87d1cd7d6569498b8af8bc7064235784 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 of msgid "" "When True, do not call `start_TCP_Server`; the caller starts the server " "when ready. Defaults to False." msgstr "" -#: 577dd2f594554ceab51324eaedf4b1b3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 +#: ac43634ddb1a4d15a9f3d0f58d011441 of msgid "" "Negotiate the RSA-encrypted channel for every connection. Defaults to " "True." msgstr "" -#: 1ea6dc3b1a34463881e1aa7e96a14525 +#: 1ffccca56902418ba98ee0c6776ad8fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:37 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 -#: ecd4aa80607e4f988ac59b64e85c8fbe of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 of msgid "" "``[pub_key_path, pvt_key_path]`` pair used instead of the default key " "lookup; an invalid pair is ignored." msgstr "" -#: 0b92e71977dc4312b9e31fab903eadf2 +#: 420bbdf8d6bb400fbd3548bea03354ac #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:36 of msgid "" "Buffering ceiling in MiB for the in-memory forward pump; past it the " "uploader is told to pause. Defaults to 2048." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 -#: e14dae3d183249e19a0f6cf671ead02b of +#: 94e4a7e67e3047fd9d565f9a5d8122ab 9dcb36b97a004812bbcf264efa812441 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 of +msgid "" +"Bytes read per receive on the control connection, covering commands and " +"messages. Defaults to 4096." +msgstr "" + +#: 116dc6d56dd44f4ebaab990a3658359d 397abb5fbc1a46db90a7829daac02465 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:42 of +msgid "" +"Chunk size in bytes streamed when sending or receiving a file or folder. " +"Defaults to 65536 (64 KiB)." +msgstr "" + +#: 446099293d824f27aed7245f3c77df69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:45 of msgid "" "Serve clients with asyncio coroutines on an event loop instead of one " "thread per client, so a single server can hold thousands of concurrent " "connections. Defaults to False." msgstr "" -#: 07311d6c7a2f4516a4209df5c7798be6 9f213be174d243d4af26f79ae9624945 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:44 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:50 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:50 of msgid "" "Log execution-process lines in addition to command and result lines. " "Defaults to False." msgstr "" -#: 28ea5071c3344615b114f12ad5be447c 497004294ca244138115a713c0ffed15 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:47 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:53 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:53 of msgid "" "Log at all; False silences every line this instance would print. Defaults" " to True." msgstr "" +#: 1608cb9ad7104c82a43f23bb929f7d84 744b24d9e233457fb87cc8faefc5a498 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:56 of +msgid "" +"Track every running file transfer in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads): each entry holds the bytes " +"transferred so far, the total size and the current speed (None while " +"``is_enable_real_time_network_speed`` is False). An entry appears when a " +"transfer starts and is dropped when it ends. Defaults to True." +msgstr "" + +#: 3658f6b3ec994d15b9321a10ae33b351 769ed811a0cb4b18aeacdd39e4b4bbe2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:64 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:64 of +msgid "" +"Measure the real-time network speed of every send and receive — the " +"control layer and every temporary connection (file transfers included) — " +"into ``upload_network_speed`` and ``recv_network_speed`` (bytes per " +"second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False " +"nothing is measured and every speed value is None. Defaults to True." +msgstr "" + #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f0e9eea68114cf3b085d08796aaf552 3f8c413bab284fb78ac0b2ef8b8fb44a -#: 4a7a4c0862a84c53b2ccf0de3b00d495 4c3773b74abf40118b9ed681d9bef66a -#: 9f4fa9dc8d5045e39702036409f07a5d aa175c9daeab453a848bb2ef9f2e3dcf -#: cf96ad3305794cd7b9578ecb55ecd8b9 fbbf706646e24207aaf3b2532903a31b +#: 63ab5a2f2327475ba324e245f8e6e2ac msgid "Raises" msgstr "" -#: 0c72321c656641a5b684299b915cbb39 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:52 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:51 -#: d72a9dcf6bc748e5898640448e229b3b of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:81 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:73 +#: ed59ec69b9a1430597e6d8758051aff5 of msgid "" "If the ``.Flow`` directories or ``decode_command_table.json`` cannot " "be created or read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 -#: e2bb545e7ee1419286f58495abc4bcd2 of +#: 031d3e96394c454093561375a377dcce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:1 of +msgid "Pause an outbound transfer of this instance." +msgstr "" + +#: 342e6dfc6f6a4399914bc72372aa5f2d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. A " +"forward relay's writer toward ``peer`` is paused the same way the " +"``/pause_trans`` line pauses it." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:3 of +msgid "Transfer id the outbound leg is keyed by." +msgstr "" + +#: 7ecc0c956c8b408688fca517eb6370fd +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:10 of +msgid "" +"Restrict the pause to the leg or relay writer toward this ``(ip, port)``;" +" None addresses every match." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:14 +#: bdee1944910b4ee3908cf225a151a5fd of +msgid "" +"True when a running leg (or relay writer) was marked paused; False " +"when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 99ba2aa702f74621ba4dd31b8c045467 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:16 of +msgid "True when a running leg (or relay writer) was marked paused;" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:17 +#: c85ed4c1a84443a98394146efcf04315 of +msgid "" +"False when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 2771724616054f628d60add2c7407e7b 3a0594b22c6849c88310243022e8ee23 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:1 of +msgid "Resume an outbound transfer paused with `pause_trans`." +msgstr "" + +#: 7a864ecc76fe40459eeff353522482fb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg or relay writer toward this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:9 of +msgid "True when a live leg (or relay writer) was resumed." +msgstr "" + +#: 364557403e3d480896c0ffc57a19df04 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:1 of +msgid "Ask a connected client to pause its transfer toward this server." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:3 +#: f13c2e0e5310443080b0f63c773d8497 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (see `pause_trans` on the receiving side)." +msgstr "" + +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:3 of +msgid "Connected client ``(ip, port)``." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:5 of +msgid "Transfer id of that client's outbound leg." +msgstr "" + +#: 5ea8eea489fc43108a439d54fba31068 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:8 of +msgid "True when the line was written; False when ``peer`` is not connected." +msgstr "" + +#: 38905ec7539d42e0839907c32dd8667f +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:13 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:10 of +msgid "True when the line was written; False when ``peer`` is not" +msgstr "" + +#: 1c7b88e29a0143a39e13441769186ef4 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:11 of +msgid "connected." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:1 +#: adfc486a05ae4063bda6a61f2a6f3c36 of +msgid "Ask a connected client to resume a transfer paused earlier." +msgstr "" + +#: 810bc26336b24ad1acba3f56d466f8e9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 of msgid "Reserve this server's port range under the cross-process lock." msgstr "" +#: 5540b6efb5864c188e080ec7aad5c3ca #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 -#: c9ae1464a03b44049e826b9b73e2aca2 d23fda91e3e645e081dd5bbd5332fc4c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 of msgid "No-op unless ``is_hand_alloc_port`` is True." msgstr "" -#: 0b8bb2090cd04385a9d960dd2808f5bc 55b8a82ae1ce4769a1c62b35d253810e -#: 6d17c5fb7b4d484ba017edb4c5d5535e +#: 356ed2e8333d49b98ed6834612b4b56d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 -#: c3818bbf57ac448cb073fb780326fdf7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 of msgid "Step between candidate ports." msgstr "" -#: 1080747700804d04ae169eef511d5bb5 45799e3c1b6e446a86b111e06365ca9b -#: 5bfd1aa496dc41b7ab2abd78f134c389 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:8 -#: efa8e8819eec4e1ba0d90562f34755b5 of +#: e18848eedc5d4d8abd97d73a0984a5d3 of msgid "Number of ports per step." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 -#: c1cf751ac2774558925ef1ffd1a6c3dc of +#: 11e0523d1b194702a07a92748468da25 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 of msgid "Release this server's reserved port range." msgstr "" +#: 801c063c5fa447bda1dbf7f5ccbc6a9a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_lock:1 -#: b2b2a77e9deb4423955004a9e3390aca of +#: of msgid "Create the lock file that reserves the server port range for this process." msgstr "" -#: 658bc1e35a794bf5a22c70ffbef94b87 +#: 672bb7a9496c43ac8b706a3d0062ddfd #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:1 #: of msgid "Report whether the server port range is reserved by some process." msgstr "" -#: 39bb21b4d3a0404fb64295a73c2ad5ba 5dc09f28266e4a3bb083923d8784f09c +#: 39423e052b70403ba07a713aa9e3cb4a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:3 #: of msgid "True while the lock file exists." msgstr "" -#: 6512b0b8da7041e8a917014e5562583c +#: 5b6cf828ffb24e098a0c86a09818da73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_unlock:1 #: of msgid "Remove the lock file that reserves the server port range." msgstr "" -#: 90520dc2f5704cdaba37211d6390b03d +#: 479bdf5518dc4a029ecf47ad44bdcd5d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:1 of msgid "Allocate the next free server port range and record it on disk." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 -#: cf0980ef8455426781e617a911f73732 of +#: 34c085a1bfca4dedafc749bfdcf14ad5 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 of msgid "" "``port`` is moved past the ranges already recorded by other servers, so " "the instance ends up with a range of its own." msgstr "" -#: 1e5f1ba9b8bf4d28971b92ef12f747f2 +#: 197b30e318d741c2b1f8afc925e91e5c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:11 of msgid "If the server port info file cannot be read or written." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 -#: bf4bb338fcf846a29910656081787945 of +#: 1c97c8ef484b42ab86d36b3742bf3879 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 of msgid "Drop this server's entry from the on-disk port range record." msgstr "" -#: 30208c231b534eedbe843d42a3cad90d +#: 9fc07e857fa048e2956e64bf78f6e386 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:1 of msgid "Allocate a transfer port, waiting until one is free." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 -#: f219ec3cd1d1448fb4e0171853a7d779 of +#: 505d7b9fb1024bc8ba886e5b0a38fbf2 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 of msgid "" "Allocated port, or 0 when allocation is disabled " "(``is_hand_alloc_port`` False)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:5 -#: af35fb0d306d447ca2a70b0f2b63ecee of +#: e85fdf7f7a594e0b9aed565b4a3ab42f of msgid "Allocated port, or 0 when allocation is disabled" msgstr "" -#: 94b2dff9085247fda189e063a4fa4a7f +#: 153357eb91794cb692467afe5e94b41c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:6 of msgid "(``is_hand_alloc_port`` False)." msgstr "" -#: 06c8b24821f94f48b265dd90995e10a9 57f02c9c5f32443e82feac04411b32ed +#: 26c5c3768e1446e78c9efc5f8038b23d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:1 of msgid "Release a port obtained from `palloc`." msgstr "" -#: 750aeace3a2043978210096a24199700 +#: 0e0379de669843778f6827973c29372e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 -#: a400ec85715c462e941f3f590f646046 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 of msgid "Port to release." msgstr "" +#: 6a8d4efd9f9a45e399525e2f169035ee #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 -#: c6c5882e52c74fb1a5aa68e621922150 e95eb44c45ea42a5b63026f73274f990 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 of msgid "Allocate the next port above the base, or the first free one in range." msgstr "" -#: 2aec0e66e9e44175a6d6a36917137cf9 +#: 73e9e2ddd451402a93d10dbac6ac9374 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 14bd404133c744e68356290e50c91f4c +#: 9d96a242eab8433ca750d670a5f63b82 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:5 of msgid "Allocated port; None when the upward range is exhausted; 0 when" msgstr "" +#: 7b05e18fccbe4ab081d3cd22d59a48e0 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 -#: a2a1781441e64797a0d7942463680610 bccdcb4c96de4d6a9f6c4318d0b1f55e of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 of msgid "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 9b0a4b0fa07b4f7e8e4476f99d191837 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:1 -#: a4c53c6cf9d24f1ca624f8ade02cfb07 of +#: f2d9abe435cf49f6825bb72a68013934 of msgid "Release a port obtained from `file_palloc` and step the cursor back." msgstr "" -#: 24467ee3998b40bd9563059c6610e4e9 2a1c562ca62f40158d89d6f16896ed18 +#: 6c1fb07a212d4bf19717407b0c7184d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 -#: ace99e97fef7403faf20dc5040a47bfa ba3e6daae9e34590bc0f2abc98c02da3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 of msgid "Port to release. Ignored when allocation is disabled." msgstr "" -#: 053f2e52a148421eb080c1df3d3de1cc 9052b949aa354df7968cacc9ed930921 +#: 1afd81c685234a20aa41c5cde93d327d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:1 of msgid "Allocate the next port below the base, or the first free one in range." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 -#: eb3a97b7706a47dda4cfb5e12930ba02 of +#: 3fc63f6d51aa4c0fb22fd0f945f9cfd7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 3c8cc24113bd420eb7f373cde6a27ef2 +#: 74a441ccfa5e421dadd215ef0725a25f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 -#: f70a4f056d6c49b2b953824ffab19db7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 of msgid "Allocated port; None when the downward range is exhausted; 0 when" msgstr "" -#: 383142a0285745bb8ef4b95b1d597151 9f78428fda474dffac2f3cdf4c3a2aeb +#: 9c4b9bddd98c463f9e140bd2d8425dad #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:1 of msgid "Release a port obtained from `spy_palloc` and step the cursor back." msgstr "" -#: 57c8111cd86f49c7af67d8e9a177a591 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:1 -#: e435af0f27b641168044b3cac4130ac5 of +#: c66c76cab8564da4b6b6cb855fd63fd5 of msgid "Register a custom command handler." msgstr "" -#: 39f637bfe6ff4822952d67419861841d 51f84d06854b4b96b7ce1fb2e778b5e5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of msgid "" "Command to intercept, e.g. \"/my_command\"; matched case-insensitively " "against the first token." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:6 -#: b53c2039d55947d689c2cfe09cac93c2 of +#: c7c29a3836c9493e9c8804cc5896144a of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back to the sender as the response." msgstr "" -#: 15398a9c312e459a897c07b18dc9fbaa +#: 7c64d0c0b9ac44b995811a0fdaa0dfaf #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:10 of msgid "" "\"server\" for commands arriving from clients, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 7ff63de06e854f88b1cebc42b464397d 8f139fd48e9c496287f9df897ccf01d6 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 +#: a0c074a9da664c5eb5fa63deb6765c36 of msgid "" "Run the handler on the worker pool instead of the reader thread. Defaults" " to False." msgstr "" -#: 1a0a724bef6140ceb235cbeaea95c1d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:17 -#: e73cb64f1ef544db8009b026ab5c376c of +#: e6c616f887334cb6925c03de2ad6f64c of msgid "" "False when ``where_to_run`` is neither \"server\" nor \"client\"; the" " handler is then not registered." @@ -733,60 +945,107 @@ msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:19 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:19 -#: e1cba64f5b384d169c366d8e16078683 eaab849e83884bd6be80fa08867ccde2 of +#: f125f1386b434f3a8199b1ceb8c44eca of msgid "False when ``where_to_run`` is neither \"server\" nor" msgstr "" -#: 4cbf71104b8544d18962b7a9adca8b7e 82c461f38cc44bc9914cb7009a5cf3e1 +#: 1a68dac068db434eb76e28015005f29c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:20 of msgid "\"client\"; the handler is then not registered." msgstr "" -#: 15aa55a075a64bb98f5819a8a5d37113 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 of -msgid "Register ``listener(client_id, message)`` for every inbound plain message." +#: 25c1023e97b64226a58cdf83f8ba07bf 9ebd0da560d747168cebc59ca93b1cb1 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:1 of +msgid "Call one registered extension command handler directly from code." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 -#: f914714947174f2298278112a91d82b0 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:3 +#: b14f4ed43e6c43c39579c1c16b169645 of msgid "" -"Plain messages are the lines received from clients that do not start with" -" ``/``; commands go through the registered command handlers instead." +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines clients send. " +"The handler runs on the calling thread — ``run_in_thread`` only affects " +"the console and inbound dispatch paths — and is called with ``None`` for " +"both ``client_socket`` and ``client_address``, since a direct call names " +"no peer." msgstr "" -#: 1b5e4524170242099c808039098d64c3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:11 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of +msgid "" +"Command line to run, e.g. ``\"/my_command arg\"``; the handler receives " +"it unchanged." +msgstr "" + +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:15 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:15 +#: of +msgid "Whatever the handler returns." +msgstr "" + +#: 0ab70b2e8ed040d4908d0900da96f6c2 0d85b81af0634a448e6a74d63c06045f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:18 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:18 +#: of +msgid "If no registered handler matches the first token of ``command``." +msgstr "" + +#: 1f5b21975ad2499a86fe21c69bfd7ca0 42f8d27a5499457da7302224dcc8a521 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:19 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:19 +#: of +msgid "If ``command`` cannot be split (unbalanced quotes)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 +#: ef5d20f1a16945368383a8cdbc3daa19 of +msgid "Register ``listener(client_id, message)`` for every inbound line." +msgstr "" + +#: 2459179e833b4e7db8e1d70571ac793a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 of +msgid "" +"Every line received from a client is reported, commands included " +"(``/help``, ``/file ...``, the crypto handshake lines, ...), so the " +"listener observes all inbound traffic; dispatch is unaffected, a command " +"still goes through the command handlers." +msgstr "" + +#: 9ec5fafe8ded489785400e3e489b8573 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:8 of msgid "" "``listener(client_id, message)`` where ``client_id`` is the sender's " "``\"ip:port\"``. It runs on the receive thread, so it must not block, and" " exceptions raised inside it are swallowed." msgstr "" -#: 2e65864bfdd2429298dbf86682b3be81 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:1 -#: e562b99848544a8cb47afb41478d1b66 of +#: edb8edc2eb3f433186b54807a8ac43ad of msgid "Unregister a listener previously added by `add_message_listener`." msgstr "" -#: 346bd1c9d44045868b59b7643f1cf09e 8ff591c39e334e1eab8d05267532faed +#: 6fd7bb75a29e4973ac2bd05119255039 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 -#: a0e48bdcb67e49498a113a58a504553c ab196c3b77b143069faa85a52626d946 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 of msgid "Listener to remove; an unknown one is ignored." msgstr "" -#: 46010db8ce4d4eb1b06348f29e115846 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 +#: cf95477e5794404fbdf4e877a132ba1c of msgid "" "Register ``listener(client_id, full_path, name, size, command)`` per " "saved file." msgstr "" -#: 72536042242c4ea9bd2e6efa63fc9336 +#: 9c57d09f6d3d437890ae3ad306071701 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:3 of msgid "" "Fired after a file uploaded by a client (a direct send, or a forwarded " @@ -794,8 +1053,8 @@ msgid "" "``file_transfer_dir``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 -#: f4ba3546e2b048d49d9c274ef8d8ac98 of +#: 6c938b7c8be3464f9925527b6deb4e1d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 of msgid "" "``listener(client_id, full_path, name, size, command)``; ``client_id`` is" " the uploader's ``\"ip:port\"`` and ``command`` the wire command that " @@ -804,196 +1063,185 @@ msgid "" "block." msgstr "" -#: 2e1706c637c54db9b8ed55ba98665535 3d6b3f43b6094b2e9776fcb9e4ce7bcb +#: 57b1e98125974187b986386da7991dd0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:1 of msgid "Unregister a listener previously added by `add_file_listener`." msgstr "" -#: 0a8d57625bba4ce4949fc23bce63f033 +#: 58f1ccd078ea406dab00d6d4be886a76 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 -#: c27185227a5f434f9641501d1d3bca2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 of msgid "Run a callable on the instance's worker pool." msgstr "" -#: 0c5aed09b63647cd87a3234ef9a4903c 40fade944d8d43b18599150134015443 +#: 6e05c7f46b244ae195c32ee52797fa37 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:3 of msgid "Callable to run." msgstr "" -#: 6bcb8f96e0584f66bbb94fe2573a7f61 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:5 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:5 -#: e959076fdf3843fc9c53ccb8492adfe6 of +#: e1c79706c9414895bdf7bf183bf5d41a of msgid "Positional arguments forwarded to ``func``." msgstr "" -#: 41d755cbd3cf48e7a0bc9d2b1aa3ab14 628a65eab1354dda83077715a47e63fb +#: 9221436fa83a4831942cf5be4e37e2cb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:7 of msgid "Keyword arguments forwarded to ``func``." msgstr "" -#: 1c03aa271c37431d974f08f11c93d7af 4b1078858cf64a1e92b36fa109fc1409 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 +#: a6b26d6cf54d4fafac2950cbe33ba56f of msgid "" "Handle for the submitted call; its worker slot is released when the " "call finishes." msgstr "" -#: 169f874c0ebb40d5aecd2549e60b4600 1e45486e3fd84627b015bf5a9a0a24b4 +#: 60f19983f7384aefbb6c97b84dd25f93 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:12 of msgid "Handle for the submitted call; its worker" msgstr "" -#: 037748a51dd94d43a3939fa8ec538d66 655c7802ef7c42a686c74d426531db8b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 +#: eadf6af0a0954798933dc427ba8e107e of msgid "slot is released when the call finishes." msgstr "" -#: 7b0b391fc53d42fb8f331d8e2da2be54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:1 -#: d6578909a33e4eef8afe892b33e0f70b of +#: fece61298a354d6db119309b29c6751d of msgid "Start a temporary listener for a side channel (not the main protocol)." msgstr "" -#: 1164584733744eb2aa574d6f61476c2d +#: 01d42ba32c2b41f482dd077cfb950f9b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 -#: c132c5365e7c487c92b4072a0020b52c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 of msgid "" "``handler(client_socket, address)`` started in its own thread for every " "accepted connection." msgstr "" -#: 03583460bc824965b9152433dfdfb097 +#: 5e1b84445ee34c9cac00e1a2c9ef297b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 -#: e81f361ea0fb46ee9c6760b0c6ef11c1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 of msgid "Port to bind; None allocates one with `palloc`." msgstr "" -#: 4f2f3f063e9c4834a77fbdb1a46d65dc +#: 9c69c4dd1d904078af48c6308ba35895 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 -#: b655787e48384873b4446ee1147bdedd of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 of msgid "Listen backlog. Defaults to 1." msgstr "" -#: 31cd65b92bb846f6b9c97b003fa00db5 +#: 47f98fd15e6144bd845d175cd039a6c2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 -#: ec56b80af0a843a991cbe77c5ee9ae45 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 of msgid "" "``(port, thread, stop_event)``; setting ``stop_event`` ends the loop," " which closes the socket and frees the port." msgstr "" -#: 7b73372b2ada4ce5b210b527015d925c 86cfce9d36f04328ba76e88df87fbcd8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 +#: ecf3d32c44db40a8a13545d623ffe2c9 of msgid "``(port, thread, stop_event)``; setting ``stop_event`` ends the" msgstr "" -#: 11b0347a0ebd4ae3931ed1f77c26a04e 9017aeb8480241f3a5f426c718bc4ee0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:14 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 +#: abce9546b7444c6383c9020c4133ec63 of msgid "loop, which closes the socket and frees the port." msgstr "" -#: 3c32a346019741da9aa2a3e409a7b0e2 82f16e3e9ba1468d8a87c91db28cc45e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 +#: a270cfabdac64296b8a33ad4d662896f of msgid "If ``port`` is None and no port can be allocated." msgstr "" +#: 031d3e96394c454093561375a377dcce #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 -#: d63b5db9eab6478ca088c9a5e90163fc f0869b5be0ab40e4a2a7eca275922557 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 of msgid "Open a temporary outbound connection for a side channel." msgstr "" -#: 3d194b9f95794116b17720aa74ce0878 +#: 112fda54e1eb4981b4272df61c5416e2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 -#: d0bb03d9590540fd980dd79c28d98e97 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 of msgid "Host to connect to." msgstr "" -#: 98a5441019de48258a099f2ec25751f5 +#: 59d3c414b4304673be5d3232d2291680 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 -#: b443afa67dc84e1a8ac501ad5c6b0ff1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 of msgid "Port to connect to." msgstr "" -#: 537482efdcc0447e81bd001ad2d4d85a -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 +#: c5766672f68f47c9908e68d2ed3be7f3 of msgid "Local port to bind; None lets the OS choose." msgstr "" -#: 2230b0e486fc4229acc03f78ec4b1e09 300e61efcfef4a2f8c87725e183ceda8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 +#: bfc1b713e9fc4fe797e50c357f472e76 of msgid "``on_data(data, client_socket)`` called for every received chunk." msgstr "" -#: 2f63095ce33849b78465729923d04ff0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:14 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:13 -#: e07d5e5deb1a4fb086664ed896076feb of +#: c563d04fcd7a41f1a2aeace42974430a of msgid "" "``(client_socket, thread, stop_event)``; setting ``stop_event`` ends " "the receiver thread." msgstr "" +#: 0e1b9679f3104a9caab601e6bc7c0905 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:16 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 -#: bf9994c99c8a48139d4c00d0dcfeca63 dbf60e58abd04e02b50316b1cb4b7b2f of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 of msgid "``(client_socket, thread, stop_event)``; setting ``stop_event``" msgstr "" -#: 6af1621f80734591950e545b955c4bbe #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:16 -#: e69a51e576e446c59185c2eceae72657 of +#: c76fce92c3f944c1857df89bbc134540 of msgid "ends the receiver thread." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 -#: c291ec3d31094e589a1bfc5713b47ee3 of +#: 5ea5fd66c3d3434292e4d8e1dd1da094 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 of msgid "Send one message to every connected client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 -#: c28f38641c704c1e912c602ced57fc9e of +#: 32945f04e0564f9d88495506f0ab4f90 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 of msgid "Clients whose send fails are disconnected and removed from ``clients``." msgstr "" -#: 3f3e7a6a5de746518e9ddd135983d073 +#: 00de0b1f60b14189b1629f8146db68a6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:5 of msgid "Payload passed to `send_message`." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:7 -#: cae2a2c29d96447d8b1056e36bbf5572 of +#: a91c8f6921c7435e990516c2134efcf8 of msgid "``(ip, port)`` to leave out, typically the client the message came from." msgstr "" -#: 9b2b7c4e77844a82bfd61276bf46f6d7 +#: 9d57c62f1fd94c1dacfe32aa50cc9665 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:1 #: of msgid "Send the messages of a console line to the clients named in it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:3 -#: cabc278e7f6a49e6bd6e533f632d0f99 of +#: e7fbf4bbd84b4920a2b9591fabcaf2d9 of msgid "" "``/send_msg`` line as typed: message text followed by one or more ``(ip, " "port)`` identifiers; each message is delivered to the identifiers that " @@ -1001,17 +1249,17 @@ msgid "" "notice." msgstr "" -#: 888e165ca1554b4db63e714e3adc63f1 +#: 9d4819fe4ca94a1b81c9e0423ff98212 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:1 of -msgid "Write one line to a client socket, encrypting when the channel is up." +msgid "Write one message to a client socket, framing it when the channel is up." msgstr "" -#: 64d6f6cc29de4d4290671afc59d808c7 +#: 1c7b88e29a0143a39e13441769186ef4 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:3 of msgid "Target connection." msgstr "" -#: 73953d67bcbf4bfabae7b0ff91bfce8c 7e2e221f6a6b43a08f534ca2d8cfb6e8 +#: 6f8bd9adaf2b4c44a9446b049144fe21 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:5 of msgid "" @@ -1019,62 +1267,73 @@ msgid "" " are." msgstr "" -#: 240dadd589af42e18e15d2c53b5c96b0 +#: 5c03983cb460497fb72f126c1d8a2bc1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:9 of msgid "" "True when the payload was written, False for an unsupported payload " "type." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 -#: dbfc49c3c67c48d5860a61f8ded20950 of +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 of msgid "True when the payload was written, False for an unsupported" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 -#: cab2f5321ba54adca315d34d921a09b5 of +#: 602950a9f5ad48ea92ab60aea3b26488 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 of msgid "payload type." msgstr "" -#: 4519dac81e714164a0edbf6ac75c9c19 +#: 149f767d72dc4da7b1d88fed768d2474 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:15 of msgid "If the server is not running or no socket was passed." msgstr "" -#: 7ea1b30273604db4854189502fdf734e +#: 07dac2d20d7041779c8b189d45ee2e64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:16 of msgid "If the socket write fails (the original error is re-raised)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:1 -#: b228437e9cb4461e9ceb078f084544eb of +#: caf2377ee7f348ab8c95bf2a27c44be4 of msgid "Read up to ``msg_length`` bytes from a client socket." msgstr "" -#: 292c2ed074e14a5eb184dceb245cab6f 58a8806cd0bb4dc9895b7f74a1b45765 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 +#: c702e4a63a5240ea97feb5bc393b4d09 e9256fbce5d848b59ae2e6d0ce88ce24 of +msgid "" +"A socket speaking frames (see `_SecureChannel`) returns decrypted " +"plaintext, served from the channel's buffer; a socket without one is read" +" raw. A read that started while the channel was raw is classified by the " +"channel when it returns, so bytes of a flip that landed during the read " +"never land in the line reader." +msgstr "" + +#: 214af2667d0f443eb16c0a4aaf723b2e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:9 of msgid "Connection to read from." msgstr "" -#: 547ccf662a6945738e8c761628807ab1 624220029a624009adb07a49140d8a2c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:5 of +#: 7c3eb31687804ba5a59acc140ba50230 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:11 of msgid "Maximum number of bytes to read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:8 -#: b0973e75b118425db7e7bfc966e5eb87 ff5195026f8143fea9240d4f21e81981 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:14 of msgid "Received bytes, empty when the peer closed the connection." msgstr "" -#: 7acd066bfa87415094144b0e0c1ea0d4 +#: 7103cfcec26c44999cb5464251ee461c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:1 of msgid "Serve one accepted client until it disconnects." msgstr "" -#: 53591274f0824492afab6874b284c33e +#: 65f9de7f44774aa6aef81fcbe4dc1c64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:3 of msgid "" "Registers the client, greets it, announces the encryption mode and reads " @@ -1084,8 +1343,8 @@ msgid "" "ends for any reason." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 -#: fba3167476a94b62af90bfc4101d1ed6 of +#: 87d5085c31a14ad38b060c48f8cf1262 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 of msgid "" "With ``is_asynic_clients_io`` False (the default) the call blocks and " "owns its thread; with it True the client is served by a coroutine on the " @@ -1094,22 +1353,22 @@ msgid "" "no event loop runs is closed with a console notice." msgstr "" -#: 72edaf343723458fb9b2fe0f40bc01b8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 +#: db3915757e2842c8afee97b2d471411e of msgid "Accepted connection." msgstr "" -#: 6a2427e7b7de4d609bf61e3fad46b413 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 +#: fae378e888be4821a14ed2483cfde1e0 of msgid "Peer ``(ip, port)``; used as the client id and as the key in ``clients``." msgstr "" -#: 061015c431a54fafb45ea722ae696003 +#: 32886e2babcf4283924034c600453c4a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:1 of msgid "Dispatch one command line received from a client." msgstr "" -#: 9cc9ee25bc464440a4ac2bca19e5a413 +#: 8972b8c4edf149fd9a4008832c85ed31 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:3 of msgid "" "Built-in commands (``/help``, ``/time``, ``/clients``, ``/quit``, " @@ -1120,24 +1379,23 @@ msgid "" "close the connection; an unknown command is only reported on the console." msgstr "" -#: 9a970df310fc4b59b113bb6160f24fd2 +#: 208294924333477a8e7d65aa3130777e #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:10 of msgid "Connection the line came from." msgstr "" -#: 8856eb18fd044b60b869be64e5f4576e +#: 306e5026cfc1441d8c754f0e02866cf3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:12 of msgid "Peer ``(ip, port)``." msgstr "" -#: 6ea3bacf1baf4eadb98d5e38236ecf90 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:14 -#: e212b51318ea4d46ab6354b818dc262b of +#: a2a3a1fd57e14260a53675457fdff0b4 of msgid "Line including its leading ``/``." msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:17 of msgid "" "Response for that client, or None when no response is due (crypto " @@ -1146,11 +1404,11 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:19 -#: b3f201060ae548098d8284d4c18c0560 of +#: ed04a3bf285b4f57bb6a5de0c4f7284f of msgid "Response for that client, or None when no response is due" msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:20 of msgid "" "(crypto lines, file transfers, ``/quit``, which answers on the socket " @@ -1158,114 +1416,108 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:1 -#: b4ee832e0ad64d189740b45a297d713d of +#: a784dfdc5ded411d985426e36f6e5435 of msgid "Send one plain message to a connected target, tagged with its origin." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:3 -#: ec8cc922a2ee4e70bdff9a8e81b74e98 of +#: b545977244dc402aa8586264d2d933f3 of msgid "" "Public API for forward extensions: the message is wrapped in a " "``/send_msg_from `` envelope so the receiver can " "attribute it to the originator (see `parse_forwarded_message`)." msgstr "" -#: 660b6f4493ec4c9994af44960900cb10 +#: 8ee5275fbf894581ade9e6f30d5d4aff #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:7 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 -#: b8a3838c85624f3dbe705afac78acc47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 of msgid "Destination ``(ip, port)``." msgstr "" -#: 1dfa946975cf4768891292e84a2bbc63 +#: 38ffd8a7079d4794811e3504c01052f8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:9 of msgid "Payload to deliver." msgstr "" -#: 09f6b3913160404b9927d5e70252d9bc 5251c2b3867b4dc1b8dd8d09ea570d90 +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:15 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 -#: a8ee713ff78b42bd8adb5743ab369aef of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 of msgid "Originating client ``(ip, port)``." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:14 -#: ad5e4419a1d04b27bec64cf1aee14c53 of +#: d2471a90e269464c977239f406051120 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the envelope was sent." msgstr "" -#: 2fd94dad15884a56b9657090a33988f9 9e706f8851a74b569ade8deb4f8f70ab +#: 320d99b8923f4eaa886ffe0a16bfc6d9 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:24 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:16 of msgid "False when ``target`` is not connected (a console notice is" msgstr "" -#: 59049e3514b74a7ba90fb8886ecca185 +#: 1a97f59b270f404096d9c2b37ab09a8c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:17 of msgid "printed); True when the envelope was sent." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 -#: b9019e7dae074d64a66ae1c81967b9b8 of +#: 6baab06dc12e4ecc80d1a16c26c2a19a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 of msgid "Build the tagged wire command that pushes one forwarded item." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 -#: fcde926ccf5640b2b2ac6aab009aa4d0 of +#: 0c3f9dcbcf8f413fbd5befefb960c402 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 of msgid "" "Public API for forward extensions. The originator tuple sits before the " "trailing transfer id, where the receiver's existing parsers ignore it and" " `parse_forward_originator` recovers it for attribution." msgstr "" -#: 3cee0d37a9e5460a90b7c9b1abe53a92 +#: 3cf58937a2d04172bf544119279d85c1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 -#: d5cb9e15787a435ab586217498d98e2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 of msgid "\"file\" or \"file_folder\"." msgstr "" -#: 8efbb4663727491e8ee77edc824ce1c0 +#: 621a93603c8549c0ba047bee6aae5a38 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 -#: e8aeb2b89d5f4969aeaf2244f06a1a47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 of msgid "Relative folder path (folders only)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:13 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:11 -#: b439157e6df44d7bac2a4367c5fb66ee b9cb86fb0ad642e18ec19debb44a2648 of +#: f0f56fb642874c3889fb0dacfed4f4ef of msgid "File or folder name." msgstr "" -#: 5f249d30e8934ed0ae07c1ca2666c6c6 +#: 72d2b6fdd324482eaea9803def1fe2da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 -#: df45d1036cb9437a853551afb3f31775 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 of msgid "Transfer id shared by the pushed item." msgstr "" -#: 9bc7aaf1a36a4311a736f5528525d33a +#: 0aa1bd5b053544e98ae4ab3ae1add5f7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:19 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 -#: f806614c8aeb428292d6ca51db8ca35b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 of msgid "Receiver-side destination directory." msgstr "" -#: 1f3c679edcf34e71a946e8668ca27a58 +#: 93e666db45e745619b90c744e1646b73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:20 of msgid "Command line to hand to `send_message`." msgstr "" -#: 3499106d953f41789e53f24bfcae3af5 +#: 56d8327bb7414a5e85292f8f2ace9d42 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:1 of msgid "Push one forwarded file or folder item to a connected target." msgstr "" -#: 959c24d8afff4486ad5f787311bf3c8b +#: 3098afa7f4ac43a184d081dda8faa6ba #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:3 of msgid "" "Public API for forward extensions: sends the line built by " @@ -1273,24 +1525,157 @@ msgid "" "`parse_forward_originator`." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 -#: cb11d22918824fb09fa82fd432aeb74a of +#: 9b9634061040430484cd2596f43a8feb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the command was sent." msgstr "" -#: 66262977fc014465964289448673a5b9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 +#: b8bb8c432f7649d5a35480fec0509a51 of msgid "printed); True when the command was sent." msgstr "" -#: 1df1cd85678d4149bdac92c3591c9e50 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:1 of +msgid "Receive one file over a transfer sub-connection." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:3 +#: d3367c6f97aa4bf4b9cb3d79b3117fce of +msgid "" +"``peer`` is the transfer's original sender (the sender for an inbound " +"transfer, never a relay): it is stored with the progress entry so a later" +" reconnect can ask that peer to continue the file." +msgstr "" + +#: 5c4faf52e8bb4808805bae58d30ac0cc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:7 +#: de641d48c530435bb4adc04755a47a6d of +msgid "" +"``resume_entry`` continues an interrupted transfer: the listener " +"announces itself, asks the sender to continue from the bytes already on " +"disk (``RESUME_LINE``) and appends the incoming chunks to the partial " +"file instead of truncating it." +msgstr "" + +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:1 of +msgid "Send one file over a transfer sub-connection." +msgstr "" + +#: 87862abb10ad423f820952355f5936bc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:3 +#: d6a618c007ec433fa10a44b0a7a90fe4 of +msgid "" +"``control_socket``/``crypto`` carry the listener's mode stamp (\"plain\" " +"or \"enc:\"): an encrypted leg aborts when the session key " +"material is missing rather than downgrading silently." +msgstr "" + +#: 97e1a0538f544c2a8e755c78805fda7c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:7 +#: a405431dfd62434b82c7052edc456123 of +msgid "" +"``fid`` is the transfer's id — the caller's own transfer id for a plain " +"send, the relay id for a forwarded upload — and keys this leg in " +"``file_upload_progress``; every leg with a fid can be paused with " +"``/pause_trans`` for that fid. None (a leg without a protocol transfer " +"id, such as a public-key push) tracks no progress." +msgstr "" + +#: 6cb58bfd1dde4b49ba3525af014e44c7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (never a relay): it is " +"stored with the progress entry so a later reconnect can be resumed. " +"``resume_offset`` continues an interrupted transfer from the byte the " +"receiver already holds: the file is read from there instead of its first " +"byte." +msgstr "" + +#: 1634dbe84a95421a92a660f7c6fdd10e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:1 of +msgid "Continue the interrupted transfers of a peer that is back." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:3 +#: eb46142fa4e44147ad3ad8c680d5bee0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and, for " +"every download this instance was receiving from ``peer``, opens a fresh " +"transfer listener and asks the sender to continue the file from the bytes" +" already on disk. Restored uploads need no action here: the peer drives " +"their resume from its own side." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:9 +#: b7d54977ca494a8b9968365dffd9bd3d of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer that is " +"connected right now." +msgstr "" + +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:13 of +msgid "Number of resumed receive legs started." +msgstr "" + +#: 52cb873f015542b6a94506cebfe735a1 737ed182911443bc8cfff3c4d094b9a9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:1 of +msgid "Continue one interrupted transfer this instance was sending." +msgstr "" + +#: 50f292ac853841c9b082eb3c3ff4d6f4 6c968a5b77b342ed891883336cfcc255 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:3 of +msgid "" +"Runs when a receiver asks to continue a transfer (``/resume_trans``, see " +"`resume_transfers` on the receiving side): the leg is re-established " +"against the receiver's fresh listener and the source file is read from " +"the byte offset the receiver already holds. Also the public API for " +"resuming one transfer on demand." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:9 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "Receiver ``(ip, port)`` the request came from; None skips the peer check." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:12 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:12 of +msgid "Transfer id of the interrupted transfer." +msgstr "" + +#: 7124e1ce01df4fcea9516bed4ca55dc7 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:14 +#: d94da1700d0e46028f7bf114d7c5da62 of +msgid "Byte offset the receiver already holds." +msgstr "" + +#: 1a97f59b270f404096d9c2b37ab09a8c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:17 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:17 of +msgid "True when the resume leg was started." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 +#: b03f4edeca5f4cc19f6d695aac3690de of msgid "Bind the server socket, then accept clients until `stop` runs." msgstr "" -#: 42bb4623926449f5b91a451bcac30a2f +#: 7e027ea659ab48e19ea346cb284fe144 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:3 of msgid "" "Blocks the calling thread. A console command thread is started when " @@ -1301,12 +1686,12 @@ msgid "" "Socket errors and the end of the accept loop both end in `stop`." msgstr "" -#: 3d3320ce03544f23ac6f43883e5a580c +#: 291f5a8cc4f648ee9910e5cd45074675 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:1 of msgid "Read console commands until the server stops." msgstr "" -#: 5f7369176edb4567b3eb5332588b8c57 +#: 1ba2e428d432496688ef23f1c07562da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:3 of msgid "" "Handles ``/stop``, ``/status``, ``/clients``, ``/send_msg``, ``/file``, " @@ -1318,12 +1703,12 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:1 -#: ccbb242b51984c9f8ce9fb519c202485 of +#: eb90f49c77e64006a0c9ae861ff849b1 of msgid "Stop the server and release everything it owns." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:3 -#: e379bbd3f7b249c6b296f371548a5b1e of +#: a059b1e71106487999c83c2e2042f509 of msgid "" "Closes the server socket and every client connection, flushes the message" " and event stores, releases the allocated port range, clears ``running`` " @@ -1331,152 +1716,192 @@ msgid "" " Safe to call more than once." msgstr "" -#: 06fe9e3a48914447af6464acedea1fa0 +#: 32b06ea315b3404caa3a05c4aed0ce64 #: PyFlow.network_api.connect_tcp.TCP_Client_Base:1 of msgid "" "TCP client: connect to a server, dispatch commands, send and receive " "messages." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 -#: ef04371450674badb666b7fb31c203da of +#: 2b30f5c9ecd24fc89cdcd58000ee1e99 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 of msgid "" -"Lines received from the server go through `receive_messages`: a line " -"starting with ``/`` is handled by `handle_server_command` (protocol " -"commands plus the handlers registered for the \"server\" side), any other" -" line is a plain message delivered to the listeners registered with " -"`add_message_listener` and stored in ``messages_dict``. With " -"``is_input_command_in_console`` the console thread `interactive_mode` " -"sends typed lines to the server." +"Lines received from the server go through `receive_messages`: every line " +"is delivered to the listeners registered with `add_message_listener` " +"first (commands included; a forwarded ``/send_msg_from`` envelope is " +"delivered as its payload), then a line starting with ``/`` is handled by " +"`handle_server_command` (protocol commands plus the handlers registered " +"for the \"server\" side), any other line is stored in ``messages_dict`` " +"as a plain message. With ``is_input_command_in_console`` the console " +"thread `interactive_mode` sends typed lines to the server." msgstr "" -#: 840ff55e5e444cfbb85251e9c4123178 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:12 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 +#: b9532c86786c43d5aea58b24157fefed of msgid "Server address this client connects to." msgstr "" -#: 1f65ef8a745743ebb31ebc5805c5b02f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:18 of +#: 2cfa1e3e1674407ba1e2683e76fef65d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 of msgid "Server port this client connects to." msgstr "" -#: 5956a034ca2347f384f682b52d927ee3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:24 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: af04fdee2c95431a9b0c17f96e50c18c of msgid "Local address the socket binds to." msgstr "" -#: 1d2b7be8ff994d15b9a3f63c0e4fab11 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:30 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 +#: b1d4b5606e1c48b6a915815527542758 of msgid "Local port, None when the OS chose one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 -#: d616019e80a741638b6ac020d6abb336 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:34 +#: d926b4f3eb4b40a4acb21f780a4dc227 of msgid "int | None" msgstr "" -#: 0a015a4f44194fe2b25bbd4dfe52d1eb -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:36 of +#: 500cfd177cf5453d887f6904b73b7851 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 of msgid "True while the connection is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 -#: da7ca1204aea47779bbaaa809f79da93 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:76 +#: fd832e1d72b642838382d529c3e1f22c of +msgid "" +"Whether `start_TCP_client` reconnects after the connection drops (and " +"resumes the interrupted transfers)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:102 +#: c194bbee7cf14d268c330e06f94ae973 of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when the connection drops and read back on the next reconnect " +"(`resume_transfers`)." +msgstr "" + +#: 40f2a9e1b730422db3dd58bc2a6046e3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 of msgid "Create the client and, unless extended, connect and start reading." msgstr "" -#: 9e0577d19b76432089a46a53a2bbf7be +#: 0552aa36b7b74474af8f43b380dbee54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:3 of msgid "Server address to connect to; required before `connect` is called." msgstr "" -#: 8400b2487cfb4cff8a72f452e3b4c83e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 +#: d246ff9aaf154bfa91b5c4c9d293afd5 of msgid "Local address the socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: 7cb2047b830c4996832b4623812a687b -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 +#: e981b68ebbea46e9b556b09f4b5cd44a of msgid "Server port. Defaults to 65432." msgstr "" -#: 7a0404b673f84a1191af5479097f8cf5 +#: 766bf4c138234fe081bbd2668dcb2a5d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:11 of msgid "Local port to bind; None lets the OS choose an ephemeral port." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 -#: df784379acc1474aba6566c969dbb7bc of +#: 5d661c0f91f64ef39cacb1a5466d752c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 of msgid "" "Socket timeout in seconds for connect and receive. Must be None when " "``is_wait_server`` is True." msgstr "" -#: 2b8bf92e3eb049ee8e994aa8b6d92fa5 +#: 9478d02062284ecaa7838f931ab80780 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:17 of msgid "Step between candidate ports in the allocation range. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 -#: fa74d746eefe4cb6862068fdbf384dd8 of +#: 2e1695ae510b43758793257124fd23c2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 of msgid "Enter interactive mode after connecting. Defaults to True." msgstr "" -#: 95ebbc90f84a41ada4b6edbec2c7a95e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 +#: e02da86957dd4f45bf84ede4e9c82cda of msgid "Keep retrying while the server is not reachable. Defaults to True." msgstr "" -#: 259f9e8d0d1547ae81e047e8ec24875d -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 +#: e1fb7f67e1714a61a9e8fe500555c700 of msgid "" "When True, do not call `start_TCP_client`; the caller connects when " "ready. Defaults to False." msgstr "" -#: 794bfe7ef8594729b0e87230d3ed9e49 +#: 1634dbe84a95421a92a660f7c6fdd10e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:34 of msgid "Negotiate the RSA-encrypted channel with the server. Defaults to True." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:40 -#: e3f9232109d34798af1f681b250ec7d5 of +#: cff66a7ac1ad410f96ed1ee03cb1cf53 of msgid "" "Buffer ceiling in MiB, kept for parity with the server class; the " "client's forward path does not read it today. Defaults to 2048." msgstr "" -#: 71b662106e594538b8a5fcb9bc190b1f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:51 of +#: 14c4889553fb42f7b0393a4a7ab46b4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:72 of +msgid "" +"Reconnect (and resume the interrupted transfers, see `resume_transfers`) " +"when the connection drops while `start_TCP_client` runs. The transfers " +"that died with the connection are persisted to the protocol's ``.Flow`` " +"directory and read back on the next connect. Defaults to False: a dropped" +" connection ends the client." +msgstr "" + +#: 0f06ff3b6db940da96ec09bee3dba526 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:80 of msgid "If ``is_wait_server`` is True and ``timeout`` is not None." msgstr "" -#: 4388cbc6302341adbdfa566d93526ef1 +#: 5dd677b9627d4b84b53dc7a6b2848b3f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:6 of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back as the response." msgstr "" -#: 14fcd0c8f3554ae983ac746cf3e58621 +#: 0a57a7875bb94767904ff8d93fa77eb8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:10 of msgid "" "\"server\" for commands pushed by the server, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 88087ef71067485dbd40d569a7b950d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:3 +#: acb1af86a6184624a47ac6cc3b7127d0 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines the server " +"sends. The handler runs on the calling thread — ``run_in_thread`` only " +"affects the console and inbound dispatch paths — and is called with this " +"client's socket and id, the context its dispatch paths give it." +msgstr "" + +#: 876e8fe2a6d645829ba12ddbad5006df #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:1 of -msgid "Register ``listener(sender_id, message)`` for every inbound plain message." +msgid "Register ``listener(sender_id, message)`` for every inbound line." msgstr "" -#: 50556c2d788d4e39a4a7cfed81ef6d6d +#: 2658650e027a4697b248f261903a4e29 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:3 of -msgid "Mirrors the server-side contract; commands are not reported here." +msgid "" +"Every line received from the server is reported, commands included, so " +"the listener observes all inbound traffic; a message another client " +"forwarded here is reported as its payload, attributed to the forwarder." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:5 -#: e6bec65449634cff953afd74d0e23e7a of +#: 412834182c9442adaf0b85e24c200ccc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:7 of msgid "" "``listener(sender_id, message)``; ``sender_id`` is the author's " "``\"ip:port\"`` — the forwarding client for a message another client " @@ -1486,21 +1911,21 @@ msgid "" "swallowed." msgstr "" -#: 38c576fe994b4a77830eaba36ca063b3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 +#: fc8a83e0b5f84273a8287b122c1a9a3e of msgid "" "Register ``listener(full_path, name, size, command)`` per saved inbound " "file." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 -#: e258540084d64816a08e0783810c4e3e of +#: 34e3386853564aab9a824e96438fc3e5 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 of msgid "" "Fired after a file pushed by the server (a direct send, or a forwarded " "file/folder item) has been fully written to ``file_transfer_dir``." msgstr "" -#: 4e10b4a74e9142e0868ab1b0b423f359 +#: 63f925709b83433e967610672b6fbc79 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:6 of msgid "" "``listener(full_path, name, size, command)``; ``command`` is the wire " @@ -1509,115 +1934,200 @@ msgid "" "it must not block." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 -#: afdf1e13067b4914a6aead736d7604e3 of +#: 4bc88415dfff40a3884ee0284b0ccc3f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. This " +"covers every outgoing transfer — a plain upload as much as a forward " +"upload — and is what the ``/pause_trans`` line does when it arrives from " +"a peer." +msgstr "" + +#: 7e190ff27df349ae90eb7bd98a0b6b5b +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:11 of +msgid "" +"Restrict the pause to the leg whose original receiver is this ``(ip, " +"port)``; None pauses whichever leg holds the fid." +msgstr "" + +#: 5479763134c04a418df6a9e5011a9dcf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:16 of +msgid "" +"True when a running leg was marked paused; False when nothing matched" +" — the switch is still armed, so a leg started later under this fid " +"starts paused." +msgstr "" + +#: 2bc5d7e5dfa94eb29b49f12562f57c88 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:18 of +msgid "True when a running leg was marked paused; False when" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:19 +#: a9c7cb3036f8409faad4c1db964d8a91 of +msgid "" +"nothing matched — the switch is still armed, so a leg started later under" +" this fid starts paused." +msgstr "" + +#: 59fa8126f08348bb9368c35b5d2336e2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg whose original receiver is this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:9 of +msgid "True when a running leg was resumed." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:1 of +msgid "Ask the server to pause its transfer toward this client." +msgstr "" + +#: 89fa1c905614496ea12a4cfde9eb3cce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:3 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (a forwarded upload this client relays is throttled this way)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:3 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "The server's ``(ip, port)``; None accepts the connected server." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:6 of +msgid "Transfer id of the server's outbound leg." +msgstr "" + +#: 39423e052b70403ba07a713aa9e3cb4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:12 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:9 of +msgid "True when the line was written." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:1 of +msgid "Ask the server to resume a transfer paused earlier." +msgstr "" + +#: 0e91f82d8856443497c399f97643b757 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 of msgid "Reserve this client's port range under the cross-process lock." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 -#: cd973d56799848ecbd65c434c9f5f0ae of +#: 6029a28126344e45b24394cb56b2f8f8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 of msgid "No-op until the server assigns a range (see ``/client_alloc_port_range``)." msgstr "" -#: 29e4db224e2d4208a5fc08a1523f9e6b +#: 32bed401c3574959ba5ed08fc9078401 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:1 of msgid "Release this client's reserved port range." msgstr "" -#: 7b0f2f6530984dcc888286f471f14747 +#: 9f86b7aac4f44886be9cd87b56072b63 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:3 of msgid "No-op unless a range was assigned (``is_hand_alloc_port`` True)." msgstr "" +#: 8154f96d9ec74bd588971a806d42f8c1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_lock:1 -#: c6e04e800074445da45886940c77a9f8 of +#: of msgid "Create the lock file that reserves the client port range for this process." msgstr "" -#: 2c7b09854c254d0bbfa62d2a356cfb24 +#: 69c2dd5d5d1d497c8bac1e62ab4fc30a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:1 #: of msgid "Report whether the client port range is reserved by some process." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_unlock:1 -#: b2cbf44d95154896ab2df64bf8be1a3d of +#: c88f37ef2d5c47bda346e804508d6ec0 of msgid "Remove the lock file that reserves the client port range." msgstr "" -#: 690717115cb64dfeb32f56302992451c +#: 478443e187814a6ca7ad798277db023f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:1 of msgid "Allocate the next free client port range and record it on disk." msgstr "" -#: 2e8d17873f8b4b419f2f6cd1f2000a62 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 +#: a8736540f4c3402fad9508e619d559d7 of msgid "" "``port`` is moved past the ranges already recorded by other clients on " "this host, so each instance ends up with a range of its own." msgstr "" -#: 2d7cb151d3bc4798914cbe3d73391c16 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 +#: bc44b1604e02467280b59cb8ad63d0af of msgid "If the client port info file cannot be read or written." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_free_port:1 -#: b6079f909975409c86477341dcf2990c of +#: e48dff576a074109a135db168b5dbe98 of msgid "Drop this client's entry from the on-disk port range record." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 -#: c7fc083bff234cb7b377bc7adbb65ca5 of +#: 3aa62e8843c6495c862f43fc6dda9d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 of msgid "Allocate a port, waiting until one is free." msgstr "" -#: 85129bb5393542e498835f3ba6dc981a +#: 2f7752fa51d946b1a4a566b38f046e80 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:3 of msgid "Allocated port, or 0 when no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 -#: e77dc25d62bc4eedbd153b7420d109f4 of +#: 503ab40fc32c4d548f65fa3272b2f4d2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:5 -#: c452f87d6e18446cbbb2f48b1dc47b9b of +#: b9fd549c95f24c2080d87cec92514db6 of msgid "Allocated port; None when the upward range is exhausted; 0 when no" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 -#: e195a16298f14417b95ed3dc3ad60fac of +#: 151a65f1c1984e4196c750108d0611cb +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 of msgid "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 -#: f7330894d1a041ca9a31ca1b390d5af7 of +#: 0c6201bb2d7e45d3a4916d7e50a21e10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 -#: a8d7d910fb874925acb423d08187908d of +#: 76c766a9c61f4075a762ccf55038a65e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 of msgid "no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 -#: c76dd143ea224bb69081222ac4228f8f of +#: 8d500513e8854ba4bb91c8905a9adb73 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 of msgid "Local port to bind; None allocates one with `palloc`." msgstr "" -#: 5a8b77d5b1e243d9b5b24039b6ff25d0 +#: 840360623c8a4c2bbafe8fe7bbf9209c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:1 of msgid "Connect to the server and start reading from it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:3 -#: b59d15dc7c7844a5bd0226eb081c9887 of +#: df94288e660b48f6809358b3dc234ec9 of msgid "" "Binds ``client_port`` when one was configured, then retries while " "``is_wait_server`` is True and the server is not reachable yet. Once the " @@ -1625,7 +2135,7 @@ msgid "" "negotiated, which closes the connection when the two sides disagree." msgstr "" -#: 8711ef70ac704a48b05e13ded3546471 +#: 22fccba0ab36499a9a7f4427abe5e9f4 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:8 of msgid "" "True when the connection is established (and, if encryption is " @@ -1633,105 +2143,107 @@ msgid "" "failed or the mode negotiation closed the connection." msgstr "" -#: 850616ca4a614020b9627a3c39a54555 +#: 0270d0a2d42740a9889106339d9f2dbb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:10 of msgid "True when the connection is established (and, if encryption is" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:11 -#: cd0e7073f18d4d2ba990f1bfda735fd4 of +#: c194691cedfb48c6bfd97d9bdc6f2246 of msgid "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 -#: b7b9e013f50348379a0208a7702b9b1f of +#: 4dc38e3ef3b74b8e8c27378242a1925a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 of msgid "Read from the server until the connection ends." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 -#: ae819668995f44878eaa9c4a8db02583 of +#: 431649a0d703476dadc6afa8adbe53d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 of msgid "" -"Runs on the receive thread: plain lines are reported to the message " -"listeners and stored in ``messages_dict`` (``/send_msg_from`` envelopes " -"are attributed to their sender first), other ``/`` lines go to " -"`handle_server_command`. Any end of the connection clears ``running`` and" -" releases the port range." +"Runs on the receive thread: every inbound line is reported to the message" +" listeners (commands included); a plain message is also stored in " +"``messages_dict``, while a ``/send_msg_from`` envelope is reported and " +"stored as its payload attributed to the forwarding client, and other " +"``/`` lines additionally go to `handle_server_command`. Any end of the " +"connection clears ``running`` and releases the port range." msgstr "" -#: 32feafb4504a473dbbe6b0957d3658f0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 +#: cf284b59f7f849039404ced20f8e12db of msgid "Write one line to a socket, encrypting when the channel is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 -#: c639152d8792432ba220c33c860f1211 of +#: 40ba2ede2d3f4666b82107af129d24d0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 of msgid "Target connection; the client passes ``self.client_socket``." msgstr "" -#: 5b421459787b4210b8bce3e7003cf35b +#: 2e663941eaf142cb96738add05f9ef4d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:10 of msgid "" "True when the payload was written; False when the client is not " "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 1684a06aa826439784ce149aece2f637 +#: 38905ec7539d42e0839907c32dd8667f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:12 of msgid "True when the payload was written; False when the client is not" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 -#: bc5ff108fa3d46afb45fd86d4106ac2f of +#: 3f7e2e6fedda476f996132c3f677f2f0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 of msgid "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 3b27239d40244e35817e0806e3363df0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 +#: a9220a130e694e0aba1d3b6320dff498 of msgid "Send the payload of a console line to the server." msgstr "" -#: 66bc43727101429bacd6a76534c53f7b +#: 2e208e83a89e4dac9793460a8808a042 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:3 of msgid "" "Console line such as ``/send_msg hello``; the first token (the command " "name) is dropped and the second one is sent." msgstr "" -#: 4cb6da8a7d464be983bf467e65fe55b0 +#: 39c8e70ca92b43b8ac687bc0aa7f4073 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:7 of msgid "If the line has fewer than two tokens." msgstr "" -#: 369743f21d0f4656aa801c8f29b4129b +#: 8d47f30ae7b0451f8ecfe207ec835ff3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:1 of msgid "Read up to ``msg_length`` bytes from a socket." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 -#: f6749336c57b4a82b5c0b19f27bd8906 of +#: 10a39005f45c46728ef9a000eeaf9109 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 of msgid "Dispatch one command line pushed by the server." msgstr "" -#: 510b3d71451048138e11fe92fdb160b4 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 +#: a7e781fde939475cb081204adac16ded of msgid "" "Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the" " connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange " "lines, and the transfer lines ``/file``, ``/file_folder``, " -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, " +"``/start_trans``, ``/resume_trans``, ``/forward_resume`` and " "``/forward_error``. Any other name goes to the handlers registered for " "the \"server\" side via `register_command`; an unknown command is only " "reported on the console." msgstr "" -#: 7724aab357eb408dbbf018c214f8eba0 +#: 91942d88960c4793b5eab8c3654c1400 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:1 of msgid "Forward plain messages to other connected clients through the server." msgstr "" -#: 12403f5be7704258849974d103865b9c +#: 75bb9147a7464a278e19af9d03b04ecb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:3 of msgid "" "The console command ``/forward_send_msg`` uses this; the client must be " @@ -1739,40 +2251,40 @@ msgid "" " so the receiving client can attribute it back to this one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 -#: fc0907a1c7484f66a7b2cc1a99d24dc0 of +#: 0f3c201936df45b687dc5532531b4a4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 of msgid "Message texts to forward." msgstr "" -#: 8d07efc16f6c45d7b9d1d4f85f945317 +#: 277bbcb2143943b5b983badb00c3f4fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:9 of msgid "Destination ``(ip, port)`` tuples." msgstr "" -#: 4afafed2326a42e391e3b098cfea4f06 +#: 5ea8eea489fc43108a439d54fba31068 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:12 of msgid "" "True when the request was written to the server; False when the " "client is not connected." msgstr "" -#: 85c761742fa5450f846373591e4af1ff +#: 2bc5d7e5dfa94eb29b49f12562f57c88 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:14 of msgid "True when the request was written to the server; False when the" msgstr "" -#: 6ae9ff84b7d64c30abd31cde1715b783 +#: 45d974ad946b408b91d41bcce65abcc8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:15 of msgid "client is not connected." msgstr "" -#: 7b79bd0e677c42fd921308a34e9a0929 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 +#: c9401da7c37e40e5978c80e4876b11a0 of msgid "Read console lines and act on them until the client stops." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 -#: d91a5c812cdb4705a2fa27ac33ef693a of +#: 793bcfd02c014200b0ec47f8e15b4d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 of msgid "" "``/quit`` closes the connection; ``/send_msg``, ``/file``, " "``/multiple_file``, ``/file_folder``, ``/multiple_file_folder``, " @@ -1782,38 +2294,77 @@ msgid "" "it stands. Ctrl-C and EOF close the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 -#: dc2c54034ec64b61a3af655e86bc81a2 of +#: 7ba721f9d59742b99e89e3b6e249e754 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (the target of a forward, " +"never the relay): it is stored with the progress entry so a later " +"reconnect can be resumed. ``resume_offset`` continues an interrupted " +"transfer from the byte the receiver already holds: the file is read from " +"there instead of its first byte." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:3 +#: a3c59554b8de41b280df7536b307bed0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and drives " +"every download that can be continued: a file the server was sending is" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:6 +#: fae378e888be4821a14ed2483cfde1e0 of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer the " +"client can reach." +msgstr "" + +#: 48061103ed9d4bcaae8a8a837b363557 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:10 of +msgid "Number of resumed transfers started or requested." +msgstr "" + +#: 6dbae803a56c442588b28af664b7a0e9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 of msgid "" "/forward_file ... ... [dest] (client " "only)." msgstr "" -#: 303ae7e9e20444e38b303177bef0fb36 +#: 05cad8b03e0747dc804ffbfda3122fe1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_folder_console:1 of msgid "" "/forward_folder ... ... [dest] " "(client only)." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 -#: ec2b9ff3c5cf4fb5a79e29242221fe67 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:3 +#: f6f606236f434f0287a969ccbe5ba2c5 of +msgid "" +"``peer`` is the transfer's original sender (the server for a pushed file," +" the originating client for a forwarded one — never the relay): it is " +"stored with the progress entry so a later reconnect can ask that peer to " +"continue the file." +msgstr "" + +#: 6e9a9717a782419baecca63fd1f46baf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 of msgid "Close the connection and release everything the client owns." msgstr "" -#: 43645acb6c524c348b870d288aafae5e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 +#: ba6c5badecf6465db6036735870ed305 of msgid "" "Stops the receive loop, releases the port range, flushes the message and " -"event stores and closes the socket. Safe to call more than once." +"event stores, persists the interrupted transfers and closes the socket. " +"Safe to call more than once." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:1 -#: afb1904037404a6c99f6b7ae2df119e2 of +#: c91a3245b93f46abbb49dbef7bcfeb1c of msgid "Connect to the server and start the client loop." msgstr "" -#: 6f912c76416e4f37a750eda0c126da35 +#: 0c83552867484ea780fcff8d34e5c2d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:3 of msgid "" "Enters `interactive_mode` when ``is_input_command_in_console`` is True, " @@ -1823,6 +2374,15 @@ msgid "" "while still connecting returns quietly, because that stop was asked for." msgstr "" +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:9 +#: eec663f58484446ebce460e6402d7b5f of +msgid "" +"With ``is_auto_reconnect`` True a dropped connection does not end the " +"client: it reconnects (waiting for the server when ``is_wait_server`` is " +"set) and every session carries the interrupted transfers of the previous " +"one (`resume_transfers`). A close or ``/quit`` still stops the client." +msgstr "" + #~ msgid "" #~ "Concepts live in " #~ "``docs/Network_APIs/TCP_Server_APIs.rst`` and " @@ -1918,3 +2478,117 @@ msgstr "" #~ " `close`." #~ msgstr "" +#~ msgid "" +#~ "one message per line, terminated by " +#~ "a newline; a line that starts with" +#~ " ``/`` is a command and goes to" +#~ " the command handlers, anything else " +#~ "is a plain message reported to the" +#~ " registered message listeners;" +#~ msgstr "" + +#~ msgid "" +#~ "an RSA-encrypted channel is negotiated" +#~ " right after connect unless " +#~ "``is_enable_encrypto`` is False;" +#~ msgstr "" + +#~ msgid "" +#~ "file/folder transfer, message forwarding and" +#~ " port allocation are layered on the" +#~ " same socket and share its command" +#~ " namespace." +#~ msgstr "" + +#~ msgid "" +#~ "The forwarding extensions use the " +#~ "module-level parsers `parse_forwarded_message`, " +#~ "`parse_forward_items_and_addrs`, `parse_forward_originator` " +#~ "and `forward_skip_message`." +#~ msgstr "" + +#~ msgid "" +#~ "Each accepted connection is served by" +#~ " `handle_client`, either in its own " +#~ "thread (the default) or by a " +#~ "coroutine on an asyncio event loop " +#~ "when ``is_asynic_clients_io`` is True: a " +#~ "line starting with ``/`` goes to " +#~ "`handle_command` (built-in commands plus " +#~ "the handlers registered with " +#~ "`register_command`), any other line is a" +#~ " plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(client_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "" +#~ "Plain messages are the lines received" +#~ " from clients that do not start " +#~ "with ``/``; commands go through the " +#~ "registered command handlers instead." +#~ msgstr "" + +#~ msgid "Write one line to a client socket, encrypting when the channel is up." +#~ msgstr "" + +#~ msgid "" +#~ "Lines received from the server go " +#~ "through `receive_messages`: a line starting" +#~ " with ``/`` is handled by " +#~ "`handle_server_command` (protocol commands plus " +#~ "the handlers registered for the " +#~ "\"server\" side), any other line is " +#~ "a plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``. With " +#~ "``is_input_command_in_console`` the console thread" +#~ " `interactive_mode` sends typed lines to" +#~ " the server." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(sender_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "Mirrors the server-side contract; commands are not reported here." +#~ msgstr "" + +#~ msgid "" +#~ "Runs on the receive thread: plain " +#~ "lines are reported to the message " +#~ "listeners and stored in ``messages_dict`` " +#~ "(``/send_msg_from`` envelopes are attributed " +#~ "to their sender first), other ``/`` " +#~ "lines go to `handle_server_command`. Any " +#~ "end of the connection clears ``running``" +#~ " and releases the port range." +#~ msgstr "" + +#~ msgid "" +#~ "Handles the protocol's own lines: " +#~ "``/crypto_mode`` (a mismatch closes the " +#~ "connection), ``/client_alloc_port_range``, the " +#~ "``/crypto_*`` exchange lines, and the " +#~ "transfer lines ``/file``, ``/file_folder``, " +#~ "``/forward_upload``, ``/pause_trans``, ``/start_trans``," +#~ " ``/forward_error``. Any other name goes" +#~ " to the handlers registered for the" +#~ " \"server\" side via `register_command`; an" +#~ " unknown command is only reported on" +#~ " the console." +#~ msgstr "" + +#~ msgid "" +#~ "Stops the receive loop, releases the " +#~ "port range, flushes the message and " +#~ "event stores and closes the socket. " +#~ "Safe to call more than once." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po index e4fb476..4d183cb 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -21,21 +21,21 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.rsa_crypto.rst:2 -#: a48a4f614e834981afd42e2cb723ce06 +#: def9740b5a2e4aaeb2aeed8b4f02c0ec msgid "PyFlow.network\\_api.rsa\\_crypto module" msgstr "" -#: PyFlow.network_api.rsa_crypto:1 e529881eccb0440c888d5c69244133f9 of +#: 46d3090efafd4504870cf72a4bea22ab PyFlow.network_api.rsa_crypto:1 of msgid "crypto_api (C/OpenSSL) RSA integration for PyFlow's TCP layer." msgstr "" -#: PyFlow.network_api.rsa_crypto:3 d9d01596a65340fb84c25298550845cf of +#: 5b1ff4a00b0f46258cda2e7440368de1 PyFlow.network_api.rsa_crypto:3 of msgid "" "A thin ctypes binding to the shared ``libcrypto_api`` plus the key " "lifecycle required by the encrypted TCP channel:" msgstr "" -#: 232e71aebc434fb6bece23f593557e9f PyFlow.network_api.rsa_crypto:6 of +#: PyFlow.network_api.rsa_crypto:6 a5a0d6d600604683990a92555a49a3fe of msgid "" "Reuse an existing RSA keypair from ``~/.ssh`` (PEM private key) when one " "is present and parseable, otherwise generate a fresh keypair into " @@ -43,7 +43,7 @@ msgid "" "honoured when both files parse and the pair matches." msgstr "" -#: 29d30af10f8c4180890f876bb14b00e3 PyFlow.network_api.rsa_crypto:10 of +#: PyFlow.network_api.rsa_crypto:10 bb413dc908624589a3e57f8a2c702728 of msgid "" "Anti-MITM identity check (TOFU): every connection exchanges public keys " "in plaintext. Each side records the peer in " @@ -53,14 +53,21 @@ msgid "" "endpoint is re-registered under the new ``(ip, port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto:16 d4873e3b840e4e7fbe4c6f85850dc2a7 of +#: PyFlow.network_api.rsa_crypto:16 aec1a7998276428881efcfac6fe4cebe of msgid "" "RSA-OAEP encrypt/decrypt with the ``_VALID`` plaintext signature so a " "stale key (for example a rotated ``~/.ssh`` pair) is detected and the " "peers re-exchange their public keys." msgstr "" -#: 49f63152bca249588cf98871d5bafa64 PyFlow.network_api.rsa_crypto:20 of +#: 392850c432f2466ab9ecfd64770e648d PyFlow.network_api.rsa_crypto:19 of +msgid "" +"ECDH key agreement (P-256/P-384/P-521) with HKDF-SHA256 session-key " +"derivation and AES-256-GCM ``seal``/``open`` (``EcdhKeyPair``, " +"``EcdhPubKey``, ``hkdf_sha256``)." +msgstr "" + +#: 55cfc03aeb3f4d6ba37b10a01dfcdccc PyFlow.network_api.rsa_crypto:23 of msgid "" "The C library is compiled into the installed package by ``setup.py`` (a C" " compiler and OpenSSL development headers are needed at install time); a " @@ -68,21 +75,33 @@ msgid "" "still supported. See ``load_library`` for the search paths." msgstr "" -#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 -#: a3ac757cc1fa4c73be13eaa020c8e60b of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 of msgid "Raised when the shared libcrypto_api cannot be loaded." msgstr "" -#: 9c5bbad270ac48cd997b23cd4f284152 PyFlow.network_api.rsa_crypto.RsaKey:1 of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:1 of +msgid "Raised when a ``pf_*`` call fails." +msgstr "" + +#: 2c3651ee5dc94886986aa9804b164e3d +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:3 of +msgid "" +"``code`` is the ``pf_err_t`` value (one of the ``PF_ERR_*`` module " +"constants), or ``None`` when the failing call returned no code." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.RsaKey:1 e620122ff0bc48dd985c4b6a0b3b41ce of msgid "Owns an ``pf_rsa_key_t*`` handle; frees it on GC." msgstr "" -#: 0eab5b9b31774196a46b7d400341a404 +#: 1a7d8e9db5a3435486d716b13f2a2a56 #: PyFlow.network_api.rsa_crypto.load_library:1 of msgid "Locate and load the shared crypto_api library (cached)." msgstr "" -#: 8bcac9994a6048e4920e23b8f94bb000 +#: 287fcfd81df2461d8e4bceebf61b7e40 #: PyFlow.network_api.rsa_crypto.load_library:3 of msgid "" "Search order: the library ``setup.py`` compiles into the installed " @@ -93,25 +112,98 @@ msgid "" "reported only if no other candidate works." msgstr "" -#: PyFlow.network_api.rsa_crypto.get_local_mac:1 -#: b555d90eff7c445a8a28cb3de88bd581 of +#: PyFlow.network_api.rsa_crypto.EcdhPubKey:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_pubkey_t*`` handle; frees it on GC." +msgstr "" + +#: 556fdf46d6c543e0ab06e2d4fabad7f1 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:1 of +msgid "Parse a peer public key from a PEM string." +msgstr "" + +#: 88cd040e91194a3785bf56d7c52d3543 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_PARSE`` for " +"malformed PEM or a point that is not on the curve (the C library verifies" +" the point)." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_keypair_t*`` handle; frees it on GC." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:3 f12b2d8d1d4846edbf60d64c34860558 +#: of +msgid "" +"``curve`` is one of ``\"P-256\"``/``\"P-384\"``/``\"P-521\"`` (``None`` " +"selects P-256). OpenSSL key objects are not safe for concurrent use, so " +"``public_pem``/``seal``/``open`` are serialised by an internal lock." +msgstr "" + +#: 07643e7c481f49cba8b4ab33bd4174e0 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.public_pem:1 of +msgid "Export our public key as a PEM SubjectPublicKeyInfo string." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:1 +#: ce09888aa11f4f01a8d4bdb80f94321f of +msgid "Encrypt ``plain`` to ``peer`` with an ECDH-derived AES-256-GCM key." +msgstr "" + +#: 965e41e97f5547c3a0bc77531ae3b3f9 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:3 of +msgid "" +"Returns the wire blob, exactly ``PF_ECDH_SEAL_OVERHEAD`` bytes longer " +"than ``plain``. Raises ``CryptoOperationError``." +msgstr "" + +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:1 of +msgid "Inverse of :meth:`seal`, using ``peer``'s public key." +msgstr "" + +#: 4212d23f4b14479b971145af1bc12fa5 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_AUTH_FAILED`` when" +" the tag does not verify (tampered ciphertext, wrong peer key or " +"mismatched AAD)." +msgstr "" + +#: 7fec5dc58def4bbc886ca30568df0661 PyFlow.network_api.rsa_crypto.hkdf_sha256:1 +#: of +msgid "HKDF-SHA256 (RFC 5869 extract-and-expand) over ``ikm``." +msgstr "" + +#: 462a97910aff4e9aae066e31f55d5233 PyFlow.network_api.rsa_crypto.hkdf_sha256:3 +#: of +msgid "" +"``salt`` and ``info`` may be empty. ``out_len`` must be in " +"``1.._HKDF_SHA256_MAX_OUT``. Raises ``CryptoOperationError``." +msgstr "" + +#: 670f4a719bf24c24b48ecb5d73b373ce +#: PyFlow.network_api.rsa_crypto.get_local_mac:1 of msgid "Return a stable 48-bit machine identifier as colon-separated hex." msgstr "" -#: 311d6e5bcdba40d1b05fd63528abcf74 -#: PyFlow.network_api.rsa_crypto.get_local_mac:3 of +#: PyFlow.network_api.rsa_crypto.get_local_mac:3 +#: f1306bb875d34b558f7418278fded413 of msgid "" "Uses ``uuid.getnode()`` (the real hardware MAC when one is available). " "Server and client on the same host share this value; the ``_`` " "prefix in the key file names keeps them apart." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto:1 b385913eca73436ab76b76787114e163 +#: 333763d798c54d52a9a56a3e4e3e2155 PyFlow.network_api.rsa_crypto.RsaCrypto:1 #: of msgid "Key lifecycle plus RSA-OAEP encrypt/decrypt for one role." msgstr "" -#: 7c2b4fafe779449a8245780da7a4ef91 PyFlow.network_api.rsa_crypto.RsaCrypto:3 +#: PyFlow.network_api.rsa_crypto.RsaCrypto:3 f52515121ac74575aaa36d45dd0341a2 #: of msgid "" "``role`` is ``\"server\"`` or ``\"client\"`` and is used to name the " @@ -120,13 +212,13 @@ msgid "" " in ``pub_key/pub_key.json`` (TOFU, see ``verify_peer_pub``)." msgstr "" -#: 1e24448b89684701a1fa13b02e9d0d84 +#: 56fed5bcfe194b7f90a0c662ae36d6c0 #: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:1 of msgid "Create the crypto wrapper for ``role`` (\"server\" or \"client\")." msgstr "" -#: 00101f4b9ef44a83b2e51f9974a3d92a -#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 +#: ca4e27664ccf40ce935d991db43f7c69 of msgid "" "``custom_keys`` may be a ``[pub_key_path, pvt_key_path]`` pair to use a " "user-supplied RSA keypair instead of the default lookup (``~/.ssh`` / " @@ -135,78 +227,78 @@ msgid "" "used instead." msgstr "" -#: 4e9b33835a9448bca28d9e2e3a782d77 +#: 7d89122ff0f54090b67209e3b08ae29c #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:1 of msgid "Load the RSA keypair (see module docstring) and cache handles." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:3 -#: e7fd217ab95d483084e4c7d58b715349 of +#: d5e494e00be44891b33cb8e0ecfb8081 of msgid "" "Runs under ``_key_lock``: the private-key handle must never be replaced " "(or freed on GC) while another thread is decrypting." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.reload_own_key:1 -#: c1e8b452b697431aaafee424e1edd3e2 of +#: f6f7d6ec8837464dad2dc647e6141a99 of msgid "Re-read the private key (e.g. after a ~/.ssh rotation)." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:1 -#: fabae86a23844d9cba130ff2f2adc080 of +#: e95d18da34d14376987a62f6cbbec778 of msgid "" "Path of the exchanged public key file for ``peer_role`` at ``(peer_ip, " "peer_port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 -#: fa9eee0dbc724d0bbfa8e36bcdd89ba4 of +#: 52dc6fb74f0c4175bfa2a2acc23cda0d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 of msgid "" "The IP is sanitized for the filesystem (``:`` -> ``_`` so IPv6 literals " "are safe on every platform, including Windows)." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 -#: ce570f7fdb834fc3982aa0ec0e98b896 of +#: 731d92a1b64342dfbf7c467af0a4c00e +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 of msgid "TOFU check-and-record for a peer public key." msgstr "" -#: 2879d5b42eed4eaca2af859a86db52e8 +#: 634283c14fb44424bf148a34d156fb71 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:3 of msgid "" "``peer_pem`` is the PEM text received on this connection, ``(peer_ip, " "peer_port)`` the endpoint it came from. Returns ``(ok, reason)``:" msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 -#: b6f7afce352240b8ba2cf6a4e38aa457 of +#: 6bb58c88f8454d7daca92b5a478ae788 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 of msgid "" "key already registered under any endpoint -> accept, and re-register it " "under the current endpoint when it moved (IPs are dynamic and ports are " "user-changeable);" msgstr "" -#: 014d219898a04debb9eace0ea28aaa83 +#: 74e2bcc89bae4fe5aecf99e6208e21d1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:10 of msgid "" "key unknown but the endpoint already holds a *different* key -> reject (a" " trusted endpoint suddenly presenting a new key);" msgstr "" -#: 5aabe21775144f3fb2e5b4ae5a190569 -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 +#: f856b875adc34f4a80c2b21cd506b143 of msgid "" "key and endpoint both unknown -> accept and record (first connection is " "trusted, TOFU)." msgstr "" -#: 2bcc3b43a6d54e91b48a51fdf715a346 +#: 556fdf46d6c543e0ab06e2d4fabad7f1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:1 of msgid "Move a freshly received public key file into the key cache." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:3 -#: a32f32a711ec453684a2fa927aaaa06e of +#: a47e84f5d21949bf98e24834f18bed76 of msgid "" "Idempotent under concurrency: several transfers may deliver the same peer" " key at once (multi-connection handshakes, several client processes " @@ -215,13 +307,13 @@ msgid "" "destination is in place." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 -#: c54c296562484982abff2e1436305b98 of +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 of msgid "Encrypt ``plaintext`` with the peer's public key file." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 -#: f7f5e3490fb44e85919611c0b3b9ecc7 of +#: 4b4dded0ad904ce2bb87c9a43c8f87e5 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 of msgid "" "Returns the ASCII wire body (no trailing newline): each chunk is RSA-OAEP" " encrypted and base64 encoded, chunks joined with ``|``. Raises if no " @@ -230,12 +322,12 @@ msgid "" "encrypt (no-GIL safe)." msgstr "" -#: 8860142532044e87aa78adc123c33d62 +#: 8f1687f4ab984c029859fd1f9cfb968c #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:1 of msgid "Decrypt a wire body with our private key." msgstr "" -#: 888f7928d8274beda354f5b657613fec +#: 8a1d1504bf4248fa9e1288776d19810b #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:3 of msgid "" "Returns ``(True, plaintext)`` on success, or ``(False, None)`` when the " diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po index b1ee4f9..3d23ccd 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -18,30 +18,32 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_client.rst:2 -#: 8379b786205a4447995cf82b275ee87a +#: 09f60d1b11ac4e92b480fa6284489970 msgid "PyFlow.transfer\\_web.setup\\_client module" msgstr "" -#: 8412539bd9af49e8976ccf5c028061d4 PyFlow.transfer_web.setup_client:1 of +#: 2f786e174934474a93c6498878a68612 PyFlow.transfer_web.setup_client:1 of msgid "PyFlow TCP client web launcher." msgstr "" -#: PyFlow.transfer_web.setup_client:3 d2ed4df91a474301aee43eaf09e1ac87 of +#: 24fa9f33454d4afc9d15c80a0299922d PyFlow.transfer_web.setup_client:3 of msgid "" "Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI " "in the browser. The user enters the server address (an http/https domain" " or a bare IP); the backend asks the server's web backend for the TCP " "server address/port, starts the TCP client, and keeps the backend running" -" to relay the user's frontend actions. The account of the server logs in" -" from the same backend: saved credentials in " -"``.Flow_Web/client_login.json`` are replayed on every start, and the " -"login window appears whenever no session could be restored." +" to relay the user's frontend actions. A server that needs accounts (a " +"verification mailbox is configured) makes the same backend log in: saved " +"credentials in ``.Flow_Web/client_login.json`` are replayed on every " +"start, and the login window appears whenever no session could be " +"restored. A server without a mailbox needs no accounts, so the login " +"window and the account controls are skipped." msgstr "" -#: PyFlow.transfer_web.setup_client.main:1 fd5a9b075a2a4b9a97dbad26743e0403 of +#: PyFlow.transfer_web.setup_client.main:1 ca4ce7c686c84b44ae429e4de15b9afd of msgid "Start the client web backend and serve its UI." msgstr "" @@ -58,3 +60,21 @@ msgstr "" #~ " actions." #~ msgstr "" +#~ msgid "" +#~ "Starts a lightweight Flask backend on" +#~ " 127.0.0.1 and opens the connect UI" +#~ " in the browser. The user enters " +#~ "the server address (an http/https domain" +#~ " or a bare IP); the backend " +#~ "asks the server's web backend for " +#~ "the TCP server address/port, starts the" +#~ " TCP client, and keeps the backend" +#~ " running to relay the user's frontend" +#~ " actions. The account of the server" +#~ " logs in from the same backend: " +#~ "saved credentials in ``.Flow_Web/client_login.json``" +#~ " are replayed on every start, and " +#~ "the login window appears whenever no " +#~ "session could be restored." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po index e298216..bc46383 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -18,43 +18,45 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_server.rst:2 -#: 88492dfde47b4dbb914aaba07f359440 +#: e6642bb55a204188b0abd0b07207713e msgid "PyFlow.transfer\\_web.setup\\_server module" msgstr "" -#: 103789700f8d41aa80e1cb374abb02a3 PyFlow.transfer_web.setup_server:1 of +#: 5966876a4564470ea674311ddb3ef63e PyFlow.transfer_web.setup_server:1 of msgid "PyFlow TCP server web launcher." msgstr "" -#: 581fc0a8029c44f7998895401060a79b PyFlow.transfer_web.setup_server:3 of +#: 588fea0dc68a4a308f9a7cfb6fe5d819 PyFlow.transfer_web.setup_server:3 of msgid "Checks ``transfer_web/.Flow_Web/setup_server.json``:" msgstr "" -#: 60412e56b0d44018bbc88cd258e2c48b PyFlow.transfer_web.setup_server:5 of +#: PyFlow.transfer_web.setup_server:5 c3df4df524da40b18a58607efd9b5e4a of msgid "" "missing -> opens the server startup-configuration UI in the browser; the" " UI saves the config (same shape as ``flow_setup``'s ``setup.json``) and " "starts the TCP server class;" msgstr "" -#: 15dae71f4c1243ecb188218cd72eb7c2 PyFlow.transfer_web.setup_server:8 of +#: 211850fce6d34d50ae152bce6d1aa3af PyFlow.transfer_web.setup_server:8 of msgid "present -> starts the TCP server class directly from the saved config." msgstr "" -#: 921ebc855440467cacd9d366085db41a PyFlow.transfer_web.setup_server:10 of +#: 7170b50dcaf2462f918af2271f247c84 PyFlow.transfer_web.setup_server:10 of msgid "" "After the TCP server is up, the lightweight Flask backend serves the " "status page and the client-facing API (``/api/server_info`` etc.) on the " -"server's address. Anonymous visitors also get the landing page with the " -"registration and password-reset flows; accounts live in the SQLite store " -"``.Flow_Web/flow_web.db``, and the verification mails are sent through " -"the mailbox configured in ``.Flow_Web/email_config.json``." +"server's address. Anonymous visitors also get the landing page; its " +"registration and password-reset flows exist while a verification mailbox " +"is configured (settings in ``.Flow_Web/email_config.json``, accounts in " +"the SQLite store ``.Flow_Web/flow_web.db``). That mailbox is also the " +"switch of the client side: with it clients log in with an account, " +"without it they connect without any account at all." msgstr "" -#: 2f09f9248b0e47e3ba9c9792d83a622b PyFlow.transfer_web.setup_server.main:1 of +#: PyFlow.transfer_web.setup_server.main:1 cbf05c29afe74ebd84b898146c971457 of msgid "Start the server web backend and serve its UI." msgstr "" @@ -66,3 +68,17 @@ msgstr "" #~ "server's address." #~ msgstr "" +#~ msgid "" +#~ "After the TCP server is up, the" +#~ " lightweight Flask backend serves the " +#~ "status page and the client-facing " +#~ "API (``/api/server_info`` etc.) on the " +#~ "server's address. Anonymous visitors also " +#~ "get the landing page with the " +#~ "registration and password-reset flows; " +#~ "accounts live in the SQLite store " +#~ "``.Flow_Web/flow_web.db``, and the verification " +#~ "mails are sent through the mailbox " +#~ "configured in ``.Flow_Web/email_config.json``." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po index ff5009c..9f65a88 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po @@ -8,47 +8,49 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst:2 -#: 86d4061dc1f542ac95555aa2deab1101 +#: ffcd351a76b74899a0105947d1049e12 msgid "PyFlow.transfer\\_web.web\\_backend.mail\\_service module" msgstr "" -#: 99f2cb604d5c450c9cda427b22b2c8cb -#: PyFlow.transfer_web.web_backend.mail_service:1 of +#: PyFlow.transfer_web.web_backend.mail_service:1 +#: c6f6b5571d954e7b986a3355033cd30c of msgid "SMTP delivery of account verification codes for the web tool." msgstr "" -#: 1d2a4d079f6c44f182332c5b44d0705a +#: 9764afd408ca43ce829f03d7d4ca675b #: PyFlow.transfer_web.web_backend.mail_service:3 of msgid "" "The administrator configures the outgoing mailbox from the server's " "startup-configuration page. The settings are validated with a real SMTP " "login and only then written to ``.Flow_Web/email_config.json``; while no " "validated configuration is present the service refuses to send, so a " -"server can never silently drop verification codes." +"server can never silently drop verification codes. The same page takes " +"the mailbox away again (`disable`), which switches the server back to " +"internal use." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 -#: e0597ff2442b43dd87c4efaef6c574c5 of +#: 5fdca457edd340eab7c9f05558a37dc5 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 of msgid "Validate untrusted SMTP settings and return them in canonical form." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 069dae5e8fb0426e897adc279499319b 4c58519a459f4b9486f0a571939d4834 -#: 83045ebe35d54d76b13e40961c070d4f eb5501cac4f240b19f2d4f5e5443e3c6 +#: 1cad23766791477aa6fb46051363ef81 73b1f3a5025140ec8701e976293f7af0 +#: 817b9cde77bb4327ad3b9f8356d27f4c a9b0b41ab3fd438c8cb2551b61e1af31 msgid "Parameters" msgstr "" -#: 14138866fd924a0083c8e6562b3860ff +#: 1b2b400edc914a76977297cb9ef6da5d #: PyFlow.transfer_web.web_backend.mail_service.normalize_config:3 of msgid "" "Settings with ``host``, ``port``, ``username``, ``password``, ``from`` " @@ -57,152 +59,183 @@ msgid "" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 170588e452e5431e815fad88a5b5537b 887b6607974c4ea8b99b628ea3efbf45 -#: a16996418f0e4e5ab58b7244ded5e63b c0463031a23c4f799b6a8217f31cc1b1 +#: 097b6a08fc5548d1a5a4568b07bf4326 1388175dc5e64a8eb1a99affd4807d9f +#: 334d15f3b1264e0b8abfc34e8fee985e 8f894b6967fd4867b82c726e85c83dc9 msgid "Returns" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 -#: dafcbdb3cccc40fa89a38363dd5680b0 of +#: 4695369c64494340bb98d06f4029f854 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 of msgid "" "The same settings with a string host, an integer port, a lowercase " "encryption mode and an explicit sender." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 -#: a68a2cdaeea44ccdb70c8e49efbcb5dd of +#: 5c191d5d632a4a71a814aa300592c904 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 of msgid "The same settings with a string host, an integer port, a lowercase" msgstr "" -#: 2bd9bb82ad2749df9c60df8271733a8c -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 of +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 +#: f98ed07dd1474127973e40ea5d133476 of msgid "encryption mode and an explicit sender." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 24fb33faf10542c7a1d5bcd8bc20e135 53904db2f0da42c6ac410c40a9e555a0 -#: 59876b786ae244308cb80d0e15975404 a636a96a44754c789c671d6e95914aea +#: 2ceb9aabd15149e2a74ab44ffc0e7e3b 4f9ea7be9a9d4179b3371b7ffaaf9c64 +#: 75ab32112eb54385b832e99cc66c0f3b 951ba3e6400f48c2baaffe4aceb25ae3 msgid "Return type" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 4375f894dabe4fd49e5d470f602e7e4e 669fcb172313407fa0df09ca10280e22 -#: 9ce7848878e44efba62bd42bd640bdeb +#: 051ee4ae623e4c52aca28e50c43a8659 6c5929a2e83444a0b5026560f2c5af02 +#: 7d5aee61dcaa450790fdaa12bda90f1c b717337ce24a4644a8684f6c14ced1d5 msgid "Raises" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 -#: f6db2cc04ccd4bc0a06c34c8d5d00b29 of +#: 8e1b87a14fc44d6383f43b22bdb71770 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 of msgid "If a setting is missing, malformed or out of range." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 -#: a46df3ad1b4d47838e7d86646e5e45d4 of +#: 9104ff2767b4468db4119f0de6103975 +#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 of msgid "SMTP client delivering verification codes." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService:3 -#: a6a714e990194ee9b2c023afa0423ec6 of +#: b29996ad41f1488f8540e22a48f131fa of msgid "" "The stored configuration is read on construction, so a validated mailbox " "is available again after a restart." msgstr "" -#: 906ef645c3f0431c8d4f44bb661e3119 +#: 67ba292bfc8c40ee863f2bf892ff74cb #: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:1 of msgid "Create the service and load the stored configuration." msgstr "" -#: 886b800f093c4d758d14028b4233d623 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 +#: f7b0ac874bc34b408853f868c5c1a9cd of msgid "" "JSON file holding the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 10490a10be734ca58da591842794088d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 +#: cdbf836d9e9c4e2a948458972edbfbae of msgid "Report whether a validated configuration lets codes be sent." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 -#: a19f7729857a4995be526dded313b07d of +#: 6f529ae442fb4a4ba2e0fd72533d0e29 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 of msgid "True when the SMTP settings were validated and stored." msgstr "" -#: 646e8fd83be4421ab0d3b4d38fe2b1c8 +#: 93c564a9ccd64ebca089cbd00f434f9e #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:1 of msgid "Return the validated SMTP settings." msgstr "" -#: 1728b9dc41484d35851721b141e661be +#: 83356ba5ccea4bceae862cc0934959cf #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:3 of msgid "" "Copy of the stored settings, or ``None`` while the service is not " "configured." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 -#: cb61516a7cac473fa2ab322e29340899 of +#: 77ff24f402974e8681e2273634e17e4c +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 of msgid "Copy of the stored settings, or ``None`` while the" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 -#: ba7116251d3b4ce7b97a3e79808c4415 of +#: 383ba8fc4ed940f38097d10bfbc8ff84 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 of msgid "service is not configured." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:1 -#: a2161943624d40a39a45564117df6d9e of +#: c7110be43ff548edb573b0b645e49ef5 of msgid "Validate SMTP settings, store them and start the sending service." msgstr "" -#: 8d8686cd5b9b46d295719719f9b29929 +#: 99385960778b4785bb73f4db98d2dada #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:3 of msgid "Settings accepted by `normalize_config`." msgstr "" -#: 5aa35eba13e04367b7f99d754176a39d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 +#: d801399842874f19943e8d2eb6dd6e6d of msgid "The validated settings as stored." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:9 -#: ab75660bdd60437dbb05953445043ce0 of +#: c4c8574eb0634811a9fd71b2e00233a9 of msgid "" "If a setting is missing or malformed, or the server refuses the " "connection or the login." msgstr "" -#: 4ebf6576a62643d9910acdfba3fcd799 +#: 5c332d9d6242449f97b7bddbe36a20cd +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:1 of +msgid "Remove the stored mailbox so no verification code can be sent." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:3 +#: bc6f8bbf1f0047cebea68882e633945d of +msgid "" +"This is the switch back to internal mode: with no mailbox the server " +"serves its clients without accounts again." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:6 +#: f669f3bdc1f44730a90a6127ff7db331 of +msgid "" +"If the stored file cannot be removed; the service then keeps its " +"settings and stays enabled." +msgstr "" + +#: 7b942af00fc54d9d836170d61972977e #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:1 of msgid "Send one verification code by email." msgstr "" -#: 8f04bd37dc8b4483af595c5e66f8fbf4 +#: 6cdc276558b54671b93a8a839f34a682 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:3 of msgid "Recipient address." msgstr "" -#: 57f0544cdf234e00b9f03da47566354f +#: 60f83153ebac42eeb7ba36ed193d0eb1 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:5 of msgid "Verification code to deliver." msgstr "" -#: 627ee080c93e46679b0eb1dea17640f6 +#: 25f348d2347c4274a624e6d13eb6dfd3 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:7 of msgid "" "\"register\", \"login\" or \"reset_password\"; decides the wording of the" " message." msgstr "" -#: 6733b65d0a2347e1918c983503394f49 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 +#: f16d610fc9f14559af45cddea444add9 of msgid "Code lifetime in seconds, stated in the message." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 -#: ce7cf70f7a2d4deca8256ada1fc9b63d of +#: 134b78c9128942938629dd61e9048916 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 of msgid "If the service is not configured, or the message cannot be delivered." msgstr "" +#~ msgid "" +#~ "The administrator configures the outgoing " +#~ "mailbox from the server's startup-" +#~ "configuration page. The settings are " +#~ "validated with a real SMTP login " +#~ "and only then written to " +#~ "``.Flow_Web/email_config.json``; while no validated" +#~ " configuration is present the service " +#~ "refuses to send, so a server can" +#~ " never silently drop verification codes." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po index 8a536de..1af2774 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -18,24 +18,24 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst:2 -#: 7bc35f7e619347e0b976ca49c973de8f +#: 4e16e69f9ae9491a95bfcab9c70cfe24 msgid "PyFlow.transfer\\_web.web\\_backend.server\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:1 -#: fd1d19a74e7a4e14a3863a4f2d4e6eef of +#: 15eb6d4006b3429a8fa230a2b460b1c5 +#: PyFlow.transfer_web.web_backend.server_backend:1 of msgid "Flask backend wrapping the PyFlow TCP server for the web tool." msgstr "" -#: 6fa9dfd64064447c82ade7290b523d5c +#: 3c413c9e37f94c7485dba6d4f96b9bf2 #: PyFlow.transfer_web.web_backend.server_backend:3 of msgid "Two modes, one process:" msgstr "" -#: 8e61412bb72d49b086f03a2245cd959d +#: 557b793ac8e441db86cf59cad5e85371 #: PyFlow.transfer_web.web_backend.server_backend:5 of msgid "" "``config`` mode: serves the server startup-configuration UI. The UI " @@ -46,7 +46,7 @@ msgid "" msgstr "" #: PyFlow.transfer_web.web_backend.server_backend:10 -#: b15a182866794bf7bfe71605fc47a301 of +#: cb922669795b42c6ad5587b527c4356a of msgid "" "``status`` mode: serves the minimal status page plus the same " "sidebar/input UI as the client frontend (forwarding disabled; native " @@ -54,93 +54,105 @@ msgid "" "clients use to discover the TCP server address/port." msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:15 -#: a297544539714d03afa00d1112541712 of +#: 0c6784517a194d65926c71b7ce7f4836 +#: PyFlow.transfer_web.web_backend.server_backend:15 of msgid "" "The backend monitors ``server.clients``: whenever a client connects or " "disconnects it broadcasts the current instance list to every connected " "client (``/web_clients_update``), and it re-checks the list every minute." msgstr "" -#: 9ad7bd78687141a8a282a951ddc57689 +#: 535e49236690482ebf574e6c65b10f39 #: PyFlow.transfer_web.web_backend.server_backend:20 of msgid "" "Inbound events (plain-text messages and file uploads arriving from " "clients) are captured on the TCP server's receive threads through " "``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` " -"APIs, queued here, and polled by the frontend via ``/api/events``." +"APIs, queued here, and polled by the frontend via ``/api/events``. The " +"message listener reports every inbound line, protocol commands included; " +"the commands are dropped here, so the queue carries user messages only. A" +" file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 69da06074d1141308bd12409e851f506 -#: PyFlow.transfer_web.web_backend.server_backend:25 of +#: 6ee75a9919554a3cb05d55c0f9dba653 +#: PyFlow.transfer_web.web_backend.server_backend:30 of msgid "" "Authentication: anonymous visitors get a white landing page (the server " -"addresses, a login button, a registration button and a password-reset " -"button); the configuration and status pages need a session. Accounts " -"live in the SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`);" -" the first run seeds the ``admin``/``admin`` administrator and the " -"frontend warns on every login until those default credentials are " -"changed. Registration, password reset and code-based client logins are " -"delivered by the mailbox configured from the startup-configuration page " -"(see `mail_service`)." -msgstr "" - -#: 1fb7feafe6ba447e992cd3ebd42801c8 -#: PyFlow.transfer_web.web_backend.server_backend:34 of +"addresses and a login button; while a verification mailbox is configured," +" also a registration button and a password-reset button); the " +"configuration and status pages need a session. Accounts live in the " +"SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the first " +"run seeds the ``admin``/``admin`` administrator and the frontend warns on" +" every login until those default credentials are changed. Registration, " +"password reset and code-based client logins are delivered by the mailbox " +"configured from the startup-configuration page (see `mail_service`)." +msgstr "" + +#: 14b91efc5192438eb9eb025aa4a50ef2 +#: PyFlow.transfer_web.web_backend.server_backend:40 of msgid "" -"Client accounts: the client web frontend logs in through " -"``/api/client_login`` with a username/email, the account password *and* a" -" mailed verification code — both factors are required — and receives a " -"session token. Re-entering the client web UI replays the saved " -"credentials and token through ``/api/client_verify``, which only accepts " -"them while they still open that account. The token binds the TCP " -"connection the client opens (``/web_bind``) to that account, and the " +"Client accounts: the verification mailbox is the switch of the whole " +"client side. While ``.Flow_Web/email_config.json`` holds a validated " +"mailbox the server is meant for public networks: the client web frontend " +"logs in through ``/api/client_login`` with a username/email, the account " +"password *and* a mailed verification code — both factors are required — " +"and receives a session token. Re-entering the client web UI replays the " +"saved credentials and token through ``/api/client_verify``, which only " +"accepts them while they still open that account. The token binds the TCP" +" connection the client opens (``/web_bind``) to that account, and the " "instance list pushed to a client is limited to its contacts, so accounts " -"that never exchanged a contact request cannot see each other." +"that never exchanged a contact request cannot see each other. Without a " +"mailbox the server is an internal tool: clients connect without " +"registration or login, every client sees every other connected instance, " +"and the client account routes are closed — only the console administrator" +" keeps an account." msgstr "" -#: 123122acd40847679e349c6e3b8d9c5e -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 of +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 +#: ab4c37912c524489a26700248a06704c of msgid "Flask app + TCP_Server_Base wrapper for the web tool." msgstr "" #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:1 -#: b7ccb1c765d744b988819d0afbbab22d of +#: fb6d7d555b47497fa6861b7f8a6a5f5d of msgid "Create the Flask app and its stores." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst -#: b841315945d14f34a8ef0541284d23e3 +#: 0fb91f29d163495c8c5e4b758c29cf92 msgid "Parameters" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 -#: c8c0a79297824242960049876ebd3e56 of +#: 79acd75ba91d4388972788215a4dcde7 +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 of msgid "" "Port of this web backend; defaults to ``DEFAULT_WEB_PORT``. A busy port " "falls back to the next free one." msgstr "" -#: 652d75ee0a3d4dd18396a8e2b5aa315e +#: 7dd94be740ee476ea378e766ecf5640b #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:6 of msgid "SQLite account database; defaults to ``.Flow_Web/flow_web.db``." msgstr "" -#: 34f17ede4f7c4556a62f8cc47f3c399d +#: 1db79ba202e74aeebefe1de0df4f3f3f #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:9 of msgid "" "JSON file with the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 011de011008f44dc9c247510315a2341 +#: 7e707a76895243cbb7e49d4a943df5f2 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:1 #: of msgid "Read ``.Flow_Web/setup_server.json`` and start the TCP server." msgstr "" +#: 7a3de044fc304747a1be4161fe0f2e51 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:3 -#: baae3df9217643d0a41c83324c8f035d of +#: of msgid "" "The saved \"ftp\" share is restored as well, so a folder shared before " "the restart keeps being served." @@ -181,3 +193,52 @@ msgstr "" #~ msgid "Rename ``username`` and set its password (self-service)." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " file uploads arriving from clients) " +#~ "are captured on the TCP server's " +#~ "receive threads through ``TCP_Server_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Authentication: anonymous visitors get a " +#~ "white landing page (the server " +#~ "addresses, a login button, a " +#~ "registration button and a password-reset" +#~ " button); the configuration and status " +#~ "pages need a session. Accounts live " +#~ "in the SQLite store ``.Flow_Web/flow_web.db``" +#~ " (see `user_database`); the first run " +#~ "seeds the ``admin``/``admin`` administrator " +#~ "and the frontend warns on every " +#~ "login until those default credentials " +#~ "are changed. Registration, password reset " +#~ "and code-based client logins are " +#~ "delivered by the mailbox configured from" +#~ " the startup-configuration page (see " +#~ "`mail_service`)." +#~ msgstr "" + +#~ msgid "" +#~ "Client accounts: the client web frontend" +#~ " logs in through ``/api/client_login`` with" +#~ " a username/email, the account password " +#~ "*and* a mailed verification code — " +#~ "both factors are required — and " +#~ "receives a session token. Re-entering" +#~ " the client web UI replays the " +#~ "saved credentials and token through " +#~ "``/api/client_verify``, which only accepts " +#~ "them while they still open that " +#~ "account. The token binds the TCP " +#~ "connection the client opens (``/web_bind``)" +#~ " to that account, and the instance" +#~ " list pushed to a client is " +#~ "limited to its contacts, so accounts " +#~ "that never exchanged a contact request" +#~ " cannot see each other." +#~ msgstr "" + diff --git a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po index 47df6cf..0f03981 100644 --- a/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po +++ b/docs/source/locale/ru/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: ru\n" @@ -18,19 +18,19 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_front.client_backend.rst:2 -#: 411a61682c95447192de34eca6a7b40c +#: a7e084a5059341aa9b7419059c4fa4b0 msgid "PyFlow.transfer\\_web.web\\_front.client\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:1 -#: c5b03318abd74b32b6ffba1696f8b20b of +#: 22485674cb53445a86703fb118698523 +#: PyFlow.transfer_web.web_front.client_backend:1 of msgid "Flask backend wrapping the PyFlow TCP client for the web tool." msgstr "" -#: 13a2da9087074258858c4dd7a697671e +#: 31862d77d7184e55a1e729d7e72baed0 #: PyFlow.transfer_web.web_front.client_backend:3 of msgid "" "The launcher (``setup_client.py``) starts this backend and opens the " @@ -41,70 +41,123 @@ msgid "" "relay the user's frontend actions:" msgstr "" -#: 95d3503d45ac47ba8c8a9522aceb4764 +#: 1a028258cda844ee945b9522d51afb9d #: PyFlow.transfer_web.web_front.client_backend:10 of msgid "messages/files/folders to the server use the native transfer methods;" msgstr "" #: PyFlow.transfer_web.web_front.client_backend:11 -#: be1496ab996044798cfc05692616cd8a of +#: e160c2a0daf9498cbe2041a8e964ff47 of msgid "" "messages to other clients use the native ``/forward_send_msg`` forwarding" " (a client-only command relayed by the server);" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:13 -#: a59ab775ca734b828f09313089028a9f of +#: 16da18234f0a499893b711e7b555b42a +#: PyFlow.transfer_web.web_front.client_backend:13 of msgid "" "files/folders to other clients are forwarded through the built-in " "``forward_extension_tcp`` extension." msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:16 -#: ea807a0c324b430c8731aa632d099643 of +#: 79dee862a03f4d0c9bc9403f8d461465 +#: PyFlow.transfer_web.web_front.client_backend:16 of msgid "" "The sidebar instance list is kept fresh by the server's " "``/web_clients_update`` broadcasts; a reload button re-requests the list " "via ``/web_sync_clients``." msgstr "" -#: 3656f3e4bded46b596db7d1bdc666b90 +#: 13d20ecd894c4e26a28266b7ac128dfd #: PyFlow.transfer_web.web_front.client_backend:20 of msgid "" "Inbound events (plain-text messages and files pushed by the server, " "whether direct sends or client forwards) are captured on the TCP client's" " receive threads through ``TCP_Client_Base``'s " "``add_message_listener``/``add_file_listener`` APIs, queued here, and " -"polled by the frontend via ``/api/events``." +"polled by the frontend via ``/api/events``. The message listener reports" +" every inbound line, protocol commands included; a direct command from " +"the server is dropped here, so the queue carries user messages only. A " +"file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 565c32267ec64ccbb0904ef2ec5609df -#: PyFlow.transfer_web.web_front.client_backend:26 of +#: 5c1c2971ea0e45d8a56544972cdc4ff4 +#: PyFlow.transfer_web.web_front.client_backend:31 of msgid "" -"Accounts: a connected client logs in with a server account before the " -"instance list is usable. A forced login needs both factors — the account" -" password and a verification code mailed to the account address — while a" -" client that starts again replays the saved credentials and session token" -" through ``/api/client_verify``. ``/api/login`` opens the session, the " +"Accounts: the connected server decides whether its clients need accounts." +" A server with a verification mailbox is public, so this backend forces " +"the account login before the instance list is usable; a server without " +"one is internal and everything account-related is skipped — no login " +"window, no contacts, and every client sees every other instance. A " +"forced login needs both factors — the account password and a verification" +" code mailed to the account address — while a client that starts again " +"replays the saved credentials and session token through " +"``/api/client_verify``. ``/api/login`` opens the session, the " "``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the " "contact management to the server, and the session token is sent over TCP " "with ``/web_bind`` so the server can push the contact list of that " "account. The credentials are remembered in " -"``.Flow_Web/client_login.json`` (owner-readable only) and the login " -"window is shown whenever no session could be restored." +"``.Flow_Web/client_login.json`` (owner-readable only)." msgstr "" -#: 1e6c10d599f046398e16a7b47e0b8dab +#: 0913e15917534119b775fb5c545c439d #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp:1 of msgid "Flask app + TCP_Client_Base wrapper for the web tool." msgstr "" -#: 6c87b744956640d682bef32158496990 #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:1 +#: bc85ca281f4e4df5a0f10290029fca34 of +msgid "Start the TCP client from ``.Flow_Web/setup_client.json``." +msgstr "" + +#: 612871943a7e45a2bacdc377aec78b77 +#: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:3 #: of -msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +msgid "" +"The connected server reports whether its clients log in; only then is a " +"saved session replayed, and the login window is only shown then." msgstr "" #~ msgid "Read ``.Flow_Web/setup_client.json`` and start the TCP client." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " files pushed by the server, whether" +#~ " direct sends or client forwards) are" +#~ " captured on the TCP client's receive" +#~ " threads through ``TCP_Client_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Accounts: a connected client logs in " +#~ "with a server account before the " +#~ "instance list is usable. A forced " +#~ "login needs both factors — the " +#~ "account password and a verification code" +#~ " mailed to the account address — " +#~ "while a client that starts again " +#~ "replays the saved credentials and " +#~ "session token through ``/api/client_verify``. " +#~ "``/api/login`` opens the session, the " +#~ "``/api/contacts/*`` and ``/api/contact_requests`` " +#~ "routes proxy the contact management to" +#~ " the server, and the session token" +#~ " is sent over TCP with ``/web_bind``" +#~ " so the server can push the " +#~ "contact list of that account. The " +#~ "credentials are remembered in " +#~ "``.Flow_Web/client_login.json`` (owner-readable " +#~ "only) and the login window is " +#~ "shown whenever no session could be " +#~ "restored." +#~ msgstr "" + +#~ msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/Crypto/Crypto.po b/docs/source/locale/zh_CN/LC_MESSAGES/Crypto/Crypto.po index d6fb86f..cf77e6f 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/Crypto/Crypto.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/Crypto/Crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../source/Crypto/Crypto.rst:2 bb50e4f310ea43d9ba55e4b367ed7740 +#: ../../source/Crypto/Crypto.rst:2 9878b2fb3d9d4d6ba3cd00002ed6f0b7 msgid "C/OpenSSL Crypto Module" msgstr "C/OpenSSL 加密模块" -#: ../../source/Crypto/Crypto.rst:4 2838c629d37d42ef92dbabeab8d33801 +#: ../../source/Crypto/Crypto.rst:4 aa824d3e127240b0928431af3dd8c831 #, fuzzy msgid "" "The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL " @@ -31,62 +31,62 @@ msgstr "" "``src/crypto_api`` 目录包含 ServSpy 的 C/OpenSSL 加密库。该库独立于 Python 运行时,并使用 " "CMake 从存储库根构建。" -#: ../../source/Crypto/Crypto.rst:8 2c028ead37a24eb98321135f22f3673d +#: ../../source/Crypto/Crypto.rst:8 294667df2a20495887126b808c7d9706 msgid "The module provides:" msgstr "该模块提供:" -#: ../../source/Crypto/Crypto.rst:10 e290cfffb80140899093170eda086e61 +#: ../../source/Crypto/Crypto.rst:10 472d4f3082db42f198b7f13fdbf041f2 msgid "RSA-OAEP encryption and decryption with SHA-256." msgstr "使用 SHA-256 进行 RSA-OAEP 加密和解密。" -#: ../../source/Crypto/Crypto.rst:11 125f1968eba34f6896b44b6406f0e6c2 +#: ../../source/Crypto/Crypto.rst:11 0eb3f7206503452ca2229a1d7c323390 msgid "ECDH key agreement on P-256, P-384, and P-521." msgstr "P-256、P-384 和 P-521 上的 ECDH 密钥协议。" -#: ../../source/Crypto/Crypto.rst:12 cee735932767478e95a96b9a59ddcdd2 +#: ../../source/Crypto/Crypto.rst:12 ab0be16cfbca493a88c6eb4a2ef1bb07 msgid "HKDF-SHA256 session-key derivation." msgstr "HKDF-SHA256 会话密钥派生。" -#: ../../source/Crypto/Crypto.rst:13 7d211e9cf2e64cab9b79c0173805334e +#: ../../source/Crypto/Crypto.rst:13 56667bb7a4554c1b8efc918c9593f950 msgid "AES-256-GCM authenticated encryption for ECDH sessions." msgstr "ECDH 会话的 AES-256-GCM 身份验证加密。" -#: ../../source/Crypto/Crypto.rst:14 d345fd729851496c82017971bdb55276 +#: ../../source/Crypto/Crypto.rst:14 8de85fb1a2f843ea91d0aa30df0a00c7 msgid "PEM key persistence and structured error reporting." msgstr "PEM 密钥持久性和结构化错误报告。" -#: ../../source/Crypto/Crypto.rst:16 d86187e532624ac49492cca1b064a89b +#: ../../source/Crypto/Crypto.rst:16 564b1d414738498791d9083f279330fe msgid "" "The library version is 1.0.0 (``PF_CRYPTO_VERSION_MAJOR`` / " "``PF_CRYPTO_VERSION_MINOR`` / ``PF_CRYPTO_VERSION_PATCH`` and " "``PF_CRYPTO_VERSION_STRING`` in ``pf_crypto.h``)." msgstr "" -#: ../../source/Crypto/Crypto.rst:20 5e6c65799ec14fd8b67034bd1b3beb07 +#: ../../source/Crypto/Crypto.rst:20 10fda1fcea98430a8924fdfa8bbce2fa #, fuzzy msgid "The public headers are located in ``PyFlow/crypto_api/include``:" msgstr "公共标头位于“src/crypto_api/include”中:" -#: ../../source/Crypto/Crypto.rst:22 87305d509fc94f5186438e34d9583987 +#: ../../source/Crypto/Crypto.rst:22 86168d67fc8047ba8d4c61b2b9e23caf #, fuzzy msgid "``pf_crypto.h`` - common errors, OpenSSL diagnostics, and HKDF." msgstr "``ss_crypto.h`` - 常见错误、OpenSSL 诊断和 HKDF。" -#: ../../source/Crypto/Crypto.rst:23 5d221a05e5034eccadaec2206256a2af +#: ../../source/Crypto/Crypto.rst:23 ddfd841fba4b4045bb3fc84419010fe7 #, fuzzy msgid "``pf_rsa.h`` - RSA key and encryption APIs." msgstr "``ss_rsa.h`` - RSA 密钥和加密 API。" -#: ../../source/Crypto/Crypto.rst:24 e10e899ebf934a18a686d225d3f967d9 +#: ../../source/Crypto/Crypto.rst:24 eb2168817ac54389a35e194a444250f4 #, fuzzy msgid "``pf_ecdh.h`` - ECDH key agreement and seal/open APIs." msgstr "``ss_ecdh.h`` - ECDH 密钥协议和密封/开放 API。" -#: ../../source/Crypto/Crypto.rst:27 09186509365444d4ac1ce145d76bcd28 +#: ../../source/Crypto/Crypto.rst:27 43fa12b668bb4dc389f2bbd9edaf9187 msgid "Build" msgstr "建造" -#: ../../source/Crypto/Crypto.rst:29 ae41004303f342d2ac3e302fe5ff9b40 +#: ../../source/Crypto/Crypto.rst:29 35019410fade4c18b07d32d37c05ba0d msgid "" "The module requires OpenSSL 1.1.1 or newer and CMake 3.16 or newer. On " "Debian or Ubuntu, install the build dependencies with:" @@ -94,7 +94,7 @@ msgstr "" "该模块需要 OpenSSL 1.1.1 或更高版本以及 CMake 3.16 或更高版本。在 Debian 或 Ubuntu " "上,使用以下命令安装构建依赖项:" -#: ../../source/Crypto/Crypto.rst:37 7c534481ca81453b89692a8758bbeba0 +#: ../../source/Crypto/Crypto.rst:37 3834ad9e83c24331b03d264103f5cdad msgid "" "Installing the Python package builds it automatically: ``setup.py`` " "compiles the three sources and installs the result inside the package " @@ -102,19 +102,19 @@ msgid "" "pyflow-net`` needs only a C compiler and the OpenSSL development headers." msgstr "" -#: ../../source/Crypto/Crypto.rst:42 6abf3a2d83804b73b1bfd45add4322d8 +#: ../../source/Crypto/Crypto.rst:42 a72fb95d5d114cdca29347b18e2c1253 msgid "" "Build it from the repository root with CMake when the C test suite or the" " C API itself is wanted:" msgstr "" -#: ../../source/Crypto/Crypto.rst:51 6fbb49d9124649f1b387de2f0377a4af +#: ../../source/Crypto/Crypto.rst:51 96617bb44be2438ebbde9e9f750b3e09 msgid "" "``ctest --test-dir`` was added in CMake 3.20; with the 3.16 minimum the " "equivalent is ``ctest --output-on-failure`` run from inside ``build/``." msgstr "" -#: ../../source/Crypto/Crypto.rst:54 f42772e265ad4248b11c37141f4fb6e8 +#: ../../source/Crypto/Crypto.rst:54 244b7aff35aa4272a121b9fbbadae117 #, fuzzy msgid "" "The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, " @@ -125,27 +125,26 @@ msgstr "" "C " "测试套件位于“test/crypto_api/”(“test_hkdf”、“test_rsa”、“test_ecdh”)中,并与库一起构建和运行。" -#: ../../source/Crypto/Crypto.rst:59 ed6b92c776ca441ab8629088ecd973bc +#: ../../source/Crypto/Crypto.rst:59 30ea804b8270411f8793908bdc7a2a97 #, fuzzy msgid "" "The library is built as a shared object (``libcrypto_api.so``) so it can " "be loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes " -"binding used by the TCP layer to encrypt messages with RSA-OAEP (see the " -"``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). " -"The binding also implements the TCP layer's anti-MITM identity check " -"(TOFU): peer public keys are exchanged on every connection, recorded " -"under the peer's ``(ip, port)`` in " -"``network_api/.Flow/pub_key/pub_key.json`` with the SHA-256 of the " -"received PEM text, and a changed key for a recorded endpoint rejects the " -"connection; a key already known under another endpoint is accepted and " -"re-registered under the new one. The encryption state machine is bounded:" -" three consecutive decode failures trip a circuit breaker " -"(``MAX_DECODE_FAILURES`` in ``connect_tcp.py``) that stops re-keying, and" -" a key that is stale or rotated makes the TCP layer reload its own key " -"and re-exchange. The binding looks for the library via " -"``ctypes.util.find_library`` and then next to the repository root in " -"``build/`` (``libcrypto_api.so``, ``libcrypto_api.dylib``, " -"``libcrypto_api.dll`` and ``build/Release/crypto_api.dll``)." +"binding used by the TCP layer. It exposes the RSA-OAEP message encryption" +" and the ECDH/AES-256-GCM sealing (``EcdhKeyPair`` / ``EcdhPubKey`` / " +"``hkdf_sha256``) that the framed TCP channel uses for its bulk and file " +"transfer payloads (see the ``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"encrypted channel sections). The binding also implements the TCP layer's " +"anti-MITM identity check (TOFU): endpoint rejects the connection; a key " +"already known under another endpoint is accepted and re-registered under " +"the new one. The encryption state machine is bounded: three consecutive " +"decode failures trip a circuit breaker (``MAX_DECODE_FAILURES`` in " +"``connect_tcp.py``) that stops re-keying, and a key that is stale or " +"rotated makes the TCP layer reload its own key and re-exchange. The " +"binding looks for the library via ``ctypes.util.find_library`` and then " +"next to the repository root in ``build/`` (``libcrypto_api.so``, " +"``libcrypto_api.dylib``, ``libcrypto_api.dll`` and " +"``build/Release/crypto_api.dll``)." msgstr "" "该库被构建为共享对象(“libcrypto_api.so”),因此可以从Python加载:“src/network_api/rsa_crypto.py”是TCP层使用的ctypes绑定" ",用于使用RSA-OAEP加密消息(请参阅“TCP_Server_APIs”/“TCP_Client_APIs”加密通道部分)。该绑定还实现了 " @@ -153,13 +152,13 @@ msgstr "" "记录在“network_api/.Flow/pub_key/pub_key.json”中对等方的“(ip, " "port)”下,并且记录端点的更改密钥会拒绝连接。绑定通过“ctypes.util.find_library”和存储库根目录旁边的“build/”查找库。" -#: ../../source/Crypto/Crypto.rst:77 ad993af85f8f45f5a3661448f69961bf +#: ../../source/Crypto/Crypto.rst:77 9594680fce33464f9ff9cb9590bb5d0a msgid "" "The build produces the SOVERSIONed names ``libcrypto_api.so.1`` / " "``libcrypto_api.so.1.0.0`` plus the ``libcrypto_api.so`` loader symlink." msgstr "" -#: ../../source/Crypto/Crypto.rst:80 7ea41df5c6644e8197d587e03642123f +#: ../../source/Crypto/Crypto.rst:80 80c24657a4c9445088459fff264379b2 #, fuzzy msgid "" "CMake install rules export the ``crypto_api`` library, its public " @@ -174,11 +173,11 @@ msgstr "" "CMake 安装规则导出“crypto_api”库、其公共标头和 CMake 包配置。所有 CMake 内容都位于存储库根目录:CMake " "包模板和 pkg-config 模板是“cmake/crypto_apiConfig.cmake.in”和“crypto_api.pc.in”。" -#: ../../source/Crypto/Crypto.rst:89 0d7e08f1e07445dfa77b47a85a25def7 +#: ../../source/Crypto/Crypto.rst:89 dccd3901c8024859b9a9753e818d6692 msgid "Common API" msgstr "通用API" -#: ../../source/Crypto/Crypto.rst:91 1c9b38b493964582875d168e61ccf829 +#: ../../source/Crypto/Crypto.rst:91 c1b71e19c8f6422eabd99bd0997daae8 msgid "" "Most public functions return ``pf_err_t``; ``PF_OK`` indicates success. " "Functions that report a size or a string instead have their own return " @@ -190,22 +189,25 @@ msgid "" "pending OpenSSL error queue." msgstr "" -#: ../../source/Crypto/Crypto.rst:114 07ac67f777704ad9822023430f0109c4 +#: ../../source/Crypto/Crypto.rst:114 67ae5556635e43a487c38bf8011e1c5b #, fuzzy msgid "" "The library uses caller-provided output buffers for fixed-size results. " "Functions that return allocated buffers document that the caller must " -"release them with ``free``. Opaque key handles must be released with " +"release them with ``pf_crypto_free`` — the library's own ``free``, so the" +" allocation and the deallocation always run on the same C runtime (a host" +" such as CPython on Windows may use a different one, and freeing across " +"runtimes corrupts the heap). Opaque key handles must be released with " "their corresponding ``*_free`` function. HKDF output is capped at " "``PF_CRYPTO_HKDF_SHA256_MAX_OUT`` (8160 bytes) by both " "``pf_crypto_hkdf_sha256`` and ``pf_ecdh_derive_key``." msgstr "该库使用调用者提供的输出缓冲区来获取固定大小的结果。返回分配的缓冲区的函数记录了调用者必须使用“free”释放它们。不透明的按键句柄必须使用其相应的“*_free”函数来释放。" -#: ../../source/Crypto/Crypto.rst:122 619e39d223d54a48ba983a3b30bd7d9d +#: ../../source/Crypto/Crypto.rst:125 69248ac47e7e47f18e953dee857db239 msgid "RSA API" msgstr "RSA API" -#: ../../source/Crypto/Crypto.rst:124 5eeaa87820f941dd8e171c973269036e +#: ../../source/Crypto/Crypto.rst:127 a770dcc04e2c42d1be50fe30d298df4b #, fuzzy msgid "" "RSA keys are generated with ``pf_rsa_keygen``. The implementation uses " @@ -215,7 +217,7 @@ msgstr "" "RSA 密钥是使用“ss_rsa_keygen”生成的。该实现使用 RSA-OAEP 和 SHA-256 进行加密和解密。接受 2048 至 " "16384 位的密钥大小;建议使用 2048、3072 或 4096 位。" -#: ../../source/Crypto/Crypto.rst:148 f85a46b466ef47ee9d195f439ba3b153 +#: ../../source/Crypto/Crypto.rst:151 e7b876b8fb354b2da45d3c13f50ededf msgid "" "The first encryption call with ``out == NULL`` queries the required " "output size; ``pf_rsa_decrypt`` supports the same query pattern. RSA " @@ -227,34 +229,34 @@ msgid "" "handle." msgstr "" -#: ../../source/Crypto/Crypto.rst:156 ff9d2472cf614dd0827d0887f195ed43 +#: ../../source/Crypto/Crypto.rst:159 6af957980305426e915b3f62d9eb1ed4 msgid "Public and private keys can be stored as PEM files:" msgstr "公钥和私钥可以存储为 PEM 文件:" -#: ../../source/Crypto/Crypto.rst:167 a3f163de660b4d49a36a8aedead555da +#: ../../source/Crypto/Crypto.rst:170 6bf9df3c51d540b69680723a4845de2d msgid "ECDH API" msgstr "ECDH API" -#: ../../source/Crypto/Crypto.rst:169 4535e8f410a742f38d32ff53d404c37b +#: ../../source/Crypto/Crypto.rst:172 3c69950828364df49bbf0b37313f9987 #, fuzzy msgid "" "ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The " "supported curve names are:" msgstr "ECDH 密钥对是使用“ss_ecdh_keypair_generate”创建的。支持的曲线名称是:" -#: ../../source/Crypto/Crypto.rst:172 9624f8475c8d4618a7054e7c18ae5e1f +#: ../../source/Crypto/Crypto.rst:175 6a4d2171568847d4984c8705818c4bf9 msgid "``PF_ECDH_CURVE_P256``" msgstr "``PF_ECDH_CURVE_P256``" -#: ../../source/Crypto/Crypto.rst:173 4585a2433d684621a5f90805b74cef6c +#: ../../source/Crypto/Crypto.rst:176 c0da017a21dc46ed93b3da0727454dc3 msgid "``PF_ECDH_CURVE_P384``" msgstr "``PF_ECDH_CURVE_P384``" -#: ../../source/Crypto/Crypto.rst:174 14dde8ddd1b44ae1a4cb64179caa5aa5 +#: ../../source/Crypto/Crypto.rst:177 b2019f9f782b48dc85c5e3b24647fd94 msgid "``PF_ECDH_CURVE_P521``" msgstr "``PF_ECDH_CURVE_P521``" -#: ../../source/Crypto/Crypto.rst:176 43b77941f20d44958205bea666a208d5 +#: ../../source/Crypto/Crypto.rst:179 0962e1bca8da48d1835cbe8facb8a0ea #, fuzzy msgid "" "An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` " @@ -262,7 +264,7 @@ msgid "" "strings. Parsed peer keys are checked to lie on the curve before use." msgstr "公钥作为 PEM subjectPublicKeyInfo 字符串进行交换。使用前会检查已解析的对等密钥。" -#: ../../source/Crypto/Crypto.rst:200 ac2db67c049d4f55a2fc2f9972c6d57c +#: ../../source/Crypto/Crypto.rst:203 c5c15560992c48beb7637c19a517f07f #, fuzzy msgid "" "The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are " @@ -275,23 +277,23 @@ msgstr "" "建议将更高级别的 ``ss_ecdh_seal`` 和 ``ss_ecdh_open`` API 用于应用程序负载。他们使用 HKDF-" "SHA256 派生 AES-256-GCM 密钥,包括随机盐和 IV,并验证可选的 AAD。" -#: ../../source/Crypto/Crypto.rst:207 70a8e3f511f34359974c9152d60500b2 +#: ../../source/Crypto/Crypto.rst:210 f794a8f7227443e381d5337e9fe95677 #, fuzzy msgid "The ``pf_ecdh_seal`` output format is:" msgstr "``ss_ecdh_seal`` 输出格式为:" -#: ../../source/Crypto/Crypto.rst:213 28f1933678854354b8ef357adcfdd380 +#: ../../source/Crypto/Crypto.rst:216 ee4a7ea6853249a7a137f949e3b9d7cc #, fuzzy msgid "" "The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty " "plaintext is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` " "and no plaintext is returned. On success the output buffer is " -"``malloc``-ed and the caller frees it." +"``malloc``-ed and the caller releases it with ``pf_crypto_free``." msgstr "" "固定开销为“SS_ECDH_SEAL_OVERHEAD”(44 " "字节)。允许空明文。失败的标签检查返回``SS_ERR_AUTH_FAILED``并且不返回明文。" -#: ../../source/Crypto/Crypto.rst:218 9a7c6cc7b5a94e5fac26bc6802310183 +#: ../../source/Crypto/Crypto.rst:221 212039cbe4b74827b643af47aaaf9970 msgid "" "ECDH key pairs can be persisted with ``pf_ecdh_keypair_write_priv`` and " "``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-" @@ -299,18 +301,18 @@ msgid "" "``pf_ecdh_pubkey_free`` release the handles." msgstr "" -#: ../../source/Crypto/Crypto.rst:224 7f05214ee91a478581014c39643d7bfb +#: ../../source/Crypto/Crypto.rst:227 a84d53d68554474fbb2beaa2146cee86 msgid "Security Notes" msgstr "安全说明" -#: ../../source/Crypto/Crypto.rst:226 a6482f5940d1469088bb376b1d25d31c +#: ../../source/Crypto/Crypto.rst:229 5e398f6a7ace4aeea29bcd40e75a59b1 msgid "" "ECDH provides key agreement, but it does not authenticate public-key " "ownership by itself. Public keys must be exchanged over an authenticated " "channel or verified with an external signature/certificate mechanism." msgstr "ECDH 提供密钥协商,但它本身并不验证公钥所有权。公钥必须通过经过身份验证的通道进行交换或使用外部签名/证书机制进行验证。" -#: ../../source/Crypto/Crypto.rst:230 fb49962bd1f0474c91610fa9dd020584 +#: ../../source/Crypto/Crypto.rst:233 df43fe66482c4e0fb896ab598ce43c7d #, fuzzy msgid "" "Private key files may be protected with a passphrase: " @@ -321,64 +323,64 @@ msgid "" "plaintext session keys." msgstr "私钥文件可以用密码保护。应用程序应限制其文件权限并避免记录密码、私钥或纯文本会话密钥。" -#: ../../source/Crypto/Crypto.rst:238 e09bc96e058a4b14b135a1430b8a3ad9 +#: ../../source/Crypto/Crypto.rst:241 02cb264ad6c747d29b37bfa1f1cc6362 msgid "Error Handling" msgstr "错误处理" -#: ../../source/Crypto/Crypto.rst:240 8246aab2cf7d4913a7345684940c9220 +#: ../../source/Crypto/Crypto.rst:243 60786ad51ea444da97922957e670ea90 msgid "The main error codes are:" msgstr "主要错误代码有:" -#: ../../source/Crypto/Crypto.rst:242 45059d6bf45c42c2bc8e8c6f023836f4 +#: ../../source/Crypto/Crypto.rst:245 8c1b057428f2445889d1159d6636b097 msgid "" "``PF_ERR_INVALID_ARG`` - NULL argument, illegal length or bad parameter " "combination (e.g. out-of-range RSA key size, a NULL salt/info with a non-" "zero length, or a plaintext longer than the key allows)." msgstr "" -#: ../../source/Crypto/Crypto.rst:245 daed84defdb64065849a0ef880b22eea +#: ../../source/Crypto/Crypto.rst:248 27e26e555ee24ce68ab7943b4117a57d #, fuzzy msgid "``PF_ERR_NOMEM`` - allocation failure." msgstr "``SS_ERR_NOMEM`` - 分配失败。" -#: ../../source/Crypto/Crypto.rst:246 788a5b4b06714adcab5aeb36b81757e4 +#: ../../source/Crypto/Crypto.rst:249 2b3828e4bfa04329a60b479be7f0dfe5 #, fuzzy msgid "``PF_ERR_OPENSSL`` - OpenSSL operation failure." msgstr "``SS_ERR_IO`` - 文件操作失败。" -#: ../../source/Crypto/Crypto.rst:247 0e06a2169f5d445cab788910aaee188a +#: ../../source/Crypto/Crypto.rst:250 2c3c9ab09d294be8911f4fb31c335db6 #, fuzzy msgid "``PF_ERR_IO`` - file operation failure." msgstr "``SS_ERR_IO`` - 文件操作失败。" -#: ../../source/Crypto/Crypto.rst:248 0d1b17cc4e744efd891efe2d292f6dd8 +#: ../../source/Crypto/Crypto.rst:251 a928f8b90e154bdaa43ef4e4ee7d578d #, fuzzy msgid "" "``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key " "passphrase." msgstr "``SS_ERR_PARSE`` - PEM/DER 输入格式错误或私钥密码错误。" -#: ../../source/Crypto/Crypto.rst:249 8d5f6adfe3b24ecebb6ed2d84cece394 +#: ../../source/Crypto/Crypto.rst:252 9cd41d63123d49caa946160465dda70f #, fuzzy msgid "``PF_ERR_BUFFER_TOO_SMALL`` - caller output buffer is insufficient." msgstr "``SS_ERR_BUFFER_TOO_SMALL`` - 调用者输出缓冲区不足。" -#: ../../source/Crypto/Crypto.rst:250 7a88e3913e8948edbcf645b5097b47b3 +#: ../../source/Crypto/Crypto.rst:253 78532f0a764249178076a4adcc032f7f #, fuzzy msgid "``PF_ERR_AUTH_FAILED`` - AES-GCM authentication failed." msgstr "``SS_ERR_AUTH_FAILED`` - AES-GCM 身份验证失败。" -#: ../../source/Crypto/Crypto.rst:251 1182998c4b164675a840d89b3a8e994b +#: ../../source/Crypto/Crypto.rst:254 5e5f5421333e4382ae5e700d7570648b #, fuzzy msgid "``PF_ERR_UNSUPPORTED`` - unsupported curve or key type." msgstr "``SS_ERR_UNSUPPORTED`` - 不支持的曲线或关键点类型。" -#: ../../source/Crypto/Crypto.rst:252 0af6413bc92a46a48a1ea044a6b4f05b +#: ../../source/Crypto/Crypto.rst:255 d1fea86be03940d097132b112b6f14f2 #, fuzzy msgid "``PF_ERR_DECRYPT`` - RSA decryption failed." msgstr "``SS_ERR_DECRYPT`` - RSA 解密失败。" -#: ../../source/Crypto/Crypto.rst:254 b425983151054505a243c1d65c68a2b8 +#: ../../source/Crypto/Crypto.rst:257 9b1c2b2d3f48459bbedee21c92aafe31 msgid "For detailed OpenSSL diagnostics:" msgstr "有关详细的 OpenSSL 诊断:" diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/File_Transfer/File_Transfer.po b/docs/source/locale/zh_CN/LC_MESSAGES/File_Transfer/File_Transfer.po index 8551530..8bc8f16 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/File_Transfer/File_Transfer.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/File_Transfer/File_Transfer.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,12 +20,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/File_Transfer/File_Transfer.rst:2 -#: 2d215e70ec1e43988343e3d32392d8aa +#: d9c92006bc3e49c9a5d184d74f2e7824 msgid "TCP File Transfer Mechanism" msgstr "TCP文件传输机制" #: ../../source/File_Transfer/File_Transfer.rst:4 -#: f603ff252cb64bea9b7c9034d2d46221 +#: b32ed3356f814a369d9d4bc153c017fa msgid "" "This document describes the file transfer subsystem implemented in both " "the ``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file " @@ -36,45 +36,46 @@ msgid "" msgstr "本文档描述了在“TCP_Server_Base”和“TCP_Client_Base”类中实现的文件传输子系统。文件传输机制允许在服务器及其连接的客户端之间发送和接收单个文件、文件夹、多个文件和多个文件夹。它还支持从服务器控制台由服务器发起的传输。" #: ../../source/File_Transfer/File_Transfer.rst:14 -#: f28ca12001c24b1c954e10fdb63aa493 +#: ad6d3cd551694899ba6998e43167bb10 msgid "The design follows a **two-phase handshake** pattern:" msgstr "该设计遵循**两阶段握手**模式:" #: ../../source/File_Transfer/File_Transfer.rst:16 -#: b348421cfc6d4267a58231db041e7d67 +#: f67e58b5ae8b4e2a8f9a9021efba0b5c msgid "A transfer command is exchanged over the main control connection." msgstr "传输命令通过主控制连接进行交换。" #: ../../source/File_Transfer/File_Transfer.rst:18 -#: 0483543fb8f0497a9ee256fee509e4fc +#: 4d267488a6cf4911bc2c3cb7801dce8d msgid "" "A separate TCP connection is established on a dynamically allocated port " "to transfer the actual file data (metadata + payload)." msgstr "在动态分配的端口上建立单独的 TCP 连接以传输实际文件数据(元数据 + 有效负载)。" #: ../../source/File_Transfer/File_Transfer.rst:22 -#: 0e13d1b8b6ef46ce855c8949ef36f219 +#: a0490aac6cc74a8f9de5e9872378b87c #, fuzzy msgid "" -"All file transfers use **stream-oriented reading/writing** with fixed-" -"size chunks (65536 bytes, hardcoded in both directions) to avoid blocking" -" and to handle large files efficiently." +"All file transfers use **stream-oriented reading/writing** with a " +"configurable chunk size (``file_transfer_chunk_len``, 65536 bytes by " +"default, in both directions) to avoid blocking and to handle large files " +"efficiently." msgstr "所有文件传输都使用**面向流的读/写**和固定大小的块(默认为 64 KiB),以避免阻塞并有效处理大文件。" #: ../../source/File_Transfer/File_Transfer.rst:28 -#: a8c11b500a31468aa10fc4d6537c691c +#: 9ad33f3c1a2e4164b384a71388b895f5 msgid "" "*Note: For a high-level overview of the server and client classes, please" " refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" msgstr "*注意:有关服务器和客户端类的高级概述,请参阅 TCP_Server_APIs 和 TCP_Client_APIs。*" #: ../../source/File_Transfer/File_Transfer.rst:35 -#: aeba1deb576440f29ab1d507d38fb22d +#: 2c31714fc81743fa9fbb8701d87347ac msgid "File Transfer Protocol" msgstr "文件传输协议" #: ../../source/File_Transfer/File_Transfer.rst:37 -#: a97e5fe0762d4d2d8ffef8527985c9e7 +#: 61af0fc38ea74fcfae8b2a1316d2e6ea msgid "" "The protocol is symmetric: the same low-level exchange is used regardless" " of whether the server sends to a client or the client sends to the " @@ -84,7 +85,7 @@ msgid "" msgstr "该协议是对称的:无论服务器发送到客户端还是客户端发送到服务器,都使用相同的低级交换。传输的**发起者**(发送命令的一方)同时也是文件数据的**发送者**;另一方充当**接收者**。" #: ../../source/File_Transfer/File_Transfer.rst:46 -#: 1a2e27611ea0452d99cd3e8ac299683c +#: 2ef019fa21e74d26873cb1da802747ac msgid "" "The low-level wire markers are stored in " "``PyFlow/network_api/decode_command_table.json``, which each instance " @@ -93,7 +94,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:52 -#: ebc9fc6492964c47b4744d8e2faf6ffd +#: be499b6571974e1a87d5c471578ac79b #, fuzzy msgid "" "``server_start_file_transfer_sign`` — from " @@ -103,7 +104,7 @@ msgid "" msgstr "``server_start_file_transfer_sign`` - 由接收方发送给发送方,表明接收方已准备就绪。" #: ../../source/File_Transfer/File_Transfer.rst:57 -#: d23e35d928494417918b1e9e1810d2e9 +#: 3c9a4f28914742dab2a8175df58f9419 msgid "" "``send_file_header_sign`` / ``send_file_data_sign`` — from " "``file_send_server_header`` / ``file_send_server_data``; both attributes " @@ -111,7 +112,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:60 -#: 07ce10ba9a534d2db23cb3505f3d9ad7 +#: 2035637777a449768450196f0fec1397 msgid "" "``server_received_file_header_sign`` / ``server_received_file_data_sign``" " — from ``file_receive_client_header`` / ``file_receive_client_data``; " @@ -121,7 +122,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:67 -#: a2c795d996c4491e9c90f46871d655b0 +#: 0fc372ae19be49029aa105a95e480640 #, fuzzy msgid "" "``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by " @@ -130,7 +131,7 @@ msgid "" msgstr "``error_sign`` - 当发生错误时由任何一方发送,导致传输套接字关闭。" #: ../../source/File_Transfer/File_Transfer.rst:72 -#: b95751f788c044d69f86a067e221a340 +#: 41f6d3d6e0e848bc8f6aecb995223622 msgid "" "The remaining keys of the table cover the other three direction/phase " "combinations. Protocol control lines that are not part of this table " @@ -141,47 +142,49 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:80 -#: c481ce301cdc4dddba6f392dc6de4e6a +#: 45a36aa9239d4caba8752e4dc4fd551b msgid "### Metadata Exchange" msgstr "### 元数据交换" #: ../../source/File_Transfer/File_Transfer.rst:82 -#: a6fea134d58a457ab825ec59930e0c48 +#: d4ace80bc05f4bafb8144e1de31060dc msgid "" "The sender performs the following steps after the dedicated file-transfer" " socket is connected:" msgstr "连接专用文件传输套接字后,发送方执行以下步骤:" #: ../../source/File_Transfer/File_Transfer.rst:86 -#: e18ac26158444f719667794153f422d8 +#: 5df80a71cd274a92975e8d010f564872 msgid "" "Wait for the receiver's start signal " "(``server_start_file_transfer_sign``) with a 10-second timeout." msgstr "等待接收器的启动信号(``server_start_file_transfer_sign``),超时时间为 10 秒。" #: ../../source/File_Transfer/File_Transfer.rst:89 -#: fb269796ce6d45cbb73b0201dce1cec9 +#: d68741e000fe48d3857ec0b0363d4182 msgid "Send the filename length as a 4-byte unsigned integer (big-endian)." msgstr "以 4 字节无符号整数(大端)形式发送文件名长度。" #: ../../source/File_Transfer/File_Transfer.rst:91 -#: c48725bc3ac54f16bef68243c780831d +#: 95260b76f4524ddb8700ca05352f294d msgid "Send the filename encoded in UTF-8." msgstr "发送以 UTF-8 编码的文件名。" #: ../../source/File_Transfer/File_Transfer.rst:92 -#: 951751cbb7ab400dbfd8ac2e574d2bf0 +#: 7efa294dbe7e4921974628e8fb08cc00 msgid "Send the file size as an 8-byte unsigned integer (big-endian)." msgstr "以 8 字节无符号整数(大端)形式发送文件大小。" #: ../../source/File_Transfer/File_Transfer.rst:94 -#: db806fd98e8b48dabcd3fa755f1d6567 +#: 065d4ab3bf384d81a22df89aeba09349 #, fuzzy -msgid "Send the file content in 65536-byte chunks until EOF." +msgid "" +"Send the file content in ``file_transfer_chunk_len``-byte chunks (65536 " +"by default) until EOF." msgstr "以 64 KiB 块的形式发送文件内容,直到 EOF。" -#: ../../source/File_Transfer/File_Transfer.rst:95 -#: 265efb19bd5c46569983bb4156bc195c +#: ../../source/File_Transfer/File_Transfer.rst:96 +#: aeec7f8ff0ab424cbc5b7c1a32ff9433 msgid "" "Wait for the completion acknowledgement " "(``server_received_file_data_sign``) with a dynamic timeout (base 30 " @@ -190,63 +193,63 @@ msgstr "" "等待动态超时(基本 30 秒加上每 100 MiB 10 秒)的完成确认 " "(``s​​erver_reeived_file_data_sign``)。" -#: ../../source/File_Transfer/File_Transfer.rst:100 -#: b2944c94e7a9468daf924f021a5f0bab +#: ../../source/File_Transfer/File_Transfer.rst:101 +#: b80094b922a24c409f10eb9c8b05373b msgid "The receiver performs the complementary steps:" msgstr "接收器执行补充步骤:" -#: ../../source/File_Transfer/File_Transfer.rst:102 -#: 1353e95158fc496db86676f544168584 +#: ../../source/File_Transfer/File_Transfer.rst:103 +#: 5f71fc707ffe4b06a275b3db9f77178d msgid "Send the start signal." msgstr "发送启动信号。" -#: ../../source/File_Transfer/File_Transfer.rst:103 -#: e32e19b7ac2e4a20a76a7c5640212835 +#: ../../source/File_Transfer/File_Transfer.rst:104 +#: 7132d6fe15ce42a3bef64e0073e9baff msgid "Read the 4-byte length, then the filename, then the 8-byte size." msgstr "读取 4 字节长度,然后读取文件名,然后读取 8 字节大小。" -#: ../../source/File_Transfer/File_Transfer.rst:105 -#: 1bbea38ba8ec4f84970f408827ba1be4 +#: ../../source/File_Transfer/File_Transfer.rst:106 +#: 7e0fcaec6d704455b94fc9f7defbef55 msgid "Acknowledge the header with ``server_received_file_header_sign``." msgstr "使用“server_reeived_file_header_sign”确认标头。" -#: ../../source/File_Transfer/File_Transfer.rst:107 -#: ef7144f2c0c94c9fa25c2a5bad6ed5e8 +#: ../../source/File_Transfer/File_Transfer.rst:108 +#: d6a854d18d404082bdec0e2cf355ea62 msgid "Receive the file data in chunks and write to disk." msgstr "以块的形式接收文件数据并写入磁盘。" -#: ../../source/File_Transfer/File_Transfer.rst:108 -#: bb81c955e5024b6d9b6042fa3eb4c13f +#: ../../source/File_Transfer/File_Transfer.rst:109 +#: 69981b7e399e4de89858906b286aaf06 msgid "Acknowledge completion with ``server_received_file_data_sign``." msgstr "使用“server_reeived_file_data_sign”确认完成。" -#: ../../source/File_Transfer/File_Transfer.rst:111 -#: cd24d3a3f8704419889c764cf5812a99 +#: ../../source/File_Transfer/File_Transfer.rst:112 +#: b98957309caf49eba2657154bffbaf90 msgid "" "Any error during the exchange causes the failing side to send " "``error_sign``, and both sides close the transfer socket. The main " "control connection remains unaffected." msgstr "交换期间的任何错误都会导致失败的一方发送“error_sign”,并且双方都会关闭传输套接字。主控制连接不受影响。" -#: ../../source/File_Transfer/File_Transfer.rst:120 -#: 0313763b7bc6427cb80da39d09a94be1 +#: ../../source/File_Transfer/File_Transfer.rst:121 +#: f289e3c6e5b445f48eda6ed3434c9de8 msgid "Client-Initiated Transfer (Client → Server)" msgstr "客户端发起的传输(客户端 → 服务器)" -#: ../../source/File_Transfer/File_Transfer.rst:122 -#: 155d9f3383cf42fe8fa0e4fe095fbae7 +#: ../../source/File_Transfer/File_Transfer.rst:123 +#: 17e1ddd91efe4690ad00f85f54875eda msgid "" "When the user types a file-related command in the client's interactive " "console, the call chain proceeds as follows." msgstr "当用户在客户端的交互式控制台中键入与文件相关的命令时,调用链将按如下方式进行。" -#: ../../source/File_Transfer/File_Transfer.rst:126 -#: ab7df52a36c742a0be4924b613ddebd4 +#: ../../source/File_Transfer/File_Transfer.rst:127 +#: 9cacd6ea79a14ff6ae602d7ed47926c8 msgid "### Console Input Handling" msgstr "### 控制台输入处理" -#: ../../source/File_Transfer/File_Transfer.rst:128 -#: 42cde8d25ccd4424b5c871c7adf3af91 +#: ../../source/File_Transfer/File_Transfer.rst:129 +#: 07a7b69b45d04950877f071f25ad7c2c #, fuzzy msgid "" "In ``TCP_Client_Base.interactive_mode()``, user input is read line by " @@ -256,19 +259,19 @@ msgid "" "below." msgstr "在“TCP_Client_Base.interactive_mode()”中,用户输入被逐行读取。可以识别以“/file”、“/multiple_file”、“/file_folder”或“/multiple_file_folder”开头的命令。对于每个这样的命令,客户端调用相应的线程安全入口点(以“_thread”结尾的方法)。" -#: ../../source/File_Transfer/File_Transfer.rst:136 -#: 08d0c910eba54d3cb8447d3cea15064f +#: ../../source/File_Transfer/File_Transfer.rst:137 +#: 250bb94df2a14d339b150a70e8fed215 #, fuzzy msgid "### Entry Points" msgstr "### 线程安全入口点" -#: ../../source/File_Transfer/File_Transfer.rst:138 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:139 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "The console dispatches to these methods:" msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:140 -#: 3ddbfd1b9e454342aa47f388d5bc7263 +#: ../../source/File_Transfer/File_Transfer.rst:141 +#: a0f0599853724ff9a15c501c154f52ea #, fuzzy msgid "" "``file_transfer_client_recv_client_start_thread(message, " @@ -278,23 +281,23 @@ msgstr "" "``file_transfer_client_recv_client_start_thread(消息,file_folder_abspath " "=无)``" -#: ../../source/File_Transfer/File_Transfer.rst:143 -#: 4db440e1419b4ce895c7e03b85b070c1 +#: ../../source/File_Transfer/File_Transfer.rst:144 +#: 9d60213404014fbe8bee542f67d80398 msgid "``folder_file_transfer_client_recv_client_start(message)``" msgstr "``folder_file_transfer_client_recv_client_start(消息)``" -#: ../../source/File_Transfer/File_Transfer.rst:144 -#: 936c7a26041045da8e4e20ec45d3959d +#: ../../source/File_Transfer/File_Transfer.rst:145 +#: 2e6c7b2b820349ebac90f27d835477d0 msgid "``multiple_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_file_transfer_client_recv_client_start(消息)``" -#: ../../source/File_Transfer/File_Transfer.rst:145 -#: 972ecc6300354468b126961a483ecf2c +#: ../../source/File_Transfer/File_Transfer.rst:146 +#: bdee0e9084194b45b5fad3a44e9aaf85 msgid "``multiple_folder_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_folder_file_transfer_client_recv_client_start(消息)``" -#: ../../source/File_Transfer/File_Transfer.rst:147 -#: fef1e1b2a2024f89abd300268004380d +#: ../../source/File_Transfer/File_Transfer.rst:148 +#: ae9108b44e304198a7d0bff6bae8ab60 msgid "" "The last three run synchronously on the console thread; they walk the " "tree or the file list and spawn one worker thread per file themselves, so" @@ -303,13 +306,13 @@ msgid "" "``max_thread_num`` of them run at once." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:153 -#: f5919b72c7ec40e2a1b1d49cf57c9021 +#: ../../source/File_Transfer/File_Transfer.rst:154 +#: 8e945e4bdc124e749ee0a5976249a787 msgid "### Worker Function (Client Side)" msgstr "### 工作函数(客户端)" -#: ../../source/File_Transfer/File_Transfer.rst:155 -#: 70bed6a3ccbd47e89653ab1b2d62fb9d +#: ../../source/File_Transfer/File_Transfer.rst:156 +#: cc8b9fc35bfb4cf395a2114786c01718 msgid "" "The core worker function for a single file is " "``file_transfer_client_recv_client_start(message, " @@ -318,13 +321,13 @@ msgstr "" "单个文件的核心工作函数是“file_transfer_client_recv_client_start(message, " "file_folder_abspath=None)”。其逻辑如下:" -#: ../../source/File_Transfer/File_Transfer.rst:160 -#: f7103ca89460442ba018095bf48ae23c +#: ../../source/File_Transfer/File_Transfer.rst:161 +#: e3d81c4f4e724d81b426fdbfedb9c062 msgid "Allocate a unique client ID using the lock ``file_client_id_lock``." msgstr "使用锁“file_client_id_lock”分配唯一的客户端 ID。" -#: ../../source/File_Transfer/File_Transfer.rst:162 -#: ea5fe1051d864a3caccc15bf2373b03e +#: ../../source/File_Transfer/File_Transfer.rst:163 +#: 81b9ac67e27341c0a17468f3b6787d14 msgid "" "Extend the original command string with the client ID (e.g., ``/file " "mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server " @@ -333,15 +336,15 @@ msgstr "" "使用客户端 ID 扩展原始命令字符串(例如,``/file mydoc.txt`` 变为``/file mydoc.txt " "42``),并使用``send_message()`` 通过主控制连接将其发送到服务器。" -#: ../../source/File_Transfer/File_Transfer.rst:168 -#: b56d7f67a1844b0cb893a3939ed8ed70 +#: ../../source/File_Transfer/File_Transfer.rst:169 +#: af07c5ef546a4102bbb836b65b2fd3be msgid "" "Obtain a local port for the outgoing file transfer socket by calling " "``palloc()``." msgstr "通过调用“palloc()”获取传出文件传输套接字的本地端口。" -#: ../../source/File_Transfer/File_Transfer.rst:171 -#: 83314b464667496cb415f119beb0dc31 +#: ../../source/File_Transfer/File_Transfer.rst:172 +#: 37226a4f2e1e4a878ba325fca05df9bf msgid "" "Wait (up to 20 seconds) for the server to reply with a port number. The " "server's reply (``/server_file_transfer_port ``) is " @@ -351,8 +354,8 @@ msgstr "" "等待(最多 20 秒)服务器回复端口号。服务器的回复(``/server_file_transfer_port " "``)由主连接接收并存储在``file_server_port_list``中。当找到匹配的条目时,将提取端口。" -#: ../../source/File_Transfer/File_Transfer.rst:179 -#: bd938c291cbe44aa913d35413fc76a6b +#: ../../source/File_Transfer/File_Transfer.rst:180 +#: e9cd68239fe3498597f07ccfa774ae22 msgid "" "Call the low-level send function ``file_transfer_mode(filename, " "server_host, server_port, client_port)``." @@ -360,8 +363,8 @@ msgstr "" "调用低级发送函数“file_transfer_mode(filename, server_host, server_port, " "client_port)”。" -#: ../../source/File_Transfer/File_Transfer.rst:183 -#: 75779fa321754e05adc2ee87ac490f07 +#: ../../source/File_Transfer/File_Transfer.rst:184 +#: 145c524c53654e84a0bb45d3a065733e #, fuzzy msgid "" "For folder transfers, the worker function " @@ -378,8 +381,8 @@ msgstr "" " ”命令以在服务器上创建相应的目录。对于每个文件,它使用“/file_folder " "”形式的命令调用“file_transfer_client_recv_client_start_thread”。信号量(``file_semaphore``)将并发文件传输的数量限制为``max_thread_num``。" -#: ../../source/File_Transfer/File_Transfer.rst:198 -#: bbb76713d93e4920a87d1551cbdf9999 +#: ../../source/File_Transfer/File_Transfer.rst:199 +#: 5a7d502137c8442eafae448cee95a72a msgid "" "``multiple_file_transfer_client_recv_client_start`` loops over the given " "files and starts one worker thread per file, each holding " @@ -387,32 +390,32 @@ msgid "" "are capped by ``max_thread_num`` on that path too." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:203 -#: d9634b910f4f4509a717a6e7cb8445e2 +#: ../../source/File_Transfer/File_Transfer.rst:204 +#: 4ae4777e086a48558cbe3dda0ecdb3fb msgid "### Server-Side Handler (Receiving)" msgstr "### 服务器端处理程序(接收)" -#: ../../source/File_Transfer/File_Transfer.rst:205 -#: ecf51220b2924da78e59cd7118a5d976 +#: ../../source/File_Transfer/File_Transfer.rst:206 +#: 66a812ac1ac84ad2b912deb843f3c059 msgid "" "When the server receives an extended command like ``/file mydoc.txt 42`` " "on the main control connection, ``handle_command`` detects it and calls:" msgstr "当服务器在主控制连接上收到诸如“/file mydoc.txt 42”之类的扩展命令时,“handle_command”会检测到它并调用:" -#: ../../source/File_Transfer/File_Transfer.rst:210 -#: 7437faffb1f7433faaea35c296c7ab96 +#: ../../source/File_Transfer/File_Transfer.rst:211 +#: 081e020d3e674d01bfde15c0922aa25c msgid "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " command)``" msgstr "``file_transfer_server_recv_server_start_thread(client_id,client_socket,命令)``" -#: ../../source/File_Transfer/File_Transfer.rst:213 -#: 1ff4d8b0423b490db4a9b179d745dcb7 +#: ../../source/File_Transfer/File_Transfer.rst:214 +#: 4b5b5057002a457db83aed00c6148a7f msgid "The server then:" msgstr "服务器然后:" -#: ../../source/File_Transfer/File_Transfer.rst:215 -#: 988de890b2fc4ebfbe68944b368ce5b8 +#: ../../source/File_Transfer/File_Transfer.rst:216 +#: e2ad0e97b7854be4a3dded6cf7d602b7 msgid "" "Creates a new thread via " "``file_transfer_server_recv_server_start(client_id, client_socket, " @@ -421,20 +424,20 @@ msgstr "" "通过 file_transfer_server_recv_server_start(client_id, client_socket, " "command, new_save_path=None, file_name=None) 创建一个新线程。" -#: ../../source/File_Transfer/File_Transfer.rst:219 -#: 47e1493ecf784674924778f581e6a71a +#: ../../source/File_Transfer/File_Transfer.rst:220 +#: ee8cdc9ae93c4579a05e37b32c86f705 msgid "Allocates a transfer port with ``palloc()``." msgstr "使用 palloc() 分配传输端口。" -#: ../../source/File_Transfer/File_Transfer.rst:220 -#: b19bd45b30ee42178dab7b9aafa79e5e +#: ../../source/File_Transfer/File_Transfer.rst:221 +#: ac8a87e1e481417284d90ba8cb843415 msgid "" "Calls ``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``." msgstr "调用“file_transfer_mode_recv(主机、端口、client_socket、client_id、new_save_path、file_name、command)”。" -#: ../../source/File_Transfer/File_Transfer.rst:223 -#: a2f55cc995c14ec1ac34545e458dccb2 +#: ../../source/File_Transfer/File_Transfer.rst:224 +#: 2f6675b7698c41938542b09cbfb482e8 msgid "" "This low-level receive function sets up a listening socket on the " "allocated port, sends the port number back to the client (as " @@ -446,20 +449,20 @@ msgstr "" "这个低级接收函数在分配的端口上设置一个监听套接字,将端口号发送回客户端(如“/server_file_transfer_port " "”),接受客户端的连接,并执行文件传输协议中描述的协议步骤。接收到的文件保存在“received_files/”下(如果请求文件夹传输,则保存在子目录下)。" -#: ../../source/File_Transfer/File_Transfer.rst:233 -#: da7e5a1f96b3422bbfd8f056eb28dae3 +#: ../../source/File_Transfer/File_Transfer.rst:234 +#: 9fe861572b8746aeaa8266d8d30f963f msgid "" "After the transfer completes (or fails), the port is released with " "``pfree()``." msgstr "传输完成(或失败)后,使用“pfree()”释放端口。" -#: ../../source/File_Transfer/File_Transfer.rst:240 -#: e9956de8dffe4d898caed46c0e78c93b +#: ../../source/File_Transfer/File_Transfer.rst:241 +#: 3e4e81fa8cea4ef5ab2a39602eb29355 msgid "Server-Initiated Transfer (Server → Client)" msgstr "服务器发起的传输(服务器 → 客户端)" -#: ../../source/File_Transfer/File_Transfer.rst:242 -#: 5e8dbd4b351d467cb809c3182feac0a2 +#: ../../source/File_Transfer/File_Transfer.rst:243 +#: 3ab21d4beefb41be83651eec10fd3899 msgid "" "When the server administrator types a command in the server console, for " "example ``/file /path/to/file.txt (127.0.0.1,54321)``, the console input " @@ -469,13 +472,13 @@ msgstr "" "当服务器管理员在服务器控制台中键入命令时,例如“/file /path/to/file.txt " "(127.0.0.1,54321)”,控制台输入线程(“console_input”)会解析该命令并调用相应的服务器端文件传输 API。" -#: ../../source/File_Transfer/File_Transfer.rst:250 -#: 3bec81e76a2c4bf3b37386e180cc4fc1 +#: ../../source/File_Transfer/File_Transfer.rst:251 +#: fa019410dca84c04b24bf9334131aa8d msgid "The recommended entry points for server-to-client transfers are:" msgstr "服务器到客户端传输的推荐入口点是:" -#: ../../source/File_Transfer/File_Transfer.rst:253 -#: 585d149b4b3f47f09176b4b61d3baeaa +#: ../../source/File_Transfer/File_Transfer.rst:254 +#: 99103b4e1f234e2dac2ffc955ab5b23e msgid "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` for a single file." @@ -483,13 +486,13 @@ msgstr "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` 对于单个文件。" -#: ../../source/File_Transfer/File_Transfer.rst:256 -#: 81935504645c451b844d109037b46ae0 +#: ../../source/File_Transfer/File_Transfer.rst:257 +#: a1560a9b45c043618778f38beb1c3cb2 msgid "``folder_file_transfer_server_recv_client_start(message)`` for a folder." msgstr "文件夹的``folder_file_transfer_server_recv_client_start(message)``。" -#: ../../source/File_Transfer/File_Transfer.rst:258 -#: 4ca3cac907c04414925f5219b700d0e5 +#: ../../source/File_Transfer/File_Transfer.rst:259 +#: c18cb827a52f48d6b2883b708e2c871e msgid "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " for multiple files to multiple clients." @@ -497,8 +500,8 @@ msgstr "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " 用于将多个文件传输到多个客户端。" -#: ../../source/File_Transfer/File_Transfer.rst:260 -#: 536f30cc03f84b218a5ca9b84deb9f88 +#: ../../source/File_Transfer/File_Transfer.rst:261 +#: 1b9fd8eea75e46899f68c6ca1312e896 msgid "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " for different file lists to different clients." @@ -506,8 +509,8 @@ msgstr "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " 用于不同客户端的不同文件列表。" -#: ../../source/File_Transfer/File_Transfer.rst:263 -#: 92500d9fd7124d9ca7b648f03df90141 +#: ../../source/File_Transfer/File_Transfer.rst:264 +#: d34ac75777c74fe4bc63e1a100fd2aa3 msgid "" "The worker function ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` performs the following steps:" @@ -515,36 +518,36 @@ msgstr "" "辅助函数 file_transfer_server_recv_client_start(message, " "file_folder_abspath=None) 执行以下步骤:" -#: ../../source/File_Transfer/File_Transfer.rst:268 -#: 583e8c89824f46ae839d233ab9e70e1a +#: ../../source/File_Transfer/File_Transfer.rst:269 +#: 29d03e172fd346e2a7928b55510df4f1 msgid "" "Extract the target client address from the last part of the command " "(e.g., ``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the " "client's socket from ``self.clients``." msgstr "使用“ast.literal_eval()”从命令的最后部分提取目标客户端地址(例如“(127.0.0.1,54321)”)。从“self.clients”获取客户端的套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:273 -#: fd63ce90d3794b2181cdaa927e1a7a38 +#: ../../source/File_Transfer/File_Transfer.rst:274 +#: 7a8d8ed423524d6e91a311a3aa3d5a9a msgid "" "Allocate a unique client ID and extend the command with it, then send the" " extended command to the client over the main connection." msgstr "分配唯一的客户端 ID 并用它扩展命令,然后通过主连接将扩展命令发送到客户端。" -#: ../../source/File_Transfer/File_Transfer.rst:277 -#: 6138738f134b48b2a98d05d3569172c7 +#: ../../source/File_Transfer/File_Transfer.rst:278 +#: 94b6c1f8a6a240e4ba4be8cf20f87c7f msgid "Allocate a local port with ``palloc()``." msgstr "使用 palloc() 分配本地端口。" -#: ../../source/File_Transfer/File_Transfer.rst:278 -#: 26fa94f94e1841f6845765f4fd65949d +#: ../../source/File_Transfer/File_Transfer.rst:279 +#: 723a05b6c3974b65a539af723f1e0872 msgid "" "Wait for the client to reply with its own port number (via " "``/server_file_transfer_port``), which is stored in " "``file_server_port_list`` by the main connection's message handler." msgstr "等待客户端回复其自己的端口号(通过“/server_file_transfer_port”),该端口号由主连接的消息处理程序存储在“file_server_port_list”中。" -#: ../../source/File_Transfer/File_Transfer.rst:283 -#: 4bd913210d8945ffb7312070e070f252 +#: ../../source/File_Transfer/File_Transfer.rst:284 +#: 878572ca3d2948a9acbb6741f00ddd62 msgid "" "Call ``file_transfer_mode(filename, client_host, client_port, " "local_port)`` to send the file." @@ -552,8 +555,8 @@ msgstr "" "调用“file_transfer_mode(filename, client_host, client_port, " "local_port)”发送文件。" -#: ../../source/File_Transfer/File_Transfer.rst:287 -#: 39d0bdae658241a0a8205977cccd0395 +#: ../../source/File_Transfer/File_Transfer.rst:288 +#: ca517571b2d34c0497fcf5d5b12c93a1 msgid "" "On the client side, when it receives a command like ``/file " "/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls" @@ -568,38 +571,38 @@ msgstr "" " client_socket, " "command)”。这将启动一个接收器线程,类似于用于客户端启动的传输的服务器接收器:它分配一个端口,用“/server_file_transfer_port”回复,并调用“file_transfer_mode_recv”来接收和保存文件。" -#: ../../source/File_Transfer/File_Transfer.rst:303 -#: 014166967bb14b20a2782598b535575a +#: ../../source/File_Transfer/File_Transfer.rst:304 +#: cb7bdf5091e54e039de9d5578c273b93 msgid "Folder Transfer Mechanism (Detailed)" msgstr "文件夹传输机制(详细)" -#: ../../source/File_Transfer/File_Transfer.rst:305 -#: 38eff5e62e844c0e94d587ba7132d26c +#: ../../source/File_Transfer/File_Transfer.rst:306 +#: b282df0b45bd4bb087ae10816fd3f06d msgid "" "Transferring a folder is implemented as a **recursive walk** that sends " "separate commands for subdirectories and files. The logic is symmetric on" " both client and server." msgstr "传输文件夹是通过“递归遍历”来实现的,它为子目录和文件发送单独的命令。客户端和服务器上的逻辑是对称的。" -#: ../../source/File_Transfer/File_Transfer.rst:311 -#: 7319cca2fbef48679002d3bf0469d842 +#: ../../source/File_Transfer/File_Transfer.rst:312 +#: fb34b1f5d8a4488b9aef8b71dcb764ec msgid "### Creating Directories" msgstr "### 创建目录" -#: ../../source/File_Transfer/File_Transfer.rst:313 -#: ad592f4510c34ecca1cba340caa2710e +#: ../../source/File_Transfer/File_Transfer.rst:314 +#: 6b67f2390d914745a253523cef9a2e0b msgid "" "For a directory that needs to be created on the receiver side, the sender" " sends a command of the form:" msgstr "对于需要在接收方创建的目录,发送方发送以下形式的命令:" -#: ../../source/File_Transfer/File_Transfer.rst:317 -#: 114e36ce42e940cc8f0ec8c64c1db031 +#: ../../source/File_Transfer/File_Transfer.rst:318 +#: 7aaf85bf38fa4621a760dc56b6f99ad6 msgid "``/file_folder ``" msgstr "``/file_folder <相对路径>``" -#: ../../source/File_Transfer/File_Transfer.rst:319 -#: a120552b93294a059a34132ab935068a +#: ../../source/File_Transfer/File_Transfer.rst:320 +#: 046f125a1f6e41e4808a9cd703e34ee4 msgid "" "The receiver's handler for this command (in either " "``file_folder_transfer_server_recv_server_start_thread`` or " @@ -609,23 +612,23 @@ msgid "" "The relative path uses forward slashes to be platform-independent." msgstr "该命令的接收器处理程序(在“file_folder_transfer_server_recv_server_start_thread”或“file_folder_transfer_client_recv_server_start_thread”中)在基本接收目录下创建相应的目录(对于服务器来说是“received_files/”,对于客户端来说是相同的目录)。相对路径使用正斜杠与平台无关。" -#: ../../source/File_Transfer/File_Transfer.rst:330 -#: 2743fec0a2434e2b96ea3c49fecf268c +#: ../../source/File_Transfer/File_Transfer.rst:331 +#: 3fb5d6322ccd47f79e601e38684fe234 msgid "### Sending Files Inside a Folder" msgstr "### 发送文件夹内的文件" -#: ../../source/File_Transfer/File_Transfer.rst:332 -#: fb31b657a05547109dea51165844a632 +#: ../../source/File_Transfer/File_Transfer.rst:333 +#: c9f77546ed49407fa57c57f0b0a76acf msgid "For each file, the sender sends a command of the form:" msgstr "对于每个文件,发送者发送以下形式的命令:" -#: ../../source/File_Transfer/File_Transfer.rst:334 -#: 2da676ce8dd649169ba224f6d29cbbc9 +#: ../../source/File_Transfer/File_Transfer.rst:335 +#: f5a164466b0d4d4382b7d880bd320e3d msgid "``/file_folder ``" msgstr "``/file_folder <相对路径> <文件名>``" -#: ../../source/File_Transfer/File_Transfer.rst:336 -#: 8972f356722148e3b34cbaa95390d700 +#: ../../source/File_Transfer/File_Transfer.rst:337 +#: c507cca92d1c463ea9f4d429a38a9b6a msgid "" "The receiver treats this as a file transfer request. The second argument " "(``file_name``) is used as the final filename, and the relative path " @@ -635,13 +638,13 @@ msgid "" "``file_transfer_server_recv_client_start``, depending on direction)." msgstr "接收方将此视为文件传输请求。第二个参数(``file_name``)用作最终文件名,相对路径确定基本接收目录下的子目录。实际文件数据使用相同的单文件协议传输(通过“file_transfer_client_recv_client_start”或“file_transfer_server_recv_client_start”,具体取决于方向)。" -#: ../../source/File_Transfer/File_Transfer.rst:347 -#: a0ded05fd7f2406abb0ee41fcc33b53b +#: ../../source/File_Transfer/File_Transfer.rst:348 +#: e1e2b8dd57524ecfabd47c2c8386dfea msgid "### Concurrency Control for Folders" msgstr "### 文件夹的并发控制" -#: ../../source/File_Transfer/File_Transfer.rst:349 -#: 14b0ec4d109c448198db41c196df8a70 +#: ../../source/File_Transfer/File_Transfer.rst:350 +#: 32b26f72bba4482490f38968dcee5837 msgid "" "Because a folder can contain many files, the sender uses a semaphore " "(``file_semaphore``) to limit the number of concurrently active file " @@ -651,13 +654,13 @@ msgid "" "the server." msgstr "由于一个文件夹可以包含许多文件,因此发送方使用信号量(“file_semaphore”)来限制并发活动文件传输的数量。在开始每个文件传输之前获取信号量并在“finally”块中释放。最大并发数由客户端上的“max_thread_num”和服务器上的“max_file_transfer_thread_num”设置。" -#: ../../source/File_Transfer/File_Transfer.rst:362 -#: 2c7d84b855df4587bfb110f525299e39 +#: ../../source/File_Transfer/File_Transfer.rst:363 +#: 8ce424a7f1de4933b3113a0e3ab98155 msgid "Custom Destination Directory" msgstr "自定义目标目录" -#: ../../source/File_Transfer/File_Transfer.rst:364 -#: b972e019f10143a99af9de9b7a8e371a +#: ../../source/File_Transfer/File_Transfer.rst:365 +#: 6ca8ee9f021842939f446e999c067dfb msgid "" "Every transfer family accepts an optional trailing " "``destination_file_path`` argument that replaces the receiver's default " @@ -666,8 +669,8 @@ msgid "" "default location exactly as before." msgstr "每个传输系列都接受一个可选的尾随“destination_file_path”参数,该参数替换接收者的默认保存目录(“received_files/”或配置的“file_transfer_dir”)。当省略它时,传输将像以前一样转到默认位置。" -#: ../../source/File_Transfer/File_Transfer.rst:372 -#: 1e801c2a599e4595b5f883ada1a63fc6 +#: ../../source/File_Transfer/File_Transfer.rst:373 +#: 6291da89ffa542dfbd94f599a9321216 msgid "" "The destination is **always the last argument** of the command and names " "a *directory* on the receiving machine: the received file keeps its own " @@ -677,59 +680,59 @@ msgid "" "default save directory. Missing directories are created." msgstr "目标**始终是命令的最后一个参数**,并在接收计算机上命名一个*目录*:接收到的文件保留其自己的名称(``/``),传输的文件夹在目标下保留其结构(``//...``)。绝对路径按原样使用;相对路径在默认保存目录下解析。创建丢失的目录。" -#: ../../source/File_Transfer/File_Transfer.rst:384 -#: 6b85151737b64a3e90154ba763b205d2 +#: ../../source/File_Transfer/File_Transfer.rst:385 +#: 76243e0349c1474bbdf14e1ef2a8e52b msgid "Command syntax:" msgstr "命令语法:" -#: ../../source/File_Transfer/File_Transfer.rst:386 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:387 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "Client console (the receiver is the server):" msgstr "客户端控制台(接收者是服务器):" -#: ../../source/File_Transfer/File_Transfer.rst:388 -#: bac62d5b11c84f96b2b3841af7fc7a85 +#: ../../source/File_Transfer/File_Transfer.rst:389 +#: c9fa612895bc4f92839d2de77b6cbc7f msgid "``/file [destination_file_path]``" msgstr "``/file <文件路径> [目标文件路径]``" -#: ../../source/File_Transfer/File_Transfer.rst:390 -#: aa07623d0b4048be944b30c6fc07cc1b +#: ../../source/File_Transfer/File_Transfer.rst:391 +#: 2d34a030a1804d299a0b56c14984b1b5 msgid "``/multiple_file ... [destination_file_path]``" msgstr "``/multiple_file <文件1> <文件2> ... [目标文件路径]``" -#: ../../source/File_Transfer/File_Transfer.rst:392 -#: 1a9cfb266bb24df6ac2ddeb286a212d0 +#: ../../source/File_Transfer/File_Transfer.rst:393 +#: a7dd1e241a4346d4b873072c5948f187 #, fuzzy msgid "``/file_folder [destination_file_path]``" msgstr "``/file_folder <相对路径>``" -#: ../../source/File_Transfer/File_Transfer.rst:394 -#: 46f89a56ef594dec945f21425306e2de +#: ../../source/File_Transfer/File_Transfer.rst:395 +#: 953993d920eb4959987d98423440ce61 msgid "``/multiple_file_folder ... [destination_file_path]``" msgstr "``/multiple_file_folder <文件夹1> <文件夹2> ... [目标文件路径]``" -#: ../../source/File_Transfer/File_Transfer.rst:396 -#: 085ba670e149450a8b385d68c8f9d366 +#: ../../source/File_Transfer/File_Transfer.rst:397 +#: 886c8b7d760044cabe48ce044412ca64 #, fuzzy msgid "" "Server console (the receiver is the target client, given as a quoted " "``(ip, port)`` address tuple, not as a client id):" msgstr "服务器控制台(接收者是目标客户端,以带引号的地址元组形式给出):" -#: ../../source/File_Transfer/File_Transfer.rst:400 -#: abc0fb96992e4b09aaa9714ba73a094b +#: ../../source/File_Transfer/File_Transfer.rst:401 +#: 48d3bf6084224062867313a9597044d7 #, fuzzy msgid "``/file <(ip, port)> [destination_file_path]``" msgstr "``/file <文件路径> [目标文件路径]``" -#: ../../source/File_Transfer/File_Transfer.rst:402 -#: d9329c72161247bf8d5f0a609178c488 +#: ../../source/File_Transfer/File_Transfer.rst:403 +#: 684fa9b22136418b94cbb4202f702cd2 #, fuzzy msgid "``/file_folder <(ip, port)> [destination_file_path]``" msgstr "``/file_folder <相对路径>``" -#: ../../source/File_Transfer/File_Transfer.rst:404 -#: af78c6ec2f3e4072aaac19d2d131cf5d +#: ../../source/File_Transfer/File_Transfer.rst:405 +#: 9380dc31685947e3a835107f435deed2 #, fuzzy msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -738,16 +741,16 @@ msgstr "" "``/multiple_file_multiple_client <文件1> <文件2> ... <客户端ID1> <客户端ID2> ... " "[目标文件路径]``" -#: ../../source/File_Transfer/File_Transfer.rst:406 -#: 2fdbf92caa6a46df9dae793592be802d +#: ../../source/File_Transfer/File_Transfer.rst:407 +#: 62488b8bb4e149be86c1d655bd80b6a8 #, fuzzy msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, port)1> ... " "[destination_file_path]``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:408 -#: abc1dac22b594c54a22b03d59e1a8338 +#: ../../source/File_Transfer/File_Transfer.rst:409 +#: d6a0c51014c9403fb82ebdf5c93928bc msgid "" "For the multiple-item commands the destination is the last argument; when" " the last argument is not a ``(ip, port)`` tuple it is treated as the " @@ -757,13 +760,13 @@ msgid "" "destination)." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:418 -#: 0c7fa56659f543ed93adacd874dd2e8b +#: ../../source/File_Transfer/File_Transfer.rst:419 +#: 373c2a5a23334df7a25d23f8d94abd66 msgid "Native In-Memory Forwarding" msgstr "本机内存转发" -#: ../../source/File_Transfer/File_Transfer.rst:420 -#: 133205c62a0846318b30f5f5fe0dc296 +#: ../../source/File_Transfer/File_Transfer.rst:421 +#: dd57639b3e0e4068bd9533fc039597cd #, fuzzy msgid "" "The main protocol also provides a native, client-side forwarding feature " @@ -777,30 +780,30 @@ msgstr "" "主协议还提供了一种本机客户端转发功能,可通过服务器将数据从一个客户端中继到多个其他客户端**,而无需在服务器上进行任何磁盘 " "I/O**。与前向扩展(上传到磁盘然后从磁盘下载)不同,服务器仅将数据保存在内存中并将其直接流式传输到目标客户端。这避免了双倍传输时间和磁盘读/写开销。" -#: ../../source/File_Transfer/File_Transfer.rst:432 -#: b177ec0385be4e9da692646b88cd3ed8 +#: ../../source/File_Transfer/File_Transfer.rst:433 +#: 982c4c9538914821a07887fb8ab9b95d #, fuzzy msgid "Commands (client console only; rejected on the server console):" msgstr "客户端控制台(接收者是服务器):" -#: ../../source/File_Transfer/File_Transfer.rst:435 -#: 789bd7878891443fa43ec5111b3a028b +#: ../../source/File_Transfer/File_Transfer.rst:436 +#: 14406316555743359a854540ab6937c8 #, fuzzy msgid "" "``/forward_file ... ... " "[destination_file_path]``" msgstr "``/forward_file <文件1> <文件2> ... <地址1> <地址2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:436 -#: 04d9ece635c94b8c9257e0cb41bd5b81 +#: ../../source/File_Transfer/File_Transfer.rst:437 +#: 4dc576898177404da124649f7ce9ac28 #, fuzzy msgid "" "``/forward_folder ... ... " "[destination_file_path]``" msgstr "``/forward_folder <文件夹1> <文件夹2> ... <地址1> <地址2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:438 -#: 2f7b628a4e0246e385e9e8817b8d7a87 +#: ../../source/File_Transfer/File_Transfer.rst:439 +#: 220dfbf0a0d84559a8befb4eee500ba0 msgid "" "The number of files/folders and the number of target clients (written as " "quoted address tuples) is unlimited. Target addresses that are " @@ -808,8 +811,8 @@ msgid "" "are skipped and the remaining targets are still served." msgstr "文件/文件夹的数量和目标客户端的数量(写为带引号的地址元组)是无限的。无法到达(未连接到服务器)或等于服务器本身的目标地址将被跳过,而其余目标仍将得到服务。" -#: ../../source/File_Transfer/File_Transfer.rst:446 -#: 84f3e0acf89e4767bbb572cc6edc81aa +#: ../../source/File_Transfer/File_Transfer.rst:447 +#: 6137bf9406784c6f82d9f41560a52566 msgid "" "Like every transfer family, both commands accept an optional trailing " "``destination_file_path`` that replaces the default save directory on " @@ -823,22 +826,22 @@ msgstr "" ",转发文件夹将其结构保留在``//... ``下。当参数被省略时,目标写入其默认`` " "file_transfer_dir ``。" -#: ../../source/File_Transfer/File_Transfer.rst:457 -#: 6b31e93335824fe1bfdb83b84f42f08c +#: ../../source/File_Transfer/File_Transfer.rst:458 +#: f6697695e9ef4e3694fa9046e41578e0 msgid "The data path reuses the protocol's own transfer machinery:" msgstr "数据路径重用协议自己的传输机制:" -#: ../../source/File_Transfer/File_Transfer.rst:460 -#: 469812eff1874189a000989c9260cf1b +#: ../../source/File_Transfer/File_Transfer.rst:461 +#: 6ee037f0e4024d2988fcb2ccf3deef70 #, fuzzy msgid "" "The forwarding client streams the file with the standard file-transfer " -"byte stream (metadata header + 65536-byte chunks) to a transfer socket on" -" the server." +"byte stream (metadata header + ``file_transfer_chunk_len``-byte chunks, " +"default 65536) to a transfer socket on the server." msgstr "转发客户端将带有标准文件传输字节流(元数据标头 + 64 KiB 块)的文件流式传输到服务器上的传输套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:465 -#: 42efd096a6744f489dc623a6ee503666 +#: ../../source/File_Transfer/File_Transfer.rst:467 +#: 43c94e746a5c46748846d0dc18a4e0ff msgid "" "The server acts as a pure relay: it reads the stream into per-target " "memory queues and writes each chunk to every target's transfer socket. " @@ -846,21 +849,21 @@ msgid "" "never writes to disk." msgstr "服务器充当纯粹的中继:它将流读取到每个目标的内存队列中,并将每个块写入每个目标的传输套接字。服务器从不解析超出大小标头的文件内容,也从不写入磁盘。" -#: ../../source/File_Transfer/File_Transfer.rst:472 -#: f43cb20c7bc648018f6f77ea09c8d538 +#: ../../source/File_Transfer/File_Transfer.rst:474 +#: 9dec57916af34e109bee7ce1e0bae2d4 msgid "" "Every target client receives the stream with the ordinary receive path " "(``file_transfer_mode_recv``) and writes it to its own local disk, " "exactly as if the server had pushed the file directly." msgstr "每个目标客户端都使用普通接收路径(“file_transfer_mode_recv”)接收流并将其写入自己的本地磁盘,就像服务器直接推送文件一样。" -#: ../../source/File_Transfer/File_Transfer.rst:478 -#: 3885df70422e4306ac80be623aa9581f +#: ../../source/File_Transfer/File_Transfer.rst:480 +#: a095abaf821e41a6a66adbb776bc35ef msgid "### Memory Bounding and Flow Control" msgstr "### 内存限制和流量控制" -#: ../../source/File_Transfer/File_Transfer.rst:480 -#: e371e5b793824e3386b43cb07a4222fd +#: ../../source/File_Transfer/File_Transfer.rst:482 +#: 244214dd675345f8a72b1088ad99fea0 #, fuzzy msgid "" "Because uploader, server and targets may have different bandwidths, data " @@ -880,30 +883,30 @@ msgstr "" "TCP_Client_Base 都采用 max_mem_buff 参数(以 MB 为单位,默认 2048,即 2 " "GB),该参数限制了转发机制在该进程中可以保留的内存。当服务器的缓冲字节超过“max_mem_buff”时,它会向转发客户端发送“/pause_trans”,从而停止读取源文件;一旦作者将缓冲区排空到低水位线(限制的一半)以下,服务器就会发送“/start_trans”并恢复上传。接收客户端将每个块同步排出到磁盘,因此它们的缓冲内存保持受单个块的限制;两侧都存在“/pause_trans”/“/start_trans”处理程序,因此任何一侧都可以在缓冲数据时限制传输。" -#: ../../source/File_Transfer/File_Transfer.rst:504 -#: b737bf957d354491b30903bfb0f89a3b +#: ../../source/File_Transfer/File_Transfer.rst:506 +#: 0aa14deaf6474437b421a65e21fce7d8 msgid "Concurrency and Threading" msgstr "并发和线程" -#: ../../source/File_Transfer/File_Transfer.rst:506 -#: 505576a3522748318a95cd3937a96834 +#: ../../source/File_Transfer/File_Transfer.rst:508 +#: 825c5e1a8b9b405c967ca49a1861e258 msgid "" "Both the server and the client use multiple levels of concurrency control" " to ensure stability during file transfers." msgstr "服务器和客户端均采用多级并发控制来保证文件传输过程中的稳定性。" -#: ../../source/File_Transfer/File_Transfer.rst:510 -#: 1d1a7b2ee1434530ae6abb411b0175cc +#: ../../source/File_Transfer/File_Transfer.rst:512 +#: 0d48b1245cd54597928cfc28d5b3c248 msgid "### File Transfer Semaphore" msgstr "### 文件传输信号量" -#: ../../source/File_Transfer/File_Transfer.rst:512 -#: 078680d22b10410db9f7f21fe0e1a91d +#: ../../source/File_Transfer/File_Transfer.rst:514 +#: e2674ee9e0584513bc53aa815603fd24 msgid "Client: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" msgstr "客户端:``self.file_semaphore = threading.Semaphore(max_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:514 -#: 777a1dcc1258459d89dacbbb7b946c11 +#: ../../source/File_Transfer/File_Transfer.rst:516 +#: 1c0d27d13ad844159d29c6e662d51d09 msgid "" "Server: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" @@ -911,8 +914,8 @@ msgstr "" "服务器:``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:517 -#: 315a82a6dd1a420bbe819a806f3b8292 +#: ../../source/File_Transfer/File_Transfer.rst:519 +#: cb65901904c8411ba53fc629023f732d #, fuzzy msgid "" "This semaphore limits the number of simultaneous file transfers (used " @@ -922,13 +925,13 @@ msgid "" "at ``max_thread_num`` (``max_file_transfer_thread_num`` on the server)." msgstr "此信号量限制同时文件传输的数量(主要在发送文件夹或多个文件时使用)。每个传输都在自己的线程中运行,并且在线程启动之前获取信号量。" -#: ../../source/File_Transfer/File_Transfer.rst:524 -#: b39cfe74f74b4b568221d23addc55da3 +#: ../../source/File_Transfer/File_Transfer.rst:526 +#: 6d93783b298e4ce98b999ff890d4a5f4 msgid "### Threading Model" msgstr "### 线程模型" -#: ../../source/File_Transfer/File_Transfer.rst:526 -#: 5586d5cc13a940bb92877b1fed3d03fd +#: ../../source/File_Transfer/File_Transfer.rst:528 +#: 036a972600e645119d8a523fa08a52db msgid "" "Each file transfer runs in a dedicated daemon thread, created by the " "``_thread`` wrapper functions (e.g., " @@ -936,29 +939,29 @@ msgid "" "transfer from blocking the main control loop." msgstr "每个文件传输都在一个专用的守护线程中运行,该守护线程由“_thread”包装函数创建(例如“file_transfer_client_recv_client_start_thread”)。这可以防止缓慢的传输阻塞主控制循环。" -#: ../../source/File_Transfer/File_Transfer.rst:532 -#: 7b1cceca816c426b865265e0c302c425 +#: ../../source/File_Transfer/File_Transfer.rst:534 +#: a84aaf5f9fb64d92b97c32185a1e7cb5 msgid "" "The thread that receives the transfer command (e.g., the server's " "``handle_command`` thread) does not wait for the transfer to complete; it" " returns immediately after spawning the worker thread." msgstr "接收传输命令的线程(例如服务器的“handle_command”线程)不会等待传输完成;它在产生工作线程后立即返回。" -#: ../../source/File_Transfer/File_Transfer.rst:537 -#: 2d25f2be19fb467bb222d3780e2be853 +#: ../../source/File_Transfer/File_Transfer.rst:539 +#: 669fb6da8e7444dd829a6e14295648b1 msgid "" "The low-level receive function (``file_transfer_mode_recv``) blocks while" " reading from the transfer socket, but because it runs in a dedicated " "thread, the main connection remains responsive." msgstr "低级接收函数(“file_transfer_mode_recv”)在从传输套接字读取时会阻塞,但由于它在专用线程中运行,因此主连接仍保持响应。" -#: ../../source/File_Transfer/File_Transfer.rst:543 -#: 641bce0854274c369c0b915a1c3d964a +#: ../../source/File_Transfer/File_Transfer.rst:545 +#: e39f8ae06ae84a6b84de8a3008ca17cb msgid "### Thread Pool for Custom Commands" msgstr "### 自定义命令的线程池" -#: ../../source/File_Transfer/File_Transfer.rst:545 -#: c41d6414ad5542aa8bbeaa67d28730d5 +#: ../../source/File_Transfer/File_Transfer.rst:547 +#: 3ad49853529d4563bacdfb4ca6eee115 msgid "" "Both classes also provide a ``ThreadPoolExecutor`` " "(``self._custom_executor``) for custom command handlers. When a handler " @@ -969,21 +972,21 @@ msgid "" "processing." msgstr "这两个类还为自定义命令处理程序提供了“ThreadPoolExecutor”(“self._custom_executor”)。当使用“run_in_thread=True”注册处理程序时,它会通过“submit_task”提交到该池,该池还使用信号量将并发限制为“max_custom_workers”。此机制独立于文件传输信号量,旨在用于通用命令处理。" -#: ../../source/File_Transfer/File_Transfer.rst:560 -#: adfe7eb4ec4942e9979652f98b3beed9 +#: ../../source/File_Transfer/File_Transfer.rst:562 +#: 1862d74da28a40219f82cfd7af89c126 msgid "Port Allocation and Management" msgstr "端口分配与管理" -#: ../../source/File_Transfer/File_Transfer.rst:562 -#: 845beb63ef9c47ba8379637a1b0662fb +#: ../../source/File_Transfer/File_Transfer.rst:564 +#: bd53ec8aa4ef498aa0815db16ed03140 msgid "" "File transfers require ephemeral ports for the secondary data " "connections. The ``palloc()`` and ``pfree()`` methods are used to obtain " "and release these ports. Two modes are available:" msgstr "文件传输需要临时端口来进行辅助数据连接。 ``palloc()`` 和 ``pfree()`` 方法用于获取和释放这些端口。有两种模式可供选择:" -#: ../../source/File_Transfer/File_Transfer.rst:568 -#: 8195ea505bdf43a2a0f68b78d958c709 +#: ../../source/File_Transfer/File_Transfer.rst:570 +#: eeaa9379d7d941159ac34f30ff6bb5f9 msgid "" "**Automatic mode** (``is_hand_alloc_port=False``): ``palloc()`` returns " "``0``, and the operating system assigns a free port when the socket is " @@ -992,8 +995,8 @@ msgstr "" "**自动模式**(``is_hand_alloc_port=False``):``palloc()`` " "返回``0``,操作系统在套接字绑定时分配一个空闲端口。这是大多数用例的推荐模式。" -#: ../../source/File_Transfer/File_Transfer.rst:573 -#: 9a796b6e464d4d9e8e131401d5022e1f +#: ../../source/File_Transfer/File_Transfer.rst:575 +#: e3dc324e81734bd4bc768174caf200bf #, fuzzy msgid "" "**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; " @@ -1009,40 +1012,40 @@ msgstr "" "self.max_port]`` " "中提取端口,步长为``port_add_step``。服务器通过“/client_alloc_port_range”向客户端广播允许的范围,然后客户端使用相同的手动分配逻辑。" -#: ../../source/File_Transfer/File_Transfer.rst:588 -#: 7d275701519c4d60ba94cf086010e92d +#: ../../source/File_Transfer/File_Transfer.rst:590 +#: 29cfdab183eb4f9f83de41ef62a60785 msgid "" "*Note: For more details about port allocation, please visit the Port " "Allocation API sections in :doc:`TCP_Server_APIs` and " ":doc:`TCP_Client_APIs`.*" msgstr "*注意:有关端口分配的更多详细信息,请访问 TCP_Server_APIs 和 TCP_Client_APIs 中的端口分配 API 部分。*" -#: ../../source/File_Transfer/File_Transfer.rst:596 -#: e92794553f6f4189978c5486f4d09fce +#: ../../source/File_Transfer/File_Transfer.rst:598 +#: 189736d8d1f8464b8d301f219700fda4 msgid "Error Handling and Timeouts" msgstr "错误处理和超时" -#: ../../source/File_Transfer/File_Transfer.rst:598 -#: 6ef0c4c7a91a42d0acc6b0a387247432 +#: ../../source/File_Transfer/File_Transfer.rst:600 +#: bcc373777989436f9df3657446d1a7f2 msgid "### Timeout Values" msgstr "### 超时值" -#: ../../source/File_Transfer/File_Transfer.rst:600 -#: 2b8dea32ffe04d4988e44fca72384271 +#: ../../source/File_Transfer/File_Transfer.rst:602 +#: 27d75d097a804ec28ebec5c67469c9c6 msgid "" "**Start signal timeout**: 10 seconds. If the receiver does not send " "``server_start_file_transfer_sign`` within this time, the sender aborts." msgstr "**启动信号超时**:10 秒。如果接收方在此时间内未发送“server_start_file_transfer_sign”,则发送方将中止。" -#: ../../source/File_Transfer/File_Transfer.rst:604 -#: 2d19f71ef52b4f3097bf0c2f3e64be7b +#: ../../source/File_Transfer/File_Transfer.rst:606 +#: 93e877c411eb4c96bd7861ff61f35e7a msgid "" "**Port negotiation timeout**: 20 seconds. The initiator waits for the " "peer's ``/server_file_transfer_port`` response." msgstr "**端口协商超时**:20 秒。发起者等待对等方的“/server_file_transfer_port”响应。" -#: ../../source/File_Transfer/File_Transfer.rst:607 -#: 67dba14dcd534ae484df410cb48c8e53 +#: ../../source/File_Transfer/File_Transfer.rst:609 +#: 9e1d395bb59540a49393bebe6630e5eb msgid "" "**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 " "* 1024)) * 10`` seconds. Larger files get proportionally more time." @@ -1050,39 +1053,39 @@ msgstr "" "**完成确认超时**:``30 + (file_size // (100 * 1024 * 1024)) * 10`` " "秒。文件越大,相应的时间就越长。" -#: ../../source/File_Transfer/File_Transfer.rst:611 -#: f175db3ace1448068c029d1527feb065 +#: ../../source/File_Transfer/File_Transfer.rst:613 +#: 6b4e6135669b41178fdbb47ea5975381 msgid "### Error Signalling" msgstr "### 错误信号" -#: ../../source/File_Transfer/File_Transfer.rst:613 -#: 988d9d4636944c0abc8d186178d2a4f7 +#: ../../source/File_Transfer/File_Transfer.rst:615 +#: 448fdc6ba3dd4d9eae925e7e241f8cb8 msgid "" "Any error during the handshake or data transfer causes the failing side " "to send ``error_sign`` over the transfer socket." msgstr "握手或数据传输期间的任何错误都会导致失败方通过传输套接字发送“error_sign”。" -#: ../../source/File_Transfer/File_Transfer.rst:616 -#: d171618e798b46d0a6ac7473b4a787ba +#: ../../source/File_Transfer/File_Transfer.rst:618 +#: 5b4c23a93e984ce0af2e43cf4752225b msgid "" "The other side, upon receiving the error sign, closes the transfer socket" " and aborts the transfer." msgstr "另一端收到错误标志后,关闭传输套接字并中止传输。" -#: ../../source/File_Transfer/File_Transfer.rst:619 -#: c712f2f5e1794c528d4816a761030029 +#: ../../source/File_Transfer/File_Transfer.rst:621 +#: b337a2726ded4d619c5e8026bef3f6ea msgid "" "The main control connection remains unaffected; only the transfer socket " "is closed." msgstr "主控连接不受影响;仅关闭传输套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:623 -#: 9d55f6049713415794e53bd6a476e11f +#: ../../source/File_Transfer/File_Transfer.rst:625 +#: 68be52c8e5ce447a9c5ec51a661229cf msgid "### Exception Handling" msgstr "### 异常处理" -#: ../../source/File_Transfer/File_Transfer.rst:625 -#: a45a6eaec53b4699a7e61d4e422ace85 +#: ../../source/File_Transfer/File_Transfer.rst:627 +#: 036db9bc1858417ca589816028b83f80 #, fuzzy msgid "" "All socket operations are wrapped in try-except blocks. When an exception" @@ -1096,13 +1099,172 @@ msgstr "" "块中。当发生异常时(例如,连接重置、未找到文件),错误将用``traceback.print_exc()`` " "记录,并且传输会正常中止。如果可能,将发送“error_sign”,并关闭传输套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:638 -#: 00af57a759ec4845b5810bb85ac1f485 +#: ../../source/File_Transfer/File_Transfer.rst:640 +#: ba1f05134dd24afa9867881cc45ed14a +msgid "Transfer Progress and Network Speed" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:642 +#: 5c7b182bb5214dd2ad49e5b171876e95 +msgid "Both classes record every running file transfer:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:644 +#: 8adbb686d9b04c97b5a7314ec4a5d1fd +msgid "``file_recv_progress`` — the files being received (downloads);" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:645 +#: 3d2d981185624b5498121d82b12d44ba +msgid "``file_upload_progress`` — the files being sent (uploads)." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:647 +#: e59132f2790d4b4fb2aa707e1d3b43b6 +msgid "" +"The keys are the transfers' fids: the transfer id the sender stamps on " +"the transfer command (``/file ``), which also identifies the " +"relay leg of a forwarded file. The protocol-internal public-key push is " +"not tracked. Each value is a five-item list:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:652 +#: bf66e7dae7e24cf3a3687ffd30f547ec +msgid "``[0]``: bytes transferred so far;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:653 +#: 2652aa8074764124b520d4e84b7667d5 +msgid "``[1]``: total size of the file, in bytes;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:654 +#: 8b09fc93700d4b6ca7a517700649c289 +msgid "" +"``[2]``: the current network speed of that direction — ``None`` until the" +" transfer has moved its first chunk, and while " +"``is_enable_real_time_network_speed`` is ``False``;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:657 +#: 311adcc13bd441a985ebcd8c775b152f +msgid "" +"``[3]``: local path of the file: the source of an outbound transfer, the " +"file being written for an inbound one;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:659 +#: 7a1f875aeb8b497ab7785620e402ff97 +msgid "" +"``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender " +"in a download's entry, the receiver in an upload's. A forwarded transfer " +"stores the original peer on both sides, never the relaying server." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:663 +#: da38fbed94114f10b6f7366e43906dd8 +msgid "" +"An entry appears when a transfer starts and is removed when it ends, so " +"the stores hold exactly the transfers that are in flight at that moment " +"(iterate over a copy while transfers are running). With " +"``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is " +"ever recorded — and, since the stores are the state a reconnect resumes " +"from, no transfer can be resumed either." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:670 +#: edbdd37cf5a04d42bf01f6bff5aa3307 +msgid "" +"``is_enable_real_time_network_speed`` (``True`` by default) measures the " +"protocol's current traffic — the control layer and every temporary " +"connection, file transfers included — into ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With the flag ``False`` nothing is " +"sampled and every speed value is ``None``." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:677 +#: c60e3cb78c8d48faace7569bdb50f8f5 +msgid "" +"The web tool (``transfer_web``) reads these stores: both backends serve " +"``/api/transfers`` (the rows plus the two speed attributes), and the " +"shared frontend renders the live speed readout in the topbar and one " +"progress bar per running transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:685 +#: ce90e0b6082e4d37a79346aa7b2763f9 +msgid "Pausing, Reconnecting and Resuming Transfers" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:687 +#: 5fbf414617474bd79978360043f149a3 +msgid "" +"An outbound transfer can be held and released at any time with the " +"``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or " +"from the peer with the ``/pause_trans `` and ``/start_trans `` " +"lines: ``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, " +"fid)`` send them. The leg stops before its next chunk and stays open; a " +"leg that is paused keeps its socket, so nothing is torn down. Every " +"outbound transfer honours its own fid — a plain upload as much as the " +"upload leg of a forwarded file — so the flow control the server uses on a" +" relay works on any transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:696 +#: d4ace80bc05f4bafb8144e1de31060dc +msgid "The temporary connections of a transfer are resumed after a disconnect:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:698 +#: d7d49609832d4c5bb2d7cecb059805eb +msgid "" +"when a connection drops, both sides write their transfer stores to " +"``.Flow/server_file_trans_progress.json`` / " +"``.Flow/client_file_trans_progress.json`` (the " +"``file_trans_progress_file`` attribute) — every upload, every download " +"and, on the server, the relay records a disconnected forward is re-driven" +" from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:703 +#: 353cf50d60014cceb4c5a36bf5b98b83 +msgid "" +"an interrupted transfer keeps its progress entry and its partial file " +"instead of dropping them, so the file on disk is exactly the state to " +"continue from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:706 +#: c7017b370d4147128e54a94458a7b536 +msgid "" +"after a reconnect the receiver drives the resume (`resume_transfers`): it" +" opens a fresh transfer listener, announces it and sends ``/resume_trans " +" `` with the byte offset its partial file holds. The sender " +"re-establishes the leg, reads its source from that offset and only the " +"remainder of the file travels. A forwarded transfer is asked for through " +"the server, which routes ``/forward_resume`` to the originating client so" +" it re-forwards just the missing part." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:714 +#: ee858a76e93f44d5934cb2d89f6709a5 +msgid "" +"The server resumes a peer's transfers when it reconnects, and a client " +"with ``is_auto_reconnect=True`` reconnects on its own and resumes every " +"transfer it can reach; `resume_transfers` is public, so an application " +"can also drive the resume itself. Legs the previous session left behind " +"are closed before the resume runs, so two legs never write the same " +"transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:723 +#: fe9377db9cf04b9da0dbe4d07c730adf msgid "Related API Definitions" msgstr "相关API定义" -#: ../../source/File_Transfer/File_Transfer.rst:640 -#: 92c3b5d713cb49cfb144026af574a0b4 +#: ../../source/File_Transfer/File_Transfer.rst:725 +#: cc71cb9b1d6642a2acc89d45a49022cc msgid "" "This section lists all public file-transfer related methods in " "``TCP_Server_Base`` and ``TCP_Client_Base``. For a complete list of all " @@ -1111,13 +1273,13 @@ msgstr "" "本节列出了“TCP_Server_Base”和“TCP_Client_Base”中所有与公共文件传输相关的方法。有关所有公共 API " "的完整列表,请参阅本文档末尾的表格。" -#: ../../source/File_Transfer/File_Transfer.rst:646 -#: bbc49149589d43719bc774a99b84ce6e +#: ../../source/File_Transfer/File_Transfer.rst:731 +#: d6683e415f794c5bb693f8c24370e7f9 msgid "### Server-Side File Transfer APIs" msgstr "### 服务器端文件传输 API" -#: ../../source/File_Transfer/File_Transfer.rst:652 -#: 59386d051c734452801f4bd00d5dd654 +#: ../../source/File_Transfer/File_Transfer.rst:737 +#: 9123c69197c34d93bb68d088897ebeca msgid "" "Initiates a server-to-client file transfer. ``message`` is the command " "string (e.g., ``/file /path/to/file.txt (127.0.0.1,54321)``). If " @@ -1127,13 +1289,13 @@ msgstr "" "启动服务器到客户端的文件传输。 ``message`` 是命令字符串(例如,``/file /path/to/file.txt " "(127.0.0.1,54321)``)。如果提供了“file_folder_abspath”(用于文件夹传输),则它指定父文件夹的绝对路径。" -#: ../../source/File_Transfer/File_Transfer.rst:663 -#: 431a043a77bc4d82a206650afde47b86 +#: ../../source/File_Transfer/File_Transfer.rst:748 +#: 367dfd82c95c413d963a15152469fc44 msgid "Thread-safe version that starts a new thread for the transfer." msgstr "线程安全版本,启动新线程进行传输。" -#: ../../source/File_Transfer/File_Transfer.rst:669 -#: e17536344cb444b699c7465d8bcbdded +#: ../../source/File_Transfer/File_Transfer.rst:754 +#: d4aa76b7eb2c46c29adee0120a939b66 #, fuzzy msgid "" "Sends an entire folder from server to client. ``message`` should be of " @@ -1143,8 +1305,8 @@ msgstr "" "将整个文件夹从服务器发送到客户端。 “message” 的格式应为“/file_folder " "”。" -#: ../../source/File_Transfer/File_Transfer.rst:676 -#: 88f9df0240054009a6957b13ee08f2ef +#: ../../source/File_Transfer/File_Transfer.rst:761 +#: 29f2a5e19bf04a09a8711ac1c892a4ad msgid "" "Sends multiple items to multiple clients. The message format is " "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -1155,8 +1317,8 @@ msgid "" "destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:688 -#: 39b67f1d0e6b438386eb04c6d44da6b8 +#: ../../source/File_Transfer/File_Transfer.rst:773 +#: ff8bc5c8969b45c1bbcf1eba5b77485a msgid "" "Sends different file lists to different clients. Files that appear before" " a group of client addresses are sent to that group; a new group starts " @@ -1167,217 +1329,242 @@ msgid "" "optional trailing destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:701 -#: 37108379b0b9495584bb135d5860ea4a +#: ../../source/File_Transfer/File_Transfer.rst:786 +#: f8a880287b7b49d4bdc2239ecf4a0577 msgid "" "Receives a file from a client. Called internally when the server receives" " a ``/file`` command from a client." msgstr "从客户端接收文件。当服务器从客户端接收到“/file”命令时在内部调用。" -#: ../../source/File_Transfer/File_Transfer.rst:710 -#: adeb784cb6b24d6cbf143a7a50eba80a +#: ../../source/File_Transfer/File_Transfer.rst:795 +#: 97bfaa9c24ae47c39328707b8f17a91a msgid "" "Low-level receive function that performs the handshake and writes the " "incoming file to disk." msgstr "执行握手并将传入文件写入磁盘的低级接收函数。" -#: ../../source/File_Transfer/File_Transfer.rst:718 -#: 0bb492f5335d426d8dc715847665b3f4 +#: ../../source/File_Transfer/File_Transfer.rst:804 +#: c7be9703e0454f7f96586642bc8f6a22 msgid "" "Low-level send function that connects to the receiver and transmits the " -"file." -msgstr "连接到接收器并传输文件的低级发送函数。" +"file. ``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's" +" original receiver and ``resume_offset`` continues an interrupted file " +"from the byte the receiver already holds." +msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:720 -#: 29189fe72c61456ba2d5aa1ece75145e +#: ../../source/File_Transfer/File_Transfer.rst:810 +#: 3e7b689215e840bebd368b4d29104ebc msgid "### Client-Side File Transfer APIs" msgstr "### 客户端文件传输 API" -#: ../../source/File_Transfer/File_Transfer.rst:726 -#: 6c2f54ee2660441291a3fbbcaa95262c +#: ../../source/File_Transfer/File_Transfer.rst:816 +#: 1e97e492d6504579a9a265eb1242395e msgid "" "Initiates a client-to-server file transfer. ``message`` is the user " "command (e.g., ``/file mydoc.txt``). Used internally by the interactive " "console." msgstr "启动客户端到服务器的文件传输。 “message” 是用户命令(例如“/file mydoc.txt”)。由交互式控制台内部使用。" -#: ../../source/File_Transfer/File_Transfer.rst:734 -#: ../../source/File_Transfer/File_Transfer.rst:765 -#: 07c4ae801fb54cbcb508af4b208f75dd +#: ../../source/File_Transfer/File_Transfer.rst:824 +#: ../../source/File_Transfer/File_Transfer.rst:855 +#: 0cd2695763114a0b831df0bfa80a3d56 msgid "Thread-safe version." msgstr "线程安全版本。" -#: ../../source/File_Transfer/File_Transfer.rst:740 -#: 0d66d4aac681414fb7b8a46117571fe9 +#: ../../source/File_Transfer/File_Transfer.rst:830 +#: 261399ca508d463eafa7f03a00bfc658 msgid "Sends a folder from client to server." msgstr "将文件夹从客户端发送到服务器。" -#: ../../source/File_Transfer/File_Transfer.rst:746 -#: 2818655cecfc49f7ab1c9800b9418018 +#: ../../source/File_Transfer/File_Transfer.rst:836 +#: ef5e3b92b11c4530960c1c344a51c73b msgid "Sends multiple files from client to server." msgstr "将多个文件从客户端发送到服务器。" -#: ../../source/File_Transfer/File_Transfer.rst:752 -#: 6ee08a69dbc5486a94fe2f616f0899e2 +#: ../../source/File_Transfer/File_Transfer.rst:842 +#: f2c90ee949d7484480cbb2cd5310bf26 msgid "Sends multiple folders from client to server." msgstr "将多个文件夹从客户端发送到服务器。" -#: ../../source/File_Transfer/File_Transfer.rst:759 -#: 5a88c3508e074cff9ae445d00193f212 +#: ../../source/File_Transfer/File_Transfer.rst:849 +#: 0b13d26a40174243a15698b4bfcbb69f msgid "" "Receives a file from the server (called when the server initiates a " "transfer)." msgstr "从服务器接收文件(在服务器启动传输时调用)。" -#: ../../source/File_Transfer/File_Transfer.rst:771 -#: 42db9f7f09c044c8a58243854644adfb +#: ../../source/File_Transfer/File_Transfer.rst:861 +#: 3b78a4355d7f4ee2bbbe6bf934a962c0 msgid "Receives a folder from the server." msgstr "从服务器接收文件夹。" -#: ../../source/File_Transfer/File_Transfer.rst:779 -#: 0a051d591bb54e529c771345409ec7df +#: ../../source/File_Transfer/File_Transfer.rst:869 +#: 3d044e0754b94d1289b491502ce83610 msgid "Low-level receive function on the client side." msgstr "客户端的低级接收函数。" -#: ../../source/File_Transfer/File_Transfer.rst:786 -#: e0149bdd716249289f6ba260e3c3f053 +#: ../../source/File_Transfer/File_Transfer.rst:877 +#: 7311023a7fa644ed9b57a2873cd3bca8 msgid "" "Low‑level send function on the client side (identical to server's " "version)." msgstr "客户端的低级发送功能(与服务器版本相同)。" -#: ../../source/File_Transfer/File_Transfer.rst:791 -#: e612d36affc0456b9314f39816bf62f3 +#: ../../source/File_Transfer/File_Transfer.rst:882 +#: 7e74e9a09a8a4cf2a8a372a50b1ee51b msgid "Public API Summary" msgstr "公共API摘要" -#: ../../source/File_Transfer/File_Transfer.rst:793 -#: 8347c97393fe47ea83c13f6777faa36c +#: ../../source/File_Transfer/File_Transfer.rst:884 +#: 87aaf0a5d3b44f41a419d97b6567f6d0 msgid "" "All public APIs (including non-file-transfer methods) are listed below " "for reference." msgstr "下面列出了所有公共 API(包括非文件传输方法)以供参考。" -#: ../../source/File_Transfer/File_Transfer.rst:797 -#: 5ac025a5e948425a9a430c7c75b045f9 +#: ../../source/File_Transfer/File_Transfer.rst:888 +#: a195ee393f2a442c810e59811a6ae126 msgid "### TCP_Server_Base Public APIs" msgstr "### TCP_Server_Base 公共 API" -#: ../../source/File_Transfer/File_Transfer.rst:799 -#: ddf4d1d8e04e40659404ebb55c843c41 +#: ../../source/File_Transfer/File_Transfer.rst:890 +#: 0408d74a9140472e9a774143a60e5749 msgid "``file_transfer_server_recv_client_start``" msgstr "``file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:800 -#: 052d49abc8514ed19346f7b023783fa9 +#: ../../source/File_Transfer/File_Transfer.rst:891 +#: 24a33cb212844e04a8a271ada32412f0 msgid "``file_transfer_server_recv_client_start_thread``" msgstr "``file_transfer_server_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:801 -#: 6db2d78cc0b94b4b93d6080164897079 +#: ../../source/File_Transfer/File_Transfer.rst:892 +#: 7e286d1ece6940868bea6b937486e617 msgid "``folder_file_transfer_server_recv_client_start``" msgstr "``folder_file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:802 -#: ec1b13e6e07449ec820d5cdc7a983048 +#: ../../source/File_Transfer/File_Transfer.rst:893 +#: 37fc5bd346c84415bb15138a42508fbe msgid "``multiple_file_multiple_client_transfer_server_recv_client_start``" msgstr "``multiple_file_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:803 -#: 7d780de964e543a8b703dd413d331c43 +#: ../../source/File_Transfer/File_Transfer.rst:894 +#: 38a2b16e3ab648688cf7e8d1cae8be72 msgid "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:804 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:895 +#: ad39bc6b71f048b09bca3b895e9d32f8 #, fuzzy msgid "" "``file_folder_transfer_server_recv_server_start_thread`` (folder " "receiving)" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:806 -#: 02e685a79bc64a32ad888008a9dde074 +#: ../../source/File_Transfer/File_Transfer.rst:896 +#: ../../source/File_Transfer/File_Transfer.rst:916 +#: 37aeb9835435434881f94eb9951370d6 660ac3b979cc43d0beece659b9b0935f +msgid "``pause_trans`` / ``start_trans`` (hold and release an outbound transfer)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:897 +#: 7641e3ece9314197863d872836635218 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:898 +#: ../../source/File_Transfer/File_Transfer.rst:918 +#: 9c62709c2c06456dbfddee1f1ce6871e de496a0be32c490585ae0cbafc931a71 +msgid "``resume_transfers`` / ``resume_trans`` (continue interrupted transfers)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:900 +#: 11476e0eaa3b4a4286612812e4e2c004 msgid "" "(The low-level helpers ``file_transfer_server_recv_server_start``, " "``file_transfer_mode_recv``, and ``file_transfer_mode`` are not " "considered public but are documented for completeness.)" msgstr "(低级助手“file_transfer_server_recv_server_start”、“file_transfer_mode_recv”和“file_transfer_mode”不被认为是公共的,但为了完整性而被记录下来。)" -#: ../../source/File_Transfer/File_Transfer.rst:812 -#: 5193d200c3f245caae4095ab4114a467 +#: ../../source/File_Transfer/File_Transfer.rst:906 +#: 907e861cebe648fbacb799bae8bb15e0 msgid "### TCP_Client_Base Public APIs" msgstr "### TCP_Client_Base 公共 API" -#: ../../source/File_Transfer/File_Transfer.rst:814 -#: df25f04d660046669347072182ca0bde +#: ../../source/File_Transfer/File_Transfer.rst:908 +#: 88bd80083f754caeb026f9ce1b8c6b55 msgid "``file_transfer_client_recv_client_start``" msgstr "``file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:815 -#: 2a43c7e5134b4a64af241547e798bdf3 +#: ../../source/File_Transfer/File_Transfer.rst:909 +#: 3b21ff73da694465906482412b4fb4e3 msgid "``file_transfer_client_recv_client_start_thread``" msgstr "``file_transfer_client_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:816 -#: 6a88ac28f634410ab54d999291b5b309 +#: ../../source/File_Transfer/File_Transfer.rst:910 +#: c8af43896a2443a5b14bd29863731c2c msgid "``folder_file_transfer_client_recv_client_start``" msgstr "``folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:817 -#: 6d47f6da5f54475989d93fca0c141f2d +#: ../../source/File_Transfer/File_Transfer.rst:911 +#: 7a3d3e4a52334b169a62d3b30d7a3190 msgid "``multiple_file_transfer_client_recv_client_start``" msgstr "``multiple_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:818 -#: 06e20b477a9744de9f2d2efcf0fbf57f +#: ../../source/File_Transfer/File_Transfer.rst:912 +#: 19e18754c4674842ad5116f709588e03 msgid "``multiple_folder_file_transfer_client_recv_client_start``" msgstr "``multiple_folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:819 -#: a8dd89a54e0f498b88185761dc4c0f46 +#: ../../source/File_Transfer/File_Transfer.rst:913 +#: 4cf80f9f34e045c59a680d0450c9103a msgid "``file_transfer_client_recv_server_start``" msgstr "``file_transfer_client_recv_server_start``" -#: ../../source/File_Transfer/File_Transfer.rst:820 -#: 0811953096e94bd887990bb58d2de56a +#: ../../source/File_Transfer/File_Transfer.rst:914 +#: c09f5fcba03f461f89238dd31abf6e88 msgid "``file_transfer_client_recv_server_start_thread``" msgstr "``file_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:821 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:915 +#: ad39bc6b71f048b09bca3b895e9d32f8 msgid "``file_folder_transfer_client_recv_server_start_thread``" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:823 -#: bbbea73553dd4dfd98e0ee4076c1d42b +#: ../../source/File_Transfer/File_Transfer.rst:917 +#: 4b82ae9a067f46d5bb297431468a67a4 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:920 +#: 99140d0be72649199911a57a26e2f2cf msgid "(The low-level helpers are documented but not part of the public API.)" msgstr "(低级帮助程序已记录,但不属于公共 API 的一部分。)" -#: ../../source/File_Transfer/File_Transfer.rst:827 -#: 56f1214838224007ade30eb34009810c +#: ../../source/File_Transfer/File_Transfer.rst:924 +#: 60355543ac904504af8529431ce2c1fa msgid "See Also" msgstr "参见" -#: ../../source/File_Transfer/File_Transfer.rst:829 -#: d513a2ce6fdf40eca5746ea840b4314f +#: ../../source/File_Transfer/File_Transfer.rst:926 +#: 7a5902ad3de64bf79d54d7f2f83ecbfb msgid "" "For more information about the TCP server and client base classes, please" " refer to:" msgstr "关于TCP服务器和客户端基类的更多信息,请参考:" -#: ../../source/File_Transfer/File_Transfer.rst:833 -#: 66b9f83c47d848779de9019a6f33c9a4 +#: ../../source/File_Transfer/File_Transfer.rst:930 +#: f10c29f467b849e8b4254998b44f99ba msgid ":doc:`../Network_APIs/TCP_Server_APIs`" msgstr ":doc:`../Network_APIs/TCP_Server_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:834 -#: 5cfe4f734d2043c2afe489c53c4ce963 +#: ../../source/File_Transfer/File_Transfer.rst:931 +#: 335ba244d28342449db065c252d7e14c msgid ":doc:`../Network_APIs/TCP_Client_APIs`" msgstr ":doc:`../Network_APIs/TCP_Client_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:836 -#: 47b4292bf8754c389fccf965d9b417d8 +#: ../../source/File_Transfer/File_Transfer.rst:933 +#: 92d0227c356447a098cba072d5b43c98 msgid "" "For details on port allocation, see the Port Allocation API sections in " "those documents." @@ -1454,3 +1641,9 @@ msgstr "有关端口分配的详细信息,请参阅这些文档中的端口分 #~ " a.txt b.txt (ip1,port1) (ip2,port2) c.txt" #~ " (ip3,port3)``" +#~ msgid "" +#~ "Low-level send function that connects" +#~ " to the receiver and transmits the" +#~ " file." +#~ msgstr "连接到接收器并传输文件的低级发送函数。" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/Instance_Setup/Instance_Setup.po b/docs/source/locale/zh_CN/LC_MESSAGES/Instance_Setup/Instance_Setup.po index 35ff938..ec69497 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/Instance_Setup/Instance_Setup.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/Instance_Setup/Instance_Setup.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,12 +18,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Instance_Setup/Instance_Setup.rst:3 -#: b4877074f48944ef95449bad6b451f04 +#: 552b0fbec3774a638b0029ce5fd72949 msgid "Flow Setup Launcher" msgstr "流程设置启动器" #: ../../source/Instance_Setup/Instance_Setup.rst:5 -#: 745aff08935b4042b2885b7f10d524f1 +#: 31952c3324264ea28368c7725796ff63 #, fuzzy msgid "" "The ``flow_setup.py`` script is a launcher for the TCP server/client " @@ -36,12 +36,12 @@ msgstr "" "服务器/客户端框架的启动器。它允许您以交互方式或通过命令行参数快速生成单个服务器或客户端实例。每个启动的实例都在单独的终端窗口(或无头系统上的后台进程)中运行。" #: ../../source/Instance_Setup/Instance_Setup.rst:13 -#: 5cfe71ed904f4f24bef1210b411ee40d +#: c8f9652279de42bb983523a15048596e msgid "Features" msgstr "特征" #: ../../source/Instance_Setup/Instance_Setup.rst:15 -#: d5544e89cd884c938e1bfed52fdaf35a +#: 2bd321903dd94d9985805a44d9ef3d94 #, fuzzy msgid "" "**Interactive mode** – step-by-step creation of server and client " @@ -50,7 +50,7 @@ msgid "" msgstr "**交互模式** – 逐步创建服务器或客户端实例。" #: ../../source/Instance_Setup/Instance_Setup.rst:18 -#: a3239003782944f1aceb438c4b164657 +#: df9cbf9e1d024f9386a4b6278c82249e #, fuzzy msgid "" "**Command-line mode** – launch one server or one client with all " @@ -58,14 +58,14 @@ msgid "" msgstr "**命令行模式** – 在一个命令中使用所有参数启动。" #: ../../source/Instance_Setup/Instance_Setup.rst:20 -#: 6c36fb284a4b4984bd220e047e26ed37 +#: b3406e8f62894233be438b7988e444da msgid "" "**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser" " UI of the ``transfer_web`` web tool." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:22 -#: 1a357d61f62b41dd91e150d24c323a98 +#: e359866c167e4e7ca5bf0791fd471ac4 msgid "" "**Extension registration** – ``--add`` / ``--delete`` register or " "unregister extension protocol files; the registered files are loaded on " @@ -73,7 +73,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:25 -#: 0deeeb0bc12644eaab437361d69dbe77 +#: 5f7cba6df26144e9840d140f94065b33 #, fuzzy msgid "" "**Persistent configuration** – stores the latest instance definitions in " @@ -84,7 +84,7 @@ msgstr "" "将最新的实例定义存储在“setup.json”(与脚本相同的目录)中。每种类型(服务器/客户端)仅保留一个配置,该配置在每次更新时都会被覆盖。" #: ../../source/Instance_Setup/Instance_Setup.rst:29 -#: 0b60fca4ab384444a03750dcb790150f +#: b93809688cb74986ac64e4baceb9f0f6 msgid "" "**Multiple instances** – the ``servers`` and ``clients`` lists may hold " "any number of entries. Adding an entry identical to an existing one of " @@ -92,7 +92,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:33 -#: af8b8bdd4c994728a0bf4a7b358976b7 +#: be9bc008af594306be21e731d6aefee3 #, fuzzy msgid "" "**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, " @@ -103,7 +103,7 @@ msgstr "" "(Terminal.app)。" #: ../../source/Instance_Setup/Instance_Setup.rst:36 -#: 4696d04613af4a1ea055df8be236adc3 +#: 57005cb0d04f47b2a8f10ad0bc9c7b43 #, fuzzy msgid "" "**Complete parameter support** – all parameters accepted by " @@ -114,22 +114,22 @@ msgstr "" "接受的所有参数都可以存储在``setup.json`` 中以进行微调。" #: ../../source/Instance_Setup/Instance_Setup.rst:41 -#: 343fcd49c74b4cfd9d351f93c60e59bc +#: 2ff27919a6f64e8fb610158de5ffdf69 msgid "Usage" msgstr "用法" #: ../../source/Instance_Setup/Instance_Setup.rst:44 -#: 7e39ebc551894366b757ddfb5c406753 +#: dddde4f2d7084bc48efa1296cfd3f22c msgid "Interactive Mode" msgstr "互动模式" #: ../../source/Instance_Setup/Instance_Setup.rst:46 -#: 5f7b3715a9524fa2a0aed70bbefc5008 +#: f060e64959674f52b223bbc4b01d568c msgid "Run the script without any arguments:" msgstr "不带任何参数运行脚本:" #: ../../source/Instance_Setup/Instance_Setup.rst:52 -#: a17a608e2ac24987b6c4a428acd770e9 +#: 6bb60d44328244d4ab20f3ae5ba2b827 msgid "" "When ``setup.json`` already exists, the launcher first asks whether to " "overwrite it, and the interactive collection itself asks whether the " @@ -137,7 +137,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:56 -#: 7fe4792645644307bf450194c2d98fa7 +#: d247a8d3c3f1430c8dfa6dccad66da0a msgid "" "``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` " "launches every stored instance and exits; ``Y`` (or no existing file) " @@ -145,7 +145,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:59 -#: e60cbc55c5834e8ab8ce55e696159e9a +#: 96169445a67545178cdd4b68ce5faae3 msgid "" "``Delete or change existing instances or configs? (Y/N):`` – asked only " "when stored instances exist. ``Y`` opens the instance editor (see below);" @@ -153,23 +153,23 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:63 -#: eaf7134992f44c58aa4181664a3bc638 +#: 80847dcc3e404a779b2e693cf8de50d5 #, fuzzy msgid "``Choose the type (0 for Server, 1 for Client)``." msgstr "选择类型(0 表示服务器,1 表示客户端)。" #: ../../source/Instance_Setup/Instance_Setup.rst:64 -#: 6a5569dd541a4043802c5d85f125db64 +#: cebc8ba62d1a48a69d8019c3862dc18b msgid "Enter the bind address and port (``host:port``)." msgstr "输入绑定地址和端口(``host:port``)。" #: ../../source/Instance_Setup/Instance_Setup.rst:65 -#: e70e2b6322a04c748193e1cec4b0ee2c +#: 4311b66e1b974b4596f2693908ba3109 msgid "If Client, also enter the server address and port to connect to." msgstr "如果是客户端,还需输入要连接的服务器地址和端口。" #: ../../source/Instance_Setup/Instance_Setup.rst:67 -#: df73da29736d4b878bef8427a95945aa +#: 3a5cff8b854c40939873ad57b060d9c3 msgid "" "Decide whether to add another instance. An entry that already exists in " "the list is not added again; a new one is appended, so several instances " @@ -177,14 +177,14 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:71 -#: 8e0df08f751f46deb43ba1006ed04b20 +#: 7c893e0f8399455ba1b14d9c796d75a8 msgid "" "After editing, the launcher asks ``Add new instances? (Y/N)`` before " "returning to the add flow." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:74 -#: 237874cb10d040cf86074695574daf32 +#: 49c58d9bb0b1440485f3cbecdb2843d6 msgid "" "When the editor is left with changes, ``setup.json`` is rewritten with " "every instance, and all stored instances (reused plus newly added) are " @@ -192,97 +192,97 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:79 -#: c81a1dba5f224291a56257375f84a1a0 +#: a1e74fd1f7f04e548b268c3dc0d6763e msgid "Global commands" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:81 -#: 8247157dfc0b4a32aa9ae300813386c6 +#: b8ede51e5254499e9dd613bc93db15ca msgid "" "The following words can be typed at **every** prompt, including field-" "value prompts:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: c29ffb659bf3446490bc9eaac6f2e7ea +#: c2b850e77d9b44559be9b25d93611a70 msgid "Effect" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``Help``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 886877e3eb7d407fa62b16a4fc968f62 +#: 200a2a3be7ea46b291882aef0b8d9031 msgid "Print the usage text of the current prompt." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: c569666357334b05ba4189c122bbeaaf +#: a6ce48cd04e04b3ea42ad16e04e37359 msgid "``Fix_Config``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: 0a5c8bdb9c1d4f7eb8a41fce85acf0b4 +#: fcd62172378d4da498de2a21a03f97a0 msgid "Jump to the instance editor (or, inside it, save and return to the list)." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 #, fuzzy msgid "``Setup``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "" "Launch every instance configured in ``setup.json`` and exit the setup " "program." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: cc2a8285cba3495db468d5f007f3ecfc +#: 85343de947b74e3b97e4c59109ebcd9e msgid "``Add_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: a6c3fac6c8f44d75a7a266bae3c54729 +#: 6b8af44d732b4673afbc2f9cbec357d3 msgid "Prompt for extension file path(s) and register them." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 4febe01e668f4cc1aa1b92e328780ebe +#: a35baf4ca7d949eba92cf6c6279c9cd2 msgid "``Delete_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 5e54a7238b604a5fbe930ff4c5fd05d5 +#: d6f9495c1ad046d5877eb8159799ae88 msgid "Prompt for registered extension path(s) to remove." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 88bb1def13564b809d980ac0d7f22832 +#: 7c985bf621ba4fbeaa8f25042d47ed95 msgid "``Quit``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 22644327258c472aab543baf2ee08784 +#: 18f32c4c66094837a84906ba56ef236d msgid "Exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:103 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Instance editor" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:105 -#: 5832e770c51e4e61b0a372086616ad57 +#: 021cb4d2e2234dff8a9b206826926e33 msgid "" "The editor is reached by typing ``Fix_Config`` (at any prompt) or by " "answering ``Y`` to the \"Delete or change existing instances\" question. " @@ -295,37 +295,37 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:115 -#: 36e871e8b76b4e6f8ab3d41c6e58e053 +#: be9f3fe33bf943419ada71d457c635e1 msgid "Vim-style commands:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:117 -#: bf18c8047500461486e3bc05c6154ecc +#: f11526b8f13f4f6eabba91f7543c7120 msgid "``:w`` – write ``setup.json`` without leaving the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:118 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "``:wq`` – write ``setup.json`` and leave the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:119 -#: 8e54b99375e441308cd3dc8ec4cd5d3a +#: 740d1745df7841a59959dbdab98a73b4 msgid "``:q`` – leave; refused while there are unsaved changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:120 -#: 32cdc0d2f2f34602a77b692202f56b24 +#: 944a89864f5c46c488287ee0740d83d5 msgid "``:q!`` – leave and discard all changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:121 -#: 7360415b19b04c13ab167e500f3437ac +#: 927b5a52f9454d65af949f5cc188e33d msgid "``Quit`` – exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:123 -#: aea22c0686c64df8bc842a51fbd2d67e +#: d4163489911a454f9e4fd1b6cdd1de5a msgid "" "Inside the config editor, ``j``/``k`` move between fields, ``Esc`` or " "``back`` returns to the list, and a field index or ``Enter`` edits the " @@ -336,170 +336,170 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:132 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command‑line Mode" msgstr "命令行模式" #: ../../source/Instance_Setup/Instance_Setup.rst:134 -#: 19ffa2fc838a441786de354b2a574153 +#: d798ec606de2454da5f10e9d0a7e677c msgid "Use the following options:" msgstr "使用以下选项:" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: c6dc291839964e119fb50574caedfd9c +#: 4d5c1aebbede473c8598cbc45f8deb20 msgid "Option" msgstr "选项" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: 4a498223c2cb4e45914dcd53bb7f2f12 +#: a50ba126b168482997fae00497252fd4 msgid "Description" msgstr "描述" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: 649f1c33bb9d4afa89d1796bef081ddf +#: 7755904907ee46f6a34144360ed876f7 #, python-brace-format msgid "``--type {0,1}``" msgstr "`` --type {0,1} ``" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: f0793c0f15584b42bc66b82e672854b5 +#: 0175b3fbf31e44829a685a07be420436 msgid "" "0 = Server, 1 = Client. Required for a plain command-line launch; without" " it the launcher runs interactively." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--setup_addr_port``" msgstr "`` --setup_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 58e47d807455460fb6e76d76b836bc30 +#: b7962f6d3a194e3eb91915d5681a2b7b #, fuzzy msgid "Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." msgstr "输入绑定地址和端口(``host:port``)。" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 31efc70f958b4608b07bc24eb1ec633b +#: 388a3dd952ac47a78598792ef7d587bc msgid "``--connect_addr_port``" msgstr "`` --connect_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 041b4144717b4f54ad1b24d06726293b +#: 7d96425a64374a36a457a9167fc6d39c msgid "" "Server address and port to connect to. Required for Client; rejected in " "Server mode." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``--setup_num``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 139258adce2844a28d57733bb973ec1e +#: 26698837fb26457ba9674e8ccf0cf881 msgid "" "Number of instances to launch. Only 1 is allowed; a larger value is " "accepted but ignored with a warning." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_server``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 108977e4c89b442488c39cad5378e8e5 +#: 9b1821de6d0f4c4d9af6c4e47eab4e5d msgid "" "Launch the ``transfer_web`` server tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_client``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 99410d7adbc749e2bee7ff014945d19b +#: 91fa396110c94aa9a29f0a569763e030 msgid "" "Launch the ``transfer_web`` client tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: 5de4064738ce4d529c9df9d1da98a556 +#: 118dce4ec3934bd4b5bb6e7b1aa31bf0 msgid "``--add PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: be6adb7451d84f9f934044d2891cc4db +#: 2a630e280d3040d6a78cd865dd3e2ae7 msgid "Register extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 58e2f444f8394dd5a5c41b400675c736 +#: c505cbcf44104e6799bfcb83251c2f72 msgid "``--delete PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 638774f6e42549ad88f930e50a2c3cad +#: 74b797d0ddf046d3b1dda4eea01013b7 msgid "Unregister extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:167 -#: e9b3cc31339a4f318337e8c68cc61fd5 +#: 54c5d51b3cb841ceaefda13a7613a8ae msgid "" "A command-line launch replaces ``setup.json`` with the single launching " "instance, so any other stored instance is dropped." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:171 -#: 327a63e83b8f4df9af4a5e6a32e2ce6e +#: 99952fa68b694654b82a309a26419152 msgid "Examples" msgstr "示例" #: ../../source/Instance_Setup/Instance_Setup.rst:173 -#: c03b73272d554d1a885a04e6470d43c9 +#: 9c77e76f40a940e99e754d27e3bc1b05 msgid "**Launch a single server** on ``127.0.0.1:8000``:" msgstr "**在“127.0.0.1:8000”上启动单个服务器**:" #: ../../source/Instance_Setup/Instance_Setup.rst:179 -#: 69edc9f7ea534c00bdaab2a4c84ef2cf +#: 37df8730dce9408a87ba48b775eb2b0a msgid "" "**Launch a client** bound to port ``9000``, connecting to a server at " "``127.0.0.1:8000``:" msgstr "**启动绑定到端口“9000”的客户端**,连接到“127.0.0.1:8000”的服务器:" #: ../../source/Instance_Setup/Instance_Setup.rst:186 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "**Launch from an existing configuration** (if ``setup.json`` is present):" msgstr "**从现有配置启动**(如果存在“setup.json”):" #: ../../source/Instance_Setup/Instance_Setup.rst:193 -#: f2fd3c19413a4e6abb4b18037a347443 +#: 0538ca5ad181412c9136f318be43dfa0 msgid "**Launch the web tool** instead of a TCP instance:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:200 -#: 71feceacd5b94bd98ce1973f45c16df1 +#: 4a43a3b821764068aaa05c153037208f msgid "**Register an extension protocol file**:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:207 -#: 00dff5a17f42419585f498c51f7fcc97 +#: ff45af42eb7d4d3faa8640a18bfd61f6 msgid "Configuration File" msgstr "配置文件" #: ../../source/Instance_Setup/Instance_Setup.rst:209 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "" "The script writes a file named ``setup.json`` in the same directory. Its " "structure is:" msgstr "该脚本在同一目录中写入一个名为“setup.json”的文件。其结构为:" #: ../../source/Instance_Setup/Instance_Setup.rst:233 -#: 82c31bcb59fc481eaa532d1a0696ed8d +#: b0129978b1a9468188663a40126df876 msgid "" "**Both lists may contain any number of objects.** Every entry is " "completed with the default value of each parameter that the entry does " @@ -508,21 +508,23 @@ msgid "" "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " "``is_input_command_in_console``, ``max_custom_workers``, " "``is_extend_command``, ``is_enable_encrypto``, ``is_custom_keys``, " -"``max_mem_buff``, ``is_asynic_clients_io``, ``is_debug`` and " +"``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_asynic_clients_io``, ``is_debug`` and " "``is_print_log``; the client entry carries ``host``, ``client_host``, " "``port``, ``client_port``, ``timeout``, ``port_add_step``, " "``max_thread_num``, ``is_input_command_in_console``, ``is_wait_server``, " "``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_debug`` and ``is_print_log``." +"``is_custom_keys``, ``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_debug`` and ``is_print_log``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:251 -#: 8ffd3b4e6719464cbd48a2b20d5764f2 +#: ../../source/Instance_Setup/Instance_Setup.rst:252 +#: 8731a083a201487bb579beb4a238a0db msgid "Custom Parameters" msgstr "自定义参数" -#: ../../source/Instance_Setup/Instance_Setup.rst:253 -#: 284b4f1899d94269a530dec33958d0c8 +#: ../../source/Instance_Setup/Instance_Setup.rst:254 +#: 8910f94645f54874893c20f724780cbd msgid "" "You may edit ``setup.json`` by hand (or change the same fields in the " "instance editor) to give any parameter accepted by ``TCP_Server_Base`` or" @@ -534,21 +536,21 @@ msgid "" "``setup.json`` from that, so hand-written extra keys are lost." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:264 -#: 3746b90215c84dc38c8ca2bb20d396f6 +#: ../../source/Instance_Setup/Instance_Setup.rst:265 +#: c62b1bfe8ceb40f8865a34ac87b4ba18 msgid "Extension Protocols and Startup Mode" msgstr "扩展协议和启动模式" -#: ../../source/Instance_Setup/Instance_Setup.rst:266 -#: 4c6e6cc80e9c4ce3afe79fad55a2815a +#: ../../source/Instance_Setup/Instance_Setup.rst:267 +#: e6a7dcb4ea184e828e6667ae6505d872 msgid "" "Two extension protocols ship with the launcher and are loaded " "automatically for every instance whose ``setup.json`` entry sets " "``is_extend_command=True``:" msgstr "启动器附带两个扩展协议,并为每个“setup.json”条目设置“is_extend_command=True”的实例自动加载:" -#: ../../source/Instance_Setup/Instance_Setup.rst:270 -#: 2d05270538524347899b403011286dcc +#: ../../source/Instance_Setup/Instance_Setup.rst:271 +#: 7159f768fc9a4ac199bfe0a4d8478fba #, fuzzy msgid "" "``command_control_extension_tcp.py`` – remote command execution with per-" @@ -556,8 +558,8 @@ msgid "" "completion report)." msgstr "``command_control_extension_tcp.py`` – 远程命令" -#: ../../source/Instance_Setup/Instance_Setup.rst:273 -#: 1540ce3848be4d519034dd90e1d27fdd +#: ../../source/Instance_Setup/Instance_Setup.rst:274 +#: d2d277053c74470abc949b891493a5f0 #, fuzzy msgid "" "``forward_extension_tcp.py`` – forwarding messages, files, multiple " @@ -569,24 +571,24 @@ msgstr "" "使用每个客户端日志收集执行(``/command``)。 -``forward_extension_tcp.py`` - " "将消息、文件、多个文件、文件夹和多个文件夹转发到任意数量的目标客户端(``/send_msg_forward``、``/file_forward``、``/multiple_file_forward``、``/folder_forward``、``/multiple_folder_forward``)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:281 -#: 92e914da56f1402e85ef75819caf5b3f +#: ../../source/Instance_Setup/Instance_Setup.rst:282 +#: a8194174e5fd4dcf87ede716eaada9a4 msgid "" "Plain-message forwarding is native to the TCP protocol (no extension " "needed): the client-only command ``/forward_send_msg`` relays messages to" " the listed destination clients through the server." msgstr "纯消息转发是TCP协议的原生(不需要扩展) :仅客户端命令``/forward_send_msg ``通过服务器将消息中继到列出的目标客户端。" -#: ../../source/Instance_Setup/Instance_Setup.rst:286 -#: 836d703843ed4940a42f3b7a0c36b78e +#: ../../source/Instance_Setup/Instance_Setup.rst:287 +#: 98297b76f3404736b92b6c507726a50a #, fuzzy msgid "" "With ``is_extend_command=False`` (the default) the raw TCP protocol is " "started without these two built-in extensions." msgstr "使用“is_extend_command=False”(默认)仅启动原始 TCP 协议。" -#: ../../source/Instance_Setup/Instance_Setup.rst:289 -#: 3849c157ba79441e8406bcf9a4fc7695 +#: ../../source/Instance_Setup/Instance_Setup.rst:290 +#: fbbe2f02d9174359baca2c685704b475 msgid "" "Independently of ``is_extend_command``, every launch also loads the " "extension protocol files registered in ``PyFlow/added_extensions.json`` " @@ -594,15 +596,15 @@ msgid "" "``add_extension.load_registered_extensions``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:295 -#: fef96f9c96c64f6690b54175c7e7830d +#: ../../source/Instance_Setup/Instance_Setup.rst:296 +#: 9b5ab0319a9843f1b39721d3a96d1777 msgid "" "The ``is_input_command_in_console`` flag selects how the instance is " "started:" msgstr "``is_input_command_in_console`` 标志选择实例的启动方式:" -#: ../../source/Instance_Setup/Instance_Setup.rst:298 -#: 407ae406135b42b3a6efd4ba5242b296 +#: ../../source/Instance_Setup/Instance_Setup.rst:299 +#: 1ec730c995b1454da1b208331d9ca8fe #, fuzzy msgid "" "``True`` (default) – the instance's own start method " @@ -612,8 +614,8 @@ msgstr "" "`` True `` (默认) – `` START_TCP_SERVER () ``/`` START_TCP_CLIENT () " "``被直接调用,控制台输入循环在其自己的线程中运行。" -#: ../../source/Instance_Setup/Instance_Setup.rst:301 -#: 1e10d27ee5c04d69ac9de20031a68b31 +#: ../../source/Instance_Setup/Instance_Setup.rst:302 +#: 3cfb2eba312943cea85388f4e9faf40d #, fuzzy msgid "" "``False`` – the instance is started in a background thread and the " @@ -623,8 +625,8 @@ msgstr "" "直接调用“start_TCP_client()”,控制台输入循环在其自己的线程中运行。 -``False`` - " "实例在后台线程中运行,启动器使进程保持活动状态,直到实例停止(对于无头部署很有用)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:305 -#: 3743e0549b4449008324f68e282a0d81 +#: ../../source/Instance_Setup/Instance_Setup.rst:306 +#: 3b3482fa903f4afd81234e588a229c1f #, fuzzy msgid "" "Both extensions also expose injectable registration " @@ -639,48 +641,48 @@ msgstr "" "is_input_command_in_console=True)`` /``server_setup(instance=None, " "is_input_command_in_console=True)`` 接受现有实例,因此可以加载多个扩展从代码到同一个实例。" -#: ../../source/Instance_Setup/Instance_Setup.rst:314 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: ../../source/Instance_Setup/Instance_Setup.rst:315 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Internal Operation" msgstr "内部运作" -#: ../../source/Instance_Setup/Instance_Setup.rst:316 -#: 4ca266ef495b4a61bce44251b65f8c91 +#: ../../source/Instance_Setup/Instance_Setup.rst:317 +#: 8870bc6b731d40a095a40faed0c8f16d #, fuzzy msgid "" "Each instance is launched in a new terminal window (or background " "process)." msgstr "每个实例都在新的终端窗口中启动" -#: ../../source/Instance_Setup/Instance_Setup.rst:318 -#: 2b6246012ce84ec0945a9245b208ae95 +#: ../../source/Instance_Setup/Instance_Setup.rst:319 +#: 13c720a93ba54e8ca330fce3a078bb5b #, fuzzy msgid "" "The configuration is passed via a temporary JSON file to avoid shell " "escaping issues." msgstr "配置通过临时 JSON 传递" -#: ../../source/Instance_Setup/Instance_Setup.rst:320 -#: e40392b9adef407ca3ade4bf2d252190 +#: ../../source/Instance_Setup/Instance_Setup.rst:321 +#: 9566eb3cb70e4b77bcbdb584f7e0b6fc #, fuzzy msgid "" "If an instance fails to start, the error is displayed and the window " "pauses for inspection." msgstr "显示并且窗口暂停以进行检查。" -#: ../../source/Instance_Setup/Instance_Setup.rst:324 -#: 2d7f7f35978a449995958b44730759d3 +#: ../../source/Instance_Setup/Instance_Setup.rst:325 +#: 5f0f0f6a41384356986a1182f14a0a4c msgid "Requirements" msgstr "要求" -#: ../../source/Instance_Setup/Instance_Setup.rst:326 -#: ddf48eb8fc2d48f9adbc38a39965ec22 +#: ../../source/Instance_Setup/Instance_Setup.rst:327 +#: 49ceb74e41104b00971cd9edecef08ae #, fuzzy msgid "Python 3.10+" msgstr "Python 3.6+" -#: ../../source/Instance_Setup/Instance_Setup.rst:327 -#: 9bc8a330f1384ade97e4ee55efa58e6b +#: ../../source/Instance_Setup/Instance_Setup.rst:328 +#: 1d80811611c944f9bf772364ab45d1e4 msgid "" "The ``PyFlow.network_api.connect_tcp`` module must be importable (the " "script imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." @@ -784,3 +786,26 @@ msgstr "" #~ msgid "and ``TCP_Client_Base`` from there)." #~ msgstr "和来自那里的“TCP_Client_Base”)。" +#~ msgid "" +#~ "**Both lists may contain any number " +#~ "of objects.** Every entry is completed" +#~ " with the default value of each " +#~ "parameter that the entry does not " +#~ "set. The stored server entry therefore" +#~ " carries ``host``, ``port``, ``max_clients``, " +#~ "``port_add_step``, ``port_range_num``, " +#~ "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " +#~ "``is_input_command_in_console``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, " +#~ "``is_asynic_clients_io``, ``is_debug`` and " +#~ "``is_print_log``; the client entry carries " +#~ "``host``, ``client_host``, ``port``, " +#~ "``client_port``, ``timeout``, ``port_add_step``, " +#~ "``max_thread_num``, ``is_input_command_in_console``, " +#~ "``is_wait_server``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, ``is_debug`` " +#~ "and ``is_print_log``." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po b/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po index 131cbfa..2f3c73f 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,54 +20,54 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Client_APIs.rst:2 -#: 6dd11dd380344faabc9dea6d41655b1c +#: 596423c8d92e4592b221947ca5595ea7 msgid "The TCP Client APIs" msgstr "TCP 客户端 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:5 -#: 2d8b31ea476c498188b1d3df403c2402 +#: bf347a93657146d6b019250273bc439c msgid "TCP Client setup API" msgstr "TCP 客户端设置 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:7 -#: d699c50b2310495bb2521c5da6d30543 +#: 7e3dc9343f554fc181d2c2853898916c msgid "" "The TCP Client Setup API is used to create a TCP client. The client in " "the protocol is usually used to connect to the TCP server and exchange " "data with the server." msgstr "TCP 客户端设置 API 用于创建 TCP 客户端。协议中的客户端通常用于连接TCP服务器并与服务器交换数据。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:34 -#: 5505d653e132458686537e957323bb9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 +#: fb61c59ca5e646f3b749359b2ea13a40 msgid "" "The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The" " parameters of the ``__init__`` method are as follows:" msgstr "TCP 客户端设置 API 在“TCP_Client_Base”类中定义。 ``__init__``方法的参数如下:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:37 -#: 6a41dd3d0f00421b914a6ae9e588d6b8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 +#: d8b55d105dd144198594dd4f454fe5c5 msgid "``host``: The server host IP address to connect to." msgstr "``host``:要连接的服务器主机 IP 地址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 -#: cc6ddd6c80bb46f3b393c9882e096a0a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 +#: ee9f5f584e6643529cdca91384562ebf msgid "``client_host``: The local host IP address to bind the client socket to." msgstr "``client_host``:将客户端套接字绑定到的本地主机 IP 地址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:39 -#: 949c21452bb94effa6c13959868ac90f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 +#: 03357b8c2f974a419c6933d68976b6eb msgid "``port``: The server port number to connect to." msgstr "``port``:要连接的服务器端口号。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:40 -#: 97c56df67b0c435aaf8ee89bea56266b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 +#: cd50ed1b09934f3bae2a4c615187d157 msgid "" "``client_port``: The local port number to bind the client socket to " "(``None`` means let the OS choose)." msgstr "``client_port``:将客户端套接字绑定到的本地端口号(``None`` 意味着让操作系统选择)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 -#: 309676fc53ff4cd39a8d9e200c54f1bf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 +#: f8cdf36b87834ea7a95209d2ca048332 msgid "" "``timeout``: The socket timeout in seconds for connection and receive " "operations. ``None`` (the default) is not \"no timeout\": the socket then" @@ -75,41 +75,41 @@ msgid "" " receive loop (it simply continues)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 -#: 9bf924fa535a44e78c98664e8d2b304f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 +#: 20c7ea1afac14f80a2b739cb6ae1957f msgid "" "``port_add_step``: The step size for incrementing the port number (used " "only in manual allocation mode)." msgstr "``port_add_step``:增加端口号的步长(仅在手动分配模式下使用)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 -#: 5abb7f5137714757b6957a177747d1e5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 +#: eb06f09e560543e5ba0abb3627a63585 msgid "" "``max_thread_num``: The maximum number of threads for concurrent file " "transfer operations." msgstr "``max_thread_num``:并发文件传输操作的最大线程数。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 -#: e71bd35480184667a6390f2a28c0894a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:48 +#: 5ff72dc0ec90411bb0d20f618d015093 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console (interactive mode)." msgstr "``is_input_command_in_console``:指示是否在控制台中输入命令的标志(交互模式)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 -#: f4dd649db47842fdb7b64e39d5887cdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:49 +#: 5e12aa05eb854b15b0b6779b40b5a302 msgid "" "``is_wait_server``: A flag indicating whether to keep retrying connection" " until the server is available." msgstr "``is_wait_server``:指示是否继续重试连接直到服务器可用的标志。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 -#: 69c7bfb0cc784e9a817d98096357d9d6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:50 +#: b3232047b364478caad5b3e5361e71be msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``:自定义工作线程的最大数量。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 -#: 892ac76eabb04f90b9c95f29009b6c11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 +#: a951c5564286432082b3e6a06aae8a48 msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the client itself by calling " @@ -117,8 +117,8 @@ msgid "" "register its commands first and connect later." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 -#: 0cfe21e428fd45f08a9d8c080c285535 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:55 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-" @@ -127,8 +127,8 @@ msgstr "" "“is_enable_encrypto”:指示与服务器交换的消息是否经过 RSA 加密的标志(请参阅 tcp-client-encrypted-" "channel-api)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:53 -#: 353688102eb6441ebf87384e57f0c661 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 +#: 8ac8a71ca8564a89bb52f882c4fedefc msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -138,8 +138,8 @@ msgstr "" "``is_custom_keys``:可选的``[pub_key_path, pvt_key_path]`` 用户提供的 RSA " "密钥对。两个文件都必须存在,解析为 PEM,并且相互配对;无效的对将被默默地忽略,并使用默认的键查找(``None`` 保留默认查找)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 -#: 0176e8b8b8ea44c396d55657d74a91cd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:61 +#: c01569233a864bf0b106a877fb924c27 #, fuzzy msgid "" "``max_mem_buff``: The buffering ceiling in MiB, stored as bytes " @@ -147,8 +147,22 @@ msgid "" " client's forward path does not read it today. The default is 2048." msgstr "`` max_mem_buff `` :默认值为`` 2048 `` (与服务器类保持奇偶校验;客户端的前向路径今天不读取它)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:60 -#: 276f7755eaea4b808ad6cfe985eaa8aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:64 +#: 10fb41da1af34a539a962083252bdf55 +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 +#: 1b569fa80b59490dacc6bcdf3a924d60 +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 +#: ac73e6da7c3044f1bf68aff504142765 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the client logs command content and execution results only;" @@ -157,8 +171,8 @@ msgstr "" "`` is_debug `` :选择记录多少详细信息的标志。使用`` False `` (默认值) ,客户端仅记录命令内容和执行结果;使用`` " "True `` ,客户端还记录执行过程的关键步骤。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:63 -#: 58a790ecb724454298659bf9831fb2ae +#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_print_log``: A flag indicating whether the client logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." @@ -166,70 +180,102 @@ msgstr "" "`` is_print_log `` :指示客户端是否记录所有日志的标志。对于`` False `` ,它不打印任何内容,无论`` " "is_debug ``说什么。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 -#: 36eebcb4edbb4f1e96862b64762c4d6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 +#: fa251d2893fa413aac9d5e525df18209 +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when the " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:85 +#: 3a9f1a8e8b8f45dbb9011b3b0e28cd92 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:93 +#: 3272388be97643f98bada0a995516141 msgid "Every parameter has default values:" msgstr "每个参数都有默认值:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 -#: 4a2b0f17cb4f47669a8dcb3734c17468 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:95 +#: 9fd3d516d31841fd9054a2a3dfcb1ac4 msgid "``host``: Default is ``None`` (must be provided before connecting)" msgstr "``host``:默认为``None``(必须在连接前提供)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:69 -#: 7dea100856734d3ba4ee6352d45cc554 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:96 +#: ece6c7a48ae74f86b6e207d960c6daa2 msgid "``client_host``: Default is ``'127.0.0.1'``" msgstr "“client_host”:默认为“127.0.0.1”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:70 -#: e646757cb9d1425fa72970698c2938e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 +#: 8a9d85bb281e43e69ea0ae48363fb8da msgid "``port``: Default is ``65432``" msgstr "“端口”:默认为“65432”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 -#: 4c232543227544acae211825b01a795a -msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" -msgstr "“client_port”:默认为“None”(操作系统分配临时端口)" +#: ../../source/Network_APIs/TCP_Client_APIs.rst:98 +#: 4653721a3e8143fea8a43899bb0e6437 +msgid "" +"``client_port``: Default is ``None`` (OS assigns ephemeral port). A " +"configured port that cannot be bound — a session that just ended can hold" +" it in the operating system's ``TIME_WAIT`` — is reported and the " +"connection is made from an OS-assigned port instead." +msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:72 -#: 3c772d5ab49243b993d5dfea9af5d472 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:102 +#: 4439e99a222744a9bca762b5f14b4d74 msgid "``timeout``: Default is ``None``" msgstr "“超时”:默认为“无”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:73 -#: 501a6c2966d2470cbf9ce2a8909ef130 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 +#: 0b0f6a9551ff4bf28ad02095893db9d8 msgid "``port_add_step``: Default is ``1``" msgstr "“port_add_step”:默认为“1”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 -#: 697656b4cb24453c89b1a848299e4167 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:104 +#: bcb1ee681a0f47319338faf71a99adf7 msgid "``max_thread_num``: Default is ``10``" msgstr "“max_thread_num”:默认为“10”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:75 -#: 632284d8c9b349f89018f8a19ce9662e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:105 +#: 08471d033b174cf395292c36068d4cb8 msgid "``is_input_command_in_console``: Default is ``True``" msgstr "“is_input_command_in_console”:默认为“True”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:76 -#: ec7a8bd80ad2471d9208999fc34792f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:106 +#: bbf2ad3b5e4340c9b481f8af135281e2 msgid "``is_wait_server``: Default is ``True``" msgstr "``is_wait_server``:默认为``True``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:77 -#: c036a352181d422894b56b0c14167bdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:107 +#: 63f2004d0c5b4fef8cf23eaa7be020b1 msgid "``max_custom_workers``: Default is ``10``" msgstr "“max_custom_workers”:默认为“10”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:78 -#: 64df1f8395ca45d497875fb232c71b0e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:108 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_client()`` automatically)" msgstr "“is_extend_command”:默认为“False”(当“True”时,“__init__”不会自动调用“start_TCP_client()”)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:80 -#: ca18c257b4054fad931a19b59a8a4606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:110 +#: c723e855f50a4ec3abf45aaae2e02f45 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, the client " "performs an RSA public-key exchange with the server right after " @@ -238,8 +284,8 @@ msgstr "" "“is_enable_encrypto”:默认为“True”(当“True”时,客户端在连接后立即与服务器执行 RSA " "公钥交换,并且所有后续消息都被加密)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:83 -#: 0c6ecb6d7f504ef8a9a666bc2659a009 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:113 +#: 16c586bc40d94d6b9624812993e12579 msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -248,36 +294,71 @@ msgstr "" "``is_custom_keys``:默认为``None``(``[pub_key_path, pvt_key_path]`` " "列表使用用户提供的密钥对而不是默认的``~/.ssh``/生成的密钥)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:86 -#: 96c8a6add16d4a999f8910133dad83b4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:116 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "`` is_debug `` :默认值为`` False `` ( `` True ``将执行过程行添加到命令/结果行)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:88 -#: 4ea3ee5f013c46c98a380ed9fa7b6e64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:118 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "client would print)" msgstr "`` is_print_log `` :默认值为`` True `` ( `` False ``会使客户端打印的每一行保持沉默)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:90 -#: a1d9d8ceda754443aef4e9dd2031e754 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:120 +#: 58fc5a7851094fcba7903d9e6cd4e8e7 msgid "" "``max_mem_buff``: Default is ``2048`` (kept for parity with the server " "class; the client's forward path does not read it today)" msgstr "`` max_mem_buff `` :默认值为`` 2048 `` (与服务器类保持奇偶校验;客户端的前向路径今天不读取它)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:94 -#: 930f7b1c90474a16b2dc7d13c41c238c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:123 +#: 08471d033b174cf395292c36068d4cb8 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "“max_custom_workers”:默认为“10”" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 +#: ff70e67852154092b227e2f05357a78d +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:125 +#: bd7d9bb9bbe14bc38eed56c574fc0987 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:127 +#: 5282067c345342d4872377ec83b3ba95 +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 +#: d10be044603c42e9a26b3164dcb7cb51 +msgid "" +"``is_auto_reconnect``: Default is ``False`` (``True`` makes " +"`start_TCP_client` reconnect after the connection drops and resume the " +"interrupted transfers, see :ref:`transfer-pause-and-reconnect`. The dead " +"session's socket is closed abortively first, so a configured " +"``client_port`` can be bound again — Windows refuses it otherwise)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:135 +#: 4b99048b2ec14a988fd9b83b23284d25 msgid "" "The TCP Client Setup API will initialize all the necessary parameters and" " resources for the TCP client." msgstr "TCP 客户端设置 API 将为 TCP 客户端初始化所有必需的参数和资源。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 -#: 221e218700a34372ae96eae9189831aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 +#: b7da2a334a9543aa96178bddc8b6855c msgid "" "*Note: In the main class of the TCP client setup API, we initialize the " "`start_TCP_client` method to set up all functions which are needed in the" @@ -287,8 +368,8 @@ msgstr "" "*注意:在 TCP 客户端设置 API 的主类中,我们初始化 `start_TCP_client` 方法来设置 TCP " "客户端所需的所有功能,包括连接到服务器、处理传入消息和管理用户输入。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 -#: 00cb8ca5027d464f88e778a8f2a4faec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 +#: 0aa6b4133bf54878ad5d35aa8523ae88 msgid "" "*Note: By default ``TCP_Client_Base.__init__`` calls " "``start_TCP_client()`` to connect and enter interactive mode. If you set " @@ -298,16 +379,16 @@ msgstr "" "*注意:默认情况下``TCP_Client_Base.__init__`` 调用``start_TCP_client()`` " "进行连接并进入交互模式。如果您设置“is_extend_command=True”,实例将不会自动启动,您应该在准备好时手动调用“start_TCP_client()”。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:109 -#: 4d8f352fa0be45e1b75d44727035e828 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 +#: 7a35992f8c7c410da60029bb06fb054a msgid "" "*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must" " be ``None``. The constructor will raise a ``ValueError`` if " "``is_wait_server`` is ``True`` and ``timeout`` is not ``None``.*" msgstr "*注意:如果设置“is_wait_server=True”,则“timeout”参数必须为“None”。如果“is_wait_server”为“True”且“timeout”不是“None”,则构造函数将引发“ValueError”。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:119 -#: 92cea23fb57c482cb1199cabd89af968 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 +#: 35b6f81f408041c4a7e650d3b92957d1 msgid "" "In the `start_TCP_client` method, we first attempt to connect to the " "server by calling the `connect` method. If the connection fails and " @@ -315,8 +396,8 @@ msgid "" "it will exit." msgstr "在`start_TCP_client`方法中,我们首先尝试通过调用`connect`方法连接到服务器。如果连接失败并且“is_wait_server”为“True”,客户端将不断重试;否则它将退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 -#: 2e529671abf848fd87771801ae4a3763 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:165 +#: d8e70dde1c62462cb4954eb1ceb50f3a #, fuzzy msgid "" "*Note: The client socket is created in the `connect` method (called by " @@ -325,8 +406,8 @@ msgid "" "client instance.*" msgstr "*注意:在`start_TCP_client`方法中创建的客户端套接字基于IPv4,并使用创建客户端实例时提供的参数“self.host”和“self.port”。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 -#: abe7c8d5d59b4a589ec6537a06a7333b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:170 +#: 80f69db837ec4e1d9bb90bc821019532 msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will either start the interactive input loop " @@ -334,16 +415,16 @@ msgid "" "input)." msgstr "其次,根据“self.is_input_command_in_console”参数,我们将启动交互式输入循环(“interactive_mode”)或简单地保持连接处于活动状态(无控制台输入)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:134 -#: e6ad1c25ef6e409aa4dba10b44fbe7a4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 +#: 445af010e93f421099da8d8dd5212210 msgid "" "After that, if the interactive mode is enabled, the client will read user" " input from the console and send messages to the server until the " "connection is closed." msgstr "之后,如果启用了交互模式,客户端将从控制台读取用户输入并向服务器发送消息,直到连接关闭。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 -#: c957271185064b21a0bc78265e007969 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:179 +#: 2d4020f99c3c4a4485815c383a0a4bfe msgid "" "*Note: There is a global variable ``self.running`` which is set to " "``True`` after the client successfully connects to the server. The " @@ -353,8 +434,8 @@ msgstr "" "*注意:有一个全局变量“self.running”,在客户端成功连接到服务器后,该变量将变为“True”。 " "“self.running”变量用于控制主接收循环,当客户端关闭时它将变为“False”。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 -#: d055f0b3b19940be8b0549705d6cd3b5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:185 +#: e4de5ae390fc4c1c9a50703299f80356 msgid "" "The `connect` method will try to establish a TCP connection to the " "server. If a ``client_port`` is specified, the client will bind to that " @@ -365,47 +446,47 @@ msgstr "" "`connect` 方法将尝试建立到服务器的 TCP " "连接。如果指定了“client_port”,客户端将在连接之前绑定到该本地端口。该方法将优雅地处理超时和连接拒绝错误,特别是当启用“is_wait_server”时。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 -#: 4615e65c81854301ac43f16a4d7e16b1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 +#: 17315c7599be4d2e8d8f62ad4c866eb3 msgid "" "When the connection is established, a background thread " "`receive_messages` is started to continuously read data from the server." msgstr "当连接建立后,会启动一个后台线程receive_messages,不断从服务器读取数据。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:154 -#: bace28ef9c5841ffac04669beeb4e56a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:195 +#: 26bc6f1cf62947c88fd9de780337d225 msgid "So what can the setup function do if the connection fails?" msgstr "那么如果连接失败的话setup函数可以做什么呢?" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:156 -#: f89e08eff4f84bfba70ee321e26e218b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:197 +#: e7519cc6a4124a008a804ecbe9b10453 msgid "" "First, if the connection attempt times out, the client will either wait " "and retry (if ``is_wait_server`` is ``True``) or exit with an error." msgstr "首先,如果连接尝试超时,客户端将等待并重试(如果“is_wait_server”为“True”)或错误退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 -#: fe3484d9a2b04f29944bc0d412d73536 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:201 +#: 2bcc61a302d34c7dbc18f9bcc7beba5a msgid "" "Secondly, if the server is not running (connection refused), the " "behaviour is the same: retry or exit based on ``is_wait_server``." msgstr "其次,如果服务器未运行(连接被拒绝),行为是相同的:根据“is_wait_server”重试或退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:164 -#: 18131d4fd10c42d09e1eca9697bda2fb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:205 +#: c33c7409acd94d6b8f69e0f718e50c1f msgid "" "If any other socket error occurs, the client will print the error message" " and return ``False``, and the `start_TCP_client` method will call " "``sys.exit(1)``." msgstr "如果发生任何其他套接字错误,客户端将打印错误消息并返回“False”,并且“start_TCP_client”方法将调用“sys.exit(1)”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:168 -#: 050d63fcb50c4053aba93e3d05dae63c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:209 +#: d78f849334b6404d8840b12839d05b8c msgid "For shutting down the client, the `close` method is defined as:" msgstr "为了关闭客户端,“close”方法定义为:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 -#: c0860fa6e2c240e5a2a56b278f3369f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 +#: 4b23bb29324b408ca1a3c06128ede442 #, fuzzy msgid "" "In the `close` method, we set ``self.running`` to ``False``, free any " @@ -414,8 +495,8 @@ msgid "" "client socket. This ensures a clean disconnection." msgstr "在“close”方法中,我们将“self.running”设置为“False”,通过调用“free_port”释放所有分配的端口,然后关闭客户端套接字。这确保了干净的断开。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:180 -#: 6a703de12132431982451a11b661b4d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:221 +#: 510de5709a444a0c8296717f1e8bed2b msgid "" "``close`` also wins against a connection attempt that is still in flight:" " if it runs before ``connect`` puts the socket up, that call closes the " @@ -423,118 +504,118 @@ msgid "" "client." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:184 -#: ae54449f52b0491aaeb0c11de7749e4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:225 +#: c67deae0af3b4ab9bf572198122cc09d msgid "" "*Note: The `free_port` method works similarly to the server side, " "releasing any manually allocated ports if manual allocation mode is " "enabled.*" msgstr "*注意:“free_port”方法的工作方式与服务器端类似,如果启用了手动分配模式,则释放任何手动分配的端口。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 +#: fbb5ed3c54a34df4bc6bf8f9688e295c msgid "TCP Client handling information API" msgstr "TCP客户端处理信息API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:193 -#: 57895cdce9c1426289087c4448ac2325 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 +#: 7c21a424a7774ad6b4a257c5ad645db4 msgid "" "The client handling information API documents the core TCP client methods" " that manage the server connection, receive raw data, and send messages." msgstr "客户端处理信息 API 记录了管理服务器连接、接收原始数据和发送消息的核心 TCP 客户端方法。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:198 -#: f9294ef58d274a9ba6b8edbec8c07606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:239 +#: b0fc366cad48412999e75faf81120a6e msgid "" "Unlike the server, the client maintains only a single connection and does" " not provide broadcast or ``send_msg_to_specific_client`` methods." msgstr "与服务器不同,客户端仅维护单个连接,并且不提供广播或“send_msg_to_specific_client”方法。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:208 -#: 67e867cdfba84730bef1ad32d859ea24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:249 +#: ff50f500c3804fdb9562b5e9ae1a3482 msgid "" "`receive_messages` is the main background thread function in " "``TCP_Client_Base``. It is started after a successful connection and is " "responsible for:" msgstr "`receive_messages` 是 `TCP_Client_Base` 中的主要后台线程函数。它在连接成功后启动,负责:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:212 -#: 17684d40e43543e88db7135b66b26e09 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 +#: 364f1d2b080843518fee4bcc0e74a8ca msgid "" "continuously receiving raw bytes from the server socket using " "`receive_message`" msgstr "使用“receive_message”连续从服务器套接字接收原始字节" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:213 -#: dc882668c1244dc3b7e57b07ad08612a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:254 +#: cf3b7cf194ec42919b87199c4586dfc4 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "缓冲传入数据,直到换行符终止的消息完成" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:214 -#: 707313e8051245478059aa883da7459f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:255 +#: ad695c0a732a4ad78cdd07c79f2d5dc3 msgid "splitting and processing each message line-by-line" msgstr "逐行拆分和处理每条消息" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:215 -#: e9edeedb0eb64a278e03efa5169a36f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:256 +#: 387a605c25f8407d86b77c452ded00f7 msgid "" "routing special commands (starting with ``/``) that come from the server " "to `handle_server_command`" msgstr "将来自服务器的特殊命令(以“/”开头)路由到“handle_server_command”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 -#: 0ab735831831448a88f60538f859ce4e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:257 +#: d1729cfa1e314df68d3e7ce7e553f3a5 msgid "" "printing every received line to the console with a ``[server]`` prefix " "(command lines included, after ``handle_server_command`` has processed " "them)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:218 -#: e09f439632994d0fadb0ae8f58eef0cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:259 +#: 083b077c5c1845338f11ae62bace15b5 msgid "" "unwrapping forwarded lines (``/send_msg_from``) so a message another " "client forwarded here is attributed to its author" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:220 -#: 166f9028c1cc41ff94be560b77e17504 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:261 +#: 1dd20cbdeac3480bbaec2f7ae6f1f1ed msgid "" "handling connection resets and other socket errors, and cleaning up when " "the server closes the connection" msgstr "处理连接重置和其他套接字错误,并在服务器关闭连接时进行清理" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:229 -#: db2e058412bc44d6ba39131b3b40a7ac +#: ../../source/Network_APIs/TCP_Client_APIs.rst:270 +#: e890dee4fb944eeaa9e6b2cf3cd9047a msgid "" "In `handle_server_command`, the client processes built-in commands sent " "by the server, such as:" msgstr "在`handle_server_command`中,客户端处理服务器发送的内置命令,例如:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:273 +#: b957ec8457f34618802ea0441634a894 #, fuzzy msgid "" "``/client_alloc_port_range``: configures the client's manual port " "allocation range from the line the server sends it on connect." msgstr "``/client_alloc_port_range``:根据服务器广播配置客户端手动端口分配范围。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 -#: 2558e50f505a4b6ca51c7a44fa9ad957 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:275 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/server_file_transfer_port``: receives the file transfer port assigned " "by the server for an ongoing file operation." msgstr "``/server_file_transfer_port``:接收服务器为正在进行的文件操作分配的文件传输端口。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:236 -#: 5147df6f2f794cf2949b7cef1ed24791 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:277 +#: 4eb4fe22d5db4b56b622dfd29459c3b7 msgid "" "``/file`` and ``/file_folder``: handle file transfer requests initiated " "by the server (server-to-client transfers)." msgstr "``/file`` 和 ``/file_folder``:处理服务器发起的文件传输请求(服务器到客户端传输)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:238 -#: 4755bb63eb0e4f8cbf481633417fc3c7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:279 +#: 3c550345aa484cb8bc44681842864044 msgid "" "``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``," " ``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the " @@ -542,15 +623,15 @@ msgid "" "the connection." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:242 -#: f7cbe268c5e84987aec0bb18a0a81aa7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 +#: 31a62335177b49a19f708aee2aa5b0b1 msgid "" "``/forward_upload``, ``/pause_trans``, ``/start_trans``, " "``/forward_error``: forwarding and transfer-control messages." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:245 -#: d89b63a85c3d402fbb0df0f75edc4736 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:286 +#: b4c3c6ea61f344b8a3d3baf6b659d9c7 msgid "" "If you have registered custom commands using the command extension API, " "`handle_server_command` will also check if the incoming command matches " @@ -559,48 +640,48 @@ msgstr "" "如果您使用命令扩展 API " "注册了自定义命令,“handle_server_command”还将检查传入命令是否与任何已注册的处理程序匹配并相应地执行它。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:250 -#: 943d4fb64bad477f969403f360288769 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 +#: 4b6cc84b10d34254b7e6e0d7ae226ddc msgid "" "*Note: For more details of the command extension API, see the :ref:`tcp-" "client-command-api` section.*" msgstr "*注意:有关命令扩展 API 的更多详细信息,请参阅 :ref:`tcp-client-command-api` 部分。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 -#: c2b4ba39cca64ea7ab62a59d016f0544 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:294 +#: b9ff85e2f76d4c1697602ebf69fed3a8 msgid "" "Closing the connection when the server goes away is not part of " "`handle_server_command`: it is `receive_messages` that reports the " "disconnect and clears ``self.running``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:265 -#: 9312fc5109a547d588d98c16a9b79c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:306 +#: 4376aa47bf63490998e7008547d0c86f msgid "" "`receive_message` is identical to the server version: it reads up to " "``msg_length`` bytes from the given socket and returns the raw byte " "payload. Message decoding and newline framing are handled by the caller." msgstr "“receive_message”与服务器版本相同:它从给定套接字读取最多“msg_length”字节并返回原始字节有效负载。消息解码和换行帧由调用者处理。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:278 -#: 7a64cec6a8084261a443f57f7032a5bb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:319 +#: 29b51f413be748e4b101bf498e593ef2 msgid "" "`send_message` sends data from the client to the server. It verifies the " "client is still running and the socket is valid, then:" msgstr "`send_message` 将数据从客户端发送到服务器。它验证客户端仍在运行并且套接字有效,然后:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:281 -#: 9a5d3a7c041b47d68b80186e09492467 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 +#: e4158824d7b04b37a0f75c9ff67eab45 msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "接受“str”和“bytes”消息负载" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:282 -#: c4247339bf084481af72ba498d8f9bcd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:323 +#: ea9158c1798941cb9df13f5a01b14f69 msgid "trims string payloads and appends a newline if missing" msgstr "修剪字符串有效负载并在丢失时附加换行符" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 -#: 55c0dfde024b4bdea57da54d86297dbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:324 +#: 0fb0befad2844821a59b8c5c686e1c39 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -610,59 +691,60 @@ msgstr "" "当套接字处于加密模式时(公钥交换已完成),明文使用“_VALID”标记进行签名,RSA-" "OAEP使用服务器的公钥加密,base64编码并以换行符结尾,而不是以明文形式发送" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:287 -#: 6e2bbc8edbad40568dfe3eae781ab27c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:328 +#: e8d7a04011e74da18b274e1ad3ca3ab8 msgid "encodes string payloads as UTF-8" msgstr "将字符串有效负载编码为 UTF-8" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:288 -#: 40b2936e9c6b4325b19b27f83932cf83 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:329 +#: 08c9e9aca2334e67b5051b42cc7dbad0 msgid "sends the complete message with ``client_socket.sendall(data)``" msgstr "使用“client_socket.sendall(data)”发送完整消息" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:289 -#: 9ab8a09e5ca4416abd843cf1612f20a2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:330 +#: 99b4f8d523b2406499891c514befc372 msgid "" "returns ``True`` on success, otherwise logs the error and returns " "``False``" msgstr "成功时返回“True”,否则记录错误并返回“False”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 -#: 0eb535b8380441869c432950417def80 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:332 +#: 18101652b1e34996866324fce0aa8a4d msgid "" "The client also provides an interactive input loop (`interactive_mode`) " "that reads user input from the console and sends messages to the server." msgstr "客户端还提供交互式输入循环(“interactive_mode”),用于从控制台读取用户输入并将消息发送到服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:298 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:339 +#: fbb5ed3c54a34df4bc6bf8f9688e295c #, fuzzy msgid "TCP Client inbound event listener API" msgstr "TCP客户端文件传输API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:300 -#: 8b78c521249c4604933d30cfc99cc7a9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:341 +#: 15461ca186ed497083b901e65a3b33d1 msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:310 -#: 2f13976d605042919a1a19e346d85bd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:351 +#: 0d916f8d3eaf4336b5be87a5faf153a3 msgid "" "``add_message_listener`` registers ``listener(sender_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to `handle_server_command` instead). ``sender_id`` is the author's " -"``\"ip:port\"`` — for a message another client forwarded here through the" -" ``/send_msg_from`` envelope it is the forwarding client, and it is " -"``None`` for a direct push from the server. ``add_file_listener`` " -"registers ``listener(client_id, full_path, name, size, command)`` and " -"fires after a file sent by the server has been fully written to disk. " -"Both listeners run on a protocol thread, so they must not block, and an " -"exception inside a listener is logged and swallowed. The ``remove_*`` " -"counterparts unregister a listener and ignore unknown ones." +"every inbound line, commands included, so a listener observes all inbound" +" traffic; a message another client forwarded here through the " +"``/send_msg_from`` envelope is reported as its payload. ``sender_id`` is " +"the author's ``\"ip:port\"`` — the forwarding client for such a forwarded" +" message, and it is ``None`` for a direct push from the server. " +"``add_file_listener`` registers ``listener(client_id, full_path, name, " +"size, command)`` and fires after a file sent by the server has been fully" +" written to disk. Both listeners run on a protocol thread, so they must " +"not block, and an exception inside a listener is logged and swallowed. " +"The ``remove_*`` counterparts unregister a listener and ignore unknown " +"ones." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 -#: 75d993e34b944014be1b88aee03a4f9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:364 +#: 196be233dc00497a94ee87f9999a9897 msgid "" "Received messages and events are also stored per sender socket in " "``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -671,13 +753,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``close`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:331 -#: 6535dcf4080e4090bf82df637e452cc6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:373 +#: 6d52a0605748445694e0f4b1a6c52ea7 msgid "TCP Client encrypted channel API" msgstr "TCP客户端加密通道API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:333 -#: e2dbda95b2ff4483b8b71394ae4b83c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:375 +#: 14a20833906f4e18b92856c3e98a8886 msgid "" "When the client is created with ``is_enable_encrypto=True`` (the " "default), it performs an RSA public-key exchange with the server " @@ -686,13 +768,13 @@ msgstr "" "当使用“is_enable_encrypto=True”(默认值)创建客户端时,它会在连接后立即与服务器执行 RSA " "公钥交换,然后再对任何消息内容进行加密。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:338 -#: 411e33f708ba4961aaf9073beffe7404 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:380 +#: 46166a685e064cd29ad7701d3a352fc4 msgid "Key material" msgstr "关键材料" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:340 -#: 89d96a4b9abe4ccd98bdd72682b94a56 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:382 +#: ffdef9bf79aa41e6a401b0a16c24a674 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -704,8 +786,8 @@ msgstr "" "私钥存在于“~/.ssh/id_rsa”中,则它会被重用;否则,将在“network_api/.Flow/pvt_key”(“client_priv.pem”/“client_pub.pem”)中生成新的" " RSA-2048 密钥对。交换的公钥始终源自私钥,因此会自动选取旋转的“~/.ssh”对。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:345 -#: 74eb9aca2b1849e48138cbea3e76a39d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 +#: 2c27cfc2e8ce47fb8732aec1e00d3479 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -716,8 +798,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:352 -#: e935794dae5f4c2682336e72732afec3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:394 +#: 425ba3d582c3490b9375d99baa9b61e6 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -729,8 +811,8 @@ msgstr "" "pvt_key_path]”强制用户提供的密钥对:两个文件必须存在,解析为 PEM " "并相互配对(使用公钥加密的探针必须使用私钥解密);无效的对将被忽略并使用默认查找。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:357 -#: 72a43fff94f04914848603d6ede43cfd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:399 +#: 696441cc5dd44fc4af958c547c8b6b90 msgid "" "Public keys received from the server are cached in " "``network_api/.Flow/pub_key`` as ``server__.pem`` (the server " @@ -740,13 +822,13 @@ msgstr "" "从服务器接收到的公钥以“server__.pem”形式缓存在“network_api/.Flow/pub_key”中(密钥来自的服务器端点;“:”被替换为“_”,因此" " IPv6 文字在每个平台上都是安全的,包括 Windows)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:363 -#: a4903fbcbc6f4c9d93c8fc3066fcc1c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:405 +#: 2a81e756d1c947d384d20dbbbe5d6d52 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM 身份检查 (TOFU)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:365 -#: e30dc3b276654ea2b6ec48793d8df984 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:407 +#: 7a915eef76594c3ea715adb845fcabc6 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -759,31 +841,31 @@ msgstr "" "每个连接都以明文形式重新交换公钥,并且每一方都会在“network_api/.Flow/pub_key/pub_key.json”中记录对等点:密钥是“(ip," " port)”(对等点可到达的端点的 Python 元组),值是“[<公钥的 sha256>, <公钥 PEM>]”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:372 -#: 247a92c41f0d45ed9a5f8ad2d12bca2e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:414 +#: 4d56fbd290604113a600a56d8e89cdfb msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "来自端点的首次连接:密钥被记录并受信任(首次使用时信任)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:374 -#: 7adc6b725e7244df8bc1b861b4cec80c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:416 +#: a6be8828e0594ddc8aa71229934cc73d msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " "``(ip, port)`` instead of being duplicated." msgstr "稍后的连接显示*相同*密钥:已接受。如果端点更改(动态 IP / 用户更改的端口),记录将移动到新的“(ip,端口)”而不是重复。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:377 -#: ba6d10fef7fb42cd8dd6518c415762d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 +#: fda350faac9a4efd82575a386fc929c0 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is received and " "the client closes)." msgstr "稍后的连接为已记录的端点提供*不同的*密钥:连接被拒绝(收到“/crypto_reject”并且客户端关闭)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:381 -#: 7f2ec5e5c2604098906635697130c4fd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:423 +#: 9d62655e00324c518633c6c1d615d515 msgid "" "The client-side record is keyed by the fixed server address, so a server " "that changes its public key (for example a MITM substitution) is always " @@ -793,13 +875,13 @@ msgstr "" "客户端记录由固定服务器地址作为密钥,因此更改其公钥(例如 MITM " "替换)的服务器在以后的连接中始终会被拒绝。要重置信任(轮换密钥、新服务器),请删除“pub_key.json”条目(或整个文件)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 -#: 9a08bf51aea742de8d0a0f351d055b3a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:429 +#: 799c58ee59b0416688562166f58a14c1 msgid "Handshake" msgstr "握手" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:389 -#: 879e1be6d2de4859bc0777d1cd1682f8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:431 +#: 6f92afe3b8314a9985b62fe55cdeee70 #, fuzzy msgid "" "Right after connecting, the client announces its encryption mode with a " @@ -807,47 +889,75 @@ msgid "" "server's answer; a mode mismatch closes the connection. It then sends a " "plaintext ``/crypto_key_exchange `` greeting; the server " "replies with ``/crypto_key_exchange_ack " -"``. Both sides then push their public key files over the file-" -"transfer mechanism (plaintext) and TOFU-check the received key. Both " -"sides switch to encrypted mode only after ``/crypto_ready`` has been " -"received from the peer (so plaintext and ciphertext never interleave on a" -" connection). On later connections the keys are re-exchanged and TOFU-" -"checked again; the exchange is never skipped, only the identity check " -"short-circuits for known keys. Public-key pushes are only accepted while " -"a handshake is in progress, so an arbitrary unauthenticated server cannot" -" poison the registry." +"``. Both (plaintext) and TOFU-check the received key. Both sides " +"switch to encrypted mode only after ``/crypto_ready`` has been received " +"from the peer (so plaintext and framed traffic never interleave on a " +"connection), then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted while a handshake is in progress, so an " +"arbitrary unauthenticated server cannot poison the registry." msgstr "" "客户端在连接后立即发送明文“/crypto_key_exchange”问候语;服务器回复``/crypto_key_exchange_ack " " " "``。然后,双方通过文件传输机制(明文)推送其公钥文件,并对收到的密钥进行豆腐式检查。只有在从对等方收到“/crypto_ready”后,双方才会切换到加密模式(因此明文和密文永远不会在连接上交错)。在以后的连接中,密钥将被重新交换并再次进行" " TOFU 检查;交换永远不会被跳过,只有已知密钥的身份检查会短路。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:406 -#: a36303a34b174e6a8c4a421f297e4452 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:451 +#: a501267a3c9848e6aac40eb13359da87 msgid "Replay protection" msgstr "重放保护" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:408 -#: dd11c43faac347858ff85f846d7af6d1 -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." +#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 +#: cde1f1712c904c89aa5838bc54c715b6 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." msgstr "" -"握手交换随机会话随机数,线路上的每条加密线路都携带它加上每个连接的序列号:``||``。接收方丢弃随机数与当前会话不匹配的行(从旧连接重播的密文)或其序列号不是预期的行(会话内重播的密文/乱序);当套接字在(重新)交换后切换到加密模式时,两个计数器都会重置。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:417 -#: ddfd9d5832b541ba81de53f2f9abd91b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:469 +#: 51478387b6dd4b2e9f7a3d10f72a8b90 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 +#: a47f9db0c3674a12ab6d3ab5d056a8c4 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:483 +#: 6740137a28b84e5dbb3f85e8d58d32b5 msgid "Decode verification and key rotation" msgstr "解码验证和密钥轮换" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 -#: 2f8d9ddc0f434f0b98331fc3c14f710b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 +#: 8445bf9265124e38a642f9d46fc43c36 msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -864,22 +974,28 @@ msgstr "" " TOFU 检查:密钥未更改的对等点将再次被接受,而为记录的端点提供“不同”密钥的对等点将被拒绝(请参阅上面的 TOFU " "部分)。故意轮换密钥对的用户必须删除对等端过时的“pub_key.json”条目(或整个文件)才能重新信任新密钥。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:430 -#: 3b373e99ee2c4aff93e808c206dfb3f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:496 +#: 5698fde8f08b4be3a059d92a69ae3459 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures the connection is closed instead of re-" "exchanging, so a garbage-injection or persistent-mismatch storm cannot " -"spin the loop forever. A successful decryption resets the counter." +"spin the loop forever. Genuine peer traffic (messages and commands other " +"than the protocol's own handshake/coordination lines) resets the counter." +" Frames the peer had already sent when this side dropped out of encrypted" +" mode are stale: they cannot be authenticated any more, so they are " +"consumed and dropped — they neither surface as messages nor reset the " +"counter." msgstr "重新交换是断路的:在“MAX_DECODE_FAILURES”(3)连续解码失败之后,连接被关闭而不是重新交换,因此垃圾注入或持久不匹配风暴不能永远旋转循环。成功解密会重置计数器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:438 -#: aaefbbdc89554770aebdf60c16950f0f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:508 +#: 6569277ee0b644488685204e70c3e425 msgid "TCP Client command API" msgstr "TCP 客户端命令 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:440 -#: 22612be28f9d4da5b01258de1c7520f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:510 +#: b2ab9f46d6b14c8eaa97512fd117c6db msgid "" "The client supports both built-in commands that the user can type in the " "console, and a command extension API similar to the server. The main " @@ -889,8 +1005,8 @@ msgstr "" "客户端既支持用户可以在控制台中键入的内置命令,也支持类似于服务器的命令扩展 " "API。传入服务器命令的主要入口点是“handle_server_command”,而用户输入的命令在“interactive_mode”下处理。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:446 -#: 5607f70cfddc4466946bc9082ce494ab +#: ../../source/Network_APIs/TCP_Client_APIs.rst:516 +#: 5e296796f3694cdfbf48c8538979bb7f msgid "" "The client supports two modes of operation: interactive console input " "(when ``is_input_command_in_console`` is ``True``) or programmatic " @@ -899,31 +1015,31 @@ msgstr "" "客户端支持两种操作模式:交互式控制台输入(当 is_input_command_in_console 为 True 时)或编程控制(当为 " "False 时)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:450 -#: bfa689507e214d7a961f1042698850ce +#: ../../source/Network_APIs/TCP_Client_APIs.rst:520 +#: 0261c3323c4248e3bfb846d5751da36f msgid "Built-in client console commands (user-typed) include:" msgstr "内置客户端控制台命令(用户输入)包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:452 -#: 9a2bcb83868f473aae1fa0090af2dd49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:522 +#: d466b066b3654e7183cf72f86523bcd1 msgid "``/quit``: sends a quit message to the server and closes the connection." msgstr "``/quit``:向服务器发送退出消息并关闭连接。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 -#: 84be485738544bd98d7e0d2f49415cda +#: ../../source/Network_APIs/TCP_Client_APIs.rst:523 +#: 3d22aacfa1914a879be55a3518fb2a7e msgid "" "``/send_msg ``: sends the second token of the line as a chat " "message (``send_message_to_server`` drops the command name and sends only" " the next token)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:456 -#: 6bb0b49ebc5743fe9332f66948330822 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 +#: 16b438ba77f945d2a68bb24f97a69ef5 msgid "``/file ``: starts a file transfer from client to server." msgstr "``/file ``:启动从客户端到服务器的文件传输。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:457 -#: eb7e88c4607340ba8795bacb617ae98a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:527 +#: 65a2f7cca5684f21ae85deaf2675b2fa #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files from client " @@ -933,37 +1049,37 @@ msgstr "" "``/multiple_file " "...``:从客户端发送多个文件到服务器(每个文件在其自己的线程中,遵守信号量限制)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:460 -#: 98dda85c8e2a4623a9dc2d39643cddbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:530 +#: 0cb1732f55e8499ab36b6923ed56a8ec msgid "" "``/file_folder ``: sends an entire folder from client to " "server, preserving the directory structure." msgstr "``/file_folder ``:将整个文件夹从客户端发送到服务器,保留目录结构。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:462 -#: 1f2e6b52be7f4875aa8434ff22117ee0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:532 +#: f8d95f978af24a0d8056fc369d555f5f msgid "" "``/multiple_file_folder ...``: sends multiple folders" " from client to server." msgstr "``/multiple_file_folder ...``:将多个文件夹从客户端发送到服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:464 -#: 48811f3665104578b8921efe71ada53a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:534 +#: c3477f2df53d499db3c6a9b41f8bdedf msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands (client-only; the server refuses " "them)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:468 -#: 3fe8e4c73ecc42e98bde402ff3858c64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:538 +#: d6c13262c84f4ae2a43371ee4e09cfad msgid "" "Ctrl-C and EOF close the connection, send a final ``/quit`` and wait 0.5 " "seconds before the process ends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 -#: c330e7622ffc46a19b41f3e6394c3dc8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 +#: 7971066cb1de4bc2b8047248fa93d58e msgid "" "*Note: Unlike the server, the client does not have built-in ``/help``, " "``/time``, or ``/clients`` commands because those are typically handled " @@ -971,8 +1087,8 @@ msgid "" "should refer to the server documentation for available commands.*" msgstr "*注意:与服务器不同,客户端没有内置的“/help”、“/time”或“/clients”命令,因为这些命令通常由服务器处理。客户端的``/help``命令没有执行;用户应参阅服务器文档以获取可用命令。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:477 -#: f7ea97482c86419cb7e1e5db99cd79c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:547 +#: 44cf1d07758f4fa89eb47d9aad2369a5 msgid "" "A user-typed line that is not built-in and not a registered custom " "command is sent to the server as a chat message, and the client logs " @@ -980,66 +1096,74 @@ msgid "" "with that wording too)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:482 -#: 677fc4a9eabd4d5ab97bf0e2e73b05ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:552 +#: 7f463379f38f44558c3121e202f9343b msgid "" "*Note: a custom command is matched against the first token of the line, " "so a handler registered for ``/mycmd`` runs when the user types ``/mycmd " "...``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 -#: 1325358de66e4303bb8f9ff817415890 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:555 +#: ae962d51828a4e859fd9080b6eb9ec88 msgid "The command extension API for the client is defined as:" msgstr "客户端的命令扩展 API 定义为:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:494 -#: 24f976022e4245e0aa95c2cf112854c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:565 +#: cfa1714f672d4103bae0af84db5a1d63 msgid "" "The arguments of the `register_command` function are the same as on the " "server side:" msgstr "`register_command` 函数的参数与服务器端相同:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:497 -#: 087de666d0cb46b39328508976a7dc92 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:568 +#: 2f936e153d6f4587b918adf94d6ba438 msgid "" "``command_name``: The name of the command to register (should start with " "a slash, e.g., ``/mycmd``)." msgstr "``command_name``:要注册的命令的名称(应以斜杠开头,例如``/mycmd``)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:499 -#: 3acea6e2461e40f9b02b90154cb62c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 +#: c19aa473ddf5488cbe8b5039b68e08cf msgid "" "``handler``: The function to call when the command is received. The " "handler must accept three parameters: ``client_socket``, " "``client_address``, and ``command``." msgstr "``handler``:收到命令时调用的函数。处理程序必须接受三个参数:“client_socket”、“client_address”和“command”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:501 -#: 60a8ef01850843b48c37e1ce0248d247 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 +#: d327d91dee274ac1951b18ee3700c15a msgid "" "``where_to_run``: Specifies where the command should be executed. Valid " "values are ``\"server\"`` (command sent from the server) or " "``\"client\"`` (command typed in the client's console)." msgstr "``where_to_run``:指定应执行命令的位置。有效值为“服务器”(从服务器发送的命令)或“客户端”(在客户端控制台中键入的命令)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:503 -#: 0a59b9453a5145ffa92a1e91741cfa49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:574 +#: 17b9e2d9c50344bdb8e704423df3c4c8 msgid "" "``run_in_thread``: A boolean indicating whether to run the handler in a " "separate thread from the thread pool." msgstr "“run_in_thread”:一个布尔值,指示是否在线程池中的单独线程中运行处理程序。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:506 -#: 73925e7106344a879ba8a7e1f4ea6408 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:577 +#: a4fcfb0b0f89415fa269eccf366b2539 msgid "" "It returns ``False`` when ``where_to_run`` is neither ``\"server\"`` nor " "``\"client\"`` (nothing is registered then); on success it returns " "``None``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:509 -#: e9b4b0ddbfd143759ab38205955ff2de +#: ../../source/Network_APIs/TCP_Client_APIs.rst:580 +#: 55e17f10381d4c6e9c13c484a6d7b2f7 +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code, on the client as on the server; the command's first token " +"selects it, exactly as it does for a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 +#: 889fe9598c0045ccaee7de4e93d59f8e #, python-brace-format msgid "" "*Note: The client stores registered commands in the same structure as the" @@ -1050,16 +1174,16 @@ msgstr "" "*注意:客户端以与服务器相同的结构存储注册命令:``self._custom_handlers = [{}, {}]``,其中索引 0 " "用于来自服务器的命令,索引 1 用于在客户端控制台中键入的命令。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:514 -#: 87c31576643d4e328b32b14b69b4f818 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:589 +#: 9a244a7eb66d4c0c9666537c17e6f3ac msgid "" "The client also provides the `submit_task` method to submit functions to " "its internal thread pool executor, and `_execute_custom_handler` to " "safely execute registered handlers with error handling." msgstr "客户端还提供“submit_task”方法来将函数提交到其内部线程池执行器,并提供“_execute_custom_handler”来安全地执行带有错误处理的注册处理程序。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:519 -#: e64628a99ba249f8acef54a08b182c79 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:594 +#: 4cbf4048c25443dda40d622c49a8e26e #, fuzzy msgid "" "The `submit_task` method works identically to the server version: it " @@ -1069,21 +1193,21 @@ msgid "" "the call finishes)." msgstr "“submit_task”方法的工作方式与服务器版本相同:它向客户端线程池提交一个可调用函数,使用信号量将并发限制为“max_custom_workers”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 -#: e8f3baf910cb4b2497cb6f6eab9053e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:601 +#: 3a2bd1984dd14769b92c6e40c6ad357c msgid "Temporary server and client creation" msgstr "临时服务器和客户端创建" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:528 -#: 26cf9b3fd35d4af993c53f9a8e4bffb6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:603 +#: 0c9b9ad8c6ca4f679f8e54fb58940d3e msgid "" "The client also includes temporary TCP server and client creation APIs. " "They are similar to those in the server class but use `self.client_host` " "as the local binding address." msgstr "客户端还包括临时 TCP 服务器和客户端创建 API。它们与服务器类中的类似,但使用 self.client_host 作为本地绑定地址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 -#: 6fb3cae805964394bf0864814b4b8ecd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:616 +#: 03e3fc356d234c01a0bd94bad68b8ddc #, fuzzy msgid "" "`create_temporary_server` binds to ``(self.client_host, port)``. If " @@ -1096,8 +1220,8 @@ msgstr "" "port)``。如果“port”为“None”,它将调用“self.palloc()”来获取端口(在手动模式下)或返回“0”(操作系统分配)。它返回一个元组“(port," " server_thread, stop_event)”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:558 -#: 8ab44b7d114a4eca8079a87b61ca219f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:633 +#: 61b63d2c156f4512aead02cbbfe0569e #, fuzzy msgid "" "`create_temporary_client` connects to the specified server. If " @@ -1109,51 +1233,51 @@ msgstr "" "`create_temporary_client` " "连接到指定的服务器。如果给出了“bind_port”,它将绑定到“(self.client_host,bind_port)”。如果“bind_port”为“None”,它将通过“self.palloc()”获取端口并自动绑定。它返回一个元组``(client_sock,recv_thread,stop_event)``。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:564 -#: d5a66d0848e24412a1e121fba226cff8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 +#: a528285ae2714861bf6162938ad1aa0a msgid "" "These methods allow the client to act as a temporary server or to spawn a" " separate client connection for auxiliary tasks (such as file transfers)," " without interfering with the main connection." msgstr "这些方法允许客户端充当临时服务器或为辅助任务(例如文件传输)生成单独的客户端连接,而不会干扰主连接。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 -#: 16bd0374c6194f4b9bd2db749597217f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:645 +#: 46a7a0338f5040f38903a61af8ff8ae5 msgid "TCP Client console commands (interactive mode)" msgstr "TCP 客户端控制台命令(交互模式)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 -#: dbe05db8944f49818decf56adb4855b6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:647 +#: 8a93646c1be14bb8bfcb5be5140f1572 msgid "" "When the client is started with ``is_input_command_in_console=True`` (the" " default), the `interactive_mode` method is invoked. This method reads " "lines from standard input and processes them." msgstr "当客户端以“is_input_command_in_console=True”(默认值)启动时,将调用“interactive_mode”方法。此方法从标准输入读取行并处理它们。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:576 -#: eea6d19cd2f44de6ae2bd67081f49b5a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:651 +#: 5370ea52c70741728cc72ae1618e65e8 msgid "Supported console commands (user-typed) include:" msgstr "支持的控制台命令(用户输入)包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:578 -#: 3d1b84c153974f14bdd57c17a892a158 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 +#: 3ee645c39b844b1e8b14a1eb54bef876 msgid "``/quit``: closes the connection and exits the client." msgstr "``/quit``:关闭连接并退出客户端。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:579 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:654 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/send_msg ``: sends the second token of the line to the " "server as a chat message." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:581 -#: 50b34e795f4a4d1595f8a2f6c1ebfad5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:656 +#: c34b32925f024797841232729eca131e msgid "``/file ``: sends a single file to the server." msgstr "``/file ``:将单个文件发送到服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:582 -#: d90b52a3886c48c1b86fe1d4a08adb11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:657 +#: 739e72b7a06a4eefa6cdd1a952d3d781 #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files to the " @@ -1162,44 +1286,44 @@ msgstr "" "``/multiple_file ...``:同时发送多个文件到服务器(受``max_thread_num`` " "限制)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:583 -#: 66d2f7d1d87847e39e4172ae789b6a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:658 +#: d9421edab02e4b33850db50a0011ad16 msgid "" "``/file_folder ``: sends an entire folder to the server, " "recursively." msgstr "``/file_folder ``:递归地将整个文件夹发送到服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 -#: 321bde30af944560b349b5dd6a162a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:659 +#: efd08f6cefcd4f44bcd4ff0687cee8bc msgid "" "``/multiple_file_folder ...``: sends multiple folders" " to the server." msgstr "``/multiple_file_folder ...``:将多个文件夹发送到服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:585 -#: 9feff7033be8445599773701f51926df +#: ../../source/Network_APIs/TCP_Client_APIs.rst:660 +#: ed70094fabb34d46afadb56fd5c7c37d msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:587 -#: 6489b5a0fb2948748f0f1bd5f303c779 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:662 +#: 1dc2bd43fd56402785fb76b3895b03b2 msgid "" "Any other non-empty line is sent as-is to the server — the same path chat" " text takes." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:591 -#: 3295a0d774d0473da7c5d7405d72abd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:666 +#: d72b6516a43b4f26bb5750604f41ff74 msgid "" "The client does not have a built-in ``/help`` command. Please refer to " "the server's help for available commands (e.g., by typing ``/help`` after" " connecting to the server)." msgstr "客户端没有内置的“/help”命令。请参阅服务器的帮助以获取可用命令(例如,在连接到服务器后键入“/help”)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:595 -#: dd63bf8cfd3641c0be9adad9b06aa8e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:670 +#: e6081a66251a4a57bc5724dccb8c852b msgid "" "A line registered with ``register_command(..., where_to_run=\"client\")``" " runs when its first token matches a registered name; handlers registered" @@ -1207,84 +1331,87 @@ msgid "" "server sends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:600 -#: 7efd09ba06ba4067b03810eb838caa24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:675 +#: 4befe76529e04e859f9422d8ebe3921a msgid "" "*Note: The client logs ``Unknown server command: `` for any line it" " did not recognise, including plain chat text, because those lines take " "the same fallback path.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:604 -#: 8cd9357ee0494a20b9ba9d4b8ed3514b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:679 +#: 2cbc548821b84721b1aea4f88573f02f msgid "Example interactive session::" msgstr "交互式会话示例::" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:617 -#: 45b4cc10dbab4342a2653adafcad5e63 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:692 +#: bd36c89659694280b349cc621b598254 msgid "TCP Client file transfer API" msgstr "TCP客户端文件传输API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:619 -#: 2476ecf352184c39a27da75545ff67b9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 +#: 0f20edbf8203493aa579cb5a1195712b msgid "" "The TCP client contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers, using the same " "underlying protocol as the server." msgstr "TCP 客户端包含一个文件传输子系统,支持客户端到服务器和服务器到客户端传输,使用与服务器相同的底层协议。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:623 -#: 37c359049bd04adcbcde988494c16efa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:698 +#: 02806a329fba478293ef172f63bfb93d msgid "" "As with the server documentation, only the list of APIs is provided here." " For detailed internal flow, please refer to the server documentation or " "the source code." msgstr "与服务器文档一样,此处仅提供 API 列表。详细的内部流程请参考服务器文档或者源码。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:627 -#: a0aef36e6c984775b79dc1c35e39cd61 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 +#: 2a7f8a3995cf4e2b81a3bf5c3c85b0fa msgid "The file transfer API for the client includes:" msgstr "客户端的文件传输API包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:629 -#: e340f1fe00774c58bc70b398a745589d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:704 +#: dc5da9cf7ac441c8842cc97d904582ba msgid "The basic function for client-to-server file transfer is:" msgstr "客户端到服务器文件传输的基本功能是:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 -#: 3cfc45f71fac4d49b0c188b84068d5b7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:714 +#: db4145949f7a42aab5ff42bf72d6ff2e msgid "" "The non-``_thread`` versions take the destination folder as a required " "argument (the ``_thread`` wrappers default it to ``None``, which means " "the default transfer folder)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:643 -#: 6058cc068109448faaad1e4936bb7863 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:718 +#: 743dd6f0cdba49678277c1d19c178f20 msgid "" "For server-initiated transfers (server-to-client), the client provides " "these handlers:" msgstr "对于服务器发起的传输(服务器到客户端),客户端提供以下处理程序:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 -#: 1e596cb7ccd942aeb30e335c53e1afa1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:728 +#: 72f8a6d975094c7984fbef810a422975 msgid "The low-level receive mode function is:" msgstr "低级接收模式函数为:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:661 -#: 885c49e37dd94f2bb3aca9d95dc72222 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:736 +#: b04d81d08ea941b3b6beea16e4a05bc0 msgid "And the low-level send mode function is:" msgstr "低层发送模式函数为:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:668 -#: 17759b30b9ae4c68b00432ae33741a99 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:744 +#: 724cadb0ca764d9aaafd664c63b858d6 msgid "" -"``pause_fid`` is the forwarding id used to pause/resume the transfer with" -" ``/pause_trans`` / ``/start_trans``." +"``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) " +"addresses; ``peer`` is the transfer's original receiver and " +"``resume_offset`` continues an interrupted file from the byte the " +"receiver already holds." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:671 -#: 4dc07ef115aa4712807fede2f2040e12 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 +#: f5823da74e1a4879a65624511d10e0cb msgid "" "We recommend that for client-to-server file transfers, you use the " "console commands (``/file``, ``/file_folder``, etc.) rather than calling " @@ -1298,8 +1425,8 @@ msgstr "" "API,因为控制台命令已经正确处理线程和信号量限制。如果您需要直接调用 API,请使用 `_thread` " "版本(例如,`file_transfer_client_recv_client_start_thread`)以避免阻塞主线程。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:680 -#: 1165a3c7f2bc470da7c706aead0fc73f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 +#: 2d0ea3d6726e43a3b3b551bf23c5ce00 msgid "" "*Note: The file transfer API functions follow the same handshake protocol" " as the server: the initiator sends a command over the main connection, " @@ -1307,13 +1434,13 @@ msgid "" "transferred over a separate TCP connection.*" msgstr "*注意:文件传输 API 函数遵循与服务器相同的握手协议:发起者通过主连接发送命令,然后协商临时端口,并通过单独的 TCP 连接传输实际文件数据。*" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:687 -#: 95c14f0f60154aa3b15d0dd0dfe41a69 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 +#: 997f666f071d44499a4be946c3a808e5 msgid "Port allocation API" msgstr "端口分配API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:689 -#: 9e3832473379404391011a22af4fb605 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 +#: 937556f090f74e86ab56041fbda5c543 msgid "" "The client port allocation APIs are nearly identical to those of the " "server. They allow you to allocate ephemeral ports either automatically " @@ -1321,8 +1448,8 @@ msgid "" "range." msgstr "客户端端口分配 API 与服务器的端口分配 API 几乎相同。它们允许您自动分配临时端口(通过返回 0,让操作系统选择)或在配置的范围内手动分配。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 -#: 93aa2cdf7f3c49fb8ad14ad1b78415e4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 +#: a37e79b6f8e34e3ab589f9127a2fbaf2 msgid "" "To configure the port allocation mode, the client reads the " "``/client_alloc_port_range`` line the server sends it right after the " @@ -1335,8 +1462,8 @@ msgstr "" "``行。当服务器发送带有数字的命令时,客户端设置`` self.is_hand_alloc_port = True " "``并配置范围。如果服务器发送`` NO_LIMIT `` ,则客户端使用自动分配(分配调用返回0 )。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 -#: 3d693309e5ae4fbaa587212cf81bc16f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 +#: a29288d0ba7d46409b9fbc7e4b3ff7b0 msgid "" "In manual allocation mode, the port range is determined by the server's " "broadcast value. The client maintains its own range based on " @@ -1349,13 +1476,13 @@ msgstr "" " - self.port_add_step *each_client_port_range”,最大端口为“self.port + 1 + " "self.port_add_step *each_client_port_range”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:710 -#: ab3bb204b8f5402093e6d329cd98cd64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 +#: baf74c2478324ced80df912ff96e7baa msgid "The main methods for port allocation are:" msgstr "端口分配的主要方法有:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:717 -#: 93b31be2d4bf4e5ca9f8b4ab9b095a45 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 +#: c4170cd3e6844792b110dfba945f0298 msgid "" "`palloc` returns an available port (either 0 for automatic mode, or a " "concrete port number from the manual range). It internally calls " @@ -1365,16 +1492,16 @@ msgstr "" "`palloc` 返回一个可用端口(自动模式为 " "0,或者手动范围内的具体端口号)。它在内部循环调用“file_palloc”(加法分配)和“spy_palloc”(减法分配)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:729 -#: d54f0b635e194239932cf1bb5cace701 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:807 +#: 1c21e96227684b8998d8a6c6c595caf0 msgid "" "`pfree` releases a previously allocated port. In manual mode, it removes " "the port from the internal list and adjusts the latest port pointers. In " "automatic mode, it does nothing." msgstr "`pfree` 释放先前分配的端口。在手动模式下,它将端口从内部列表中删除并调整最新的端口指针。在自动模式下,它不执行任何操作。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:734 -#: 60b2327bda49480fac483fb4ca52eb5d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:812 +#: e270023d96364a59a4436f846b296202 msgid "" "As with the server, the automatic mode (returning 0) is recommended for " "most use cases because it avoids port conflicts and simplifies code. " @@ -1384,251 +1511,276 @@ msgstr "" "与服务器一样,建议大多数用例使用自动模式(返回 " "0),因为它可以避免端口冲突并简化代码。手动模式适用于必须严格控制端口范围的环境(例如防火墙或测试)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:741 -#: bade6122477d4a959b6f9a942b150ea0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:819 +#: 31a306a34d04473c85f2c36abe5747e7 msgid "TCP Client APIs table" msgstr "TCP 客户端 API 表" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:743 -#: be55c1d2020c4088ac45dcd1f2c6add4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:821 +#: e38b3c22a1e041be93c1b9133368dacb msgid "In short, the table of contents of the public APIs is as follows:" msgstr "简而言之,公共API的目录如下:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:746 -#: 8bb46aea2dff4e57853087e452fdca3f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:824 +#: 5c9291fc111d4f87a26c3b323d69bf27 msgid "The client setup APIs:" msgstr "客户端设置 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:747 -#: 6c95cdbfa4634d9f9561908b316ab03e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:825 +#: dc26d3c73e994b2a89d83b6dc2b0ff20 msgid "`TCP_Client_Base`" msgstr "`TCP_Client_Base`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:748 -#: a5ab88edb0dd42dd81166dc614c4c353 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:826 +#: caab3a11f54d4540890a84cada3cecd3 msgid "`start_TCP_client`" msgstr "`启动_TCP_客户端`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 -#: 11f6500a3ac64b41ba44c22ef2069007 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:827 +#: c38e962856a84b6eaf6f0759e9a48ec4 msgid "`connect`" msgstr "`连接`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:750 -#: 0263dd292461441192546c1f9237adaf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:828 +#: 411023a9191243338f22e59a33cb72c2 msgid "`close`" msgstr "`关闭`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:752 -#: 11848e9f043f4952afaad4305b07486d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:830 +#: 982308344bc1464c982613021965e40f msgid "The client handling information APIs:" msgstr "客户端处理信息API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:753 -#: 6c2bd74a71a64468b3247862791409e1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:831 +#: 611645ffa9bb4259923b685f7389fab4 msgid "`receive_messages`" msgstr "`接收消息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:754 -#: a15228535750492caa9b3ebfba4d9901 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:832 +#: b5a951b6b0694dd7992bcb3d054bd2b3 msgid "`handle_server_command`" msgstr "`处理服务器命令`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:755 -#: 47cb15f07d394f78a15345f254e42b0b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:833 +#: 334fb0ff014d4f418ac474db4c68d247 msgid "`receive_message`" msgstr "`接收消息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:756 -#: f0074be846de4eef8d98f07a3fd153a7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:834 +#: df7b9a0f6c034b8ab9b1fb20b3bf879a msgid "`send_message`" msgstr "`发送消息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:757 -#: ca1943c93c2048d9805e6c3494744d90 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:835 +#: ffb875c0ebd844368deedf382811f851 msgid "`interactive_mode`" msgstr "`交互模式`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:836 +#: 5630f1fb130842aba877cdb0c29e4ff1 #, fuzzy msgid "`send_message_to_server`" msgstr "`发送消息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:760 -#: 1059c94b173f48aa9304663c6d74a805 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:838 +#: 494c8644a7254a7b81e9886d840813e8 msgid "2.1. The inbound event listener APIs:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:761 -#: 54202f3279bb4bb19457be283d4f5d75 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:839 +#: 6f15aa9d9fe142088b15a802e28823f5 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:762 -#: 88625c35b2ec49889b14309d8373c1ef +#: ../../source/Network_APIs/TCP_Client_APIs.rst:840 +#: d240527b31854c3eb36c83b57b838e5d msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:763 -#: eca517026718488aa026202ff440ce41 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:841 +#: fb735c656faa4a28983b3c90a8f9f452 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 -#: a5c242c6e4084aef98fa59f17778731d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:843 +#: 7299f59deb95485b9ce5f240b3318d86 msgid "" "The client encrypted channel APIs (see :ref:`tcp-client-encrypted-" "channel-api`):" msgstr "客户端加密通道 API(请参阅 tcp-client-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:766 -#: c5006b19599d4a45bc86d5cfac770d94 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:844 +#: 51757de232d548c3b7c230b7e6456906 msgid "`_crypto_exchange_thread`" msgstr "`_crypto_exchange_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 -#: 3d8e73d09493460c845a98dabf5ad9f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:845 +#: ad3834da9c474029952e0043a46c2ed6 msgid "`_crypto_after_ack`" msgstr "`_crypto_after_ack`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:768 -#: 75bbad7153834bad9492a242fa26b789 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:846 +#: 0ca576944d8a497abeb39cdf5c4ccdb7 msgid "`_crypto_push_pub_key`" msgstr "`_crypto_push_pub_key`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:769 -#: 59aff25473e942eb9b11f6aa4c1ff235 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:847 +#: 11b6eacdaa484d689499dad3be56bd79 msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:771 -#: aeba48f8f86e45f199838191146c7f4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:849 +#: b71d430231c24a6995ba0b267f09f4bf msgid "The client command APIs:" msgstr "客户端命令API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 -#: 0a25d8003bd64c63ad151aedf3fb15ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:850 +#: efb7ccdbabfd477d83af89aed1eb4c5d msgid "`register_command`" msgstr "`注册命令`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:773 -#: c9e2f51101b942ef8e722216e59ed972 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:851 +#: 72f8a6d975094c7984fbef810a422975 +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:852 +#: d549ceac7407457f81c403d7be88aa99 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:774 -#: 92211b1c671c48ce8e0d14c9d12b71f1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:853 +#: c6fe8883469e47b88e0a4bb3be30c1a6 msgid "`submit_task`" msgstr "`提交任务`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:775 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:854 +#: 5630f1fb130842aba877cdb0c29e4ff1 msgid "`create_temporary_server`" msgstr "`创建临时服务器`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:776 -#: e23b2af57072452ab0fab0c5652bde72 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:855 +#: 9cf956cb593f4c758da50d45c684466b msgid "`create_temporary_client`" msgstr "`创建临时客户端`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:778 -#: 91270c73be944993a8751739a6ef133e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:857 +#: 55aa7c66f7a24443a58e108948608136 msgid "The client file transfer APIs:" msgstr "客户端文件传输API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:779 -#: 358e4cb2a7174129b65dc582f3b977f7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:858 +#: d79011e4d398480cbdb00e021f1461fe msgid "`file_transfer_client_recv_client_start`" msgstr "`file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 -#: f4971cf5af03413e9b0011378a57d487 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:859 +#: 300f91c72ed8400d85821a3e2a0ab1ec msgid "`file_transfer_client_recv_client_start_thread`" msgstr "`file_transfer_client_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:781 -#: 077b6550f3b8496fb4d8d8592eac5ca6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:860 +#: 1f3a30d9bf5d44baa9459a21df8f70d4 msgid "`folder_file_transfer_client_recv_client_start`" msgstr "`folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:782 -#: 194dd830cddc49acaad93077b41fb646 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:861 +#: 5619c7c126b14852ace1e5ed9a428e0a msgid "`multiple_file_transfer_client_recv_client_start`" msgstr "`multiple_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:783 -#: e6ea79e90d794733b2bb84b5799ab3ec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:862 +#: e1e3f53d8275406f9f2f31a406617843 msgid "`multiple_folder_file_transfer_client_recv_client_start`" msgstr "`multiple_folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:784 -#: ce228984911540d29bef2d0b7e73eabc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:863 +#: 0f3b14e3c193426191323ee76959278e msgid "`file_transfer_client_recv_server_start`" msgstr "`file_transfer_client_recv_server_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:785 -#: 7ff0717c8e504c869e36a3d9fd829652 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:864 +#: 4612a53ee9154895a8758a6cc45c0b76 msgid "`file_transfer_client_recv_server_start_thread`" msgstr "`file_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:786 -#: db7e615cfbd347359a6a683642049c31 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:865 +#: 5dff8ca27b7b40e6941b8190a136173c msgid "`file_folder_transfer_client_recv_server_start_thread`" msgstr "`file_folder_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:787 -#: 16a578b31e344b5d82b9935e56aafa02 -msgid "`file_transfer_mode_recv`" -msgstr "`文件传输模式_接收`" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 -#: 7659e4e26bef45e89e4659a045cd77cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:866 +#: c66340b3ef204af29e58170db0efc057 msgid "`file_transfer_mode`" msgstr "`文件传输模式`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:790 -#: 6a81df270092467db215985a9b0ea90e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:868 +#: 87af784aa34949379dc6a73c148a402d +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:869 +#: 9aa5be3d37804a5c8286d23160add073 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:870 +#: 4612a53ee9154895a8758a6cc45c0b76 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:871 +#: e340c2c825324df7b3aee14da0f9d919 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:872 +#: 0f3b14e3c193426191323ee76959278e +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:874 +#: 5bf1072901734d3d8d0b119e5f50627c msgid "The client console commands (interactive mode):" msgstr "客户端控制台命令(交互模式):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:791 -#: c2174ab210464a2e82c298e0f70fee20 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:875 +#: cb2350fc1fd047f39fb9841ce78dd4ed msgid "`/quit`" msgstr "`/退出`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:792 -#: ffa9f9ef47ae46629a6fc29d29d9ab44 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:876 +#: 70b54395545d4421bd90e40acd8b28d5 msgid "`/file`" msgstr "`/文件`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:793 -#: 86990039800e4a999b76a431d6a6dd8a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:877 +#: bd2dec3b0774465d87ed9f3f853f30db msgid "`/multiple_file`" msgstr "`/多个文件`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:794 -#: 6f26c82663494206964a6bb68ddcfe6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:878 +#: efe4930f9bd34df19b1ee98085605346 msgid "`/file_folder`" msgstr "`/文件文件夹`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 -#: 63d6611c586c46d3a9053712a112162d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:879 +#: acb8ceac4b5540aca3230cff6bfefa86 msgid "`/multiple_file_folder`" msgstr "`/多个文件文件夹`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:798 -#: 7bb84bbf4494463d9e477ddce9f0fec2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:882 +#: 9db1c5c6b375448e80c2af32c0464023 msgid "See Also" msgstr "参见" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:800 -#: 5cc4da34c3dc479eb9af04123c8502f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:884 +#: 0c84c6f4e6e9450aa96935335c505122 msgid ":doc:`TCP_Server_APIs` — TCP server." msgstr ":doc:`TCP_Server_APIs` — TCP 服务器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:801 -#: 134b0d0b135c4e68a08b0d14959d6307 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:885 +#: efc25fa97296452199853b1bb3cc3f21 msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 端点。" @@ -1771,3 +1923,57 @@ msgstr ":doc:`UDP_APIs` — UDP 端点。" #~ msgid "The multiple folders transfer function is:" #~ msgstr "多文件夹传输函数为:" +#~ msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" +#~ msgstr "“client_port”:默认为“None”(操作系统分配临时端口)" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(sender_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to " +#~ "`handle_server_command` instead). ``sender_id`` is" +#~ " the author's ``\"ip:port\"`` — for a" +#~ " message another client forwarded here " +#~ "through the ``/send_msg_from`` envelope it " +#~ "is the forwarding client, and it " +#~ "is ``None`` for a direct push from" +#~ " the server. ``add_file_listener`` registers " +#~ "``listener(client_id, full_path, name, size, " +#~ "command)`` and fires after a file " +#~ "sent by the server has been fully" +#~ " written to disk. Both listeners run" +#~ " on a protocol thread, so they " +#~ "must not block, and an exception " +#~ "inside a listener is logged and " +#~ "swallowed. The ``remove_*`` counterparts " +#~ "unregister a listener and ignore unknown" +#~ " ones." +#~ msgstr "" + +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "握手交换随机会话随机数,线路上的每条加密线路都携带它加上每个连接的序列号:``||``。接收方丢弃随机数与当前会话不匹配的行(从旧连接重播的密文)或其序列号不是预期的行(会话内重播的密文/乱序);当套接字在(重新)交换后切换到加密模式时,两个计数器都会重置。" + +#~ msgid "" +#~ "``pause_fid`` is the forwarding id used" +#~ " to pause/resume the transfer with " +#~ "``/pause_trans`` / ``/start_trans``." +#~ msgstr "" + +#~ msgid "`file_transfer_mode_recv`" +#~ msgstr "`文件传输模式_接收`" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po b/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po index 897db51..12d9a82 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,86 +20,86 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Server_APIs.rst:2 -#: 6233736da6d8410985a7db552ebb0405 +#: c4332266e3f842cc912424ee842fcfe0 msgid "The TCP Server APIs" msgstr "TCP 服务器 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:5 -#: 6e1c64d13b9e4deebc7c276d00bfca94 +#: 769ff5b424d54086a70b199663089327 msgid "TCP Server setup API" msgstr "TCP 服务器设置 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:7 -#: 05209d5966c24f19bcf70e93d016fe24 +#: 2d81aa6d8ba84a868113fd9e08fc5c60 msgid "" "The TCP Server Setup API is used to create a TCP server. The server in " "the protocol is usually used to connect and listen to the TCP clients and" " handle the data from the clients." msgstr "TCP 服务器设置 API 用于创建 TCP 服务器。协议中的服务器通常用于连接和监听TCP客户端并处理来自客户端的数据。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:35 -#: c6d17d88ca43468cab262d7b50bb7d43 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 +#: ddc5d0f6bc1b4162af2bb49f6b25a031 msgid "" "The TCP Server Setup API is defined in the ``TCP_Server_Base`` class. The" " parameters of the ``__init__`` method are as follows:" msgstr "TCP 服务器设置 API 在“TCP_Server_Base”类中定义。 ``__init__``方法的参数如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:38 -#: 7c3b5b3185bb436bbaabf0aaea5f11fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 +#: f1ffcdd5c8e74b9cbdb5e5fc8eeb34ce msgid "``host``: The host IP address to bind the TCP server to." msgstr "``host``:绑定 TCP 服务器的主机 IP 地址。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 -#: 8dbeeea956834b28a5d13a47b9eaf651 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 +#: 7e419c2e704a44228bd0bdeed976d861 msgid "``port``: The port number to bind the TCP server to." msgstr "``port``:绑定 TCP 服务器的端口号。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:40 -#: 3710af3c13574f088cd84d34ae8c83ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 +#: 854e298d71f140069b6ed51806224ca5 #, fuzzy msgid "" "``max_clients``: The maximum number of concurrent clients the server can " "handle (ignored when ``is_asynic_clients_io`` is ``True``)." msgstr "``max_clients``:服务器可以处理的并发客户端的最大数量。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 -#: c92cda0f3bdb4f839ab24c2c65c926db +#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 +#: 203462f6b127478cb9bb0c2093362827 msgid "``port_add_step``: The step size for incrementing the port number." msgstr "``port_add_step``:增加端口号的步长。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 -#: 43155638bb1344798a37f85065d411ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 +#: 3d0355b5c1924055a7d8b6acb907fad0 msgid "``port_range_num``: The number of ports to check in the range." msgstr "``port_range_num``:范围内要检查的端口数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 -#: 0459f804445d47519971903bce3e36eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 +#: a7852ea136454a1298541e96cdece1bc msgid "" "``max_file_transfer_thread_num``: The maximum number of threads for file " "transfer operations." msgstr "``max_file_transfer_thread_num``:文件传输操作的最大线程数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:45 -#: 3103e7d29cb647f9922e0b507d47a171 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:49 +#: 0f1b0f03ffe2472cb58725dc446f6f7c msgid "" "``is_hand_alloc_port``: A flag indicating whether to manually allocate " "the port." msgstr "``is_hand_alloc_port``:指示是否手动分配端口的标志。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 -#: ee86acb3489f408ca9ba116a66c5ea3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:50 +#: 969ca405744f4d57a8e70db30eada3f7 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console." msgstr "``is_input_command_in_console``:指示是否在控制台中输入命令的标志。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 -#: d593644fa1664037b99afd05ecbf9cf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:51 +#: 6b01091b3f124b8d87c9423eb6998be4 msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``:自定义工作线程的最大数量。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 -#: b46e9e9d9066432bbe75dc461b0f951f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 +#: c9d16d29465a48779ee2a54e4b9cc66e msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the server itself by calling " @@ -107,8 +107,8 @@ msgid "" "register its commands first and start the server later." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 -#: 60e4bd55be9940a48d6ae6421561fdaf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:56 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with clients are RSA-encrypted (see :ref:`tcp-server-encrypted-channel-" @@ -117,8 +117,8 @@ msgstr "" "``is_enable_encrypto``:指示与客户端交换的消息是否经过 RSA 加密的标志(请参阅 tcp-server-" "encrypted-channel-api`)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:54 -#: c6dcdd076b864336834f8490c0a25708 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 +#: 3558d7e8c52442818701d4eb794b3643 msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -128,16 +128,30 @@ msgstr "" "``is_custom_keys``:可选的``[pub_key_path, pvt_key_path]`` 用户提供的 RSA " "密钥对。两个文件都必须存在,解析为 PEM,并且相互配对;无效的对将被默默地忽略,并使用默认的键查找(``None`` 保留默认查找)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 -#: d0e99e1bc78f40f7af7470a66315bb04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:62 +#: 86265e57f3aa48e58e3fb5d9de0a9277 msgid "" "``max_mem_buff``: The in-memory buffering ceiling of the forward pump, " "given in MiB and stored as bytes (``self.max_mem_buff``); past it the " "uploading peer is told to pause. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:61 -#: 970d44aa127b40c7854cfc4dee215dcf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 +#: 7d4dd6bf4eff4f4db8ce0187088f172c +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:67 +#: 8fb93ff5bf2f49b18f2f42c92e66123f +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:69 +#: f12bacde2a874840879a51af63eeefde msgid "" "``is_asynic_clients_io``: A flag indicating whether clients are served by" " asyncio coroutines on one event loop instead of one thread per client. " @@ -148,8 +162,8 @@ msgstr "" ":指示客户端是否在一个事件循环而不是每个客户端一个线程上由异步协程提供服务的标志。它取消了`` max_clients " "``的限制,因此单个服务器可以容纳数千个并发连接。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 -#: 269ce1f748d942949c0c20017fdf4a9b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 +#: 3a36a9bba6004a41b358be9975788707 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the server logs command content and execution results only;" @@ -158,8 +172,8 @@ msgstr "" "`` is_debug `` :选择记录多少详细信息的标志。使用`` False `` (默认值) ,服务器仅记录命令内容和执行结果;使用`` " "True `` ,它还记录执行过程的关键步骤。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:68 -#: 09d8448517374602938d9ca4872e0356 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_print_log``: A flag indicating whether the server logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." @@ -167,73 +181,101 @@ msgstr "" "`` is_print_log `` :指示服务器是否记录所有日志的标志。对于`` False `` ,它不打印任何内容,无论`` " "is_debug ``说什么。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:71 -#: dc30e9a1ba5044319a3ed5ad1842b348 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 +#: 2994b78415964ff0adc713a4daed1b6b +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when a " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 +#: 9f9de22b50a94553ac1113f290dff1b4 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 +#: 8b0a1bb7ed944884854a936968f3b4bd msgid "All parameters have default values:" msgstr "每个参数都有默认值:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 -#: 5774cd0576f349d18492b59a0b6d68bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:100 +#: 89299feb872b49758f7c9bf680114bbc msgid "``host``: Default is ``'127.0.0.1'``" msgstr "“主机”:默认为“127.0.0.1”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:74 -#: 4437fda8aa004d7483cefd29ad594bca +#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 +#: 38b84b10fc4d492497c3e0b20cb9fe8c msgid "``port``: Default is ``65432``" msgstr "“端口”:默认为“65432”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:75 -#: 559c3b634b1043f2a6541f45eba488d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:102 +#: 3ccf25b3de4749a7ad73a1001fea86fb msgid "``max_clients``: Default is ``10``" msgstr "“max_clients”:默认为“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 -#: 8988cc48e66a472ebe8d505bdf8d6db9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:103 +#: 63455575485f4a25b4d2d2b83803e6b8 msgid "``port_add_step``: Default is ``1``" msgstr "“port_add_step”:默认为“1”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:77 -#: 063ec78e76b3439aafe539fad81a6036 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:104 +#: d8759c586e7143838c1ffe24c9fd6f62 msgid "``port_range_num``: Default is ``100``" msgstr "“port_range_num”:默认为“100”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:78 -#: 4a3115c33bd349fba0768f79f18c47c0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:105 +#: a8020929e0f14b5394b6dd502b7a7b67 msgid "``max_file_transfer_thread_num``: Default is ``10``" msgstr "“max_file_transfer_thread_num”:默认为“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 -#: fe7bf4015de045dcadc0024aef2bbdac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:106 +#: a9307e89f7cd471d96794bf7fbc9313c msgid "``is_hand_alloc_port``: Default is ``False``" msgstr "“is_hand_alloc_port”:默认为“False”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:80 -#: 2529e795d9b0401d930f3c09766c56d5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:107 +#: 76084a80a458455bb952e8acad677eba msgid "``is_input_command_in_console``: Default is ``True``" msgstr "“is_input_command_in_console”:默认为“True”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:81 -#: a95bee48d609469398e5a878b3d1e810 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:108 +#: f32a6549330a43f482e01def905e7415 msgid "``max_custom_workers``: Default is ``10``" msgstr "“max_custom_workers”:默认为“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:82 -#: c825fae2eaaa4afeaa551e65e4ea1ff1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:109 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_Server()`` automatically)" msgstr "“is_extend_command”:默认为“False”(当“True”时,“__init__”不会自动调用“start_TCP_Server()”)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:84 -#: 0ab49ef330a94ecb80e160bbe0f00fe9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:111 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, client " "connections go through an RSA public-key exchange and all subsequent " "messages are encrypted)" msgstr "“is_enable_encrypto”:默认为“True”(当“True”时,客户端连接将通过 RSA 公钥交换,并且所有后续消息都会被加密)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:87 -#: 6087b88026574d56aa37a817f0fe790a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:114 +#: c259e80f53a14b79a94190bcded7b30d msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -242,8 +284,20 @@ msgstr "" "``is_custom_keys``:默认为``None``(``[pub_key_path, pvt_key_path]`` " "列表使用用户提供的密钥对而不是默认的``~/.ssh``/生成的密钥)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 -#: 26758c8f847b47c9839124e86e042349 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:117 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "“max_clients”:默认为“10”" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:118 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "“max_file_transfer_thread_num”:默认为“10”" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_asynic_clients_io``: Default is ``False`` (when ``True``, every " "accepted connection is served by a coroutine on one asyncio event loop, " @@ -252,29 +306,43 @@ msgstr "" "`` is_asynic_clients_io `` :默认值为`` False `` (当'` True " "``时,每个接受的连接都由一个异步事件循环上的协程提供,并且忽略`` max_clients `` )" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:93 -#: 79dca8f502bb4401952542fb3dba6939 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:122 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "`` is_debug `` :默认值为`` False `` ( `` True ``将执行过程行添加到命令/结果行)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:95 -#: 656b6904625a4ea0977c85a93e62fd84 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:124 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "server would print)" msgstr "`` is_print_log `` :默认值为`` True `` ( `` False ``会使服务器打印的每一行保持沉默)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 -#: a3fd35f818f84d7399b7d41208ff9319 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:126 +#: abd7d3032e15468e92f96a0b5af1f926 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:128 +#: 9b2bfa874c4e4969905923bd7aa0f80c +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 +#: ff0d716f8c6344408337c57ab32bad28 msgid "" "The TCP Server Setup API will initialize all the necessary parameters and" " resources for the TCP server." msgstr "TCP 服务器设置 API 将初始化 TCP 服务器的所有必要参数和资源。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 -#: c38ba680fb704c4b9af31bcd33224c02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:134 +#: 06c57226c0e9415ab1618ae20a14f513 msgid "" "*Note: By default ``TCP_Server_Base.__init__`` calls " "``start_TCP_Server()`` to start the server automatically. If you set " @@ -284,36 +352,36 @@ msgstr "" "*注意:默认情况下``TCP_Server_Base.__init__`` 调用``start_TCP_Server()`` " "自动启动服务器。如果您设置“is_extend_command=True”,实例将不会自动启动,您应该在准备好时手动调用“start_TCP_Server()”。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:112 -#: a0900d8246aa4cda80638035485659e5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:145 +#: e473a54dc4534e29ac4361429d24cb63 msgid "" "In the `start_TCP_Server` method, we first create a TCP server socket and" " bind it to the ``self.host`` and ``self.port`` which are initialized in " "the ``__init__`` method." msgstr "在`start_TCP_Server`方法中,我们首先创建一个TCP服务器套接字并将其绑定到在`__init__`方法中初始化的`self.host`和`self.port`。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:116 -#: 4b6e513817d44c1d93cf1c39866ecf18 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:149 +#: 68dff731e96c46788af52f9c536a6d2f msgid "" "*Note: The server socket which is set up in the `start_TCP_Server` method" " is based on IPv4 form.*" msgstr "*注意:`start_TCP_Server`方法中设置的服务器套接字是基于IPv4形式的。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 -#: b8a255c83b3346199c3197dd596427b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:152 +#: 1c6fc605850b4e988e7f5dac390f905e msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will start a thread to listen to the console input of the " "server or not." msgstr "其次,根据``self.is_input_command_in_console``参数,我们会启动一个线程来监听或不监听服务器的控制台输入。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:123 -#: bd35c2a4858f46ecb2f1ea1b7e987bb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 +#: 493d7ac50eb3446394da3c71f307b0a5 msgid "After that, a main loop to accept clients will be started." msgstr "之后,将启动接受客户端的主循环。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:125 -#: 8b06edd210564df19035b30b72121c82 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 +#: 46f0159fb9a84874959c103ac08656f5 msgid "" "*Note: there is another global variable ``self.running`` which is set to " "``True`` after the server socket is successfully created. The " @@ -324,8 +392,8 @@ msgstr "" "*注意:还有另一个全局变量“self.running”,在服务器套接字成功创建后,该变量将变为“True”。 ``self.running`` " "变量用于控制 TCP 服务器的主循环,当服务器关闭时它将变为 ``False``。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 -#: 0920728e22cf4fdcbd6b6a5f32b251d4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:164 +#: ed335af1339644a090d7fc4ebdc859f1 msgid "" "With ``is_asynic_clients_io=True`` the main loop is the asyncio event " "loop instead: it accepts clients in non-blocking mode and schedules one " @@ -336,8 +404,8 @@ msgstr "" "``时,主循环是asyncio事件循环:它在非阻塞模式下接受客户端,并为每个连接安排一个协程,它从不应用`` max_clients " "``限制,并且`stop`释放它,以便循环可以结束。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:136 -#: ca2a678a5119456daf70ba9c6bcfacf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:169 +#: 613624f457b847f994b739812b6e7aed msgid "" "The main loop of the TCP server setup function first checks whether the " "number of connected clients exceeds the maximum number of clients. The " @@ -345,8 +413,8 @@ msgid "" " of the `TCP_Server_Base` class, which is initialized in ``__init__``." msgstr "TCP服务器设置函数的主循环首先检查连接的客户端数量是否超过最大客户端数量。最大客户端数量由“TCP_Server_Base”类的“self.max_clients”参数定义,该参数在“__init__”中初始化。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:141 -#: 295d9fd021d94b94b5bb5e3290af9b94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:174 +#: d6142df9dee34a85a449a322bcfc5729 #, fuzzy msgid "" "If the number of the clients is already over the limit of the connect " @@ -356,8 +424,8 @@ msgid "" "is defined as:" msgstr "如果客户端数量已经超过连接数量限制,服务器将发送过载消息并关闭连接。但如果没有超过限制,服务器将设置一个客户端处理函数“handle_client”,服务器处理函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:153 -#: a15c83c5c9984e68b88602f6a3c56d16 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:186 +#: e0d97e64db41406aa120fbdcd2ee5bb3 msgid "" "*Note: For more details of the `handle_client` function, see the :ref" ":`tcp-server-handling-information-api` section.*" @@ -365,21 +433,21 @@ msgstr "" "*注意:有关“handle_client”函数的更多详细信息,请参阅 :ref:`tcp-server-handling-information-" "api` 部分。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 -#: 4e4b61d041b24075b90f598ef42bbe78 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:189 +#: 686ed007e14d4a98b931c0c651bb7bf5 msgid "So what can the setup function do if it fails?" msgstr "那么如果setup函数运行失败了怎么办呢?" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 -#: bfc7899a0ec649d49c956d569bbad0bc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:191 +#: 189abee61a444611a486dec294da6561 #, fuzzy msgid "" "First, the try-except block in the main server loop checks whether the " "error is an ``OSError``. If it is, the main loop will exit directly." msgstr "首先,主服务器循环中的 try 和 except 代码块将检测错误是否为“OSError”。如果是,主循环将直接退出。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:162 -#: 8a3a4854f3a3441b87d0257cb4eb4e52 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 +#: e4e1ba68f4b64dc280490157405acab9 #, fuzzy msgid "" "Secondly, if the error is from the network socket, it first logs the " @@ -387,8 +455,8 @@ msgid "" "And the stop function has been defined as:" msgstr "其次,如果错误来自网络套接字,它会首先输出错误消息,并通过调用函数“stop”来停止服务器。停止函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:171 -#: 4eb334cfa82e4557b51ed511bb35fea1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:204 +#: 9eb5b6fb9d2e4394b3dbb4a1905767d0 msgid "" "To stop the TCP server, it first sets the ``self.running`` variable to " "False, to stop the main loop of the server. After that, it calls the " @@ -398,8 +466,8 @@ msgstr "" "要停止 TCP 服务器,它首先将“self.running”变量设置为 " "False,以停止服务器的主循环。之后,它调用“free_port”函数来释放已分配的端口。 `free_port` 被定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:182 -#: 2d0515291a604c0996149873392657f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:215 +#: 18d7078902794d629ad9f4e92a334402 msgid "" "*Note: For more details of the `free_port` function, see the :ref:`tcp-" "server-port-allocation-api` section.*" @@ -407,8 +475,8 @@ msgstr "" "*注意:有关 `free_port` 函数的更多详细信息,请参阅 :ref:`tcp-server-port-allocation-api` " "部分。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:185 -#: ee8148b7ac254bbba148a8ad7a4ebb94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:218 +#: dc449dddb5014d40a50ff66277707822 #, fuzzy msgid "" "At the end of the operations, the TCP server closes all client sockets " @@ -416,8 +484,8 @@ msgid "" "socket." msgstr "在操作结束时,TCP服务器将关闭字典变量“self.clients”中记录的所有客户端套接字,并关闭服务器套接字。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:188 -#: e3cce971756a4931af9b546a1e12aeb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:221 +#: 1d2d730ca10e484d9dadc386b02af66c msgid "" "Before closing the listening socket it shuts it down, which releases a " "thread that is blocked in ``accept()`` (closing alone would leave the " @@ -428,8 +496,8 @@ msgid "" "come up behind the caller's back." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 -#: eb7d0cdf9cb4455eab2a5ba068942fd5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:228 +#: 2975a8e2dfe646cc92f5b112afc6101f msgid "" "*Note: The ``self.clients`` variable is a dictionary that maps client " "address tuples to an info dictionary. The key is the client address tuple" @@ -442,52 +510,52 @@ msgstr "" "port)``),值是包含连接详细信息的字典,例如``'socket'``、``'address'``、``'id'`` " "和``'connected_time'``。请参阅下面的示例,其中显示了条目的存储方式。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:217 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 +#: 8936cbe70fcf44ac9cabec9e38c0195d msgid "TCP Server handling information API" msgstr "TCP服务器处理信息API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:219 -#: 45ece19ab8684f67b0f85203f442103e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 +#: 1bbc64aa745a4dc3a537c6c10fd9e3c5 msgid "" "The server handling information API documents the core TCP server methods" " that manage client sockets, receive raw data, and send messages." msgstr "服务器处理信息 API 记录了管理客户端套接字、接收原始数据和发送消息的核心 TCP 服务器方法。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:231 -#: 4603ad1e2ffc400491456f7abf750937 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:264 +#: 8b1b042f66a243d9b9abd829a3fefcfe msgid "" "`handle_client` is the main per-client handler in ``TCP_Server_Base``. It" " is invoked after a client connection is accepted and is responsible for:" msgstr "`handle_client` 是 `TCP_Server_Base` 中主要的每个客户端处理程序。它在客户端连接被接受后被调用,并负责:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:235 -#: dbeed4ea23664ab298a9c5e356642ddc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:268 +#: 67121b0c979f421eb7ddbfb432dad873 msgid "" "adding the client entry into ``self.clients`` with socket, address, id, " "and connected time" msgstr "将客户端条目添加到“self.clients”中,其中包含套接字、地址、id 和连接时间" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:236 -#: 98d885826d6743a0ad2c72f44e0e9944 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:269 +#: 65ac2e1844dd4a86a5e550063ee90460 msgid "printing connection information and current client count" msgstr "打印连接信息和当前客户端计数" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:237 -#: f9a1536ee7a540d693a2f4f4b3ad690c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:270 +#: 21670e3d261c41b4a0cbf772ab3f0d73 msgid "sending a welcome message to the client" msgstr "向客户发送欢迎信息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:238 -#: e75d30ed5656490994353520e09cf789 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 +#: a48af59d8ef54c12929e843db0d51e01 #, fuzzy msgid "" "sending the ``/client_alloc_port_range`` information to that client " "depending on the port allocation mode" msgstr "根据端口分配模式向所有客户端广播“/client_alloc_port_range”信息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:241 -#: 0e3762f344ff4b88bbb6699610627b41 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 +#: 034082645d394f158d8927076c6b38e9 #, fuzzy msgid "" "*Note: You can specify the port allocation mode in the arguments which " @@ -496,33 +564,33 @@ msgid "" "``is_hand_alloc_port``.*" msgstr "*注意:您可以在“TCP_Server_Base”类中定义的参数中指定端口分配模式。您可以更改的参数是“port_add_step”、“port_range_num”和“is_hand_alloc_port”。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:247 -#: 3a8f9b23f43a469ca5d7cea807598bd6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:280 +#: 2cb1bb2c2ed84122a479e562a1156bf3 msgid "receiving raw bytes from the socket using `receive_message`" msgstr "使用“receive_message”从套接字接收原始字节" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:248 -#: 8f1c9c44d13e41d1b4fdadac75fc4613 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:281 +#: f4db70de0d7d4b4f9f02a1fc2325b172 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "缓冲传入数据,直到换行符终止的消息完成" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:249 -#: 54fef48b6314483cbd813885b82ead02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:282 +#: c17ac3c5095746448b497f228eb10c88 msgid "splitting and processing each message line-by-line" msgstr "逐行拆分和处理每条消息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 -#: f7728d56338d464cad635232865f9fb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:283 +#: ba1a3439be1d43af80a46d2ee3658ac8 msgid "routing special commands beginning with ``/`` to `handle_command`" msgstr "将以 ``/`` 开头的特殊命令路由到 `handle_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 -#: f87fc68b008a4e06a719e9ab316016f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 +#: 37462f705b094332a79be9d2765c4796 msgid "The `handle_command` function is defined as:" msgstr "“handle_command”函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:263 -#: 8b47f53ad413459393250da7b5f249eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:296 +#: d5bdce3eed0b4171882356d2b207f6d2 #, fuzzy msgid "" "In `handle_command`, there are variable conditional branches to handle " @@ -534,27 +602,27 @@ msgstr "" "在“handle_command”中,有可变条件分支来处理内置命令,如“/help”、“/time”、“/clients”、“/quit”以及一些文件传输命令。如果您已经通过命令扩展" " API 添加了更多命令,该函数将确定输入的消息是否与扩展命令匹配。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 -#: 1b5f22ecb31f4b17bc31eeba617e9373 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 +#: 21bedf659c7c44a783ed367bebbec813 msgid "" "*Note: For more details of the command extension API and the built-in " "commands, see the :ref:`tcp-server-command-api` section.*" msgstr "*注意:有关命令扩展 API 和内置命令的更多详细信息,请参阅 :ref:`tcp-server-command-api` 部分。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 -#: f4e3e8921f9c4825b54b7e26c77dfaa1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:307 +#: 85099f44cbb14013a55dcaf602370b51 msgid "logging normal chat messages and acknowledging receipt" msgstr "记录正常聊天消息并确认收到" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:275 -#: e25f3746f80f4046a7aeb5f0b61bba85 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:308 +#: c4a9e9f9ccd74f0ca064b3fe6a95e739 msgid "" "removing the client from ``self.clients`` and closing the socket when the" " client disconnects or an error occurs" msgstr "从“self.clients”中删除客户端,并在客户端断开连接或发生错误时关闭套接字" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 -#: 21e6108f8c1243a39f017b806967fb1d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:318 +#: 5f6ae0695302473a8adf476a72c72d3a msgid "" "`receive_message` is a thin wrapper around socket receive operations. It " "reads up to ``msg_length`` bytes from the given ``client_socket`` and " @@ -564,25 +632,25 @@ msgstr "" "`receive_message` " "是套接字接收操作的一个薄包装器。它从给定的“client_socket”读取最多“msg_length”字节并返回原始字节有效负载。消息解码和换行消息帧由调用者处理。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:300 -#: b7e713b412334cc98292e1ca8abbf861 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:333 +#: 114485120bad452e8af2626995798eda msgid "" "`send_message` sends data back to a specific connected client. It " "verifies the server is running and the socket is valid, then:" msgstr "`send_message` 将数据发送回特​​定的连接客户端。它验证服务器正在运行并且套接字有效,然后:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:303 -#: 923c92c05c79407e841f3a5d6fefeb92 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:336 +#: 78639cd82b2f42db9ddd7d84bf06e9ee msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "接受“str”和“bytes”消息负载" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 -#: f890eeb62bbc4b5ab359452c6dd40b17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:337 +#: bff4a398dec3443391a0c6e6a9fb00ee msgid "trims string payloads and appends a newline if missing" msgstr "修剪字符串有效负载并在丢失时附加换行符" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:305 -#: 21a1156ab51b4dc598f583c1d9f9defc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:338 +#: 033e533bc19f484bb0fe7d61fe01dc46 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -592,55 +660,55 @@ msgstr "" "当套接字处于加密模式时(公钥交换已完成),明文使用“_VALID”标记进行签名,RSA-" "OAEP使用对等方的公钥加密,base64编码并以换行符结尾,而不是以明文形式发送" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:309 -#: 94980e8ed8db4bfeb6bb4f4278c10d04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:342 +#: 1f1be9fb9dff4409aa040671a8e89013 msgid "encodes string payloads as UTF-8" msgstr "将字符串有效负载编码为 UTF-8" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:310 -#: ce93763396994dbabdc93a51b56ed8c3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:343 +#: 38c4b6970f644bf6b1dee52c1d6f7157 msgid "" "sends the message with ``client_socket.sendall(data)`` when the server " "serves clients with one thread each, or through a non-blocking ``send()``" " loop when ``is_asynic_clients_io`` is ``True``" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:313 -#: eb3454d6feb84ce1a3e00a573cf20972 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 +#: b3f2ff47fdc74a1fb5b599b1f3706a59 msgid "" "returns ``True`` on success; it returns ``False`` for an unsupported " "payload type, and an invalid/closed connection raises ``RuntimeError`` " "(other socket failures are logged and re-raised)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:317 -#: 62174575716644e69c0d479ff05a9df0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:350 +#: 042c1637a86c494ca7da9ba4299b08be msgid "" "And there are also some other functions which are used to send message in" " bulk to the clients, such as the `broadcast` function and the " "`send_msg_to_specific_client` function." msgstr "还有一些其他函数用于向客户端批量发送消息,例如“broadcast”函数和“send_msg_to_specific_client”函数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:325 -#: 762f3bf7c5bb46e091ca12b1f0393624 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:358 +#: eeecf353189a46f8972335c059bef718 msgid "TCP Server encrypted channel API" msgstr "TCP服务器加密通道API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:327 -#: 67ffdc91d9694e77ab33c0c60253430d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:360 +#: e5659287613a419dbbecdc491f57b514 msgid "" "When the server is created with ``is_enable_encrypto=True`` (the " "default), every connected client goes through an RSA public-key exchange " "before any message content is encrypted." msgstr "当使用“is_enable_encrypto=True”(默认值)创建服务器时,每个连接的客户端在加密任何消息内容之前都会经过 RSA 公钥交换。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:332 -#: 8de167f009be4406b25e0e3d3be6cb4b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:365 +#: a31863451ad94e828e4d5826811dc4e9 msgid "Key material" msgstr "关键材料" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:334 -#: 01312565566c4707b6d4b55a223882d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:367 +#: aae09222bb4b42dfb9db4c7ebc329d10 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -652,8 +720,8 @@ msgstr "" "私钥存在于“~/.ssh/id_rsa”中,则它会被重用;否则,将在“network_api/.Flow/pvt_key”(“server_priv.pem”/“server_pub.pem”)中生成新的" " RSA-2048 密钥对。交换的公钥始终源自私钥,因此会自动选取旋转的“~/.ssh”对。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:339 -#: 5e641bcd12c44f73bd22b43332b12b91 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:372 +#: f4206182556e4cca9a9284905e3de143 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -664,8 +732,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 -#: 26f407b8ad29482ca30db4edd0f20abe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:379 +#: bab30142a34845e5b01353a55c4ba643 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -677,8 +745,8 @@ msgstr "" "pvt_key_path]”强制用户提供的密钥对:两个文件必须存在,解析为 PEM " "并相互配对(使用公钥加密的探针必须使用私钥解密);无效的对将被忽略并使用默认查找。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:351 -#: 3af59fcb848044718426e6b9427c017d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 +#: 324dcdafcfa048218e102466956bd1a5 msgid "" "Public keys received from clients are cached in " "``network_api/.Flow/pub_key`` as ``client__.pem`` (the peer " @@ -688,13 +756,13 @@ msgstr "" "从客户端接收到的公钥以“client__.pem”形式缓存在“network_api/.Flow/pub_key”中(密钥来自的对等端点;“:”被替换为“_”,因此" " IPv6 文字在每个平台上都是安全的,包括 Windows)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:357 -#: 26ea5ad884b4402097ce3f800bb7e8d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:390 +#: aee5a1316ad24fab8db1dedeb6c95790 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM 身份检查 (TOFU)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:359 -#: 69fe026672cc44c7b931a2a404468eb0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:392 +#: 8ceb7ab10998464e93c80c1609797ac7 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -707,31 +775,31 @@ msgstr "" "每个连接都以明文形式重新交换公钥,并且每一方都会在“network_api/.Flow/pub_key/pub_key.json”中记录对等点:密钥是“(ip," " port)”(对等点连接的端点的 Python 元组),值是“[<公钥的 sha256>,<公钥 PEM>]”。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:366 -#: f8e45fa616844ba287ea1d9a249d5157 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:399 +#: e63b24b8eded401fb82be09174963c1b msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "来自端点的首次连接:密钥被记录并受信任(首次使用时信任)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:368 -#: faa949fc11b74c9692009fba21d3a5f2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:401 +#: 9c091413145845f3b15fac0bdc9b583c msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " "``(ip, port)`` instead of being duplicated." msgstr "稍后的连接显示*相同*密钥:已接受。如果端点更改(动态 IP / 用户更改的端口),记录将移动到新的“(ip,端口)”而不是重复。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:371 -#: d80fbe47d78343d6a5ae8b7a7388b177 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:404 +#: d89337a304a24744a703acaa977b3290 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is sent and the " "socket closed)." msgstr "稍后的连接为已记录的端点提供*不同的*密钥:连接被拒绝(发送``/crypto_reject``并关闭套接字)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:375 -#: c12761b71fbb40e9b5d9f17ce7389981 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:408 +#: ff44ccbece9b48ab8e86a12cba949078 msgid "" "Because the server-side record is keyed by the client's source port, a " "client that rotates its keypair is only detected when it reconnects from " @@ -742,13 +810,13 @@ msgid "" " (or the whole file)." msgstr "由于服务器端记录由客户端的源端口作为密钥,因此只有当客户端从未更改的端点重新连接时才会检测到轮换其密钥对的客户端;使用操作系统分配的临时端口,新密钥将记录为新端点。客户端记录由固定服务器地址作为密钥,因此更改的服务器密钥始终会被拒绝。要重置信任(轮换密钥、新服务器),请删除“pub_key.json”条目(或整个文件)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 -#: 160b797ceb5340aaa631e6a42ed052f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:417 +#: e011f68df76445d18659be173dba1877 msgid "Handshake" msgstr "握手" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:386 -#: 6f031912413e4e4b8b7105c3c59f1b99 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:419 +#: 700f2215924f4bfb92c3f90f37c3e514 #, fuzzy msgid "" "The client initiates the exchange by sending a plaintext " @@ -757,44 +825,74 @@ msgid "" "Both sides then push their public key files over the file-transfer " "mechanism (plaintext) and TOFU-check the received key. Both sides switch " "to encrypted mode only after ``/crypto_ready`` has been received from the" -" peer (so plaintext and ciphertext never interleave on a connection). On " -"later connections the keys are re-exchanged and TOFU-checked again; the " -"exchange is never skipped, only the identity check short-circuits for " -"known keys. Public-key pushes are only accepted from a connection that " -"actually started the handshake, so an arbitrary unauthenticated peer " -"cannot poison the registry." +" peer (so plaintext and framed traffic never interleave on a connection)," +" then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted from a connection that actually started the " +"handshake, so an arbitrary unauthenticated peer cannot poison the " +"registry." msgstr "" "客户端通过发送明文“/crypto_key_exchange”问候语来启动交换;服务器回复``/crypto_key_exchange_ack " " " "``。然后,双方通过文件传输机制(明文)推送其公钥文件,并对收到的密钥进行豆腐式检查。只有在从对等方收到“/crypto_ready”后,双方才会切换到加密模式(因此明文和密文永远不会在连接上交错)。在以后的连接中,密钥将被重新交换并再次进行" " TOFU 检查;交换永远不会被跳过,只有已知密钥的身份检查会短路。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:400 -#: 1efd337c73d249a3b4b15394337e6307 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:437 +#: a9531ad5339a4633a1e6cc54fb8bb79b msgid "Replay protection" msgstr "重放保护" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:402 -#: 28c8ec1c26d946a19bc02d6aacc9961b -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." +#: ../../source/Network_APIs/TCP_Server_APIs.rst:439 +#: e9505df5322640ce8671b5098d655374 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." msgstr "" -"握手交换随机会话随机数,线路上的每条加密线路都携带它加上每个连接的序列号:``||``。接收方丢弃随机数与当前会话不匹配的行(从旧连接重播的密文)或其序列号不是预期的行(会话内重播的密文/乱序);当套接字在(重新)交换后切换到加密模式时,两个计数器都会重置。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:411 -#: c11de683c36c42c59ff73d0839f5afce +#: ../../source/Network_APIs/TCP_Server_APIs.rst:455 +#: 3fd7ac4d381e41589a62998726dd22f7 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:457 +#: 8ca69d91005b459a8a56f21902eaa690 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:469 +#: b32b4fa4788d4f9d88926958c81ad73f msgid "Decode verification and key rotation" msgstr "解码验证和密钥轮换" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:413 -#: ba7b28826b9f4d0a85328f08be4a76e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:471 +#: d09ae3121b0f40fb85374589b851d45c msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -811,20 +909,25 @@ msgstr "" " TOFU 检查:密钥未更改的对等点将再次被接受,而为记录的端点提供“不同”密钥的对等点将被拒绝(请参阅上面的 TOFU " "部分)。故意轮换密钥对的用户必须删除对等端过时的“pub_key.json”条目(或整个文件)才能重新信任新密钥。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:424 -#: 6f0160000f2b451a81771556bbc3b8e7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:482 +#: 7312fb4bd4c345ff9cec7ffe4245afb7 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures on one connection the connection is closed " "instead of re-exchanging, so a garbage-injection or persistent-mismatch " -"storm cannot spin the loop forever. A successful decryption resets the " -"counter." +"storm cannot spin the loop forever. Genuine peer traffic (messages and " +"commands other than the protocol's own handshake/coordination lines) " +"resets the counter. Frames the peer had already sent when this side " +"dropped out of encrypted mode are stale: they cannot be authenticated any" +" more, so they are consumed and dropped — they neither surface as " +"messages nor reset the counter." msgstr "" "重新交换是断路的:在一个连接上“MAX_DECODE_FAILURES”(3) " "连续解码失败后,连接将被关闭而不是重新交换,因此垃圾注入或持久不匹配风暴无法永远旋转循环。成功解密会重置计数器。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:438 -#: 850c5c67b6504551a3104a9cfa5710e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 +#: 4fb05c76f6734fd58aa33ee628ad933d #, fuzzy msgid "" "The `broadcast` function sends a message to all clients in the " @@ -834,8 +937,8 @@ msgid "" "the ``exclude_client`` parameter when sending the message." msgstr "在“broadcast”函数中,它将向“self.clients”变量中的所有客户端发送消息,并删除已经与服务器断开连接的客户端。如果“exclude_client”参数不是“None”,则服务器在发送消息时将排除“exclude_client”参数指定的客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:452 -#: 9ddd28be0e6b439891a25d79adbaf823 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:514 +#: 0b4f67331831429b85514fbbe3ce2602 #, fuzzy msgid "" "The `send_msg_to_specific_client` function sends one or more messages to " @@ -848,41 +951,43 @@ msgstr "" "`send_msg_to_specific_client` 函数用于通过客户端 ID " "向一个或多个特定客户端发送一条或多条消息。并且“message”参数应该输入发送消息命令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:459 -#: 4f7cd128081c4062bffdacfb4b67137c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 +#: c8f357719cc548719792a5a2cade0c03 msgid "" "These methods form the server's client I/O loop and ensure reliable " "message exchange for connected TCP clients." msgstr "这些方法形成服务器的客户端 I/O 循环,并确保连接的 TCP 客户端进行可靠的消息交换。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:466 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 +#: 8936cbe70fcf44ac9cabec9e38c0195d #, fuzzy msgid "TCP Server inbound event listener API" msgstr "TCP服务器文件传输API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:468 -#: f86e7c53407b43509932d19288024a54 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 +#: 583ef0a34dfc480da5b4fc87108cbf2f msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:478 -#: f59f2230d9f648ca99834633af460deb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:540 +#: 0a30ecd70b364968a892136d9bec809f msgid "" "``add_message_listener`` registers ``listener(client_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to the command handlers instead). ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a" -" file uploaded by a client has been fully written to the transfer " -"directory (``command`` is the wire command that triggered it, so protocol" -" pushes such as ``/crypto_pub_key`` can be recognised). Both listeners " -"run on a protocol thread, so they must not block, and an exception inside" -" a listener is logged and swallowed. The ``remove_*`` counterparts " -"unregister a listener and ignore unknown ones." +"every inbound line, commands included (``/help``, ``/file ...``, the " +"crypto handshake lines, ...), so a listener observes all inbound traffic;" +" line dispatch is unaffected, a command still goes to the command " +"handlers. ``add_file_listener`` registers ``listener(client_id, " +"full_path, name, size, command)`` and fires after a file uploaded by a " +"client has been fully written to the transfer directory (``command`` is " +"the wire command that triggered it, so protocol pushes such as " +"``/crypto_pub_key`` can be recognised). Both listeners run on a protocol " +"thread, so they must not block, and an exception inside a listener is " +"logged and swallowed. The ``remove_*`` counterparts unregister a listener" +" and ignore unknown ones." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:489 -#: a39677d08af4439989a6fced80cb12d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:553 +#: a7bb1a9276bd4860882ffd43a680d6bf msgid "" "In addition, received messages and events are stored per sender socket in" " ``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -891,30 +996,31 @@ msgid "" "``network_api/.Flow`` and cleared; ``stop`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:498 -#: cdfe98e71ed34af9a2976b7e884b5201 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 +#: 403a3b0e938b4895be69267c66ecff98 msgid "TCP Server command API" msgstr "TCP 服务器命令 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 -#: 25c853b63e744fd6a370ecd365c58fd7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 +#: 9c016262f199458585bb12055da6d30d msgid "" "The server supports several built-in commands and a command extension " "API. The main entry point is the `handle_command` method, which is " "invoked for any message starting with ``/``." msgstr "服务器支持多个内置命令和命令扩展 API。主要入口点是“handle_command”方法,任何以“/”开头的消息都会调用该方法。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:505 -#: d0e290f03c1242b580024033ffab5e04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 +#: b26b06ec49a644c9b034acf6930006bd #, fuzzy msgid "" "We support two solutions for command handling: inputting a command in the" " console or receiving a command from other clients. You can also call the" -" functions defined for each command in the code." +" functions defined for each command in the code via " +"`call_extension_functions`." msgstr "我们支持两种命令处理方案,一种是在控制台输入命令,另一种是从其他客户端接收命令,您也可以调用代码中为命令定义的函数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:510 -#: aad12adb23334f4e9c5b6b7f7637dd3e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:575 +#: 5f20432236324511acfc720b1e616e49 #, fuzzy msgid "" "*Note: You can select the solution which you want to use by changing the " @@ -925,81 +1031,93 @@ msgstr "" "*注意:您可以通过更改“TCP_Server_Base”类的参数来选择要使用的解决方案,该参数为“is_input_command_in_console”。" " ``True`` 允许服务器在控制台输入命令,而``False`` 不允许。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:517 -#: 88e051e4fef245c7a474a8478dc74b88 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:582 +#: cc5dd7cfa448466399da9463e53c1a08 msgid "Built-in client commands include:" msgstr "内置客户端命令包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:519 -#: c8a591e28fcf4243862e820e582e9127 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:584 +#: 989d1b29c70e4f9883b95523b0b420d9 msgid "``/help``: returns the available command list and usage hints." msgstr "``/help``:返回可用的命令列表和使用提示。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:520 -#: 453004b0bb914398a4d9a437f5d1b864 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:585 +#: a4795afd8b3249538f031ed27783f0a7 msgid "``/time``: returns the current server time." msgstr "``/time``:返回当前服务器时间。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 -#: 324cbdab33984517a498f1e2747a6387 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:586 +#: b2d813b2d8bb46c59195ed01431d150b msgid "``/clients``: returns the list of connected client IDs." msgstr "``/clients``:返回已连接的客户端 ID 列表。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:522 -#: a4411c0f498c434fbe864ea1627384fb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:587 +#: d81ad6c5cbe44bd589f32ce7f3e36d31 msgid "" "``/quit``: writes a goodbye message (``Bye!``) and shuts the connection " "down, so a client that stays after sending ``/quit`` is disconnected by " "the server." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:525 -#: 1248e1b365da420e8d96182e8a237d57 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:590 +#: a9fbf429095b4483b18a247ef327b461 msgid "" "``/file [destination_file_path]``: starts a file transfer " "from the client to the server. The trailing token of the wire line is the" " sender's own transfer id, appended by the sending client." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 -#: c8de5282934945bab929e1084d7848f5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 +#: cef48a93703449f8813fab1d3fb199fb #, fuzzy msgid "" "``/file_folder [destination_file_path]``: starts a folder " "transfer from the client to the server (same trailing id)." msgstr "``/file_folder ``:启动从客户端到服务器的文件夹传输请求。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 -#: d006c91db83f4404b7f7022cb9bb61c5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:595 +#: 92bf2736c9c14f1cb24ec110315f8caa msgid "" "``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``:" " internal handshake messages of the encrypted channel." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:532 -#: c026024882d44552a578b0fe4e096b34 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:597 +#: 38987654adbf4707b84c8048a9cdcbb3 msgid "" "``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, " -"``/start_trans``: internal forwarding/transfer-control messages." +"``/start_trans``: internal forwarding/transfer-control messages. " +"``/pause_trans `` and ``/start_trans `` hold and release the " +"outbound transfer with that fid (`pause_trans`/`start_trans` are the same" +" switch as a public API)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:534 -#: 5fb7405e0dae4344a58d3a61aa5f2779 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:601 +#: 7f3801d57ac34670bbe16736683db30e +msgid "" +"``/resume_trans `` and ``/forward_resume " +"``: internal transfer-reconnect messages: the receiver asks the " +"sender (or, for a forwarded transfer, the originator) to continue the " +"file from the bytes already on disk. See `resume_transfers`." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:605 +#: abd7d3032e15468e92f96a0b5af1f926 msgid "" "``/server_file_transfer_port ``: internal protocol " "message used to coordinate file transfer ports." msgstr "``/server_file_transfer_port ``:用于协调文件传输端口的内部协议消息。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:536 -#: 94f93b06051f4eebaf0b64ccf589160b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:607 +#: 1e9e32071bb1425b8617a419a7ef87f6 msgid "" "In `handle_command`, the server will first check if the command matches " "any built-in commands. If it does, the `handle_command` will call the " "functions which are defined for the commands." msgstr "在`handle_command`中,服务器将首先检查该命令是否与任何内置命令匹配。如果这样做,“handle_command”将调用为命令定义的函数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:541 -#: 16991ef553344476af487507dc3a1a0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:612 +#: f08564b44ab0442788145105b1086bb8 msgid "" "If a command is not recognized by the built-in handler, `handle_command` " "will check if it matches any registered custom commands from the command " @@ -1010,30 +1128,38 @@ msgstr "" "如果内置处理程序无法识别命令,“handle_command”将检查它是否与命令扩展 API " "中注册的任何自定义命令匹配。如果该命令已注册,则“handle_command”将调用为该命令定义的函数。命令扩展 API 定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:559 -#: 9c0334fe21e34b6ab8b1c941e1c62e2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:633 +#: ac06208b93d54ede93002123521d921b +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code; the command's first token selects it, exactly as it does for " +"a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:637 +#: 11c186c6375b4eeeb337ac755b136a94 msgid "The args of the `register_command` function are as follows:" msgstr "`register_command` 函数的参数如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 -#: ac4db02fce3d492b81a094400f44b0a8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 +#: 6741d64e02414c1c8759b14d41ec69a1 msgid "``command_name``: The name of the command to register." msgstr "``command_name``:要注册的命令的名称。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 -#: 8e250a4664ce40c89f0190ce7eb67848 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:642 +#: 21a28c492d33486a81f97ca3d8a32266 msgid "" "*Note: The ``command_name`` should start with a slash (e.g., " "``/my_command``) to be recognized as a command.*" msgstr "*注意:``command_name`` 应以斜杠开头(例如,``/my_command``)才能被识别为命令。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:567 -#: f91cdc45f9ea4c35891b087f1097ba51 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:645 +#: 6deb6588265049cbbeaea615b7d6c2cf msgid "``handler``: The function to call when the command is received." msgstr "``handler``:收到命令时调用的函数。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 -#: 1797ec404bbe45b380d46588adbb731f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:647 +#: 16d22c49f16d4430bfe740374d70705f #, fuzzy msgid "" "*Note: The ``handler`` function must have exactly three parameters: " @@ -1047,20 +1173,20 @@ msgstr "" "``client_socket`` 将被接受为发送命令的网络套接字对象,``client_address`` " "将被接受为发送命令的客户端的地址,而``command`` 参数将包含实际的命令字符串。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:577 -#: 56b8f72098b84ccea4d1bf143a31e04c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:655 +#: 7605062541fa4d70ae37d67efdfd5fdf msgid "``where_to_run``: Specifies where the command should be executed." msgstr "``where_to_run``:指定应执行命令的位置。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:578 -#: 7572e9944acd4704b2c55643fb1fbcd4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:656 +#: f6ee42356212497ba468266c87e127d4 msgid "" "``run_in_thread``: A boolean indicating whether to run the command in a " "separate thread." msgstr "``run_in_thread``:一个布尔值,指示是否在单独的线程中运行命令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:580 -#: 0ac212e49ef54e77b5429272e05561aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:658 +#: 37adfd2db6af47bf995b271dd70ad293 msgid "" "This extension API allows server-side and console-side custom commands to" " be registered dynamically. Valid values for ``where_to_run`` are " @@ -1072,16 +1198,16 @@ msgstr "" "此扩展 API 允许动态注册服务器端和控制台端自定义命令。 “where_to_run” 的有效值为“服务器”和“客户端”。 " "“服务器”表示当客户端发送命令时将处理该命令,而“客户端”表示当服务器在控制台中输入命令时将处理该命令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:589 -#: c0201e2dd3fd4c7fa8d363060c5ff49a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:667 +#: 24c64499179b4f01a92ffd8e88515738 #, fuzzy msgid "" "*Note: It's true that the valid values for ``where_to_run`` are not " "ideal, but we have not yet found a better way to define that.*" msgstr "*注意:确实,``where_to_run`` 的有效值太奇怪了,但我们没有找到更好的方法来定义它。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 -#: ec3b9b188728413eb3cd5871542b83cd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:671 +#: fbdb162f54a64fd3b454ddbf85a6e5d4 #, fuzzy msgid "" "The ways to run the command will be different according to the args " @@ -1092,8 +1218,8 @@ msgid "" "receive thread, or the caller of ``handle_command``)." msgstr "根据参数“run_in_thread”,运行命令的方式会有所不同。如果“run_in_thread”为“True”,则命令处理程序将在服务器线程池中的单独线程中执行。如果“run_in_thread”为“False”,则命令处理程序将在主服务器线程中同步执行。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:603 -#: 0a62647e915e4e4c80071b3d7fb41464 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:681 +#: 9576b9601ddd48749947aa7b18bc2c82 #, fuzzy msgid "" "*Note: We store the registered commands in a list variable with two " @@ -1109,23 +1235,23 @@ msgid "" "that should be run in a separate thread or not.*" msgstr "*注意:我们将注册的命令存储在一个列表变量中,该列表变量的内层有两个字典,该列表变量定义为“self._custom_handlers”,在“__init__”方法中初始化。命令及其处理程序将根据“where_to_run”的值存储在其中一个字典中。对于``“server”``,它将存储在第一个字典中,否则存储在第二个字典中。字典的键都是命令名,值是另一个包含处理函数的字典。还有另一个列表变量定义为“self._custom_handler_threaded”,它在“__init__”方法中初始化,它包含所有应该在单独线程中运行或不运行的命令。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:617 -#: eb202f79be654e5a8cccf56c79446b3d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:695 +#: b1f239408f354bf2bdc608ad523f233e msgid "" "*Note: ``register_command`` returns ``False`` when ``where_to_run`` is " "neither ``\"server\"`` nor ``\"client\"`` (nothing is registered then); " "on success it returns ``None``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:626 -#: 088dcc7ce39046a4afa6451d7e6369f9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:704 +#: b10dad811f9b444bb0a2e3642709b5d1 msgid "" "After that, the command handler will be called according to the command " "name, and run them by a command executor which is defined as:" msgstr "之后,命令处理程序将根据命令名称被调用,并由命令执行器运行它们,命令执行器定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 -#: 0e56345aa429469cb44d7708b6af8711 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:718 +#: 7c0987568cf245b9b78d1db2f403717f msgid "" "In this executor function, there is a try-except code block to catch the " "error when running the command handler. If there is an error when running" @@ -1139,8 +1265,8 @@ msgstr "" "代码块来捕获运行命令处理程序时的错误。如果运行命令处理程序时出现错误,服务器将记录错误消息,并且如果命令来自客户端,也会将错误消息发送回客户端。在" " try 代码块中,将使用命令参数调用命令处理程序,如果命令来自客户端,还会使用客户端套接字和客户端地址。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:650 -#: 6467226e231c4e458bb78687c9da8659 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:728 +#: a98408c31eee4f3fbad1c3afdb2a036c #, fuzzy msgid "" "If the command doesn't run in the thread, the command executor will be " @@ -1150,8 +1276,8 @@ msgid "" "defined as:" msgstr "如果命令不在线程中运行,则命令执行器将直接在“handle_command”函数中调用。但是如果命令应该在单独的线程中运行,则命令执行器将使用“submit_task”方法提交到服务器的线程池,该方法定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:665 -#: fb9ac9433b8342dd9e90707a01990fd0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:743 +#: c3401f2293044a31a7e8e6d2e8407797 #, fuzzy msgid "" "The `submit_task` method is a helper function that submits a callable to " @@ -1163,8 +1289,8 @@ msgid "" "loop." msgstr "“submit_task”方法是一个辅助函数,它将可调用函数提交给服务器的内部线程池执行器。它接受一个函数及其参数,并安排它在单独的线程中执行。这允许长时间运行或阻塞命令处理程序运行而不会阻塞主服务器循环。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:675 -#: 711e7a3b8f114200857fc39218e2820f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 +#: 9a327fd5482b4575a777e49024f42f56 msgid "" "In this high-level TCP network protocol, a temporary TCP server and " "client can also be created very simply. The temporary TCP server or " @@ -1177,8 +1303,8 @@ msgstr "" "服务器或客户端可用于需要额外套接字或端口以避免与主服务器或客户端循环发生冲突的场景。例如文件传输功能。创建临时 TCP 服务器和客户端的 API " "定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:688 -#: 7368e712e93f4be7aaeeae265b22e832 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:766 +#: b1e9ab095ed84ef8ae08333047df5b93 msgid "" "``create_temporary_server`` returns ``(port, thread, stop_event)``: the " "bound port (``palloc()`` picks one when ``port`` is None), the accept-" @@ -1187,44 +1313,44 @@ msgid "" " allocated." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:693 -#: 0750bd372cf6478eb8123ca0603de9c2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:771 +#: d23ff87180c44746b62528903a34cdb5 msgid "" "``create_temporary_client`` returns ``(client_socket, thread, " "stop_event)``: the connected socket, the receiver thread and an event " "whose ``set()`` ends that thread." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:700 -#: edf78b86ed664657adc2b46ab0f7efdd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:778 +#: c14e33129d3b41ee8c1dac7189f0408d msgid "TCP Server console commands" msgstr "TCP 服务器控制台命令" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:702 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:780 +#: 2ad09a3887894e01a67d31c28272f730 msgid "" "The server console input thread accepts administrative commands when " "``is_input_command_in_console`` is ``True``. Supported console commands " "include:" msgstr "当“is_input_command_in_console”为“True”时,服务器控制台输入线程接受管理命令。支持的控制台命令包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:706 -#: 5a059eb897914040873e954609c66c0c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:784 +#: 4d4368102eae41dbac5a8938a4726e1a msgid "``/stop``: stops the server and closes all active connections." msgstr "``/stop``:停止服务器并关闭所有活动连接。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:707 -#: db67da00bf70423a9a3cf4a2fa3a01e1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:785 +#: 8035f922921f4301bbe4ca4936ea38b3 msgid "``/status``: prints the current connection count and running state." msgstr "``/status``:打印当前连接计数和运行状态。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:708 -#: 15ab35eecbd84e64b8dfc0ac50c3d173 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:786 +#: ce2138bd90784f1daffb39cc8d46d1f1 msgid "``/clients``: prints the connected clients and their connection times." msgstr "``/clients``:打印连接的客户端及其连接时间。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:709 -#: 2d1d3fe9ee9f4d6899754d296f8ede75 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:787 +#: 8c9f96a3d0cd4fbcb311c201db9ff789 msgid "" "``/send_msg <(ip, port)> ...``: sends one or more messages " "to specific clients. Targets are literal ``(ip, port)`` tuples (its own " @@ -1232,24 +1358,24 @@ msgid "" "form)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:710 -#: 92d75f708fe642cf8a77f986f2d891b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:788 +#: 033fdbf663a04e12bfdff63da6e0f6c1 #, fuzzy msgid "" "``/file <(ip, port)> [destination_file_path]``: sends a file " "from the server to a specific client." msgstr "``/file ``:将文件从服务器发送到特定客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:711 -#: 8b28ccd83c594ee5a0ccd126db3bb2dd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:789 +#: 49fea0c411844c689ea2cabaa11c70b3 #, fuzzy msgid "" "``/file_folder <(ip, port)> [destination_file_path]``: " "sends a folder from the server to a specific client." msgstr "``/file_folder ``:将文件夹从服务器发送到特定客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:712 -#: 585e54ca3b1545f49a347b69680d3cd2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:790 +#: d4c2a98b15c04214bfca54bd719f9ab4 msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " "port)2> ...``: sends multiple files to multiple clients. Tokens are " @@ -1257,8 +1383,8 @@ msgid "" "otherwise, so files and targets may be interleaved." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:713 -#: 60def6731a3a43d1a074374978801dbc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:791 +#: e6c9995a12a24a6ba5534e475f158d86 msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, " "port)1> <(ip, port)2> ...``: sends the files that precede a group of " @@ -1267,13 +1393,13 @@ msgid "" " that is not a tuple) is accepted and passed on." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:714 -#: 0f9a9437ddcd4894b6be7502e1303c6e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:792 +#: d8253e90b4fe4d8dbe0b2bbd23134dc0 msgid "``/help``: prints a help summary of console commands." msgstr "``/help``:打印控制台命令的帮助摘要。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:716 -#: 1e898bf6aeb54dcb8533615767d03791 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:794 +#: 8cf019297938433ebe65839a4513ae63 msgid "" "The forward commands (``/forward_send_msg``, ``/forward_file``, " "``/forward_folder``) are client-only and are refused on the server " @@ -1281,15 +1407,15 @@ msgid "" "``where_to_run=\"client\"``." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:721 -#: aff923b39d6843bb976f5bb40d38a71d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:799 +#: 43db2954705945c3b3b0742033f122b9 msgid "" "These console commands make it easy to manage the active server and " "perform server-initiated file transfers without modifying the code." msgstr "这些控制台命令可以轻松管理活动服务器并执行服务器启动的文件传输,而无需修改代码。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:725 -#: bcbb903def99415298bb7b29d21f31f6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:803 +#: 261fde939721476abba9b40f0290944f #, fuzzy msgid "" "*Note: It is too long to introduce all the console commands, so for more " @@ -1298,20 +1424,20 @@ msgstr "" "*注意:由于篇幅太长,无法介绍所有控制台命令,因此有关更多详细信息,请参阅 :ref:`tcp-server-console-commands` " "部分。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:729 -#: c68a8d4ecb904da7980049abc5210fdf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 +#: 0e848b37570e4fc8b23ff7eb13a2ae3e msgid "TCP Server file transfer API" msgstr "TCP服务器文件传输API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:731 -#: 1e9d70417dbf4446bc8528cf692db8ed +#: ../../source/Network_APIs/TCP_Server_APIs.rst:809 +#: 27472ef4f13641ba9a08e6a97bb651dc msgid "" "The TCP server contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers." msgstr "TCP 服务器包含一个文件传输子系统,支持客户端到服务器和服务器到客户端传输。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:735 -#: 695753d4c2bc4f15972565a20be6b6c8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 +#: eadd29678d8a449c9659c4792b5f2cb0 #, fuzzy msgid "" "It's too long to introduce all the file transfer functions, so there is " @@ -1319,40 +1445,40 @@ msgid "" "details of the file transfer functions, please visit ..." msgstr "由于篇幅太长,无法介绍所有文件传输功能,因此仅列出了文件传输功能的 API 列表,想要了解更多文件传输功能的详细信息,请访问..." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:740 -#: 5f303019ed3747a691e61b7f20cdb1cf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:818 +#: 1ca2a6ce0f124ebc87676b1155c4c022 msgid "The file transfer API for you to use includes:" msgstr "供您使用的文件传输 API 包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:742 -#: 376da0b60e9641efa6a75ed7e52af8bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:820 +#: 63c118c7e7c4478fa14f3cb0950f6c1c msgid "The basic function for the server-to-client file transfer is defined as:" msgstr "服务器到客户端文件传输的基本函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 -#: 80a158519403430f8f7c43893634e6d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 +#: 4e3a0194c55744898eb3884b60d75672 msgid "The file transfer function which will run in the threads is defined as:" msgstr "将在线程中运行的文件传输函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:764 -#: 771b5bd6acad467d92fbeebcacbc6dba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 +#: 3fd7ac4d381e41589a62998726dd22f7 msgid "The folder transfer function is defined as:" msgstr "文件夹传输函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:773 -#: da45b1e2fcc34c1a96c1d1f9e809f742 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 +#: 833a77a7c8fa480db0a0b6e8387132d3 msgid "The multiple files transfer to multiple clients function is defined as:" msgstr "多个文件传输到多个客户端功能定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:783 -#: 15099b87947a4f08a34ca87734c23306 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:861 +#: 26032ba6212f443980c40351874b2139 msgid "" "The different multiple files transfer to the different multiple clients " "function is defined as:" msgstr "不同的多个文件传输到不同的多个客户端函数定义为:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:793 -#: d93a80b4acca404f98faaf0a7f133079 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:871 +#: 0c9b95c194634285aade290fb17bef5b #, fuzzy msgid "" "We recommend that if you want to use the mono-file transfer function, use" @@ -1372,8 +1498,8 @@ msgstr "" "file_transfer_server_recv_client_start " "函数,否则文件传输函数可能不太稳定。而对于其他文件传输函数,我们不太建议您在线程中使用它们,因为函数中已经有一些线程控制机制,所以不必担心并发性能。如果你在线程中调用它们,可能会出现一些意想不到的错误,而且也可能会变得不必要的复杂性。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 -#: c3f69c0b152c44df91753c54cf94593f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:885 +#: 28c7d60dd34d48ababd9c06199091309 msgid "" "*Note: The file transfer API functions are designed to be called from the" " command handlers for both client-initiated and server-initiated " @@ -1383,18 +1509,18 @@ msgstr "" "*注意:文件传输 API " "函数设计为从命令处理程序调用,以进行客户端启动和服务器启动的传输。它们处理传输端口、客户端连接和实际文件数据传输操作的协调。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 -#: 666eecd4aa974e2d8b5b9a1ff3acbc25 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:891 +#: 0fcf1a7def3e437d9ecbaf8d5d02470a msgid "Client-to-server transfer flow:" msgstr "客户端到服务器的传输流程:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:815 -#: f6b96397ab484021974c50cf86144a12 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:893 +#: 740bd9ad4564417e8f76f28500d1da68 msgid "The client sends ``/file`` or ``/file_folder`` to request a transfer." msgstr "客户端发送``/file`` 或``/file_folder`` 来请求传输。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:817 -#: d6b57e1e1e6e4ea78d59d9a47a1a4ccc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:895 +#: e26bd8a6fb5a4977a3039fd2bdf22114 #, fuzzy msgid "" "``handle_command`` starts a dedicated file-server thread: " @@ -1403,8 +1529,8 @@ msgid "" "``/file_folder``." msgstr "“handle_command”使用“file_transfer_server_recv_server_start_thread”启动专用文件服务器线程。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:821 -#: 3ba05b4bc071401d959f68b7019c7aa3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:899 +#: e5ef46040255421fa92c6de33d976671 msgid "" "The server allocates an ephemeral transfer port with ``palloc`` and sends" " ``/server_file_transfer_port `` back to the client." @@ -1412,65 +1538,65 @@ msgstr "" "服务器使用“palloc”分配临时传输端口并将“/server_file_transfer_port " "”发送回客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:825 -#: 9f8b5c7e3b8048c9b9ded191ecd70d6b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:903 +#: 6eaa70d4d985489e8f0e683baa6b52a1 msgid "" "The client connects to that transfer port and sends file metadata, " "including length-prefixed filename and file size." msgstr "客户端连接到该传输端口并发送文件元数据,包括带长度前缀的文件名和文件大小。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:828 -#: 95c2b39e285840678adb522483da672b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:906 +#: 245d5d51d72a41ee86c9925ec1872e35 msgid "The server receives the file and writes it under ``received_files``." msgstr "服务器接收文件并将其写入“received_files”下。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 -#: 8254cf417a46471ea770e4917e96b05b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 +#: 5ad02fbb498f483580e470b2f5291a53 msgid "Server-to-client transfer flow:" msgstr "服务器到客户端的传输流程:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:833 -#: 69032201d7254006b52a86961f08530a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:911 +#: 341ba310459442de906ec90ad72a16d9 msgid "" "``file_transfer_server_recv_client_start`` is used to initiate outgoing " "transfers from server to a connected client." msgstr "``file_transfer_server_recv_client_start`` 用于启动从服务器到连接的客户端的传出传输。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:835 -#: 408f93d233f44860a854950b3e60f8f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:913 +#: c5f727be6f954b9d87c3ebf0b8ae32ce msgid "" "The server sends transfer commands to the client socket and waits for the" " client to establish the file transfer connection." msgstr "服务器向客户端套接字发送传输命令,并等待客户端建立文件传输连接。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:837 -#: 718dadb723164e65a2eb6fdcfb7d8420 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:915 +#: 88151618a44849269aea215557a4ca1c msgid "" "Folder transfers are performed recursively, with each file transfer " "respecting ``self.max_file_transfer_thread_num`` and the configured " "semaphore limit." msgstr "文件夹传输以递归方式执行,每个文件传输都遵循“self.max_file_transfer_thread_num”和配置的信号量限制。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:840 -#: f23efbda41cb40289b93c954f6d051b0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:918 +#: 4734f1f535e7485ca5c91b06dec65f79 msgid "Common file transfer helper methods include:" msgstr "常见的文件传输帮助方法包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 -#: b86c426b7c8a46b59735ef1a6a0da725 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:920 +#: aaa12a7a9d3f4adeb08d59d5fbc9d131 msgid "" "``file_transfer_server_recv_server_start``: receives file data from a " "client." msgstr "``file_transfer_server_recv_server_start``:从客户端接收文件数据。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:843 -#: 74859cc9d4a745d99225f6522b4455c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:921 +#: 404a990c105247b09e2f2d1716527269 #, fuzzy msgid "``file_transfer_server_recv_client_start``: sends a file to a client." msgstr "``file_transfer_server_recv_client_start``:将文件或文件夹发送到客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:844 -#: 78042f93790547a8a844087d3daf81b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:922 +#: 0ec7dfbbfb1644f1ad5c42a1b2a04dc9 #, fuzzy msgid "" "``file_transfer_mode``: performs the low-level sender-side transfer " @@ -1478,28 +1604,28 @@ msgid "" "key to a client)." msgstr "``file_transfer_mode``:执行低级客户端传输握手。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:846 -#: a03a3b41f63c4c7d8e6800e6e42c215f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:924 +#: 6056cfcc5fa740e58986f2e8ce900042 msgid "" "``file_transfer_mode_recv``: performs the low-level receive-side transfer" " handshake." msgstr "``file_transfer_mode_recv``:执行低级接收端传输握手。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 -#: 82f418a15fbf4c009e188c0fe656a483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:929 +#: e0dc9b775fb94f0ab2728b56c57f88bd msgid "Port allocation API" msgstr "端口分配API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:853 -#: c041090f476c4f37a46fc7a3f49653cb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:931 +#: 9711bca31e6b464e940739ba262f5153 #, fuzzy msgid "" "The server allocation APIs allow you to allocate a new port for other " "servers. There are two kinds of port allocation modes." msgstr "服务器分配 API 允许您为其他服务器分配新端口。端口分配方式有两种。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:857 -#: 4fa11de65ebc4b51b83ea26802b43e3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:935 +#: 30e2a47526db46b29ef31b8730b5dd8a msgid "" "To change the port allocation mode, you can set the " "``is_hand_alloc_port`` argument on the server instance. When set to " @@ -1507,8 +1633,8 @@ msgid "" "mode, or set to ``True`` it will choose the manual allocation mode." msgstr "要更改端口分配模式,您可以在服务器实例上设置“is_hand_alloc_port”参数。当设置为“False”时,服务器实例将选择自动端口分配模式,或者设置为“True”时,服务器实例将选择手动分配模式。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:863 -#: aaa3428304234c0f81e2f83ab0481f17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 +#: 2a3a8472358240aea19de918a8d83602 #, fuzzy msgid "" "We strongly recommend using the automatic port allocation mode, which is " @@ -1518,16 +1644,16 @@ msgid "" "``0``." msgstr "我们最推荐您使用自动端口分配模式,这是服务器的默认模式,因为自动端口分配模式比手动端口分配模式更简单,也更稳定。在此模式下,调用分配API时,将返回``0``。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:870 -#: f9fbfedba34e4c3386442a9425b52a44 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 +#: 29df017de0bc4b399ebbe204db974707 msgid "" "*Note: The `bind` function in standard lib `socket` of the python " "executor, when input ``0`` to the port parameter, will automatically " "assign an available port by operating system.*" msgstr "*注意:python执行器的标准lib `socket`中的`bind`函数,当端口参数输入``0`时,操作系统会自动分配一个可用的端口。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:875 -#: 4a1a578af0b14571a4180ebfc88073d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 +#: df4b1b82912e444c89fd2ea7adbec615 #, fuzzy msgid "" "The other port allocation mode is the manual port allocation mode, there " @@ -1536,8 +1662,8 @@ msgid "" " may conflict and may cause unexpected errors." msgstr "另一种端口分配方式是手动端口分配方式,服务器有一个端口分配范围。请避免在同一主机上打开其他服务器,因为在现有版本中,端口分配范围会发生冲突,并可能导致一些意外错误。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:882 -#: d9301928a8f643868d7cc5852f986e0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 +#: c835077f32f6478a8c0ad000340fd11f msgid "" "The range of the port allocation is configured in the server settings. " "The minimum allocatable port is ``self.port-" @@ -1547,8 +1673,8 @@ msgstr "" "端口分配的范围在服务器设置中配置。最小可分配端口为“self.port-" "self.port_add_step*self.port_range_num”,最大可分配端口为“self.port+1+self.port_add_step*self.port_range_num”。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:888 -#: 17b2666361504a0d8f5e10eb5fc9056a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 +#: 5ad5c89c89a141f2bb5c56e49b94bf1a msgid "" "*Note: The ``self.port`` is the ``port`` argument of the server class. " "The ``self.port_add_step`` is the ``port_add_step`` argument. And the " @@ -1557,13 +1683,13 @@ msgstr "" "*注意:“self.port”是服务器类的“port”参数。 “self.port_add_step” 是“port_add_step” 参数。 " "``self.port_range_num`` 是``port_range_num`` 参数。*" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:894 -#: fefbe2307beb49d083c05018a96a2f3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 +#: 8ea7c9e4e1ad46efb978d3d466a53db6 msgid "There are some relevant methods that can be used:" msgstr "有一些相关的方法可以使用:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 -#: 60738ce1224042aa9b39f5e5feec0e95 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 +#: f9525c162a254de4b11de650677ffd79 #, fuzzy msgid "" "The `palloc` method allows you to get a port. When using this function, " @@ -1575,8 +1701,8 @@ msgid "" "persistent log (no-ops in automatic mode)." msgstr "`palloc` 方法允许您获取端口。使用此函数时,您无需担心端口分配模式,因为此方法中已经实现了分配模式检测器。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:919 -#: 54ccf91661524b1487fb666243fb627a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:997 +#: dee22bb387e140e9ae43d6ebc9afbd58 #, fuzzy msgid "" "The `pfree` method allows you to free a port. Like the `palloc` method, " @@ -1584,16 +1710,16 @@ msgid "" "method." msgstr "`pfree` 方法允许您释放一个端口,与 `palloc` 方法相同,使用该方法时不需要关心端口分配模式。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:923 -#: f4a62c2b675845148f52b3437e9c151e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1001 +#: 6bd53cf6dcea462fbad9ca450e42eec4 msgid "" "And there are the main functions for you to call, and for more " "information about the port allocation functions, see the :ref:`tcp-" "server-port-allocation-api` section." msgstr "还有主要的函数供您调用,有关端口分配函数的更多信息,请参阅 :ref:`tcp-server-port-allocation-api` 部分。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:927 -#: 9aead9c3ede94037a42b4f83a45b3bb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1005 +#: d158c9d060c14aa39d042757684d6131 msgid "" "This mode is useful when you need an individual port for the server or " "must reserve a controlled range of ports for client-file transfers by " @@ -1601,251 +1727,291 @@ msgid "" " server processes share the same host." msgstr "当您需要服务器的单独端口或必须通过手动端口分配为客户端文件传输保留受控端口范围时(例如在测试环境中或多个服务器进程共享同一主机时),此模式非常有用。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:934 -#: bad6d4dc4cdb4524b686b936a219637d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1012 +#: e51f806efbae4f9daf44365d182f21fa msgid "TCP Server APIs table" msgstr "TCP 服务器 API 表" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:936 -#: 7d833bb126d34e528b706e8bf0e8a755 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1014 +#: c07f101dcc584239b2a4a7532c1ada42 msgid "In short, the table of contents of the public APIs are as follows:" msgstr "简而言之,公共API的目录如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:939 -#: 665b3f99a31a46a1af942df11ae56b08 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1017 +#: 66d85143ceff487f9620241fa1391d21 msgid "The server setup APIs:" msgstr "服务器设置 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:940 -#: fadd7d9d1d664608bca880a41e9ea51d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1018 +#: 904c44d78ca84c5cb7b595c6d360b2df msgid "`TCP_Server_Base`" msgstr "`TCP_服务器_基础`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 -#: 53e896a56ad44c29b03df161113e8d24 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1019 +#: 5da37cfc4922407dab0d65df73991067 msgid "`start_TCP_Server`" msgstr "`启动_TCP_服务器`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:942 -#: 80dc73e7ae064470b60bf81cf731b1a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1020 +#: 6e0f0866c62749239469bceea81ae727 msgid "`stop`" msgstr "`停止`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:944 -#: bad96f05bf9741c3a015b46ddb0c5485 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1022 +#: f84f11b7394147a9802c7de69d1d99e5 msgid "The server handling information APIs:" msgstr "服务器处理信息API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:945 -#: c11c56f2f920425cb0f8a796ba8436ae +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1023 +#: 0ee5a3ad2c3643b9b85c813b5a5ba4be msgid "`handle_client`" msgstr "`handle_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:946 -#: 601d3f32dca44ce0aa8f90496fa82683 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1024 +#: 803b7f781de04d00ae128d89b0350cf5 msgid "`handle_command`" msgstr "`处理命令`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:947 -#: a95b98f525c44f8e99aa1ce37d14521c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1025 +#: cb9095dd05b24093984b4609ee0bb8b6 msgid "`receive_message`" msgstr "`接收消息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 -#: b4d6756915c3424eac84ee276c68ec48 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1026 +#: c40a11b2d9b34f389fce8bc6d8076ab2 msgid "`send_message`" msgstr "`发送消息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:949 -#: 5458006437d24bb68711e2523f7d7cba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1027 +#: 3c4a73128c044a38bac0b64d6551f512 msgid "`broadcast`" msgstr "`广播`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:950 -#: e87f4ae0d0284a778641c6198ee918fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1028 +#: 16f4acaa490c4ec7afbd88fb3b50f62c msgid "`send_msg_to_specific_client`" msgstr "`发送消息到特定客户端`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:951 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1029 +#: 2ad09a3887894e01a67d31c28272f730 #, fuzzy msgid "" "`console_input` (only started when ``is_input_command_in_console`` is " "``True``)" msgstr "“is_input_command_in_console”:默认为“True”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1031 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 #, fuzzy msgid "" "2.1. The inbound event listener APIs (see :ref:`tcp-server-event-" "listener-api`):" msgstr "服务器加密通道 API(请参阅 tcp-server-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:954 -#: e0409b880c784bc4a8cb876315709114 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1032 +#: 6f0e5784864d4f62b0fd68d41a8105c4 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:955 -#: 2dea82fdc0a04600801da255ef214a2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1033 +#: 647c22de04784b0c97bbc829edf1e2b3 msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:956 -#: d90982abe8e24aefb021d1bdb6cb8ca8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1034 +#: 8fc8a08031dd48eba706b833414ef995 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:958 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1036 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 msgid "" "The server encrypted channel APIs (see :ref:`tcp-server-encrypted-" "channel-api`):" msgstr "服务器加密通道 API(请参阅 tcp-server-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:959 -#: 0164b9a39ec64638b0951431e562f5c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1037 +#: 67ad7bf1d5754801a36a114c86e650f9 msgid "`_crypto_on_client_hello`" msgstr "`_crypto_on_client_hello`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 -#: 35472e2955b24167aadb9aa8587b2674 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1038 +#: e2ec1fc9abbc4a1389e8df768c33e7c8 msgid "`_crypto_wait_server_ready`" msgstr "`_crypto_wait_server_ready`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:961 -#: 2e8d4e8d8741462e8e6a6b36b36e0c07 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1039 +#: e3987c4ee8ae4d79b0aafb035a806494 msgid "`_crypto_push_pub_to_client`" msgstr "`_crypto_push_pub_to_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:962 -#: b7eb540259ae4240ba76640b6afd72b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1040 +#: b1829201e7fe4428b9689b03e50374bf msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:964 -#: 9265fbd06c8a43fc972c1010a348684d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1042 +#: c875b30243a24ac4923a442613a677e0 msgid "The server command APIs:" msgstr "服务器命令API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:965 -#: 6c53a87d79a749ffa1e2a93231037ac1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1043 +#: 5d011d31b13d446f814fd6bd5e63efce msgid "`register_command`" msgstr "`注册命令`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 -#: 30a77ceac778437989abfaa0a23c1f4a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1044 +#: 2f117382a2154410989fb34342460f8b +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1045 +#: ffa5682de7884beb92ad1259ff1b8dd2 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:967 -#: 1940d4e8daf143e9ad1c971530233180 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1046 +#: cf39c195db7c41caa0f01bd982276547 msgid "`submit_task`" msgstr "`提交任务`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:968 -#: f2448f5089ba44458298a4194c2795f0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1047 +#: 85f02dafa5374a7b89e8bd8a65e54b19 msgid "`create_temporary_server`" msgstr "`创建临时服务器`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:969 -#: 097562a3555e413385ee95ded3a46118 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1048 +#: 2f117382a2154410989fb34342460f8b msgid "`create_temporary_client`" msgstr "`创建临时客户端`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:971 -#: af034155f20a44b79b9c6ec49fc189aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1050 +#: 0131ddf38e824d959a1d61148155ae0d msgid "The server file transfer APIs:" msgstr "服务器文件传输API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 -#: 9cbb9edbc9574de99f8168bf2df7df03 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1051 +#: 7483d578f02a4babb71dda0efb204b61 msgid "`file_transfer_server_recv_client_start`" msgstr "`file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:973 -#: fc70c45345764fb2aa8bc3d71f927248 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1052 +#: c2cf0a257e2543478df2dccdf52fdb00 msgid "`file_transfer_server_recv_client_start_thread`" msgstr "`file_transfer_server_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:974 -#: c1918a177fcf47cbb881d7e14300776d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1053 +#: 187f0ce4a65e41adb7ee99b021de4d2b msgid "`folder_file_transfer_server_recv_client_start`" msgstr "`folder_file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:975 -#: 6f61085c3cb24ae298dc0eadbe113f6c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1054 +#: be99cf24a4ae4f03b5472d8ee3412889 msgid "`multiple_file_multiple_client_transfer_server_recv_client_start`" msgstr "`multiple_file_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:976 -#: 46d60103b77c4de19be1ac4a12d4331b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1055 +#: ea76c872d16c4a709ec52ab7415e40a0 msgid "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" msgstr "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:978 -#: 565a0271f5ed4b679a742f7677ed9e63 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1056 +#: 6056cfcc5fa740e58986f2e8ce900042 +msgid "`file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1057 +#: 8df3552dd5ae41a4b3020c15ebe8509d +msgid "`forward_item_to` / `forward_message_to`: single forward destinations" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1059 +#: ad8e7d49e5294f5b976ae225ccb67d22 +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1060 +#: 92ba3cd2c6004b60abe5976efa845d76 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1061 +#: 8cee01b7bbd1439b81f24891d7149fa4 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1062 +#: f5615a6934a141c9aa2bb01bcab9aea0 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1063 +#: 187f0ce4a65e41adb7ee99b021de4d2b +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1065 +#: 944bb0f890764ad7a62584cc73782927 msgid "The server console commands:" msgstr "服务器控制台命令:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:979 -#: e79a38bbae1d44e5b9e7b3e939b42e14 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1066 +#: e85b5444c86048cfa691dc42bb7c9f88 msgid "`/stop`" msgstr "`/停止`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:980 -#: 98cb7e67ddc64c7e91c8f445d3d7b601 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1067 +#: 7250fb98f32f47d4b6204ceb5f93f550 msgid "`/status`" msgstr "`/状态`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:981 -#: ec1899e60fc1456ba2117f7b0bf676e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1068 +#: 48237f11d42c41e392b282787896bd00 msgid "`/clients`" msgstr "`/客户`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:982 -#: 0bb68238715a4e889bef60bf524c996a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1069 +#: 65fddabf6eec444fa89598e10a43f63f msgid "`/send_msg`" msgstr "`/发送消息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:983 -#: 4c5dc721d573437385383ec46f76658a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1070 +#: c53a3810c2784772a6cb72f993ae8b4d msgid "`/file`" msgstr "`/文件`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:984 -#: 4fca7dce90044c119e5722297774fabe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1071 +#: 57d39ac1201f4866a57b5d291385d207 msgid "`/file_folder`" msgstr "`/文件文件夹`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:985 -#: 29fe035c678b49ef80321587017ba483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1072 +#: 2cbc4a81ca0548d4aa183c2ad034ab6a msgid "`/multiple_file_multiple_client`" msgstr "`/multiple_file_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:986 -#: ba4e2c65e7034bd8a7a278697b76e8a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1073 +#: ce0f96a7a5e24b3cab89623df65ac40f msgid "`/diff_multiple_file_diff_multiple_client`" msgstr "`/diff_multiple_file_diff_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 -#: 97c3c838cb784a729fc52242a89f7156 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1074 +#: a9bffb7745c94e7cb45f4fc030c00da3 msgid "`/help`" msgstr "`/帮助`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:990 -#: 0b5cb5ab31e648b99f176a269cbad11e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1077 +#: 2d084d51c4c44ebda431944babb6c256 msgid "See Also" msgstr "参见" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:992 -#: d85e9537bf8e453ea2d533f25e659d2a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1079 +#: aa497d5f407a4e439cd10a4de1e24b05 msgid ":doc:`TCP_Client_APIs` — TCP client." msgstr ":doc:`TCP_Client_APIs` — TCP 客户端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:993 -#: 1893e2b71add4e0ba8840ea169e0b102 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1080 +#: e1e5363e891e4e68855f9b021bbd4abf msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 端点。" @@ -2048,3 +2214,48 @@ msgstr ":doc:`UDP_APIs` — UDP 端点。" #~ "``/diff_multiple_file_diff_multiple_client " #~ " ... ...``:将不同的文件列表发送到不同的客户端。" +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "握手交换随机会话随机数,线路上的每条加密线路都携带它加上每个连接的序列号:``||``。接收方丢弃随机数与当前会话不匹配的行(从旧连接重播的密文)或其序列号不是预期的行(会话内重播的密文/乱序);当套接字在(重新)交换后切换到加密模式时,两个计数器都会重置。" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(client_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to the " +#~ "command handlers instead). ``add_file_listener`` " +#~ "registers ``listener(client_id, full_path, name, " +#~ "size, command)`` and fires after a " +#~ "file uploaded by a client has been" +#~ " fully written to the transfer " +#~ "directory (``command`` is the wire " +#~ "command that triggered it, so protocol" +#~ " pushes such as ``/crypto_pub_key`` can " +#~ "be recognised). Both listeners run on" +#~ " a protocol thread, so they must " +#~ "not block, and an exception inside " +#~ "a listener is logged and swallowed. " +#~ "The ``remove_*`` counterparts unregister a " +#~ "listener and ignore unknown ones." +#~ msgstr "" + +#~ msgid "" +#~ "``/forward_item``, ``/forward_send_msg``, " +#~ "``/pause_trans``, ``/start_trans``: internal " +#~ "forwarding/transfer-control messages." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po index b60b668..df71d08 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po @@ -6,24 +6,85 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PyFlow\n" +"Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-16 11:10+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" -"Language-Team: zh_CN \n" "Language: zh_CN\n" +"Language-Team: zh_CN \n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" "Generated-By: Babel 2.18.0\n" -#: ../../api/PyFlow.command_control_extension_tcp.rst:2 +#: ../../source/api/PyFlow.command_control_extension_tcp.rst:2 #: a6084f2941f34f579f28c55e9dfb768d msgid "PyFlow.command\\_control\\_extension\\_tcp module" msgstr "PyFlow.command\\_control\\_extension\\_tcp模块" +#: 9209095513ec402980427a0ddd988219 PyFlow.command_control_extension_tcp:1 of +#, fuzzy +msgid "Command-control extension for the TCP protocol." +msgstr "PyFlow.command\\_control\\_extension\\_tcp模块" + +#: 47d5c98c564241a6911eff0abea987ec PyFlow.command_control_extension_tcp:3 of +msgid "" +"One command batch, run by every listed client, with each client's output " +"collected on the server:" +msgstr "" + +#: PyFlow.command_control_extension_tcp:6 b14c7eec72b44dc1bd343997acf1cf44 of +msgid "/command ... ... " +msgstr "" + +#: PyFlow.command_control_extension_tcp:7 fe2fb5a737534088b175ea340c1763f9 of +msgid "" +"typed on the server console. Every client runs the whole command list in " +"a single shell session, in order, so state such as a changed working " +"directory carries over from one command to the next: ``/command \"cd " +"/path/to/search\" \"ls ./\" \"(ip, port)\"`` lists the files of " +"``/path/to/search``, while sending ``cd`` and ``ls`` as two separate " +"``/command`` lines does not." +msgstr "" + +#: 29a70dd76bf34e90a9ea54ac27202289 PyFlow.command_control_extension_tcp:14 of +msgid "" +"Commands come first and client addresses last; every address is written " +"as a Python address tuple, e.g. ``\"('127.0.0.1', 3000)\"``. There is no " +"limit on the number of commands or on the number of clients, and every " +"listed client receives the same command list. Two internal commands carry" +" the log back:" +msgstr "" + +#: 9ef58aea395a436382e23f39797e3e8e PyFlow.command_control_extension_tcp:19 of +msgid "/command_log_chunk " +msgstr "" + +#: 3361f3fb70584140989542af7c3361a7 PyFlow.command_control_extension_tcp:20 of +msgid "" +"sent by the client after it uploaded one log chunk through the file " +"transfer channel; the server appends the chunk's entries to that client's" +" log file" +msgstr "" + +#: 2563d4e4d9744c2fb16d84690c2e94e2 PyFlow.command_control_extension_tcp:24 of +msgid "" +"sent by the client when the batch is over; the server merges every " +"collected log file into ``merged_logs.json``" +msgstr "" + +#: PyFlow.command_control_extension_tcp:27 e40a302503cb4bdda5420aa79d0c57eb of +msgid "" +"A client captures the output of the running commands and uploads a chunk " +"every ``_LOG_CHUNK_BYTES`` of captured output (a smaller final chunk " +"closes each command), so a command that never stops is still tracked in " +"real time. Every chunk is appended to the same log file - " +"``logs__.json`` in the server's ``logs`` directory - which is " +"therefore never re-sent and never rewritten, only extended." +msgstr "" + #: 9209095513ec402980427a0ddd988219 #: PyFlow.command_control_extension_tcp.setup_server_commands:1 of msgid "Register the control-extension commands on a server instance." @@ -33,3 +94,4 @@ msgstr "在服务器实例上注册control-extension命令。" #: PyFlow.command_control_extension_tcp.setup_client_commands:1 of msgid "Register the control-extension commands on a client instance." msgstr "在客户端实例上注册control-extension命令。" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po index 8dde942..2c77325 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,156 +20,156 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.connect_tcp.rst:2 -#: 59f41330dfa54a88831a20f4dc97c0f6 +#: 1e4cd09ce3ef45ceb95b8eb81eb7493b msgid "PyFlow.network\\_api.connect\\_tcp module" msgstr "PyFlow.network\\ _api.connect\\_tcp模块" -#: PyFlow.network_api.connect_tcp:1 dca225f091cb4dd1810a8bd04c3a5004 of +#: 25b88cdb337c44539a843c674ba6825b PyFlow.network_api.connect_tcp:1 of msgid "" "TCP transport for PyFlow: the server and client base classes and the wire" " parsers." msgstr "PyFlow的TCP传输:服务器和客户端基类以及线解析器。" -#: PyFlow.network_api.connect_tcp:3 d5888d829f2e4850926eb364ede4678e of +#: 1f1482fc5c2849a68f34c74a8b55ab79 PyFlow.network_api.connect_tcp:3 of msgid "" "``TCP_Server_Base`` accepts connections and dispatches inbound lines; " "``TCP_Client_Base`` connects, sends and reads on the same conventions:" msgstr "`` TCP_Server_Base ``接受连接并分派入站行; `` TCP_Client_Base ``连接、发送和读取相同的约定:" -#: PyFlow.network_api.connect_tcp:6 bd065af9d94b44298f9716ca96809b8c of +#: 104e5170c1c34bf9ad719f896e0c4226 PyFlow.network_api.connect_tcp:6 of msgid "" -"one message per line, terminated by a newline; a line that starts with " -"``/`` is a command and goes to the command handlers, anything else is a " -"plain message reported to the registered message listeners;" -msgstr "每行一条消息,由换行符终止;以''/``开头的行是一个命令并转到命令处理程序,其他任何内容都是报告给注册消息侦听器的纯消息;" +"one message per line, terminated by a newline; every inbound line is " +"reported to the registered message listeners (commands included), and a " +"line that starts with ``/`` is then dispatched to the command handlers, " +"anything else treated as a plain message;" +msgstr "" -#: 91ea1db95e554f2fbd2c1e92eb2d1353 PyFlow.network_api.connect_tcp:9 of +#: 6c6c01958e5741e080edcb804b4d12d1 PyFlow.network_api.connect_tcp:10 of msgid "" -"an RSA-encrypted channel is negotiated right after connect unless " -"``is_enable_encrypto`` is False;" -msgstr "连接后立即协商RSA加密通道,除非`` is_enable_encrypto ``为False ;" +"unless ``is_enable_encrypto`` is False, an encrypted channel is " +"negotiated right after connect: the handshake lines and the public-key " +"pushes stay plaintext, then every later message travels as a frame (RSA-" +"OAEP for small text payloads, an ECDH-keyed AES-GCM seal for everything " +"else, including file data), and each file/folder transfer sub-connection " +"is framed the same way once both sides hold the session keys (see " +"`_SecureChannel`);" +msgstr "" -#: PyFlow.network_api.connect_tcp:11 dfcece05b6774c5496b99d6c08039fce of +#: 9702905f1f8a4750905b2ffb96f99ec8 PyFlow.network_api.connect_tcp:16 of +#, fuzzy msgid "" "file/folder transfer, message forwarding and port allocation are layered " -"on the same socket and share its command namespace." +"on the same socket and share its command namespace;" msgstr "文件/文件夹传输、消息转发和端口分配分层在同一套接字上,并共享其命令命名空间。" -#: 89db462eaa88489c9390ddfa67a77a73 PyFlow.network_api.connect_tcp:14 of +#: 3488995e2a8349a58393d9f2d1155b99 PyFlow.network_api.connect_tcp:18 of +msgid "" +"an interrupted transfer is resumed after a disconnect: both sides persist" +" their transfer stores under the protocol's ``.Flow`` directory and the " +"receiver asks the sender to continue the file from the bytes already on " +"disk (``resume_transfers``; the wire lines are ``/resume_trans`` and " +"``/forward_resume``)." +msgstr "" + +#: 4cc5743bdfe54148ad38f54f10e688c9 PyFlow.network_api.connect_tcp:24 of msgid "" "The forwarding extensions use the module-level parsers " "`parse_forwarded_message`, `parse_forward_items_and_addrs`, " -"`parse_forward_originator` and `forward_skip_message`." +"`parse_forward_originator` and `forward_skip_message`; the reconnect " +"logic uses `parse_resume_command`, `parse_forward_resume_command` and " +"`_resume_offset_for`." msgstr "" -#: 98c270e82fa8468487e1b4d25bab8c0c PyFlow.network_api.connect_tcp:18 of +#: 49796529cb7f49ee8131b257212b5420 PyFlow.network_api.connect_tcp:30 of msgid "" "Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and " "``TCP_Client_APIs.rst``; argument, return and exception contracts live in" " the docstrings below." msgstr "" -#: 76126c02e928423b89dc4662d9a190f2 +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_resume_command:1 of +msgid "Split a ``/resume_trans `` line." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 14dcda8b059b480982e3fb03399e665b 99035a24f6e94207b84545f8c71a451e +#: cb62202c244d4c08974c674c13a02dca +msgid "Returns" +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_resume_command:3 of +msgid "``(fid, offset)``, or None when the line is malformed." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 19eb6fca79324b0791f8ec7488a5246c +msgid "Return type" +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:1 of +msgid "Split a ``/forward_resume `` line." +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:3 of +msgid "``(target, fid, offset)``, or None when the line is malformed." +msgstr "" + +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:5 of +msgid "``(target, fid, offset)``, or None when the line is" +msgstr "" + +#: 4ead8d8f93644adeb812150e760f7792 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:6 of +msgid "malformed." +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 #: PyFlow.network_api.connect_tcp.parse_forwarded_message:1 of msgid "Split a ``/send_msg_from `` relay envelope." msgstr "" #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0e9ae2e0bd0c44da835c0999abec5f08 1aaf58afc7f043919f411c02d435031d -#: 1c819a8207464e439fd4675d1b823409 1d2cff780d6642deb6ab5fbf32c34185 -#: 1e24bfa274504842b67c3cb0c7a37118 26160724c12740ecbe3cc707bc46c197 -#: 2edb81613e9c4bd0949f5d6efa1a542f 30a7ccf5e56e4640a7a6e592d13a4f7c -#: 3514f6292626456eb4b0c31a30e24cf5 38d82b9bc4414212a8458de940d3b69b -#: 406f1bd372c14cd897f0d2dc1fdc8fd7 4400798a6d9d41a89b686b015f53a454 -#: 54f261fe47134a9494f12b5053492006 5e9d8d1799714d389a6fd79edd0e5bac -#: 6239fd721a0f476aaf509ab580317c75 6658645eabff4ba6b0b326727f89a4f1 -#: 6f375e9a65e04034a4fd1475f3073e42 70b19bc5e5da467dbbae99d81fe54ed7 -#: 79e2d4be536b429cbbfe5016df915b72 7c3cf59acfe34a15a6c920a0f58ec56f -#: 822df543855349c2993aabd5596b5383 8245849b603f4313a3ea2423abd5c899 -#: 83eba13f6fae4ded929924151baa0c52 9449c184a2e145909d2e1f114534253d -#: 9a393c8c90d0446a97c34af1c173f83d 9cdc7d0b4bc2400498e9c57ed16ba459 -#: a2ddcff09d1641b5b269ec31031008f9 a5cbf7c6c5b0494b8652be7d28a7b3d1 -#: a9ec9ede7c8144ddb920261d29edc23d b5b42f99934e4b0b939671c6fb08f748 -#: b630deb98dea40c28f1cb88dcbfdb261 b6e3a01b0f044a15a7d322c63f58c262 -#: bb3b7e5558c74c8eb287944b93b9c664 bd95cc8d5960426e92ad149ce0ecaeb4 -#: be47c4f21d4d4515be0684c6c1215c0c cdebf66a7b714ef39236c1dc9773c8f7 -#: d02c1be3236b424f87b75728f76d672c d5b3f5bf790c4fc6aefb763d9c473474 -#: da6cef9244b1429881584994b097c71a e98998d054b74d0e820367ea5de54d02 -#: ea4e1b708c2f409f89bf4ca2a6e4fbf3 ebca3c62590345118f3fe5a8d85ce154 -#: ebcdb45484b64f7f9023808632316025 efca1ecd18f440db9489b40ae6480409 -#: f7766cda09fd4c0bb6b565f5fa4a3688 fe80dd07199943c784dd488826f958b7 +#: 4fa9ba6e763440b8ab00832520b4d305 501a0caef71d436e84469bc1ef9c1e5f +#: 70d6dae11a144ed7b7e9d8e16dbf478c acdf8b3b266f4eccb6ceca17a110603b msgid "Parameters" msgstr "" -#: 35b277cd5b2249dc8b38c36654b1f75a -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 +#: e42a6166c82d4861b25cb55f587db28c of msgid "Received line, e.g. ``/send_msg_from ('127.0.0.1', 3000) hello``." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0cd9914c895f4b308548863df6d8c13c 113c57937f6f402da7758e74266680ea -#: 139720899e024d348d0b43b9af2b2ef7 2cb731c57fb64497a6424e4e51fe17bb -#: 30c59afde30c44428a97266ca87baa21 3f574beaf02948d599ffd8c50922e530 -#: 40e4cbf377a94cf8803c13b2f01dbc77 4aa76ebde46243b18f2a5d811d902d1e -#: 4d5706674a0c40a99769b5cfba21b29d 5518a67cc7364710b2b0c03f6de9de1b -#: 564a8841a88d40e0a44b1b0d72a0b3a4 56e96f344ac14995adeb056f90d3e39a -#: 638d047aee4d45a689f4a54f8d2be451 6e5db10681f24a01a208604d8de1ecf4 -#: 6ea11f9fd50e46f8aef42a25872d8d47 833d97bdb57049979db335d24819041a -#: a00fef59262447aa931fe606e260a7ab a9795b94ba634cb8a7dc1fd6a7e6f326 -#: b1a77959b26540128ea564370170744f b1e2a43372ac48fe9a367121a736eaee -#: b2f18766a5ec40d69bfd15b13fa54aa2 b963bb66a63649d5b5cc0ce3d852aab4 -#: c1bd9b5e40e644e3a1f1198e5d2247c2 d558170070474bcb9d798b72d878f185 -#: d86bf79c265c42ec969d2c8058f20a3c d906d179eca24642883fb6ff991399b8 -#: ddfeae931eb14b529e08b61ae9de5aaf ecb12ada91914625a7c5e9894b67886f -#: f8e1381487764684b80cbc9d8f6a511c fa2587a106c540d1a870afc4a3ae97b7 -msgid "Returns" -msgstr "" - -#: 24de94d25531410aa507869ac615529b -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 +#: f25d1962656c4f339805427e2573f84f of msgid "" "``(sender_id, payload)`` where ``sender_id`` is the sender's " "``\"ip:port\"``, or None when the line is not a well-formed envelope." msgstr "" #: PyFlow.network_api.connect_tcp.parse_forwarded_message:9 -#: f4818c7037924b089072be17dbe65cda of +#: d0d7af37e4134902ae64e10b2e43b4c1 of msgid "``(sender_id, payload)`` where ``sender_id`` is the" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 -#: e4ce35611cb240c382217f2166803af1 of +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 of msgid "" "sender's ``\"ip:port\"``, or None when the line is not a well-formed " "envelope." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f2c39309f3e47aa9157bf244f35d1e6 126027ff5c8b494e8223688394767c35 -#: 15e8f6af90d84f4c99e9a9706f995a3f 18eed5a02c0346f6966237e6812afce0 -#: 208eff4f470f474395ac42a58f179feb 308f9ffcdfe2443cb6fe0f3a79e7d4b3 -#: 30fd0d7f7d9547149d06568b9ae4b217 34500bb5a5ea4428ba3ba1f34f8555f3 -#: 357fa966af0e4661a01d3a18b3686c63 38f178d3602f47bcbf100a047fc22ccc -#: 4268152920654e59975b69aed4638761 43cc49d0a3b2478f8a24fcdea7c2ce78 -#: 448b06753df84443af4aae1dcb008d56 4530cc6fc87d4dbcb79dd0e90ea83694 -#: 496c6102672e49fc96cd7210ed1ec602 502647c8224842608ded5058bf1c6748 -#: 574093f9f9054b898b9ab8b20a239a40 5882a32ac8a34ab7b568b256092e1aca -#: 73e564d3b91d42388f95effb067d6218 7f2f462183d442c98c624d6750d86319 -#: 8203a323a9af48edb0f9e91ca6260ed6 87a376020e0a47fb90cc4f2d9b045d7c -#: 8f12aa18be1a4aaf97b8db14f282a929 a61c3c1917b8486bad659991683c48cb -#: a9e445f3a3094e3bb7957551bcf7fd21 c0afcff99bfc47f3ba7a3f0b3e836444 -#: c4d251b617f2419cb1093f6896b14cb8 d4bc332ce5f34c61b3105fb392b302e5 -#: e9a98b5852d84cf4939d9ea0f17b038c f17ca1aa780b447cb305e1db1c181efb -msgid "Return type" -msgstr "" - -#: 1ad7def88bd34ce7accca28c4d123b79 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 +#: f22254d8ca2d47ad8bc9c98664369d61 of msgid "Split forward-command tokens into items and destination addresses." msgstr "" -#: 67578e526f0b4dfc924c46a44e7bea78 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 +#: b207f60051004834bab91ba392a88437 of msgid "" "A token of the form ``('ip', port)`` is a destination, everything else is" " a forwarded item (message text or a path). Used by the native message " @@ -177,252 +177,326 @@ msgid "" "extension." msgstr "" -#: 18a87e9cbc124ce5a6f91d61a72fc6de +#: 5329fb72f5954768a6cec05ff4cccfea #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:7 of msgid "Tokens after the command name." msgstr "" -#: 0e46577c966b41c4ad6f0aea95fd7e5c +#: 2aebf669048046ddb279a935bcfcfde4 #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:10 of msgid "" "``(items, addrs)`` in the order given; ``items`` holds texts and " "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 608bcdb865a94f869885cd560de7012e +#: 96b96bd19fe94312bddf340fad073cbc #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:12 of msgid "``(items, addrs)`` in the order given; ``items`` holds texts and" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 -#: e8c390dc356e4be9bb2f52cd0540e859 of +#: 8e82954621d748e2b412952a7fb2753b +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 of msgid "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 0e422066050d4ba18799efa53c6b771e -#: PyFlow.network_api.connect_tcp.forward_skip_message:1 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:1 +#: a51324658c7943158d90ed706cecc41d of msgid "Build the console notice for a forward destination that cannot be served." msgstr "" -#: 1eb2f924bcbc4e3783e3a4706c93052f -#: PyFlow.network_api.connect_tcp.forward_skip_message:3 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:3 +#: b541e8446e374bc8b38cd7912a1fa33c of msgid "Destination ``(ip, port)`` that is unreachable or is the server itself." msgstr "" -#: PyFlow.network_api.connect_tcp.forward_skip_message:7 -#: b7ceaa070f754fe88242c2b495b3ff9f of +#: 10e03f21d05e478d9cde0c7176f6e1b8 +#: PyFlow.network_api.connect_tcp.forward_skip_message:7 of msgid "One-line notice for the console." msgstr "" -#: 59d83fde0d964794ba76d45749bfc021 +#: 8005e532fe9d491ca8ddd996889d605d #: PyFlow.network_api.connect_tcp.parse_forward_originator:1 of msgid "Extract the originator's ``\"ip:port\"`` from a received transfer command." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 -#: b91ee97cb2574a19b8c87c99bf8ca181 of +#: 2cf3052a89c645e782430f1f05fb37a1 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 of msgid "" "The server's forward relay tags every pushed ``/file`` and " "``/file_folder`` command with the forwarding client's address tuple; a " "direct send carries the receiver's own address instead." msgstr "" -#: 20da4b9824cd4fd6bb0ef55ebc38158b +#: 335f6c1b16104395ba38a33188943d8a #: PyFlow.network_api.connect_tcp.parse_forward_originator:7 of msgid "Received transfer command." msgstr "" -#: 9f25fa22a7b14822b8cbc1fd929976b9 -#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 of +#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 +#: e5bd1024ad3f47f19cafc4c83a844b60 of msgid "" "This instance's own ``\"ip:port\"``; a command carrying it is a direct " "send and yields None." msgstr "" -#: 6455c3bb288d4239811cb0104086c0fa +#: 65469492f844448fab269b701cbdb704 #: PyFlow.network_api.connect_tcp.parse_forward_originator:13 of msgid "" "Originator ``\"ip:port\"``, or None when the command carries no " "originator (direct send or non-transfer command)." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 -#: a466d04757ec40f1a2888518b8fb1d9a of +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 of msgid "Originator ``\"ip:port\"``, or None when the command carries no" msgstr "" #: PyFlow.network_api.connect_tcp.parse_forward_originator:16 -#: da8c46fb38624c7d97d91970aee4667c of +#: a2d34276c4f54c69981f9b51f36cc31d of msgid "originator (direct send or non-transfer command)." msgstr "" -#: 201f6bd5376a4ebaa7488dd3b58197c0 +#: 31646cd2d4f049a38b7910ac6836d2f9 +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:1 of +msgid "A command passed to `call_extension_functions` is not registered." +msgstr "" + +#: 42bee6e5f57b43cba7c5b4c4a1769e9a +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:3 of +msgid "" +"Raised when the first token of the command matches no handler registered " +"with `register_command`, on either instance class." +msgstr "" + +#: 7297b41c47664243b9677b32e21de07e #: PyFlow.network_api.connect_tcp.TCP_Server_Base:1 of msgid "TCP server: accept clients, dispatch commands, relay messages and files." msgstr "" -#: 4f7013d76f9d447b974f22cca228ba0f +#: 0d632c9f5b234888a691b03ade8ff7da #: PyFlow.network_api.connect_tcp.TCP_Server_Base:3 of msgid "" "Each accepted connection is served by `handle_client`, either in its own " "thread (the default) or by a coroutine on an asyncio event loop when " -"``is_asynic_clients_io`` is True: a line starting with ``/`` goes to " -"`handle_command` (built-in commands plus the handlers registered with " -"`register_command`), any other line is a plain message delivered to the " -"listeners registered with `add_message_listener` and stored in " -"``messages_dict``." +"``is_asynic_clients_io`` is True: every inbound line is delivered to the " +"listeners registered with `add_message_listener` first; a line starting " +"with ``/`` then goes to `handle_command` (built-in commands plus the " +"handlers registered with `register_command`), any other line is a plain " +"message stored in ``messages_dict``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 -#: fd2aa2103a434e7b84e9f5300dfb2637 of +#: 2870b0163d68487daf7526e91eb49ff6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 of msgid "Address the server socket binds to." msgstr "" -#: 0887ce96e330478f83984d935911cd2b 13fa6bd77a314fcbae42aeef584d47b6 -#: 1d012f62b99a4b0d8802295d814667dd 1d5b594e02824d74b812b69dc7b34a88 -#: 3b8af6dc474d493eb9749cb07384c5d1 4916b5bac8044e249473dae03d0af5e5 -#: 6a138e9d5ed24b6b9a9f213ffa6d07bb 7c114dabd42344d790a98003f7d68a6a -#: 889f9fb97d4b483cbfd9ae6bbb3e1dbb 89e6193e8e8c45f3ba6d49b9ec578812 #: PyFlow.network_api.connect_tcp.TCP_Client_Base #: PyFlow.network_api.connect_tcp.TCP_Server_Base -#: a0a81405abb64b70834a292dfa52ea47 a32afd5e800648f08c2ed1582462900f -#: a4c849cfce9b4544a50162a1abd07ffc e953785e3c774cb783e506a118b6f5f9 -#: efd7bf86f2f3403a843bdc7079ed87ae f87fe645a0c846168779119b106eb83b of +#: cf754e752b6c445989b3301b807fc9eb of msgid "type" msgstr "" -#: 194d7e538b9142bb9cadf40639c7dfc2 8d779f308c7343fca45fb6b7c544b6f8 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: 568be916ae0340289a6569e718e7cbf2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:16 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:106 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:15 -#: a043713065174240b3b3cb2839829b42 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:100 of msgid "str" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 -#: eaf91e01d29744a4b66b30d163b14bd4 of +#: 6ac74cca7b0f443ca89f3d2c3bbe1aaa +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 of msgid "First port considered for binding and for allocation." msgstr "" -#: 143512a7a9624b79853380f79b9db5e0 6093b43271e041dfb256e660e61561c5 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 +#: 9ecf88c5193c470b98dc95d184c94f92 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:22 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:21 of msgid "int" msgstr "" -#: 0f4f0acdd1a64e9cb4eb06b5fc12103e +#: 6746407aac194c4880c7cbf82b7fa2fb #: PyFlow.network_api.connect_tcp.TCP_Server_Base:25 of msgid "" "Accepted connections keyed by ``(ip, port)``; each value holds " "``socket``, ``address``, ``id`` and ``connected_time``." msgstr "" -#: 6fcc166b59cb4ae7a6a6e30f2dbd2784 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 of +#: 7ba2aaf3fe4c42739121eb3ca2bcc79a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:89 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:98 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:92 of msgid "dict" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 -#: d85332af5e73403388989eacf82a251d of +#: 93556efee2aa445684af3fdc1532548a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 of msgid "True while the accept loop runs." msgstr "" -#: 0effb5fc02cf402ab9d27f4a51954fd1 168f4d3c8da74ebab98953585b27b866 -#: 21bd44747d4e4c9aa4a0afa0f559707d 3c8b6ad08eac44ba9eacbb2fb9752304 -#: 420ec28762864e58ad5f3a63f2811a0f 87eb97e54ef847398f653aa5b65b0191 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: 0ab0667a38254203929e173ab5024f1d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:40 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:46 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:52 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:58 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:65 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:72 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:79 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:34 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:41 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:47 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:53 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:59 -#: e1e2580e801a44cc962b509779f690fc f827c454ead24d7587ae4125b1f60fda -#: f8f0e0ce3c4841278a15e583a0ec5f92 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:66 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:73 of msgid "bool" msgstr "" -#: 62103bebe6fe47aa8a3830133baa0a70 +#: 9023ee78c5fe4680a3875c881abe3307 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:38 of msgid "" "Whether clients are served by coroutines on an event loop instead of one " "thread per client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:42 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 -#: c291fba3b400472996751ffdc24251b7 d0ade3e16cf044fca75a0e1bdf17038c of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 of msgid "Whether the RSA channel is negotiated." msgstr "" -#: 8bb4af4279e44eef8df452f4429780ff -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:48 +#: 3c5a67d3c5824c15b42b71fbadddf5d3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:51 -#: c9414c44325b4b5eaed34bf2a7e49ed4 of +#: a5ac1b25d44547ba836c5dc354438315 of msgid "Whether execution-process lines are logged as well." msgstr "" -#: 5bdaf96cd6894bc4a179ae3ddc66c29c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:54 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 -#: a50b56a084674a89bb56dd9791348a75 of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 of msgid "Whether the instance logs anything at all." msgstr "" -#: 75856a665d5045349622c29bee22fe17 +#: 3114d37d38af4cfcaa75397192202b93 62437fad8325442b91f177e93b8be7ef +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:62 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:63 of +msgid "" +"Whether every running file transfer is tracked in " +"``file_recv_progress``/``file_upload_progress``." +msgstr "" + +#: 58bd8f0892f044a583a276490dc2a7f5 855f8e2ee2a449398779d56b269628d6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:70 of +msgid "" +"Whether the real-time network speed is measured into " +"``upload_network_speed``/``recv_network_speed``." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:77 +#: afff1dd047f4479b84d46859c7da90b8 ce793576b862473cb130a29582aab5fd of +msgid "" +"Running downloads keyed by fid; each value is ``[received bytes, total " +"bytes, current speed, file path, peer]`` (the speed is None until the " +"transfer has moved its first chunk, and while speed measurement is off; " +"``peer`` is the sender's ``(ip, port)``)." +msgstr "" + +#: 36c2c0e7900d436a977b8895e671c9f0 659caaa0c8bc40d3a9ce8d0905787584 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:93 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:87 of +msgid "" +"Running uploads keyed by fid; each value is ``[sent bytes, total bytes, " +"current speed, file path, peer]``, with ``peer`` the receiver's ``(ip, " +"port)``. A forwarded transfer stores the original peer on both sides, " +"never the relay." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:96 +#: f9528e6c490d4807b949f6730c6ece8e of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when a connection drops and read back on the next reconnect " +"(``resume_transfers``)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:110 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:104 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second sent, or None when not measured." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:113 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:120 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:107 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:114 +#: d926b4f3eb4b40a4acb21f780a4dc227 of +msgid "float | None" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:117 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:111 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second received, or None when not measured." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:1 of msgid "Create the server and, unless extended, start accepting clients." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:3 -#: a2cce435d92d46e5b0b2cd59d43c8759 of +#: bf58d54a167d45de9a18641877ada912 of msgid "Address the server socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 -#: d4c7cd9cc01e4371961f0950fd861b12 of +#: 2f4d0c4bfd8246d4984d4c843510775d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 of msgid "First port to bind; also the base of the allocation range." msgstr "" -#: 716408a19bf349878edfd5f1948f57ec +#: 47138ce8f587467aa353e302f473df48 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:8 of msgid "" "Maximum concurrent clients served in thread mode; ignored when " "``is_asynic_clients_io`` is True. Defaults to 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 -#: c37fcc062f6947228f3dc0b85ec5a5ca of +#: 8786a9d2b6b449209be813778d785712 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 of msgid "Step between candidate ports. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 -#: e683b27a8b884c5b99511f99e20b6bf9 of +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 of msgid "Number of ports per step. Defaults to 100." msgstr "" -#: 6291e503f9bf4c78a9c226058a67bce1 +#: 973382c423524d44a569c318399e0b99 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:15 -#: e59cefed7c4e4148b863b89e4d17004e of +#: d5f8f341d98d478289d9a226f37c1003 of msgid "Concurrent file transfers allowed. Defaults to 10." msgstr "" -#: 792cebf4ce084bd9b222b9ee83eeb5f4 +#: 4fe9a7607dbc4eebbce4e62f9306c76f #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:18 of msgid "" "Reserve a port range across processes, so several instances on one host " "do not collide. Defaults to False." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 -#: befe96138f8544cbb8320f33af43af3e of +#: 8aa56addc6ae4a7790dc957d1e1c2b60 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 of msgid "Start the console command thread. Defaults to True." msgstr "" -#: 10c1ed53a097472297ade439439e218f 3bc54f27f3db4bce846f5ec756f0e68f +#: 242566ff64584fba88e4fed8bb189110 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:28 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:24 of msgid "" @@ -430,301 +504,440 @@ msgid "" " 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 -#: f0a3afe6bc0c4eb2ad2e9e5ae43e2d88 of +#: 87d1cd7d6569498b8af8bc7064235784 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 of msgid "" "When True, do not call `start_TCP_Server`; the caller starts the server " "when ready. Defaults to False." msgstr "" -#: 577dd2f594554ceab51324eaedf4b1b3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 +#: ac43634ddb1a4d15a9f3d0f58d011441 of msgid "" "Negotiate the RSA-encrypted channel for every connection. Defaults to " "True." msgstr "" -#: 1ea6dc3b1a34463881e1aa7e96a14525 +#: 1ffccca56902418ba98ee0c6776ad8fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:37 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 -#: ecd4aa80607e4f988ac59b64e85c8fbe of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 of msgid "" "``[pub_key_path, pvt_key_path]`` pair used instead of the default key " "lookup; an invalid pair is ignored." msgstr "" -#: 0b92e71977dc4312b9e31fab903eadf2 +#: 420bbdf8d6bb400fbd3548bea03354ac #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:36 of msgid "" "Buffering ceiling in MiB for the in-memory forward pump; past it the " "uploader is told to pause. Defaults to 2048." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 -#: e14dae3d183249e19a0f6cf671ead02b of +#: 94e4a7e67e3047fd9d565f9a5d8122ab 9dcb36b97a004812bbcf264efa812441 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 of +msgid "" +"Bytes read per receive on the control connection, covering commands and " +"messages. Defaults to 4096." +msgstr "" + +#: 116dc6d56dd44f4ebaab990a3658359d 397abb5fbc1a46db90a7829daac02465 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:42 of +msgid "" +"Chunk size in bytes streamed when sending or receiving a file or folder. " +"Defaults to 65536 (64 KiB)." +msgstr "" + +#: 446099293d824f27aed7245f3c77df69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:45 of msgid "" "Serve clients with asyncio coroutines on an event loop instead of one " "thread per client, so a single server can hold thousands of concurrent " "connections. Defaults to False." msgstr "" -#: 07311d6c7a2f4516a4209df5c7798be6 9f213be174d243d4af26f79ae9624945 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:44 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:50 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:50 of msgid "" "Log execution-process lines in addition to command and result lines. " "Defaults to False." msgstr "" -#: 28ea5071c3344615b114f12ad5be447c 497004294ca244138115a713c0ffed15 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:47 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:53 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:53 of msgid "" "Log at all; False silences every line this instance would print. Defaults" " to True." msgstr "" +#: 1608cb9ad7104c82a43f23bb929f7d84 744b24d9e233457fb87cc8faefc5a498 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:56 of +msgid "" +"Track every running file transfer in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads): each entry holds the bytes " +"transferred so far, the total size and the current speed (None while " +"``is_enable_real_time_network_speed`` is False). An entry appears when a " +"transfer starts and is dropped when it ends. Defaults to True." +msgstr "" + +#: 3658f6b3ec994d15b9321a10ae33b351 769ed811a0cb4b18aeacdd39e4b4bbe2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:64 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:64 of +msgid "" +"Measure the real-time network speed of every send and receive — the " +"control layer and every temporary connection (file transfers included) — " +"into ``upload_network_speed`` and ``recv_network_speed`` (bytes per " +"second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False " +"nothing is measured and every speed value is None. Defaults to True." +msgstr "" + #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f0e9eea68114cf3b085d08796aaf552 3f8c413bab284fb78ac0b2ef8b8fb44a -#: 4a7a4c0862a84c53b2ccf0de3b00d495 4c3773b74abf40118b9ed681d9bef66a -#: 9f4fa9dc8d5045e39702036409f07a5d aa175c9daeab453a848bb2ef9f2e3dcf -#: cf96ad3305794cd7b9578ecb55ecd8b9 fbbf706646e24207aaf3b2532903a31b +#: 63ab5a2f2327475ba324e245f8e6e2ac msgid "Raises" msgstr "" -#: 0c72321c656641a5b684299b915cbb39 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:52 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:51 -#: d72a9dcf6bc748e5898640448e229b3b of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:81 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:73 +#: ed59ec69b9a1430597e6d8758051aff5 of msgid "" "If the ``.Flow`` directories or ``decode_command_table.json`` cannot " "be created or read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 -#: e2bb545e7ee1419286f58495abc4bcd2 of +#: 031d3e96394c454093561375a377dcce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:1 of +msgid "Pause an outbound transfer of this instance." +msgstr "" + +#: 342e6dfc6f6a4399914bc72372aa5f2d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. A " +"forward relay's writer toward ``peer`` is paused the same way the " +"``/pause_trans`` line pauses it." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:3 of +msgid "Transfer id the outbound leg is keyed by." +msgstr "" + +#: 7ecc0c956c8b408688fca517eb6370fd +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:10 of +msgid "" +"Restrict the pause to the leg or relay writer toward this ``(ip, port)``;" +" None addresses every match." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:14 +#: bdee1944910b4ee3908cf225a151a5fd of +msgid "" +"True when a running leg (or relay writer) was marked paused; False " +"when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 99ba2aa702f74621ba4dd31b8c045467 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:16 of +msgid "True when a running leg (or relay writer) was marked paused;" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:17 +#: c85ed4c1a84443a98394146efcf04315 of +msgid "" +"False when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 2771724616054f628d60add2c7407e7b 3a0594b22c6849c88310243022e8ee23 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:1 of +msgid "Resume an outbound transfer paused with `pause_trans`." +msgstr "" + +#: 7a864ecc76fe40459eeff353522482fb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg or relay writer toward this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:9 of +msgid "True when a live leg (or relay writer) was resumed." +msgstr "" + +#: 364557403e3d480896c0ffc57a19df04 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:1 of +msgid "Ask a connected client to pause its transfer toward this server." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:3 +#: f13c2e0e5310443080b0f63c773d8497 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (see `pause_trans` on the receiving side)." +msgstr "" + +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:3 of +msgid "Connected client ``(ip, port)``." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:5 of +msgid "Transfer id of that client's outbound leg." +msgstr "" + +#: 5ea8eea489fc43108a439d54fba31068 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:8 of +msgid "True when the line was written; False when ``peer`` is not connected." +msgstr "" + +#: 38905ec7539d42e0839907c32dd8667f +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:13 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:10 of +msgid "True when the line was written; False when ``peer`` is not" +msgstr "" + +#: 1c7b88e29a0143a39e13441769186ef4 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:11 of +msgid "connected." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:1 +#: adfc486a05ae4063bda6a61f2a6f3c36 of +msgid "Ask a connected client to resume a transfer paused earlier." +msgstr "" + +#: 810bc26336b24ad1acba3f56d466f8e9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 of msgid "Reserve this server's port range under the cross-process lock." msgstr "" +#: 5540b6efb5864c188e080ec7aad5c3ca #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 -#: c9ae1464a03b44049e826b9b73e2aca2 d23fda91e3e645e081dd5bbd5332fc4c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 of msgid "No-op unless ``is_hand_alloc_port`` is True." msgstr "" -#: 0b8bb2090cd04385a9d960dd2808f5bc 55b8a82ae1ce4769a1c62b35d253810e -#: 6d17c5fb7b4d484ba017edb4c5d5535e +#: 356ed2e8333d49b98ed6834612b4b56d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 -#: c3818bbf57ac448cb073fb780326fdf7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 of msgid "Step between candidate ports." msgstr "" -#: 1080747700804d04ae169eef511d5bb5 45799e3c1b6e446a86b111e06365ca9b -#: 5bfd1aa496dc41b7ab2abd78f134c389 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:8 -#: efa8e8819eec4e1ba0d90562f34755b5 of +#: e18848eedc5d4d8abd97d73a0984a5d3 of msgid "Number of ports per step." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 -#: c1cf751ac2774558925ef1ffd1a6c3dc of +#: 11e0523d1b194702a07a92748468da25 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 of msgid "Release this server's reserved port range." msgstr "" +#: 801c063c5fa447bda1dbf7f5ccbc6a9a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_lock:1 -#: b2b2a77e9deb4423955004a9e3390aca of +#: of msgid "Create the lock file that reserves the server port range for this process." msgstr "" -#: 658bc1e35a794bf5a22c70ffbef94b87 +#: 672bb7a9496c43ac8b706a3d0062ddfd #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:1 #: of msgid "Report whether the server port range is reserved by some process." msgstr "" -#: 39bb21b4d3a0404fb64295a73c2ad5ba 5dc09f28266e4a3bb083923d8784f09c +#: 39423e052b70403ba07a713aa9e3cb4a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:3 #: of msgid "True while the lock file exists." msgstr "" -#: 6512b0b8da7041e8a917014e5562583c +#: 5b6cf828ffb24e098a0c86a09818da73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_unlock:1 #: of msgid "Remove the lock file that reserves the server port range." msgstr "" -#: 90520dc2f5704cdaba37211d6390b03d +#: 479bdf5518dc4a029ecf47ad44bdcd5d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:1 of msgid "Allocate the next free server port range and record it on disk." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 -#: cf0980ef8455426781e617a911f73732 of +#: 34c085a1bfca4dedafc749bfdcf14ad5 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 of msgid "" "``port`` is moved past the ranges already recorded by other servers, so " "the instance ends up with a range of its own." msgstr "" -#: 1e5f1ba9b8bf4d28971b92ef12f747f2 +#: 197b30e318d741c2b1f8afc925e91e5c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:11 of msgid "If the server port info file cannot be read or written." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 -#: bf4bb338fcf846a29910656081787945 of +#: 1c97c8ef484b42ab86d36b3742bf3879 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 of msgid "Drop this server's entry from the on-disk port range record." msgstr "" -#: 30208c231b534eedbe843d42a3cad90d +#: 9fc07e857fa048e2956e64bf78f6e386 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:1 of msgid "Allocate a transfer port, waiting until one is free." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 -#: f219ec3cd1d1448fb4e0171853a7d779 of +#: 505d7b9fb1024bc8ba886e5b0a38fbf2 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 of msgid "" "Allocated port, or 0 when allocation is disabled " "(``is_hand_alloc_port`` False)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:5 -#: af35fb0d306d447ca2a70b0f2b63ecee of +#: e85fdf7f7a594e0b9aed565b4a3ab42f of msgid "Allocated port, or 0 when allocation is disabled" msgstr "" -#: 94b2dff9085247fda189e063a4fa4a7f +#: 153357eb91794cb692467afe5e94b41c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:6 of msgid "(``is_hand_alloc_port`` False)." msgstr "" -#: 06c8b24821f94f48b265dd90995e10a9 57f02c9c5f32443e82feac04411b32ed +#: 26c5c3768e1446e78c9efc5f8038b23d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:1 of msgid "Release a port obtained from `palloc`." msgstr "" -#: 750aeace3a2043978210096a24199700 +#: 0e0379de669843778f6827973c29372e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 -#: a400ec85715c462e941f3f590f646046 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 of msgid "Port to release." msgstr "" +#: 6a8d4efd9f9a45e399525e2f169035ee #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 -#: c6c5882e52c74fb1a5aa68e621922150 e95eb44c45ea42a5b63026f73274f990 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 of msgid "Allocate the next port above the base, or the first free one in range." msgstr "" -#: 2aec0e66e9e44175a6d6a36917137cf9 +#: 73e9e2ddd451402a93d10dbac6ac9374 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 14bd404133c744e68356290e50c91f4c +#: 9d96a242eab8433ca750d670a5f63b82 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:5 of msgid "Allocated port; None when the upward range is exhausted; 0 when" msgstr "" +#: 7b05e18fccbe4ab081d3cd22d59a48e0 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 -#: a2a1781441e64797a0d7942463680610 bccdcb4c96de4d6a9f6c4318d0b1f55e of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 of msgid "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 9b0a4b0fa07b4f7e8e4476f99d191837 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:1 -#: a4c53c6cf9d24f1ca624f8ade02cfb07 of +#: f2d9abe435cf49f6825bb72a68013934 of msgid "Release a port obtained from `file_palloc` and step the cursor back." msgstr "" -#: 24467ee3998b40bd9563059c6610e4e9 2a1c562ca62f40158d89d6f16896ed18 +#: 6c1fb07a212d4bf19717407b0c7184d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 -#: ace99e97fef7403faf20dc5040a47bfa ba3e6daae9e34590bc0f2abc98c02da3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 of msgid "Port to release. Ignored when allocation is disabled." msgstr "" -#: 053f2e52a148421eb080c1df3d3de1cc 9052b949aa354df7968cacc9ed930921 +#: 1afd81c685234a20aa41c5cde93d327d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:1 of msgid "Allocate the next port below the base, or the first free one in range." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 -#: eb3a97b7706a47dda4cfb5e12930ba02 of +#: 3fc63f6d51aa4c0fb22fd0f945f9cfd7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 3c8cc24113bd420eb7f373cde6a27ef2 +#: 74a441ccfa5e421dadd215ef0725a25f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 -#: f70a4f056d6c49b2b953824ffab19db7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 of msgid "Allocated port; None when the downward range is exhausted; 0 when" msgstr "" -#: 383142a0285745bb8ef4b95b1d597151 9f78428fda474dffac2f3cdf4c3a2aeb +#: 9c4b9bddd98c463f9e140bd2d8425dad #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:1 of msgid "Release a port obtained from `spy_palloc` and step the cursor back." msgstr "" -#: 57c8111cd86f49c7af67d8e9a177a591 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:1 -#: e435af0f27b641168044b3cac4130ac5 of +#: c66c76cab8564da4b6b6cb855fd63fd5 of msgid "Register a custom command handler." msgstr "" -#: 39f637bfe6ff4822952d67419861841d 51f84d06854b4b96b7ce1fb2e778b5e5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of msgid "" "Command to intercept, e.g. \"/my_command\"; matched case-insensitively " "against the first token." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:6 -#: b53c2039d55947d689c2cfe09cac93c2 of +#: c7c29a3836c9493e9c8804cc5896144a of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back to the sender as the response." msgstr "" -#: 15398a9c312e459a897c07b18dc9fbaa +#: 7c64d0c0b9ac44b995811a0fdaa0dfaf #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:10 of msgid "" "\"server\" for commands arriving from clients, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 7ff63de06e854f88b1cebc42b464397d 8f139fd48e9c496287f9df897ccf01d6 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 +#: a0c074a9da664c5eb5fa63deb6765c36 of msgid "" "Run the handler on the worker pool instead of the reader thread. Defaults" " to False." msgstr "" -#: 1a0a724bef6140ceb235cbeaea95c1d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:17 -#: e73cb64f1ef544db8009b026ab5c376c of +#: e6c616f887334cb6925c03de2ad6f64c of msgid "" "False when ``where_to_run`` is neither \"server\" nor \"client\"; the" " handler is then not registered." @@ -732,60 +945,107 @@ msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:19 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:19 -#: e1cba64f5b384d169c366d8e16078683 eaab849e83884bd6be80fa08867ccde2 of +#: f125f1386b434f3a8199b1ceb8c44eca of msgid "False when ``where_to_run`` is neither \"server\" nor" msgstr "" -#: 4cbf71104b8544d18962b7a9adca8b7e 82c461f38cc44bc9914cb7009a5cf3e1 +#: 1a68dac068db434eb76e28015005f29c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:20 of msgid "\"client\"; the handler is then not registered." msgstr "" -#: 15aa55a075a64bb98f5819a8a5d37113 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 of -msgid "Register ``listener(client_id, message)`` for every inbound plain message." +#: 25c1023e97b64226a58cdf83f8ba07bf 9ebd0da560d747168cebc59ca93b1cb1 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:1 of +msgid "Call one registered extension command handler directly from code." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 -#: f914714947174f2298278112a91d82b0 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:3 +#: b14f4ed43e6c43c39579c1c16b169645 of msgid "" -"Plain messages are the lines received from clients that do not start with" -" ``/``; commands go through the registered command handlers instead." +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines clients send. " +"The handler runs on the calling thread — ``run_in_thread`` only affects " +"the console and inbound dispatch paths — and is called with ``None`` for " +"both ``client_socket`` and ``client_address``, since a direct call names " +"no peer." msgstr "" -#: 1b5e4524170242099c808039098d64c3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:11 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of +msgid "" +"Command line to run, e.g. ``\"/my_command arg\"``; the handler receives " +"it unchanged." +msgstr "" + +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:15 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:15 +#: of +msgid "Whatever the handler returns." +msgstr "" + +#: 0ab70b2e8ed040d4908d0900da96f6c2 0d85b81af0634a448e6a74d63c06045f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:18 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:18 +#: of +msgid "If no registered handler matches the first token of ``command``." +msgstr "" + +#: 1f5b21975ad2499a86fe21c69bfd7ca0 42f8d27a5499457da7302224dcc8a521 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:19 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:19 +#: of +msgid "If ``command`` cannot be split (unbalanced quotes)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 +#: ef5d20f1a16945368383a8cdbc3daa19 of +msgid "Register ``listener(client_id, message)`` for every inbound line." +msgstr "" + +#: 2459179e833b4e7db8e1d70571ac793a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 of +msgid "" +"Every line received from a client is reported, commands included " +"(``/help``, ``/file ...``, the crypto handshake lines, ...), so the " +"listener observes all inbound traffic; dispatch is unaffected, a command " +"still goes through the command handlers." +msgstr "" + +#: 9ec5fafe8ded489785400e3e489b8573 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:8 of msgid "" "``listener(client_id, message)`` where ``client_id`` is the sender's " "``\"ip:port\"``. It runs on the receive thread, so it must not block, and" " exceptions raised inside it are swallowed." msgstr "" -#: 2e65864bfdd2429298dbf86682b3be81 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:1 -#: e562b99848544a8cb47afb41478d1b66 of +#: edb8edc2eb3f433186b54807a8ac43ad of msgid "Unregister a listener previously added by `add_message_listener`." msgstr "" -#: 346bd1c9d44045868b59b7643f1cf09e 8ff591c39e334e1eab8d05267532faed +#: 6fd7bb75a29e4973ac2bd05119255039 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 -#: a0e48bdcb67e49498a113a58a504553c ab196c3b77b143069faa85a52626d946 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 of msgid "Listener to remove; an unknown one is ignored." msgstr "" -#: 46010db8ce4d4eb1b06348f29e115846 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 +#: cf95477e5794404fbdf4e877a132ba1c of msgid "" "Register ``listener(client_id, full_path, name, size, command)`` per " "saved file." msgstr "" -#: 72536042242c4ea9bd2e6efa63fc9336 +#: 9c57d09f6d3d437890ae3ad306071701 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:3 of msgid "" "Fired after a file uploaded by a client (a direct send, or a forwarded " @@ -793,8 +1053,8 @@ msgid "" "``file_transfer_dir``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 -#: f4ba3546e2b048d49d9c274ef8d8ac98 of +#: 6c938b7c8be3464f9925527b6deb4e1d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 of msgid "" "``listener(client_id, full_path, name, size, command)``; ``client_id`` is" " the uploader's ``\"ip:port\"`` and ``command`` the wire command that " @@ -803,196 +1063,185 @@ msgid "" "block." msgstr "" -#: 2e1706c637c54db9b8ed55ba98665535 3d6b3f43b6094b2e9776fcb9e4ce7bcb +#: 57b1e98125974187b986386da7991dd0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:1 of msgid "Unregister a listener previously added by `add_file_listener`." msgstr "" -#: 0a8d57625bba4ce4949fc23bce63f033 +#: 58f1ccd078ea406dab00d6d4be886a76 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 -#: c27185227a5f434f9641501d1d3bca2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 of msgid "Run a callable on the instance's worker pool." msgstr "" -#: 0c5aed09b63647cd87a3234ef9a4903c 40fade944d8d43b18599150134015443 +#: 6e05c7f46b244ae195c32ee52797fa37 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:3 of msgid "Callable to run." msgstr "" -#: 6bcb8f96e0584f66bbb94fe2573a7f61 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:5 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:5 -#: e959076fdf3843fc9c53ccb8492adfe6 of +#: e1c79706c9414895bdf7bf183bf5d41a of msgid "Positional arguments forwarded to ``func``." msgstr "" -#: 41d755cbd3cf48e7a0bc9d2b1aa3ab14 628a65eab1354dda83077715a47e63fb +#: 9221436fa83a4831942cf5be4e37e2cb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:7 of msgid "Keyword arguments forwarded to ``func``." msgstr "" -#: 1c03aa271c37431d974f08f11c93d7af 4b1078858cf64a1e92b36fa109fc1409 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 +#: a6b26d6cf54d4fafac2950cbe33ba56f of msgid "" "Handle for the submitted call; its worker slot is released when the " "call finishes." msgstr "" -#: 169f874c0ebb40d5aecd2549e60b4600 1e45486e3fd84627b015bf5a9a0a24b4 +#: 60f19983f7384aefbb6c97b84dd25f93 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:12 of msgid "Handle for the submitted call; its worker" msgstr "" -#: 037748a51dd94d43a3939fa8ec538d66 655c7802ef7c42a686c74d426531db8b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 +#: eadf6af0a0954798933dc427ba8e107e of msgid "slot is released when the call finishes." msgstr "" -#: 7b0b391fc53d42fb8f331d8e2da2be54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:1 -#: d6578909a33e4eef8afe892b33e0f70b of +#: fece61298a354d6db119309b29c6751d of msgid "Start a temporary listener for a side channel (not the main protocol)." msgstr "" -#: 1164584733744eb2aa574d6f61476c2d +#: 01d42ba32c2b41f482dd077cfb950f9b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 -#: c132c5365e7c487c92b4072a0020b52c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 of msgid "" "``handler(client_socket, address)`` started in its own thread for every " "accepted connection." msgstr "" -#: 03583460bc824965b9152433dfdfb097 +#: 5e1b84445ee34c9cac00e1a2c9ef297b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 -#: e81f361ea0fb46ee9c6760b0c6ef11c1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 of msgid "Port to bind; None allocates one with `palloc`." msgstr "" -#: 4f2f3f063e9c4834a77fbdb1a46d65dc +#: 9c69c4dd1d904078af48c6308ba35895 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 -#: b655787e48384873b4446ee1147bdedd of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 of msgid "Listen backlog. Defaults to 1." msgstr "" -#: 31cd65b92bb846f6b9c97b003fa00db5 +#: 47f98fd15e6144bd845d175cd039a6c2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 -#: ec56b80af0a843a991cbe77c5ee9ae45 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 of msgid "" "``(port, thread, stop_event)``; setting ``stop_event`` ends the loop," " which closes the socket and frees the port." msgstr "" -#: 7b73372b2ada4ce5b210b527015d925c 86cfce9d36f04328ba76e88df87fbcd8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 +#: ecf3d32c44db40a8a13545d623ffe2c9 of msgid "``(port, thread, stop_event)``; setting ``stop_event`` ends the" msgstr "" -#: 11b0347a0ebd4ae3931ed1f77c26a04e 9017aeb8480241f3a5f426c718bc4ee0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:14 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 +#: abce9546b7444c6383c9020c4133ec63 of msgid "loop, which closes the socket and frees the port." msgstr "" -#: 3c32a346019741da9aa2a3e409a7b0e2 82f16e3e9ba1468d8a87c91db28cc45e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 +#: a270cfabdac64296b8a33ad4d662896f of msgid "If ``port`` is None and no port can be allocated." msgstr "" +#: 031d3e96394c454093561375a377dcce #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 -#: d63b5db9eab6478ca088c9a5e90163fc f0869b5be0ab40e4a2a7eca275922557 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 of msgid "Open a temporary outbound connection for a side channel." msgstr "" -#: 3d194b9f95794116b17720aa74ce0878 +#: 112fda54e1eb4981b4272df61c5416e2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 -#: d0bb03d9590540fd980dd79c28d98e97 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 of msgid "Host to connect to." msgstr "" -#: 98a5441019de48258a099f2ec25751f5 +#: 59d3c414b4304673be5d3232d2291680 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 -#: b443afa67dc84e1a8ac501ad5c6b0ff1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 of msgid "Port to connect to." msgstr "" -#: 537482efdcc0447e81bd001ad2d4d85a -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 +#: c5766672f68f47c9908e68d2ed3be7f3 of msgid "Local port to bind; None lets the OS choose." msgstr "" -#: 2230b0e486fc4229acc03f78ec4b1e09 300e61efcfef4a2f8c87725e183ceda8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 +#: bfc1b713e9fc4fe797e50c357f472e76 of msgid "``on_data(data, client_socket)`` called for every received chunk." msgstr "" -#: 2f63095ce33849b78465729923d04ff0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:14 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:13 -#: e07d5e5deb1a4fb086664ed896076feb of +#: c563d04fcd7a41f1a2aeace42974430a of msgid "" "``(client_socket, thread, stop_event)``; setting ``stop_event`` ends " "the receiver thread." msgstr "" +#: 0e1b9679f3104a9caab601e6bc7c0905 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:16 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 -#: bf9994c99c8a48139d4c00d0dcfeca63 dbf60e58abd04e02b50316b1cb4b7b2f of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 of msgid "``(client_socket, thread, stop_event)``; setting ``stop_event``" msgstr "" -#: 6af1621f80734591950e545b955c4bbe #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:16 -#: e69a51e576e446c59185c2eceae72657 of +#: c76fce92c3f944c1857df89bbc134540 of msgid "ends the receiver thread." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 -#: c291ec3d31094e589a1bfc5713b47ee3 of +#: 5ea5fd66c3d3434292e4d8e1dd1da094 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 of msgid "Send one message to every connected client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 -#: c28f38641c704c1e912c602ced57fc9e of +#: 32945f04e0564f9d88495506f0ab4f90 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 of msgid "Clients whose send fails are disconnected and removed from ``clients``." msgstr "" -#: 3f3e7a6a5de746518e9ddd135983d073 +#: 00de0b1f60b14189b1629f8146db68a6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:5 of msgid "Payload passed to `send_message`." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:7 -#: cae2a2c29d96447d8b1056e36bbf5572 of +#: a91c8f6921c7435e990516c2134efcf8 of msgid "``(ip, port)`` to leave out, typically the client the message came from." msgstr "" -#: 9b2b7c4e77844a82bfd61276bf46f6d7 +#: 9d57c62f1fd94c1dacfe32aa50cc9665 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:1 #: of msgid "Send the messages of a console line to the clients named in it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:3 -#: cabc278e7f6a49e6bd6e533f632d0f99 of +#: e7fbf4bbd84b4920a2b9591fabcaf2d9 of msgid "" "``/send_msg`` line as typed: message text followed by one or more ``(ip, " "port)`` identifiers; each message is delivered to the identifiers that " @@ -1000,17 +1249,17 @@ msgid "" "notice." msgstr "" -#: 888e165ca1554b4db63e714e3adc63f1 +#: 9d4819fe4ca94a1b81c9e0423ff98212 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:1 of -msgid "Write one line to a client socket, encrypting when the channel is up." +msgid "Write one message to a client socket, framing it when the channel is up." msgstr "" -#: 64d6f6cc29de4d4290671afc59d808c7 +#: 1c7b88e29a0143a39e13441769186ef4 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:3 of msgid "Target connection." msgstr "" -#: 73953d67bcbf4bfabae7b0ff91bfce8c 7e2e221f6a6b43a08f534ca2d8cfb6e8 +#: 6f8bd9adaf2b4c44a9446b049144fe21 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:5 of msgid "" @@ -1018,62 +1267,73 @@ msgid "" " are." msgstr "" -#: 240dadd589af42e18e15d2c53b5c96b0 +#: 5c03983cb460497fb72f126c1d8a2bc1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:9 of msgid "" "True when the payload was written, False for an unsupported payload " "type." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 -#: dbfc49c3c67c48d5860a61f8ded20950 of +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 of msgid "True when the payload was written, False for an unsupported" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 -#: cab2f5321ba54adca315d34d921a09b5 of +#: 602950a9f5ad48ea92ab60aea3b26488 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 of msgid "payload type." msgstr "" -#: 4519dac81e714164a0edbf6ac75c9c19 +#: 149f767d72dc4da7b1d88fed768d2474 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:15 of msgid "If the server is not running or no socket was passed." msgstr "" -#: 7ea1b30273604db4854189502fdf734e +#: 07dac2d20d7041779c8b189d45ee2e64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:16 of msgid "If the socket write fails (the original error is re-raised)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:1 -#: b228437e9cb4461e9ceb078f084544eb of +#: caf2377ee7f348ab8c95bf2a27c44be4 of msgid "Read up to ``msg_length`` bytes from a client socket." msgstr "" -#: 292c2ed074e14a5eb184dceb245cab6f 58a8806cd0bb4dc9895b7f74a1b45765 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 +#: c702e4a63a5240ea97feb5bc393b4d09 e9256fbce5d848b59ae2e6d0ce88ce24 of +msgid "" +"A socket speaking frames (see `_SecureChannel`) returns decrypted " +"plaintext, served from the channel's buffer; a socket without one is read" +" raw. A read that started while the channel was raw is classified by the " +"channel when it returns, so bytes of a flip that landed during the read " +"never land in the line reader." +msgstr "" + +#: 214af2667d0f443eb16c0a4aaf723b2e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:9 of msgid "Connection to read from." msgstr "" -#: 547ccf662a6945738e8c761628807ab1 624220029a624009adb07a49140d8a2c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:5 of +#: 7c3eb31687804ba5a59acc140ba50230 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:11 of msgid "Maximum number of bytes to read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:8 -#: b0973e75b118425db7e7bfc966e5eb87 ff5195026f8143fea9240d4f21e81981 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:14 of msgid "Received bytes, empty when the peer closed the connection." msgstr "" -#: 7acd066bfa87415094144b0e0c1ea0d4 +#: 7103cfcec26c44999cb5464251ee461c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:1 of msgid "Serve one accepted client until it disconnects." msgstr "" -#: 53591274f0824492afab6874b284c33e +#: 65f9de7f44774aa6aef81fcbe4dc1c64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:3 of msgid "" "Registers the client, greets it, announces the encryption mode and reads " @@ -1083,8 +1343,8 @@ msgid "" "ends for any reason." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 -#: fba3167476a94b62af90bfc4101d1ed6 of +#: 87d5085c31a14ad38b060c48f8cf1262 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 of msgid "" "With ``is_asynic_clients_io`` False (the default) the call blocks and " "owns its thread; with it True the client is served by a coroutine on the " @@ -1093,22 +1353,22 @@ msgid "" "no event loop runs is closed with a console notice." msgstr "" -#: 72edaf343723458fb9b2fe0f40bc01b8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 +#: db3915757e2842c8afee97b2d471411e of msgid "Accepted connection." msgstr "" -#: 6a2427e7b7de4d609bf61e3fad46b413 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 +#: fae378e888be4821a14ed2483cfde1e0 of msgid "Peer ``(ip, port)``; used as the client id and as the key in ``clients``." msgstr "" -#: 061015c431a54fafb45ea722ae696003 +#: 32886e2babcf4283924034c600453c4a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:1 of msgid "Dispatch one command line received from a client." msgstr "" -#: 9cc9ee25bc464440a4ac2bca19e5a413 +#: 8972b8c4edf149fd9a4008832c85ed31 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:3 of msgid "" "Built-in commands (``/help``, ``/time``, ``/clients``, ``/quit``, " @@ -1119,24 +1379,23 @@ msgid "" "close the connection; an unknown command is only reported on the console." msgstr "" -#: 9a970df310fc4b59b113bb6160f24fd2 +#: 208294924333477a8e7d65aa3130777e #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:10 of msgid "Connection the line came from." msgstr "" -#: 8856eb18fd044b60b869be64e5f4576e +#: 306e5026cfc1441d8c754f0e02866cf3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:12 of msgid "Peer ``(ip, port)``." msgstr "" -#: 6ea3bacf1baf4eadb98d5e38236ecf90 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:14 -#: e212b51318ea4d46ab6354b818dc262b of +#: a2a3a1fd57e14260a53675457fdff0b4 of msgid "Line including its leading ``/``." msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:17 of msgid "" "Response for that client, or None when no response is due (crypto " @@ -1145,11 +1404,11 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:19 -#: b3f201060ae548098d8284d4c18c0560 of +#: ed04a3bf285b4f57bb6a5de0c4f7284f of msgid "Response for that client, or None when no response is due" msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:20 of msgid "" "(crypto lines, file transfers, ``/quit``, which answers on the socket " @@ -1157,114 +1416,108 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:1 -#: b4ee832e0ad64d189740b45a297d713d of +#: a784dfdc5ded411d985426e36f6e5435 of msgid "Send one plain message to a connected target, tagged with its origin." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:3 -#: ec8cc922a2ee4e70bdff9a8e81b74e98 of +#: b545977244dc402aa8586264d2d933f3 of msgid "" "Public API for forward extensions: the message is wrapped in a " "``/send_msg_from `` envelope so the receiver can " "attribute it to the originator (see `parse_forwarded_message`)." msgstr "" -#: 660b6f4493ec4c9994af44960900cb10 +#: 8ee5275fbf894581ade9e6f30d5d4aff #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:7 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 -#: b8a3838c85624f3dbe705afac78acc47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 of msgid "Destination ``(ip, port)``." msgstr "" -#: 1dfa946975cf4768891292e84a2bbc63 +#: 38ffd8a7079d4794811e3504c01052f8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:9 of msgid "Payload to deliver." msgstr "" -#: 09f6b3913160404b9927d5e70252d9bc 5251c2b3867b4dc1b8dd8d09ea570d90 +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:15 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 -#: a8ee713ff78b42bd8adb5743ab369aef of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 of msgid "Originating client ``(ip, port)``." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:14 -#: ad5e4419a1d04b27bec64cf1aee14c53 of +#: d2471a90e269464c977239f406051120 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the envelope was sent." msgstr "" -#: 2fd94dad15884a56b9657090a33988f9 9e706f8851a74b569ade8deb4f8f70ab +#: 320d99b8923f4eaa886ffe0a16bfc6d9 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:24 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:16 of msgid "False when ``target`` is not connected (a console notice is" msgstr "" -#: 59049e3514b74a7ba90fb8886ecca185 +#: 1a97f59b270f404096d9c2b37ab09a8c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:17 of msgid "printed); True when the envelope was sent." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 -#: b9019e7dae074d64a66ae1c81967b9b8 of +#: 6baab06dc12e4ecc80d1a16c26c2a19a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 of msgid "Build the tagged wire command that pushes one forwarded item." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 -#: fcde926ccf5640b2b2ac6aab009aa4d0 of +#: 0c3f9dcbcf8f413fbd5befefb960c402 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 of msgid "" "Public API for forward extensions. The originator tuple sits before the " "trailing transfer id, where the receiver's existing parsers ignore it and" " `parse_forward_originator` recovers it for attribution." msgstr "" -#: 3cee0d37a9e5460a90b7c9b1abe53a92 +#: 3cf58937a2d04172bf544119279d85c1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 -#: d5cb9e15787a435ab586217498d98e2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 of msgid "\"file\" or \"file_folder\"." msgstr "" -#: 8efbb4663727491e8ee77edc824ce1c0 +#: 621a93603c8549c0ba047bee6aae5a38 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 -#: e8aeb2b89d5f4969aeaf2244f06a1a47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 of msgid "Relative folder path (folders only)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:13 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:11 -#: b439157e6df44d7bac2a4367c5fb66ee b9cb86fb0ad642e18ec19debb44a2648 of +#: f0f56fb642874c3889fb0dacfed4f4ef of msgid "File or folder name." msgstr "" -#: 5f249d30e8934ed0ae07c1ca2666c6c6 +#: 72d2b6fdd324482eaea9803def1fe2da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 -#: df45d1036cb9437a853551afb3f31775 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 of msgid "Transfer id shared by the pushed item." msgstr "" -#: 9bc7aaf1a36a4311a736f5528525d33a +#: 0aa1bd5b053544e98ae4ab3ae1add5f7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:19 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 -#: f806614c8aeb428292d6ca51db8ca35b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 of msgid "Receiver-side destination directory." msgstr "" -#: 1f3c679edcf34e71a946e8668ca27a58 +#: 93e666db45e745619b90c744e1646b73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:20 of msgid "Command line to hand to `send_message`." msgstr "" -#: 3499106d953f41789e53f24bfcae3af5 +#: 56d8327bb7414a5e85292f8f2ace9d42 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:1 of msgid "Push one forwarded file or folder item to a connected target." msgstr "" -#: 959c24d8afff4486ad5f787311bf3c8b +#: 3098afa7f4ac43a184d081dda8faa6ba #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:3 of msgid "" "Public API for forward extensions: sends the line built by " @@ -1272,24 +1525,157 @@ msgid "" "`parse_forward_originator`." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 -#: cb11d22918824fb09fa82fd432aeb74a of +#: 9b9634061040430484cd2596f43a8feb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the command was sent." msgstr "" -#: 66262977fc014465964289448673a5b9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 +#: b8bb8c432f7649d5a35480fec0509a51 of msgid "printed); True when the command was sent." msgstr "" -#: 1df1cd85678d4149bdac92c3591c9e50 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:1 of +msgid "Receive one file over a transfer sub-connection." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:3 +#: d3367c6f97aa4bf4b9cb3d79b3117fce of +msgid "" +"``peer`` is the transfer's original sender (the sender for an inbound " +"transfer, never a relay): it is stored with the progress entry so a later" +" reconnect can ask that peer to continue the file." +msgstr "" + +#: 5c4faf52e8bb4808805bae58d30ac0cc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:7 +#: de641d48c530435bb4adc04755a47a6d of +msgid "" +"``resume_entry`` continues an interrupted transfer: the listener " +"announces itself, asks the sender to continue from the bytes already on " +"disk (``RESUME_LINE``) and appends the incoming chunks to the partial " +"file instead of truncating it." +msgstr "" + +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:1 of +msgid "Send one file over a transfer sub-connection." +msgstr "" + +#: 87862abb10ad423f820952355f5936bc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:3 +#: d6a618c007ec433fa10a44b0a7a90fe4 of +msgid "" +"``control_socket``/``crypto`` carry the listener's mode stamp (\"plain\" " +"or \"enc:\"): an encrypted leg aborts when the session key " +"material is missing rather than downgrading silently." +msgstr "" + +#: 97e1a0538f544c2a8e755c78805fda7c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:7 +#: a405431dfd62434b82c7052edc456123 of +msgid "" +"``fid`` is the transfer's id — the caller's own transfer id for a plain " +"send, the relay id for a forwarded upload — and keys this leg in " +"``file_upload_progress``; every leg with a fid can be paused with " +"``/pause_trans`` for that fid. None (a leg without a protocol transfer " +"id, such as a public-key push) tracks no progress." +msgstr "" + +#: 6cb58bfd1dde4b49ba3525af014e44c7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (never a relay): it is " +"stored with the progress entry so a later reconnect can be resumed. " +"``resume_offset`` continues an interrupted transfer from the byte the " +"receiver already holds: the file is read from there instead of its first " +"byte." +msgstr "" + +#: 1634dbe84a95421a92a660f7c6fdd10e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:1 of +msgid "Continue the interrupted transfers of a peer that is back." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:3 +#: eb46142fa4e44147ad3ad8c680d5bee0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and, for " +"every download this instance was receiving from ``peer``, opens a fresh " +"transfer listener and asks the sender to continue the file from the bytes" +" already on disk. Restored uploads need no action here: the peer drives " +"their resume from its own side." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:9 +#: b7d54977ca494a8b9968365dffd9bd3d of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer that is " +"connected right now." +msgstr "" + +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:13 of +msgid "Number of resumed receive legs started." +msgstr "" + +#: 52cb873f015542b6a94506cebfe735a1 737ed182911443bc8cfff3c4d094b9a9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:1 of +msgid "Continue one interrupted transfer this instance was sending." +msgstr "" + +#: 50f292ac853841c9b082eb3c3ff4d6f4 6c968a5b77b342ed891883336cfcc255 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:3 of +msgid "" +"Runs when a receiver asks to continue a transfer (``/resume_trans``, see " +"`resume_transfers` on the receiving side): the leg is re-established " +"against the receiver's fresh listener and the source file is read from " +"the byte offset the receiver already holds. Also the public API for " +"resuming one transfer on demand." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:9 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "Receiver ``(ip, port)`` the request came from; None skips the peer check." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:12 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:12 of +msgid "Transfer id of the interrupted transfer." +msgstr "" + +#: 7124e1ce01df4fcea9516bed4ca55dc7 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:14 +#: d94da1700d0e46028f7bf114d7c5da62 of +msgid "Byte offset the receiver already holds." +msgstr "" + +#: 1a97f59b270f404096d9c2b37ab09a8c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:17 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:17 of +msgid "True when the resume leg was started." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 +#: b03f4edeca5f4cc19f6d695aac3690de of msgid "Bind the server socket, then accept clients until `stop` runs." msgstr "" -#: 42bb4623926449f5b91a451bcac30a2f +#: 7e027ea659ab48e19ea346cb284fe144 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:3 of msgid "" "Blocks the calling thread. A console command thread is started when " @@ -1300,12 +1686,12 @@ msgid "" "Socket errors and the end of the accept loop both end in `stop`." msgstr "" -#: 3d3320ce03544f23ac6f43883e5a580c +#: 291f5a8cc4f648ee9910e5cd45074675 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:1 of msgid "Read console commands until the server stops." msgstr "" -#: 5f7369176edb4567b3eb5332588b8c57 +#: 1ba2e428d432496688ef23f1c07562da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:3 of msgid "" "Handles ``/stop``, ``/status``, ``/clients``, ``/send_msg``, ``/file``, " @@ -1317,12 +1703,12 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:1 -#: ccbb242b51984c9f8ce9fb519c202485 of +#: eb90f49c77e64006a0c9ae861ff849b1 of msgid "Stop the server and release everything it owns." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:3 -#: e379bbd3f7b249c6b296f371548a5b1e of +#: a059b1e71106487999c83c2e2042f509 of msgid "" "Closes the server socket and every client connection, flushes the message" " and event stores, releases the allocated port range, clears ``running`` " @@ -1330,152 +1716,192 @@ msgid "" " Safe to call more than once." msgstr "" -#: 06fe9e3a48914447af6464acedea1fa0 +#: 32b06ea315b3404caa3a05c4aed0ce64 #: PyFlow.network_api.connect_tcp.TCP_Client_Base:1 of msgid "" "TCP client: connect to a server, dispatch commands, send and receive " "messages." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 -#: ef04371450674badb666b7fb31c203da of +#: 2b30f5c9ecd24fc89cdcd58000ee1e99 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 of msgid "" -"Lines received from the server go through `receive_messages`: a line " -"starting with ``/`` is handled by `handle_server_command` (protocol " -"commands plus the handlers registered for the \"server\" side), any other" -" line is a plain message delivered to the listeners registered with " -"`add_message_listener` and stored in ``messages_dict``. With " -"``is_input_command_in_console`` the console thread `interactive_mode` " -"sends typed lines to the server." +"Lines received from the server go through `receive_messages`: every line " +"is delivered to the listeners registered with `add_message_listener` " +"first (commands included; a forwarded ``/send_msg_from`` envelope is " +"delivered as its payload), then a line starting with ``/`` is handled by " +"`handle_server_command` (protocol commands plus the handlers registered " +"for the \"server\" side), any other line is stored in ``messages_dict`` " +"as a plain message. With ``is_input_command_in_console`` the console " +"thread `interactive_mode` sends typed lines to the server." msgstr "" -#: 840ff55e5e444cfbb85251e9c4123178 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:12 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 +#: b9532c86786c43d5aea58b24157fefed of msgid "Server address this client connects to." msgstr "" -#: 1f65ef8a745743ebb31ebc5805c5b02f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:18 of +#: 2cfa1e3e1674407ba1e2683e76fef65d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 of msgid "Server port this client connects to." msgstr "" -#: 5956a034ca2347f384f682b52d927ee3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:24 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: af04fdee2c95431a9b0c17f96e50c18c of msgid "Local address the socket binds to." msgstr "" -#: 1d2b7be8ff994d15b9a3f63c0e4fab11 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:30 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 +#: b1d4b5606e1c48b6a915815527542758 of msgid "Local port, None when the OS chose one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 -#: d616019e80a741638b6ac020d6abb336 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:34 +#: d926b4f3eb4b40a4acb21f780a4dc227 of msgid "int | None" msgstr "" -#: 0a015a4f44194fe2b25bbd4dfe52d1eb -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:36 of +#: 500cfd177cf5453d887f6904b73b7851 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 of msgid "True while the connection is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 -#: da7ca1204aea47779bbaaa809f79da93 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:76 +#: fd832e1d72b642838382d529c3e1f22c of +msgid "" +"Whether `start_TCP_client` reconnects after the connection drops (and " +"resumes the interrupted transfers)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:102 +#: c194bbee7cf14d268c330e06f94ae973 of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when the connection drops and read back on the next reconnect " +"(`resume_transfers`)." +msgstr "" + +#: 40f2a9e1b730422db3dd58bc2a6046e3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 of msgid "Create the client and, unless extended, connect and start reading." msgstr "" -#: 9e0577d19b76432089a46a53a2bbf7be +#: 0552aa36b7b74474af8f43b380dbee54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:3 of msgid "Server address to connect to; required before `connect` is called." msgstr "" -#: 8400b2487cfb4cff8a72f452e3b4c83e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 +#: d246ff9aaf154bfa91b5c4c9d293afd5 of msgid "Local address the socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: 7cb2047b830c4996832b4623812a687b -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 +#: e981b68ebbea46e9b556b09f4b5cd44a of msgid "Server port. Defaults to 65432." msgstr "" -#: 7a0404b673f84a1191af5479097f8cf5 +#: 766bf4c138234fe081bbd2668dcb2a5d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:11 of msgid "Local port to bind; None lets the OS choose an ephemeral port." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 -#: df784379acc1474aba6566c969dbb7bc of +#: 5d661c0f91f64ef39cacb1a5466d752c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 of msgid "" "Socket timeout in seconds for connect and receive. Must be None when " "``is_wait_server`` is True." msgstr "" -#: 2b8bf92e3eb049ee8e994aa8b6d92fa5 +#: 9478d02062284ecaa7838f931ab80780 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:17 of msgid "Step between candidate ports in the allocation range. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 -#: fa74d746eefe4cb6862068fdbf384dd8 of +#: 2e1695ae510b43758793257124fd23c2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 of msgid "Enter interactive mode after connecting. Defaults to True." msgstr "" -#: 95ebbc90f84a41ada4b6edbec2c7a95e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 +#: e02da86957dd4f45bf84ede4e9c82cda of msgid "Keep retrying while the server is not reachable. Defaults to True." msgstr "" -#: 259f9e8d0d1547ae81e047e8ec24875d -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 +#: e1fb7f67e1714a61a9e8fe500555c700 of msgid "" "When True, do not call `start_TCP_client`; the caller connects when " "ready. Defaults to False." msgstr "" -#: 794bfe7ef8594729b0e87230d3ed9e49 +#: 1634dbe84a95421a92a660f7c6fdd10e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:34 of msgid "Negotiate the RSA-encrypted channel with the server. Defaults to True." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:40 -#: e3f9232109d34798af1f681b250ec7d5 of +#: cff66a7ac1ad410f96ed1ee03cb1cf53 of msgid "" "Buffer ceiling in MiB, kept for parity with the server class; the " "client's forward path does not read it today. Defaults to 2048." msgstr "" -#: 71b662106e594538b8a5fcb9bc190b1f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:51 of +#: 14c4889553fb42f7b0393a4a7ab46b4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:72 of +msgid "" +"Reconnect (and resume the interrupted transfers, see `resume_transfers`) " +"when the connection drops while `start_TCP_client` runs. The transfers " +"that died with the connection are persisted to the protocol's ``.Flow`` " +"directory and read back on the next connect. Defaults to False: a dropped" +" connection ends the client." +msgstr "" + +#: 0f06ff3b6db940da96ec09bee3dba526 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:80 of msgid "If ``is_wait_server`` is True and ``timeout`` is not None." msgstr "" -#: 4388cbc6302341adbdfa566d93526ef1 +#: 5dd677b9627d4b84b53dc7a6b2848b3f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:6 of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back as the response." msgstr "" -#: 14fcd0c8f3554ae983ac746cf3e58621 +#: 0a57a7875bb94767904ff8d93fa77eb8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:10 of msgid "" "\"server\" for commands pushed by the server, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 88087ef71067485dbd40d569a7b950d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:3 +#: acb1af86a6184624a47ac6cc3b7127d0 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines the server " +"sends. The handler runs on the calling thread — ``run_in_thread`` only " +"affects the console and inbound dispatch paths — and is called with this " +"client's socket and id, the context its dispatch paths give it." +msgstr "" + +#: 876e8fe2a6d645829ba12ddbad5006df #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:1 of -msgid "Register ``listener(sender_id, message)`` for every inbound plain message." +msgid "Register ``listener(sender_id, message)`` for every inbound line." msgstr "" -#: 50556c2d788d4e39a4a7cfed81ef6d6d +#: 2658650e027a4697b248f261903a4e29 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:3 of -msgid "Mirrors the server-side contract; commands are not reported here." +msgid "" +"Every line received from the server is reported, commands included, so " +"the listener observes all inbound traffic; a message another client " +"forwarded here is reported as its payload, attributed to the forwarder." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:5 -#: e6bec65449634cff953afd74d0e23e7a of +#: 412834182c9442adaf0b85e24c200ccc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:7 of msgid "" "``listener(sender_id, message)``; ``sender_id`` is the author's " "``\"ip:port\"`` — the forwarding client for a message another client " @@ -1485,21 +1911,21 @@ msgid "" "swallowed." msgstr "" -#: 38c576fe994b4a77830eaba36ca063b3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 +#: fc8a83e0b5f84273a8287b122c1a9a3e of msgid "" "Register ``listener(full_path, name, size, command)`` per saved inbound " "file." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 -#: e258540084d64816a08e0783810c4e3e of +#: 34e3386853564aab9a824e96438fc3e5 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 of msgid "" "Fired after a file pushed by the server (a direct send, or a forwarded " "file/folder item) has been fully written to ``file_transfer_dir``." msgstr "" -#: 4e10b4a74e9142e0868ab1b0b423f359 +#: 63f925709b83433e967610672b6fbc79 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:6 of msgid "" "``listener(full_path, name, size, command)``; ``command`` is the wire " @@ -1508,115 +1934,200 @@ msgid "" "it must not block." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 -#: afdf1e13067b4914a6aead736d7604e3 of +#: 4bc88415dfff40a3884ee0284b0ccc3f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. This " +"covers every outgoing transfer — a plain upload as much as a forward " +"upload — and is what the ``/pause_trans`` line does when it arrives from " +"a peer." +msgstr "" + +#: 7e190ff27df349ae90eb7bd98a0b6b5b +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:11 of +msgid "" +"Restrict the pause to the leg whose original receiver is this ``(ip, " +"port)``; None pauses whichever leg holds the fid." +msgstr "" + +#: 5479763134c04a418df6a9e5011a9dcf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:16 of +msgid "" +"True when a running leg was marked paused; False when nothing matched" +" — the switch is still armed, so a leg started later under this fid " +"starts paused." +msgstr "" + +#: 2bc5d7e5dfa94eb29b49f12562f57c88 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:18 of +msgid "True when a running leg was marked paused; False when" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:19 +#: a9c7cb3036f8409faad4c1db964d8a91 of +msgid "" +"nothing matched — the switch is still armed, so a leg started later under" +" this fid starts paused." +msgstr "" + +#: 59fa8126f08348bb9368c35b5d2336e2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg whose original receiver is this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:9 of +msgid "True when a running leg was resumed." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:1 of +msgid "Ask the server to pause its transfer toward this client." +msgstr "" + +#: 89fa1c905614496ea12a4cfde9eb3cce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:3 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (a forwarded upload this client relays is throttled this way)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:3 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "The server's ``(ip, port)``; None accepts the connected server." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:6 of +msgid "Transfer id of the server's outbound leg." +msgstr "" + +#: 39423e052b70403ba07a713aa9e3cb4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:12 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:9 of +msgid "True when the line was written." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:1 of +msgid "Ask the server to resume a transfer paused earlier." +msgstr "" + +#: 0e91f82d8856443497c399f97643b757 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 of msgid "Reserve this client's port range under the cross-process lock." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 -#: cd973d56799848ecbd65c434c9f5f0ae of +#: 6029a28126344e45b24394cb56b2f8f8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 of msgid "No-op until the server assigns a range (see ``/client_alloc_port_range``)." msgstr "" -#: 29e4db224e2d4208a5fc08a1523f9e6b +#: 32bed401c3574959ba5ed08fc9078401 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:1 of msgid "Release this client's reserved port range." msgstr "" -#: 7b0f2f6530984dcc888286f471f14747 +#: 9f86b7aac4f44886be9cd87b56072b63 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:3 of msgid "No-op unless a range was assigned (``is_hand_alloc_port`` True)." msgstr "" +#: 8154f96d9ec74bd588971a806d42f8c1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_lock:1 -#: c6e04e800074445da45886940c77a9f8 of +#: of msgid "Create the lock file that reserves the client port range for this process." msgstr "" -#: 2c7b09854c254d0bbfa62d2a356cfb24 +#: 69c2dd5d5d1d497c8bac1e62ab4fc30a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:1 #: of msgid "Report whether the client port range is reserved by some process." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_unlock:1 -#: b2cbf44d95154896ab2df64bf8be1a3d of +#: c88f37ef2d5c47bda346e804508d6ec0 of msgid "Remove the lock file that reserves the client port range." msgstr "" -#: 690717115cb64dfeb32f56302992451c +#: 478443e187814a6ca7ad798277db023f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:1 of msgid "Allocate the next free client port range and record it on disk." msgstr "" -#: 2e8d17873f8b4b419f2f6cd1f2000a62 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 +#: a8736540f4c3402fad9508e619d559d7 of msgid "" "``port`` is moved past the ranges already recorded by other clients on " "this host, so each instance ends up with a range of its own." msgstr "" -#: 2d7cb151d3bc4798914cbe3d73391c16 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 +#: bc44b1604e02467280b59cb8ad63d0af of msgid "If the client port info file cannot be read or written." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_free_port:1 -#: b6079f909975409c86477341dcf2990c of +#: e48dff576a074109a135db168b5dbe98 of msgid "Drop this client's entry from the on-disk port range record." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 -#: c7fc083bff234cb7b377bc7adbb65ca5 of +#: 3aa62e8843c6495c862f43fc6dda9d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 of msgid "Allocate a port, waiting until one is free." msgstr "" -#: 85129bb5393542e498835f3ba6dc981a +#: 2f7752fa51d946b1a4a566b38f046e80 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:3 of msgid "Allocated port, or 0 when no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 -#: e77dc25d62bc4eedbd153b7420d109f4 of +#: 503ab40fc32c4d548f65fa3272b2f4d2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:5 -#: c452f87d6e18446cbbb2f48b1dc47b9b of +#: b9fd549c95f24c2080d87cec92514db6 of msgid "Allocated port; None when the upward range is exhausted; 0 when no" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 -#: e195a16298f14417b95ed3dc3ad60fac of +#: 151a65f1c1984e4196c750108d0611cb +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 of msgid "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 -#: f7330894d1a041ca9a31ca1b390d5af7 of +#: 0c6201bb2d7e45d3a4916d7e50a21e10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 -#: a8d7d910fb874925acb423d08187908d of +#: 76c766a9c61f4075a762ccf55038a65e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 of msgid "no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 -#: c76dd143ea224bb69081222ac4228f8f of +#: 8d500513e8854ba4bb91c8905a9adb73 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 of msgid "Local port to bind; None allocates one with `palloc`." msgstr "" -#: 5a8b77d5b1e243d9b5b24039b6ff25d0 +#: 840360623c8a4c2bbafe8fe7bbf9209c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:1 of msgid "Connect to the server and start reading from it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:3 -#: b59d15dc7c7844a5bd0226eb081c9887 of +#: df94288e660b48f6809358b3dc234ec9 of msgid "" "Binds ``client_port`` when one was configured, then retries while " "``is_wait_server`` is True and the server is not reachable yet. Once the " @@ -1624,7 +2135,7 @@ msgid "" "negotiated, which closes the connection when the two sides disagree." msgstr "" -#: 8711ef70ac704a48b05e13ded3546471 +#: 22fccba0ab36499a9a7f4427abe5e9f4 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:8 of msgid "" "True when the connection is established (and, if encryption is " @@ -1632,105 +2143,107 @@ msgid "" "failed or the mode negotiation closed the connection." msgstr "" -#: 850616ca4a614020b9627a3c39a54555 +#: 0270d0a2d42740a9889106339d9f2dbb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:10 of msgid "True when the connection is established (and, if encryption is" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:11 -#: cd0e7073f18d4d2ba990f1bfda735fd4 of +#: c194691cedfb48c6bfd97d9bdc6f2246 of msgid "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 -#: b7b9e013f50348379a0208a7702b9b1f of +#: 4dc38e3ef3b74b8e8c27378242a1925a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 of msgid "Read from the server until the connection ends." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 -#: ae819668995f44878eaa9c4a8db02583 of +#: 431649a0d703476dadc6afa8adbe53d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 of msgid "" -"Runs on the receive thread: plain lines are reported to the message " -"listeners and stored in ``messages_dict`` (``/send_msg_from`` envelopes " -"are attributed to their sender first), other ``/`` lines go to " -"`handle_server_command`. Any end of the connection clears ``running`` and" -" releases the port range." +"Runs on the receive thread: every inbound line is reported to the message" +" listeners (commands included); a plain message is also stored in " +"``messages_dict``, while a ``/send_msg_from`` envelope is reported and " +"stored as its payload attributed to the forwarding client, and other " +"``/`` lines additionally go to `handle_server_command`. Any end of the " +"connection clears ``running`` and releases the port range." msgstr "" -#: 32feafb4504a473dbbe6b0957d3658f0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 +#: cf284b59f7f849039404ced20f8e12db of msgid "Write one line to a socket, encrypting when the channel is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 -#: c639152d8792432ba220c33c860f1211 of +#: 40ba2ede2d3f4666b82107af129d24d0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 of msgid "Target connection; the client passes ``self.client_socket``." msgstr "" -#: 5b421459787b4210b8bce3e7003cf35b +#: 2e663941eaf142cb96738add05f9ef4d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:10 of msgid "" "True when the payload was written; False when the client is not " "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 1684a06aa826439784ce149aece2f637 +#: 38905ec7539d42e0839907c32dd8667f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:12 of msgid "True when the payload was written; False when the client is not" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 -#: bc5ff108fa3d46afb45fd86d4106ac2f of +#: 3f7e2e6fedda476f996132c3f677f2f0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 of msgid "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 3b27239d40244e35817e0806e3363df0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 +#: a9220a130e694e0aba1d3b6320dff498 of msgid "Send the payload of a console line to the server." msgstr "" -#: 66bc43727101429bacd6a76534c53f7b +#: 2e208e83a89e4dac9793460a8808a042 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:3 of msgid "" "Console line such as ``/send_msg hello``; the first token (the command " "name) is dropped and the second one is sent." msgstr "" -#: 4cb6da8a7d464be983bf467e65fe55b0 +#: 39c8e70ca92b43b8ac687bc0aa7f4073 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:7 of msgid "If the line has fewer than two tokens." msgstr "" -#: 369743f21d0f4656aa801c8f29b4129b +#: 8d47f30ae7b0451f8ecfe207ec835ff3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:1 of msgid "Read up to ``msg_length`` bytes from a socket." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 -#: f6749336c57b4a82b5c0b19f27bd8906 of +#: 10a39005f45c46728ef9a000eeaf9109 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 of msgid "Dispatch one command line pushed by the server." msgstr "" -#: 510b3d71451048138e11fe92fdb160b4 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 +#: a7e781fde939475cb081204adac16ded of msgid "" "Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the" " connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange " "lines, and the transfer lines ``/file``, ``/file_folder``, " -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, " +"``/start_trans``, ``/resume_trans``, ``/forward_resume`` and " "``/forward_error``. Any other name goes to the handlers registered for " "the \"server\" side via `register_command`; an unknown command is only " "reported on the console." msgstr "" -#: 7724aab357eb408dbbf018c214f8eba0 +#: 91942d88960c4793b5eab8c3654c1400 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:1 of msgid "Forward plain messages to other connected clients through the server." msgstr "" -#: 12403f5be7704258849974d103865b9c +#: 75bb9147a7464a278e19af9d03b04ecb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:3 of msgid "" "The console command ``/forward_send_msg`` uses this; the client must be " @@ -1738,40 +2251,40 @@ msgid "" " so the receiving client can attribute it back to this one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 -#: fc0907a1c7484f66a7b2cc1a99d24dc0 of +#: 0f3c201936df45b687dc5532531b4a4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 of msgid "Message texts to forward." msgstr "" -#: 8d07efc16f6c45d7b9d1d4f85f945317 +#: 277bbcb2143943b5b983badb00c3f4fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:9 of msgid "Destination ``(ip, port)`` tuples." msgstr "" -#: 4afafed2326a42e391e3b098cfea4f06 +#: 5ea8eea489fc43108a439d54fba31068 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:12 of msgid "" "True when the request was written to the server; False when the " "client is not connected." msgstr "" -#: 85c761742fa5450f846373591e4af1ff +#: 2bc5d7e5dfa94eb29b49f12562f57c88 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:14 of msgid "True when the request was written to the server; False when the" msgstr "" -#: 6ae9ff84b7d64c30abd31cde1715b783 +#: 45d974ad946b408b91d41bcce65abcc8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:15 of msgid "client is not connected." msgstr "" -#: 7b79bd0e677c42fd921308a34e9a0929 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 +#: c9401da7c37e40e5978c80e4876b11a0 of msgid "Read console lines and act on them until the client stops." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 -#: d91a5c812cdb4705a2fa27ac33ef693a of +#: 793bcfd02c014200b0ec47f8e15b4d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 of msgid "" "``/quit`` closes the connection; ``/send_msg``, ``/file``, " "``/multiple_file``, ``/file_folder``, ``/multiple_file_folder``, " @@ -1781,38 +2294,77 @@ msgid "" "it stands. Ctrl-C and EOF close the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 -#: dc2c54034ec64b61a3af655e86bc81a2 of +#: 7ba721f9d59742b99e89e3b6e249e754 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (the target of a forward, " +"never the relay): it is stored with the progress entry so a later " +"reconnect can be resumed. ``resume_offset`` continues an interrupted " +"transfer from the byte the receiver already holds: the file is read from " +"there instead of its first byte." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:3 +#: a3c59554b8de41b280df7536b307bed0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and drives " +"every download that can be continued: a file the server was sending is" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:6 +#: fae378e888be4821a14ed2483cfde1e0 of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer the " +"client can reach." +msgstr "" + +#: 48061103ed9d4bcaae8a8a837b363557 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:10 of +msgid "Number of resumed transfers started or requested." +msgstr "" + +#: 6dbae803a56c442588b28af664b7a0e9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 of msgid "" "/forward_file ... ... [dest] (client " "only)." msgstr "" -#: 303ae7e9e20444e38b303177bef0fb36 +#: 05cad8b03e0747dc804ffbfda3122fe1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_folder_console:1 of msgid "" "/forward_folder ... ... [dest] " "(client only)." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 -#: ec2b9ff3c5cf4fb5a79e29242221fe67 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:3 +#: f6f606236f434f0287a969ccbe5ba2c5 of +msgid "" +"``peer`` is the transfer's original sender (the server for a pushed file," +" the originating client for a forwarded one — never the relay): it is " +"stored with the progress entry so a later reconnect can ask that peer to " +"continue the file." +msgstr "" + +#: 6e9a9717a782419baecca63fd1f46baf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 of msgid "Close the connection and release everything the client owns." msgstr "" -#: 43645acb6c524c348b870d288aafae5e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 +#: ba6c5badecf6465db6036735870ed305 of msgid "" "Stops the receive loop, releases the port range, flushes the message and " -"event stores and closes the socket. Safe to call more than once." +"event stores, persists the interrupted transfers and closes the socket. " +"Safe to call more than once." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:1 -#: afb1904037404a6c99f6b7ae2df119e2 of +#: c91a3245b93f46abbb49dbef7bcfeb1c of msgid "Connect to the server and start the client loop." msgstr "" -#: 6f912c76416e4f37a750eda0c126da35 +#: 0c83552867484ea780fcff8d34e5c2d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:3 of msgid "" "Enters `interactive_mode` when ``is_input_command_in_console`` is True, " @@ -1822,6 +2374,15 @@ msgid "" "while still connecting returns quietly, because that stop was asked for." msgstr "" +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:9 +#: eec663f58484446ebce460e6402d7b5f of +msgid "" +"With ``is_auto_reconnect`` True a dropped connection does not end the " +"client: it reconnects (waiting for the server when ``is_wait_server`` is " +"set) and every session carries the interrupted transfers of the previous " +"one (`resume_transfers`). A close or ``/quit`` still stops the client." +msgstr "" + #~ msgid "" #~ "Concepts live in " #~ "``docs/Network_APIs/TCP_Server_APIs.rst`` and " @@ -1917,3 +2478,110 @@ msgstr "" #~ " `close`." #~ msgstr "" +#~ msgid "" +#~ "one message per line, terminated by " +#~ "a newline; a line that starts with" +#~ " ``/`` is a command and goes to" +#~ " the command handlers, anything else " +#~ "is a plain message reported to the" +#~ " registered message listeners;" +#~ msgstr "每行一条消息,由换行符终止;以''/``开头的行是一个命令并转到命令处理程序,其他任何内容都是报告给注册消息侦听器的纯消息;" + +#~ msgid "" +#~ "an RSA-encrypted channel is negotiated" +#~ " right after connect unless " +#~ "``is_enable_encrypto`` is False;" +#~ msgstr "连接后立即协商RSA加密通道,除非`` is_enable_encrypto ``为False ;" + +#~ msgid "" +#~ "The forwarding extensions use the " +#~ "module-level parsers `parse_forwarded_message`, " +#~ "`parse_forward_items_and_addrs`, `parse_forward_originator` " +#~ "and `forward_skip_message`." +#~ msgstr "" + +#~ msgid "" +#~ "Each accepted connection is served by" +#~ " `handle_client`, either in its own " +#~ "thread (the default) or by a " +#~ "coroutine on an asyncio event loop " +#~ "when ``is_asynic_clients_io`` is True: a " +#~ "line starting with ``/`` goes to " +#~ "`handle_command` (built-in commands plus " +#~ "the handlers registered with " +#~ "`register_command`), any other line is a" +#~ " plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(client_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "" +#~ "Plain messages are the lines received" +#~ " from clients that do not start " +#~ "with ``/``; commands go through the " +#~ "registered command handlers instead." +#~ msgstr "" + +#~ msgid "Write one line to a client socket, encrypting when the channel is up." +#~ msgstr "" + +#~ msgid "" +#~ "Lines received from the server go " +#~ "through `receive_messages`: a line starting" +#~ " with ``/`` is handled by " +#~ "`handle_server_command` (protocol commands plus " +#~ "the handlers registered for the " +#~ "\"server\" side), any other line is " +#~ "a plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``. With " +#~ "``is_input_command_in_console`` the console thread" +#~ " `interactive_mode` sends typed lines to" +#~ " the server." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(sender_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "Mirrors the server-side contract; commands are not reported here." +#~ msgstr "" + +#~ msgid "" +#~ "Runs on the receive thread: plain " +#~ "lines are reported to the message " +#~ "listeners and stored in ``messages_dict`` " +#~ "(``/send_msg_from`` envelopes are attributed " +#~ "to their sender first), other ``/`` " +#~ "lines go to `handle_server_command`. Any " +#~ "end of the connection clears ``running``" +#~ " and releases the port range." +#~ msgstr "" + +#~ msgid "" +#~ "Handles the protocol's own lines: " +#~ "``/crypto_mode`` (a mismatch closes the " +#~ "connection), ``/client_alloc_port_range``, the " +#~ "``/crypto_*`` exchange lines, and the " +#~ "transfer lines ``/file``, ``/file_folder``, " +#~ "``/forward_upload``, ``/pause_trans``, ``/start_trans``," +#~ " ``/forward_error``. Any other name goes" +#~ " to the handlers registered for the" +#~ " \"server\" side via `register_command`; an" +#~ " unknown command is only reported on" +#~ " the console." +#~ msgstr "" + +#~ msgid "" +#~ "Stops the receive loop, releases the " +#~ "port range, flushes the message and " +#~ "event stores and closes the socket. " +#~ "Safe to call more than once." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po index 9a55dd5..060c6eb 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -20,21 +20,21 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.rsa_crypto.rst:2 -#: a48a4f614e834981afd42e2cb723ce06 +#: def9740b5a2e4aaeb2aeed8b4f02c0ec msgid "PyFlow.network\\_api.rsa\\_crypto module" msgstr "" -#: PyFlow.network_api.rsa_crypto:1 e529881eccb0440c888d5c69244133f9 of +#: 46d3090efafd4504870cf72a4bea22ab PyFlow.network_api.rsa_crypto:1 of msgid "crypto_api (C/OpenSSL) RSA integration for PyFlow's TCP layer." msgstr "" -#: PyFlow.network_api.rsa_crypto:3 d9d01596a65340fb84c25298550845cf of +#: 5b1ff4a00b0f46258cda2e7440368de1 PyFlow.network_api.rsa_crypto:3 of msgid "" "A thin ctypes binding to the shared ``libcrypto_api`` plus the key " "lifecycle required by the encrypted TCP channel:" msgstr "" -#: 232e71aebc434fb6bece23f593557e9f PyFlow.network_api.rsa_crypto:6 of +#: PyFlow.network_api.rsa_crypto:6 a5a0d6d600604683990a92555a49a3fe of msgid "" "Reuse an existing RSA keypair from ``~/.ssh`` (PEM private key) when one " "is present and parseable, otherwise generate a fresh keypair into " @@ -42,7 +42,7 @@ msgid "" "honoured when both files parse and the pair matches." msgstr "" -#: 29d30af10f8c4180890f876bb14b00e3 PyFlow.network_api.rsa_crypto:10 of +#: PyFlow.network_api.rsa_crypto:10 bb413dc908624589a3e57f8a2c702728 of msgid "" "Anti-MITM identity check (TOFU): every connection exchanges public keys " "in plaintext. Each side records the peer in " @@ -52,14 +52,21 @@ msgid "" "endpoint is re-registered under the new ``(ip, port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto:16 d4873e3b840e4e7fbe4c6f85850dc2a7 of +#: PyFlow.network_api.rsa_crypto:16 aec1a7998276428881efcfac6fe4cebe of msgid "" "RSA-OAEP encrypt/decrypt with the ``_VALID`` plaintext signature so a " "stale key (for example a rotated ``~/.ssh`` pair) is detected and the " "peers re-exchange their public keys." msgstr "" -#: 49f63152bca249588cf98871d5bafa64 PyFlow.network_api.rsa_crypto:20 of +#: 392850c432f2466ab9ecfd64770e648d PyFlow.network_api.rsa_crypto:19 of +msgid "" +"ECDH key agreement (P-256/P-384/P-521) with HKDF-SHA256 session-key " +"derivation and AES-256-GCM ``seal``/``open`` (``EcdhKeyPair``, " +"``EcdhPubKey``, ``hkdf_sha256``)." +msgstr "" + +#: 55cfc03aeb3f4d6ba37b10a01dfcdccc PyFlow.network_api.rsa_crypto:23 of msgid "" "The C library is compiled into the installed package by ``setup.py`` (a C" " compiler and OpenSSL development headers are needed at install time); a " @@ -67,21 +74,33 @@ msgid "" "still supported. See ``load_library`` for the search paths." msgstr "" -#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 -#: a3ac757cc1fa4c73be13eaa020c8e60b of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 of msgid "Raised when the shared libcrypto_api cannot be loaded." msgstr "" -#: 9c5bbad270ac48cd997b23cd4f284152 PyFlow.network_api.rsa_crypto.RsaKey:1 of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:1 of +msgid "Raised when a ``pf_*`` call fails." +msgstr "" + +#: 2c3651ee5dc94886986aa9804b164e3d +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:3 of +msgid "" +"``code`` is the ``pf_err_t`` value (one of the ``PF_ERR_*`` module " +"constants), or ``None`` when the failing call returned no code." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.RsaKey:1 e620122ff0bc48dd985c4b6a0b3b41ce of msgid "Owns an ``pf_rsa_key_t*`` handle; frees it on GC." msgstr "" -#: 0eab5b9b31774196a46b7d400341a404 +#: 1a7d8e9db5a3435486d716b13f2a2a56 #: PyFlow.network_api.rsa_crypto.load_library:1 of msgid "Locate and load the shared crypto_api library (cached)." msgstr "" -#: 8bcac9994a6048e4920e23b8f94bb000 +#: 287fcfd81df2461d8e4bceebf61b7e40 #: PyFlow.network_api.rsa_crypto.load_library:3 of msgid "" "Search order: the library ``setup.py`` compiles into the installed " @@ -92,25 +111,98 @@ msgid "" "reported only if no other candidate works." msgstr "" -#: PyFlow.network_api.rsa_crypto.get_local_mac:1 -#: b555d90eff7c445a8a28cb3de88bd581 of +#: PyFlow.network_api.rsa_crypto.EcdhPubKey:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_pubkey_t*`` handle; frees it on GC." +msgstr "" + +#: 556fdf46d6c543e0ab06e2d4fabad7f1 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:1 of +msgid "Parse a peer public key from a PEM string." +msgstr "" + +#: 88cd040e91194a3785bf56d7c52d3543 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_PARSE`` for " +"malformed PEM or a point that is not on the curve (the C library verifies" +" the point)." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_keypair_t*`` handle; frees it on GC." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:3 f12b2d8d1d4846edbf60d64c34860558 +#: of +msgid "" +"``curve`` is one of ``\"P-256\"``/``\"P-384\"``/``\"P-521\"`` (``None`` " +"selects P-256). OpenSSL key objects are not safe for concurrent use, so " +"``public_pem``/``seal``/``open`` are serialised by an internal lock." +msgstr "" + +#: 07643e7c481f49cba8b4ab33bd4174e0 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.public_pem:1 of +msgid "Export our public key as a PEM SubjectPublicKeyInfo string." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:1 +#: ce09888aa11f4f01a8d4bdb80f94321f of +msgid "Encrypt ``plain`` to ``peer`` with an ECDH-derived AES-256-GCM key." +msgstr "" + +#: 965e41e97f5547c3a0bc77531ae3b3f9 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:3 of +msgid "" +"Returns the wire blob, exactly ``PF_ECDH_SEAL_OVERHEAD`` bytes longer " +"than ``plain``. Raises ``CryptoOperationError``." +msgstr "" + +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:1 of +msgid "Inverse of :meth:`seal`, using ``peer``'s public key." +msgstr "" + +#: 4212d23f4b14479b971145af1bc12fa5 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_AUTH_FAILED`` when" +" the tag does not verify (tampered ciphertext, wrong peer key or " +"mismatched AAD)." +msgstr "" + +#: 7fec5dc58def4bbc886ca30568df0661 PyFlow.network_api.rsa_crypto.hkdf_sha256:1 +#: of +msgid "HKDF-SHA256 (RFC 5869 extract-and-expand) over ``ikm``." +msgstr "" + +#: 462a97910aff4e9aae066e31f55d5233 PyFlow.network_api.rsa_crypto.hkdf_sha256:3 +#: of +msgid "" +"``salt`` and ``info`` may be empty. ``out_len`` must be in " +"``1.._HKDF_SHA256_MAX_OUT``. Raises ``CryptoOperationError``." +msgstr "" + +#: 670f4a719bf24c24b48ecb5d73b373ce +#: PyFlow.network_api.rsa_crypto.get_local_mac:1 of msgid "Return a stable 48-bit machine identifier as colon-separated hex." msgstr "" -#: 311d6e5bcdba40d1b05fd63528abcf74 -#: PyFlow.network_api.rsa_crypto.get_local_mac:3 of +#: PyFlow.network_api.rsa_crypto.get_local_mac:3 +#: f1306bb875d34b558f7418278fded413 of msgid "" "Uses ``uuid.getnode()`` (the real hardware MAC when one is available). " "Server and client on the same host share this value; the ``_`` " "prefix in the key file names keeps them apart." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto:1 b385913eca73436ab76b76787114e163 +#: 333763d798c54d52a9a56a3e4e3e2155 PyFlow.network_api.rsa_crypto.RsaCrypto:1 #: of msgid "Key lifecycle plus RSA-OAEP encrypt/decrypt for one role." msgstr "" -#: 7c2b4fafe779449a8245780da7a4ef91 PyFlow.network_api.rsa_crypto.RsaCrypto:3 +#: PyFlow.network_api.rsa_crypto.RsaCrypto:3 f52515121ac74575aaa36d45dd0341a2 #: of msgid "" "``role`` is ``\"server\"`` or ``\"client\"`` and is used to name the " @@ -119,13 +211,13 @@ msgid "" " in ``pub_key/pub_key.json`` (TOFU, see ``verify_peer_pub``)." msgstr "" -#: 1e24448b89684701a1fa13b02e9d0d84 +#: 56fed5bcfe194b7f90a0c662ae36d6c0 #: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:1 of msgid "Create the crypto wrapper for ``role`` (\"server\" or \"client\")." msgstr "" -#: 00101f4b9ef44a83b2e51f9974a3d92a -#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 +#: ca4e27664ccf40ce935d991db43f7c69 of msgid "" "``custom_keys`` may be a ``[pub_key_path, pvt_key_path]`` pair to use a " "user-supplied RSA keypair instead of the default lookup (``~/.ssh`` / " @@ -134,78 +226,78 @@ msgid "" "used instead." msgstr "" -#: 4e9b33835a9448bca28d9e2e3a782d77 +#: 7d89122ff0f54090b67209e3b08ae29c #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:1 of msgid "Load the RSA keypair (see module docstring) and cache handles." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:3 -#: e7fd217ab95d483084e4c7d58b715349 of +#: d5e494e00be44891b33cb8e0ecfb8081 of msgid "" "Runs under ``_key_lock``: the private-key handle must never be replaced " "(or freed on GC) while another thread is decrypting." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.reload_own_key:1 -#: c1e8b452b697431aaafee424e1edd3e2 of +#: f6f7d6ec8837464dad2dc647e6141a99 of msgid "Re-read the private key (e.g. after a ~/.ssh rotation)." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:1 -#: fabae86a23844d9cba130ff2f2adc080 of +#: e95d18da34d14376987a62f6cbbec778 of msgid "" "Path of the exchanged public key file for ``peer_role`` at ``(peer_ip, " "peer_port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 -#: fa9eee0dbc724d0bbfa8e36bcdd89ba4 of +#: 52dc6fb74f0c4175bfa2a2acc23cda0d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 of msgid "" "The IP is sanitized for the filesystem (``:`` -> ``_`` so IPv6 literals " "are safe on every platform, including Windows)." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 -#: ce570f7fdb834fc3982aa0ec0e98b896 of +#: 731d92a1b64342dfbf7c467af0a4c00e +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 of msgid "TOFU check-and-record for a peer public key." msgstr "" -#: 2879d5b42eed4eaca2af859a86db52e8 +#: 634283c14fb44424bf148a34d156fb71 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:3 of msgid "" "``peer_pem`` is the PEM text received on this connection, ``(peer_ip, " "peer_port)`` the endpoint it came from. Returns ``(ok, reason)``:" msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 -#: b6f7afce352240b8ba2cf6a4e38aa457 of +#: 6bb58c88f8454d7daca92b5a478ae788 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 of msgid "" "key already registered under any endpoint -> accept, and re-register it " "under the current endpoint when it moved (IPs are dynamic and ports are " "user-changeable);" msgstr "" -#: 014d219898a04debb9eace0ea28aaa83 +#: 74e2bcc89bae4fe5aecf99e6208e21d1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:10 of msgid "" "key unknown but the endpoint already holds a *different* key -> reject (a" " trusted endpoint suddenly presenting a new key);" msgstr "" -#: 5aabe21775144f3fb2e5b4ae5a190569 -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 +#: f856b875adc34f4a80c2b21cd506b143 of msgid "" "key and endpoint both unknown -> accept and record (first connection is " "trusted, TOFU)." msgstr "" -#: 2bcc3b43a6d54e91b48a51fdf715a346 +#: 556fdf46d6c543e0ab06e2d4fabad7f1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:1 of msgid "Move a freshly received public key file into the key cache." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:3 -#: a32f32a711ec453684a2fa927aaaa06e of +#: a47e84f5d21949bf98e24834f18bed76 of msgid "" "Idempotent under concurrency: several transfers may deliver the same peer" " key at once (multi-connection handshakes, several client processes " @@ -214,13 +306,13 @@ msgid "" "destination is in place." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 -#: c54c296562484982abff2e1436305b98 of +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 of msgid "Encrypt ``plaintext`` with the peer's public key file." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 -#: f7f5e3490fb44e85919611c0b3b9ecc7 of +#: 4b4dded0ad904ce2bb87c9a43c8f87e5 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 of msgid "" "Returns the ASCII wire body (no trailing newline): each chunk is RSA-OAEP" " encrypted and base64 encoded, chunks joined with ``|``. Raises if no " @@ -229,12 +321,12 @@ msgid "" "encrypt (no-GIL safe)." msgstr "" -#: 8860142532044e87aa78adc123c33d62 +#: 8f1687f4ab984c029859fd1f9cfb968c #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:1 of msgid "Decrypt a wire body with our private key." msgstr "" -#: 888f7928d8274beda354f5b657613fec +#: 8a1d1504bf4248fa9e1288776d19810b #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:3 of msgid "" "Returns ``(True, plaintext)`` on success, or ``(False, None)`` when the " diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po index 71fee8d..6afe8cb 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,30 +17,32 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_client.rst:2 -#: 8379b786205a4447995cf82b275ee87a +#: 09f60d1b11ac4e92b480fa6284489970 msgid "PyFlow.transfer\\_web.setup\\_client module" msgstr "" -#: 8412539bd9af49e8976ccf5c028061d4 PyFlow.transfer_web.setup_client:1 of +#: 2f786e174934474a93c6498878a68612 PyFlow.transfer_web.setup_client:1 of msgid "PyFlow TCP client web launcher." msgstr "" -#: PyFlow.transfer_web.setup_client:3 d2ed4df91a474301aee43eaf09e1ac87 of +#: 24fa9f33454d4afc9d15c80a0299922d PyFlow.transfer_web.setup_client:3 of msgid "" "Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI " "in the browser. The user enters the server address (an http/https domain" " or a bare IP); the backend asks the server's web backend for the TCP " "server address/port, starts the TCP client, and keeps the backend running" -" to relay the user's frontend actions. The account of the server logs in" -" from the same backend: saved credentials in " -"``.Flow_Web/client_login.json`` are replayed on every start, and the " -"login window appears whenever no session could be restored." +" to relay the user's frontend actions. A server that needs accounts (a " +"verification mailbox is configured) makes the same backend log in: saved " +"credentials in ``.Flow_Web/client_login.json`` are replayed on every " +"start, and the login window appears whenever no session could be " +"restored. A server without a mailbox needs no accounts, so the login " +"window and the account controls are skipped." msgstr "" -#: PyFlow.transfer_web.setup_client.main:1 fd5a9b075a2a4b9a97dbad26743e0403 of +#: PyFlow.transfer_web.setup_client.main:1 ca4ce7c686c84b44ae429e4de15b9afd of msgid "Start the client web backend and serve its UI." msgstr "" @@ -57,3 +59,21 @@ msgstr "" #~ " actions." #~ msgstr "" +#~ msgid "" +#~ "Starts a lightweight Flask backend on" +#~ " 127.0.0.1 and opens the connect UI" +#~ " in the browser. The user enters " +#~ "the server address (an http/https domain" +#~ " or a bare IP); the backend " +#~ "asks the server's web backend for " +#~ "the TCP server address/port, starts the" +#~ " TCP client, and keeps the backend" +#~ " running to relay the user's frontend" +#~ " actions. The account of the server" +#~ " logs in from the same backend: " +#~ "saved credentials in ``.Flow_Web/client_login.json``" +#~ " are replayed on every start, and " +#~ "the login window appears whenever no " +#~ "session could be restored." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po index e9744f6..3b62154 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,43 +17,45 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_server.rst:2 -#: 88492dfde47b4dbb914aaba07f359440 +#: e6642bb55a204188b0abd0b07207713e msgid "PyFlow.transfer\\_web.setup\\_server module" msgstr "" -#: 103789700f8d41aa80e1cb374abb02a3 PyFlow.transfer_web.setup_server:1 of +#: 5966876a4564470ea674311ddb3ef63e PyFlow.transfer_web.setup_server:1 of msgid "PyFlow TCP server web launcher." msgstr "" -#: 581fc0a8029c44f7998895401060a79b PyFlow.transfer_web.setup_server:3 of +#: 588fea0dc68a4a308f9a7cfb6fe5d819 PyFlow.transfer_web.setup_server:3 of msgid "Checks ``transfer_web/.Flow_Web/setup_server.json``:" msgstr "" -#: 60412e56b0d44018bbc88cd258e2c48b PyFlow.transfer_web.setup_server:5 of +#: PyFlow.transfer_web.setup_server:5 c3df4df524da40b18a58607efd9b5e4a of msgid "" "missing -> opens the server startup-configuration UI in the browser; the" " UI saves the config (same shape as ``flow_setup``'s ``setup.json``) and " "starts the TCP server class;" msgstr "" -#: 15dae71f4c1243ecb188218cd72eb7c2 PyFlow.transfer_web.setup_server:8 of +#: 211850fce6d34d50ae152bce6d1aa3af PyFlow.transfer_web.setup_server:8 of msgid "present -> starts the TCP server class directly from the saved config." msgstr "" -#: 921ebc855440467cacd9d366085db41a PyFlow.transfer_web.setup_server:10 of +#: 7170b50dcaf2462f918af2271f247c84 PyFlow.transfer_web.setup_server:10 of msgid "" "After the TCP server is up, the lightweight Flask backend serves the " "status page and the client-facing API (``/api/server_info`` etc.) on the " -"server's address. Anonymous visitors also get the landing page with the " -"registration and password-reset flows; accounts live in the SQLite store " -"``.Flow_Web/flow_web.db``, and the verification mails are sent through " -"the mailbox configured in ``.Flow_Web/email_config.json``." +"server's address. Anonymous visitors also get the landing page; its " +"registration and password-reset flows exist while a verification mailbox " +"is configured (settings in ``.Flow_Web/email_config.json``, accounts in " +"the SQLite store ``.Flow_Web/flow_web.db``). That mailbox is also the " +"switch of the client side: with it clients log in with an account, " +"without it they connect without any account at all." msgstr "" -#: 2f09f9248b0e47e3ba9c9792d83a622b PyFlow.transfer_web.setup_server.main:1 of +#: PyFlow.transfer_web.setup_server.main:1 cbf05c29afe74ebd84b898146c971457 of msgid "Start the server web backend and serve its UI." msgstr "" @@ -65,3 +67,17 @@ msgstr "" #~ "server's address." #~ msgstr "" +#~ msgid "" +#~ "After the TCP server is up, the" +#~ " lightweight Flask backend serves the " +#~ "status page and the client-facing " +#~ "API (``/api/server_info`` etc.) on the " +#~ "server's address. Anonymous visitors also " +#~ "get the landing page with the " +#~ "registration and password-reset flows; " +#~ "accounts live in the SQLite store " +#~ "``.Flow_Web/flow_web.db``, and the verification " +#~ "mails are sent through the mailbox " +#~ "configured in ``.Flow_Web/email_config.json``." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po index ff5009c..9f65a88 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po @@ -8,47 +8,49 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst:2 -#: 86d4061dc1f542ac95555aa2deab1101 +#: ffcd351a76b74899a0105947d1049e12 msgid "PyFlow.transfer\\_web.web\\_backend.mail\\_service module" msgstr "" -#: 99f2cb604d5c450c9cda427b22b2c8cb -#: PyFlow.transfer_web.web_backend.mail_service:1 of +#: PyFlow.transfer_web.web_backend.mail_service:1 +#: c6f6b5571d954e7b986a3355033cd30c of msgid "SMTP delivery of account verification codes for the web tool." msgstr "" -#: 1d2a4d079f6c44f182332c5b44d0705a +#: 9764afd408ca43ce829f03d7d4ca675b #: PyFlow.transfer_web.web_backend.mail_service:3 of msgid "" "The administrator configures the outgoing mailbox from the server's " "startup-configuration page. The settings are validated with a real SMTP " "login and only then written to ``.Flow_Web/email_config.json``; while no " "validated configuration is present the service refuses to send, so a " -"server can never silently drop verification codes." +"server can never silently drop verification codes. The same page takes " +"the mailbox away again (`disable`), which switches the server back to " +"internal use." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 -#: e0597ff2442b43dd87c4efaef6c574c5 of +#: 5fdca457edd340eab7c9f05558a37dc5 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 of msgid "Validate untrusted SMTP settings and return them in canonical form." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 069dae5e8fb0426e897adc279499319b 4c58519a459f4b9486f0a571939d4834 -#: 83045ebe35d54d76b13e40961c070d4f eb5501cac4f240b19f2d4f5e5443e3c6 +#: 1cad23766791477aa6fb46051363ef81 73b1f3a5025140ec8701e976293f7af0 +#: 817b9cde77bb4327ad3b9f8356d27f4c a9b0b41ab3fd438c8cb2551b61e1af31 msgid "Parameters" msgstr "" -#: 14138866fd924a0083c8e6562b3860ff +#: 1b2b400edc914a76977297cb9ef6da5d #: PyFlow.transfer_web.web_backend.mail_service.normalize_config:3 of msgid "" "Settings with ``host``, ``port``, ``username``, ``password``, ``from`` " @@ -57,152 +59,183 @@ msgid "" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 170588e452e5431e815fad88a5b5537b 887b6607974c4ea8b99b628ea3efbf45 -#: a16996418f0e4e5ab58b7244ded5e63b c0463031a23c4f799b6a8217f31cc1b1 +#: 097b6a08fc5548d1a5a4568b07bf4326 1388175dc5e64a8eb1a99affd4807d9f +#: 334d15f3b1264e0b8abfc34e8fee985e 8f894b6967fd4867b82c726e85c83dc9 msgid "Returns" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 -#: dafcbdb3cccc40fa89a38363dd5680b0 of +#: 4695369c64494340bb98d06f4029f854 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 of msgid "" "The same settings with a string host, an integer port, a lowercase " "encryption mode and an explicit sender." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 -#: a68a2cdaeea44ccdb70c8e49efbcb5dd of +#: 5c191d5d632a4a71a814aa300592c904 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 of msgid "The same settings with a string host, an integer port, a lowercase" msgstr "" -#: 2bd9bb82ad2749df9c60df8271733a8c -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 of +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 +#: f98ed07dd1474127973e40ea5d133476 of msgid "encryption mode and an explicit sender." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 24fb33faf10542c7a1d5bcd8bc20e135 53904db2f0da42c6ac410c40a9e555a0 -#: 59876b786ae244308cb80d0e15975404 a636a96a44754c789c671d6e95914aea +#: 2ceb9aabd15149e2a74ab44ffc0e7e3b 4f9ea7be9a9d4179b3371b7ffaaf9c64 +#: 75ab32112eb54385b832e99cc66c0f3b 951ba3e6400f48c2baaffe4aceb25ae3 msgid "Return type" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 4375f894dabe4fd49e5d470f602e7e4e 669fcb172313407fa0df09ca10280e22 -#: 9ce7848878e44efba62bd42bd640bdeb +#: 051ee4ae623e4c52aca28e50c43a8659 6c5929a2e83444a0b5026560f2c5af02 +#: 7d5aee61dcaa450790fdaa12bda90f1c b717337ce24a4644a8684f6c14ced1d5 msgid "Raises" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 -#: f6db2cc04ccd4bc0a06c34c8d5d00b29 of +#: 8e1b87a14fc44d6383f43b22bdb71770 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 of msgid "If a setting is missing, malformed or out of range." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 -#: a46df3ad1b4d47838e7d86646e5e45d4 of +#: 9104ff2767b4468db4119f0de6103975 +#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 of msgid "SMTP client delivering verification codes." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService:3 -#: a6a714e990194ee9b2c023afa0423ec6 of +#: b29996ad41f1488f8540e22a48f131fa of msgid "" "The stored configuration is read on construction, so a validated mailbox " "is available again after a restart." msgstr "" -#: 906ef645c3f0431c8d4f44bb661e3119 +#: 67ba292bfc8c40ee863f2bf892ff74cb #: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:1 of msgid "Create the service and load the stored configuration." msgstr "" -#: 886b800f093c4d758d14028b4233d623 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 +#: f7b0ac874bc34b408853f868c5c1a9cd of msgid "" "JSON file holding the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 10490a10be734ca58da591842794088d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 +#: cdbf836d9e9c4e2a948458972edbfbae of msgid "Report whether a validated configuration lets codes be sent." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 -#: a19f7729857a4995be526dded313b07d of +#: 6f529ae442fb4a4ba2e0fd72533d0e29 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 of msgid "True when the SMTP settings were validated and stored." msgstr "" -#: 646e8fd83be4421ab0d3b4d38fe2b1c8 +#: 93c564a9ccd64ebca089cbd00f434f9e #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:1 of msgid "Return the validated SMTP settings." msgstr "" -#: 1728b9dc41484d35851721b141e661be +#: 83356ba5ccea4bceae862cc0934959cf #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:3 of msgid "" "Copy of the stored settings, or ``None`` while the service is not " "configured." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 -#: cb61516a7cac473fa2ab322e29340899 of +#: 77ff24f402974e8681e2273634e17e4c +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 of msgid "Copy of the stored settings, or ``None`` while the" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 -#: ba7116251d3b4ce7b97a3e79808c4415 of +#: 383ba8fc4ed940f38097d10bfbc8ff84 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 of msgid "service is not configured." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:1 -#: a2161943624d40a39a45564117df6d9e of +#: c7110be43ff548edb573b0b645e49ef5 of msgid "Validate SMTP settings, store them and start the sending service." msgstr "" -#: 8d8686cd5b9b46d295719719f9b29929 +#: 99385960778b4785bb73f4db98d2dada #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:3 of msgid "Settings accepted by `normalize_config`." msgstr "" -#: 5aa35eba13e04367b7f99d754176a39d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 +#: d801399842874f19943e8d2eb6dd6e6d of msgid "The validated settings as stored." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:9 -#: ab75660bdd60437dbb05953445043ce0 of +#: c4c8574eb0634811a9fd71b2e00233a9 of msgid "" "If a setting is missing or malformed, or the server refuses the " "connection or the login." msgstr "" -#: 4ebf6576a62643d9910acdfba3fcd799 +#: 5c332d9d6242449f97b7bddbe36a20cd +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:1 of +msgid "Remove the stored mailbox so no verification code can be sent." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:3 +#: bc6f8bbf1f0047cebea68882e633945d of +msgid "" +"This is the switch back to internal mode: with no mailbox the server " +"serves its clients without accounts again." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:6 +#: f669f3bdc1f44730a90a6127ff7db331 of +msgid "" +"If the stored file cannot be removed; the service then keeps its " +"settings and stays enabled." +msgstr "" + +#: 7b942af00fc54d9d836170d61972977e #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:1 of msgid "Send one verification code by email." msgstr "" -#: 8f04bd37dc8b4483af595c5e66f8fbf4 +#: 6cdc276558b54671b93a8a839f34a682 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:3 of msgid "Recipient address." msgstr "" -#: 57f0544cdf234e00b9f03da47566354f +#: 60f83153ebac42eeb7ba36ed193d0eb1 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:5 of msgid "Verification code to deliver." msgstr "" -#: 627ee080c93e46679b0eb1dea17640f6 +#: 25f348d2347c4274a624e6d13eb6dfd3 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:7 of msgid "" "\"register\", \"login\" or \"reset_password\"; decides the wording of the" " message." msgstr "" -#: 6733b65d0a2347e1918c983503394f49 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 +#: f16d610fc9f14559af45cddea444add9 of msgid "Code lifetime in seconds, stated in the message." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 -#: ce7cf70f7a2d4deca8256ada1fc9b63d of +#: 134b78c9128942938629dd61e9048916 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 of msgid "If the service is not configured, or the message cannot be delivered." msgstr "" +#~ msgid "" +#~ "The administrator configures the outgoing " +#~ "mailbox from the server's startup-" +#~ "configuration page. The settings are " +#~ "validated with a real SMTP login " +#~ "and only then written to " +#~ "``.Flow_Web/email_config.json``; while no validated" +#~ " configuration is present the service " +#~ "refuses to send, so a server can" +#~ " never silently drop verification codes." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po index dafef32..82708f2 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,24 +17,24 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst:2 -#: 7bc35f7e619347e0b976ca49c973de8f +#: 4e16e69f9ae9491a95bfcab9c70cfe24 msgid "PyFlow.transfer\\_web.web\\_backend.server\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:1 -#: fd1d19a74e7a4e14a3863a4f2d4e6eef of +#: 15eb6d4006b3429a8fa230a2b460b1c5 +#: PyFlow.transfer_web.web_backend.server_backend:1 of msgid "Flask backend wrapping the PyFlow TCP server for the web tool." msgstr "" -#: 6fa9dfd64064447c82ade7290b523d5c +#: 3c413c9e37f94c7485dba6d4f96b9bf2 #: PyFlow.transfer_web.web_backend.server_backend:3 of msgid "Two modes, one process:" msgstr "" -#: 8e61412bb72d49b086f03a2245cd959d +#: 557b793ac8e441db86cf59cad5e85371 #: PyFlow.transfer_web.web_backend.server_backend:5 of msgid "" "``config`` mode: serves the server startup-configuration UI. The UI " @@ -45,7 +45,7 @@ msgid "" msgstr "" #: PyFlow.transfer_web.web_backend.server_backend:10 -#: b15a182866794bf7bfe71605fc47a301 of +#: cb922669795b42c6ad5587b527c4356a of msgid "" "``status`` mode: serves the minimal status page plus the same " "sidebar/input UI as the client frontend (forwarding disabled; native " @@ -53,93 +53,105 @@ msgid "" "clients use to discover the TCP server address/port." msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:15 -#: a297544539714d03afa00d1112541712 of +#: 0c6784517a194d65926c71b7ce7f4836 +#: PyFlow.transfer_web.web_backend.server_backend:15 of msgid "" "The backend monitors ``server.clients``: whenever a client connects or " "disconnects it broadcasts the current instance list to every connected " "client (``/web_clients_update``), and it re-checks the list every minute." msgstr "" -#: 9ad7bd78687141a8a282a951ddc57689 +#: 535e49236690482ebf574e6c65b10f39 #: PyFlow.transfer_web.web_backend.server_backend:20 of msgid "" "Inbound events (plain-text messages and file uploads arriving from " "clients) are captured on the TCP server's receive threads through " "``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` " -"APIs, queued here, and polled by the frontend via ``/api/events``." +"APIs, queued here, and polled by the frontend via ``/api/events``. The " +"message listener reports every inbound line, protocol commands included; " +"the commands are dropped here, so the queue carries user messages only. A" +" file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 69da06074d1141308bd12409e851f506 -#: PyFlow.transfer_web.web_backend.server_backend:25 of +#: 6ee75a9919554a3cb05d55c0f9dba653 +#: PyFlow.transfer_web.web_backend.server_backend:30 of msgid "" "Authentication: anonymous visitors get a white landing page (the server " -"addresses, a login button, a registration button and a password-reset " -"button); the configuration and status pages need a session. Accounts " -"live in the SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`);" -" the first run seeds the ``admin``/``admin`` administrator and the " -"frontend warns on every login until those default credentials are " -"changed. Registration, password reset and code-based client logins are " -"delivered by the mailbox configured from the startup-configuration page " -"(see `mail_service`)." -msgstr "" - -#: 1fb7feafe6ba447e992cd3ebd42801c8 -#: PyFlow.transfer_web.web_backend.server_backend:34 of +"addresses and a login button; while a verification mailbox is configured," +" also a registration button and a password-reset button); the " +"configuration and status pages need a session. Accounts live in the " +"SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the first " +"run seeds the ``admin``/``admin`` administrator and the frontend warns on" +" every login until those default credentials are changed. Registration, " +"password reset and code-based client logins are delivered by the mailbox " +"configured from the startup-configuration page (see `mail_service`)." +msgstr "" + +#: 14b91efc5192438eb9eb025aa4a50ef2 +#: PyFlow.transfer_web.web_backend.server_backend:40 of msgid "" -"Client accounts: the client web frontend logs in through " -"``/api/client_login`` with a username/email, the account password *and* a" -" mailed verification code — both factors are required — and receives a " -"session token. Re-entering the client web UI replays the saved " -"credentials and token through ``/api/client_verify``, which only accepts " -"them while they still open that account. The token binds the TCP " -"connection the client opens (``/web_bind``) to that account, and the " +"Client accounts: the verification mailbox is the switch of the whole " +"client side. While ``.Flow_Web/email_config.json`` holds a validated " +"mailbox the server is meant for public networks: the client web frontend " +"logs in through ``/api/client_login`` with a username/email, the account " +"password *and* a mailed verification code — both factors are required — " +"and receives a session token. Re-entering the client web UI replays the " +"saved credentials and token through ``/api/client_verify``, which only " +"accepts them while they still open that account. The token binds the TCP" +" connection the client opens (``/web_bind``) to that account, and the " "instance list pushed to a client is limited to its contacts, so accounts " -"that never exchanged a contact request cannot see each other." +"that never exchanged a contact request cannot see each other. Without a " +"mailbox the server is an internal tool: clients connect without " +"registration or login, every client sees every other connected instance, " +"and the client account routes are closed — only the console administrator" +" keeps an account." msgstr "" -#: 123122acd40847679e349c6e3b8d9c5e -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 of +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 +#: ab4c37912c524489a26700248a06704c of msgid "Flask app + TCP_Server_Base wrapper for the web tool." msgstr "" #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:1 -#: b7ccb1c765d744b988819d0afbbab22d of +#: fb6d7d555b47497fa6861b7f8a6a5f5d of msgid "Create the Flask app and its stores." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst -#: b841315945d14f34a8ef0541284d23e3 +#: 0fb91f29d163495c8c5e4b758c29cf92 msgid "Parameters" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 -#: c8c0a79297824242960049876ebd3e56 of +#: 79acd75ba91d4388972788215a4dcde7 +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 of msgid "" "Port of this web backend; defaults to ``DEFAULT_WEB_PORT``. A busy port " "falls back to the next free one." msgstr "" -#: 652d75ee0a3d4dd18396a8e2b5aa315e +#: 7dd94be740ee476ea378e766ecf5640b #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:6 of msgid "SQLite account database; defaults to ``.Flow_Web/flow_web.db``." msgstr "" -#: 34f17ede4f7c4556a62f8cc47f3c399d +#: 1db79ba202e74aeebefe1de0df4f3f3f #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:9 of msgid "" "JSON file with the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 011de011008f44dc9c247510315a2341 +#: 7e707a76895243cbb7e49d4a943df5f2 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:1 #: of msgid "Read ``.Flow_Web/setup_server.json`` and start the TCP server." msgstr "" +#: 7a3de044fc304747a1be4161fe0f2e51 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:3 -#: baae3df9217643d0a41c83324c8f035d of +#: of msgid "" "The saved \"ftp\" share is restored as well, so a folder shared before " "the restart keeps being served." @@ -180,3 +192,52 @@ msgstr "" #~ msgid "Rename ``username`` and set its password (self-service)." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " file uploads arriving from clients) " +#~ "are captured on the TCP server's " +#~ "receive threads through ``TCP_Server_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Authentication: anonymous visitors get a " +#~ "white landing page (the server " +#~ "addresses, a login button, a " +#~ "registration button and a password-reset" +#~ " button); the configuration and status " +#~ "pages need a session. Accounts live " +#~ "in the SQLite store ``.Flow_Web/flow_web.db``" +#~ " (see `user_database`); the first run " +#~ "seeds the ``admin``/``admin`` administrator " +#~ "and the frontend warns on every " +#~ "login until those default credentials " +#~ "are changed. Registration, password reset " +#~ "and code-based client logins are " +#~ "delivered by the mailbox configured from" +#~ " the startup-configuration page (see " +#~ "`mail_service`)." +#~ msgstr "" + +#~ msgid "" +#~ "Client accounts: the client web frontend" +#~ " logs in through ``/api/client_login`` with" +#~ " a username/email, the account password " +#~ "*and* a mailed verification code — " +#~ "both factors are required — and " +#~ "receives a session token. Re-entering" +#~ " the client web UI replays the " +#~ "saved credentials and token through " +#~ "``/api/client_verify``, which only accepts " +#~ "them while they still open that " +#~ "account. The token binds the TCP " +#~ "connection the client opens (``/web_bind``)" +#~ " to that account, and the instance" +#~ " list pushed to a client is " +#~ "limited to its contacts, so accounts " +#~ "that never exchanged a contact request" +#~ " cannot see each other." +#~ msgstr "" + diff --git a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po index d4c0134..b32fb68 100644 --- a/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po +++ b/docs/source/locale/zh_CN/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_CN\n" @@ -17,19 +17,19 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_front.client_backend.rst:2 -#: 411a61682c95447192de34eca6a7b40c +#: a7e084a5059341aa9b7419059c4fa4b0 msgid "PyFlow.transfer\\_web.web\\_front.client\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:1 -#: c5b03318abd74b32b6ffba1696f8b20b of +#: 22485674cb53445a86703fb118698523 +#: PyFlow.transfer_web.web_front.client_backend:1 of msgid "Flask backend wrapping the PyFlow TCP client for the web tool." msgstr "" -#: 13a2da9087074258858c4dd7a697671e +#: 31862d77d7184e55a1e729d7e72baed0 #: PyFlow.transfer_web.web_front.client_backend:3 of msgid "" "The launcher (``setup_client.py``) starts this backend and opens the " @@ -40,70 +40,123 @@ msgid "" "relay the user's frontend actions:" msgstr "" -#: 95d3503d45ac47ba8c8a9522aceb4764 +#: 1a028258cda844ee945b9522d51afb9d #: PyFlow.transfer_web.web_front.client_backend:10 of msgid "messages/files/folders to the server use the native transfer methods;" msgstr "" #: PyFlow.transfer_web.web_front.client_backend:11 -#: be1496ab996044798cfc05692616cd8a of +#: e160c2a0daf9498cbe2041a8e964ff47 of msgid "" "messages to other clients use the native ``/forward_send_msg`` forwarding" " (a client-only command relayed by the server);" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:13 -#: a59ab775ca734b828f09313089028a9f of +#: 16da18234f0a499893b711e7b555b42a +#: PyFlow.transfer_web.web_front.client_backend:13 of msgid "" "files/folders to other clients are forwarded through the built-in " "``forward_extension_tcp`` extension." msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:16 -#: ea807a0c324b430c8731aa632d099643 of +#: 79dee862a03f4d0c9bc9403f8d461465 +#: PyFlow.transfer_web.web_front.client_backend:16 of msgid "" "The sidebar instance list is kept fresh by the server's " "``/web_clients_update`` broadcasts; a reload button re-requests the list " "via ``/web_sync_clients``." msgstr "" -#: 3656f3e4bded46b596db7d1bdc666b90 +#: 13d20ecd894c4e26a28266b7ac128dfd #: PyFlow.transfer_web.web_front.client_backend:20 of msgid "" "Inbound events (plain-text messages and files pushed by the server, " "whether direct sends or client forwards) are captured on the TCP client's" " receive threads through ``TCP_Client_Base``'s " "``add_message_listener``/``add_file_listener`` APIs, queued here, and " -"polled by the frontend via ``/api/events``." +"polled by the frontend via ``/api/events``. The message listener reports" +" every inbound line, protocol commands included; a direct command from " +"the server is dropped here, so the queue carries user messages only. A " +"file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 565c32267ec64ccbb0904ef2ec5609df -#: PyFlow.transfer_web.web_front.client_backend:26 of +#: 5c1c2971ea0e45d8a56544972cdc4ff4 +#: PyFlow.transfer_web.web_front.client_backend:31 of msgid "" -"Accounts: a connected client logs in with a server account before the " -"instance list is usable. A forced login needs both factors — the account" -" password and a verification code mailed to the account address — while a" -" client that starts again replays the saved credentials and session token" -" through ``/api/client_verify``. ``/api/login`` opens the session, the " +"Accounts: the connected server decides whether its clients need accounts." +" A server with a verification mailbox is public, so this backend forces " +"the account login before the instance list is usable; a server without " +"one is internal and everything account-related is skipped — no login " +"window, no contacts, and every client sees every other instance. A " +"forced login needs both factors — the account password and a verification" +" code mailed to the account address — while a client that starts again " +"replays the saved credentials and session token through " +"``/api/client_verify``. ``/api/login`` opens the session, the " "``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the " "contact management to the server, and the session token is sent over TCP " "with ``/web_bind`` so the server can push the contact list of that " "account. The credentials are remembered in " -"``.Flow_Web/client_login.json`` (owner-readable only) and the login " -"window is shown whenever no session could be restored." +"``.Flow_Web/client_login.json`` (owner-readable only)." msgstr "" -#: 1e6c10d599f046398e16a7b47e0b8dab +#: 0913e15917534119b775fb5c545c439d #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp:1 of msgid "Flask app + TCP_Client_Base wrapper for the web tool." msgstr "" -#: 6c87b744956640d682bef32158496990 #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:1 +#: bc85ca281f4e4df5a0f10290029fca34 of +msgid "Start the TCP client from ``.Flow_Web/setup_client.json``." +msgstr "" + +#: 612871943a7e45a2bacdc377aec78b77 +#: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:3 #: of -msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +msgid "" +"The connected server reports whether its clients log in; only then is a " +"saved session replayed, and the login window is only shown then." msgstr "" #~ msgid "Read ``.Flow_Web/setup_client.json`` and start the TCP client." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " files pushed by the server, whether" +#~ " direct sends or client forwards) are" +#~ " captured on the TCP client's receive" +#~ " threads through ``TCP_Client_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Accounts: a connected client logs in " +#~ "with a server account before the " +#~ "instance list is usable. A forced " +#~ "login needs both factors — the " +#~ "account password and a verification code" +#~ " mailed to the account address — " +#~ "while a client that starts again " +#~ "replays the saved credentials and " +#~ "session token through ``/api/client_verify``. " +#~ "``/api/login`` opens the session, the " +#~ "``/api/contacts/*`` and ``/api/contact_requests`` " +#~ "routes proxy the contact management to" +#~ " the server, and the session token" +#~ " is sent over TCP with ``/web_bind``" +#~ " so the server can push the " +#~ "contact list of that account. The " +#~ "credentials are remembered in " +#~ "``.Flow_Web/client_login.json`` (owner-readable " +#~ "only) and the login window is " +#~ "shown whenever no session could be " +#~ "restored." +#~ msgstr "" + +#~ msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/Crypto/Crypto.po b/docs/source/locale/zh_TW/LC_MESSAGES/Crypto/Crypto.po index 1f95239..e0c6e70 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/Crypto/Crypto.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/Crypto/Crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,11 +17,11 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../source/Crypto/Crypto.rst:2 bb50e4f310ea43d9ba55e4b367ed7740 +#: ../../source/Crypto/Crypto.rst:2 9878b2fb3d9d4d6ba3cd00002ed6f0b7 msgid "C/OpenSSL Crypto Module" msgstr "C/OpenSSL 加密模組" -#: ../../source/Crypto/Crypto.rst:4 2838c629d37d42ef92dbabeab8d33801 +#: ../../source/Crypto/Crypto.rst:4 aa824d3e127240b0928431af3dd8c831 #, fuzzy msgid "" "The ``PyFlow/crypto_api`` directory contains PyFlow's C/OpenSSL " @@ -31,62 +31,62 @@ msgstr "" "``src/crypto_api`` 目錄包含 ServSpy 的 C/OpenSSL 加密函式庫。該庫獨立於 Python 運行時,並使用 " "CMake 從儲存庫根建置。" -#: ../../source/Crypto/Crypto.rst:8 2c028ead37a24eb98321135f22f3673d +#: ../../source/Crypto/Crypto.rst:8 294667df2a20495887126b808c7d9706 msgid "The module provides:" msgstr "此模組提供:" -#: ../../source/Crypto/Crypto.rst:10 e290cfffb80140899093170eda086e61 +#: ../../source/Crypto/Crypto.rst:10 472d4f3082db42f198b7f13fdbf041f2 msgid "RSA-OAEP encryption and decryption with SHA-256." msgstr "使用 SHA-256 進行 RSA-OAEP 加密和解密。" -#: ../../source/Crypto/Crypto.rst:11 125f1968eba34f6896b44b6406f0e6c2 +#: ../../source/Crypto/Crypto.rst:11 0eb3f7206503452ca2229a1d7c323390 msgid "ECDH key agreement on P-256, P-384, and P-521." msgstr "P-256、P-384 和 P-521 上的 ECDH 金鑰協定。" -#: ../../source/Crypto/Crypto.rst:12 cee735932767478e95a96b9a59ddcdd2 +#: ../../source/Crypto/Crypto.rst:12 ab0be16cfbca493a88c6eb4a2ef1bb07 msgid "HKDF-SHA256 session-key derivation." msgstr "HKDF-SHA256 會話金鑰派生。" -#: ../../source/Crypto/Crypto.rst:13 7d211e9cf2e64cab9b79c0173805334e +#: ../../source/Crypto/Crypto.rst:13 56667bb7a4554c1b8efc918c9593f950 msgid "AES-256-GCM authenticated encryption for ECDH sessions." msgstr "ECDH 會話的 AES-256-GCM 驗證加密。" -#: ../../source/Crypto/Crypto.rst:14 d345fd729851496c82017971bdb55276 +#: ../../source/Crypto/Crypto.rst:14 8de85fb1a2f843ea91d0aa30df0a00c7 msgid "PEM key persistence and structured error reporting." msgstr "PEM 金鑰持久性和結構化錯誤報告。" -#: ../../source/Crypto/Crypto.rst:16 d86187e532624ac49492cca1b064a89b +#: ../../source/Crypto/Crypto.rst:16 564b1d414738498791d9083f279330fe msgid "" "The library version is 1.0.0 (``PF_CRYPTO_VERSION_MAJOR`` / " "``PF_CRYPTO_VERSION_MINOR`` / ``PF_CRYPTO_VERSION_PATCH`` and " "``PF_CRYPTO_VERSION_STRING`` in ``pf_crypto.h``)." msgstr "" -#: ../../source/Crypto/Crypto.rst:20 5e6c65799ec14fd8b67034bd1b3beb07 +#: ../../source/Crypto/Crypto.rst:20 10fda1fcea98430a8924fdfa8bbce2fa #, fuzzy msgid "The public headers are located in ``PyFlow/crypto_api/include``:" msgstr "公共標頭位於“src/crypto_api/include”中:" -#: ../../source/Crypto/Crypto.rst:22 87305d509fc94f5186438e34d9583987 +#: ../../source/Crypto/Crypto.rst:22 86168d67fc8047ba8d4c61b2b9e23caf #, fuzzy msgid "``pf_crypto.h`` - common errors, OpenSSL diagnostics, and HKDF." msgstr "``ss_crypto.h`` - 常見錯誤、OpenSSL 診斷和 HKDF。" -#: ../../source/Crypto/Crypto.rst:23 5d221a05e5034eccadaec2206256a2af +#: ../../source/Crypto/Crypto.rst:23 ddfd841fba4b4045bb3fc84419010fe7 #, fuzzy msgid "``pf_rsa.h`` - RSA key and encryption APIs." msgstr "``ss_rsa.h`` - RSA 金鑰和加密 API。" -#: ../../source/Crypto/Crypto.rst:24 e10e899ebf934a18a686d225d3f967d9 +#: ../../source/Crypto/Crypto.rst:24 eb2168817ac54389a35e194a444250f4 #, fuzzy msgid "``pf_ecdh.h`` - ECDH key agreement and seal/open APIs." msgstr "``ss_ecdh.h`` - ECDH 金鑰協定和密封/開放 API。" -#: ../../source/Crypto/Crypto.rst:27 09186509365444d4ac1ce145d76bcd28 +#: ../../source/Crypto/Crypto.rst:27 43fa12b668bb4dc389f2bbd9edaf9187 msgid "Build" msgstr "建造" -#: ../../source/Crypto/Crypto.rst:29 ae41004303f342d2ac3e302fe5ff9b40 +#: ../../source/Crypto/Crypto.rst:29 35019410fade4c18b07d32d37c05ba0d msgid "" "The module requires OpenSSL 1.1.1 or newer and CMake 3.16 or newer. On " "Debian or Ubuntu, install the build dependencies with:" @@ -94,7 +94,7 @@ msgstr "" "此模組需要 OpenSSL 1.1.1 或更高版本以及 CMake 3.16 或更高版本。在 Debian 或 Ubuntu " "上,使用以下命令安裝建置依賴項:" -#: ../../source/Crypto/Crypto.rst:37 7c534481ca81453b89692a8758bbeba0 +#: ../../source/Crypto/Crypto.rst:37 3834ad9e83c24331b03d264103f5cdad msgid "" "Installing the Python package builds it automatically: ``setup.py`` " "compiles the three sources and installs the result inside the package " @@ -102,19 +102,19 @@ msgid "" "pyflow-net`` needs only a C compiler and the OpenSSL development headers." msgstr "" -#: ../../source/Crypto/Crypto.rst:42 6abf3a2d83804b73b1bfd45add4322d8 +#: ../../source/Crypto/Crypto.rst:42 a72fb95d5d114cdca29347b18e2c1253 msgid "" "Build it from the repository root with CMake when the C test suite or the" " C API itself is wanted:" msgstr "" -#: ../../source/Crypto/Crypto.rst:51 6fbb49d9124649f1b387de2f0377a4af +#: ../../source/Crypto/Crypto.rst:51 96617bb44be2438ebbde9e9f750b3e09 msgid "" "``ctest --test-dir`` was added in CMake 3.20; with the 3.16 minimum the " "equivalent is ``ctest --output-on-failure`` run from inside ``build/``." msgstr "" -#: ../../source/Crypto/Crypto.rst:54 f42772e265ad4248b11c37141f4fb6e8 +#: ../../source/Crypto/Crypto.rst:54 244b7aff35aa4272a121b9fbbadae117 #, fuzzy msgid "" "The C test suite lives in ``test/crypto_api/`` (``test_hkdf``, " @@ -125,27 +125,26 @@ msgstr "" "C " "測試套件位於“test/crypto_api/”(“test_hkdf”、“test_rsa”、“test_ecdh”)中,並與程式庫一起建置和運行。" -#: ../../source/Crypto/Crypto.rst:59 ed6b92c776ca441ab8629088ecd973bc +#: ../../source/Crypto/Crypto.rst:59 30ea804b8270411f8793908bdc7a2a97 #, fuzzy msgid "" "The library is built as a shared object (``libcrypto_api.so``) so it can " "be loaded from Python: ``PyFlow/network_api/rsa_crypto.py`` is a ctypes " -"binding used by the TCP layer to encrypt messages with RSA-OAEP (see the " -"``TCP_Server_APIs`` / ``TCP_Client_APIs`` encrypted channel sections). " -"The binding also implements the TCP layer's anti-MITM identity check " -"(TOFU): peer public keys are exchanged on every connection, recorded " -"under the peer's ``(ip, port)`` in " -"``network_api/.Flow/pub_key/pub_key.json`` with the SHA-256 of the " -"received PEM text, and a changed key for a recorded endpoint rejects the " -"connection; a key already known under another endpoint is accepted and " -"re-registered under the new one. The encryption state machine is bounded:" -" three consecutive decode failures trip a circuit breaker " -"(``MAX_DECODE_FAILURES`` in ``connect_tcp.py``) that stops re-keying, and" -" a key that is stale or rotated makes the TCP layer reload its own key " -"and re-exchange. The binding looks for the library via " -"``ctypes.util.find_library`` and then next to the repository root in " -"``build/`` (``libcrypto_api.so``, ``libcrypto_api.dylib``, " -"``libcrypto_api.dll`` and ``build/Release/crypto_api.dll``)." +"binding used by the TCP layer. It exposes the RSA-OAEP message encryption" +" and the ECDH/AES-256-GCM sealing (``EcdhKeyPair`` / ``EcdhPubKey`` / " +"``hkdf_sha256``) that the framed TCP channel uses for its bulk and file " +"transfer payloads (see the ``TCP_Server_APIs`` / ``TCP_Client_APIs`` " +"encrypted channel sections). The binding also implements the TCP layer's " +"anti-MITM identity check (TOFU): endpoint rejects the connection; a key " +"already known under another endpoint is accepted and re-registered under " +"the new one. The encryption state machine is bounded: three consecutive " +"decode failures trip a circuit breaker (``MAX_DECODE_FAILURES`` in " +"``connect_tcp.py``) that stops re-keying, and a key that is stale or " +"rotated makes the TCP layer reload its own key and re-exchange. The " +"binding looks for the library via ``ctypes.util.find_library`` and then " +"next to the repository root in ``build/`` (``libcrypto_api.so``, " +"``libcrypto_api.dylib``, ``libcrypto_api.dll`` and " +"``build/Release/crypto_api.dll``)." msgstr "" "函式庫被建構為共享物件(“libcrypto_api.so”),因此可以從Python載入:「src/network_api/rsa_crypto.py」是TCP層使用的ctypes綁定" ",用於使用RSA-OAEP加密訊息(請參閱「TCP_Server_APIs」/「TCP_Client_APIs」加密通道部分)。此綁定也實作了 " @@ -153,13 +152,13 @@ msgstr "" "記錄在「network_api/.Flow/pub_key/pub_key.json」中對等方的「(ip, " "port)」下,並且記錄端點的變更金鑰會拒絕連線點的變更金鑰會拒絕連線點。綁定透過「ctypes.util.find_library」和儲存庫根目錄旁的「build/」來尋找庫。" -#: ../../source/Crypto/Crypto.rst:77 ad993af85f8f45f5a3661448f69961bf +#: ../../source/Crypto/Crypto.rst:77 9594680fce33464f9ff9cb9590bb5d0a msgid "" "The build produces the SOVERSIONed names ``libcrypto_api.so.1`` / " "``libcrypto_api.so.1.0.0`` plus the ``libcrypto_api.so`` loader symlink." msgstr "" -#: ../../source/Crypto/Crypto.rst:80 7ea41df5c6644e8197d587e03642123f +#: ../../source/Crypto/Crypto.rst:80 80c24657a4c9445088459fff264379b2 #, fuzzy msgid "" "CMake install rules export the ``crypto_api`` library, its public " @@ -174,11 +173,11 @@ msgstr "" "CMake 安裝規則匯出「crypto_api」庫、其公共標頭和 CMake 套件配置。所有 CMake 內容都位於儲存庫根目錄:CMake " "套件範本和 pkg-config 範本是「cmake/crypto_apiConfig.cmake.in」和「crypto_api.pc.in」。" -#: ../../source/Crypto/Crypto.rst:89 0d7e08f1e07445dfa77b47a85a25def7 +#: ../../source/Crypto/Crypto.rst:89 dccd3901c8024859b9a9753e818d6692 msgid "Common API" msgstr "一般API" -#: ../../source/Crypto/Crypto.rst:91 1c9b38b493964582875d168e61ccf829 +#: ../../source/Crypto/Crypto.rst:91 c1b71e19c8f6422eabd99bd0997daae8 msgid "" "Most public functions return ``pf_err_t``; ``PF_OK`` indicates success. " "Functions that report a size or a string instead have their own return " @@ -190,22 +189,25 @@ msgid "" "pending OpenSSL error queue." msgstr "" -#: ../../source/Crypto/Crypto.rst:114 07ac67f777704ad9822023430f0109c4 +#: ../../source/Crypto/Crypto.rst:114 67ae5556635e43a487c38bf8011e1c5b #, fuzzy msgid "" "The library uses caller-provided output buffers for fixed-size results. " "Functions that return allocated buffers document that the caller must " -"release them with ``free``. Opaque key handles must be released with " +"release them with ``pf_crypto_free`` — the library's own ``free``, so the" +" allocation and the deallocation always run on the same C runtime (a host" +" such as CPython on Windows may use a different one, and freeing across " +"runtimes corrupts the heap). Opaque key handles must be released with " "their corresponding ``*_free`` function. HKDF output is capped at " "``PF_CRYPTO_HKDF_SHA256_MAX_OUT`` (8160 bytes) by both " "``pf_crypto_hkdf_sha256`` and ``pf_ecdh_derive_key``." msgstr "該函式庫使用呼叫者提供的輸出緩衝區來取得固定大小的結果。傳回分配的緩衝區的函數記錄了呼叫者必須使用“free”釋放它們。不透明的按鍵句柄必須使用其對應的“*_free”函數來釋放。" -#: ../../source/Crypto/Crypto.rst:122 619e39d223d54a48ba983a3b30bd7d9d +#: ../../source/Crypto/Crypto.rst:125 69248ac47e7e47f18e953dee857db239 msgid "RSA API" msgstr "RSA API" -#: ../../source/Crypto/Crypto.rst:124 5eeaa87820f941dd8e171c973269036e +#: ../../source/Crypto/Crypto.rst:127 a770dcc04e2c42d1be50fe30d298df4b #, fuzzy msgid "" "RSA keys are generated with ``pf_rsa_keygen``. The implementation uses " @@ -215,7 +217,7 @@ msgstr "" "RSA 金鑰是使用「ss_rsa_keygen」產生的。此實作使用 RSA-OAEP 和 SHA-256 進行加密和解密。接受 2048 至 " "16384 位元的金鑰大小;建議使用 2048、3072 或 4096 位元。" -#: ../../source/Crypto/Crypto.rst:148 f85a46b466ef47ee9d195f439ba3b153 +#: ../../source/Crypto/Crypto.rst:151 e7b876b8fb354b2da45d3c13f50ededf msgid "" "The first encryption call with ``out == NULL`` queries the required " "output size; ``pf_rsa_decrypt`` supports the same query pattern. RSA " @@ -227,34 +229,34 @@ msgid "" "handle." msgstr "" -#: ../../source/Crypto/Crypto.rst:156 ff9d2472cf614dd0827d0887f195ed43 +#: ../../source/Crypto/Crypto.rst:159 6af957980305426e915b3f62d9eb1ed4 msgid "Public and private keys can be stored as PEM files:" msgstr "公鑰和私鑰可以儲存為 PEM 檔案:" -#: ../../source/Crypto/Crypto.rst:167 a3f163de660b4d49a36a8aedead555da +#: ../../source/Crypto/Crypto.rst:170 6bf9df3c51d540b69680723a4845de2d msgid "ECDH API" msgstr "ECDH API" -#: ../../source/Crypto/Crypto.rst:169 4535e8f410a742f38d32ff53d404c37b +#: ../../source/Crypto/Crypto.rst:172 3c69950828364df49bbf0b37313f9987 #, fuzzy msgid "" "ECDH key pairs are created with ``pf_ecdh_keypair_generate``. The " "supported curve names are:" msgstr "ECDH 金鑰對是使用「ss_ecdh_keypair_generate」建立的。支援的曲線名稱是:" -#: ../../source/Crypto/Crypto.rst:172 9624f8475c8d4618a7054e7c18ae5e1f +#: ../../source/Crypto/Crypto.rst:175 6a4d2171568847d4984c8705818c4bf9 msgid "``PF_ECDH_CURVE_P256``" msgstr "``PF_ECDH_CURVE_P256``" -#: ../../source/Crypto/Crypto.rst:173 4585a2433d684621a5f90805b74cef6c +#: ../../source/Crypto/Crypto.rst:176 c0da017a21dc46ed93b3da0727454dc3 msgid "``PF_ECDH_CURVE_P384``" msgstr "``PF_ECDH_CURVE_P384``" -#: ../../source/Crypto/Crypto.rst:174 14dde8ddd1b44ae1a4cb64179caa5aa5 +#: ../../source/Crypto/Crypto.rst:177 b2019f9f782b48dc85c5e3b24647fd94 msgid "``PF_ECDH_CURVE_P521``" msgstr "``PF_ECDH_CURVE_P521``" -#: ../../source/Crypto/Crypto.rst:176 43b77941f20d44958205bea666a208d5 +#: ../../source/Crypto/Crypto.rst:179 0962e1bca8da48d1835cbe8facb8a0ea #, fuzzy msgid "" "An unknown curve name returns ``PF_ERR_UNSUPPORTED``, and ``NULL`` " @@ -262,7 +264,7 @@ msgid "" "strings. Parsed peer keys are checked to lie on the curve before use." msgstr "公鑰作為 PEM subjectPublicKeyInfo 字串進行交換。使用前會檢查已解析的對等金鑰。" -#: ../../source/Crypto/Crypto.rst:200 ac2db67c049d4f55a2fc2f9972c6d57c +#: ../../source/Crypto/Crypto.rst:203 c5c15560992c48beb7637c19a517f07f #, fuzzy msgid "" "The higher-level ``pf_ecdh_seal`` and ``pf_ecdh_open`` APIs are " @@ -275,23 +277,23 @@ msgstr "" "建議將更高層級的 ``ss_ecdh_seal`` 和 ``ss_ecdh_open`` API 用於應用程式負載。他們使用 HKDF-" "SHA256 派生 AES-256-GCM 金鑰,包括隨機鹽和 IV,並驗證可選的 AAD。" -#: ../../source/Crypto/Crypto.rst:207 70a8e3f511f34359974c9152d60500b2 +#: ../../source/Crypto/Crypto.rst:210 f794a8f7227443e381d5337e9fe95677 #, fuzzy msgid "The ``pf_ecdh_seal`` output format is:" msgstr "``ss_ecdh_seal`` 輸出格式為:" -#: ../../source/Crypto/Crypto.rst:213 28f1933678854354b8ef357adcfdd380 +#: ../../source/Crypto/Crypto.rst:216 ee4a7ea6853249a7a137f949e3b9d7cc #, fuzzy msgid "" "The fixed overhead is ``PF_ECDH_SEAL_OVERHEAD`` (44 bytes). Empty " "plaintext is allowed. A failed tag check returns ``PF_ERR_AUTH_FAILED`` " "and no plaintext is returned. On success the output buffer is " -"``malloc``-ed and the caller frees it." +"``malloc``-ed and the caller releases it with ``pf_crypto_free``." msgstr "" "固定開銷為“SS_ECDH_SEAL_OVERHEAD”(44 " "位元組)。允許空明文。失敗的標籤檢查回傳``SS_ERR_AUTH_FAILED``並且不回傳明文。" -#: ../../source/Crypto/Crypto.rst:218 9a7c6cc7b5a94e5fac26bc6802310183 +#: ../../source/Crypto/Crypto.rst:221 212039cbe4b74827b643af47aaaf9970 msgid "" "ECDH key pairs can be persisted with ``pf_ecdh_keypair_write_priv`` and " "``pf_ecdh_keypair_read_priv`` (PKCS#8 PEM, optionally passphrase-" @@ -299,18 +301,18 @@ msgid "" "``pf_ecdh_pubkey_free`` release the handles." msgstr "" -#: ../../source/Crypto/Crypto.rst:224 7f05214ee91a478581014c39643d7bfb +#: ../../source/Crypto/Crypto.rst:227 a84d53d68554474fbb2beaa2146cee86 msgid "Security Notes" msgstr "安全說明" -#: ../../source/Crypto/Crypto.rst:226 a6482f5940d1469088bb376b1d25d31c +#: ../../source/Crypto/Crypto.rst:229 5e398f6a7ace4aeea29bcd40e75a59b1 msgid "" "ECDH provides key agreement, but it does not authenticate public-key " "ownership by itself. Public keys must be exchanged over an authenticated " "channel or verified with an external signature/certificate mechanism." msgstr "ECDH 提供金鑰協商,但它本身並未驗證公鑰所有權。公鑰必須透過經過身份驗證的通道進行交換或使用外部簽章/憑證機制進行驗證。" -#: ../../source/Crypto/Crypto.rst:230 fb49962bd1f0474c91610fa9dd020584 +#: ../../source/Crypto/Crypto.rst:233 df43fe66482c4e0fb896ab598ce43c7d #, fuzzy msgid "" "Private key files may be protected with a passphrase: " @@ -321,64 +323,64 @@ msgid "" "plaintext session keys." msgstr "私鑰檔案可以用密碼保護。應用程式應限制其檔案權限並避免記錄密碼、私鑰或純文字會話金鑰。" -#: ../../source/Crypto/Crypto.rst:238 e09bc96e058a4b14b135a1430b8a3ad9 +#: ../../source/Crypto/Crypto.rst:241 02cb264ad6c747d29b37bfa1f1cc6362 msgid "Error Handling" msgstr "錯誤處理" -#: ../../source/Crypto/Crypto.rst:240 8246aab2cf7d4913a7345684940c9220 +#: ../../source/Crypto/Crypto.rst:243 60786ad51ea444da97922957e670ea90 msgid "The main error codes are:" msgstr "主要錯誤代碼有:" -#: ../../source/Crypto/Crypto.rst:242 45059d6bf45c42c2bc8e8c6f023836f4 +#: ../../source/Crypto/Crypto.rst:245 8c1b057428f2445889d1159d6636b097 msgid "" "``PF_ERR_INVALID_ARG`` - NULL argument, illegal length or bad parameter " "combination (e.g. out-of-range RSA key size, a NULL salt/info with a non-" "zero length, or a plaintext longer than the key allows)." msgstr "" -#: ../../source/Crypto/Crypto.rst:245 daed84defdb64065849a0ef880b22eea +#: ../../source/Crypto/Crypto.rst:248 27e26e555ee24ce68ab7943b4117a57d #, fuzzy msgid "``PF_ERR_NOMEM`` - allocation failure." msgstr "``SS_ERR_NOMEM`` - 分配失敗。" -#: ../../source/Crypto/Crypto.rst:246 788a5b4b06714adcab5aeb36b81757e4 +#: ../../source/Crypto/Crypto.rst:249 2b3828e4bfa04329a60b479be7f0dfe5 #, fuzzy msgid "``PF_ERR_OPENSSL`` - OpenSSL operation failure." msgstr "``SS_ERR_IO`` - 檔案操作失敗。" -#: ../../source/Crypto/Crypto.rst:247 0e06a2169f5d445cab788910aaee188a +#: ../../source/Crypto/Crypto.rst:250 2c3c9ab09d294be8911f4fb31c335db6 #, fuzzy msgid "``PF_ERR_IO`` - file operation failure." msgstr "``SS_ERR_IO`` - 檔案操作失敗。" -#: ../../source/Crypto/Crypto.rst:248 0d1b17cc4e744efd891efe2d292f6dd8 +#: ../../source/Crypto/Crypto.rst:251 a928f8b90e154bdaa43ef4e4ee7d578d #, fuzzy msgid "" "``PF_ERR_PARSE`` - malformed PEM/DER input or wrong private-key " "passphrase." msgstr "``SS_ERR_PARSE`` - PEM/DER 輸入格式錯誤或私鑰密碼錯誤。" -#: ../../source/Crypto/Crypto.rst:249 8d5f6adfe3b24ecebb6ed2d84cece394 +#: ../../source/Crypto/Crypto.rst:252 9cd41d63123d49caa946160465dda70f #, fuzzy msgid "``PF_ERR_BUFFER_TOO_SMALL`` - caller output buffer is insufficient." msgstr "``SS_ERR_BUFFER_TOO_SMALL`` - 呼叫者輸出緩衝區不足。" -#: ../../source/Crypto/Crypto.rst:250 7a88e3913e8948edbcf645b5097b47b3 +#: ../../source/Crypto/Crypto.rst:253 78532f0a764249178076a4adcc032f7f #, fuzzy msgid "``PF_ERR_AUTH_FAILED`` - AES-GCM authentication failed." msgstr "``SS_ERR_AUTH_FAILED`` - AES-GCM 驗證失敗。" -#: ../../source/Crypto/Crypto.rst:251 1182998c4b164675a840d89b3a8e994b +#: ../../source/Crypto/Crypto.rst:254 5e5f5421333e4382ae5e700d7570648b #, fuzzy msgid "``PF_ERR_UNSUPPORTED`` - unsupported curve or key type." msgstr "``SS_ERR_UNSUPPORTED`` - 不支援的曲線或關鍵點類型。" -#: ../../source/Crypto/Crypto.rst:252 0af6413bc92a46a48a1ea044a6b4f05b +#: ../../source/Crypto/Crypto.rst:255 d1fea86be03940d097132b112b6f14f2 #, fuzzy msgid "``PF_ERR_DECRYPT`` - RSA decryption failed." msgstr "``SS_ERR_DECRYPT`` - RSA 解密失敗。" -#: ../../source/Crypto/Crypto.rst:254 b425983151054505a243c1d65c68a2b8 +#: ../../source/Crypto/Crypto.rst:257 9b1c2b2d3f48459bbedee21c92aafe31 msgid "For detailed OpenSSL diagnostics:" msgstr "有關詳細的 OpenSSL 診斷:" diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/File_Transfer/File_Transfer.po b/docs/source/locale/zh_TW/LC_MESSAGES/File_Transfer/File_Transfer.po index 1040ce8..317210b 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/File_Transfer/File_Transfer.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/File_Transfer/File_Transfer.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -20,12 +20,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/File_Transfer/File_Transfer.rst:2 -#: 2d215e70ec1e43988343e3d32392d8aa +#: d9c92006bc3e49c9a5d184d74f2e7824 msgid "TCP File Transfer Mechanism" msgstr "TCP檔案傳輸機制" #: ../../source/File_Transfer/File_Transfer.rst:4 -#: f603ff252cb64bea9b7c9034d2d46221 +#: b32ed3356f814a369d9d4bc153c017fa msgid "" "This document describes the file transfer subsystem implemented in both " "the ``TCP_Server_Base`` and ``TCP_Client_Base`` classes. The file " @@ -36,45 +36,46 @@ msgid "" msgstr "本文檔描述了在「TCP_Server_Base」和「TCP_Client_Base」類別中實現的檔案傳輸子系統。文件傳輸機制允許在伺服器及其連接的客戶端之間發送和接收單個文件、資料夾、多個文件和多個資料夾。它還支援從伺服器控制台由伺服器發起的傳輸。" #: ../../source/File_Transfer/File_Transfer.rst:14 -#: f28ca12001c24b1c954e10fdb63aa493 +#: ad6d3cd551694899ba6998e43167bb10 msgid "The design follows a **two-phase handshake** pattern:" msgstr "設計遵循**兩階段握手**模式:" #: ../../source/File_Transfer/File_Transfer.rst:16 -#: b348421cfc6d4267a58231db041e7d67 +#: f67e58b5ae8b4e2a8f9a9021efba0b5c msgid "A transfer command is exchanged over the main control connection." msgstr "傳輸命令透過主控制連線進行交換。" #: ../../source/File_Transfer/File_Transfer.rst:18 -#: 0483543fb8f0497a9ee256fee509e4fc +#: 4d267488a6cf4911bc2c3cb7801dce8d msgid "" "A separate TCP connection is established on a dynamically allocated port " "to transfer the actual file data (metadata + payload)." msgstr "在動態分配的連接埠上建立單獨的 TCP 連線以傳輸實際檔案資料(元資料 + 有效負載)。" #: ../../source/File_Transfer/File_Transfer.rst:22 -#: 0e13d1b8b6ef46ce855c8949ef36f219 +#: a0490aac6cc74a8f9de5e9872378b87c #, fuzzy msgid "" -"All file transfers use **stream-oriented reading/writing** with fixed-" -"size chunks (65536 bytes, hardcoded in both directions) to avoid blocking" -" and to handle large files efficiently." +"All file transfers use **stream-oriented reading/writing** with a " +"configurable chunk size (``file_transfer_chunk_len``, 65536 bytes by " +"default, in both directions) to avoid blocking and to handle large files " +"efficiently." msgstr "所有檔案傳輸都使用**面向流的讀取/寫入**和固定大小的區塊(預設為 64 KiB),以避免阻塞並有效處理大型檔案。" #: ../../source/File_Transfer/File_Transfer.rst:28 -#: a8c11b500a31468aa10fc4d6537c691c +#: 9ad33f3c1a2e4164b384a71388b895f5 msgid "" "*Note: For a high-level overview of the server and client classes, please" " refer to :doc:`TCP_Server_APIs` and :doc:`TCP_Client_APIs`.*" msgstr "*注意:有關伺服器和客戶端類別的高階概述,請參閱 TCP_Server_APIs 和 TCP_Client_APIs。 *" #: ../../source/File_Transfer/File_Transfer.rst:35 -#: aeba1deb576440f29ab1d507d38fb22d +#: 2c31714fc81743fa9fbb8701d87347ac msgid "File Transfer Protocol" msgstr "文件傳輸協定" #: ../../source/File_Transfer/File_Transfer.rst:37 -#: a97e5fe0762d4d2d8ffef8527985c9e7 +#: 61af0fc38ea74fcfae8b2a1316d2e6ea msgid "" "The protocol is symmetric: the same low-level exchange is used regardless" " of whether the server sends to a client or the client sends to the " @@ -84,7 +85,7 @@ msgid "" msgstr "該協定是對稱的:無論伺服器發送到客戶端還是客戶端發送到伺服器,都使用相同的低階交換。傳輸的**發起者**(發送命令的一方)同時也是文件資料的**發送者**;另一方充當**接收者**。" #: ../../source/File_Transfer/File_Transfer.rst:46 -#: 1a2e27611ea0452d99cd3e8ac299683c +#: 2ef019fa21e74d26873cb1da802747ac msgid "" "The low-level wire markers are stored in " "``PyFlow/network_api/decode_command_table.json``, which each instance " @@ -93,7 +94,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:52 -#: ebc9fc6492964c47b4744d8e2faf6ffd +#: be499b6571974e1a87d5c471578ac79b #, fuzzy msgid "" "``server_start_file_transfer_sign`` — from " @@ -103,7 +104,7 @@ msgid "" msgstr "``server_start_file_transfer_sign`` - 由接收者傳送給傳送者,表示接收者已準備就緒。" #: ../../source/File_Transfer/File_Transfer.rst:57 -#: d23e35d928494417918b1e9e1810d2e9 +#: 3c9a4f28914742dab2a8175df58f9419 msgid "" "``send_file_header_sign`` / ``send_file_data_sign`` — from " "``file_send_server_header`` / ``file_send_server_data``; both attributes " @@ -111,7 +112,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:60 -#: 07ce10ba9a534d2db23cb3505f3d9ad7 +#: 2035637777a449768450196f0fec1397 msgid "" "``server_received_file_header_sign`` / ``server_received_file_data_sign``" " — from ``file_receive_client_header`` / ``file_receive_client_data``; " @@ -121,7 +122,7 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:67 -#: a2c795d996c4491e9c90f46871d655b0 +#: 0fc372ae19be49029aa105a95e480640 #, fuzzy msgid "" "``error_sign`` — from ``file_send_receive_error`` (``/FER``), sent by " @@ -130,7 +131,7 @@ msgid "" msgstr "``error_sign`` - 當發生錯誤時由任何一方發送,導致傳輸套接字關閉。" #: ../../source/File_Transfer/File_Transfer.rst:72 -#: b95751f788c044d69f86a067e221a340 +#: 41f6d3d6e0e848bc8f6aecb995223622 msgid "" "The remaining keys of the table cover the other three direction/phase " "combinations. Protocol control lines that are not part of this table " @@ -141,110 +142,112 @@ msgid "" msgstr "" #: ../../source/File_Transfer/File_Transfer.rst:80 -#: c481ce301cdc4dddba6f392dc6de4e6a +#: 45a36aa9239d4caba8752e4dc4fd551b msgid "### Metadata Exchange" msgstr "### 元資料交換" #: ../../source/File_Transfer/File_Transfer.rst:82 -#: a6fea134d58a457ab825ec59930e0c48 +#: d4ace80bc05f4bafb8144e1de31060dc msgid "" "The sender performs the following steps after the dedicated file-transfer" " socket is connected:" msgstr "連接專用檔案傳輸套接字後,發送方執行下列步驟:" #: ../../source/File_Transfer/File_Transfer.rst:86 -#: e18ac26158444f719667794153f422d8 +#: 5df80a71cd274a92975e8d010f564872 msgid "" "Wait for the receiver's start signal " "(``server_start_file_transfer_sign``) with a 10-second timeout." msgstr "等待接收器的啟動訊號(``server_start_file_transfer_sign``),逾時時間為 10 秒。" #: ../../source/File_Transfer/File_Transfer.rst:89 -#: fb269796ce6d45cbb73b0201dce1cec9 +#: d68741e000fe48d3857ec0b0363d4182 msgid "Send the filename length as a 4-byte unsigned integer (big-endian)." msgstr "以 4 位元組無符號整數(大端)形式傳送檔案名稱長度。" #: ../../source/File_Transfer/File_Transfer.rst:91 -#: c48725bc3ac54f16bef68243c780831d +#: 95260b76f4524ddb8700ca05352f294d msgid "Send the filename encoded in UTF-8." msgstr "發送以 UTF-8 編碼的檔案名稱。" #: ../../source/File_Transfer/File_Transfer.rst:92 -#: 951751cbb7ab400dbfd8ac2e574d2bf0 +#: 7efa294dbe7e4921974628e8fb08cc00 msgid "Send the file size as an 8-byte unsigned integer (big-endian)." msgstr "以 8 位元組無符號整數(大端)形式傳送檔案大小。" #: ../../source/File_Transfer/File_Transfer.rst:94 -#: db806fd98e8b48dabcd3fa755f1d6567 +#: 065d4ab3bf384d81a22df89aeba09349 #, fuzzy -msgid "Send the file content in 65536-byte chunks until EOF." +msgid "" +"Send the file content in ``file_transfer_chunk_len``-byte chunks (65536 " +"by default) until EOF." msgstr "以 64 KiB 區塊的形式發送文件內容,直到 EOF。" -#: ../../source/File_Transfer/File_Transfer.rst:95 -#: 265efb19bd5c46569983bb4156bc195c +#: ../../source/File_Transfer/File_Transfer.rst:96 +#: aeec7f8ff0ab424cbc5b7c1a32ff9433 msgid "" "Wait for the completion acknowledgement " "(``server_received_file_data_sign``) with a dynamic timeout (base 30 " "seconds plus 10 seconds per 100 MiB)." msgstr "等待動態逾時(基本 30 秒加上每 100 MiB 10 秒)的完成確認 (``erver_reeived_file_data_sign``)。" -#: ../../source/File_Transfer/File_Transfer.rst:100 -#: b2944c94e7a9468daf924f021a5f0bab +#: ../../source/File_Transfer/File_Transfer.rst:101 +#: b80094b922a24c409f10eb9c8b05373b msgid "The receiver performs the complementary steps:" msgstr "接收器執行補充步驟:" -#: ../../source/File_Transfer/File_Transfer.rst:102 -#: 1353e95158fc496db86676f544168584 +#: ../../source/File_Transfer/File_Transfer.rst:103 +#: 5f71fc707ffe4b06a275b3db9f77178d msgid "Send the start signal." msgstr "發送啟動訊號。" -#: ../../source/File_Transfer/File_Transfer.rst:103 -#: e32e19b7ac2e4a20a76a7c5640212835 +#: ../../source/File_Transfer/File_Transfer.rst:104 +#: 7132d6fe15ce42a3bef64e0073e9baff msgid "Read the 4-byte length, then the filename, then the 8-byte size." msgstr "讀取 4 位元組長度,然後讀取檔名,然後讀取 8 位元組大小。" -#: ../../source/File_Transfer/File_Transfer.rst:105 -#: 1bbea38ba8ec4f84970f408827ba1be4 +#: ../../source/File_Transfer/File_Transfer.rst:106 +#: 7e0fcaec6d704455b94fc9f7defbef55 msgid "Acknowledge the header with ``server_received_file_header_sign``." msgstr "使用“server_reeived_file_header_sign”確認標頭。" -#: ../../source/File_Transfer/File_Transfer.rst:107 -#: ef7144f2c0c94c9fa25c2a5bad6ed5e8 +#: ../../source/File_Transfer/File_Transfer.rst:108 +#: d6a854d18d404082bdec0e2cf355ea62 msgid "Receive the file data in chunks and write to disk." msgstr "以區塊的形式接收檔案資料並寫入磁碟。" -#: ../../source/File_Transfer/File_Transfer.rst:108 -#: bb81c955e5024b6d9b6042fa3eb4c13f +#: ../../source/File_Transfer/File_Transfer.rst:109 +#: 69981b7e399e4de89858906b286aaf06 msgid "Acknowledge completion with ``server_received_file_data_sign``." msgstr "使用“server_reeived_file_data_sign”確認完成。" -#: ../../source/File_Transfer/File_Transfer.rst:111 -#: cd24d3a3f8704419889c764cf5812a99 +#: ../../source/File_Transfer/File_Transfer.rst:112 +#: b98957309caf49eba2657154bffbaf90 msgid "" "Any error during the exchange causes the failing side to send " "``error_sign``, and both sides close the transfer socket. The main " "control connection remains unaffected." msgstr "交換期間的任何錯誤都會導致失敗的一方發送“error_sign”,並且雙方都會關閉傳輸套接字。主控制連線不受影響。" -#: ../../source/File_Transfer/File_Transfer.rst:120 -#: 0313763b7bc6427cb80da39d09a94be1 +#: ../../source/File_Transfer/File_Transfer.rst:121 +#: f289e3c6e5b445f48eda6ed3434c9de8 msgid "Client-Initiated Transfer (Client → Server)" msgstr "客戶端發起的傳輸(客戶端 → 伺服器)" -#: ../../source/File_Transfer/File_Transfer.rst:122 -#: 155d9f3383cf42fe8fa0e4fe095fbae7 +#: ../../source/File_Transfer/File_Transfer.rst:123 +#: 17e1ddd91efe4690ad00f85f54875eda msgid "" "When the user types a file-related command in the client's interactive " "console, the call chain proceeds as follows." msgstr "當使用者在客戶端的互動式控制台中鍵入與檔案相關的命令時,呼叫鏈將如下進行。" -#: ../../source/File_Transfer/File_Transfer.rst:126 -#: ab7df52a36c742a0be4924b613ddebd4 +#: ../../source/File_Transfer/File_Transfer.rst:127 +#: 9cacd6ea79a14ff6ae602d7ed47926c8 msgid "### Console Input Handling" msgstr "### 控制台輸入處理" -#: ../../source/File_Transfer/File_Transfer.rst:128 -#: 42cde8d25ccd4424b5c871c7adf3af91 +#: ../../source/File_Transfer/File_Transfer.rst:129 +#: 07a7b69b45d04950877f071f25ad7c2c #, fuzzy msgid "" "In ``TCP_Client_Base.interactive_mode()``, user input is read line by " @@ -254,19 +257,19 @@ msgid "" "below." msgstr "在「TCP_Client_Base.interactive_mode()」中,使用者輸入被逐行讀取。可以辨識以「/file」、「/multiple_file」、「/file_folder」或「/multiple_file_folder」開頭的指令。對於每個這樣的命令,客戶端呼叫對應的線程安全入口點(以“_thread”結尾的方法)。" -#: ../../source/File_Transfer/File_Transfer.rst:136 -#: 08d0c910eba54d3cb8447d3cea15064f +#: ../../source/File_Transfer/File_Transfer.rst:137 +#: 250bb94df2a14d339b150a70e8fed215 #, fuzzy msgid "### Entry Points" msgstr "### 線程安全入口點" -#: ../../source/File_Transfer/File_Transfer.rst:138 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:139 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "The console dispatches to these methods:" msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:140 -#: 3ddbfd1b9e454342aa47f388d5bc7263 +#: ../../source/File_Transfer/File_Transfer.rst:141 +#: a0f0599853724ff9a15c501c154f52ea #, fuzzy msgid "" "``file_transfer_client_recv_client_start_thread(message, " @@ -276,23 +279,23 @@ msgstr "" "``file_transfer_client_recv_client_start_thread(訊息,file_folder_abspath " "=無)``" -#: ../../source/File_Transfer/File_Transfer.rst:143 -#: 4db440e1419b4ce895c7e03b85b070c1 +#: ../../source/File_Transfer/File_Transfer.rst:144 +#: 9d60213404014fbe8bee542f67d80398 msgid "``folder_file_transfer_client_recv_client_start(message)``" msgstr "``folder_file_transfer_client_recv_client_start(訊息)``" -#: ../../source/File_Transfer/File_Transfer.rst:144 -#: 936c7a26041045da8e4e20ec45d3959d +#: ../../source/File_Transfer/File_Transfer.rst:145 +#: 2e6c7b2b820349ebac90f27d835477d0 msgid "``multiple_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_file_transfer_client_recv_client_start(訊息)``" -#: ../../source/File_Transfer/File_Transfer.rst:145 -#: 972ecc6300354468b126961a483ecf2c +#: ../../source/File_Transfer/File_Transfer.rst:146 +#: bdee0e9084194b45b5fad3a44e9aaf85 msgid "``multiple_folder_file_transfer_client_recv_client_start(message)``" msgstr "``multiple_folder_file_transfer_client_recv_client_start(訊息)``" -#: ../../source/File_Transfer/File_Transfer.rst:147 -#: fef1e1b2a2024f89abd300268004380d +#: ../../source/File_Transfer/File_Transfer.rst:148 +#: ae9108b44e304198a7d0bff6bae8ab60 msgid "" "The last three run synchronously on the console thread; they walk the " "tree or the file list and spawn one worker thread per file themselves, so" @@ -301,13 +304,13 @@ msgid "" "``max_thread_num`` of them run at once." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:153 -#: f5919b72c7ec40e2a1b1d49cf57c9021 +#: ../../source/File_Transfer/File_Transfer.rst:154 +#: 8e945e4bdc124e749ee0a5976249a787 msgid "### Worker Function (Client Side)" msgstr "### 工作函數(客戶端)" -#: ../../source/File_Transfer/File_Transfer.rst:155 -#: 70bed6a3ccbd47e89653ab1b2d62fb9d +#: ../../source/File_Transfer/File_Transfer.rst:156 +#: cc8b9fc35bfb4cf395a2114786c01718 msgid "" "The core worker function for a single file is " "``file_transfer_client_recv_client_start(message, " @@ -316,13 +319,13 @@ msgstr "" "單一檔案的核心工作函數是「file_transfer_client_recv_client_start(message, " "file_folder_abspath=None)」。其邏輯如下:" -#: ../../source/File_Transfer/File_Transfer.rst:160 -#: f7103ca89460442ba018095bf48ae23c +#: ../../source/File_Transfer/File_Transfer.rst:161 +#: e3d81c4f4e724d81b426fdbfedb9c062 msgid "Allocate a unique client ID using the lock ``file_client_id_lock``." msgstr "使用鎖定“file_client_id_lock”分配唯一的客戶端 ID。" -#: ../../source/File_Transfer/File_Transfer.rst:162 -#: ea5fe1051d864a3caccc15bf2373b03e +#: ../../source/File_Transfer/File_Transfer.rst:163 +#: 81b9ac67e27341c0a17468f3b6787d14 msgid "" "Extend the original command string with the client ID (e.g., ``/file " "mydoc.txt`` becomes ``/file mydoc.txt 42``) and send it to the server " @@ -331,15 +334,15 @@ msgstr "" "使用客戶端 ID 擴展原始命令字串(例如,``/file mydoc.txt`` 變成``/file mydoc.txt " "42``),並使用``send_message()`` 透過主控制連線將其傳送到伺服器。" -#: ../../source/File_Transfer/File_Transfer.rst:168 -#: b56d7f67a1844b0cb893a3939ed8ed70 +#: ../../source/File_Transfer/File_Transfer.rst:169 +#: af07c5ef546a4102bbb836b65b2fd3be msgid "" "Obtain a local port for the outgoing file transfer socket by calling " "``palloc()``." msgstr "透過呼叫“palloc()”來取得傳出檔案傳輸套接字的本機連接埠。" -#: ../../source/File_Transfer/File_Transfer.rst:171 -#: 83314b464667496cb415f119beb0dc31 +#: ../../source/File_Transfer/File_Transfer.rst:172 +#: 37226a4f2e1e4a878ba325fca05df9bf msgid "" "Wait (up to 20 seconds) for the server to reply with a port number. The " "server's reply (``/server_file_transfer_port ``) is " @@ -349,8 +352,8 @@ msgstr "" "等待(最多 20 秒)伺服器回覆連接埠號碼。伺服器的回應(``/server_file_transfer_port " "``)由主連線接收並儲存在``file_server_port_list``中。當找到符合的條目時,將提取連接埠。" -#: ../../source/File_Transfer/File_Transfer.rst:179 -#: bd938c291cbe44aa913d35413fc76a6b +#: ../../source/File_Transfer/File_Transfer.rst:180 +#: e9cd68239fe3498597f07ccfa774ae22 msgid "" "Call the low-level send function ``file_transfer_mode(filename, " "server_host, server_port, client_port)``." @@ -358,8 +361,8 @@ msgstr "" "呼叫低階傳送函數「file_transfer_mode(filename, server_host, server_port, " "client_port)」。" -#: ../../source/File_Transfer/File_Transfer.rst:183 -#: 75779fa321754e05adc2ee87ac490f07 +#: ../../source/File_Transfer/File_Transfer.rst:184 +#: 145c524c53654e84a0bb45d3a065733e #, fuzzy msgid "" "For folder transfers, the worker function " @@ -376,8 +379,8 @@ msgstr "" " ”命令以在伺服器上建立相應的目錄。對於每個文件,它使用“/file_folder " "”形式的命令來呼叫“file_transfer_client_recv_client_start_thread”。信號量(``file_semaphore``)將並發檔案傳輸的數量限制為``max_thread_num``。" -#: ../../source/File_Transfer/File_Transfer.rst:198 -#: bbb76713d93e4920a87d1551cbdf9999 +#: ../../source/File_Transfer/File_Transfer.rst:199 +#: 5a7d502137c8442eafae448cee95a72a msgid "" "``multiple_file_transfer_client_recv_client_start`` loops over the given " "files and starts one worker thread per file, each holding " @@ -385,32 +388,32 @@ msgid "" "are capped by ``max_thread_num`` on that path too." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:203 -#: d9634b910f4f4509a717a6e7cb8445e2 +#: ../../source/File_Transfer/File_Transfer.rst:204 +#: 4ae4777e086a48558cbe3dda0ecdb3fb msgid "### Server-Side Handler (Receiving)" msgstr "### 伺服器端處理程序(接收)" -#: ../../source/File_Transfer/File_Transfer.rst:205 -#: ecf51220b2924da78e59cd7118a5d976 +#: ../../source/File_Transfer/File_Transfer.rst:206 +#: 66a812ac1ac84ad2b912deb843f3c059 msgid "" "When the server receives an extended command like ``/file mydoc.txt 42`` " "on the main control connection, ``handle_command`` detects it and calls:" msgstr "當伺服器在主控制連線上收到諸如「/file mydoc.txt 42」之類的擴充指令時,「handle_command」會偵測到它並呼叫:" -#: ../../source/File_Transfer/File_Transfer.rst:210 -#: 7437faffb1f7433faaea35c296c7ab96 +#: ../../source/File_Transfer/File_Transfer.rst:211 +#: 081e020d3e674d01bfde15c0922aa25c msgid "" "``file_transfer_server_recv_server_start_thread(client_id, client_socket," " command)``" msgstr "``file_transfer_server_recv_server_start_thread(client_id,client_socket,指令)``" -#: ../../source/File_Transfer/File_Transfer.rst:213 -#: 1ff4d8b0423b490db4a9b179d745dcb7 +#: ../../source/File_Transfer/File_Transfer.rst:214 +#: 4b5b5057002a457db83aed00c6148a7f msgid "The server then:" msgstr "伺服器然後:" -#: ../../source/File_Transfer/File_Transfer.rst:215 -#: 988de890b2fc4ebfbe68944b368ce5b8 +#: ../../source/File_Transfer/File_Transfer.rst:216 +#: e2ad0e97b7854be4a3dded6cf7d602b7 msgid "" "Creates a new thread via " "``file_transfer_server_recv_server_start(client_id, client_socket, " @@ -419,20 +422,20 @@ msgstr "" "透過 file_transfer_server_recv_server_start(client_id, client_socket, " "command, new_save_path=None, file_name=None) 建立新執行緒。" -#: ../../source/File_Transfer/File_Transfer.rst:219 -#: 47e1493ecf784674924778f581e6a71a +#: ../../source/File_Transfer/File_Transfer.rst:220 +#: ee8cdc9ae93c4579a05e37b32c86f705 msgid "Allocates a transfer port with ``palloc()``." msgstr "使用 palloc() 分配傳輸連接埠。" -#: ../../source/File_Transfer/File_Transfer.rst:220 -#: b19bd45b30ee42178dab7b9aafa79e5e +#: ../../source/File_Transfer/File_Transfer.rst:221 +#: ac8a87e1e481417284d90ba8cb843415 msgid "" "Calls ``file_transfer_mode_recv(host, port, client_socket, client_id, " "new_save_path, file_name, command)``." msgstr "呼叫「file_transfer_mode_recv(主機、連接埠、client_socket、client_id、new_save_path、file_name、command)」。" -#: ../../source/File_Transfer/File_Transfer.rst:223 -#: a2f55cc995c14ec1ac34545e458dccb2 +#: ../../source/File_Transfer/File_Transfer.rst:224 +#: 2f6675b7698c41938542b09cbfb482e8 msgid "" "This low-level receive function sets up a listening socket on the " "allocated port, sends the port number back to the client (as " @@ -445,20 +448,20 @@ msgstr "" " " "」),接受客戶端的連接,並執行檔案傳輸協定中所述的協定步驟。接收到的檔案保存在「received_files/」下(如果請求資料夾傳輸,則儲存在子目錄下)。" -#: ../../source/File_Transfer/File_Transfer.rst:233 -#: da7e5a1f96b3422bbfd8f056eb28dae3 +#: ../../source/File_Transfer/File_Transfer.rst:234 +#: 9fe861572b8746aeaa8266d8d30f963f msgid "" "After the transfer completes (or fails), the port is released with " "``pfree()``." msgstr "傳輸完成(或失敗)後,使用“pfree()”釋放連接埠。" -#: ../../source/File_Transfer/File_Transfer.rst:240 -#: e9956de8dffe4d898caed46c0e78c93b +#: ../../source/File_Transfer/File_Transfer.rst:241 +#: 3e4e81fa8cea4ef5ab2a39602eb29355 msgid "Server-Initiated Transfer (Server → Client)" msgstr "伺服器發起的傳輸(伺服器 → 客戶端)" -#: ../../source/File_Transfer/File_Transfer.rst:242 -#: 5e8dbd4b351d467cb809c3182feac0a2 +#: ../../source/File_Transfer/File_Transfer.rst:243 +#: 3ab21d4beefb41be83651eec10fd3899 msgid "" "When the server administrator types a command in the server console, for " "example ``/file /path/to/file.txt (127.0.0.1,54321)``, the console input " @@ -468,13 +471,13 @@ msgstr "" "當伺服器管理員在伺服器控制台中鍵入命令時,例如“/file /path/to/file.txt " "(127.0.0.1,54321)”,控制台輸入執行緒(“console_input”)會解析該指令並呼叫對應的伺服器端檔案傳輸 API。" -#: ../../source/File_Transfer/File_Transfer.rst:250 -#: 3bec81e76a2c4bf3b37386e180cc4fc1 +#: ../../source/File_Transfer/File_Transfer.rst:251 +#: fa019410dca84c04b24bf9334131aa8d msgid "The recommended entry points for server-to-client transfers are:" msgstr "伺服器到客戶端傳輸的建議入口點是:" -#: ../../source/File_Transfer/File_Transfer.rst:253 -#: 585d149b4b3f47f09176b4b61d3baeaa +#: ../../source/File_Transfer/File_Transfer.rst:254 +#: 99103b4e1f234e2dac2ffc955ab5b23e msgid "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` for a single file." @@ -482,13 +485,13 @@ msgstr "" "``file_transfer_server_recv_client_start_thread(message, " "file_folder_abspath=None)`` 對於單一檔案。" -#: ../../source/File_Transfer/File_Transfer.rst:256 -#: 81935504645c451b844d109037b46ae0 +#: ../../source/File_Transfer/File_Transfer.rst:257 +#: a1560a9b45c043618778f38beb1c3cb2 msgid "``folder_file_transfer_server_recv_client_start(message)`` for a folder." msgstr "資料夾的``folder_file_transfer_server_recv_client_start(message)``。" -#: ../../source/File_Transfer/File_Transfer.rst:258 -#: 4ca3cac907c04414925f5219b700d0e5 +#: ../../source/File_Transfer/File_Transfer.rst:259 +#: c18cb827a52f48d6b2883b708e2c871e msgid "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " for multiple files to multiple clients." @@ -496,8 +499,8 @@ msgstr "" "``multiple_file_multiple_client_transfer_server_recv_client_start(message)``" " 用於將多個檔案傳輸到多個客戶端。" -#: ../../source/File_Transfer/File_Transfer.rst:260 -#: 536f30cc03f84b218a5ca9b84deb9f88 +#: ../../source/File_Transfer/File_Transfer.rst:261 +#: 1b9fd8eea75e46899f68c6ca1312e896 msgid "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " for different file lists to different clients." @@ -505,8 +508,8 @@ msgstr "" "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(message)``" " 用於不同客戶端的不同檔案清單。" -#: ../../source/File_Transfer/File_Transfer.rst:263 -#: 92500d9fd7124d9ca7b648f03df90141 +#: ../../source/File_Transfer/File_Transfer.rst:264 +#: d34ac75777c74fe4bc63e1a100fd2aa3 msgid "" "The worker function ``file_transfer_server_recv_client_start(message, " "file_folder_abspath=None)`` performs the following steps:" @@ -514,36 +517,36 @@ msgstr "" "輔助函式 file_transfer_server_recv_client_start(message, " "file_folder_abspath=None) 執行下列步驟:" -#: ../../source/File_Transfer/File_Transfer.rst:268 -#: 583e8c89824f46ae839d233ab9e70e1a +#: ../../source/File_Transfer/File_Transfer.rst:269 +#: 29d03e172fd346e2a7928b55510df4f1 msgid "" "Extract the target client address from the last part of the command " "(e.g., ``(127.0.0.1,54321)``) using ``ast.literal_eval()``. Obtain the " "client's socket from ``self.clients``." msgstr "使用「ast.literal_eval()」從指令的最後部分提取目標用戶端位址(例如「(127.0.0.1,54321)」)。從“self.clients”取得客戶端的套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:273 -#: fd63ce90d3794b2181cdaa927e1a7a38 +#: ../../source/File_Transfer/File_Transfer.rst:274 +#: 7a8d8ed423524d6e91a311a3aa3d5a9a msgid "" "Allocate a unique client ID and extend the command with it, then send the" " extended command to the client over the main connection." msgstr "分配唯一的客戶端 ID 並用它擴展命令,然後透過主連接將擴展命令傳送到客戶端。" -#: ../../source/File_Transfer/File_Transfer.rst:277 -#: 6138738f134b48b2a98d05d3569172c7 +#: ../../source/File_Transfer/File_Transfer.rst:278 +#: 94b6c1f8a6a240e4ba4be8cf20f87c7f msgid "Allocate a local port with ``palloc()``." msgstr "使用 palloc() 分配本地連接埠。" -#: ../../source/File_Transfer/File_Transfer.rst:278 -#: 26fa94f94e1841f6845765f4fd65949d +#: ../../source/File_Transfer/File_Transfer.rst:279 +#: 723a05b6c3974b65a539af723f1e0872 msgid "" "Wait for the client to reply with its own port number (via " "``/server_file_transfer_port``), which is stored in " "``file_server_port_list`` by the main connection's message handler." msgstr "等待用戶端回覆自己的連接埠號碼(透過「/server_file_transfer_port」),該連接埠號碼由主連線的訊息處理程序儲存在「file_server_port_list」中。" -#: ../../source/File_Transfer/File_Transfer.rst:283 -#: 4bd913210d8945ffb7312070e070f252 +#: ../../source/File_Transfer/File_Transfer.rst:284 +#: 878572ca3d2948a9acbb6741f00ddd62 msgid "" "Call ``file_transfer_mode(filename, client_host, client_port, " "local_port)`` to send the file." @@ -551,8 +554,8 @@ msgstr "" "呼叫「file_transfer_mode(filename, client_host, client_port, " "local_port)」傳送檔案。" -#: ../../source/File_Transfer/File_Transfer.rst:287 -#: 39d0bdae658241a0a8205977cccd0395 +#: ../../source/File_Transfer/File_Transfer.rst:288 +#: ca517571b2d34c0497fcf5d5b12c93a1 msgid "" "On the client side, when it receives a command like ``/file " "/path/to/file.txt (127.0.0.1,54321) 42``, ``handle_server_command`` calls" @@ -567,38 +570,38 @@ msgstr "" " client_socket, commandent_socket, " "command)」。這將啟動一個接收器線程,類似於用於客戶端啟動的傳輸的伺服器接收器:它分配一個端口,用“/server_file_transfer_port”回复,並調用“file_transfer_mode_recv”來接收和保存檔案。" -#: ../../source/File_Transfer/File_Transfer.rst:303 -#: 014166967bb14b20a2782598b535575a +#: ../../source/File_Transfer/File_Transfer.rst:304 +#: cb7bdf5091e54e039de9d5578c273b93 msgid "Folder Transfer Mechanism (Detailed)" msgstr "資料夾傳輸機制(詳細)" -#: ../../source/File_Transfer/File_Transfer.rst:305 -#: 38eff5e62e844c0e94d587ba7132d26c +#: ../../source/File_Transfer/File_Transfer.rst:306 +#: b282df0b45bd4bb087ae10816fd3f06d msgid "" "Transferring a folder is implemented as a **recursive walk** that sends " "separate commands for subdirectories and files. The logic is symmetric on" " both client and server." msgstr "傳輸資料夾是透過「遞歸遍歷」來實現的,它為子目錄和檔案發送單獨的命令。客戶端和伺服器上的邏輯是對稱的。" -#: ../../source/File_Transfer/File_Transfer.rst:311 -#: 7319cca2fbef48679002d3bf0469d842 +#: ../../source/File_Transfer/File_Transfer.rst:312 +#: fb34b1f5d8a4488b9aef8b71dcb764ec msgid "### Creating Directories" msgstr "### 建立目錄" -#: ../../source/File_Transfer/File_Transfer.rst:313 -#: ad592f4510c34ecca1cba340caa2710e +#: ../../source/File_Transfer/File_Transfer.rst:314 +#: 6b67f2390d914745a253523cef9a2e0b msgid "" "For a directory that needs to be created on the receiver side, the sender" " sends a command of the form:" msgstr "對於需要在接收方建立的目錄,發送方發送以下形式的命令:" -#: ../../source/File_Transfer/File_Transfer.rst:317 -#: 114e36ce42e940cc8f0ec8c64c1db031 +#: ../../source/File_Transfer/File_Transfer.rst:318 +#: 7aaf85bf38fa4621a760dc56b6f99ad6 msgid "``/file_folder ``" msgstr "``/file_folder <相對路徑>``" -#: ../../source/File_Transfer/File_Transfer.rst:319 -#: a120552b93294a059a34132ab935068a +#: ../../source/File_Transfer/File_Transfer.rst:320 +#: 046f125a1f6e41e4808a9cd703e34ee4 msgid "" "The receiver's handler for this command (in either " "``file_folder_transfer_server_recv_server_start_thread`` or " @@ -608,23 +611,23 @@ msgid "" "The relative path uses forward slashes to be platform-independent." msgstr "該指令的接收器處理程序(在“file_folder_transfer_server_recv_server_start_thread”或“file_folder_transfer_client_recv_server_start_thread”中)在基本接收目錄下建立對應的目錄(對於伺服器來說是“received_files/”,對於客戶端來說是相同的目錄)。相對路徑使用正斜線與平台無關。" -#: ../../source/File_Transfer/File_Transfer.rst:330 -#: 2743fec0a2434e2b96ea3c49fecf268c +#: ../../source/File_Transfer/File_Transfer.rst:331 +#: 3fb5d6322ccd47f79e601e38684fe234 msgid "### Sending Files Inside a Folder" msgstr "### 發送資料夾內的文件" -#: ../../source/File_Transfer/File_Transfer.rst:332 -#: fb31b657a05547109dea51165844a632 +#: ../../source/File_Transfer/File_Transfer.rst:333 +#: c9f77546ed49407fa57c57f0b0a76acf msgid "For each file, the sender sends a command of the form:" msgstr "對於每個文件,發送者發送以下形式的命令:" -#: ../../source/File_Transfer/File_Transfer.rst:334 -#: 2da676ce8dd649169ba224f6d29cbbc9 +#: ../../source/File_Transfer/File_Transfer.rst:335 +#: f5a164466b0d4d4382b7d880bd320e3d msgid "``/file_folder ``" msgstr "``/file_folder <相對路徑> <檔名>``" -#: ../../source/File_Transfer/File_Transfer.rst:336 -#: 8972f356722148e3b34cbaa95390d700 +#: ../../source/File_Transfer/File_Transfer.rst:337 +#: c507cca92d1c463ea9f4d429a38a9b6a msgid "" "The receiver treats this as a file transfer request. The second argument " "(``file_name``) is used as the final filename, and the relative path " @@ -634,13 +637,13 @@ msgid "" "``file_transfer_server_recv_client_start``, depending on direction)." msgstr "接收方將此視為文件傳輸請求。第二個參數(``file_name``)用作最終檔案名,相對路徑決定基本接收目錄下的子目錄。實際檔案資料使用相同的單一檔案協定傳輸(透過“file_transfer_client_recv_client_start”或“file_transfer_server_recv_client_start”,視方向而定)。" -#: ../../source/File_Transfer/File_Transfer.rst:347 -#: a0ded05fd7f2406abb0ee41fcc33b53b +#: ../../source/File_Transfer/File_Transfer.rst:348 +#: e1e2b8dd57524ecfabd47c2c8386dfea msgid "### Concurrency Control for Folders" msgstr "### 資料夾的同時控制" -#: ../../source/File_Transfer/File_Transfer.rst:349 -#: 14b0ec4d109c448198db41c196df8a70 +#: ../../source/File_Transfer/File_Transfer.rst:350 +#: 32b26f72bba4482490f38968dcee5837 msgid "" "Because a folder can contain many files, the sender uses a semaphore " "(``file_semaphore``) to limit the number of concurrently active file " @@ -650,13 +653,13 @@ msgid "" "the server." msgstr "由於一個資料夾可以包含許多文件,因此發送方使用信號量(“file_semaphore”)來限制並發活動文件傳輸的數量。在開始每個檔案傳輸之前獲取信號量並在“finally”區塊中釋放。最大並發數由客戶端上的「max_thread_num」和伺服器上的「max_file_transfer_thread_num」設定。" -#: ../../source/File_Transfer/File_Transfer.rst:362 -#: 2c7d84b855df4587bfb110f525299e39 +#: ../../source/File_Transfer/File_Transfer.rst:363 +#: 8ce424a7f1de4933b3113a0e3ab98155 msgid "Custom Destination Directory" msgstr "自訂目標目錄" -#: ../../source/File_Transfer/File_Transfer.rst:364 -#: b972e019f10143a99af9de9b7a8e371a +#: ../../source/File_Transfer/File_Transfer.rst:365 +#: 6ca8ee9f021842939f446e999c067dfb msgid "" "Every transfer family accepts an optional trailing " "``destination_file_path`` argument that replaces the receiver's default " @@ -665,8 +668,8 @@ msgid "" "default location exactly as before." msgstr "每個傳輸系列都接受一個可選的尾隨“destination_file_path”參數,該參數會取代接收者的預設保存目錄(“received_files/”或配置的“file_transfer_dir”)。當省略它時,傳輸將像以前一樣轉到預設位置。" -#: ../../source/File_Transfer/File_Transfer.rst:372 -#: 1e801c2a599e4595b5f883ada1a63fc6 +#: ../../source/File_Transfer/File_Transfer.rst:373 +#: 6291da89ffa542dfbd94f599a9321216 msgid "" "The destination is **always the last argument** of the command and names " "a *directory* on the receiving machine: the received file keeps its own " @@ -676,59 +679,59 @@ msgid "" "default save directory. Missing directories are created." msgstr "目標**始終是命令的最後一個參數**,並在接收電腦上命名一個*目錄*:接收到的檔案保留其自己的名稱(``/``),傳輸的資料夾在目標下保留其結構(``//...``)。絕對路徑按原樣使用;相對路徑在預設保存目錄下解析。建立遺失的目錄。" -#: ../../source/File_Transfer/File_Transfer.rst:384 -#: 6b85151737b64a3e90154ba763b205d2 +#: ../../source/File_Transfer/File_Transfer.rst:385 +#: 76243e0349c1474bbdf14e1ef2a8e52b msgid "Command syntax:" msgstr "命令語法:" -#: ../../source/File_Transfer/File_Transfer.rst:386 -#: 9d80a0419f274373acc89686e909b71d +#: ../../source/File_Transfer/File_Transfer.rst:387 +#: 0c055bfc5ba4465a98a3555f8aa124c3 msgid "Client console (the receiver is the server):" msgstr "客戶端控制台(接收者是伺服器):" -#: ../../source/File_Transfer/File_Transfer.rst:388 -#: bac62d5b11c84f96b2b3841af7fc7a85 +#: ../../source/File_Transfer/File_Transfer.rst:389 +#: c9fa612895bc4f92839d2de77b6cbc7f msgid "``/file [destination_file_path]``" msgstr "``/file <檔案路徑> [目標檔案路徑]``" -#: ../../source/File_Transfer/File_Transfer.rst:390 -#: aa07623d0b4048be944b30c6fc07cc1b +#: ../../source/File_Transfer/File_Transfer.rst:391 +#: 2d34a030a1804d299a0b56c14984b1b5 msgid "``/multiple_file ... [destination_file_path]``" msgstr "``/multiple_file <檔案1> <檔案2> ... [目標檔案路徑]``" -#: ../../source/File_Transfer/File_Transfer.rst:392 -#: 1a9cfb266bb24df6ac2ddeb286a212d0 +#: ../../source/File_Transfer/File_Transfer.rst:393 +#: a7dd1e241a4346d4b873072c5948f187 #, fuzzy msgid "``/file_folder [destination_file_path]``" msgstr "``/file_folder <相對路徑>``" -#: ../../source/File_Transfer/File_Transfer.rst:394 -#: 46f89a56ef594dec945f21425306e2de +#: ../../source/File_Transfer/File_Transfer.rst:395 +#: 953993d920eb4959987d98423440ce61 msgid "``/multiple_file_folder ... [destination_file_path]``" msgstr "``/multiple_file_folder <資料夾1> <資料夾2> ... [目標檔案路徑]``" -#: ../../source/File_Transfer/File_Transfer.rst:396 -#: 085ba670e149450a8b385d68c8f9d366 +#: ../../source/File_Transfer/File_Transfer.rst:397 +#: 886c8b7d760044cabe48ce044412ca64 #, fuzzy msgid "" "Server console (the receiver is the target client, given as a quoted " "``(ip, port)`` address tuple, not as a client id):" msgstr "伺服器控制台(接收者是目標客戶端,以引號的位址元組形式給出):" -#: ../../source/File_Transfer/File_Transfer.rst:400 -#: abc0fb96992e4b09aaa9714ba73a094b +#: ../../source/File_Transfer/File_Transfer.rst:401 +#: 48d3bf6084224062867313a9597044d7 #, fuzzy msgid "``/file <(ip, port)> [destination_file_path]``" msgstr "``/file <檔案路徑> [目標檔案路徑]``" -#: ../../source/File_Transfer/File_Transfer.rst:402 -#: d9329c72161247bf8d5f0a609178c488 +#: ../../source/File_Transfer/File_Transfer.rst:403 +#: 684fa9b22136418b94cbb4202f702cd2 #, fuzzy msgid "``/file_folder <(ip, port)> [destination_file_path]``" msgstr "``/file_folder <相對路徑>``" -#: ../../source/File_Transfer/File_Transfer.rst:404 -#: af78c6ec2f3e4072aaac19d2d131cf5d +#: ../../source/File_Transfer/File_Transfer.rst:405 +#: 9380dc31685947e3a835107f435deed2 #, fuzzy msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -737,16 +740,16 @@ msgstr "" "``/multiple_file_multiple_client <檔案1> <檔案2> ... <客戶端ID1> <客戶端ID2> ... " "[目標檔案路徑]``" -#: ../../source/File_Transfer/File_Transfer.rst:406 -#: 2fdbf92caa6a46df9dae793592be802d +#: ../../source/File_Transfer/File_Transfer.rst:407 +#: 62488b8bb4e149be86c1d655bd80b6a8 #, fuzzy msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, port)1> ... " "[destination_file_path]``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:408 -#: abc1dac22b594c54a22b03d59e1a8338 +#: ../../source/File_Transfer/File_Transfer.rst:409 +#: d6a0c51014c9403fb82ebdf5c93928bc msgid "" "For the multiple-item commands the destination is the last argument; when" " the last argument is not a ``(ip, port)`` tuple it is treated as the " @@ -756,13 +759,13 @@ msgid "" "destination)." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:418 -#: 0c7fa56659f543ed93adacd874dd2e8b +#: ../../source/File_Transfer/File_Transfer.rst:419 +#: 373c2a5a23334df7a25d23f8d94abd66 msgid "Native In-Memory Forwarding" msgstr "本機記憶體轉發" -#: ../../source/File_Transfer/File_Transfer.rst:420 -#: 133205c62a0846318b30f5f5fe0dc296 +#: ../../source/File_Transfer/File_Transfer.rst:421 +#: dd57639b3e0e4068bd9533fc039597cd #, fuzzy msgid "" "The main protocol also provides a native, client-side forwarding feature " @@ -776,30 +779,30 @@ msgstr "" "主協定還提供了本機用戶端轉送功能,可透過伺服器將資料從一個用戶端中繼到多個其他用戶端**,而無需在伺服器上進行任何磁碟 " "I/O**。與前向擴展(上傳到磁碟然後從磁碟下載)不同,伺服器僅將資料保存在記憶體中並將其直接串流傳輸到目標用戶端。這避免了雙倍傳輸時間和磁碟讀/寫開銷。" -#: ../../source/File_Transfer/File_Transfer.rst:432 -#: b177ec0385be4e9da692646b88cd3ed8 +#: ../../source/File_Transfer/File_Transfer.rst:433 +#: 982c4c9538914821a07887fb8ab9b95d #, fuzzy msgid "Commands (client console only; rejected on the server console):" msgstr "客戶端控制台(接收者是伺服器):" -#: ../../source/File_Transfer/File_Transfer.rst:435 -#: 789bd7878891443fa43ec5111b3a028b +#: ../../source/File_Transfer/File_Transfer.rst:436 +#: 14406316555743359a854540ab6937c8 #, fuzzy msgid "" "``/forward_file ... ... " "[destination_file_path]``" msgstr "``/forward_file <檔案1> <檔案2> ... <位址1> <位址2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:436 -#: 04d9ece635c94b8c9257e0cb41bd5b81 +#: ../../source/File_Transfer/File_Transfer.rst:437 +#: 4dc576898177404da124649f7ce9ac28 #, fuzzy msgid "" "``/forward_folder ... ... " "[destination_file_path]``" msgstr "``/forward_folder <資料夾1> <資料夾2> ... <地址1> <地址2> ...``" -#: ../../source/File_Transfer/File_Transfer.rst:438 -#: 2f7b628a4e0246e385e9e8817b8d7a87 +#: ../../source/File_Transfer/File_Transfer.rst:439 +#: 220dfbf0a0d84559a8befb4eee500ba0 msgid "" "The number of files/folders and the number of target clients (written as " "quoted address tuples) is unlimited. Target addresses that are " @@ -807,8 +810,8 @@ msgid "" "are skipped and the remaining targets are still served." msgstr "文件/資料夾的數量和目標客戶端的數量(寫為引號的地址元組)是無限的。無法到達(未連接到伺服器)或等於伺服器本身的目標位址將被跳過,而其餘目標仍將得到服務。" -#: ../../source/File_Transfer/File_Transfer.rst:446 -#: 84f3e0acf89e4767bbb572cc6edc81aa +#: ../../source/File_Transfer/File_Transfer.rst:447 +#: 6137bf9406784c6f82d9f41560a52566 msgid "" "Like every transfer family, both commands accept an optional trailing " "``destination_file_path`` that replaces the default save directory on " @@ -822,22 +825,22 @@ msgstr "" ",而轉發的文件夾將其結構保持在``//... ``之下。省略參數時,目標會寫入其預設的`` " "file_transfer_dir ``。" -#: ../../source/File_Transfer/File_Transfer.rst:457 -#: 6b31e93335824fe1bfdb83b84f42f08c +#: ../../source/File_Transfer/File_Transfer.rst:458 +#: f6697695e9ef4e3694fa9046e41578e0 msgid "The data path reuses the protocol's own transfer machinery:" msgstr "資料路徑重用協定自己的傳輸機制:" -#: ../../source/File_Transfer/File_Transfer.rst:460 -#: 469812eff1874189a000989c9260cf1b +#: ../../source/File_Transfer/File_Transfer.rst:461 +#: 6ee037f0e4024d2988fcb2ccf3deef70 #, fuzzy msgid "" "The forwarding client streams the file with the standard file-transfer " -"byte stream (metadata header + 65536-byte chunks) to a transfer socket on" -" the server." +"byte stream (metadata header + ``file_transfer_chunk_len``-byte chunks, " +"default 65536) to a transfer socket on the server." msgstr "轉送客戶端將具有標準檔案傳輸位元組流(元資料標頭 + 64 KiB 區塊)的檔案串流傳輸到伺服器上的傳輸套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:465 -#: 42efd096a6744f489dc623a6ee503666 +#: ../../source/File_Transfer/File_Transfer.rst:467 +#: 43c94e746a5c46748846d0dc18a4e0ff msgid "" "The server acts as a pure relay: it reads the stream into per-target " "memory queues and writes each chunk to every target's transfer socket. " @@ -845,21 +848,21 @@ msgid "" "never writes to disk." msgstr "伺服器充當純粹的中繼:它將流讀取到每個目標的記憶體佇列中,並將每個區塊寫入每個目標的傳輸套接字。伺服器從不解析超出大小標頭的檔案內容,也從不寫入磁碟。" -#: ../../source/File_Transfer/File_Transfer.rst:472 -#: f43cb20c7bc648018f6f77ea09c8d538 +#: ../../source/File_Transfer/File_Transfer.rst:474 +#: 9dec57916af34e109bee7ce1e0bae2d4 msgid "" "Every target client receives the stream with the ordinary receive path " "(``file_transfer_mode_recv``) and writes it to its own local disk, " "exactly as if the server had pushed the file directly." msgstr "每個目標客戶端都使用普通接收路徑(“file_transfer_mode_recv”)接收流並將其寫入自己的本機磁碟,就像伺服器直接推送檔案一樣。" -#: ../../source/File_Transfer/File_Transfer.rst:478 -#: 3885df70422e4306ac80be623aa9581f +#: ../../source/File_Transfer/File_Transfer.rst:480 +#: a095abaf821e41a6a66adbb776bc35ef msgid "### Memory Bounding and Flow Control" msgstr "### 記憶體限制與流量控制" -#: ../../source/File_Transfer/File_Transfer.rst:480 -#: e371e5b793824e3386b43cb07a4222fd +#: ../../source/File_Transfer/File_Transfer.rst:482 +#: 244214dd675345f8a72b1088ad99fea0 #, fuzzy msgid "" "Because uploader, server and targets may have different bandwidths, data " @@ -879,30 +882,30 @@ msgstr "" "TCP_Client_Base 都採用 max_mem_buff 參數(以 MB 為單位,預設 2048,即 2 " "GB),此參數限制了轉送機制在該行程中可以保留的記憶體。當伺服器的緩衝位元組超過“max_mem_buff”時,它會向轉發客戶端發送“/pause_trans”,從而停止讀取來源檔案;一旦作者將緩衝區排空到低水位線(限制的一半)以下,伺服器就會發送“/start_trans”並恢復上傳。接收客戶端將每個區塊同步排出到磁碟,因此它們的緩衝記憶體保持受單一區塊的限制;兩側都存在“/pause_trans”/“/start_trans”處理程序,因此任何一側都可以在緩衝資料時限制傳輸。" -#: ../../source/File_Transfer/File_Transfer.rst:504 -#: b737bf957d354491b30903bfb0f89a3b +#: ../../source/File_Transfer/File_Transfer.rst:506 +#: 0aa14deaf6474437b421a65e21fce7d8 msgid "Concurrency and Threading" msgstr "並發和線程" -#: ../../source/File_Transfer/File_Transfer.rst:506 -#: 505576a3522748318a95cd3937a96834 +#: ../../source/File_Transfer/File_Transfer.rst:508 +#: 825c5e1a8b9b405c967ca49a1861e258 msgid "" "Both the server and the client use multiple levels of concurrency control" " to ensure stability during file transfers." msgstr "伺服器和用戶端均採用多層並發控制來確保文件傳輸過程中的穩定性。" -#: ../../source/File_Transfer/File_Transfer.rst:510 -#: 1d1a7b2ee1434530ae6abb411b0175cc +#: ../../source/File_Transfer/File_Transfer.rst:512 +#: 0d48b1245cd54597928cfc28d5b3c248 msgid "### File Transfer Semaphore" msgstr "### 檔案傳輸信號量" -#: ../../source/File_Transfer/File_Transfer.rst:512 -#: 078680d22b10410db9f7f21fe0e1a91d +#: ../../source/File_Transfer/File_Transfer.rst:514 +#: e2674ee9e0584513bc53aa815603fd24 msgid "Client: ``self.file_semaphore = threading.Semaphore(max_thread_num)``" msgstr "客戶端:``self.file_semaphore = threading.Semaphore(max_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:514 -#: 777a1dcc1258459d89dacbbb7b946c11 +#: ../../source/File_Transfer/File_Transfer.rst:516 +#: 1c0d27d13ad844159d29c6e662d51d09 msgid "" "Server: ``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" @@ -910,8 +913,8 @@ msgstr "" "伺服器:``self.file_semaphore = " "threading.Semaphore(max_file_transfer_thread_num)``" -#: ../../source/File_Transfer/File_Transfer.rst:517 -#: 315a82a6dd1a420bbe819a806f3b8292 +#: ../../source/File_Transfer/File_Transfer.rst:519 +#: cb65901904c8411ba53fc629023f732d #, fuzzy msgid "" "This semaphore limits the number of simultaneous file transfers (used " @@ -921,13 +924,13 @@ msgid "" "at ``max_thread_num`` (``max_file_transfer_thread_num`` on the server)." msgstr "此信號量限制同時文件傳輸的數量(主要在發送資料夾或多個文件時使用)。每個傳輸都在自己的線程中運行,並且在線程啟動之前獲取信號量。" -#: ../../source/File_Transfer/File_Transfer.rst:524 -#: b39cfe74f74b4b568221d23addc55da3 +#: ../../source/File_Transfer/File_Transfer.rst:526 +#: 6d93783b298e4ce98b999ff890d4a5f4 msgid "### Threading Model" msgstr "### 線程模型" -#: ../../source/File_Transfer/File_Transfer.rst:526 -#: 5586d5cc13a940bb92877b1fed3d03fd +#: ../../source/File_Transfer/File_Transfer.rst:528 +#: 036a972600e645119d8a523fa08a52db msgid "" "Each file transfer runs in a dedicated daemon thread, created by the " "``_thread`` wrapper functions (e.g., " @@ -935,29 +938,29 @@ msgid "" "transfer from blocking the main control loop." msgstr "每個檔案傳輸都在專用的守護執行緒中執行,該執行緒由「_thread」包裝函數建立(例如「file_transfer_client_recv_client_start_thread」)。這可以防止緩慢的傳輸阻塞主控制循環。" -#: ../../source/File_Transfer/File_Transfer.rst:532 -#: 7b1cceca816c426b865265e0c302c425 +#: ../../source/File_Transfer/File_Transfer.rst:534 +#: a84aaf5f9fb64d92b97c32185a1e7cb5 msgid "" "The thread that receives the transfer command (e.g., the server's " "``handle_command`` thread) does not wait for the transfer to complete; it" " returns immediately after spawning the worker thread." msgstr "接收傳輸命令的線程(例如伺服器的“handle_command”線程)不會等待傳輸完成;它在產生工作線程後立即返回。" -#: ../../source/File_Transfer/File_Transfer.rst:537 -#: 2d25f2be19fb467bb222d3780e2be853 +#: ../../source/File_Transfer/File_Transfer.rst:539 +#: 669fb6da8e7444dd829a6e14295648b1 msgid "" "The low-level receive function (``file_transfer_mode_recv``) blocks while" " reading from the transfer socket, but because it runs in a dedicated " "thread, the main connection remains responsive." msgstr "低階接收函數(“file_transfer_mode_recv”)在從傳輸套接字讀取時會阻塞,但由於它在專用執行緒中運行,因此主連接仍保持回應。" -#: ../../source/File_Transfer/File_Transfer.rst:543 -#: 641bce0854274c369c0b915a1c3d964a +#: ../../source/File_Transfer/File_Transfer.rst:545 +#: e39f8ae06ae84a6b84de8a3008ca17cb msgid "### Thread Pool for Custom Commands" msgstr "### 自訂指令的執行緒池" -#: ../../source/File_Transfer/File_Transfer.rst:545 -#: c41d6414ad5542aa8bbeaa67d28730d5 +#: ../../source/File_Transfer/File_Transfer.rst:547 +#: 3ad49853529d4563bacdfb4ca6eee115 msgid "" "Both classes also provide a ``ThreadPoolExecutor`` " "(``self._custom_executor``) for custom command handlers. When a handler " @@ -968,21 +971,21 @@ msgid "" "processing." msgstr "這兩個類別也為自訂命令處理程序提供了“ThreadPoolExecutor”(“self._custom_executor”)。當使用「run_in_thread=True」註冊處理程序時,它會透過「submit_task」提交到該池,該池也使用信號量將並發限制為「max_custom_workers」。此機制獨立於檔案傳輸信號量,旨在用於通用命令處理。" -#: ../../source/File_Transfer/File_Transfer.rst:560 -#: adfe7eb4ec4942e9979652f98b3beed9 +#: ../../source/File_Transfer/File_Transfer.rst:562 +#: 1862d74da28a40219f82cfd7af89c126 msgid "Port Allocation and Management" msgstr "連接埠分配與管理" -#: ../../source/File_Transfer/File_Transfer.rst:562 -#: 845beb63ef9c47ba8379637a1b0662fb +#: ../../source/File_Transfer/File_Transfer.rst:564 +#: bd53ec8aa4ef498aa0815db16ed03140 msgid "" "File transfers require ephemeral ports for the secondary data " "connections. The ``palloc()`` and ``pfree()`` methods are used to obtain " "and release these ports. Two modes are available:" msgstr "檔案傳輸需要臨時連接埠來進行輔助資料連線。 ``palloc()`` 和 ``pfree()`` 方法用於取得和釋放這些連接埠。有兩種模式可供選擇:" -#: ../../source/File_Transfer/File_Transfer.rst:568 -#: 8195ea505bdf43a2a0f68b78d958c709 +#: ../../source/File_Transfer/File_Transfer.rst:570 +#: eeaa9379d7d941159ac34f30ff6bb5f9 msgid "" "**Automatic mode** (``is_hand_alloc_port=False``): ``palloc()`` returns " "``0``, and the operating system assigns a free port when the socket is " @@ -991,8 +994,8 @@ msgstr "" "**自動模式**(``is_hand_alloc_port=False``):``palloc()`` " "傳回``0``,作業系統在套接字綁定時指派一個空閒連接埠。這是大多數用例的推薦模式。" -#: ../../source/File_Transfer/File_Transfer.rst:573 -#: 9a796b6e464d4d9e8e131401d5022e1f +#: ../../source/File_Transfer/File_Transfer.rst:575 +#: e3dc324e81734bd4bc768174caf200bf #, fuzzy msgid "" "**Manual mode** (``is_hand_alloc_port=True`` on the server constructor; " @@ -1008,40 +1011,40 @@ msgstr "" "self.max_port]`` " "中提取端口,步长为``port_add_step``。伺服器透過“/client_alloc_port_range”向客戶端廣播允許的範圍,然後客戶端使用相同的手動分配邏輯。" -#: ../../source/File_Transfer/File_Transfer.rst:588 -#: 7d275701519c4d60ba94cf086010e92d +#: ../../source/File_Transfer/File_Transfer.rst:590 +#: 29cfdab183eb4f9f83de41ef62a60785 msgid "" "*Note: For more details about port allocation, please visit the Port " "Allocation API sections in :doc:`TCP_Server_APIs` and " ":doc:`TCP_Client_APIs`.*" msgstr "*注意:有關連接埠分配的更多詳細信息,請訪問 TCP_Server_APIs 和 TCP_Client_APIs 中的連接埠分配 API 部分。 *" -#: ../../source/File_Transfer/File_Transfer.rst:596 -#: e92794553f6f4189978c5486f4d09fce +#: ../../source/File_Transfer/File_Transfer.rst:598 +#: 189736d8d1f8464b8d301f219700fda4 msgid "Error Handling and Timeouts" msgstr "錯誤處理和超時" -#: ../../source/File_Transfer/File_Transfer.rst:598 -#: 6ef0c4c7a91a42d0acc6b0a387247432 +#: ../../source/File_Transfer/File_Transfer.rst:600 +#: bcc373777989436f9df3657446d1a7f2 msgid "### Timeout Values" msgstr "### 逾時值" -#: ../../source/File_Transfer/File_Transfer.rst:600 -#: 2b8dea32ffe04d4988e44fca72384271 +#: ../../source/File_Transfer/File_Transfer.rst:602 +#: 27d75d097a804ec28ebec5c67469c9c6 msgid "" "**Start signal timeout**: 10 seconds. If the receiver does not send " "``server_start_file_transfer_sign`` within this time, the sender aborts." msgstr "**啟動訊號逾時**:10 秒。如果接收者在此時間內未傳送“server_start_file_transfer_sign”,則傳送者將中止。" -#: ../../source/File_Transfer/File_Transfer.rst:604 -#: 2d19f71ef52b4f3097bf0c2f3e64be7b +#: ../../source/File_Transfer/File_Transfer.rst:606 +#: 93e877c411eb4c96bd7861ff61f35e7a msgid "" "**Port negotiation timeout**: 20 seconds. The initiator waits for the " "peer's ``/server_file_transfer_port`` response." msgstr "**連接埠協商逾時**:20 秒。發起者等待對等方的「/server_file_transfer_port」回應。" -#: ../../source/File_Transfer/File_Transfer.rst:607 -#: 67dba14dcd534ae484df410cb48c8e53 +#: ../../source/File_Transfer/File_Transfer.rst:609 +#: 9e1d395bb59540a49393bebe6630e5eb msgid "" "**Completion acknowledgement timeout**: ``30 + (file_size // (100 * 1024 " "* 1024)) * 10`` seconds. Larger files get proportionally more time." @@ -1049,39 +1052,39 @@ msgstr "" "**完成確認逾時**:``30 + (file_size // (100 * 1024 * 1024)) * 10`` " "秒。文件越大,相應的時間就越長。" -#: ../../source/File_Transfer/File_Transfer.rst:611 -#: f175db3ace1448068c029d1527feb065 +#: ../../source/File_Transfer/File_Transfer.rst:613 +#: 6b4e6135669b41178fdbb47ea5975381 msgid "### Error Signalling" msgstr "### 錯誤訊號" -#: ../../source/File_Transfer/File_Transfer.rst:613 -#: 988d9d4636944c0abc8d186178d2a4f7 +#: ../../source/File_Transfer/File_Transfer.rst:615 +#: 448fdc6ba3dd4d9eae925e7e241f8cb8 msgid "" "Any error during the handshake or data transfer causes the failing side " "to send ``error_sign`` over the transfer socket." msgstr "握手或資料傳輸期間的任何錯誤都會導致失敗方透過傳輸套接字發送“error_sign”。" -#: ../../source/File_Transfer/File_Transfer.rst:616 -#: d171618e798b46d0a6ac7473b4a787ba +#: ../../source/File_Transfer/File_Transfer.rst:618 +#: 5b4c23a93e984ce0af2e43cf4752225b msgid "" "The other side, upon receiving the error sign, closes the transfer socket" " and aborts the transfer." msgstr "另一端收到錯誤標誌後,關閉傳輸套接字並中止傳輸。" -#: ../../source/File_Transfer/File_Transfer.rst:619 -#: c712f2f5e1794c528d4816a761030029 +#: ../../source/File_Transfer/File_Transfer.rst:621 +#: b337a2726ded4d619c5e8026bef3f6ea msgid "" "The main control connection remains unaffected; only the transfer socket " "is closed." msgstr "主控連線不受影響;僅關閉傳輸套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:623 -#: 9d55f6049713415794e53bd6a476e11f +#: ../../source/File_Transfer/File_Transfer.rst:625 +#: 68be52c8e5ce447a9c5ec51a661229cf msgid "### Exception Handling" msgstr "### 例外處理" -#: ../../source/File_Transfer/File_Transfer.rst:625 -#: a45a6eaec53b4699a7e61d4e422ace85 +#: ../../source/File_Transfer/File_Transfer.rst:627 +#: 036db9bc1858417ca589816028b83f80 #, fuzzy msgid "" "All socket operations are wrapped in try-except blocks. When an exception" @@ -1095,13 +1098,172 @@ msgstr "" "區塊中。當發生異常時(例如,連線重設、未找到檔案),錯誤將會以``traceback.print_exc()`` " "記錄,且傳輸會正常中止。如果可能,將發送“error_sign”,並關閉傳輸套接字。" -#: ../../source/File_Transfer/File_Transfer.rst:638 -#: 00af57a759ec4845b5810bb85ac1f485 +#: ../../source/File_Transfer/File_Transfer.rst:640 +#: ba1f05134dd24afa9867881cc45ed14a +msgid "Transfer Progress and Network Speed" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:642 +#: 5c7b182bb5214dd2ad49e5b171876e95 +msgid "Both classes record every running file transfer:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:644 +#: 8adbb686d9b04c97b5a7314ec4a5d1fd +msgid "``file_recv_progress`` — the files being received (downloads);" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:645 +#: 3d2d981185624b5498121d82b12d44ba +msgid "``file_upload_progress`` — the files being sent (uploads)." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:647 +#: e59132f2790d4b4fb2aa707e1d3b43b6 +msgid "" +"The keys are the transfers' fids: the transfer id the sender stamps on " +"the transfer command (``/file ``), which also identifies the " +"relay leg of a forwarded file. The protocol-internal public-key push is " +"not tracked. Each value is a five-item list:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:652 +#: bf66e7dae7e24cf3a3687ffd30f547ec +msgid "``[0]``: bytes transferred so far;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:653 +#: 2652aa8074764124b520d4e84b7667d5 +msgid "``[1]``: total size of the file, in bytes;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:654 +#: 8b09fc93700d4b6ca7a517700649c289 +msgid "" +"``[2]``: the current network speed of that direction — ``None`` until the" +" transfer has moved its first chunk, and while " +"``is_enable_real_time_network_speed`` is ``False``;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:657 +#: 311adcc13bd441a985ebcd8c775b152f +msgid "" +"``[3]``: local path of the file: the source of an outbound transfer, the " +"file being written for an inbound one;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:659 +#: 7a1f875aeb8b497ab7785620e402ff97 +msgid "" +"``[4]``: the ``(ip, port)`` of the transfer's original peer — the sender " +"in a download's entry, the receiver in an upload's. A forwarded transfer " +"stores the original peer on both sides, never the relaying server." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:663 +#: da38fbed94114f10b6f7366e43906dd8 +msgid "" +"An entry appears when a transfer starts and is removed when it ends, so " +"the stores hold exactly the transfers that are in flight at that moment " +"(iterate over a copy while transfers are running). With " +"``is_enable_file_transfer_progress_bar`` set to ``False`` no entry is " +"ever recorded — and, since the stores are the state a reconnect resumes " +"from, no transfer can be resumed either." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:670 +#: edbdd37cf5a04d42bf01f6bff5aa3307 +msgid "" +"``is_enable_real_time_network_speed`` (``True`` by default) measures the " +"protocol's current traffic — the control layer and every temporary " +"connection, file transfers included — into ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With the flag ``False`` nothing is " +"sampled and every speed value is ``None``." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:677 +#: c60e3cb78c8d48faace7569bdb50f8f5 +msgid "" +"The web tool (``transfer_web``) reads these stores: both backends serve " +"``/api/transfers`` (the rows plus the two speed attributes), and the " +"shared frontend renders the live speed readout in the topbar and one " +"progress bar per running transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:685 +#: ce90e0b6082e4d37a79346aa7b2763f9 +msgid "Pausing, Reconnecting and Resuming Transfers" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:687 +#: 5fbf414617474bd79978360043f149a3 +msgid "" +"An outbound transfer can be held and released at any time with the " +"``pause_trans(fid)`` and ``start_trans(fid)`` methods (both classes), or " +"from the peer with the ``/pause_trans `` and ``/start_trans `` " +"lines: ``pause_trans_remote(peer, fid)``/``start_trans_remote(peer, " +"fid)`` send them. The leg stops before its next chunk and stays open; a " +"leg that is paused keeps its socket, so nothing is torn down. Every " +"outbound transfer honours its own fid — a plain upload as much as the " +"upload leg of a forwarded file — so the flow control the server uses on a" +" relay works on any transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:696 +#: d4ace80bc05f4bafb8144e1de31060dc +msgid "The temporary connections of a transfer are resumed after a disconnect:" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:698 +#: d7d49609832d4c5bb2d7cecb059805eb +msgid "" +"when a connection drops, both sides write their transfer stores to " +"``.Flow/server_file_trans_progress.json`` / " +"``.Flow/client_file_trans_progress.json`` (the " +"``file_trans_progress_file`` attribute) — every upload, every download " +"and, on the server, the relay records a disconnected forward is re-driven" +" from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:703 +#: 353cf50d60014cceb4c5a36bf5b98b83 +msgid "" +"an interrupted transfer keeps its progress entry and its partial file " +"instead of dropping them, so the file on disk is exactly the state to " +"continue from;" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:706 +#: c7017b370d4147128e54a94458a7b536 +msgid "" +"after a reconnect the receiver drives the resume (`resume_transfers`): it" +" opens a fresh transfer listener, announces it and sends ``/resume_trans " +" `` with the byte offset its partial file holds. The sender " +"re-establishes the leg, reads its source from that offset and only the " +"remainder of the file travels. A forwarded transfer is asked for through " +"the server, which routes ``/forward_resume`` to the originating client so" +" it re-forwards just the missing part." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:714 +#: ee858a76e93f44d5934cb2d89f6709a5 +msgid "" +"The server resumes a peer's transfers when it reconnects, and a client " +"with ``is_auto_reconnect=True`` reconnects on its own and resumes every " +"transfer it can reach; `resume_transfers` is public, so an application " +"can also drive the resume itself. Legs the previous session left behind " +"are closed before the resume runs, so two legs never write the same " +"transfer." +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:723 +#: fe9377db9cf04b9da0dbe4d07c730adf msgid "Related API Definitions" msgstr "相關API定義" -#: ../../source/File_Transfer/File_Transfer.rst:640 -#: 92c3b5d713cb49cfb144026af574a0b4 +#: ../../source/File_Transfer/File_Transfer.rst:725 +#: cc71cb9b1d6642a2acc89d45a49022cc msgid "" "This section lists all public file-transfer related methods in " "``TCP_Server_Base`` and ``TCP_Client_Base``. For a complete list of all " @@ -1110,13 +1272,13 @@ msgstr "" "本節列出了「TCP_Server_Base」和「TCP_Client_Base」中所有與公共檔案傳輸相關的方法。有關所有公共 API " "的完整列表,請參閱本文檔末尾的表格。" -#: ../../source/File_Transfer/File_Transfer.rst:646 -#: bbc49149589d43719bc774a99b84ce6e +#: ../../source/File_Transfer/File_Transfer.rst:731 +#: d6683e415f794c5bb693f8c24370e7f9 msgid "### Server-Side File Transfer APIs" msgstr "### 伺服器端檔案傳輸 API" -#: ../../source/File_Transfer/File_Transfer.rst:652 -#: 59386d051c734452801f4bd00d5dd654 +#: ../../source/File_Transfer/File_Transfer.rst:737 +#: 9123c69197c34d93bb68d088897ebeca msgid "" "Initiates a server-to-client file transfer. ``message`` is the command " "string (e.g., ``/file /path/to/file.txt (127.0.0.1,54321)``). If " @@ -1126,13 +1288,13 @@ msgstr "" "啟動伺服器到客戶端的檔案傳輸。 ``message`` 是指令字串(例如,``/file /path/to/file.txt " "(127.0.0.1,54321)``)。如果提供了「file_folder_abspath」(用於資料夾傳輸),則它指定父資料夾的絕對路徑。" -#: ../../source/File_Transfer/File_Transfer.rst:663 -#: 431a043a77bc4d82a206650afde47b86 +#: ../../source/File_Transfer/File_Transfer.rst:748 +#: 367dfd82c95c413d963a15152469fc44 msgid "Thread-safe version that starts a new thread for the transfer." msgstr "線程安全版本,啟動新線程進行傳輸。" -#: ../../source/File_Transfer/File_Transfer.rst:669 -#: e17536344cb444b699c7465d8bcbdded +#: ../../source/File_Transfer/File_Transfer.rst:754 +#: d4aa76b7eb2c46c29adee0120a939b66 #, fuzzy msgid "" "Sends an entire folder from server to client. ``message`` should be of " @@ -1142,8 +1304,8 @@ msgstr "" "將整個資料夾從伺服器傳送到客戶端。 “message” 的格式應為“/file_folder " "”。" -#: ../../source/File_Transfer/File_Transfer.rst:676 -#: 88f9df0240054009a6957b13ee08f2ef +#: ../../source/File_Transfer/File_Transfer.rst:761 +#: 29f2a5e19bf04a09a8711ac1c892a4ad msgid "" "Sends multiple items to multiple clients. The message format is " "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " @@ -1154,8 +1316,8 @@ msgid "" "destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:688 -#: 39b67f1d0e6b438386eb04c6d44da6b8 +#: ../../source/File_Transfer/File_Transfer.rst:773 +#: ff8bc5c8969b45c1bbcf1eba5b77485a msgid "" "Sends different file lists to different clients. Files that appear before" " a group of client addresses are sent to that group; a new group starts " @@ -1166,217 +1328,242 @@ msgid "" "optional trailing destination path is accepted." msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:701 -#: 37108379b0b9495584bb135d5860ea4a +#: ../../source/File_Transfer/File_Transfer.rst:786 +#: f8a880287b7b49d4bdc2239ecf4a0577 msgid "" "Receives a file from a client. Called internally when the server receives" " a ``/file`` command from a client." msgstr "從客戶端接收文件。當伺服器從客戶端接收到“/file”命令時在內部呼叫。" -#: ../../source/File_Transfer/File_Transfer.rst:710 -#: adeb784cb6b24d6cbf143a7a50eba80a +#: ../../source/File_Transfer/File_Transfer.rst:795 +#: 97bfaa9c24ae47c39328707b8f17a91a msgid "" "Low-level receive function that performs the handshake and writes the " "incoming file to disk." msgstr "執行握手並將傳入檔案寫入磁碟的低階接收函數。" -#: ../../source/File_Transfer/File_Transfer.rst:718 -#: 0bb492f5335d426d8dc715847665b3f4 +#: ../../source/File_Transfer/File_Transfer.rst:804 +#: c7be9703e0454f7f96586642bc8f6a22 msgid "" "Low-level send function that connects to the receiver and transmits the " -"file." -msgstr "連接到接收器並傳輸檔案的低階發送函數。" +"file. ``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` addresses; ``peer`` is the transfer's" +" original receiver and ``resume_offset`` continues an interrupted file " +"from the byte the receiver already holds." +msgstr "" -#: ../../source/File_Transfer/File_Transfer.rst:720 -#: 29189fe72c61456ba2d5aa1ece75145e +#: ../../source/File_Transfer/File_Transfer.rst:810 +#: 3e7b689215e840bebd368b4d29104ebc msgid "### Client-Side File Transfer APIs" msgstr "### 客戶端檔案傳輸 API" -#: ../../source/File_Transfer/File_Transfer.rst:726 -#: 6c2f54ee2660441291a3fbbcaa95262c +#: ../../source/File_Transfer/File_Transfer.rst:816 +#: 1e97e492d6504579a9a265eb1242395e msgid "" "Initiates a client-to-server file transfer. ``message`` is the user " "command (e.g., ``/file mydoc.txt``). Used internally by the interactive " "console." msgstr "啟動客戶端到伺服器的檔案傳輸。 “message” 是使用者命令(例如“/file mydoc.txt”)。由互動式控制台內部使用。" -#: ../../source/File_Transfer/File_Transfer.rst:734 -#: ../../source/File_Transfer/File_Transfer.rst:765 -#: 07c4ae801fb54cbcb508af4b208f75dd +#: ../../source/File_Transfer/File_Transfer.rst:824 +#: ../../source/File_Transfer/File_Transfer.rst:855 +#: 0cd2695763114a0b831df0bfa80a3d56 msgid "Thread-safe version." msgstr "線程安全版本。" -#: ../../source/File_Transfer/File_Transfer.rst:740 -#: 0d66d4aac681414fb7b8a46117571fe9 +#: ../../source/File_Transfer/File_Transfer.rst:830 +#: 261399ca508d463eafa7f03a00bfc658 msgid "Sends a folder from client to server." msgstr "將資料夾從客戶端傳送到伺服器。" -#: ../../source/File_Transfer/File_Transfer.rst:746 -#: 2818655cecfc49f7ab1c9800b9418018 +#: ../../source/File_Transfer/File_Transfer.rst:836 +#: ef5e3b92b11c4530960c1c344a51c73b msgid "Sends multiple files from client to server." msgstr "將多個文件從客戶端傳送到伺服器。" -#: ../../source/File_Transfer/File_Transfer.rst:752 -#: 6ee08a69dbc5486a94fe2f616f0899e2 +#: ../../source/File_Transfer/File_Transfer.rst:842 +#: f2c90ee949d7484480cbb2cd5310bf26 msgid "Sends multiple folders from client to server." msgstr "將多個資料夾從客戶端傳送到伺服器。" -#: ../../source/File_Transfer/File_Transfer.rst:759 -#: 5a88c3508e074cff9ae445d00193f212 +#: ../../source/File_Transfer/File_Transfer.rst:849 +#: 0b13d26a40174243a15698b4bfcbb69f msgid "" "Receives a file from the server (called when the server initiates a " "transfer)." msgstr "從伺服器接收檔案(在伺服器啟動傳輸時呼叫)。" -#: ../../source/File_Transfer/File_Transfer.rst:771 -#: 42db9f7f09c044c8a58243854644adfb +#: ../../source/File_Transfer/File_Transfer.rst:861 +#: 3b78a4355d7f4ee2bbbe6bf934a962c0 msgid "Receives a folder from the server." msgstr "從伺服器接收資料夾。" -#: ../../source/File_Transfer/File_Transfer.rst:779 -#: 0a051d591bb54e529c771345409ec7df +#: ../../source/File_Transfer/File_Transfer.rst:869 +#: 3d044e0754b94d1289b491502ce83610 msgid "Low-level receive function on the client side." msgstr "客戶端的低階接收函數。" -#: ../../source/File_Transfer/File_Transfer.rst:786 -#: e0149bdd716249289f6ba260e3c3f053 +#: ../../source/File_Transfer/File_Transfer.rst:877 +#: 7311023a7fa644ed9b57a2873cd3bca8 msgid "" "Low‑level send function on the client side (identical to server's " "version)." msgstr "客戶端的低階發送功能(與伺服器版本相同)。" -#: ../../source/File_Transfer/File_Transfer.rst:791 -#: e612d36affc0456b9314f39816bf62f3 +#: ../../source/File_Transfer/File_Transfer.rst:882 +#: 7e74e9a09a8a4cf2a8a372a50b1ee51b msgid "Public API Summary" msgstr "公共API摘要" -#: ../../source/File_Transfer/File_Transfer.rst:793 -#: 8347c97393fe47ea83c13f6777faa36c +#: ../../source/File_Transfer/File_Transfer.rst:884 +#: 87aaf0a5d3b44f41a419d97b6567f6d0 msgid "" "All public APIs (including non-file-transfer methods) are listed below " "for reference." msgstr "下面列出了所有公共 API(包括非文件傳輸方法)以供參考。" -#: ../../source/File_Transfer/File_Transfer.rst:797 -#: 5ac025a5e948425a9a430c7c75b045f9 +#: ../../source/File_Transfer/File_Transfer.rst:888 +#: a195ee393f2a442c810e59811a6ae126 msgid "### TCP_Server_Base Public APIs" msgstr "### TCP_Server_Base 公用 API" -#: ../../source/File_Transfer/File_Transfer.rst:799 -#: ddf4d1d8e04e40659404ebb55c843c41 +#: ../../source/File_Transfer/File_Transfer.rst:890 +#: 0408d74a9140472e9a774143a60e5749 msgid "``file_transfer_server_recv_client_start``" msgstr "``file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:800 -#: 052d49abc8514ed19346f7b023783fa9 +#: ../../source/File_Transfer/File_Transfer.rst:891 +#: 24a33cb212844e04a8a271ada32412f0 msgid "``file_transfer_server_recv_client_start_thread``" msgstr "``file_transfer_server_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:801 -#: 6db2d78cc0b94b4b93d6080164897079 +#: ../../source/File_Transfer/File_Transfer.rst:892 +#: 7e286d1ece6940868bea6b937486e617 msgid "``folder_file_transfer_server_recv_client_start``" msgstr "``folder_file_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:802 -#: ec1b13e6e07449ec820d5cdc7a983048 +#: ../../source/File_Transfer/File_Transfer.rst:893 +#: 37fc5bd346c84415bb15138a42508fbe msgid "``multiple_file_multiple_client_transfer_server_recv_client_start``" msgstr "``multiple_file_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:803 -#: 7d780de964e543a8b703dd413d331c43 +#: ../../source/File_Transfer/File_Transfer.rst:894 +#: 38a2b16e3ab648688cf7e8d1cae8be72 msgid "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" msgstr "``diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:804 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:895 +#: ad39bc6b71f048b09bca3b895e9d32f8 #, fuzzy msgid "" "``file_folder_transfer_server_recv_server_start_thread`` (folder " "receiving)" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:806 -#: 02e685a79bc64a32ad888008a9dde074 +#: ../../source/File_Transfer/File_Transfer.rst:896 +#: ../../source/File_Transfer/File_Transfer.rst:916 +#: 37aeb9835435434881f94eb9951370d6 660ac3b979cc43d0beece659b9b0935f +msgid "``pause_trans`` / ``start_trans`` (hold and release an outbound transfer)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:897 +#: 7641e3ece9314197863d872836635218 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask a client to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:898 +#: ../../source/File_Transfer/File_Transfer.rst:918 +#: 9c62709c2c06456dbfddee1f1ce6871e de496a0be32c490585ae0cbafc931a71 +msgid "``resume_transfers`` / ``resume_trans`` (continue interrupted transfers)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:900 +#: 11476e0eaa3b4a4286612812e4e2c004 msgid "" "(The low-level helpers ``file_transfer_server_recv_server_start``, " "``file_transfer_mode_recv``, and ``file_transfer_mode`` are not " "considered public but are documented for completeness.)" msgstr "(低階助手「file_transfer_server_recv_server_start」、「file_transfer_mode_recv」和「file_transfer_mode」不被認為是公共的,但為了完整性而被記錄下來。)" -#: ../../source/File_Transfer/File_Transfer.rst:812 -#: 5193d200c3f245caae4095ab4114a467 +#: ../../source/File_Transfer/File_Transfer.rst:906 +#: 907e861cebe648fbacb799bae8bb15e0 msgid "### TCP_Client_Base Public APIs" msgstr "### TCP_Client_Base 公用 API" -#: ../../source/File_Transfer/File_Transfer.rst:814 -#: df25f04d660046669347072182ca0bde +#: ../../source/File_Transfer/File_Transfer.rst:908 +#: 88bd80083f754caeb026f9ce1b8c6b55 msgid "``file_transfer_client_recv_client_start``" msgstr "``file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:815 -#: 2a43c7e5134b4a64af241547e798bdf3 +#: ../../source/File_Transfer/File_Transfer.rst:909 +#: 3b21ff73da694465906482412b4fb4e3 msgid "``file_transfer_client_recv_client_start_thread``" msgstr "``file_transfer_client_recv_client_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:816 -#: 6a88ac28f634410ab54d999291b5b309 +#: ../../source/File_Transfer/File_Transfer.rst:910 +#: c8af43896a2443a5b14bd29863731c2c msgid "``folder_file_transfer_client_recv_client_start``" msgstr "``folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:817 -#: 6d47f6da5f54475989d93fca0c141f2d +#: ../../source/File_Transfer/File_Transfer.rst:911 +#: 7a3d3e4a52334b169a62d3b30d7a3190 msgid "``multiple_file_transfer_client_recv_client_start``" msgstr "``multiple_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:818 -#: 06e20b477a9744de9f2d2efcf0fbf57f +#: ../../source/File_Transfer/File_Transfer.rst:912 +#: 19e18754c4674842ad5116f709588e03 msgid "``multiple_folder_file_transfer_client_recv_client_start``" msgstr "``multiple_folder_file_transfer_client_recv_client_start``" -#: ../../source/File_Transfer/File_Transfer.rst:819 -#: a8dd89a54e0f498b88185761dc4c0f46 +#: ../../source/File_Transfer/File_Transfer.rst:913 +#: 4cf80f9f34e045c59a680d0450c9103a msgid "``file_transfer_client_recv_server_start``" msgstr "``file_transfer_client_recv_server_start``" -#: ../../source/File_Transfer/File_Transfer.rst:820 -#: 0811953096e94bd887990bb58d2de56a +#: ../../source/File_Transfer/File_Transfer.rst:914 +#: c09f5fcba03f461f89238dd31abf6e88 msgid "``file_transfer_client_recv_server_start_thread``" msgstr "``file_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:821 -#: bb9c5d31d258469d885127a592d6b1ed +#: ../../source/File_Transfer/File_Transfer.rst:915 +#: ad39bc6b71f048b09bca3b895e9d32f8 msgid "``file_folder_transfer_client_recv_server_start_thread``" msgstr "``file_folder_transfer_client_recv_server_start_thread``" -#: ../../source/File_Transfer/File_Transfer.rst:823 -#: bbbea73553dd4dfd98e0ee4076c1d42b +#: ../../source/File_Transfer/File_Transfer.rst:917 +#: 4b82ae9a067f46d5bb297431468a67a4 +msgid "``pause_trans_remote`` / ``start_trans_remote`` (ask the server to do it)" +msgstr "" + +#: ../../source/File_Transfer/File_Transfer.rst:920 +#: 99140d0be72649199911a57a26e2f2cf msgid "(The low-level helpers are documented but not part of the public API.)" msgstr "(低階幫助程序已記錄,但不屬於公共 API 的一部分。)" -#: ../../source/File_Transfer/File_Transfer.rst:827 -#: 56f1214838224007ade30eb34009810c +#: ../../source/File_Transfer/File_Transfer.rst:924 +#: 60355543ac904504af8529431ce2c1fa msgid "See Also" msgstr "參見" -#: ../../source/File_Transfer/File_Transfer.rst:829 -#: d513a2ce6fdf40eca5746ea840b4314f +#: ../../source/File_Transfer/File_Transfer.rst:926 +#: 7a5902ad3de64bf79d54d7f2f83ecbfb msgid "" "For more information about the TCP server and client base classes, please" " refer to:" msgstr "關於TCP伺服器和客戶端基類的更多信息,請參考:" -#: ../../source/File_Transfer/File_Transfer.rst:833 -#: 66b9f83c47d848779de9019a6f33c9a4 +#: ../../source/File_Transfer/File_Transfer.rst:930 +#: f10c29f467b849e8b4254998b44f99ba msgid ":doc:`../Network_APIs/TCP_Server_APIs`" msgstr ":doc:`../Network_APIs/TCP_Server_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:834 -#: 5cfe4f734d2043c2afe489c53c4ce963 +#: ../../source/File_Transfer/File_Transfer.rst:931 +#: 335ba244d28342449db065c252d7e14c msgid ":doc:`../Network_APIs/TCP_Client_APIs`" msgstr ":doc:`../Network_APIs/TCP_Client_APIs`" -#: ../../source/File_Transfer/File_Transfer.rst:836 -#: 47b4292bf8754c389fccf965d9b417d8 +#: ../../source/File_Transfer/File_Transfer.rst:933 +#: 92d0227c356447a098cba072d5b43c98 msgid "" "For details on port allocation, see the Port Allocation API sections in " "those documents." @@ -1453,3 +1640,9 @@ msgstr "有關連接埠指派的詳細信息,請參閱這些文件中的連接 #~ " a.txt b.txt (ip1,port1) (ip2,port2) c.txt" #~ " (ip3,port3)``" +#~ msgid "" +#~ "Low-level send function that connects" +#~ " to the receiver and transmits the" +#~ " file." +#~ msgstr "連接到接收器並傳輸檔案的低階發送函數。" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/Instance_Setup/Instance_Setup.po b/docs/source/locale/zh_TW/LC_MESSAGES/Instance_Setup/Instance_Setup.po index bd6d109..8dee5f4 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/Instance_Setup/Instance_Setup.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/Instance_Setup/Instance_Setup.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,12 +18,12 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Instance_Setup/Instance_Setup.rst:3 -#: b4877074f48944ef95449bad6b451f04 +#: 552b0fbec3774a638b0029ce5fd72949 msgid "Flow Setup Launcher" msgstr "流程設定啟動器" #: ../../source/Instance_Setup/Instance_Setup.rst:5 -#: 745aff08935b4042b2885b7f10d524f1 +#: 31952c3324264ea28368c7725796ff63 #, fuzzy msgid "" "The ``flow_setup.py`` script is a launcher for the TCP server/client " @@ -36,12 +36,12 @@ msgstr "" "伺服器/客戶端框架的啟動器。它允許您以互動方式或透過命令列參數快速產生單一伺服器或客戶端實例。每個啟動的實例都在單獨的終端視窗(或無頭系統上的後台進程)中運作。" #: ../../source/Instance_Setup/Instance_Setup.rst:13 -#: 5cfe71ed904f4f24bef1210b411ee40d +#: c8f9652279de42bb983523a15048596e msgid "Features" msgstr "特徵" #: ../../source/Instance_Setup/Instance_Setup.rst:15 -#: d5544e89cd884c938e1bfed52fdaf35a +#: 2bd321903dd94d9985805a44d9ef3d94 #, fuzzy msgid "" "**Interactive mode** – step-by-step creation of server and client " @@ -50,7 +50,7 @@ msgid "" msgstr "**互動模式** – 逐步建立伺服器或客戶端實例。" #: ../../source/Instance_Setup/Instance_Setup.rst:18 -#: a3239003782944f1aceb438c4b164657 +#: df9cbf9e1d024f9386a4b6278c82249e #, fuzzy msgid "" "**Command-line mode** – launch one server or one client with all " @@ -58,14 +58,14 @@ msgid "" msgstr "**命令列模式** – 在一個命令中使用所有參數啟動。" #: ../../source/Instance_Setup/Instance_Setup.rst:20 -#: 6c36fb284a4b4984bd220e047e26ed37 +#: b3406e8f62894233be438b7988e444da msgid "" "**Web-tool mode** – ``--web_server`` / ``--web_client`` start the browser" " UI of the ``transfer_web`` web tool." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:22 -#: 1a357d61f62b41dd91e150d24c323a98 +#: e359866c167e4e7ca5bf0791fd471ac4 msgid "" "**Extension registration** – ``--add`` / ``--delete`` register or " "unregister extension protocol files; the registered files are loaded on " @@ -73,7 +73,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:25 -#: 0deeeb0bc12644eaab437361d69dbe77 +#: 5f7cba6df26144e9840d140f94065b33 #, fuzzy msgid "" "**Persistent configuration** – stores the latest instance definitions in " @@ -84,7 +84,7 @@ msgstr "" "將最新的實例定義儲存在「setup.json」(與腳本相同的目錄)中。每種類型(伺服器/客戶端)僅保留一個配置,該配置在每次更新時都會被覆寫。" #: ../../source/Instance_Setup/Instance_Setup.rst:29 -#: 0b60fca4ab384444a03750dcb790150f +#: b93809688cb74986ac64e4baceb9f0f6 msgid "" "**Multiple instances** – the ``servers`` and ``clients`` lists may hold " "any number of entries. Adding an entry identical to an existing one of " @@ -92,7 +92,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:33 -#: af8b8bdd4c994728a0bf4a7b358976b7 +#: be9bc008af594306be21e731d6aefee3 #, fuzzy msgid "" "**Cross-platform** – supports Windows (cmd), Linux (gnome-terminal, " @@ -103,7 +103,7 @@ msgstr "" "(Terminal.app)。" #: ../../source/Instance_Setup/Instance_Setup.rst:36 -#: 4696d04613af4a1ea055df8be236adc3 +#: 57005cb0d04f47b2a8f10ad0bc9c7b43 #, fuzzy msgid "" "**Complete parameter support** – all parameters accepted by " @@ -114,22 +114,22 @@ msgstr "" "接受的所有參數都可以儲存在``setup.json`` 中以進行微調。" #: ../../source/Instance_Setup/Instance_Setup.rst:41 -#: 343fcd49c74b4cfd9d351f93c60e59bc +#: 2ff27919a6f64e8fb610158de5ffdf69 msgid "Usage" msgstr "用法" #: ../../source/Instance_Setup/Instance_Setup.rst:44 -#: 7e39ebc551894366b757ddfb5c406753 +#: dddde4f2d7084bc48efa1296cfd3f22c msgid "Interactive Mode" msgstr "互動模式" #: ../../source/Instance_Setup/Instance_Setup.rst:46 -#: 5f7b3715a9524fa2a0aed70bbefc5008 +#: f060e64959674f52b223bbc4b01d568c msgid "Run the script without any arguments:" msgstr "不帶任何參數運行腳本:" #: ../../source/Instance_Setup/Instance_Setup.rst:52 -#: a17a608e2ac24987b6c4a428acd770e9 +#: 6bb60d44328244d4ab20f3ae5ba2b827 msgid "" "When ``setup.json`` already exists, the launcher first asks whether to " "overwrite it, and the interactive collection itself asks whether the " @@ -137,7 +137,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:56 -#: 7fe4792645644307bf450194c2d98fa7 +#: d247a8d3c3f1430c8dfa6dccad66da0a msgid "" "``setup.json exists. Overwrite configuration data? (Y/N):`` – ``N`` " "launches every stored instance and exits; ``Y`` (or no existing file) " @@ -145,7 +145,7 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:59 -#: e60cbc55c5834e8ab8ce55e696159e9a +#: 96169445a67545178cdd4b68ce5faae3 msgid "" "``Delete or change existing instances or configs? (Y/N):`` – asked only " "when stored instances exist. ``Y`` opens the instance editor (see below);" @@ -153,23 +153,23 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:63 -#: eaf7134992f44c58aa4181664a3bc638 +#: 80847dcc3e404a779b2e693cf8de50d5 #, fuzzy msgid "``Choose the type (0 for Server, 1 for Client)``." msgstr "選擇類型(0 表示伺服器,1 表示客戶端)。" #: ../../source/Instance_Setup/Instance_Setup.rst:64 -#: 6a5569dd541a4043802c5d85f125db64 +#: cebc8ba62d1a48a69d8019c3862dc18b msgid "Enter the bind address and port (``host:port``)." msgstr "輸入綁定位址和連接埠(``host:port``)。" #: ../../source/Instance_Setup/Instance_Setup.rst:65 -#: e70e2b6322a04c748193e1cec4b0ee2c +#: 4311b66e1b974b4596f2693908ba3109 msgid "If Client, also enter the server address and port to connect to." msgstr "如果是客戶端,還需輸入要連接的伺服器位址和連接埠。" #: ../../source/Instance_Setup/Instance_Setup.rst:67 -#: df73da29736d4b878bef8427a95945aa +#: 3a5cff8b854c40939873ad57b060d9c3 msgid "" "Decide whether to add another instance. An entry that already exists in " "the list is not added again; a new one is appended, so several instances " @@ -177,14 +177,14 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:71 -#: 8e0df08f751f46deb43ba1006ed04b20 +#: 7c893e0f8399455ba1b14d9c796d75a8 msgid "" "After editing, the launcher asks ``Add new instances? (Y/N)`` before " "returning to the add flow." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:74 -#: 237874cb10d040cf86074695574daf32 +#: 49c58d9bb0b1440485f3cbecdb2843d6 msgid "" "When the editor is left with changes, ``setup.json`` is rewritten with " "every instance, and all stored instances (reused plus newly added) are " @@ -192,97 +192,97 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:79 -#: c81a1dba5f224291a56257375f84a1a0 +#: a1e74fd1f7f04e548b268c3dc0d6763e msgid "Global commands" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:81 -#: 8247157dfc0b4a32aa9ae300813386c6 +#: b8ede51e5254499e9dd613bc93db15ca msgid "" "The following words can be typed at **every** prompt, including field-" "value prompts:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:85 -#: c29ffb659bf3446490bc9eaac6f2e7ea +#: c2b850e77d9b44559be9b25d93611a70 msgid "Effect" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``Help``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:87 -#: 886877e3eb7d407fa62b16a4fc968f62 +#: 200a2a3be7ea46b291882aef0b8d9031 msgid "Print the usage text of the current prompt." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: c569666357334b05ba4189c122bbeaaf +#: a6ce48cd04e04b3ea42ad16e04e37359 msgid "``Fix_Config``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:89 -#: 0a5c8bdb9c1d4f7eb8a41fce85acf0b4 +#: fcd62172378d4da498de2a21a03f97a0 msgid "Jump to the instance editor (or, inside it, save and return to the list)." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 #, fuzzy msgid "``Setup``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:92 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "" "Launch every instance configured in ``setup.json`` and exit the setup " "program." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: cc2a8285cba3495db468d5f007f3ecfc +#: 85343de947b74e3b97e4c59109ebcd9e msgid "``Add_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:95 -#: a6c3fac6c8f44d75a7a266bae3c54729 +#: 6b8af44d732b4673afbc2f9cbec357d3 msgid "Prompt for extension file path(s) and register them." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 4febe01e668f4cc1aa1b92e328780ebe +#: a35baf4ca7d949eba92cf6c6279c9cd2 msgid "``Delete_Extension``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:97 -#: 5e54a7238b604a5fbe930ff4c5fd05d5 +#: d6f9495c1ad046d5877eb8159799ae88 msgid "Prompt for registered extension path(s) to remove." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 88bb1def13564b809d980ac0d7f22832 +#: 7c985bf621ba4fbeaa8f25042d47ed95 msgid "``Quit``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:99 -#: 22644327258c472aab543baf2ee08784 +#: 18f32c4c66094837a84906ba56ef236d msgid "Exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:103 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Instance editor" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:105 -#: 5832e770c51e4e61b0a372086616ad57 +#: 021cb4d2e2234dff8a9b206826926e33 msgid "" "The editor is reached by typing ``Fix_Config`` (at any prompt) or by " "answering ``Y`` to the \"Delete or change existing instances\" question. " @@ -295,37 +295,37 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:115 -#: 36e871e8b76b4e6f8ab3d41c6e58e053 +#: be9f3fe33bf943419ada71d457c635e1 msgid "Vim-style commands:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:117 -#: bf18c8047500461486e3bc05c6154ecc +#: f11526b8f13f4f6eabba91f7543c7120 msgid "``:w`` – write ``setup.json`` without leaving the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:118 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "``:wq`` – write ``setup.json`` and leave the editor." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:119 -#: 8e54b99375e441308cd3dc8ec4cd5d3a +#: 740d1745df7841a59959dbdab98a73b4 msgid "``:q`` – leave; refused while there are unsaved changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:120 -#: 32cdc0d2f2f34602a77b692202f56b24 +#: 944a89864f5c46c488287ee0740d83d5 msgid "``:q!`` – leave and discard all changes." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:121 -#: 7360415b19b04c13ab167e500f3437ac +#: 927b5a52f9454d65af949f5cc188e33d msgid "``Quit`` – exit the setup program immediately." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:123 -#: aea22c0686c64df8bc842a51fbd2d67e +#: d4163489911a454f9e4fd1b6cdd1de5a msgid "" "Inside the config editor, ``j``/``k`` move between fields, ``Esc`` or " "``back`` returns to the list, and a field index or ``Enter`` edits the " @@ -336,170 +336,170 @@ msgid "" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:132 -#: 720b396d65c547fa845910a437a48236 +#: b5cd8be69a40420a89cf7ad69631cd45 msgid "Command‑line Mode" msgstr "命令列模式" #: ../../source/Instance_Setup/Instance_Setup.rst:134 -#: 19ffa2fc838a441786de354b2a574153 +#: d798ec606de2454da5f10e9d0a7e677c msgid "Use the following options:" msgstr "使用以下選項:" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: c6dc291839964e119fb50574caedfd9c +#: 4d5c1aebbede473c8598cbc45f8deb20 msgid "Option" msgstr "選項" #: ../../source/Instance_Setup/Instance_Setup.rst:137 -#: 4a498223c2cb4e45914dcd53bb7f2f12 +#: a50ba126b168482997fae00497252fd4 msgid "Description" msgstr "描述" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: 649f1c33bb9d4afa89d1796bef081ddf +#: 7755904907ee46f6a34144360ed876f7 #, python-brace-format msgid "``--type {0,1}``" msgstr "`` --type {0,1} ``" #: ../../source/Instance_Setup/Instance_Setup.rst:139 -#: f0793c0f15584b42bc66b82e672854b5 +#: 0175b3fbf31e44829a685a07be420436 msgid "" "0 = Server, 1 = Client. Required for a plain command-line launch; without" " it the launcher runs interactively." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--setup_addr_port``" msgstr "`` --setup_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:143 -#: 58e47d807455460fb6e76d76b836bc30 +#: b7962f6d3a194e3eb91915d5681a2b7b #, fuzzy msgid "Bind address and port (e.g. ``127.0.0.1:8000``). Required with ``--type``." msgstr "輸入綁定位址和連接埠(``host:port``)。" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 31efc70f958b4608b07bc24eb1ec633b +#: 388a3dd952ac47a78598792ef7d587bc msgid "``--connect_addr_port``" msgstr "`` --connect_addr_port ``" #: ../../source/Instance_Setup/Instance_Setup.rst:147 -#: 041b4144717b4f54ad1b24d06726293b +#: 7d96425a64374a36a457a9167fc6d39c msgid "" "Server address and port to connect to. Required for Client; rejected in " "Server mode." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 7702fd6a612347919c73ec35852a4622 +#: 7bb925846a36488d945c3442889d83c0 msgid "``--setup_num``" msgstr "`` --setup_num ``" #: ../../source/Instance_Setup/Instance_Setup.rst:150 -#: 139258adce2844a28d57733bb973ec1e +#: 26698837fb26457ba9674e8ccf0cf881 msgid "" "Number of instances to launch. Only 1 is allowed; a larger value is " "accepted but ignored with a warning." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_server``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:154 -#: 108977e4c89b442488c39cad5378e8e5 +#: 9b1821de6d0f4c4d9af6c4e47eab4e5d msgid "" "Launch the ``transfer_web`` server tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 984f0a2d64024749ae1cfb521b9866d2 +#: 7cc185b424ee489282d9d85571d54fae msgid "``--web_client``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:157 -#: 99410d7adbc749e2bee7ff014945d19b +#: 91fa396110c94aa9a29f0a569763e030 msgid "" "Launch the ``transfer_web`` client tool (browser UI) instead of a TCP " "instance." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: 5de4064738ce4d529c9df9d1da98a556 +#: 118dce4ec3934bd4b5bb6e7b1aa31bf0 msgid "``--add PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:160 -#: be6adb7451d84f9f934044d2891cc4db +#: 2a630e280d3040d6a78cd865dd3e2ae7 msgid "Register extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 58e2f444f8394dd5a5c41b400675c736 +#: c505cbcf44104e6799bfcb83251c2f72 msgid "``--delete PATH [PATH ...]``" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:163 -#: 638774f6e42549ad88f930e50a2c3cad +#: 74b797d0ddf046d3b1dda4eea01013b7 msgid "Unregister extension protocol file(s), then exit." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:167 -#: e9b3cc31339a4f318337e8c68cc61fd5 +#: 54c5d51b3cb841ceaefda13a7613a8ae msgid "" "A command-line launch replaces ``setup.json`` with the single launching " "instance, so any other stored instance is dropped." msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:171 -#: 327a63e83b8f4df9af4a5e6a32e2ce6e +#: 99952fa68b694654b82a309a26419152 msgid "Examples" msgstr "範例" #: ../../source/Instance_Setup/Instance_Setup.rst:173 -#: c03b73272d554d1a885a04e6470d43c9 +#: 9c77e76f40a940e99e754d27e3bc1b05 msgid "**Launch a single server** on ``127.0.0.1:8000``:" msgstr "**在「127.0.0.1:8000」上啟動單一伺服器**:" #: ../../source/Instance_Setup/Instance_Setup.rst:179 -#: 69edc9f7ea534c00bdaab2a4c84ef2cf +#: 37df8730dce9408a87ba48b775eb2b0a msgid "" "**Launch a client** bound to port ``9000``, connecting to a server at " "``127.0.0.1:8000``:" msgstr "**啟動綁定到連接埠「9000」的客戶端**,連接到「127.0.0.1:8000」的伺服器:" #: ../../source/Instance_Setup/Instance_Setup.rst:186 -#: afc6f0adaafd49009ee96e36393060cd +#: 0bdae3cd584e464ab526840aa032e3a4 msgid "**Launch from an existing configuration** (if ``setup.json`` is present):" msgstr "**從現有配置啟動**(如果存在“setup.json”):" #: ../../source/Instance_Setup/Instance_Setup.rst:193 -#: f2fd3c19413a4e6abb4b18037a347443 +#: 0538ca5ad181412c9136f318be43dfa0 msgid "**Launch the web tool** instead of a TCP instance:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:200 -#: 71feceacd5b94bd98ce1973f45c16df1 +#: 4a43a3b821764068aaa05c153037208f msgid "**Register an extension protocol file**:" msgstr "" #: ../../source/Instance_Setup/Instance_Setup.rst:207 -#: 00dff5a17f42419585f498c51f7fcc97 +#: ff45af42eb7d4d3faa8640a18bfd61f6 msgid "Configuration File" msgstr "設定檔" #: ../../source/Instance_Setup/Instance_Setup.rst:209 -#: e723d0258ef143079a508676b8d418db +#: 39e34a4760354d78b87a8e050029e197 msgid "" "The script writes a file named ``setup.json`` in the same directory. Its " "structure is:" msgstr "該腳本在同一目錄中寫入一個名為「setup.json」的檔案。其結構為:" #: ../../source/Instance_Setup/Instance_Setup.rst:233 -#: 82c31bcb59fc481eaa532d1a0696ed8d +#: b0129978b1a9468188663a40126df876 msgid "" "**Both lists may contain any number of objects.** Every entry is " "completed with the default value of each parameter that the entry does " @@ -508,21 +508,23 @@ msgid "" "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " "``is_input_command_in_console``, ``max_custom_workers``, " "``is_extend_command``, ``is_enable_encrypto``, ``is_custom_keys``, " -"``max_mem_buff``, ``is_asynic_clients_io``, ``is_debug`` and " +"``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_asynic_clients_io``, ``is_debug`` and " "``is_print_log``; the client entry carries ``host``, ``client_host``, " "``port``, ``client_port``, ``timeout``, ``port_add_step``, " "``max_thread_num``, ``is_input_command_in_console``, ``is_wait_server``, " "``max_custom_workers``, ``is_extend_command``, ``is_enable_encrypto``, " -"``is_custom_keys``, ``max_mem_buff``, ``is_debug`` and ``is_print_log``." +"``is_custom_keys``, ``max_mem_buff``, ``recv_messages_chunk_len``, " +"``file_transfer_chunk_len``, ``is_debug`` and ``is_print_log``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:251 -#: 8ffd3b4e6719464cbd48a2b20d5764f2 +#: ../../source/Instance_Setup/Instance_Setup.rst:252 +#: 8731a083a201487bb579beb4a238a0db msgid "Custom Parameters" msgstr "自訂參數" -#: ../../source/Instance_Setup/Instance_Setup.rst:253 -#: 284b4f1899d94269a530dec33958d0c8 +#: ../../source/Instance_Setup/Instance_Setup.rst:254 +#: 8910f94645f54874893c20f724780cbd msgid "" "You may edit ``setup.json`` by hand (or change the same fields in the " "instance editor) to give any parameter accepted by ``TCP_Server_Base`` or" @@ -534,21 +536,21 @@ msgid "" "``setup.json`` from that, so hand-written extra keys are lost." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:264 -#: 3746b90215c84dc38c8ca2bb20d396f6 +#: ../../source/Instance_Setup/Instance_Setup.rst:265 +#: c62b1bfe8ceb40f8865a34ac87b4ba18 msgid "Extension Protocols and Startup Mode" msgstr "擴展協定和啟動模式" -#: ../../source/Instance_Setup/Instance_Setup.rst:266 -#: 4c6e6cc80e9c4ce3afe79fad55a2815a +#: ../../source/Instance_Setup/Instance_Setup.rst:267 +#: e6a7dcb4ea184e828e6667ae6505d872 msgid "" "Two extension protocols ship with the launcher and are loaded " "automatically for every instance whose ``setup.json`` entry sets " "``is_extend_command=True``:" msgstr "啟動器隨附兩個擴充協議,並為每個「setup.json」條目設定「is_extend_command=True」的實例自動載入:" -#: ../../source/Instance_Setup/Instance_Setup.rst:270 -#: 2d05270538524347899b403011286dcc +#: ../../source/Instance_Setup/Instance_Setup.rst:271 +#: 7159f768fc9a4ac199bfe0a4d8478fba #, fuzzy msgid "" "``command_control_extension_tcp.py`` – remote command execution with per-" @@ -556,8 +558,8 @@ msgid "" "completion report)." msgstr "``command_control_extension_tcp.py`` – 遠端命令" -#: ../../source/Instance_Setup/Instance_Setup.rst:273 -#: 1540ce3848be4d519034dd90e1d27fdd +#: ../../source/Instance_Setup/Instance_Setup.rst:274 +#: d2d277053c74470abc949b891493a5f0 #, fuzzy msgid "" "``forward_extension_tcp.py`` – forwarding messages, files, multiple " @@ -569,24 +571,24 @@ msgstr "" "使用每個客戶端日誌收集執行(``/command``)。 -``forward_extension_tcp.py`` - " "将消息、文件、多个文件、文件夹和多个文件夹转发到任意数量的目标客户端(``/send_msg_forward``、``/file_forward``、``/multiple_file_forward``、``/folder_forward``、``/multiple_folder_forward``)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:281 -#: 92e914da56f1402e85ef75819caf5b3f +#: ../../source/Instance_Setup/Instance_Setup.rst:282 +#: a8194174e5fd4dcf87ede716eaada9a4 msgid "" "Plain-message forwarding is native to the TCP protocol (no extension " "needed): the client-only command ``/forward_send_msg`` relays messages to" " the listed destination clients through the server." msgstr "純訊息轉發原生於TCP通訊協定(無需擴充) :僅用戶端指令``/forward_send_msg ``透過伺服器將訊息轉送至列出的目標用戶端。" -#: ../../source/Instance_Setup/Instance_Setup.rst:286 -#: 836d703843ed4940a42f3b7a0c36b78e +#: ../../source/Instance_Setup/Instance_Setup.rst:287 +#: 98297b76f3404736b92b6c507726a50a #, fuzzy msgid "" "With ``is_extend_command=False`` (the default) the raw TCP protocol is " "started without these two built-in extensions." msgstr "使用“is_extend_command=False”(預設)僅啟動原始 TCP 協定。" -#: ../../source/Instance_Setup/Instance_Setup.rst:289 -#: 3849c157ba79441e8406bcf9a4fc7695 +#: ../../source/Instance_Setup/Instance_Setup.rst:290 +#: fbbe2f02d9174359baca2c685704b475 msgid "" "Independently of ``is_extend_command``, every launch also loads the " "extension protocol files registered in ``PyFlow/added_extensions.json`` " @@ -594,15 +596,15 @@ msgid "" "``add_extension.load_registered_extensions``." msgstr "" -#: ../../source/Instance_Setup/Instance_Setup.rst:295 -#: fef96f9c96c64f6690b54175c7e7830d +#: ../../source/Instance_Setup/Instance_Setup.rst:296 +#: 9b5ab0319a9843f1b39721d3a96d1777 msgid "" "The ``is_input_command_in_console`` flag selects how the instance is " "started:" msgstr "``is_input_command_in_console`` 標誌選擇實例的啟動方式:" -#: ../../source/Instance_Setup/Instance_Setup.rst:298 -#: 407ae406135b42b3a6efd4ba5242b296 +#: ../../source/Instance_Setup/Instance_Setup.rst:299 +#: 1ec730c995b1454da1b208331d9ca8fe #, fuzzy msgid "" "``True`` (default) – the instance's own start method " @@ -612,8 +614,8 @@ msgstr "" "`` True `` (預設) – `` START_TCP_SERVER () ``/`` START_TCP_CLIENT () " "``被直接呼叫,主控臺輸入迴圈在其自己的執行緒中執行。" -#: ../../source/Instance_Setup/Instance_Setup.rst:301 -#: 1e10d27ee5c04d69ac9de20031a68b31 +#: ../../source/Instance_Setup/Instance_Setup.rst:302 +#: 3cfb2eba312943cea85388f4e9faf40d #, fuzzy msgid "" "``False`` – the instance is started in a background thread and the " @@ -623,8 +625,8 @@ msgstr "" "直接呼叫“start_TCP_client()”,控制台輸入循環在其自己的執行緒中運行。 -``False`` - " "實例在後台執行緒中執行,啟動器可讓進程保持活動狀態,直到實例停止(對於無頭部署很有用)。" -#: ../../source/Instance_Setup/Instance_Setup.rst:305 -#: 3743e0549b4449008324f68e282a0d81 +#: ../../source/Instance_Setup/Instance_Setup.rst:306 +#: 3b3482fa903f4afd81234e588a229c1f #, fuzzy msgid "" "Both extensions also expose injectable registration " @@ -639,48 +641,48 @@ msgstr "" "is_input_command_in_console=True)`` /``server_`` /``server_ " "is_input_command_in_console=True)`` 接受現有實例,因此可以載入多個擴充功能從程式碼到同一個實例。" -#: ../../source/Instance_Setup/Instance_Setup.rst:314 -#: 34bd8aa59f064b5b9c6323a01278a409 +#: ../../source/Instance_Setup/Instance_Setup.rst:315 +#: 1dc7b46c0e3047d2885573cc4f55e7c6 msgid "Internal Operation" msgstr "內部運作" -#: ../../source/Instance_Setup/Instance_Setup.rst:316 -#: 4ca266ef495b4a61bce44251b65f8c91 +#: ../../source/Instance_Setup/Instance_Setup.rst:317 +#: 8870bc6b731d40a095a40faed0c8f16d #, fuzzy msgid "" "Each instance is launched in a new terminal window (or background " "process)." msgstr "每個實例都在新的終端機視窗中啟動" -#: ../../source/Instance_Setup/Instance_Setup.rst:318 -#: 2b6246012ce84ec0945a9245b208ae95 +#: ../../source/Instance_Setup/Instance_Setup.rst:319 +#: 13c720a93ba54e8ca330fce3a078bb5b #, fuzzy msgid "" "The configuration is passed via a temporary JSON file to avoid shell " "escaping issues." msgstr "配置透過臨時 JSON 傳遞" -#: ../../source/Instance_Setup/Instance_Setup.rst:320 -#: e40392b9adef407ca3ade4bf2d252190 +#: ../../source/Instance_Setup/Instance_Setup.rst:321 +#: 9566eb3cb70e4b77bcbdb584f7e0b6fc #, fuzzy msgid "" "If an instance fails to start, the error is displayed and the window " "pauses for inspection." msgstr "顯示並且視窗暫停以進行檢查。" -#: ../../source/Instance_Setup/Instance_Setup.rst:324 -#: 2d7f7f35978a449995958b44730759d3 +#: ../../source/Instance_Setup/Instance_Setup.rst:325 +#: 5f0f0f6a41384356986a1182f14a0a4c msgid "Requirements" msgstr "要求" -#: ../../source/Instance_Setup/Instance_Setup.rst:326 -#: ddf48eb8fc2d48f9adbc38a39965ec22 +#: ../../source/Instance_Setup/Instance_Setup.rst:327 +#: 49ceb74e41104b00971cd9edecef08ae #, fuzzy msgid "Python 3.10+" msgstr "Python 3.6+" -#: ../../source/Instance_Setup/Instance_Setup.rst:327 -#: 9bc8a330f1384ade97e4ee55efa58e6b +#: ../../source/Instance_Setup/Instance_Setup.rst:328 +#: 1d80811611c944f9bf772364ab45d1e4 msgid "" "The ``PyFlow.network_api.connect_tcp`` module must be importable (the " "script imports ``TCP_Server_Base`` and ``TCP_Client_Base`` from there)." @@ -784,3 +786,26 @@ msgstr "" #~ msgid "and ``TCP_Client_Base`` from there)." #~ msgstr "和來自那裡的“TCP_Client_Base”)。" +#~ msgid "" +#~ "**Both lists may contain any number " +#~ "of objects.** Every entry is completed" +#~ " with the default value of each " +#~ "parameter that the entry does not " +#~ "set. The stored server entry therefore" +#~ " carries ``host``, ``port``, ``max_clients``, " +#~ "``port_add_step``, ``port_range_num``, " +#~ "``max_file_transfer_thread_num``, ``is_hand_alloc_port``, " +#~ "``is_input_command_in_console``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, " +#~ "``is_asynic_clients_io``, ``is_debug`` and " +#~ "``is_print_log``; the client entry carries " +#~ "``host``, ``client_host``, ``port``, " +#~ "``client_port``, ``timeout``, ``port_add_step``, " +#~ "``max_thread_num``, ``is_input_command_in_console``, " +#~ "``is_wait_server``, ``max_custom_workers``, " +#~ "``is_extend_command``, ``is_enable_encrypto``, " +#~ "``is_custom_keys``, ``max_mem_buff``, ``is_debug`` " +#~ "and ``is_print_log``." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po b/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po index e3944c6..b92d211 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Client_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -20,54 +20,54 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Client_APIs.rst:2 -#: 6dd11dd380344faabc9dea6d41655b1c +#: 596423c8d92e4592b221947ca5595ea7 msgid "The TCP Client APIs" msgstr "TCP 用戶端 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:5 -#: 2d8b31ea476c498188b1d3df403c2402 +#: bf347a93657146d6b019250273bc439c msgid "TCP Client setup API" msgstr "TCP 用戶端設定 API" #: ../../source/Network_APIs/TCP_Client_APIs.rst:7 -#: d699c50b2310495bb2521c5da6d30543 +#: 7e3dc9343f554fc181d2c2853898916c msgid "" "The TCP Client Setup API is used to create a TCP client. The client in " "the protocol is usually used to connect to the TCP server and exchange " "data with the server." msgstr "TCP 用戶端設定 API 用於建立 TCP 用戶端。協定中的客戶端通常用於連接TCP伺服器並與伺服器交換資料。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:34 -#: 5505d653e132458686537e957323bb9c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 +#: fb61c59ca5e646f3b749359b2ea13a40 msgid "" "The TCP Client Setup API is defined in the ``TCP_Client_Base`` class. The" " parameters of the ``__init__`` method are as follows:" msgstr "TCP 用戶端設定 API 在「TCP_Client_Base」類別中定義。 ``__init__``方法的參數如下:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:37 -#: 6a41dd3d0f00421b914a6ae9e588d6b8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 +#: d8b55d105dd144198594dd4f454fe5c5 msgid "``host``: The server host IP address to connect to." msgstr "``host``:要連線的伺服器主機 IP 位址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:38 -#: cc6ddd6c80bb46f3b393c9882e096a0a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 +#: ee9f5f584e6643529cdca91384562ebf msgid "``client_host``: The local host IP address to bind the client socket to." msgstr "``client_host``:將客戶端套接字綁定到的本機 IP 位址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:39 -#: 949c21452bb94effa6c13959868ac90f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 +#: 03357b8c2f974a419c6933d68976b6eb msgid "``port``: The server port number to connect to." msgstr "``port``:要連接​​的伺服器連接埠號碼。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:40 -#: 97c56df67b0c435aaf8ee89bea56266b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 +#: cd50ed1b09934f3bae2a4c615187d157 msgid "" "``client_port``: The local port number to bind the client socket to " "(``None`` means let the OS choose)." msgstr "``client_port``:將客戶端套接字綁定到的本機連接埠號碼(``None`` 表示讓作業系統選擇)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:41 -#: 309676fc53ff4cd39a8d9e200c54f1bf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 +#: f8cdf36b87834ea7a95209d2ca048332 msgid "" "``timeout``: The socket timeout in seconds for connection and receive " "operations. ``None`` (the default) is not \"no timeout\": the socket then" @@ -75,41 +75,41 @@ msgid "" " receive loop (it simply continues)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:42 -#: 9bf924fa535a44e78c98664e8d2b304f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 +#: 20c7ea1afac14f80a2b739cb6ae1957f msgid "" "``port_add_step``: The step size for incrementing the port number (used " "only in manual allocation mode)." msgstr "``port_add_step``:增加連接埠號碼的步長(僅在手動分配模式下使用)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:43 -#: 5abb7f5137714757b6957a177747d1e5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 +#: eb06f09e560543e5ba0abb3627a63585 msgid "" "``max_thread_num``: The maximum number of threads for concurrent file " "transfer operations." msgstr "``max_thread_num``:並發檔案傳輸操作的最大執行緒數。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:44 -#: e71bd35480184667a6390f2a28c0894a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:48 +#: 5ff72dc0ec90411bb0d20f618d015093 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console (interactive mode)." msgstr "``is_input_command_in_console``:指示是否在控制台中輸入指令的標誌(互動模式)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:45 -#: f4dd649db47842fdb7b64e39d5887cdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:49 +#: 5e12aa05eb854b15b0b6779b40b5a302 msgid "" "``is_wait_server``: A flag indicating whether to keep retrying connection" " until the server is available." msgstr "``is_wait_server``:指示是否繼續重試連線直到伺服器可用的標誌。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:46 -#: 69c7bfb0cc784e9a817d98096357d9d6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:50 +#: b3232047b364478caad5b3e5361e71be msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``:自訂工作執行緒的最大數量。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:47 -#: 892ac76eabb04f90b9c95f29009b6c11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 +#: a951c5564286432082b3e6a06aae8a48 msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the client itself by calling " @@ -117,8 +117,8 @@ msgid "" "register its commands first and connect later." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:51 -#: 0cfe21e428fd45f08a9d8c080c285535 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:55 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with the server are RSA-encrypted (see :ref:`tcp-client-encrypted-" @@ -127,8 +127,8 @@ msgstr "" "「is_enable_encrypto」:指示與伺服器交換的訊息是否經過 RSA 加密的標誌(請參閱 tcp-client-encrypted-" "channel-api)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:53 -#: 353688102eb6441ebf87384e57f0c661 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 +#: 8ac8a71ca8564a89bb52f882c4fedefc msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -138,93 +138,139 @@ msgstr "" "``is_custom_keys``:可選的``[pub_key_path, pvt_key_path]`` 使用者提供的 RSA " "金鑰對。兩個檔案都必須存在,解析為 PEM,並且相互配對;無效的對將被默默地忽略,並使用預設的鍵查找(``None`` 保留預設查找)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:57 -#: 0176e8b8b8ea44c396d55657d74a91cd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:61 +#: c01569233a864bf0b106a877fb924c27 msgid "" "``max_mem_buff``: The buffering ceiling in MiB, stored as bytes " "(``self.max_mem_buff``). It is kept for parity with the server class; the" " client's forward path does not read it today. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:60 -#: 276f7755eaea4b808ad6cfe985eaa8aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:64 +#: 10fb41da1af34a539a962083252bdf55 +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 +#: 1b569fa80b59490dacc6bcdf3a924d60 +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 +#: ac73e6da7c3044f1bf68aff504142765 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the client logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:63 -#: 58a790ecb724454298659bf9831fb2ae +#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 +#: fbb5a64713a34d85868f8b8ec549a4ca msgid "" "``is_print_log``: A flag indicating whether the client logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:66 -#: 36eebcb4edbb4f1e96862b64762c4d6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 +#: fa251d2893fa413aac9d5e525df18209 +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when the " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:85 +#: 3a9f1a8e8b8f45dbb9011b3b0e28cd92 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:93 +#: 3272388be97643f98bada0a995516141 msgid "Every parameter has default values:" msgstr "每個參數都有預設值:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:68 -#: 4a2b0f17cb4f47669a8dcb3734c17468 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:95 +#: 9fd3d516d31841fd9054a2a3dfcb1ac4 msgid "``host``: Default is ``None`` (must be provided before connecting)" msgstr "``host``:預設為``None``(必須在連線前提供)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:69 -#: 7dea100856734d3ba4ee6352d45cc554 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:96 +#: ece6c7a48ae74f86b6e207d960c6daa2 msgid "``client_host``: Default is ``'127.0.0.1'``" msgstr "“client_host”:預設為“127.0.0.1”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:70 -#: e646757cb9d1425fa72970698c2938e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 +#: 8a9d85bb281e43e69ea0ae48363fb8da msgid "``port``: Default is ``65432``" msgstr "“連接埠”:預設為“65432”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:71 -#: 4c232543227544acae211825b01a795a -msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" -msgstr "“client_port”:預設為“None”(作業系統分配臨時連接埠)" +#: ../../source/Network_APIs/TCP_Client_APIs.rst:98 +#: 4653721a3e8143fea8a43899bb0e6437 +msgid "" +"``client_port``: Default is ``None`` (OS assigns ephemeral port). A " +"configured port that cannot be bound — a session that just ended can hold" +" it in the operating system's ``TIME_WAIT`` — is reported and the " +"connection is made from an OS-assigned port instead." +msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:72 -#: 3c772d5ab49243b993d5dfea9af5d472 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:102 +#: 4439e99a222744a9bca762b5f14b4d74 msgid "``timeout``: Default is ``None``" msgstr "“超時”:預設為“無”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:73 -#: 501a6c2966d2470cbf9ce2a8909ef130 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 +#: 0b0f6a9551ff4bf28ad02095893db9d8 msgid "``port_add_step``: Default is ``1``" msgstr "“port_add_step”:預設為“1”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:74 -#: 697656b4cb24453c89b1a848299e4167 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:104 +#: bcb1ee681a0f47319338faf71a99adf7 msgid "``max_thread_num``: Default is ``10``" msgstr "“max_thread_num”:預設為“10”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:75 -#: 632284d8c9b349f89018f8a19ce9662e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:105 +#: 08471d033b174cf395292c36068d4cb8 msgid "``is_input_command_in_console``: Default is ``True``" msgstr "“is_input_command_in_console”:預設為“True”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:76 -#: ec7a8bd80ad2471d9208999fc34792f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:106 +#: bbf2ad3b5e4340c9b481f8af135281e2 msgid "``is_wait_server``: Default is ``True``" msgstr "``is_wait_server``:預設為``True``" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:77 -#: c036a352181d422894b56b0c14167bdf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:107 +#: 63f2004d0c5b4fef8cf23eaa7be020b1 msgid "``max_custom_workers``: Default is ``10``" msgstr "“max_custom_workers”:預設為“10”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:78 -#: 64df1f8395ca45d497875fb232c71b0e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:108 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_client()`` automatically)" msgstr "“is_extend_command”:預設為“False”(當“True”時,“__init__”不會自動呼叫“start_TCP_client()”)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:80 -#: ca18c257b4054fad931a19b59a8a4606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:110 +#: c723e855f50a4ec3abf45aaae2e02f45 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, the client " "performs an RSA public-key exchange with the server right after " @@ -233,8 +279,8 @@ msgstr "" "「is_enable_encrypto」:預設為「True」(當「True」時,用戶端在連線後立即與伺服器執行 RSA " "公鑰交換,並且所有後續訊息都已加密)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:83 -#: 0c6ecb6d7f504ef8a9a666bc2659a009 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:113 +#: 16c586bc40d94d6b9624812993e12579 msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -243,36 +289,71 @@ msgstr "" "``is_custom_keys``:預設為``None``(``[pub_key_path, pvt_key_path]`` " "清單使用使用者提供的金鑰對而不是預設的``~/.ssh``/產生的金鑰)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:86 -#: 96c8a6add16d4a999f8910133dad83b4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:116 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:88 -#: 4ea3ee5f013c46c98a380ed9fa7b6e64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:118 +#: 682f3bfe7fe0419493c15afe03553247 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "client would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:90 -#: a1d9d8ceda754443aef4e9dd2031e754 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:120 +#: 58fc5a7851094fcba7903d9e6cd4e8e7 msgid "" "``max_mem_buff``: Default is ``2048`` (kept for parity with the server " "class; the client's forward path does not read it today)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:94 -#: 930f7b1c90474a16b2dc7d13c41c238c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:123 +#: 08471d033b174cf395292c36068d4cb8 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "“max_custom_workers”:預設為“10”" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 +#: ff70e67852154092b227e2f05357a78d +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:125 +#: bd7d9bb9bbe14bc38eed56c574fc0987 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:127 +#: 5282067c345342d4872377ec83b3ba95 +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 +#: d10be044603c42e9a26b3164dcb7cb51 +msgid "" +"``is_auto_reconnect``: Default is ``False`` (``True`` makes " +"`start_TCP_client` reconnect after the connection drops and resume the " +"interrupted transfers, see :ref:`transfer-pause-and-reconnect`. The dead " +"session's socket is closed abortively first, so a configured " +"``client_port`` can be bound again — Windows refuses it otherwise)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:135 +#: 4b99048b2ec14a988fd9b83b23284d25 msgid "" "The TCP Client Setup API will initialize all the necessary parameters and" " resources for the TCP client." msgstr "TCP 用戶端設定 API 將為 TCP 用戶端初始化所有必要的參數和資源。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:97 -#: 221e218700a34372ae96eae9189831aa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 +#: b7da2a334a9543aa96178bddc8b6855c msgid "" "*Note: In the main class of the TCP client setup API, we initialize the " "`start_TCP_client` method to set up all functions which are needed in the" @@ -282,8 +363,8 @@ msgstr "" "*注意:在 TCP 用戶端設定 API 的主類別中,我們初始化 `start_TCP_client` 方法來設定 TCP " "用戶端所需的所有功能,包括連接到伺服器、處理傳入訊息和管理使用者輸入。 *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:103 -#: 00cb8ca5027d464f88e778a8f2a4faec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 +#: 0aa6b4133bf54878ad5d35aa8523ae88 msgid "" "*Note: By default ``TCP_Client_Base.__init__`` calls " "``start_TCP_client()`` to connect and enter interactive mode. If you set " @@ -294,8 +375,8 @@ msgstr "" "進行連線並進入互動模式。如果您設定“is_extend_command=True”,實例將不會自動啟動,您應該在準備好時手動呼叫“start_TCP_client()”。" " *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:109 -#: 4d8f352fa0be45e1b75d44727035e828 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 +#: 7a35992f8c7c410da60029bb06fb054a msgid "" "*Note: If you set ``is_wait_server=True``, the ``timeout`` parameter must" " be ``None``. The constructor will raise a ``ValueError`` if " @@ -304,8 +385,8 @@ msgstr "" "*注意:如果設定“is_wait_server=True”,則“timeout”參數必須為“None”。如果“is_wait_server”為“True”且“timeout”不是“None”,則建構函式將引發“ValueError”。" " *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:119 -#: 92cea23fb57c482cb1199cabd89af968 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 +#: 35b6f81f408041c4a7e650d3b92957d1 msgid "" "In the `start_TCP_client` method, we first attempt to connect to the " "server by calling the `connect` method. If the connection fails and " @@ -313,8 +394,8 @@ msgid "" "it will exit." msgstr "在`start_TCP_client`方法中,我們首先嘗試透過呼叫`connect`方法連接到伺服器。如果連線失敗並且“is_wait_server”為“True”,則用戶端將不斷重試;否則它將退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:124 -#: 2e529671abf848fd87771801ae4a3763 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:165 +#: d8e70dde1c62462cb4954eb1ceb50f3a #, fuzzy msgid "" "*Note: The client socket is created in the `connect` method (called by " @@ -325,8 +406,8 @@ msgstr "" "*注意:在`start_TCP_client`方法中建立的客戶端套接字是基於IPv4,並使用建立客戶端實例時提供的參數「self.host」和「self.port」。" " *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:129 -#: abe7c8d5d59b4a589ec6537a06a7333b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:170 +#: 80f69db837ec4e1d9bb90bc821019532 msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will either start the interactive input loop " @@ -334,16 +415,16 @@ msgid "" "input)." msgstr "其次,根據「self.is_input_command_in_console」參數,我們將啟動互動式輸入循環(「interactive_mode」)或簡單地保持連線處於活動狀態(無控制台輸入)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:134 -#: e6ad1c25ef6e409aa4dba10b44fbe7a4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 +#: 445af010e93f421099da8d8dd5212210 msgid "" "After that, if the interactive mode is enabled, the client will read user" " input from the console and send messages to the server until the " "connection is closed." msgstr "之後,如果啟用了互動模式,用戶端將從控制台讀取使用者輸入並向伺服器發送訊息,直到連線關閉。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:138 -#: c957271185064b21a0bc78265e007969 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:179 +#: 2d4020f99c3c4a4485815c383a0a4bfe msgid "" "*Note: There is a global variable ``self.running`` which is set to " "``True`` after the client successfully connects to the server. The " @@ -353,8 +434,8 @@ msgstr "" "*注意:有一個全域變數“self.running”,在客戶端成功連接到伺服器後,該變數將變為“True”。 " "“self.running”變數用於控制主接收循環,當客戶端關閉時它將變為“False”。 *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:144 -#: d055f0b3b19940be8b0549705d6cd3b5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:185 +#: e4de5ae390fc4c1c9a50703299f80356 msgid "" "The `connect` method will try to establish a TCP connection to the " "server. If a ``client_port`` is specified, the client will bind to that " @@ -365,47 +446,47 @@ msgstr "" "`connect` 方法將嘗試建立到伺服器的 TCP " "連線。如果指定了“client_port”,用戶端將在連線之前綁定到該本機連接埠。此方法將優雅地處理逾時和連接拒絕錯誤,特別是當啟用“is_wait_server”時。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:150 -#: 4615e65c81854301ac43f16a4d7e16b1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 +#: 17315c7599be4d2e8d8f62ad4c866eb3 msgid "" "When the connection is established, a background thread " "`receive_messages` is started to continuously read data from the server." msgstr "當連線建立後,會啟動一個後台執行緒receive_messages,不斷從伺服器讀取資料。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:154 -#: bace28ef9c5841ffac04669beeb4e56a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:195 +#: 26bc6f1cf62947c88fd9de780337d225 msgid "So what can the setup function do if the connection fails?" msgstr "那如果連線失敗的話setup函數可以做什麼呢?" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:156 -#: f89e08eff4f84bfba70ee321e26e218b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:197 +#: e7519cc6a4124a008a804ecbe9b10453 msgid "" "First, if the connection attempt times out, the client will either wait " "and retry (if ``is_wait_server`` is ``True``) or exit with an error." msgstr "首先,如果連線嘗試逾時,客戶端將等待並重試(如果「is_wait_server」為「True」)或錯誤退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:160 -#: fe3484d9a2b04f29944bc0d412d73536 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:201 +#: 2bcc61a302d34c7dbc18f9bcc7beba5a msgid "" "Secondly, if the server is not running (connection refused), the " "behaviour is the same: retry or exit based on ``is_wait_server``." msgstr "其次,如果伺服器未執行(連線被拒絕),行為是相同的:根據「is_wait_server」重試或退出。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:164 -#: 18131d4fd10c42d09e1eca9697bda2fb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:205 +#: c33c7409acd94d6b8f69e0f718e50c1f msgid "" "If any other socket error occurs, the client will print the error message" " and return ``False``, and the `start_TCP_client` method will call " "``sys.exit(1)``." msgstr "如果發生任何其他套接字錯誤,客戶端將列印錯誤訊息並傳回“False”,並且“start_TCP_client”方法將呼叫“sys.exit(1)”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:168 -#: 050d63fcb50c4053aba93e3d05dae63c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:209 +#: d78f849334b6404d8840b12839d05b8c msgid "For shutting down the client, the `close` method is defined as:" msgstr "為了關閉客戶端,“close”方法定義為:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:175 -#: c0860fa6e2c240e5a2a56b278f3369f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 +#: 4b23bb29324b408ca1a3c06128ede442 #, fuzzy msgid "" "In the `close` method, we set ``self.running`` to ``False``, free any " @@ -414,8 +495,8 @@ msgid "" "client socket. This ensures a clean disconnection." msgstr "在“close”方法中,我們將“self.running”設為“False”,透過呼叫“free_port”釋放所有已指派的端口,然後關閉客戶端套接字。這確保了乾淨的斷開。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:180 -#: 6a703de12132431982451a11b661b4d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:221 +#: 510de5709a444a0c8296717f1e8bed2b msgid "" "``close`` also wins against a connection attempt that is still in flight:" " if it runs before ``connect`` puts the socket up, that call closes the " @@ -423,118 +504,118 @@ msgid "" "client." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:184 -#: ae54449f52b0491aaeb0c11de7749e4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:225 +#: c67deae0af3b4ab9bf572198122cc09d msgid "" "*Note: The `free_port` method works similarly to the server side, " "releasing any manually allocated ports if manual allocation mode is " "enabled.*" msgstr "*注意:“free_port”方法的工作方式与服务器端类似,如果启用了手动分配模式,则释放任何手动分配的端口。 *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:191 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 +#: fbb5ed3c54a34df4bc6bf8f9688e295c msgid "TCP Client handling information API" msgstr "TCP客戶端處理資訊API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:193 -#: 57895cdce9c1426289087c4448ac2325 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 +#: 7c21a424a7774ad6b4a257c5ad645db4 msgid "" "The client handling information API documents the core TCP client methods" " that manage the server connection, receive raw data, and send messages." msgstr "客戶端處理資訊 API 記錄了管理伺服器連線、接收原始資料和傳送訊息的核心 TCP 用戶端方法。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:198 -#: f9294ef58d274a9ba6b8edbec8c07606 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:239 +#: b0fc366cad48412999e75faf81120a6e msgid "" "Unlike the server, the client maintains only a single connection and does" " not provide broadcast or ``send_msg_to_specific_client`` methods." msgstr "與伺服器不同,客戶端僅維護單一連接,且不提供廣播或“send_msg_to_specific_client”方法。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:208 -#: 67e867cdfba84730bef1ad32d859ea24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:249 +#: ff50f500c3804fdb9562b5e9ae1a3482 msgid "" "`receive_messages` is the main background thread function in " "``TCP_Client_Base``. It is started after a successful connection and is " "responsible for:" msgstr "`receive_messages` 是 `TCP_Client_Base` 中的主要後台執行緒函數。它在連接成功後啟動,負責:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:212 -#: 17684d40e43543e88db7135b66b26e09 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 +#: 364f1d2b080843518fee4bcc0e74a8ca msgid "" "continuously receiving raw bytes from the server socket using " "`receive_message`" msgstr "使用“receive_message”連續從伺服器套接字接收原始位元組" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:213 -#: dc882668c1244dc3b7e57b07ad08612a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:254 +#: cf3b7cf194ec42919b87199c4586dfc4 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "緩衝傳入數據,直到換行符終止的訊息完成" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:214 -#: 707313e8051245478059aa883da7459f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:255 +#: ad695c0a732a4ad78cdd07c79f2d5dc3 msgid "splitting and processing each message line-by-line" msgstr "逐行拆分並處理每個訊息" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:215 -#: e9edeedb0eb64a278e03efa5169a36f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:256 +#: 387a605c25f8407d86b77c452ded00f7 msgid "" "routing special commands (starting with ``/``) that come from the server " "to `handle_server_command`" msgstr "將來自伺服器的特殊命令(以“/”開頭)路由到“handle_server_command”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:216 -#: 0ab735831831448a88f60538f859ce4e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:257 +#: d1729cfa1e314df68d3e7ce7e553f3a5 msgid "" "printing every received line to the console with a ``[server]`` prefix " "(command lines included, after ``handle_server_command`` has processed " "them)" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:218 -#: e09f439632994d0fadb0ae8f58eef0cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:259 +#: 083b077c5c1845338f11ae62bace15b5 msgid "" "unwrapping forwarded lines (``/send_msg_from``) so a message another " "client forwarded here is attributed to its author" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:220 -#: 166f9028c1cc41ff94be560b77e17504 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:261 +#: 1dd20cbdeac3480bbaec2f7ae6f1f1ed msgid "" "handling connection resets and other socket errors, and cleaning up when " "the server closes the connection" msgstr "處理連線重設和其他套接字錯誤,並在伺服器關閉連線時進行清理" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:229 -#: db2e058412bc44d6ba39131b3b40a7ac +#: ../../source/Network_APIs/TCP_Client_APIs.rst:270 +#: e890dee4fb944eeaa9e6b2cf3cd9047a msgid "" "In `handle_server_command`, the client processes built-in commands sent " "by the server, such as:" msgstr "在`handle_server_command`中,客戶端處理伺服器所傳送的內建指令,例如:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:232 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:273 +#: b957ec8457f34618802ea0441634a894 #, fuzzy msgid "" "``/client_alloc_port_range``: configures the client's manual port " "allocation range from the line the server sends it on connect." msgstr "``/client_alloc_port_range``:根據伺服器廣播設定客戶端手動連接埠分配範圍。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:234 -#: 2558e50f505a4b6ca51c7a44fa9ad957 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:275 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/server_file_transfer_port``: receives the file transfer port assigned " "by the server for an ongoing file operation." msgstr "``/server_file_transfer_port``:接收伺服器為正在進行的檔案操作分配的檔案傳輸連接埠。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:236 -#: 5147df6f2f794cf2949b7cef1ed24791 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:277 +#: 4eb4fe22d5db4b56b622dfd29459c3b7 msgid "" "``/file`` and ``/file_folder``: handle file transfer requests initiated " "by the server (server-to-client transfers)." msgstr "``/file`` 和 ``/file_folder``:處理伺服器啟動的檔案傳輸請求(伺服器到客戶端傳輸)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:238 -#: 4755bb63eb0e4f8cbf481633417fc3c7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:279 +#: 3c550345aa484cb8bc44681842864044 msgid "" "``/crypto_mode``, ``/crypto_key_exchange``, ``/crypto_key_exchange_ack``," " ``/crypto_reject``, ``/crypto_pub_key``, ``/crypto_ready``: the " @@ -542,15 +623,15 @@ msgid "" "the connection." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:242 -#: f7cbe268c5e84987aec0bb18a0a81aa7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 +#: 31a62335177b49a19f708aee2aa5b0b1 msgid "" "``/forward_upload``, ``/pause_trans``, ``/start_trans``, " "``/forward_error``: forwarding and transfer-control messages." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:245 -#: d89b63a85c3d402fbb0df0f75edc4736 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:286 +#: b4c3c6ea61f344b8a3d3baf6b659d9c7 msgid "" "If you have registered custom commands using the command extension API, " "`handle_server_command` will also check if the incoming command matches " @@ -559,48 +640,48 @@ msgstr "" "如果您使用命令擴充 API " "註冊了自訂命令,「handle_server_command」也會檢查傳入命令是否與任何已註冊的處理程序相符並相應地執行它。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:250 -#: 943d4fb64bad477f969403f360288769 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 +#: 4b6cc84b10d34254b7e6e0d7ae226ddc msgid "" "*Note: For more details of the command extension API, see the :ref:`tcp-" "client-command-api` section.*" msgstr "*注意:有關命令擴展 API 的更多詳細信息,請參閱 :ref:`tcp-client-command-api` 部分。 *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:253 -#: c2b4ba39cca64ea7ab62a59d016f0544 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:294 +#: b9ff85e2f76d4c1697602ebf69fed3a8 msgid "" "Closing the connection when the server goes away is not part of " "`handle_server_command`: it is `receive_messages` that reports the " "disconnect and clears ``self.running``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:265 -#: 9312fc5109a547d588d98c16a9b79c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:306 +#: 4376aa47bf63490998e7008547d0c86f msgid "" "`receive_message` is identical to the server version: it reads up to " "``msg_length`` bytes from the given socket and returns the raw byte " "payload. Message decoding and newline framing are handled by the caller." msgstr "“receive_message”與伺服器版本相同:它從給定套接字讀取最多“msg_length”位元組並返回原始位元組有效負載。訊息解碼和換行幀由呼叫者處理。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:278 -#: 7a64cec6a8084261a443f57f7032a5bb +#: ../../source/Network_APIs/TCP_Client_APIs.rst:319 +#: 29b51f413be748e4b101bf498e593ef2 msgid "" "`send_message` sends data from the client to the server. It verifies the " "client is still running and the socket is valid, then:" msgstr "`send_message` 將資料從客戶端傳送到伺服器。它驗證客戶端仍在運行並且套接字有效,然後:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:281 -#: 9a5d3a7c041b47d68b80186e09492467 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 +#: e4158824d7b04b37a0f75c9ff67eab45 msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "接受“str”和“bytes”訊息負載" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:282 -#: c4247339bf084481af72ba498d8f9bcd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:323 +#: ea9158c1798941cb9df13f5a01b14f69 msgid "trims string payloads and appends a newline if missing" msgstr "修剪字串有效負載並在遺失時附加換行符" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:283 -#: 55c0dfde024b4bdea57da54d86297dbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:324 +#: 0fb0befad2844821a59b8c5c686e1c39 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -610,59 +691,60 @@ msgstr "" "當套接字處於加密模式時(公鑰交換已完成),明文使用“_VALID”標記進行簽名,RSA-" "OAEP使用伺服器的公鑰加密,base64編碼並以換行符號結尾,而不是以明文形式發送" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:287 -#: 6e2bbc8edbad40568dfe3eae781ab27c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:328 +#: e8d7a04011e74da18b274e1ad3ca3ab8 msgid "encodes string payloads as UTF-8" msgstr "將字串有效負載編碼為 UTF-8" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:288 -#: 40b2936e9c6b4325b19b27f83932cf83 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:329 +#: 08c9e9aca2334e67b5051b42cc7dbad0 msgid "sends the complete message with ``client_socket.sendall(data)``" msgstr "使用“client_socket.sendall(data)”發送完整訊息" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:289 -#: 9ab8a09e5ca4416abd843cf1612f20a2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:330 +#: 99b4f8d523b2406499891c514befc372 msgid "" "returns ``True`` on success, otherwise logs the error and returns " "``False``" msgstr "成功時傳回“True”,否則記錄錯誤並傳回“False”" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:291 -#: 0eb535b8380441869c432950417def80 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:332 +#: 18101652b1e34996866324fce0aa8a4d msgid "" "The client also provides an interactive input loop (`interactive_mode`) " "that reads user input from the console and sends messages to the server." msgstr "客戶端還提供互動式輸入循環(“interactive_mode”),用於從控制台讀取使用者輸入並將訊息發送到伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:298 -#: 1ae2846f419343d7ba87a11ad0f2d13b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:339 +#: fbb5ed3c54a34df4bc6bf8f9688e295c #, fuzzy msgid "TCP Client inbound event listener API" msgstr "TCP客戶端檔案傳輸API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:300 -#: 8b78c521249c4604933d30cfc99cc7a9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:341 +#: 15461ca186ed497083b901e65a3b33d1 msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:310 -#: 2f13976d605042919a1a19e346d85bd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:351 +#: 0d916f8d3eaf4336b5be87a5faf153a3 msgid "" "``add_message_listener`` registers ``listener(sender_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to `handle_server_command` instead). ``sender_id`` is the author's " -"``\"ip:port\"`` — for a message another client forwarded here through the" -" ``/send_msg_from`` envelope it is the forwarding client, and it is " -"``None`` for a direct push from the server. ``add_file_listener`` " -"registers ``listener(client_id, full_path, name, size, command)`` and " -"fires after a file sent by the server has been fully written to disk. " -"Both listeners run on a protocol thread, so they must not block, and an " -"exception inside a listener is logged and swallowed. The ``remove_*`` " -"counterparts unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:322 -#: 75d993e34b944014be1b88aee03a4f9c +"every inbound line, commands included, so a listener observes all inbound" +" traffic; a message another client forwarded here through the " +"``/send_msg_from`` envelope is reported as its payload. ``sender_id`` is " +"the author's ``\"ip:port\"`` — the forwarding client for such a forwarded" +" message, and it is ``None`` for a direct push from the server. " +"``add_file_listener`` registers ``listener(client_id, full_path, name, " +"size, command)`` and fires after a file sent by the server has been fully" +" written to disk. Both listeners run on a protocol thread, so they must " +"not block, and an exception inside a listener is logged and swallowed. " +"The ``remove_*`` counterparts unregister a listener and ignore unknown " +"ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:364 +#: 196be233dc00497a94ee87f9999a9897 msgid "" "Received messages and events are also stored per sender socket in " "``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -671,13 +753,13 @@ msgid "" "``network_api/.Flow`` and cleared; ``close`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:331 -#: 6535dcf4080e4090bf82df637e452cc6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:373 +#: 6d52a0605748445694e0f4b1a6c52ea7 msgid "TCP Client encrypted channel API" msgstr "TCP客戶端加密通道API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:333 -#: e2dbda95b2ff4483b8b71394ae4b83c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:375 +#: 14a20833906f4e18b92856c3e98a8886 msgid "" "When the client is created with ``is_enable_encrypto=True`` (the " "default), it performs an RSA public-key exchange with the server " @@ -686,13 +768,13 @@ msgstr "" "當使用「is_enable_encrypto=True」(預設值)建立用戶端時,它會在連線後立即與伺服器執行 RSA " "公鑰交換,然後再對任何訊息內容進行加密。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:338 -#: 411e33f708ba4961aaf9073beffe7404 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:380 +#: 46166a685e064cd29ad7701d3a352fc4 msgid "Key material" msgstr "關鍵材料" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:340 -#: 89d96a4b9abe4ccd98bdd72682b94a56 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:382 +#: ffdef9bf79aa41e6a401b0a16c24a674 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -704,8 +786,8 @@ msgstr "" "私鑰存在於「~/.ssh/id_rsa」中,則它會被重複使用;否則,將在「network_api/.Flow/pvt_key」(「client_priv.pem」/「client_pub.pem」)中產生新的" " RSA-2048 RSA對。交換的公鑰始終來源自私鑰,因此會自動選取旋轉的「~/.ssh」對。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:345 -#: 74eb9aca2b1849e48138cbea3e76a39d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 +#: 2c27cfc2e8ce47fb8732aec1e00d3479 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -716,8 +798,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:352 -#: e935794dae5f4c2682336e72732afec3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:394 +#: 425ba3d582c3490b9375d99baa9b61e6 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -728,8 +810,8 @@ msgstr "" "可以使用「is_custom_keys = [pub_key_path, " "pvt_key_path]」強制使用者提供的金鑰對:兩個檔案必須存在,解析為 PEM 並相互配對(使用公鑰加密的探針必須使用私鑰解密);" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:357 -#: 72a43fff94f04914848603d6ede43cfd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:399 +#: 696441cc5dd44fc4af958c547c8b6b90 msgid "" "Public keys received from the server are cached in " "``network_api/.Flow/pub_key`` as ``server__.pem`` (the server " @@ -739,13 +821,13 @@ msgstr "" "從伺服器接收的公鑰以“server__.pem”形式快取在“network_api/.Flow/pub_key”中(金鑰來自的伺服器端點;“:”被替換為“_”,因此" " IPv6 文字在每個平台上都是安全的,包括 Windows)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:363 -#: a4903fbcbc6f4c9d93c8fc3066fcc1c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:405 +#: 2a81e756d1c947d384d20dbbbe5d6d52 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM 身份檢查 (TOFU)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:365 -#: e30dc3b276654ea2b6ec48793d8df984 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:407 +#: 7a915eef76594c3ea715adb845fcabc6 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -758,31 +840,31 @@ msgstr "" "每個連線都以明文形式重新交換公鑰,並且每一方都會在「network_api/.Flow/pub_key/pub_key.json」中記錄對等點:金鑰是「(ip," " port)」(對等點可到達的端點的 Python 元組),值是「[<公鑰的 sha256>, <公鑰 PEM]」。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:372 -#: 247a92c41f0d45ed9a5f8ad2d12bca2e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:414 +#: 4d56fbd290604113a600a56d8e89cdfb msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "來自端點的首次連線:金鑰被記錄並受信任(首次使用時信任)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:374 -#: 7adc6b725e7244df8bc1b861b4cec80c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:416 +#: a6be8828e0594ddc8aa71229934cc73d msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " "``(ip, port)`` instead of being duplicated." msgstr "稍後的連線顯示*相同*金鑰:已接受。如果端點變更(動態 IP / 使用者變更的連接埠),記錄將會移至新的「(ip,連接埠)」而不是重複。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:377 -#: ba6d10fef7fb42cd8dd6518c415762d7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 +#: fda350faac9a4efd82575a386fc929c0 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is received and " "the client closes)." msgstr "稍後的連線為已記錄的端點提供*不同的*金鑰:連線被拒絕(收到“/crypto_reject”並且用戶端關閉)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:381 -#: 7f2ec5e5c2604098906635697130c4fd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:423 +#: 9d62655e00324c518633c6c1d615d515 msgid "" "The client-side record is keyed by the fixed server address, so a server " "that changes its public key (for example a MITM substitution) is always " @@ -792,13 +874,13 @@ msgstr "" "客戶端記錄由固定伺服器位址作為金鑰,因此更改其公鑰(例如 MITM " "替換)的伺服器在以後的連線中始終會被拒絕。若要重置信任(輪換金鑰、新伺服器),請刪除「pub_key.json」條目(或整個檔案)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:387 -#: 9a08bf51aea742de8d0a0f351d055b3a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:429 +#: 799c58ee59b0416688562166f58a14c1 msgid "Handshake" msgstr "握手" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:389 -#: 879e1be6d2de4859bc0777d1cd1682f8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:431 +#: 6f92afe3b8314a9985b62fe55cdeee70 #, fuzzy msgid "" "Right after connecting, the client announces its encryption mode with a " @@ -806,47 +888,75 @@ msgid "" "server's answer; a mode mismatch closes the connection. It then sends a " "plaintext ``/crypto_key_exchange `` greeting; the server " "replies with ``/crypto_key_exchange_ack " -"``. Both sides then push their public key files over the file-" -"transfer mechanism (plaintext) and TOFU-check the received key. Both " -"sides switch to encrypted mode only after ``/crypto_ready`` has been " -"received from the peer (so plaintext and ciphertext never interleave on a" -" connection). On later connections the keys are re-exchanged and TOFU-" -"checked again; the exchange is never skipped, only the identity check " -"short-circuits for known keys. Public-key pushes are only accepted while " -"a handshake is in progress, so an arbitrary unauthenticated server cannot" -" poison the registry." +"``. Both (plaintext) and TOFU-check the received key. Both sides " +"switch to encrypted mode only after ``/crypto_ready`` has been received " +"from the peer (so plaintext and framed traffic never interleave on a " +"connection), then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted while a handshake is in progress, so an " +"arbitrary unauthenticated server cannot poison the registry." msgstr "" "用戶端在連線後立即發送明文「/crypto_key_exchange」問候語;伺服器回覆``/crypto_key_exchange_ack " " " "``。然後,雙方透過文件傳輸機制(明文)推送其公鑰文件,並對收到的金鑰進行豆腐式檢查。只有在從對等方收到「/crypto_ready」後,雙方才會切換到加密模式(因此明文和密文永遠不會在連線上交錯)。在以後的連接中,密鑰將被重新交換並再次進行" " TOFU 檢查;交換永遠不會被跳過,只有已知密鑰的身份檢查會短路。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:406 -#: a36303a34b174e6a8c4a421f297e4452 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:451 +#: a501267a3c9848e6aac40eb13359da87 msgid "Replay protection" msgstr "重播保護" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:408 -#: dd11c43faac347858ff85f846d7af6d1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 +#: cde1f1712c904c89aa5838bc54c715b6 msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." msgstr "" -"握手交換隨機會話隨機數,線路上的每條加密線路都攜帶它加上每個連接的序號:``||``。接收方丟棄隨機數與目前會話不符的行(從舊連接重播的密文)或其序號不是預期的行(會話內重播的密文/亂序);當套接字在(重新)交換後切換到加密模式時,兩個計數器都會重置。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:417 -#: ddfd9d5832b541ba81de53f2f9abd91b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:469 +#: 51478387b6dd4b2e9f7a3d10f72a8b90 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 +#: a47f9db0c3674a12ab6d3ab5d056a8c4 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:483 +#: 6740137a28b84e5dbb3f85e8d58d32b5 msgid "Decode verification and key rotation" msgstr "解碼驗證和金鑰輪換" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:419 -#: 2f8d9ddc0f434f0b98331fc3c14f710b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 +#: 8445bf9265124e38a642f9d46fc43c36 msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -863,22 +973,28 @@ msgstr "" " TOFU 檢查:金鑰未變更的對等點將再次被接受,而為記錄的端點提供「不同」金鑰的對等點將被拒絕(請參閱上面的 TOFU " "部分)。故意輪換金鑰對的使用者必須刪除對等端過時的「pub_key.json」條目(或整個檔案)才能重新信任新金鑰。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:430 -#: 3b373e99ee2c4aff93e808c206dfb3f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:496 +#: 5698fde8f08b4be3a059d92a69ae3459 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures the connection is closed instead of re-" "exchanging, so a garbage-injection or persistent-mismatch storm cannot " -"spin the loop forever. A successful decryption resets the counter." +"spin the loop forever. Genuine peer traffic (messages and commands other " +"than the protocol's own handshake/coordination lines) resets the counter." +" Frames the peer had already sent when this side dropped out of encrypted" +" mode are stale: they cannot be authenticated any more, so they are " +"consumed and dropped — they neither surface as messages nor reset the " +"counter." msgstr "重新交換是斷路的:在「MAX_DECODE_FAILURES」(3)連續解碼失敗之後,連接被關閉而不是重新交換,因此垃圾注入或持久不匹配風暴不能永遠旋轉循環。成功解密會重置計數器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:438 -#: aaefbbdc89554770aebdf60c16950f0f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:508 +#: 6569277ee0b644488685204e70c3e425 msgid "TCP Client command API" msgstr "TCP 用戶端命令 API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:440 -#: 22612be28f9d4da5b01258de1c7520f4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:510 +#: b2ab9f46d6b14c8eaa97512fd117c6db msgid "" "The client supports both built-in commands that the user can type in the " "console, and a command extension API similar to the server. The main " @@ -888,8 +1004,8 @@ msgstr "" "客戶端既支援使用者可以在控制台中鍵入的內建命令,也支援類似伺服器的命令擴充 " "API。傳入伺服器指令的主要入口點是“handle_server_command”,而使用者輸入的指令在“interactive_mode”下處理。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:446 -#: 5607f70cfddc4466946bc9082ce494ab +#: ../../source/Network_APIs/TCP_Client_APIs.rst:516 +#: 5e296796f3694cdfbf48c8538979bb7f msgid "" "The client supports two modes of operation: interactive console input " "(when ``is_input_command_in_console`` is ``True``) or programmatic " @@ -898,31 +1014,31 @@ msgstr "" "用戶端支援兩種操作模式:互動式控制台輸入(當 is_input_command_in_console 為 True 時)或程式控制(當為 " "False 時)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:450 -#: bfa689507e214d7a961f1042698850ce +#: ../../source/Network_APIs/TCP_Client_APIs.rst:520 +#: 0261c3323c4248e3bfb846d5751da36f msgid "Built-in client console commands (user-typed) include:" msgstr "內建客戶端控制台指令(使用者輸入)包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:452 -#: 9a2bcb83868f473aae1fa0090af2dd49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:522 +#: d466b066b3654e7183cf72f86523bcd1 msgid "``/quit``: sends a quit message to the server and closes the connection." msgstr "``/quit``:向伺服器發送退出訊息並關閉連線。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:453 -#: 84be485738544bd98d7e0d2f49415cda +#: ../../source/Network_APIs/TCP_Client_APIs.rst:523 +#: 3d22aacfa1914a879be55a3518fb2a7e msgid "" "``/send_msg ``: sends the second token of the line as a chat " "message (``send_message_to_server`` drops the command name and sends only" " the next token)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:456 -#: 6bb0b49ebc5743fe9332f66948330822 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 +#: 16b438ba77f945d2a68bb24f97a69ef5 msgid "``/file ``: starts a file transfer from client to server." msgstr "``/file ``:啟動從客戶端到伺服器的檔案傳輸。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:457 -#: eb7e88c4607340ba8795bacb617ae98a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:527 +#: 65a2f7cca5684f21ae85deaf2675b2fa #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files from client " @@ -932,37 +1048,37 @@ msgstr "" "``/multiple_file " "...``:從客戶端發送多個檔案到伺服器(每個檔案在其自己的線程中,遵守信號量限制)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:460 -#: 98dda85c8e2a4623a9dc2d39643cddbc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:530 +#: 0cb1732f55e8499ab36b6923ed56a8ec msgid "" "``/file_folder ``: sends an entire folder from client to " "server, preserving the directory structure." msgstr "``/file_folder ``:將整個資料夾從客戶端傳送到伺服器,保留目錄結構。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:462 -#: 1f2e6b52be7f4875aa8434ff22117ee0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:532 +#: f8d95f978af24a0d8056fc369d555f5f msgid "" "``/multiple_file_folder ...``: sends multiple folders" " from client to server." msgstr "``/multiple_file_folder ...``:將多個資料夾從客戶端傳送到伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:464 -#: 48811f3665104578b8921efe71ada53a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:534 +#: c3477f2df53d499db3c6a9b41f8bdedf msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands (client-only; the server refuses " "them)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:468 -#: 3fe8e4c73ecc42e98bde402ff3858c64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:538 +#: d6c13262c84f4ae2a43371ee4e09cfad msgid "" "Ctrl-C and EOF close the connection, send a final ``/quit`` and wait 0.5 " "seconds before the process ends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:471 -#: c330e7622ffc46a19b41f3e6394c3dc8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 +#: 7971066cb1de4bc2b8047248fa93d58e msgid "" "*Note: Unlike the server, the client does not have built-in ``/help``, " "``/time``, or ``/clients`` commands because those are typically handled " @@ -972,8 +1088,8 @@ msgstr "" "*注意:與伺服器不同,客戶端沒有內建的“/help”、“/time”或“/clients”命令,因為這些命令通常由伺服器處理。客戶端的``/help``命令沒有執行;使用者應參閱伺服器文件以取得可用命令。" " *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:477 -#: f7ea97482c86419cb7e1e5db99cd79c1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:547 +#: 44cf1d07758f4fa89eb47d9aad2369a5 msgid "" "A user-typed line that is not built-in and not a registered custom " "command is sent to the server as a chat message, and the client logs " @@ -981,66 +1097,74 @@ msgid "" "with that wording too)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:482 -#: 677fc4a9eabd4d5ab97bf0e2e73b05ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:552 +#: 7f463379f38f44558c3121e202f9343b msgid "" "*Note: a custom command is matched against the first token of the line, " "so a handler registered for ``/mycmd`` runs when the user types ``/mycmd " "...``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:485 -#: 1325358de66e4303bb8f9ff817415890 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:555 +#: ae962d51828a4e859fd9080b6eb9ec88 msgid "The command extension API for the client is defined as:" msgstr "客戶端的命令擴充 API 定義為:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:494 -#: 24f976022e4245e0aa95c2cf112854c5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:565 +#: cfa1714f672d4103bae0af84db5a1d63 msgid "" "The arguments of the `register_command` function are the same as on the " "server side:" msgstr "`register_command` 函數的參數與伺服器端相同:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:497 -#: 087de666d0cb46b39328508976a7dc92 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:568 +#: 2f936e153d6f4587b918adf94d6ba438 msgid "" "``command_name``: The name of the command to register (should start with " "a slash, e.g., ``/mycmd``)." msgstr "``command_name``:要註冊的命令的名稱(應以斜槓開頭,例如``/mycmd``)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:499 -#: 3acea6e2461e40f9b02b90154cb62c00 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 +#: c19aa473ddf5488cbe8b5039b68e08cf msgid "" "``handler``: The function to call when the command is received. The " "handler must accept three parameters: ``client_socket``, " "``client_address``, and ``command``." msgstr "``handler``:收到指令時呼叫的函數。處理程序必須接受三個參數:「client_socket」、「client_address」和「command」。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:501 -#: 60a8ef01850843b48c37e1ce0248d247 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 +#: d327d91dee274ac1951b18ee3700c15a msgid "" "``where_to_run``: Specifies where the command should be executed. Valid " "values are ``\"server\"`` (command sent from the server) or " "``\"client\"`` (command typed in the client's console)." msgstr "``where_to_run``:指定應執行指令的位置。有效值為“伺服器”(從伺服器發送的命令)或“客戶端”(在客戶端控制台中鍵入的命令)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:503 -#: 0a59b9453a5145ffa92a1e91741cfa49 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:574 +#: 17b9e2d9c50344bdb8e704423df3c4c8 msgid "" "``run_in_thread``: A boolean indicating whether to run the handler in a " "separate thread from the thread pool." msgstr "「run_in_thread」:一個布林值,指示是否在執行緒池中的單獨執行緒中執行處理程序。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:506 -#: 73925e7106344a879ba8a7e1f4ea6408 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:577 +#: a4fcfb0b0f89415fa269eccf366b2539 msgid "" "It returns ``False`` when ``where_to_run`` is neither ``\"server\"`` nor " "``\"client\"`` (nothing is registered then); on success it returns " "``None``." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:509 -#: e9b4b0ddbfd143759ab38205955ff2de +#: ../../source/Network_APIs/TCP_Client_APIs.rst:580 +#: 55e17f10381d4c6e9c13c484a6d7b2f7 +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code, on the client as on the server; the command's first token " +"selects it, exactly as it does for a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 +#: 889fe9598c0045ccaee7de4e93d59f8e #, python-brace-format msgid "" "*Note: The client stores registered commands in the same structure as the" @@ -1051,16 +1175,16 @@ msgstr "" "*注意:客戶端以與伺服器相同的結構儲存註冊命令:``self._custom_handlers = [{}, {}]``,其中索引 0 " "用於來自伺服器的命令,索引 1 用於在客戶端控制台中鍵入的命令。 *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:514 -#: 87c31576643d4e328b32b14b69b4f818 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:589 +#: 9a244a7eb66d4c0c9666537c17e6f3ac msgid "" "The client also provides the `submit_task` method to submit functions to " "its internal thread pool executor, and `_execute_custom_handler` to " "safely execute registered handlers with error handling." msgstr "用戶端還提供「submit_task」方法來將函數提交到其內部執行緒池執行器,並提供「_execute_custom_handler」來安全地執行帶有錯誤處理的註冊處理程序。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:519 -#: e64628a99ba249f8acef54a08b182c79 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:594 +#: 4cbf4048c25443dda40d622c49a8e26e #, fuzzy msgid "" "The `submit_task` method works identically to the server version: it " @@ -1070,21 +1194,21 @@ msgid "" "the call finishes)." msgstr "「submit_task」方法的工作方式與伺服器版本相同:它向客戶端執行緒池提交一個可呼​​叫函數,使用信號量將並發限制為「max_custom_workers」。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:526 -#: e8f3baf910cb4b2497cb6f6eab9053e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:601 +#: 3a2bd1984dd14769b92c6e40c6ad357c msgid "Temporary server and client creation" msgstr "臨時伺服器和客戶端創建" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:528 -#: 26cf9b3fd35d4af993c53f9a8e4bffb6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:603 +#: 0c9b9ad8c6ca4f679f8e54fb58940d3e msgid "" "The client also includes temporary TCP server and client creation APIs. " "They are similar to those in the server class but use `self.client_host` " "as the local binding address." msgstr "客戶端還包括臨時 TCP 伺服器和客戶端建立 API。它們與伺服器類別中的類似,但使用 self.client_host 作為本地綁定位址。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:541 -#: 6fb3cae805964394bf0864814b4b8ecd +#: ../../source/Network_APIs/TCP_Client_APIs.rst:616 +#: 03e3fc356d234c01a0bd94bad68b8ddc #, fuzzy msgid "" "`create_temporary_server` binds to ``(self.client_host, port)``. If " @@ -1097,8 +1221,8 @@ msgstr "" "port)``。如果“port”為“None”,它將呼叫“self.palloc()”來取得連接埠(在手動模式下)或返回“0”(作業系統分配)。它傳回一個元組「(port," " server_thread, stop_event)」。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:558 -#: 8ab44b7d114a4eca8079a87b61ca219f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:633 +#: 61b63d2c156f4512aead02cbbfe0569e #, fuzzy msgid "" "`create_temporary_client` connects to the specified server. If " @@ -1110,51 +1234,51 @@ msgstr "" "`create_temporary_client` " "連接到指定的伺服器。如果給了“bind_port”,它將綁定到“(self.client_host,bind_port)”。如果“bind_port”為“None”,它將透過“self.palloc()”取得連接埠並自動綁定。它傳回一個元組``(client_sock,recv_thread,stop_event)``。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:564 -#: d5a66d0848e24412a1e121fba226cff8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 +#: a528285ae2714861bf6162938ad1aa0a msgid "" "These methods allow the client to act as a temporary server or to spawn a" " separate client connection for auxiliary tasks (such as file transfers)," " without interfering with the main connection." msgstr "這些方法允許客戶端充當臨時伺服器或為輔助任務(例如檔案傳輸)產生單獨的客戶端連接,而不會幹擾主連接。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:570 -#: 16bd0374c6194f4b9bd2db749597217f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:645 +#: 46a7a0338f5040f38903a61af8ff8ae5 msgid "TCP Client console commands (interactive mode)" msgstr "TCP 用戶端控制台命令(互動模式)" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:572 -#: dbe05db8944f49818decf56adb4855b6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:647 +#: 8a93646c1be14bb8bfcb5be5140f1572 msgid "" "When the client is started with ``is_input_command_in_console=True`` (the" " default), the `interactive_mode` method is invoked. This method reads " "lines from standard input and processes them." msgstr "當客戶端以“is_input_command_in_console=True”(預設值)啟動時,將呼叫“interactive_mode”方法。此方法從標準輸入讀取行並處理它們。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:576 -#: eea6d19cd2f44de6ae2bd67081f49b5a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:651 +#: 5370ea52c70741728cc72ae1618e65e8 msgid "Supported console commands (user-typed) include:" msgstr "支援的控制台命令(使用者輸入)包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:578 -#: 3d1b84c153974f14bdd57c17a892a158 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 +#: 3ee645c39b844b1e8b14a1eb54bef876 msgid "``/quit``: closes the connection and exits the client." msgstr "``/quit``:關閉連線並退出客戶端。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:579 -#: ee6c762b67fa4e6d833c4a6e5c90dba3 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:654 +#: f84404f7844d4779af2e6030e795b5d0 msgid "" "``/send_msg ``: sends the second token of the line to the " "server as a chat message." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:581 -#: 50b34e795f4a4d1595f8a2f6c1ebfad5 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:656 +#: c34b32925f024797841232729eca131e msgid "``/file ``: sends a single file to the server." msgstr "``/file ``:將單一檔案傳送到伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:582 -#: d90b52a3886c48c1b86fe1d4a08adb11 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:657 +#: 739e72b7a06a4eefa6cdd1a952d3d781 #, fuzzy msgid "" "``/multiple_file ...``: sends multiple files to the " @@ -1163,44 +1287,44 @@ msgstr "" "``/multiple_file ...``:同時傳送多個檔案到伺服器(受``max_thread_num`` " "限制)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:583 -#: 66d2f7d1d87847e39e4172ae789b6a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:658 +#: d9421edab02e4b33850db50a0011ad16 msgid "" "``/file_folder ``: sends an entire folder to the server, " "recursively." msgstr "``/file_folder ``:遞歸地將整個資料夾傳送到伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:584 -#: 321bde30af944560b349b5dd6a162a7f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:659 +#: efd08f6cefcd4f44bcd4ff0687cee8bc msgid "" "``/multiple_file_folder ...``: sends multiple folders" " to the server." msgstr "``/multiple_file_folder ...``:將多個資料夾傳送到伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:585 -#: 9feff7033be8445599773701f51926df +#: ../../source/Network_APIs/TCP_Client_APIs.rst:660 +#: ed70094fabb34d46afadb56fd5c7c37d msgid "" "``/forward_file``, ``/forward_folder``, ``/forward_send_msg``: the " "forwarding extension's console commands." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:587 -#: 6489b5a0fb2948748f0f1bd5f303c779 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:662 +#: 1dc2bd43fd56402785fb76b3895b03b2 msgid "" "Any other non-empty line is sent as-is to the server — the same path chat" " text takes." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:591 -#: 3295a0d774d0473da7c5d7405d72abd8 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:666 +#: d72b6516a43b4f26bb5750604f41ff74 msgid "" "The client does not have a built-in ``/help`` command. Please refer to " "the server's help for available commands (e.g., by typing ``/help`` after" " connecting to the server)." msgstr "客戶端沒有內建的“/help”指令。請參閱伺服器的說明以取得可用命令(例如,在連接到伺服器後鍵入“/help”)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:595 -#: dd63bf8cfd3641c0be9adad9b06aa8e9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:670 +#: e6081a66251a4a57bc5724dccb8c852b msgid "" "A line registered with ``register_command(..., where_to_run=\"client\")``" " runs when its first token matches a registered name; handlers registered" @@ -1208,84 +1332,87 @@ msgid "" "server sends." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:600 -#: 7efd09ba06ba4067b03810eb838caa24 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:675 +#: 4befe76529e04e859f9422d8ebe3921a msgid "" "*Note: The client logs ``Unknown server command: `` for any line it" " did not recognise, including plain chat text, because those lines take " "the same fallback path.*" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:604 -#: 8cd9357ee0494a20b9ba9d4b8ed3514b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:679 +#: 2cbc548821b84721b1aea4f88573f02f msgid "Example interactive session::" msgstr "互動式會話範例::" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:617 -#: 45b4cc10dbab4342a2653adafcad5e63 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:692 +#: bd36c89659694280b349cc621b598254 msgid "TCP Client file transfer API" msgstr "TCP客戶端檔案傳輸API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:619 -#: 2476ecf352184c39a27da75545ff67b9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 +#: 0f20edbf8203493aa579cb5a1195712b msgid "" "The TCP client contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers, using the same " "underlying protocol as the server." msgstr "TCP 用戶端包含一個檔案傳輸子系統,支援客戶端到伺服器和伺服器到客戶端傳輸,使用與伺服器相同的底層協定。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:623 -#: 37c359049bd04adcbcde988494c16efa +#: ../../source/Network_APIs/TCP_Client_APIs.rst:698 +#: 02806a329fba478293ef172f63bfb93d msgid "" "As with the server documentation, only the list of APIs is provided here." " For detailed internal flow, please refer to the server documentation or " "the source code." msgstr "與伺服器文件一樣,此處僅提供 API 清單。詳細的內部流程請參考伺服器文件或來源碼。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:627 -#: a0aef36e6c984775b79dc1c35e39cd61 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 +#: 2a7f8a3995cf4e2b81a3bf5c3c85b0fa msgid "The file transfer API for the client includes:" msgstr "客戶端的檔案傳輸API包括:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:629 -#: e340f1fe00774c58bc70b398a745589d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:704 +#: dc5da9cf7ac441c8842cc97d904582ba msgid "The basic function for client-to-server file transfer is:" msgstr "客戶端到伺服器檔案傳輸的基本功能是:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:639 -#: 3cfc45f71fac4d49b0c188b84068d5b7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:714 +#: db4145949f7a42aab5ff42bf72d6ff2e msgid "" "The non-``_thread`` versions take the destination folder as a required " "argument (the ``_thread`` wrappers default it to ``None``, which means " "the default transfer folder)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:643 -#: 6058cc068109448faaad1e4936bb7863 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:718 +#: 743dd6f0cdba49678277c1d19c178f20 msgid "" "For server-initiated transfers (server-to-client), the client provides " "these handlers:" msgstr "對於伺服器發起的傳輸(伺服器到客戶端),客戶端提供以下處理程序:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:653 -#: 1e596cb7ccd942aeb30e335c53e1afa1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:728 +#: 72f8a6d975094c7984fbef810a422975 msgid "The low-level receive mode function is:" msgstr "低階接收模式函數為:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:661 -#: 885c49e37dd94f2bb3aca9d95dc72222 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:736 +#: b04d81d08ea941b3b6beea16e4a05bc0 msgid "And the low-level send mode function is:" msgstr "低層發送模式函數為:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:668 -#: 17759b30b9ae4c68b00432ae33741a99 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:744 +#: 724cadb0ca764d9aaafd664c63b858d6 msgid "" -"``pause_fid`` is the forwarding id used to pause/resume the transfer with" -" ``/pause_trans`` / ``/start_trans``." +"``fid`` keys the leg in ``file_upload_progress`` and is what " +"``/pause_trans`` / ``/start_trans`` (or `pause_trans` / `start_trans`) " +"addresses; ``peer`` is the transfer's original receiver and " +"``resume_offset`` continues an interrupted file from the byte the " +"receiver already holds." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:671 -#: 4dc07ef115aa4712807fede2f2040e12 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 +#: f5823da74e1a4879a65624511d10e0cb msgid "" "We recommend that for client-to-server file transfers, you use the " "console commands (``/file``, ``/file_folder``, etc.) rather than calling " @@ -1299,8 +1426,8 @@ msgstr "" "API,因為控制台命令已經正確處理線程和信號量限制。如果您需要直接呼叫 API,請使用 `_thread` " "版本(例如,`file_transfer_client_recv_client_start_thread`)以避免阻塞主執行緒。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:680 -#: 1165a3c7f2bc470da7c706aead0fc73f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 +#: 2d0ea3d6726e43a3b3b551bf23c5ce00 msgid "" "*Note: The file transfer API functions follow the same handshake protocol" " as the server: the initiator sends a command over the main connection, " @@ -1310,13 +1437,13 @@ msgstr "" "*注意:文件傳輸 API 函數遵循與伺服器相同的握手協定:發起者透過主連接發送命令,然後協商臨時端口,並透過單獨的 TCP 連接傳輸實際文件資料。" " *" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:687 -#: 95c14f0f60154aa3b15d0dd0dfe41a69 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 +#: 997f666f071d44499a4be946c3a808e5 msgid "Port allocation API" msgstr "連接埠分配API" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:689 -#: 9e3832473379404391011a22af4fb605 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 +#: 937556f090f74e86ab56041fbda5c543 msgid "" "The client port allocation APIs are nearly identical to those of the " "server. They allow you to allocate ephemeral ports either automatically " @@ -1326,8 +1453,8 @@ msgstr "" "客戶端連接埠分配 API 與伺服器的連接埠分配 API 幾乎相同。它們允許您自動分配臨時連接埠(透過返回 " "0,讓作業系統選擇)或在配置的範圍內手動分配。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:694 -#: 93aa2cdf7f3c49fb8ad14ad1b78415e4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 +#: a37e79b6f8e34e3ab589f9127a2fbaf2 msgid "" "To configure the port allocation mode, the client reads the " "``/client_alloc_port_range`` line the server sends it right after the " @@ -1337,8 +1464,8 @@ msgid "" "allocation (return 0 from allocation calls)." msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:702 -#: 3d693309e5ae4fbaa587212cf81bc16f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 +#: a29288d0ba7d46409b9fbc7e4b3ff7b0 msgid "" "In manual allocation mode, the port range is determined by the server's " "broadcast value. The client maintains its own range based on " @@ -1351,13 +1478,13 @@ msgstr "" " - self.port_add_step *each_client_port_range”,最大埠為“self.port + 1 + " "self.port_add_step *each_client_port_range”。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:710 -#: ab3bb204b8f5402093e6d329cd98cd64 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 +#: baf74c2478324ced80df912ff96e7baa msgid "The main methods for port allocation are:" msgstr "連接埠分配的主要方法有:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:717 -#: 93b31be2d4bf4e5ca9f8b4ab9b095a45 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 +#: c4170cd3e6844792b110dfba945f0298 msgid "" "`palloc` returns an available port (either 0 for automatic mode, or a " "concrete port number from the manual range). It internally calls " @@ -1367,16 +1494,16 @@ msgstr "" "`palloc` 傳回一個可用連接埠(自動模式為 " "0,或手動範圍內的特定連接埠號碼)。它在內部循環調用“file_palloc”(加法分配)和“spy_palloc”(減法分配)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:729 -#: d54f0b635e194239932cf1bb5cace701 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:807 +#: 1c21e96227684b8998d8a6c6c595caf0 msgid "" "`pfree` releases a previously allocated port. In manual mode, it removes " "the port from the internal list and adjusts the latest port pointers. In " "automatic mode, it does nothing." msgstr "`pfree` 釋放先前分配的連接埠。在手動模式下,它將連接埠從內部清單中刪除並調整最新的連接埠指標。在自動模式下,它不執行任何操作。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:734 -#: 60b2327bda49480fac483fb4ca52eb5d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:812 +#: e270023d96364a59a4436f846b296202 msgid "" "As with the server, the automatic mode (returning 0) is recommended for " "most use cases because it avoids port conflicts and simplifies code. " @@ -1386,251 +1513,276 @@ msgstr "" "與伺服器一樣,建議大多數用例使用自動模式(返回 " "0),因為它可以避免連接埠衝突並簡化程式碼。手動模式適用於必須嚴格控制連接埠範圍的環境(例如防火牆或測試)。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:741 -#: bade6122477d4a959b6f9a942b150ea0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:819 +#: 31a306a34d04473c85f2c36abe5747e7 msgid "TCP Client APIs table" msgstr "TCP 用戶端 API 表" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:743 -#: be55c1d2020c4088ac45dcd1f2c6add4 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:821 +#: e38b3c22a1e041be93c1b9133368dacb msgid "In short, the table of contents of the public APIs is as follows:" msgstr "簡而言之,公共API的目錄如下:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:746 -#: 8bb46aea2dff4e57853087e452fdca3f +#: ../../source/Network_APIs/TCP_Client_APIs.rst:824 +#: 5c9291fc111d4f87a26c3b323d69bf27 msgid "The client setup APIs:" msgstr "客戶端設定 API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:747 -#: 6c95cdbfa4634d9f9561908b316ab03e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:825 +#: dc26d3c73e994b2a89d83b6dc2b0ff20 msgid "`TCP_Client_Base`" msgstr "`TCP_Client_Base`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:748 -#: a5ab88edb0dd42dd81166dc614c4c353 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:826 +#: caab3a11f54d4540890a84cada3cecd3 msgid "`start_TCP_client`" msgstr "`啟動_TCP_客戶端`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:749 -#: 11f6500a3ac64b41ba44c22ef2069007 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:827 +#: c38e962856a84b6eaf6f0759e9a48ec4 msgid "`connect`" msgstr "`連線`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:750 -#: 0263dd292461441192546c1f9237adaf +#: ../../source/Network_APIs/TCP_Client_APIs.rst:828 +#: 411023a9191243338f22e59a33cb72c2 msgid "`close`" msgstr "`關閉`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:752 -#: 11848e9f043f4952afaad4305b07486d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:830 +#: 982308344bc1464c982613021965e40f msgid "The client handling information APIs:" msgstr "客戶端處理資訊API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:753 -#: 6c2bd74a71a64468b3247862791409e1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:831 +#: 611645ffa9bb4259923b685f7389fab4 msgid "`receive_messages`" msgstr "`接收訊息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:754 -#: a15228535750492caa9b3ebfba4d9901 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:832 +#: b5a951b6b0694dd7992bcb3d054bd2b3 msgid "`handle_server_command`" msgstr "`處理伺服器命令`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:755 -#: 47cb15f07d394f78a15345f254e42b0b +#: ../../source/Network_APIs/TCP_Client_APIs.rst:833 +#: 334fb0ff014d4f418ac474db4c68d247 msgid "`receive_message`" msgstr "`接收訊息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:756 -#: f0074be846de4eef8d98f07a3fd153a7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:834 +#: df7b9a0f6c034b8ab9b1fb20b3bf879a msgid "`send_message`" msgstr "`發送訊息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:757 -#: ca1943c93c2048d9805e6c3494744d90 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:835 +#: ffb875c0ebd844368deedf382811f851 msgid "`interactive_mode`" msgstr "`互動模式`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:758 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:836 +#: 5630f1fb130842aba877cdb0c29e4ff1 #, fuzzy msgid "`send_message_to_server`" msgstr "`發送訊息`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:760 -#: 1059c94b173f48aa9304663c6d74a805 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:838 +#: 494c8644a7254a7b81e9886d840813e8 msgid "2.1. The inbound event listener APIs:" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:761 -#: 54202f3279bb4bb19457be283d4f5d75 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:839 +#: 6f15aa9d9fe142088b15a802e28823f5 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:762 -#: 88625c35b2ec49889b14309d8373c1ef +#: ../../source/Network_APIs/TCP_Client_APIs.rst:840 +#: d240527b31854c3eb36c83b57b838e5d msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:763 -#: eca517026718488aa026202ff440ce41 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:841 +#: fb735c656faa4a28983b3c90a8f9f452 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:765 -#: a5c242c6e4084aef98fa59f17778731d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:843 +#: 7299f59deb95485b9ce5f240b3318d86 msgid "" "The client encrypted channel APIs (see :ref:`tcp-client-encrypted-" "channel-api`):" msgstr "用戶端加密通道 API(請參閱 tcp-client-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:766 -#: c5006b19599d4a45bc86d5cfac770d94 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:844 +#: 51757de232d548c3b7c230b7e6456906 msgid "`_crypto_exchange_thread`" msgstr "`_crypto_exchange_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:767 -#: 3d8e73d09493460c845a98dabf5ad9f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:845 +#: ad3834da9c474029952e0043a46c2ed6 msgid "`_crypto_after_ack`" msgstr "`_crypto_after_ack`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:768 -#: 75bbad7153834bad9492a242fa26b789 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:846 +#: 0ca576944d8a497abeb39cdf5c4ccdb7 msgid "`_crypto_push_pub_key`" msgstr "`_crypto_push_pub_key`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:769 -#: 59aff25473e942eb9b11f6aa4c1ff235 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:847 +#: 11b6eacdaa484d689499dad3be56bd79 msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:771 -#: aeba48f8f86e45f199838191146c7f4c +#: ../../source/Network_APIs/TCP_Client_APIs.rst:849 +#: b71d430231c24a6995ba0b267f09f4bf msgid "The client command APIs:" msgstr "客戶端命令API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:772 -#: 0a25d8003bd64c63ad151aedf3fb15ad +#: ../../source/Network_APIs/TCP_Client_APIs.rst:850 +#: efb7ccdbabfd477d83af89aed1eb4c5d msgid "`register_command`" msgstr "`註冊命令`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:773 -#: c9e2f51101b942ef8e722216e59ed972 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:851 +#: 72f8a6d975094c7984fbef810a422975 +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:852 +#: d549ceac7407457f81c403d7be88aa99 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:774 -#: 92211b1c671c48ce8e0d14c9d12b71f1 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:853 +#: c6fe8883469e47b88e0a4bb3be30c1a6 msgid "`submit_task`" msgstr "`提交任務`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:775 -#: a71e5e5a598f442b8b37dac6c03ee1f9 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:854 +#: 5630f1fb130842aba877cdb0c29e4ff1 msgid "`create_temporary_server`" msgstr "`建立臨時伺服器`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:776 -#: e23b2af57072452ab0fab0c5652bde72 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:855 +#: 9cf956cb593f4c758da50d45c684466b msgid "`create_temporary_client`" msgstr "`建立臨時客戶端`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:778 -#: 91270c73be944993a8751739a6ef133e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:857 +#: 55aa7c66f7a24443a58e108948608136 msgid "The client file transfer APIs:" msgstr "客戶端檔案傳輸API:" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:779 -#: 358e4cb2a7174129b65dc582f3b977f7 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:858 +#: d79011e4d398480cbdb00e021f1461fe msgid "`file_transfer_client_recv_client_start`" msgstr "`file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:780 -#: f4971cf5af03413e9b0011378a57d487 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:859 +#: 300f91c72ed8400d85821a3e2a0ab1ec msgid "`file_transfer_client_recv_client_start_thread`" msgstr "`file_transfer_client_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:781 -#: 077b6550f3b8496fb4d8d8592eac5ca6 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:860 +#: 1f3a30d9bf5d44baa9459a21df8f70d4 msgid "`folder_file_transfer_client_recv_client_start`" msgstr "`folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:782 -#: 194dd830cddc49acaad93077b41fb646 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:861 +#: 5619c7c126b14852ace1e5ed9a428e0a msgid "`multiple_file_transfer_client_recv_client_start`" msgstr "`multiple_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:783 -#: e6ea79e90d794733b2bb84b5799ab3ec +#: ../../source/Network_APIs/TCP_Client_APIs.rst:862 +#: e1e3f53d8275406f9f2f31a406617843 msgid "`multiple_folder_file_transfer_client_recv_client_start`" msgstr "`multiple_folder_file_transfer_client_recv_client_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:784 -#: ce228984911540d29bef2d0b7e73eabc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:863 +#: 0f3b14e3c193426191323ee76959278e msgid "`file_transfer_client_recv_server_start`" msgstr "`file_transfer_client_recv_server_start`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:785 -#: 7ff0717c8e504c869e36a3d9fd829652 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:864 +#: 4612a53ee9154895a8758a6cc45c0b76 msgid "`file_transfer_client_recv_server_start_thread`" msgstr "`file_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:786 -#: db7e615cfbd347359a6a683642049c31 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:865 +#: 5dff8ca27b7b40e6941b8190a136173c msgid "`file_folder_transfer_client_recv_server_start_thread`" msgstr "`file_folder_transfer_client_recv_server_start_thread`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:787 -#: 16a578b31e344b5d82b9935e56aafa02 -msgid "`file_transfer_mode_recv`" -msgstr "`檔案傳輸模式_接收`" - -#: ../../source/Network_APIs/TCP_Client_APIs.rst:788 -#: 7659e4e26bef45e89e4659a045cd77cc +#: ../../source/Network_APIs/TCP_Client_APIs.rst:866 +#: c66340b3ef204af29e58170db0efc057 msgid "`file_transfer_mode`" msgstr "`檔案傳輸模式`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:790 -#: 6a81df270092467db215985a9b0ea90e +#: ../../source/Network_APIs/TCP_Client_APIs.rst:868 +#: 87af784aa34949379dc6a73c148a402d +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:869 +#: 9aa5be3d37804a5c8286d23160add073 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:870 +#: 4612a53ee9154895a8758a6cc45c0b76 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:871 +#: e340c2c825324df7b3aee14da0f9d919 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:872 +#: 0f3b14e3c193426191323ee76959278e +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Client_APIs.rst:874 +#: 5bf1072901734d3d8d0b119e5f50627c msgid "The client console commands (interactive mode):" msgstr "客戶端控制台指令(互動模式):" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:791 -#: c2174ab210464a2e82c298e0f70fee20 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:875 +#: cb2350fc1fd047f39fb9841ce78dd4ed msgid "`/quit`" msgstr "`/退出`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:792 -#: ffa9f9ef47ae46629a6fc29d29d9ab44 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:876 +#: 70b54395545d4421bd90e40acd8b28d5 msgid "`/file`" msgstr "`/檔案`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:793 -#: 86990039800e4a999b76a431d6a6dd8a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:877 +#: bd2dec3b0774465d87ed9f3f853f30db msgid "`/multiple_file`" msgstr "`/多個檔案`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:794 -#: 6f26c82663494206964a6bb68ddcfe6a +#: ../../source/Network_APIs/TCP_Client_APIs.rst:878 +#: efe4930f9bd34df19b1ee98085605346 msgid "`/file_folder`" msgstr "`/檔案資料夾`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:795 -#: 63d6611c586c46d3a9053712a112162d +#: ../../source/Network_APIs/TCP_Client_APIs.rst:879 +#: acb8ceac4b5540aca3230cff6bfefa86 msgid "`/multiple_file_folder`" msgstr "`/多個檔案資料夾`" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:798 -#: 7bb84bbf4494463d9e477ddce9f0fec2 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:882 +#: 9db1c5c6b375448e80c2af32c0464023 msgid "See Also" msgstr "參見" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:800 -#: 5cc4da34c3dc479eb9af04123c8502f0 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:884 +#: 0c84c6f4e6e9450aa96935335c505122 msgid ":doc:`TCP_Server_APIs` — TCP server." msgstr ":doc:`TCP_Server_APIs` — TCP 伺服器。" -#: ../../source/Network_APIs/TCP_Client_APIs.rst:801 -#: 134b0d0b135c4e68a08b0d14959d6307 +#: ../../source/Network_APIs/TCP_Client_APIs.rst:885 +#: efc25fa97296452199853b1bb3cc3f21 msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 端點。" @@ -1773,3 +1925,57 @@ msgstr ":doc:`UDP_APIs` — UDP 端點。" #~ msgid "The multiple folders transfer function is:" #~ msgstr "多資料夾傳輸函數為:" +#~ msgid "``client_port``: Default is ``None`` (OS assigns ephemeral port)" +#~ msgstr "“client_port”:預設為“None”(作業系統分配臨時連接埠)" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(sender_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to " +#~ "`handle_server_command` instead). ``sender_id`` is" +#~ " the author's ``\"ip:port\"`` — for a" +#~ " message another client forwarded here " +#~ "through the ``/send_msg_from`` envelope it " +#~ "is the forwarding client, and it " +#~ "is ``None`` for a direct push from" +#~ " the server. ``add_file_listener`` registers " +#~ "``listener(client_id, full_path, name, size, " +#~ "command)`` and fires after a file " +#~ "sent by the server has been fully" +#~ " written to disk. Both listeners run" +#~ " on a protocol thread, so they " +#~ "must not block, and an exception " +#~ "inside a listener is logged and " +#~ "swallowed. The ``remove_*`` counterparts " +#~ "unregister a listener and ignore unknown" +#~ " ones." +#~ msgstr "" + +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "握手交換隨機會話隨機數,線路上的每條加密線路都攜帶它加上每個連接的序號:``||``。接收方丟棄隨機數與目前會話不符的行(從舊連接重播的密文)或其序號不是預期的行(會話內重播的密文/亂序);當套接字在(重新)交換後切換到加密模式時,兩個計數器都會重置。" + +#~ msgid "" +#~ "``pause_fid`` is the forwarding id used" +#~ " to pause/resume the transfer with " +#~ "``/pause_trans`` / ``/start_trans``." +#~ msgstr "" + +#~ msgid "`file_transfer_mode_recv`" +#~ msgstr "`檔案傳輸模式_接收`" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po b/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po index e677001..553bb8d 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/Network_APIs/TCP_Server_APIs.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -20,86 +20,86 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/Network_APIs/TCP_Server_APIs.rst:2 -#: 6233736da6d8410985a7db552ebb0405 +#: c4332266e3f842cc912424ee842fcfe0 msgid "The TCP Server APIs" msgstr "TCP 伺服器 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:5 -#: 6e1c64d13b9e4deebc7c276d00bfca94 +#: 769ff5b424d54086a70b199663089327 msgid "TCP Server setup API" msgstr "TCP 伺服器設定 API" #: ../../source/Network_APIs/TCP_Server_APIs.rst:7 -#: 05209d5966c24f19bcf70e93d016fe24 +#: 2d81aa6d8ba84a868113fd9e08fc5c60 msgid "" "The TCP Server Setup API is used to create a TCP server. The server in " "the protocol is usually used to connect and listen to the TCP clients and" " handle the data from the clients." msgstr "TCP 伺服器設定 API 用於建立 TCP 伺服器。協定中的伺服器通常用於連接和監聽TCP客戶端並處理來自客戶端的資料。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:35 -#: c6d17d88ca43468cab262d7b50bb7d43 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 +#: ddc5d0f6bc1b4162af2bb49f6b25a031 msgid "" "The TCP Server Setup API is defined in the ``TCP_Server_Base`` class. The" " parameters of the ``__init__`` method are as follows:" msgstr "TCP 伺服器設定 API 在「TCP_Server_Base」類別中定義。 ``__init__``方法的參數如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:38 -#: 7c3b5b3185bb436bbaabf0aaea5f11fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 +#: f1ffcdd5c8e74b9cbdb5e5fc8eeb34ce msgid "``host``: The host IP address to bind the TCP server to." msgstr "``host``:綁定 TCP 伺服器的主機 IP 位址。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:39 -#: 8dbeeea956834b28a5d13a47b9eaf651 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 +#: 7e419c2e704a44228bd0bdeed976d861 msgid "``port``: The port number to bind the TCP server to." msgstr "``port``:綁定 TCP 伺服器的連接埠號碼。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:40 -#: 3710af3c13574f088cd84d34ae8c83ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 +#: 854e298d71f140069b6ed51806224ca5 #, fuzzy msgid "" "``max_clients``: The maximum number of concurrent clients the server can " "handle (ignored when ``is_asynic_clients_io`` is ``True``)." msgstr "``max_clients``:伺服器可以處理的並發客戶端的最大數量。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:42 -#: c92cda0f3bdb4f839ab24c2c65c926db +#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 +#: 203462f6b127478cb9bb0c2093362827 msgid "``port_add_step``: The step size for incrementing the port number." msgstr "``port_add_step``:增加連接埠號碼的步長。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:43 -#: 43155638bb1344798a37f85065d411ac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 +#: 3d0355b5c1924055a7d8b6acb907fad0 msgid "``port_range_num``: The number of ports to check in the range." msgstr "``port_range_num``:範圍內要檢查的連接埠數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:44 -#: 0459f804445d47519971903bce3e36eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 +#: a7852ea136454a1298541e96cdece1bc msgid "" "``max_file_transfer_thread_num``: The maximum number of threads for file " "transfer operations." msgstr "``max_file_transfer_thread_num``:檔案傳輸操作的最大執行緒數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:45 -#: 3103e7d29cb647f9922e0b507d47a171 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:49 +#: 0f1b0f03ffe2472cb58725dc446f6f7c msgid "" "``is_hand_alloc_port``: A flag indicating whether to manually allocate " "the port." msgstr "``is_hand_alloc_port``:指示是否手動分配連接埠的標誌。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:46 -#: ee86acb3489f408ca9ba116a66c5ea3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:50 +#: 969ca405744f4d57a8e70db30eada3f7 msgid "" "``is_input_command_in_console``: A flag indicating whether to input " "commands in the console." msgstr "``is_input_command_in_console``:指示是否在控制台中輸入指令的標誌。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:47 -#: d593644fa1664037b99afd05ecbf9cf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:51 +#: 6b01091b3f124b8d87c9423eb6998be4 msgid "``max_custom_workers``: The maximum number of custom worker threads." msgstr "``max_custom_workers``:自訂工作執行緒的最大數量。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:48 -#: b46e9e9d9066432bbe75dc461b0f951f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 +#: c9d16d29465a48779ee2a54e4b9cc66e msgid "" "``is_extend_command``: A flag for extension protocols. With ``False`` " "(the default) the constructor starts the server itself by calling " @@ -107,8 +107,8 @@ msgid "" "register its commands first and start the server later." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:52 -#: 60e4bd55be9940a48d6ae6421561fdaf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:56 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_enable_encrypto``: A flag indicating whether the messages exchanged " "with clients are RSA-encrypted (see :ref:`tcp-server-encrypted-channel-" @@ -117,8 +117,8 @@ msgstr "" "``is_enable_encrypto``:指示與用戶端交換的訊息是否經過 RSA 加密的標誌(請參閱 tcp-server-" "encrypted-channel-api`)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:54 -#: c6dcdd076b864336834f8490c0a25708 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 +#: 3558d7e8c52442818701d4eb794b3643 msgid "" "``is_custom_keys``: An optional ``[pub_key_path, pvt_key_path]`` pair of " "user-supplied RSA keys. Both files must exist, parse as PEM, and pair " @@ -128,16 +128,30 @@ msgstr "" "``is_custom_keys``:可選的``[pub_key_path, pvt_key_path]`` 使用者提供的 RSA " "金鑰對。兩個檔案都必須存在,解析為 PEM,並且相互配對;無效的對將被默默地忽略,並使用預設的鍵查找(``None`` 保留預設查找)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:58 -#: d0e99e1bc78f40f7af7470a66315bb04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:62 +#: 86265e57f3aa48e58e3fb5d9de0a9277 msgid "" "``max_mem_buff``: The in-memory buffering ceiling of the forward pump, " "given in MiB and stored as bytes (``self.max_mem_buff``); past it the " "uploading peer is told to pause. The default is 2048." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:61 -#: 970d44aa127b40c7854cfc4dee215dcf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 +#: 7d4dd6bf4eff4f4db8ce0187088f172c +msgid "" +"``recv_messages_chunk_len``: The number of bytes read per receive on the " +"control connection, covering commands and messages. The default is 4096." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:67 +#: 8fb93ff5bf2f49b18f2f42c92e66123f +msgid "" +"``file_transfer_chunk_len``: The chunk size in bytes for streaming a file" +" or folder transfer in either direction. The default is 65536 (64 KiB)." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:69 +#: f12bacde2a874840879a51af63eeefde msgid "" "``is_asynic_clients_io``: A flag indicating whether clients are served by" " asyncio coroutines on one event loop instead of one thread per client. " @@ -145,88 +159,116 @@ msgid "" " of concurrent connections." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:65 -#: 269ce1f748d942949c0c20017fdf4a9b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 +#: 3a36a9bba6004a41b358be9975788707 msgid "" "``is_debug``: A flag selecting how much detail is logged. With ``False`` " "(the default) the server logs command content and execution results only;" " with ``True`` it also logs the key steps of the execution process." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:68 -#: 09d8448517374602938d9ca4872e0356 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 +#: be13e03bfce24a5ca6e5733943a7db33 msgid "" "``is_print_log``: A flag indicating whether the server logs at all. With " "``False`` it prints nothing, whatever ``is_debug`` says." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:71 -#: dc30e9a1ba5044319a3ed5ad1842b348 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 +#: 2994b78415964ff0adc713a4daed1b6b +msgid "" +"``is_enable_file_transfer_progress_bar``: A flag indicating whether every" +" running file transfer is tracked in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads). Each entry is a ``[transferred " +"bytes, total bytes, current speed, local file path, peer]`` list keyed by" +" the transfer's fid — ``peer`` is the ``(ip, port)`` of the transfer's " +"original sender (downloads) or receiver (uploads), never the relay of a " +"forwarded transfer. The entry is removed once the transfer ends; an " +"interrupted one keeps its entry (and its partial file) so the reconnect " +"logic can resume it. ``file_trans_progress_file`` names the file under " +"the protocol's ``.Flow`` directory these stores are written to when a " +"connection drops." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 +#: 9f9de22b50a94553ac1113f290dff1b4 +msgid "" +"``is_enable_real_time_network_speed``: A flag indicating whether the " +"protocol's real-time network speed is measured. With ``True`` (the " +"default) every send and receive — the control layer and every temporary " +"connection, file transfers included — feeds ``upload_network_speed`` and " +"``recv_network_speed`` (bytes per second, a rolling average over " +"``NETWORK_SPEED_WINDOW`` seconds). With ``False`` nothing is measured and" +" every speed value is ``None``." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 +#: 8b0a1bb7ed944884854a936968f3b4bd msgid "All parameters have default values:" msgstr "每個參數都有預設值:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:73 -#: 5774cd0576f349d18492b59a0b6d68bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:100 +#: 89299feb872b49758f7c9bf680114bbc msgid "``host``: Default is ``'127.0.0.1'``" msgstr "“主機”:預設為“127.0.0.1”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:74 -#: 4437fda8aa004d7483cefd29ad594bca +#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 +#: 38b84b10fc4d492497c3e0b20cb9fe8c msgid "``port``: Default is ``65432``" msgstr "“連接埠”:預設為“65432”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:75 -#: 559c3b634b1043f2a6541f45eba488d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:102 +#: 3ccf25b3de4749a7ad73a1001fea86fb msgid "``max_clients``: Default is ``10``" msgstr "“max_clients”:預設為“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:76 -#: 8988cc48e66a472ebe8d505bdf8d6db9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:103 +#: 63455575485f4a25b4d2d2b83803e6b8 msgid "``port_add_step``: Default is ``1``" msgstr "“port_add_step”:預設為“1”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:77 -#: 063ec78e76b3439aafe539fad81a6036 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:104 +#: d8759c586e7143838c1ffe24c9fd6f62 msgid "``port_range_num``: Default is ``100``" msgstr "“port_range_num”:預設為“100”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:78 -#: 4a3115c33bd349fba0768f79f18c47c0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:105 +#: a8020929e0f14b5394b6dd502b7a7b67 msgid "``max_file_transfer_thread_num``: Default is ``10``" msgstr "“max_file_transfer_thread_num”:預設為“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:79 -#: fe7bf4015de045dcadc0024aef2bbdac +#: ../../source/Network_APIs/TCP_Server_APIs.rst:106 +#: a9307e89f7cd471d96794bf7fbc9313c msgid "``is_hand_alloc_port``: Default is ``False``" msgstr "“is_hand_alloc_port”:預設為“False”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:80 -#: 2529e795d9b0401d930f3c09766c56d5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:107 +#: 76084a80a458455bb952e8acad677eba msgid "``is_input_command_in_console``: Default is ``True``" msgstr "“is_input_command_in_console”:預設為“True”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:81 -#: a95bee48d609469398e5a878b3d1e810 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:108 +#: f32a6549330a43f482e01def905e7415 msgid "``max_custom_workers``: Default is ``10``" msgstr "“max_custom_workers”:預設為“10”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:82 -#: c825fae2eaaa4afeaa551e65e4ea1ff1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:109 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_extend_command``: Default is ``False`` (when ``True``, ``__init__`` " "will not call ``start_TCP_Server()`` automatically)" msgstr "“is_extend_command”:預設為“False”(當“True”時,“__init__”不會自動呼叫“start_TCP_Server()”)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:84 -#: 0ab49ef330a94ecb80e160bbe0f00fe9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:111 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_enable_encrypto``: Default is ``True`` (when ``True``, client " "connections go through an RSA public-key exchange and all subsequent " "messages are encrypted)" msgstr "「is_enable_encrypto」:預設為「True」(當「True」時,用戶端連線將透過 RSA 公鑰交換,並且所有後續訊息都會被加密)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:87 -#: 6087b88026574d56aa37a817f0fe790a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:114 +#: c259e80f53a14b79a94190bcded7b30d msgid "" "``is_custom_keys``: Default is ``None`` (a ``[pub_key_path, " "pvt_key_path]`` list uses a user-supplied keypair instead of the default " @@ -235,37 +277,63 @@ msgstr "" "``is_custom_keys``:預設為``None``(``[pub_key_path, pvt_key_path]`` " "清單使用使用者提供的金鑰對而不是預設的``~/.ssh``/產生的金鑰)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:90 -#: 26758c8f847b47c9839124e86e042349 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:117 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``recv_messages_chunk_len``: Default is ``4096``" +msgstr "“max_clients”:預設為“10”" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:118 +#: a8020929e0f14b5394b6dd502b7a7b67 +#, fuzzy +msgid "``file_transfer_chunk_len``: Default is ``65536`` (64 KiB)" +msgstr "“max_file_transfer_thread_num”:預設為“10”" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 +#: 515932c230d64c88ab31d959cc694992 msgid "" "``is_asynic_clients_io``: Default is ``False`` (when ``True``, every " "accepted connection is served by a coroutine on one asyncio event loop, " "and ``max_clients`` is ignored)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:93 -#: 79dca8f502bb4401952542fb3dba6939 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:122 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_debug``: Default is ``False`` (``True`` adds the execution-process " "lines to the command/result lines)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:95 -#: 656b6904625a4ea0977c85a93e62fd84 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:124 +#: b423cc46e39340b1aa792d44e0157b60 msgid "" "``is_print_log``: Default is ``True`` (``False`` silences every line the " "server would print)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:98 -#: a3fd35f818f84d7399b7d41208ff9319 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:126 +#: abd7d3032e15468e92f96a0b5af1f926 +msgid "" +"``is_enable_file_transfer_progress_bar``: Default is ``True`` (``False`` " +"records no transfer progress)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:128 +#: 9b2bfa874c4e4969905923bd7aa0f80c +msgid "" +"``is_enable_real_time_network_speed``: Default is ``True`` (``False`` " +"measures no speed; every speed value is ``None``)" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 +#: ff0d716f8c6344408337c57ab32bad28 msgid "" "The TCP Server Setup API will initialize all the necessary parameters and" " resources for the TCP server." msgstr "TCP 伺服器設定 API 將初始化 TCP 伺服器的所有必要參數和資源。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:101 -#: c38ba680fb704c4b9af31bcd33224c02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:134 +#: 06c57226c0e9415ab1618ae20a14f513 msgid "" "*Note: By default ``TCP_Server_Base.__init__`` calls " "``start_TCP_Server()`` to start the server automatically. If you set " @@ -276,36 +344,36 @@ msgstr "" "自動啟動伺服器。如果您設定“is_extend_command=True”,實例將不會自動啟動,您應該在準備好時手動呼叫“start_TCP_Server()”。" " *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:112 -#: a0900d8246aa4cda80638035485659e5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:145 +#: e473a54dc4534e29ac4361429d24cb63 msgid "" "In the `start_TCP_Server` method, we first create a TCP server socket and" " bind it to the ``self.host`` and ``self.port`` which are initialized in " "the ``__init__`` method." msgstr "在`start_TCP_Server`方法中,我們先建立一個TCP伺服器套接字並將其綁定到在`__init__`方法中初始化的`self.host`和`self.port`。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:116 -#: 4b6e513817d44c1d93cf1c39866ecf18 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:149 +#: 68dff731e96c46788af52f9c536a6d2f msgid "" "*Note: The server socket which is set up in the `start_TCP_Server` method" " is based on IPv4 form.*" msgstr "*注意:`start_TCP_Server`方法中設定的伺服器套接字是基於IPv4形式的。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:119 -#: b8a255c83b3346199c3197dd596427b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:152 +#: 1c6fc605850b4e988e7f5dac390f905e msgid "" "Secondly, according to the ``self.is_input_command_in_console`` " "parameter, we will start a thread to listen to the console input of the " "server or not." msgstr "其次,根據``self.is_input_command_in_console``參數,我們會啟動一個執行緒來監聽或不監聽伺服器的控制台輸入。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:123 -#: bd35c2a4858f46ecb2f1ea1b7e987bb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 +#: 493d7ac50eb3446394da3c71f307b0a5 msgid "After that, a main loop to accept clients will be started." msgstr "之後,將啟動接受客戶端的主循環。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:125 -#: 8b06edd210564df19035b30b72121c82 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 +#: 46f0159fb9a84874959c103ac08656f5 msgid "" "*Note: there is another global variable ``self.running`` which is set to " "``True`` after the server socket is successfully created. The " @@ -316,8 +384,8 @@ msgstr "" "*注意:還有另一個全域變數“self.running”,在伺服器套接字成功建立後,該變數將變為“True”。 ``self.running`` " "變數用於控制 TCP 伺服器的主循環,當伺服器關閉時它將變為 ``False``。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:131 -#: 0920728e22cf4fdcbd6b6a5f32b251d4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:164 +#: ed335af1339644a090d7fc4ebdc859f1 msgid "" "With ``is_asynic_clients_io=True`` the main loop is the asyncio event " "loop instead: it accepts clients in non-blocking mode and schedules one " @@ -325,8 +393,8 @@ msgid "" " `stop` releases it so the loop can end." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:136 -#: ca2a678a5119456daf70ba9c6bcfacf8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:169 +#: 613624f457b847f994b739812b6e7aed msgid "" "The main loop of the TCP server setup function first checks whether the " "number of connected clients exceeds the maximum number of clients. The " @@ -334,8 +402,8 @@ msgid "" " of the `TCP_Server_Base` class, which is initialized in ``__init__``." msgstr "TCP伺服器設定函數的主循環首先檢查連線的客戶端數量是否超過最大客戶端數量。最大客戶端數量由「TCP_Server_Base」類別的「self.max_clients」參數定義,該參數在「__init__」中初始化。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:141 -#: 295d9fd021d94b94b5bb5e3290af9b94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:174 +#: d6142df9dee34a85a449a322bcfc5729 #, fuzzy msgid "" "If the number of the clients is already over the limit of the connect " @@ -345,8 +413,8 @@ msgid "" "is defined as:" msgstr "如果客戶端數量已經超過連線數量限制,伺服器將發送過載訊息並關閉連線。但如果沒有超過限制,伺服器將設定一個客戶端處理函數“handle_client”,伺服器處理函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:153 -#: a15c83c5c9984e68b88602f6a3c56d16 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:186 +#: e0d97e64db41406aa120fbdcd2ee5bb3 msgid "" "*Note: For more details of the `handle_client` function, see the :ref" ":`tcp-server-handling-information-api` section.*" @@ -354,21 +422,21 @@ msgstr "" "*注意:有關“handle_client”函數的更多詳細信息,請參閱 :ref:`tcp-server-handling-information-" "api` 部分。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:156 -#: 4e4b61d041b24075b90f598ef42bbe78 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:189 +#: 686ed007e14d4a98b931c0c651bb7bf5 msgid "So what can the setup function do if it fails?" msgstr "那如果setup函式運行失敗了怎麼辦呢?" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:158 -#: bfc7899a0ec649d49c956d569bbad0bc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:191 +#: 189abee61a444611a486dec294da6561 #, fuzzy msgid "" "First, the try-except block in the main server loop checks whether the " "error is an ``OSError``. If it is, the main loop will exit directly." msgstr "首先,主伺服器循環中的 try 和 except 程式碼區塊將偵測錯誤是否為「OSError」。如果是,主循環將直接退出。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:162 -#: 8a3a4854f3a3441b87d0257cb4eb4e52 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 +#: e4e1ba68f4b64dc280490157405acab9 #, fuzzy msgid "" "Secondly, if the error is from the network socket, it first logs the " @@ -376,8 +444,8 @@ msgid "" "And the stop function has been defined as:" msgstr "其次,如果錯誤來自網路套接字,它會先輸出錯誤訊息,並透過呼叫函數「stop」來停止伺服器。停止函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:171 -#: 4eb334cfa82e4557b51ed511bb35fea1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:204 +#: 9eb5b6fb9d2e4394b3dbb4a1905767d0 msgid "" "To stop the TCP server, it first sets the ``self.running`` variable to " "False, to stop the main loop of the server. After that, it calls the " @@ -387,8 +455,8 @@ msgstr "" "要停止 TCP 伺服器,它首先將「self.running」變數設為 " "False,以停止伺服器的主循環。之後,它會呼叫“free_port”函數來釋放已指派的連接埠。 `free_port` 被定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:182 -#: 2d0515291a604c0996149873392657f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:215 +#: 18d7078902794d629ad9f4e92a334402 msgid "" "*Note: For more details of the `free_port` function, see the :ref:`tcp-" "server-port-allocation-api` section.*" @@ -396,8 +464,8 @@ msgstr "" "*注意:有關 `free_port` 函數的更多詳細信息,請參閱 :ref:`tcp-server-port-allocation-api` " "部分。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:185 -#: ee8148b7ac254bbba148a8ad7a4ebb94 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:218 +#: dc449dddb5014d40a50ff66277707822 #, fuzzy msgid "" "At the end of the operations, the TCP server closes all client sockets " @@ -405,8 +473,8 @@ msgid "" "socket." msgstr "在操作結束時,TCP伺服器將關閉字典變數「self.clients」中記錄的所有客戶端套接字,並關閉伺服器套接字。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:188 -#: e3cce971756a4931af9b546a1e12aeb9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:221 +#: 1d2d730ca10e484d9dadc386b02af66c msgid "" "Before closing the listening socket it shuts it down, which releases a " "thread that is blocked in ``accept()`` (closing alone would leave the " @@ -417,8 +485,8 @@ msgid "" "come up behind the caller's back." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:195 -#: eb7d0cdf9cb4455eab2a5ba068942fd5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:228 +#: 2975a8e2dfe646cc92f5b112afc6101f msgid "" "*Note: The ``self.clients`` variable is a dictionary that maps client " "address tuples to an info dictionary. The key is the client address tuple" @@ -431,52 +499,52 @@ msgstr "" "port)``),值是包含連接詳細資訊的字典,例如``'socket'``、``'address'``、``'id'`` " "和``'connected_time'``。請參閱下面的範例,其中顯示了條目的儲存方式。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:217 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 +#: 8936cbe70fcf44ac9cabec9e38c0195d msgid "TCP Server handling information API" msgstr "TCP伺服器處理資訊API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:219 -#: 45ece19ab8684f67b0f85203f442103e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 +#: 1bbc64aa745a4dc3a537c6c10fd9e3c5 msgid "" "The server handling information API documents the core TCP server methods" " that manage client sockets, receive raw data, and send messages." msgstr "伺服器處理資訊 API 記錄了管理客戶端套接字、接收原始資料和發送訊息的核心 TCP 伺服器方法。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:231 -#: 4603ad1e2ffc400491456f7abf750937 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:264 +#: 8b1b042f66a243d9b9abd829a3fefcfe msgid "" "`handle_client` is the main per-client handler in ``TCP_Server_Base``. It" " is invoked after a client connection is accepted and is responsible for:" msgstr "`handle_client` 是 `TCP_Server_Base` 中主要的每個客戶端處理程序。它在客戶端連接被接受後被調用,並負責:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:235 -#: dbeed4ea23664ab298a9c5e356642ddc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:268 +#: 67121b0c979f421eb7ddbfb432dad873 msgid "" "adding the client entry into ``self.clients`` with socket, address, id, " "and connected time" msgstr "將客戶端條目新增至「self.clients」中,其中包含套接字、位址、id 和連接時間" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:236 -#: 98d885826d6743a0ad2c72f44e0e9944 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:269 +#: 65ac2e1844dd4a86a5e550063ee90460 msgid "printing connection information and current client count" msgstr "列印連線資訊和當前客戶端計數" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:237 -#: f9a1536ee7a540d693a2f4f4b3ad690c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:270 +#: 21670e3d261c41b4a0cbf772ab3f0d73 msgid "sending a welcome message to the client" msgstr "向客戶發送歡迎訊息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:238 -#: e75d30ed5656490994353520e09cf789 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 +#: a48af59d8ef54c12929e843db0d51e01 #, fuzzy msgid "" "sending the ``/client_alloc_port_range`` information to that client " "depending on the port allocation mode" msgstr "根據連接埠分配模式向所有客戶端廣播“/client_alloc_port_range”訊息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:241 -#: 0e3762f344ff4b88bbb6699610627b41 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 +#: 034082645d394f158d8927076c6b38e9 #, fuzzy msgid "" "*Note: You can specify the port allocation mode in the arguments which " @@ -487,33 +555,33 @@ msgstr "" "*注意:您可以在「TCP_Server_Base」類別中定義的參數中指定連接埠分配模式。您可以變更的參數是“port_add_step”、“port_range_num”和“is_hand_alloc_port”。" " *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:247 -#: 3a8f9b23f43a469ca5d7cea807598bd6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:280 +#: 2cb1bb2c2ed84122a479e562a1156bf3 msgid "receiving raw bytes from the socket using `receive_message`" msgstr "使用“receive_message”從套接字接收原始位元組" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:248 -#: 8f1c9c44d13e41d1b4fdadac75fc4613 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:281 +#: f4db70de0d7d4b4f9f02a1fc2325b172 msgid "buffering incoming data until newline-terminated messages are complete" msgstr "緩衝傳入數據,直到換行符終止的訊息完成" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:249 -#: 54fef48b6314483cbd813885b82ead02 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:282 +#: c17ac3c5095746448b497f228eb10c88 msgid "splitting and processing each message line-by-line" msgstr "逐行拆分並處理每個訊息" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:250 -#: f7728d56338d464cad635232865f9fb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:283 +#: ba1a3439be1d43af80a46d2ee3658ac8 msgid "routing special commands beginning with ``/`` to `handle_command`" msgstr "將以 ``/`` 開頭的特殊命令路由到 `handle_command`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:252 -#: f87fc68b008a4e06a719e9ab316016f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 +#: 37462f705b094332a79be9d2765c4796 msgid "The `handle_command` function is defined as:" msgstr "“handle_command”函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:263 -#: 8b47f53ad413459393250da7b5f249eb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:296 +#: d5bdce3eed0b4171882356d2b207f6d2 #, fuzzy msgid "" "In `handle_command`, there are variable conditional branches to handle " @@ -525,27 +593,27 @@ msgstr "" "在「handle_command」中,有可變條件分支來處理內建指令,如「/help」、「/time」、「/clients」、「/quit」以及一些檔案傳輸指令。如果您已經透過命令擴充" " API 新增了更多命令,則函數將確定輸入的訊息是否與擴充命令相符。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:271 -#: 1b5f22ecb31f4b17bc31eeba617e9373 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 +#: 21bedf659c7c44a783ed367bebbec813 msgid "" "*Note: For more details of the command extension API and the built-in " "commands, see the :ref:`tcp-server-command-api` section.*" msgstr "*注意:有關命令擴展 API 和內建命令的更多詳細信息,請參閱 :ref:`tcp-server-command-api` 部分。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:274 -#: f4e3e8921f9c4825b54b7e26c77dfaa1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:307 +#: 85099f44cbb14013a55dcaf602370b51 msgid "logging normal chat messages and acknowledging receipt" msgstr "記錄正常聊天訊息並確認收到" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:275 -#: e25f3746f80f4046a7aeb5f0b61bba85 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:308 +#: c4a9e9f9ccd74f0ca064b3fe6a95e739 msgid "" "removing the client from ``self.clients`` and closing the socket when the" " client disconnects or an error occurs" msgstr "從“self.clients”中刪除客戶端,並在客戶端斷開連接或發生錯誤時關閉套接字" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:285 -#: 21e6108f8c1243a39f017b806967fb1d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:318 +#: 5f6ae0695302473a8adf476a72c72d3a msgid "" "`receive_message` is a thin wrapper around socket receive operations. It " "reads up to ``msg_length`` bytes from the given ``client_socket`` and " @@ -555,25 +623,25 @@ msgstr "" "`receive_message` " "是套接字接收操作的一個薄包裝器。它從給定的“client_socket”讀取最多“msg_length”位元組並返回原始位元組有效負載。訊息解碼和換行訊息幀由呼叫者處理。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:300 -#: b7e713b412334cc98292e1ca8abbf861 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:333 +#: 114485120bad452e8af2626995798eda msgid "" "`send_message` sends data back to a specific connected client. It " "verifies the server is running and the socket is valid, then:" msgstr "`send_message` 將資料傳回特定的連線客戶端。它驗證伺服器正在運行並且套接字有效,然後:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:303 -#: 923c92c05c79407e841f3a5d6fefeb92 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:336 +#: 78639cd82b2f42db9ddd7d84bf06e9ee msgid "accepts both ``str`` and ``bytes`` message payloads" msgstr "接受“str”和“bytes”訊息負載" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:304 -#: f890eeb62bbc4b5ab359452c6dd40b17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:337 +#: bff4a398dec3443391a0c6e6a9fb00ee msgid "trims string payloads and appends a newline if missing" msgstr "修剪字串有效負載並在遺失時附加換行符" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:305 -#: 21a1156ab51b4dc598f583c1d9f9defc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:338 +#: 033e533bc19f484bb0fe7d61fe01dc46 msgid "" "when the socket is in encrypted mode (the public-key exchange has " "completed), the plaintext is signed with the ``_VALID`` marker, RSA-OAEP " @@ -583,55 +651,55 @@ msgstr "" "當套接字處於加密模式時(公鑰交換已完成),明文使用「_VALID」標記進行簽名,RSA-" "OAEP使用對等方的公鑰加密,base64編碼並以換行符號結尾,而不是以明文形式發送" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:309 -#: 94980e8ed8db4bfeb6bb4f4278c10d04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:342 +#: 1f1be9fb9dff4409aa040671a8e89013 msgid "encodes string payloads as UTF-8" msgstr "將字串有效負載編碼為 UTF-8" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:310 -#: ce93763396994dbabdc93a51b56ed8c3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:343 +#: 38c4b6970f644bf6b1dee52c1d6f7157 msgid "" "sends the message with ``client_socket.sendall(data)`` when the server " "serves clients with one thread each, or through a non-blocking ``send()``" " loop when ``is_asynic_clients_io`` is ``True``" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:313 -#: eb3454d6feb84ce1a3e00a573cf20972 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 +#: b3f2ff47fdc74a1fb5b599b1f3706a59 msgid "" "returns ``True`` on success; it returns ``False`` for an unsupported " "payload type, and an invalid/closed connection raises ``RuntimeError`` " "(other socket failures are logged and re-raised)" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:317 -#: 62174575716644e69c0d479ff05a9df0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:350 +#: 042c1637a86c494ca7da9ba4299b08be msgid "" "And there are also some other functions which are used to send message in" " bulk to the clients, such as the `broadcast` function and the " "`send_msg_to_specific_client` function." msgstr "還有一些其他函數用於向客戶端批量發送訊息,例如“broadcast”函數和“send_msg_to_specific_client”函數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:325 -#: 762f3bf7c5bb46e091ca12b1f0393624 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:358 +#: eeecf353189a46f8972335c059bef718 msgid "TCP Server encrypted channel API" msgstr "TCP伺服器加密通道API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:327 -#: 67ffdc91d9694e77ab33c0c60253430d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:360 +#: e5659287613a419dbbecdc491f57b514 msgid "" "When the server is created with ``is_enable_encrypto=True`` (the " "default), every connected client goes through an RSA public-key exchange " "before any message content is encrypted." msgstr "當使用「is_enable_encrypto=True」(預設值)建立伺服器時,每個連線的用戶端在加密任何訊息內容之前都會經過 RSA 公鑰交換。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:332 -#: 8de167f009be4406b25e0e3d3be6cb4b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:365 +#: a31863451ad94e828e4d5826811dc4e9 msgid "Key material" msgstr "關鍵材料" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:334 -#: 01312565566c4707b6d4b55a223882d1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:367 +#: aae09222bb4b42dfb9db4c7ebc329d10 #, fuzzy msgid "" "If a parseable PEM private key exists at ``~/.ssh/id_rsa`` it is reused; " @@ -643,8 +711,8 @@ msgstr "" "私鑰存在於「~/.ssh/id_rsa」中,則它會被重複使用;否則,將在「network_api/.Flow/pvt_key」(「server_priv.pem」/「server_pub.pem」)中產生新的" " RSA-2048 金鑰對。交換的公鑰始終來源自私鑰,因此會自動選取旋轉的「~/.ssh」對。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:339 -#: 5e641bcd12c44f73bd22b43332b12b91 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:372 +#: f4206182556e4cca9a9284905e3de143 msgid "" "The public-key file next to the private key is re-derived from the " "private key on every load: if it is missing or does not match the key in " @@ -655,8 +723,8 @@ msgid "" "(Windows rejects ``os.replace`` with EACCES while a handle is open)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:346 -#: 26f407b8ad29482ca30db4edd0f20abe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:379 +#: bab30142a34845e5b01353a55c4ba643 msgid "" "A user-supplied keypair can be forced with ``is_custom_keys = " "[pub_key_path, pvt_key_path]``: both files must exist, parse as PEM and " @@ -667,8 +735,8 @@ msgstr "" "可以使用「is_custom_keys = [pub_key_path, " "pvt_key_path]」強制使用者提供的金鑰對:兩個檔案必須存在,解析為 PEM 並相互配對(使用公鑰加密的探針必須使用私鑰解密);" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:351 -#: 3af59fcb848044718426e6b9427c017d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 +#: 324dcdafcfa048218e102466956bd1a5 msgid "" "Public keys received from clients are cached in " "``network_api/.Flow/pub_key`` as ``client__.pem`` (the peer " @@ -678,13 +746,13 @@ msgstr "" "從用戶端接收到的公鑰以“client__.pem”形式快取在“network_api/.Flow/pub_key”中(金鑰來自的對等端點;“:”被替換為“_”,因此" " IPv6 文字在每個平台上都是安全的,包括 Windows)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:357 -#: 26ea5ad884b4402097ce3f800bb7e8d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:390 +#: aee5a1316ad24fab8db1dedeb6c95790 msgid "Anti-MITM identity check (TOFU)" msgstr "反 MITM 身份檢查 (TOFU)" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:359 -#: 69fe026672cc44c7b931a2a404468eb0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:392 +#: 8ceb7ab10998464e93c80c1609797ac7 #, fuzzy msgid "" "Every connection re-exchanges public keys in plaintext, and each side " @@ -697,31 +765,31 @@ msgstr "" "每個連線都以明文形式重新交換公鑰,每一方都會在「network_api/.Flow/pub_key/pub_key.json」中記錄對等點:金鑰是「(ip," " port)」(對等點連接的端點的 Python 元組),值是「[<公鑰的 sha256>,<公鑰 PEM>」。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:366 -#: f8e45fa616844ba287ea1d9a249d5157 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:399 +#: e63b24b8eded401fb82be09174963c1b msgid "" "First connection from an endpoint: the key is recorded and trusted (trust" " on first use)." msgstr "來自端點的首次連線:金鑰被記錄並受信任(首次使用時信任)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:368 -#: faa949fc11b74c9692009fba21d3a5f2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:401 +#: 9c091413145845f3b15fac0bdc9b583c msgid "" "Later connection presenting the *same* key: accepted. If the endpoint " "changed (dynamic IP / user-changed port) the record is moved to the new " "``(ip, port)`` instead of being duplicated." msgstr "稍後的連線顯示*相同*金鑰:已接受。如果端點變更(動態 IP / 使用者變更的連接埠),記錄將會移至新的「(ip,連接埠)」而不是重複。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:371 -#: d80fbe47d78343d6a5ae8b7a7388b177 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:404 +#: d89337a304a24744a703acaa977b3290 msgid "" "Later connection presenting a *different* key for an already-recorded " "endpoint: the connection is rejected (``/crypto_reject`` is sent and the " "socket closed)." msgstr "稍後的連線為已記錄的端點提供*不同的*金鑰:連線被拒絕(發送``/crypto_reject``並關閉套接字)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:375 -#: c12761b71fbb40e9b5d9f17ce7389981 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:408 +#: ff44ccbece9b48ab8e86a12cba949078 msgid "" "Because the server-side record is keyed by the client's source port, a " "client that rotates its keypair is only detected when it reconnects from " @@ -732,13 +800,13 @@ msgid "" " (or the whole file)." msgstr "由於伺服器端記錄由客戶端的來源端口作為密鑰,因此只有當客戶端從未更改的端點重新連接時才會檢測到輪換其密鑰對的客戶端;使用作業系統分配的臨時端口,新密鑰將記錄為新端點。客戶端記錄由固定伺服器位址作為金鑰,因此更改的伺服器金鑰始終會被拒絕。若要重置信任(輪換金鑰、新伺服器),請刪除「pub_key.json」條目(或整個檔案)。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:384 -#: 160b797ceb5340aaa631e6a42ed052f1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:417 +#: e011f68df76445d18659be173dba1877 msgid "Handshake" msgstr "握手" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:386 -#: 6f031912413e4e4b8b7105c3c59f1b99 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:419 +#: 700f2215924f4bfb92c3f90f37c3e514 #, fuzzy msgid "" "The client initiates the exchange by sending a plaintext " @@ -747,44 +815,74 @@ msgid "" "Both sides then push their public key files over the file-transfer " "mechanism (plaintext) and TOFU-check the received key. Both sides switch " "to encrypted mode only after ``/crypto_ready`` has been received from the" -" peer (so plaintext and ciphertext never interleave on a connection). On " -"later connections the keys are re-exchanged and TOFU-checked again; the " -"exchange is never skipped, only the identity check short-circuits for " -"known keys. Public-key pushes are only accepted from a connection that " -"actually started the handshake, so an arbitrary unauthenticated peer " -"cannot poison the registry." +" peer (so plaintext and framed traffic never interleave on a connection)," +" then each announces frame readiness with a plaintext " +"``/crypto_frames_start`` and publishes its ephemeral session ECDH public " +"key as a ``/crypto_ecdh_pub`` line inside an RSA frame; frames are sent " +"only once both announcements have been seen. On later connections the " +"keys are re-exchanged and TOFU-checked again; the exchange is never " +"skipped, only the identity check short-circuits for known keys. Public-" +"key pushes are only accepted from a connection that actually started the " +"handshake, so an arbitrary unauthenticated peer cannot poison the " +"registry." msgstr "" "用戶端透過傳送明文「/crypto_key_exchange」問候語來啟動交換;伺服器回覆``/crypto_key_exchange_ack " " " "``。然後,雙方透過文件傳輸機制(明文)推送其公鑰文件,並對收到的金鑰進行豆腐式檢查。只有在從對等方收到「/crypto_ready」後,雙方才會切換到加密模式(因此明文和密文永遠不會在連線上交錯)。在以後的連接中,密鑰將被重新交換並再次進行" " TOFU 檢查;交換永遠不會被跳過,只有已知密鑰的身份檢查會短路。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:400 -#: 1efd337c73d249a3b4b15394337e6307 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:437 +#: a9531ad5339a4633a1e6cc54fb8bb79b msgid "Replay protection" msgstr "重播保護" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:402 -#: 28c8ec1c26d946a19bc02d6aacc9961b -msgid "" -"The handshake exchanges a random session nonce, and every encrypted line " -"on the wire carries it plus a per-connection sequence number: ``||``. The receiver drops a line whose nonce does " -"not match the current session (ciphertext replayed from an older " -"connection) or whose sequence number is not the expected one (ciphertext " -"replayed within the session / out of order); both counters reset when the" -" socket flips to encrypted mode after a (re-)exchange." -msgstr "" -"握手交換隨機會話隨機數,線路上的每條加密線路都攜帶它加上每個連接的序號:``||``。接收方丟棄隨機數與目前會話不符的行(從舊連接重播的密文)或其序號不是預期的行(會話內重播的密文/亂序);當套接字在(重新)交換後切換到加密模式時,兩個計數器都會重置。" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:411 -#: c11de683c36c42c59ff73d0839f5afce +#: ../../source/Network_APIs/TCP_Server_APIs.rst:439 +#: e9505df5322640ce8671b5098d655374 +msgid "" +"The handshake exchanges a random session nonce, and every encrypted " +"message travels in a frame — ``magic | type (1) | body length (4) | " +"body`` with ``||`` at the start of the body. Frame " +"type 1 carries a small text payload as chunked RSA-OAEP ciphertext (the " +"historic wire encoding); type 2 carries everything else, including all " +"binary and file data, as a ``pf_ecdh_seal`` blob (AES-256-GCM keyed by " +"the session's ephemeral ECDH keypair, with ``|`` bound as " +"AAD). The receiver reads the type from the frame instead of inferring the" +" algorithm from the payload length, and sequence numbers are per socket " +"and cover both frame types. The receiver drops a frame whose nonce does " +"not match the current session (replayed from an older connection) or " +"whose sequence number is not the expected one (replayed within the " +"session / out of order); both counters reset when the socket flips to " +"encrypted mode after a (re-)exchange." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:455 +#: 3fd7ac4d381e41589a62998726dd22f7 +msgid "Encrypted transfer connections" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:457 +#: 8ca69d91005b459a8a56f21902eaa690 +msgid "" +"File and folder transfers, forwarded items and the forward relay run on " +"temporary TCP connections. The listening side stamps each leg with its " +"mode and a fresh nonce in the port advertisement " +"(``/server_file_transfer_port``, ``/forward_upload``); with " +"``is_enable_encrypto`` enabled both sides then frame that connection " +"exactly like the control channel, with the same session key material, so " +"file contents, names and sizes no longer cross the wire in the clear. The" +" public-key pushes themselves stay plaintext by construction: they carry " +"the keys the session is built on. A leg whose stamp promises encryption " +"is aborted when the session key material is not ready rather than " +"silently downgraded." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:469 +#: b32b4fa4788d4f9d88926958c81ad73f msgid "Decode verification and key rotation" msgstr "解碼驗證和金鑰輪換" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:413 -#: ba7b28826b9f4d0a85328f08be4a76e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:471 +#: d09ae3121b0f40fb85374589b851d45c msgid "" "Every encrypted plaintext carries the fixed suffix ``_VALID`` (separated " "by ``_``). If a message cannot be decrypted, or the suffix is missing, " @@ -801,20 +899,25 @@ msgstr "" " TOFU 檢查:金鑰未變更的對等點將再次被接受,而為記錄的端點提供「不同」金鑰的對等點將被拒絕(請參閱上面的 TOFU " "部分)。故意輪換金鑰對的使用者必須刪除對等端過時的「pub_key.json」條目(或整個檔案)才能重新信任新金鑰。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:424 -#: 6f0160000f2b451a81771556bbc3b8e7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:482 +#: 7312fb4bd4c345ff9cec7ffe4245afb7 +#, fuzzy msgid "" "Re-exchanges are circuit-broken: after ``MAX_DECODE_FAILURES`` (3) " "consecutive decode failures on one connection the connection is closed " "instead of re-exchanging, so a garbage-injection or persistent-mismatch " -"storm cannot spin the loop forever. A successful decryption resets the " -"counter." +"storm cannot spin the loop forever. Genuine peer traffic (messages and " +"commands other than the protocol's own handshake/coordination lines) " +"resets the counter. Frames the peer had already sent when this side " +"dropped out of encrypted mode are stale: they cannot be authenticated any" +" more, so they are consumed and dropped — they neither surface as " +"messages nor reset the counter." msgstr "" "重新交換是斷路的:在一個連接上「MAX_DECODE_FAILURES」(3) " "連續解碼失敗後,連接將關閉而不是重新交換,因此垃圾注入或持久不匹配風暴無法永遠旋轉循環。成功解密會重置計數器。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:438 -#: 850c5c67b6504551a3104a9cfa5710e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 +#: 4fb05c76f6734fd58aa33ee628ad933d #, fuzzy msgid "" "The `broadcast` function sends a message to all clients in the " @@ -824,8 +927,8 @@ msgid "" "the ``exclude_client`` parameter when sending the message." msgstr "在「broadcast」函數中,它將向「self.clients」變數中的所有用戶端發送訊息,並刪除已經與伺服器斷開連接的用戶端。如果“exclude_client”參數不是“None”,則伺服器在傳送訊息時將排除“exclude_client”參數指定的用戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:452 -#: 9ddd28be0e6b439891a25d79adbaf823 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:514 +#: 0b4f67331831429b85514fbbe3ce2602 #, fuzzy msgid "" "The `send_msg_to_specific_client` function sends one or more messages to " @@ -838,41 +941,43 @@ msgstr "" "`send_msg_to_specific_client` 函數用於透過客戶端 ID " "向一個或多個特定客戶端發送一條或多個訊息。並且“message”參數應該輸入發送訊息命令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:459 -#: 4f7cd128081c4062bffdacfb4b67137c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 +#: c8f357719cc548719792a5a2cade0c03 msgid "" "These methods form the server's client I/O loop and ensure reliable " "message exchange for connected TCP clients." msgstr "這些方法會形成伺服器的客戶端 I/O 循環,並確保連線的 TCP 用戶端進行可靠的訊息交換。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:466 -#: 29e71306645e4ab1956b627b46f7b656 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 +#: 8936cbe70fcf44ac9cabec9e38c0195d #, fuzzy msgid "TCP Server inbound event listener API" msgstr "TCP伺服器檔案傳輸API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:468 -#: f86e7c53407b43509932d19288024a54 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 +#: 583ef0a34dfc480da5b4fc87108cbf2f msgid "External code can observe traffic without replacing the protocol loop:" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:478 -#: f59f2230d9f648ca99834633af460deb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:540 +#: 0a30ecd70b364968a892136d9bec809f msgid "" "``add_message_listener`` registers ``listener(client_id, message)`` for " -"every inbound plain message (lines that do not start with ``/``; commands" -" go to the command handlers instead). ``add_file_listener`` registers " -"``listener(client_id, full_path, name, size, command)`` and fires after a" -" file uploaded by a client has been fully written to the transfer " -"directory (``command`` is the wire command that triggered it, so protocol" -" pushes such as ``/crypto_pub_key`` can be recognised). Both listeners " -"run on a protocol thread, so they must not block, and an exception inside" -" a listener is logged and swallowed. The ``remove_*`` counterparts " -"unregister a listener and ignore unknown ones." -msgstr "" - -#: ../../source/Network_APIs/TCP_Server_APIs.rst:489 -#: a39677d08af4439989a6fced80cb12d1 +"every inbound line, commands included (``/help``, ``/file ...``, the " +"crypto handshake lines, ...), so a listener observes all inbound traffic;" +" line dispatch is unaffected, a command still goes to the command " +"handlers. ``add_file_listener`` registers ``listener(client_id, " +"full_path, name, size, command)`` and fires after a file uploaded by a " +"client has been fully written to the transfer directory (``command`` is " +"the wire command that triggered it, so protocol pushes such as " +"``/crypto_pub_key`` can be recognised). Both listeners run on a protocol " +"thread, so they must not block, and an exception inside a listener is " +"logged and swallowed. The ``remove_*`` counterparts unregister a listener" +" and ignore unknown ones." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:553 +#: a7bb1a9276bd4860882ffd43a680d6bf msgid "" "In addition, received messages and events are stored per sender socket in" " ``messages_dict`` / ``events_dict`` (each entry a ``[content, " @@ -881,30 +986,31 @@ msgid "" "``network_api/.Flow`` and cleared; ``stop`` flushes both stores." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:498 -#: cdfe98e71ed34af9a2976b7e884b5201 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 +#: 403a3b0e938b4895be69267c66ecff98 msgid "TCP Server command API" msgstr "TCP 伺服器命令 API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:500 -#: 25c853b63e744fd6a370ecd365c58fd7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 +#: 9c016262f199458585bb12055da6d30d msgid "" "The server supports several built-in commands and a command extension " "API. The main entry point is the `handle_command` method, which is " "invoked for any message starting with ``/``." msgstr "伺服器支援多個內建命令和命令擴展 API。主要入口點是「handle_command」方法,任何以「/」開頭的訊息都會呼叫該方法。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:505 -#: d0e290f03c1242b580024033ffab5e04 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 +#: b26b06ec49a644c9b034acf6930006bd #, fuzzy msgid "" "We support two solutions for command handling: inputting a command in the" " console or receiving a command from other clients. You can also call the" -" functions defined for each command in the code." +" functions defined for each command in the code via " +"`call_extension_functions`." msgstr "我們支援兩種命令處理方案,一種是在控制台輸入命令,另一種是從其他用戶端接收命令,您也可以呼叫程式碼中為命令定義的函數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:510 -#: aad12adb23334f4e9c5b6b7f7637dd3e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:575 +#: 5f20432236324511acfc720b1e616e49 #, fuzzy msgid "" "*Note: You can select the solution which you want to use by changing the " @@ -915,81 +1021,93 @@ msgstr "" "*注意:您可以透過變更「TCP_Server_Base」類別的參數來選擇要使用的解決方案,該參數為「is_input_command_in_console」。" " ``True`` 允許伺服器在控制台輸入指令,而``False`` 不允許。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:517 -#: 88e051e4fef245c7a474a8478dc74b88 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:582 +#: cc5dd7cfa448466399da9463e53c1a08 msgid "Built-in client commands include:" msgstr "內建客戶端指令包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:519 -#: c8a591e28fcf4243862e820e582e9127 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:584 +#: 989d1b29c70e4f9883b95523b0b420d9 msgid "``/help``: returns the available command list and usage hints." msgstr "``/help``:傳回可用的指令清單和使用提示。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:520 -#: 453004b0bb914398a4d9a437f5d1b864 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:585 +#: a4795afd8b3249538f031ed27783f0a7 msgid "``/time``: returns the current server time." msgstr "``/time``:傳回目前伺服器時間。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:521 -#: 324cbdab33984517a498f1e2747a6387 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:586 +#: b2d813b2d8bb46c59195ed01431d150b msgid "``/clients``: returns the list of connected client IDs." msgstr "``/clients``:傳回已連線的客戶端 ID 清單。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:522 -#: a4411c0f498c434fbe864ea1627384fb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:587 +#: d81ad6c5cbe44bd589f32ce7f3e36d31 msgid "" "``/quit``: writes a goodbye message (``Bye!``) and shuts the connection " "down, so a client that stays after sending ``/quit`` is disconnected by " "the server." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:525 -#: 1248e1b365da420e8d96182e8a237d57 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:590 +#: a9fbf429095b4483b18a247ef327b461 msgid "" "``/file [destination_file_path]``: starts a file transfer " "from the client to the server. The trailing token of the wire line is the" " sender's own transfer id, appended by the sending client." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:528 -#: c8de5282934945bab929e1084d7848f5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 +#: cef48a93703449f8813fab1d3fb199fb #, fuzzy msgid "" "``/file_folder [destination_file_path]``: starts a folder " "transfer from the client to the server (same trailing id)." msgstr "``/file_folder ``:啟動從客戶端到伺服器的資料夾傳輸請求。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:530 -#: d006c91db83f4404b7f7022cb9bb61c5 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:595 +#: 92bf2736c9c14f1cb24ec110315f8caa msgid "" "``/crypto_mode <0|1>``, ``/crypto_pub_key``, ``/crypto_pub_key_request``:" " internal handshake messages of the encrypted channel." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:532 -#: c026024882d44552a578b0fe4e096b34 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:597 +#: 38987654adbf4707b84c8048a9cdcbb3 msgid "" "``/forward_item``, ``/forward_send_msg``, ``/pause_trans``, " -"``/start_trans``: internal forwarding/transfer-control messages." +"``/start_trans``: internal forwarding/transfer-control messages. " +"``/pause_trans `` and ``/start_trans `` hold and release the " +"outbound transfer with that fid (`pause_trans`/`start_trans` are the same" +" switch as a public API)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:534 -#: 5fb7405e0dae4344a58d3a61aa5f2779 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:601 +#: 7f3801d57ac34670bbe16736683db30e +msgid "" +"``/resume_trans `` and ``/forward_resume " +"``: internal transfer-reconnect messages: the receiver asks the " +"sender (or, for a forwarded transfer, the originator) to continue the " +"file from the bytes already on disk. See `resume_transfers`." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:605 +#: abd7d3032e15468e92f96a0b5af1f926 msgid "" "``/server_file_transfer_port ``: internal protocol " "message used to coordinate file transfer ports." msgstr "``/server_file_transfer_port ``:用於協調檔案傳輸連接埠的內部協定訊息。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:536 -#: 94f93b06051f4eebaf0b64ccf589160b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:607 +#: 1e9e32071bb1425b8617a419a7ef87f6 msgid "" "In `handle_command`, the server will first check if the command matches " "any built-in commands. If it does, the `handle_command` will call the " "functions which are defined for the commands." msgstr "在`handle_command`中,伺服器將首先檢查該命令是否與任何內建命令相符。如果這樣做,「handle_command」將呼叫為命令定義的函數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:541 -#: 16991ef553344476af487507dc3a1a0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:612 +#: f08564b44ab0442788145105b1086bb8 msgid "" "If a command is not recognized by the built-in handler, `handle_command` " "will check if it matches any registered custom commands from the command " @@ -1000,30 +1118,38 @@ msgstr "" "如果內建處理程序無法識別命令,「handle_command」將檢查它是否與命令擴充 API " "中註冊的任何自訂命令相符。如果該命令已註冊,則「handle_command」將呼叫為該命令定義的函數。命令擴充 API 定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:559 -#: 9c0334fe21e34b6ab8b1c941e1c62e2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:633 +#: ac06208b93d54ede93002123521d921b +msgid "" +"`call_extension_functions` runs one registered command's handler straight" +" from code; the command's first token selects it, exactly as it does for " +"a typed line." +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:637 +#: 11c186c6375b4eeeb337ac755b136a94 msgid "The args of the `register_command` function are as follows:" msgstr "`register_command` 函數的參數如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:562 -#: ac4db02fce3d492b81a094400f44b0a8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 +#: 6741d64e02414c1c8759b14d41ec69a1 msgid "``command_name``: The name of the command to register." msgstr "``command_name``:要註冊的命令的名稱。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:564 -#: 8e250a4664ce40c89f0190ce7eb67848 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:642 +#: 21a28c492d33486a81f97ca3d8a32266 msgid "" "*Note: The ``command_name`` should start with a slash (e.g., " "``/my_command``) to be recognized as a command.*" msgstr "*注意:``command_name`` 應以斜線開頭(例如,``/my_command``)才能被辨識為指令。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:567 -#: f91cdc45f9ea4c35891b087f1097ba51 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:645 +#: 6deb6588265049cbbeaea615b7d6c2cf msgid "``handler``: The function to call when the command is received." msgstr "``handler``:收到指令時呼叫的函數。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:569 -#: 1797ec404bbe45b380d46588adbb731f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:647 +#: 16d22c49f16d4430bfe740374d70705f #, fuzzy msgid "" "*Note: The ``handler`` function must have exactly three parameters: " @@ -1037,20 +1163,20 @@ msgstr "" "``client_socket`` 將被接受為發送命令的網路套接字對象,``client_address`` " "將被接受為發送命令的客戶端的地址,而``command`` 參數將包含實際的命令字串。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:577 -#: 56b8f72098b84ccea4d1bf143a31e04c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:655 +#: 7605062541fa4d70ae37d67efdfd5fdf msgid "``where_to_run``: Specifies where the command should be executed." msgstr "``where_to_run``:指定應執行指令的位置。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:578 -#: 7572e9944acd4704b2c55643fb1fbcd4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:656 +#: f6ee42356212497ba468266c87e127d4 msgid "" "``run_in_thread``: A boolean indicating whether to run the command in a " "separate thread." msgstr "``run_in_thread``:一個布林值,指示是否在單獨的執行緒中執行指令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:580 -#: 0ac212e49ef54e77b5429272e05561aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:658 +#: 37adfd2db6af47bf995b271dd70ad293 msgid "" "This extension API allows server-side and console-side custom commands to" " be registered dynamically. Valid values for ``where_to_run`` are " @@ -1062,16 +1188,16 @@ msgstr "" "此擴充 API 允許動態註冊伺服器端和控制台端自訂命令。 “where_to_run” 的有效值為「伺服器」和「客戶端」。 " "「伺服器」表示當客戶端發送命令時將處理該命令,而「客戶端」表示當伺服器在控制台中輸入命令時將處理該命令。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:589 -#: c0201e2dd3fd4c7fa8d363060c5ff49a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:667 +#: 24c64499179b4f01a92ffd8e88515738 #, fuzzy msgid "" "*Note: It's true that the valid values for ``where_to_run`` are not " "ideal, but we have not yet found a better way to define that.*" msgstr "*注意:確實,``where_to_run`` 的有效值太奇怪了,但我們沒有找到更好的方法來定義它。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:593 -#: ec3b9b188728413eb3cd5871542b83cd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:671 +#: fbdb162f54a64fd3b454ddbf85a6e5d4 #, fuzzy msgid "" "The ways to run the command will be different according to the args " @@ -1082,8 +1208,8 @@ msgid "" "receive thread, or the caller of ``handle_command``)." msgstr "根據參數“run_in_thread”,運行命令的方式會有所不同。如果“run_in_thread”為“True”,則命令處理程序將在伺服器執行緒池中的單獨執行緒中執行。如果“run_in_thread”為“False”,則命令處理程序將在主伺服器執行緒中同步執行。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:603 -#: 0a62647e915e4e4c80071b3d7fb41464 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:681 +#: 9576b9601ddd48749947aa7b18bc2c82 #, fuzzy msgid "" "*Note: We store the registered commands in a list variable with two " @@ -1101,23 +1227,23 @@ msgstr "" "*注意:我們將註冊的命令儲存在一個列表變數中,該列表變數的內層有兩個字典,該列表變數定義為“self._custom_handlers”,在“__init__”方法中初始化。命令及其處理程序將根據“where_to_run”的值儲存在其中一個字典中。對於``“server”``,它將儲存在第一個字典中,否則儲存在第二個字典中。字典的鍵都是指令名,值是另一個包含處理函數的字典。還有另一個清單變數定義為“self._custom_handler_threaded”,它在“__init__”方法中初始化,它包含所有應該在單獨執行緒中執行或不執行的命令。" " *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:617 -#: eb202f79be654e5a8cccf56c79446b3d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:695 +#: b1f239408f354bf2bdc608ad523f233e msgid "" "*Note: ``register_command`` returns ``False`` when ``where_to_run`` is " "neither ``\"server\"`` nor ``\"client\"`` (nothing is registered then); " "on success it returns ``None``.*" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:626 -#: 088dcc7ce39046a4afa6451d7e6369f9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:704 +#: b10dad811f9b444bb0a2e3642709b5d1 msgid "" "After that, the command handler will be called according to the command " "name, and run them by a command executor which is defined as:" msgstr "之後,命令處理程序將根據命令名稱被調用,並由命令執行器運行它們,命令執行器定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:640 -#: 0e56345aa429469cb44d7708b6af8711 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:718 +#: 7c0987568cf245b9b78d1db2f403717f msgid "" "In this executor function, there is a try-except code block to catch the " "error when running the command handler. If there is an error when running" @@ -1131,8 +1257,8 @@ msgstr "" "程式碼區塊來捕獲執行命令處理程序時的錯誤。如果執行命令處理程序時發生錯誤,伺服器將記錄錯誤訊息,如果命令來自用戶端,也會將錯誤訊息傳送回用戶端。在" " try 程式碼區塊中,將使用命令參數呼叫命令處理程序,如果命令來自客戶端,也會使用客戶端套接字和客戶端位址。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:650 -#: 6467226e231c4e458bb78687c9da8659 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:728 +#: a98408c31eee4f3fbad1c3afdb2a036c #, fuzzy msgid "" "If the command doesn't run in the thread, the command executor will be " @@ -1142,8 +1268,8 @@ msgid "" "defined as:" msgstr "如果命令不在執行緒中執行,則命令執行器將直接在「handle_command」函數中呼叫。但是如果命令應該在單獨的執行緒中運行,則命令執行器將使用「submit_task」方法提交到伺服器的執行緒池,該方法定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:665 -#: fb9ac9433b8342dd9e90707a01990fd0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:743 +#: c3401f2293044a31a7e8e6d2e8407797 #, fuzzy msgid "" "The `submit_task` method is a helper function that submits a callable to " @@ -1155,8 +1281,8 @@ msgid "" "loop." msgstr "「submit_task」方法是一個輔助函數,它將可呼叫函數提交給伺服器的內部執行緒池執行器。它接受一個函數及其參數,並安排它在單獨的線程中執行。這允許長時間運行或阻塞命令處理程序運行而不會阻塞主伺服器循環。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:675 -#: 711e7a3b8f114200857fc39218e2820f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 +#: 9a327fd5482b4575a777e49024f42f56 msgid "" "In this high-level TCP network protocol, a temporary TCP server and " "client can also be created very simply. The temporary TCP server or " @@ -1169,8 +1295,8 @@ msgstr "" "伺服器或用戶端可用於需要額外套接字或連接埠以避免與主伺服器或用戶端循環發生衝突的場景。例如檔案傳輸功能。建立臨時 TCP 伺服器和客戶端的 API" " 定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:688 -#: 7368e712e93f4be7aaeeae265b22e832 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:766 +#: b1e9ab095ed84ef8ae08333047df5b93 msgid "" "``create_temporary_server`` returns ``(port, thread, stop_event)``: the " "bound port (``palloc()`` picks one when ``port`` is None), the accept-" @@ -1179,44 +1305,44 @@ msgid "" " allocated." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:693 -#: 0750bd372cf6478eb8123ca0603de9c2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:771 +#: d23ff87180c44746b62528903a34cdb5 msgid "" "``create_temporary_client`` returns ``(client_socket, thread, " "stop_event)``: the connected socket, the receiver thread and an event " "whose ``set()`` ends that thread." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:700 -#: edf78b86ed664657adc2b46ab0f7efdd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:778 +#: c14e33129d3b41ee8c1dac7189f0408d msgid "TCP Server console commands" msgstr "TCP 伺服器控制台命令" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:702 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:780 +#: 2ad09a3887894e01a67d31c28272f730 msgid "" "The server console input thread accepts administrative commands when " "``is_input_command_in_console`` is ``True``. Supported console commands " "include:" msgstr "當“is_input_command_in_console”為“True”時,伺服器控制台輸入執行緒接受管理命令。支援的控制台命令包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:706 -#: 5a059eb897914040873e954609c66c0c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:784 +#: 4d4368102eae41dbac5a8938a4726e1a msgid "``/stop``: stops the server and closes all active connections." msgstr "``/stop``:停止伺服器並關閉所有活動連線。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:707 -#: db67da00bf70423a9a3cf4a2fa3a01e1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:785 +#: 8035f922921f4301bbe4ca4936ea38b3 msgid "``/status``: prints the current connection count and running state." msgstr "``/status``:列印目前連線計數和運行狀態。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:708 -#: 15ab35eecbd84e64b8dfc0ac50c3d173 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:786 +#: ce2138bd90784f1daffb39cc8d46d1f1 msgid "``/clients``: prints the connected clients and their connection times." msgstr "``/clients``:列印連線的客戶端及其連線時間。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:709 -#: 2d1d3fe9ee9f4d6899754d296f8ede75 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:787 +#: 8c9f96a3d0cd4fbcb311c201db9ff789 msgid "" "``/send_msg <(ip, port)> ...``: sends one or more messages " "to specific clients. Targets are literal ``(ip, port)`` tuples (its own " @@ -1224,24 +1350,24 @@ msgid "" "form)." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:710 -#: 92d75f708fe642cf8a77f986f2d891b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:788 +#: 033fdbf663a04e12bfdff63da6e0f6c1 #, fuzzy msgid "" "``/file <(ip, port)> [destination_file_path]``: sends a file " "from the server to a specific client." msgstr "``/file ``:將檔案從伺服器傳送到特定客戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:711 -#: 8b28ccd83c594ee5a0ccd126db3bb2dd +#: ../../source/Network_APIs/TCP_Server_APIs.rst:789 +#: 49fea0c411844c689ea2cabaa11c70b3 #, fuzzy msgid "" "``/file_folder <(ip, port)> [destination_file_path]``: " "sends a folder from the server to a specific client." msgstr "``/file_folder ``:將資料夾從伺服器傳送到特定客戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:712 -#: 585e54ca3b1545f49a347b69680d3cd2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:790 +#: d4c2a98b15c04214bfca54bd719f9ab4 msgid "" "``/multiple_file_multiple_client ... <(ip, port)1> <(ip, " "port)2> ...``: sends multiple files to multiple clients. Tokens are " @@ -1249,8 +1375,8 @@ msgid "" "otherwise, so files and targets may be interleaved." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:713 -#: 60def6731a3a43d1a074374978801dbc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:791 +#: e6c9995a12a24a6ba5534e475f158d86 msgid "" "``/diff_multiple_file_diff_multiple_client ... <(ip, " "port)1> <(ip, port)2> ...``: sends the files that precede a group of " @@ -1259,13 +1385,13 @@ msgid "" " that is not a tuple) is accepted and passed on." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:714 -#: 0f9a9437ddcd4894b6be7502e1303c6e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:792 +#: d8253e90b4fe4d8dbe0b2bbd23134dc0 msgid "``/help``: prints a help summary of console commands." msgstr "``/help``:列印控制台指令的幫助摘要。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:716 -#: 1e898bf6aeb54dcb8533615767d03791 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:794 +#: 8cf019297938433ebe65839a4513ae63 msgid "" "The forward commands (``/forward_send_msg``, ``/forward_file``, " "``/forward_folder``) are client-only and are refused on the server " @@ -1273,15 +1399,15 @@ msgid "" "``where_to_run=\"client\"``." msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:721 -#: aff923b39d6843bb976f5bb40d38a71d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:799 +#: 43db2954705945c3b3b0742033f122b9 msgid "" "These console commands make it easy to manage the active server and " "perform server-initiated file transfers without modifying the code." msgstr "這些控制台命令可以輕鬆管理活動伺服器並執行伺服器啟動的檔案傳輸,而無需修改程式碼。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:725 -#: bcbb903def99415298bb7b29d21f31f6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:803 +#: 261fde939721476abba9b40f0290944f #, fuzzy msgid "" "*Note: It is too long to introduce all the console commands, so for more " @@ -1290,20 +1416,20 @@ msgstr "" "*注意:由於篇幅太長,無法介紹所有控制台命令,因此有關更多詳細信息,請參閱 :ref:`tcp-server-console-commands` " "部分。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:729 -#: c68a8d4ecb904da7980049abc5210fdf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 +#: 0e848b37570e4fc8b23ff7eb13a2ae3e msgid "TCP Server file transfer API" msgstr "TCP伺服器檔案傳輸API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:731 -#: 1e9d70417dbf4446bc8528cf692db8ed +#: ../../source/Network_APIs/TCP_Server_APIs.rst:809 +#: 27472ef4f13641ba9a08e6a97bb651dc msgid "" "The TCP server contains a file transfer subsystem that supports both " "client-to-server and server-to-client transfers." msgstr "TCP 伺服器包含一個檔案傳輸子系統,支援客戶端到伺服器和伺服器到客戶端傳輸。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:735 -#: 695753d4c2bc4f15972565a20be6b6c8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 +#: eadd29678d8a449c9659c4792b5f2cb0 #, fuzzy msgid "" "It's too long to introduce all the file transfer functions, so there is " @@ -1311,40 +1437,40 @@ msgid "" "details of the file transfer functions, please visit ..." msgstr "由於篇幅太長,無法介紹所有文件傳輸功能,因此僅列出了文件傳輸功能的 API 列表,想要了解更多文件傳輸功能的詳細信息,請訪問..." -#: ../../source/Network_APIs/TCP_Server_APIs.rst:740 -#: 5f303019ed3747a691e61b7f20cdb1cf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:818 +#: 1ca2a6ce0f124ebc87676b1155c4c022 msgid "The file transfer API for you to use includes:" msgstr "供您使用的文件傳輸 API 包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:742 -#: 376da0b60e9641efa6a75ed7e52af8bf +#: ../../source/Network_APIs/TCP_Server_APIs.rst:820 +#: 63c118c7e7c4478fa14f3cb0950f6c1c msgid "The basic function for the server-to-client file transfer is defined as:" msgstr "伺服器到客戶端文件傳輸的基本函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:753 -#: 80a158519403430f8f7c43893634e6d2 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 +#: 4e3a0194c55744898eb3884b60d75672 msgid "The file transfer function which will run in the threads is defined as:" msgstr "將在執行緒中運行的文件傳輸函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:764 -#: 771b5bd6acad467d92fbeebcacbc6dba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 +#: 3fd7ac4d381e41589a62998726dd22f7 msgid "The folder transfer function is defined as:" msgstr "資料夾傳輸函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:773 -#: da45b1e2fcc34c1a96c1d1f9e809f742 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 +#: 833a77a7c8fa480db0a0b6e8387132d3 msgid "The multiple files transfer to multiple clients function is defined as:" msgstr "多個檔案傳輸到多個客戶端功能定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:783 -#: 15099b87947a4f08a34ca87734c23306 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:861 +#: 26032ba6212f443980c40351874b2139 msgid "" "The different multiple files transfer to the different multiple clients " "function is defined as:" msgstr "不同的多個檔案傳輸到不同的多個客戶端函數定義為:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:793 -#: d93a80b4acca404f98faaf0a7f133079 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:871 +#: 0c9b95c194634285aade290fb17bef5b #, fuzzy msgid "" "We recommend that if you want to use the mono-file transfer function, use" @@ -1364,8 +1490,8 @@ msgstr "" "file_transfer_server_recv_client_start " "函數,否則檔案傳輸函數可能不太穩定。而對於其他檔案傳輸函數,我們不太建議您在線程中使用它們,因為函數中已經有一些線程控制機制,所以不必擔心並發效能。如果你在執行緒中呼叫它們,可能會出現一些意想不到的錯誤,而且也可能會變得不必要的複雜性。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:807 -#: c3f69c0b152c44df91753c54cf94593f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:885 +#: 28c7d60dd34d48ababd9c06199091309 msgid "" "*Note: The file transfer API functions are designed to be called from the" " command handlers for both client-initiated and server-initiated " @@ -1375,18 +1501,18 @@ msgstr "" "*注意:文件傳輸 API " "函數設計為從命令處理程序調用,以進行客戶端啟動和伺服器啟動的傳輸。它們處理傳輸連接埠、客戶端連接和實際檔案資料傳輸操作的協調。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:813 -#: 666eecd4aa974e2d8b5b9a1ff3acbc25 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:891 +#: 0fcf1a7def3e437d9ecbaf8d5d02470a msgid "Client-to-server transfer flow:" msgstr "客戶端到伺服器的傳輸流程:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:815 -#: f6b96397ab484021974c50cf86144a12 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:893 +#: 740bd9ad4564417e8f76f28500d1da68 msgid "The client sends ``/file`` or ``/file_folder`` to request a transfer." msgstr "客戶端發送``/file`` 或``/file_folder`` 來請求傳輸。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:817 -#: d6b57e1e1e6e4ea78d59d9a47a1a4ccc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:895 +#: e26bd8a6fb5a4977a3039fd2bdf22114 #, fuzzy msgid "" "``handle_command`` starts a dedicated file-server thread: " @@ -1395,8 +1521,8 @@ msgid "" "``/file_folder``." msgstr "「handle_command」使用「file_transfer_server_recv_server_start_thread」啟動專用檔案伺服器執行緒。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:821 -#: 3ba05b4bc071401d959f68b7019c7aa3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:899 +#: e5ef46040255421fa92c6de33d976671 msgid "" "The server allocates an ephemeral transfer port with ``palloc`` and sends" " ``/server_file_transfer_port `` back to the client." @@ -1404,65 +1530,65 @@ msgstr "" "伺服器使用“palloc”分配臨時傳輸連接埠並將“/server_file_transfer_port " "”傳回客戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:825 -#: 9f8b5c7e3b8048c9b9ded191ecd70d6b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:903 +#: 6eaa70d4d985489e8f0e683baa6b52a1 msgid "" "The client connects to that transfer port and sends file metadata, " "including length-prefixed filename and file size." msgstr "用戶端連接到該傳輸連接埠並發送文件元數據,包括帶有長度前綴的檔案名稱和檔案大小。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:828 -#: 95c2b39e285840678adb522483da672b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:906 +#: 245d5d51d72a41ee86c9925ec1872e35 msgid "The server receives the file and writes it under ``received_files``." msgstr "伺服器接收檔案並將其寫入“received_files”下。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:831 -#: 8254cf417a46471ea770e4917e96b05b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 +#: 5ad02fbb498f483580e470b2f5291a53 msgid "Server-to-client transfer flow:" msgstr "伺服器到客戶端的傳輸流程:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:833 -#: 69032201d7254006b52a86961f08530a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:911 +#: 341ba310459442de906ec90ad72a16d9 msgid "" "``file_transfer_server_recv_client_start`` is used to initiate outgoing " "transfers from server to a connected client." msgstr "``file_transfer_server_recv_client_start`` 用於啟動從伺服器到連線的客戶端的傳出傳輸。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:835 -#: 408f93d233f44860a854950b3e60f8f8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:913 +#: c5f727be6f954b9d87c3ebf0b8ae32ce msgid "" "The server sends transfer commands to the client socket and waits for the" " client to establish the file transfer connection." msgstr "伺服器向客戶端套接字發送傳輸命令,並等待客戶端建立檔案傳輸連線。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:837 -#: 718dadb723164e65a2eb6fdcfb7d8420 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:915 +#: 88151618a44849269aea215557a4ca1c msgid "" "Folder transfers are performed recursively, with each file transfer " "respecting ``self.max_file_transfer_thread_num`` and the configured " "semaphore limit." msgstr "資料夾傳輸以遞歸方式執行,每個檔案傳輸都遵循“self.max_file_transfer_thread_num”和配置的信號量限制。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:840 -#: f23efbda41cb40289b93c954f6d051b0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:918 +#: 4734f1f535e7485ca5c91b06dec65f79 msgid "Common file transfer helper methods include:" msgstr "常見的文件傳輸幫助方法包括:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:842 -#: b86c426b7c8a46b59735ef1a6a0da725 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:920 +#: aaa12a7a9d3f4adeb08d59d5fbc9d131 msgid "" "``file_transfer_server_recv_server_start``: receives file data from a " "client." msgstr "``file_transfer_server_recv_server_start``:從客戶端接收檔案資料。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:843 -#: 74859cc9d4a745d99225f6522b4455c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:921 +#: 404a990c105247b09e2f2d1716527269 #, fuzzy msgid "``file_transfer_server_recv_client_start``: sends a file to a client." msgstr "``file_transfer_server_recv_client_start``:將檔案或資料夾傳送到客戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:844 -#: 78042f93790547a8a844087d3daf81b6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:922 +#: 0ec7dfbbfb1644f1ad5c42a1b2a04dc9 #, fuzzy msgid "" "``file_transfer_mode``: performs the low-level sender-side transfer " @@ -1470,28 +1596,28 @@ msgid "" "key to a client)." msgstr "``file_transfer_mode``:執行低階客戶端傳輸握手。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:846 -#: a03a3b41f63c4c7d8e6800e6e42c215f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:924 +#: 6056cfcc5fa740e58986f2e8ce900042 msgid "" "``file_transfer_mode_recv``: performs the low-level receive-side transfer" " handshake." msgstr "``file_transfer_mode_recv``:執行低階接收端傳輸握手。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:851 -#: 82f418a15fbf4c009e188c0fe656a483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:929 +#: e0dc9b775fb94f0ab2728b56c57f88bd msgid "Port allocation API" msgstr "連接埠分配API" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:853 -#: c041090f476c4f37a46fc7a3f49653cb +#: ../../source/Network_APIs/TCP_Server_APIs.rst:931 +#: 9711bca31e6b464e940739ba262f5153 #, fuzzy msgid "" "The server allocation APIs allow you to allocate a new port for other " "servers. There are two kinds of port allocation modes." msgstr "伺服器分配 API 允許您為其他伺服器指派新連接埠。連接埠分配方式有兩種。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:857 -#: 4fa11de65ebc4b51b83ea26802b43e3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:935 +#: 30e2a47526db46b29ef31b8730b5dd8a msgid "" "To change the port allocation mode, you can set the " "``is_hand_alloc_port`` argument on the server instance. When set to " @@ -1499,8 +1625,8 @@ msgid "" "mode, or set to ``True`` it will choose the manual allocation mode." msgstr "若要變更連接埠分配模式,您可以在伺服器實例上設定“is_hand_alloc_port”參數。當設定為“False”時,伺服器實例將選擇自動連接埠分配模式,或設定為“True”時,伺服器實例將選擇手動分配模式。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:863 -#: aaa3428304234c0f81e2f83ab0481f17 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 +#: 2a3a8472358240aea19de918a8d83602 #, fuzzy msgid "" "We strongly recommend using the automatic port allocation mode, which is " @@ -1510,16 +1636,16 @@ msgid "" "``0``." msgstr "我們最推薦您使用自動連接埠分配模式,這是伺服器的預設模式,因為自動連接埠分配模式比手動連接埠分配模式更簡單,也更穩定。在此模式下,呼叫分配API時,將傳回``0``。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:870 -#: f9fbfedba34e4c3386442a9425b52a44 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 +#: 29df017de0bc4b399ebbe204db974707 msgid "" "*Note: The `bind` function in standard lib `socket` of the python " "executor, when input ``0`` to the port parameter, will automatically " "assign an available port by operating system.*" msgstr "*注意:python執行器的標準lib `socket`中的`bind`函數,當連接埠參數輸入``0`時,作業系統會自動分配一個可用的連接埠。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:875 -#: 4a1a578af0b14571a4180ebfc88073d6 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 +#: df4b1b82912e444c89fd2ea7adbec615 #, fuzzy msgid "" "The other port allocation mode is the manual port allocation mode, there " @@ -1528,8 +1654,8 @@ msgid "" " may conflict and may cause unexpected errors." msgstr "另一種連接埠分配方式是手動連接埠分配方式,伺服器有一個連接埠分配範圍。請避免在同一台主機上開啟其他伺服器,因為在現有版本中,連接埠分配範圍會發生衝突,並可能導致一些意外錯誤。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:882 -#: d9301928a8f643868d7cc5852f986e0b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 +#: c835077f32f6478a8c0ad000340fd11f msgid "" "The range of the port allocation is configured in the server settings. " "The minimum allocatable port is ``self.port-" @@ -1539,8 +1665,8 @@ msgstr "" "連接埠分配的範圍在伺服器設定中配置。最小可分配連接埠為“self.port-" "self.port_add_step*self.port_range_num”,最大可指派連接埠為“self.port+1+self.port_add_step*self.port_range_num”。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:888 -#: 17b2666361504a0d8f5e10eb5fc9056a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 +#: 5ad5c89c89a141f2bb5c56e49b94bf1a msgid "" "*Note: The ``self.port`` is the ``port`` argument of the server class. " "The ``self.port_add_step`` is the ``port_add_step`` argument. And the " @@ -1549,13 +1675,13 @@ msgstr "" "*注意:「self.port」是伺服器類別的「port」參數。 “self.port_add_step” 是“port_add_step” 參數。" " ``self.port_range_num`` 是``port_range_num`` 參數。 *" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:894 -#: fefbe2307beb49d083c05018a96a2f3f +#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 +#: 8ea7c9e4e1ad46efb978d3d466a53db6 msgid "There are some relevant methods that can be used:" msgstr "有一些相關的方法可以使用:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:909 -#: 60738ce1224042aa9b39f5e5feec0e95 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 +#: f9525c162a254de4b11de650677ffd79 #, fuzzy msgid "" "The `palloc` method allows you to get a port. When using this function, " @@ -1567,8 +1693,8 @@ msgid "" "persistent log (no-ops in automatic mode)." msgstr "`palloc` 方法可讓您取得連接埠。使用此函數時,您無需擔心連接埠指派模式,因為此方法中已經實作了分配模式偵測器。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:919 -#: 54ccf91661524b1487fb666243fb627a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:997 +#: dee22bb387e140e9ae43d6ebc9afbd58 #, fuzzy msgid "" "The `pfree` method allows you to free a port. Like the `palloc` method, " @@ -1576,16 +1702,16 @@ msgid "" "method." msgstr "`pfree` 方法允許您釋放一個端口,與 `palloc` 方法相同,使用該方法時不需要關心端口分配模式。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:923 -#: f4a62c2b675845148f52b3437e9c151e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1001 +#: 6bd53cf6dcea462fbad9ca450e42eec4 msgid "" "And there are the main functions for you to call, and for more " "information about the port allocation functions, see the :ref:`tcp-" "server-port-allocation-api` section." msgstr "還有主要的函數供您調用,有關連接埠分配函數的更多信息,請參閱 :ref:`tcp-server-port-allocation-api` 部分。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:927 -#: 9aead9c3ede94037a42b4f83a45b3bb4 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1005 +#: d158c9d060c14aa39d042757684d6131 msgid "" "This mode is useful when you need an individual port for the server or " "must reserve a controlled range of ports for client-file transfers by " @@ -1593,251 +1719,291 @@ msgid "" " server processes share the same host." msgstr "當您需要伺服器的單獨連接埠或必須透過手動連接埠指派為用戶端檔案傳輸保留受控連接埠範圍時(例如在測試環境中或多個伺服器進程共用相同主機時),此模式非常有用。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:934 -#: bad6d4dc4cdb4524b686b936a219637d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1012 +#: e51f806efbae4f9daf44365d182f21fa msgid "TCP Server APIs table" msgstr "TCP 伺服器 API 表" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:936 -#: 7d833bb126d34e528b706e8bf0e8a755 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1014 +#: c07f101dcc584239b2a4a7532c1ada42 msgid "In short, the table of contents of the public APIs are as follows:" msgstr "簡而言之,公共API的目錄如下:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:939 -#: 665b3f99a31a46a1af942df11ae56b08 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1017 +#: 66d85143ceff487f9620241fa1391d21 msgid "The server setup APIs:" msgstr "伺服器設定 API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:940 -#: fadd7d9d1d664608bca880a41e9ea51d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1018 +#: 904c44d78ca84c5cb7b595c6d360b2df msgid "`TCP_Server_Base`" msgstr "`TCP_伺服器_基礎`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:941 -#: 53e896a56ad44c29b03df161113e8d24 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1019 +#: 5da37cfc4922407dab0d65df73991067 msgid "`start_TCP_Server`" msgstr "`啟動_TCP_伺服器`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:942 -#: 80dc73e7ae064470b60bf81cf731b1a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1020 +#: 6e0f0866c62749239469bceea81ae727 msgid "`stop`" msgstr "`停止`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:944 -#: bad96f05bf9741c3a015b46ddb0c5485 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1022 +#: f84f11b7394147a9802c7de69d1d99e5 msgid "The server handling information APIs:" msgstr "伺服器處理資訊API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:945 -#: c11c56f2f920425cb0f8a796ba8436ae +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1023 +#: 0ee5a3ad2c3643b9b85c813b5a5ba4be msgid "`handle_client`" msgstr "`handle_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:946 -#: 601d3f32dca44ce0aa8f90496fa82683 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1024 +#: 803b7f781de04d00ae128d89b0350cf5 msgid "`handle_command`" msgstr "`處理指令`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:947 -#: a95b98f525c44f8e99aa1ce37d14521c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1025 +#: cb9095dd05b24093984b4609ee0bb8b6 msgid "`receive_message`" msgstr "`接收訊息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:948 -#: b4d6756915c3424eac84ee276c68ec48 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1026 +#: c40a11b2d9b34f389fce8bc6d8076ab2 msgid "`send_message`" msgstr "`發送訊息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:949 -#: 5458006437d24bb68711e2523f7d7cba +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1027 +#: 3c4a73128c044a38bac0b64d6551f512 msgid "`broadcast`" msgstr "`廣播`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:950 -#: e87f4ae0d0284a778641c6198ee918fc +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1028 +#: 16f4acaa490c4ec7afbd88fb3b50f62c msgid "`send_msg_to_specific_client`" msgstr "`發送訊息到特定客戶端`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:951 -#: 65307777148e424d9387e0e0420015e0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1029 +#: 2ad09a3887894e01a67d31c28272f730 #, fuzzy msgid "" "`console_input` (only started when ``is_input_command_in_console`` is " "``True``)" msgstr "“is_input_command_in_console”:預設為“True”" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:953 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1031 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 #, fuzzy msgid "" "2.1. The inbound event listener APIs (see :ref:`tcp-server-event-" "listener-api`):" msgstr "伺服器加密通道 API(請參閱 tcp-server-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:954 -#: e0409b880c784bc4a8cb876315709114 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1032 +#: 6f0e5784864d4f62b0fd68d41a8105c4 msgid "`add_message_listener` / `remove_message_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:955 -#: 2dea82fdc0a04600801da255ef214a2b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1033 +#: 647c22de04784b0c97bbc829edf1e2b3 msgid "`add_file_listener` / `remove_file_listener`" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:956 -#: d90982abe8e24aefb021d1bdb6cb8ca8 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1034 +#: 8fc8a08031dd48eba706b833414ef995 msgid "`messages_dict` / `events_dict` stores" msgstr "" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:958 -#: 6bc8bd4354304c05bc72c0ec826d0f96 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1036 +#: 4b1bbafaa9c64f41a4acd26af8299ab2 msgid "" "The server encrypted channel APIs (see :ref:`tcp-server-encrypted-" "channel-api`):" msgstr "伺服器加密通道 API(請參閱 tcp-server-encrypted-channel-api`):" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:959 -#: 0164b9a39ec64638b0951431e562f5c7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1037 +#: 67ad7bf1d5754801a36a114c86e650f9 msgid "`_crypto_on_client_hello`" msgstr "`_crypto_on_client_hello`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:960 -#: 35472e2955b24167aadb9aa8587b2674 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1038 +#: e2ec1fc9abbc4a1389e8df768c33e7c8 msgid "`_crypto_wait_server_ready`" msgstr "`_crypto_wait_server_ready`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:961 -#: 2e8d4e8d8741462e8e6a6b36b36e0c07 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1039 +#: e3987c4ee8ae4d79b0aafb035a806494 msgid "`_crypto_push_pub_to_client`" msgstr "`_crypto_push_pub_to_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:962 -#: b7eb540259ae4240ba76640b6afd72b7 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1040 +#: b1829201e7fe4428b9689b03e50374bf msgid "`_crypto_process_line`" msgstr "`_crypto_process_line`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:964 -#: 9265fbd06c8a43fc972c1010a348684d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1042 +#: c875b30243a24ac4923a442613a677e0 msgid "The server command APIs:" msgstr "伺服器命令API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:965 -#: 6c53a87d79a749ffa1e2a93231037ac1 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1043 +#: 5d011d31b13d446f814fd6bd5e63efce msgid "`register_command`" msgstr "`註冊命令`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:966 -#: 30a77ceac778437989abfaa0a23c1f4a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1044 +#: 2f117382a2154410989fb34342460f8b +msgid "`call_extension_functions`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1045 +#: ffa5682de7884beb92ad1259ff1b8dd2 msgid "`_execute_custom_handler`" msgstr "`_execute_custom_handler`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:967 -#: 1940d4e8daf143e9ad1c971530233180 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1046 +#: cf39c195db7c41caa0f01bd982276547 msgid "`submit_task`" msgstr "`提交任務`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:968 -#: f2448f5089ba44458298a4194c2795f0 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1047 +#: 85f02dafa5374a7b89e8bd8a65e54b19 msgid "`create_temporary_server`" msgstr "`建立臨時伺服器`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:969 -#: 097562a3555e413385ee95ded3a46118 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1048 +#: 2f117382a2154410989fb34342460f8b msgid "`create_temporary_client`" msgstr "`建立臨時客戶端`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:971 -#: af034155f20a44b79b9c6ec49fc189aa +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1050 +#: 0131ddf38e824d959a1d61148155ae0d msgid "The server file transfer APIs:" msgstr "伺服器檔案傳輸API:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:972 -#: 9cbb9edbc9574de99f8168bf2df7df03 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1051 +#: 7483d578f02a4babb71dda0efb204b61 msgid "`file_transfer_server_recv_client_start`" msgstr "`file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:973 -#: fc70c45345764fb2aa8bc3d71f927248 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1052 +#: c2cf0a257e2543478df2dccdf52fdb00 msgid "`file_transfer_server_recv_client_start_thread`" msgstr "`file_transfer_server_recv_client_start_thread`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:974 -#: c1918a177fcf47cbb881d7e14300776d +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1053 +#: 187f0ce4a65e41adb7ee99b021de4d2b msgid "`folder_file_transfer_server_recv_client_start`" msgstr "`folder_file_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:975 -#: 6f61085c3cb24ae298dc0eadbe113f6c +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1054 +#: be99cf24a4ae4f03b5472d8ee3412889 msgid "`multiple_file_multiple_client_transfer_server_recv_client_start`" msgstr "`multiple_file_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:976 -#: 46d60103b77c4de19be1ac4a12d4331b +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1055 +#: ea76c872d16c4a709ec52ab7415e40a0 msgid "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" msgstr "`diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:978 -#: 565a0271f5ed4b679a742f7677ed9e63 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1056 +#: 6056cfcc5fa740e58986f2e8ce900042 +msgid "`file_transfer_mode` / `file_transfer_mode_recv`: one transfer leg" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1057 +#: 8df3552dd5ae41a4b3020c15ebe8509d +msgid "`forward_item_to` / `forward_message_to`: single forward destinations" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1059 +#: ad8e7d49e5294f5b976ae225ccb67d22 +msgid "5.1. The transfer pause and reconnect APIs (see" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1060 +#: 92ba3cd2c6004b60abe5976efa845d76 +msgid ":ref:`transfer-pause-and-reconnect`):" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1061 +#: 8cee01b7bbd1439b81f24891d7149fa4 +msgid "`pause_trans` / `start_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1062 +#: f5615a6934a141c9aa2bb01bcab9aea0 +msgid "`pause_trans_remote` / `start_trans_remote`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1063 +#: 187f0ce4a65e41adb7ee99b021de4d2b +msgid "`resume_transfers` / `resume_trans`" +msgstr "" + +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1065 +#: 944bb0f890764ad7a62584cc73782927 msgid "The server console commands:" msgstr "伺服器控制台命令:" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:979 -#: e79a38bbae1d44e5b9e7b3e939b42e14 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1066 +#: e85b5444c86048cfa691dc42bb7c9f88 msgid "`/stop`" msgstr "`/停止`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:980 -#: 98cb7e67ddc64c7e91c8f445d3d7b601 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1067 +#: 7250fb98f32f47d4b6204ceb5f93f550 msgid "`/status`" msgstr "`/狀態`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:981 -#: ec1899e60fc1456ba2117f7b0bf676e3 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1068 +#: 48237f11d42c41e392b282787896bd00 msgid "`/clients`" msgstr "`/客戶`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:982 -#: 0bb68238715a4e889bef60bf524c996a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1069 +#: 65fddabf6eec444fa89598e10a43f63f msgid "`/send_msg`" msgstr "`/發送訊息`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:983 -#: 4c5dc721d573437385383ec46f76658a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1070 +#: c53a3810c2784772a6cb72f993ae8b4d msgid "`/file`" msgstr "`/檔案`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:984 -#: 4fca7dce90044c119e5722297774fabe +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1071 +#: 57d39ac1201f4866a57b5d291385d207 msgid "`/file_folder`" msgstr "`/檔案資料夾`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:985 -#: 29fe035c678b49ef80321587017ba483 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1072 +#: 2cbc4a81ca0548d4aa183c2ad034ab6a msgid "`/multiple_file_multiple_client`" msgstr "`/multiple_file_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:986 -#: ba4e2c65e7034bd8a7a278697b76e8a9 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1073 +#: ce0f96a7a5e24b3cab89623df65ac40f msgid "`/diff_multiple_file_diff_multiple_client`" msgstr "`/diff_multiple_file_diff_multiple_client`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:987 -#: 97c3c838cb784a729fc52242a89f7156 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1074 +#: a9bffb7745c94e7cb45f4fc030c00da3 msgid "`/help`" msgstr "`/幫助`" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:990 -#: 0b5cb5ab31e648b99f176a269cbad11e +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1077 +#: 2d084d51c4c44ebda431944babb6c256 msgid "See Also" msgstr "參見" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:992 -#: d85e9537bf8e453ea2d533f25e659d2a +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1079 +#: aa497d5f407a4e439cd10a4de1e24b05 msgid ":doc:`TCP_Client_APIs` — TCP client." msgstr ":doc:`TCP_Client_APIs` — TCP 客戶端。" -#: ../../source/Network_APIs/TCP_Server_APIs.rst:993 -#: 1893e2b71add4e0ba8840ea169e0b102 +#: ../../source/Network_APIs/TCP_Server_APIs.rst:1080 +#: e1e5363e891e4e68855f9b021bbd4abf msgid ":doc:`UDP_APIs` — UDP endpoint." msgstr ":doc:`UDP_APIs` — UDP 端點。" @@ -2043,3 +2209,48 @@ msgstr ":doc:`UDP_APIs` — UDP 端點。" #~ "``/diff_multiple_file_diff_multiple_client " #~ " ... ...``:將不同的檔案清單傳送到不同的客戶端。" +#~ msgid "" +#~ "The handshake exchanges a random session" +#~ " nonce, and every encrypted line on" +#~ " the wire carries it plus a " +#~ "per-connection sequence number: ``||``. The receiver drops " +#~ "a line whose nonce does not match" +#~ " the current session (ciphertext replayed" +#~ " from an older connection) or whose" +#~ " sequence number is not the expected" +#~ " one (ciphertext replayed within the " +#~ "session / out of order); both " +#~ "counters reset when the socket flips " +#~ "to encrypted mode after a (re-)exchange." +#~ msgstr "" +#~ "握手交換隨機會話隨機數,線路上的每條加密線路都攜帶它加上每個連接的序號:``||``。接收方丟棄隨機數與目前會話不符的行(從舊連接重播的密文)或其序號不是預期的行(會話內重播的密文/亂序);當套接字在(重新)交換後切換到加密模式時,兩個計數器都會重置。" + +#~ msgid "" +#~ "``add_message_listener`` registers ``listener(client_id," +#~ " message)`` for every inbound plain " +#~ "message (lines that do not start " +#~ "with ``/``; commands go to the " +#~ "command handlers instead). ``add_file_listener`` " +#~ "registers ``listener(client_id, full_path, name, " +#~ "size, command)`` and fires after a " +#~ "file uploaded by a client has been" +#~ " fully written to the transfer " +#~ "directory (``command`` is the wire " +#~ "command that triggered it, so protocol" +#~ " pushes such as ``/crypto_pub_key`` can " +#~ "be recognised). Both listeners run on" +#~ " a protocol thread, so they must " +#~ "not block, and an exception inside " +#~ "a listener is logged and swallowed. " +#~ "The ``remove_*`` counterparts unregister a " +#~ "listener and ignore unknown ones." +#~ msgstr "" + +#~ msgid "" +#~ "``/forward_item``, ``/forward_send_msg``, " +#~ "``/pause_trans``, ``/start_trans``: internal " +#~ "forwarding/transfer-control messages." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po index dac09ff..1b7969c 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.command_control_extension_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-16 11:10+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -19,11 +19,71 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.18.0\n" -#: ../../api/PyFlow.command_control_extension_tcp.rst:2 +#: ../../source/api/PyFlow.command_control_extension_tcp.rst:2 #: a6084f2941f34f579f28c55e9dfb768d msgid "PyFlow.command\\_control\\_extension\\_tcp module" msgstr "" +#: 9209095513ec402980427a0ddd988219 PyFlow.command_control_extension_tcp:1 of +msgid "Command-control extension for the TCP protocol." +msgstr "" + +#: 47d5c98c564241a6911eff0abea987ec PyFlow.command_control_extension_tcp:3 of +msgid "" +"One command batch, run by every listed client, with each client's output " +"collected on the server:" +msgstr "" + +#: PyFlow.command_control_extension_tcp:6 b14c7eec72b44dc1bd343997acf1cf44 of +msgid "/command ... ... " +msgstr "" + +#: PyFlow.command_control_extension_tcp:7 fe2fb5a737534088b175ea340c1763f9 of +msgid "" +"typed on the server console. Every client runs the whole command list in " +"a single shell session, in order, so state such as a changed working " +"directory carries over from one command to the next: ``/command \"cd " +"/path/to/search\" \"ls ./\" \"(ip, port)\"`` lists the files of " +"``/path/to/search``, while sending ``cd`` and ``ls`` as two separate " +"``/command`` lines does not." +msgstr "" + +#: 29a70dd76bf34e90a9ea54ac27202289 PyFlow.command_control_extension_tcp:14 of +msgid "" +"Commands come first and client addresses last; every address is written " +"as a Python address tuple, e.g. ``\"('127.0.0.1', 3000)\"``. There is no " +"limit on the number of commands or on the number of clients, and every " +"listed client receives the same command list. Two internal commands carry" +" the log back:" +msgstr "" + +#: 9ef58aea395a436382e23f39797e3e8e PyFlow.command_control_extension_tcp:19 of +msgid "/command_log_chunk " +msgstr "" + +#: 3361f3fb70584140989542af7c3361a7 PyFlow.command_control_extension_tcp:20 of +msgid "" +"sent by the client after it uploaded one log chunk through the file " +"transfer channel; the server appends the chunk's entries to that client's" +" log file" +msgstr "" + +#: 2563d4e4d9744c2fb16d84690c2e94e2 PyFlow.command_control_extension_tcp:24 of +msgid "" +"sent by the client when the batch is over; the server merges every " +"collected log file into ``merged_logs.json``" +msgstr "" + +#: PyFlow.command_control_extension_tcp:27 e40a302503cb4bdda5420aa79d0c57eb of +msgid "" +"A client captures the output of the running commands and uploads a chunk " +"every ``_LOG_CHUNK_BYTES`` of captured output (a smaller final chunk " +"closes each command), so a command that never stops is still tracked in " +"real time. Every chunk is appended to the same log file - " +"``logs__.json`` in the server's ``logs`` directory - which is " +"therefore never re-sent and never rewritten, only extended." +msgstr "" + #: 9209095513ec402980427a0ddd988219 #: PyFlow.command_control_extension_tcp.setup_server_commands:1 of msgid "Register the control-extension commands on a server instance." diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po index 24d7d91..65c3282 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.connect_tcp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -20,156 +20,155 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.connect_tcp.rst:2 -#: 59f41330dfa54a88831a20f4dc97c0f6 +#: 1e4cd09ce3ef45ceb95b8eb81eb7493b msgid "PyFlow.network\\_api.connect\\_tcp module" msgstr "" -#: PyFlow.network_api.connect_tcp:1 dca225f091cb4dd1810a8bd04c3a5004 of +#: 25b88cdb337c44539a843c674ba6825b PyFlow.network_api.connect_tcp:1 of msgid "" "TCP transport for PyFlow: the server and client base classes and the wire" " parsers." msgstr "" -#: PyFlow.network_api.connect_tcp:3 d5888d829f2e4850926eb364ede4678e of +#: 1f1482fc5c2849a68f34c74a8b55ab79 PyFlow.network_api.connect_tcp:3 of msgid "" "``TCP_Server_Base`` accepts connections and dispatches inbound lines; " "``TCP_Client_Base`` connects, sends and reads on the same conventions:" msgstr "" -#: PyFlow.network_api.connect_tcp:6 bd065af9d94b44298f9716ca96809b8c of +#: 104e5170c1c34bf9ad719f896e0c4226 PyFlow.network_api.connect_tcp:6 of msgid "" -"one message per line, terminated by a newline; a line that starts with " -"``/`` is a command and goes to the command handlers, anything else is a " -"plain message reported to the registered message listeners;" +"one message per line, terminated by a newline; every inbound line is " +"reported to the registered message listeners (commands included), and a " +"line that starts with ``/`` is then dispatched to the command handlers, " +"anything else treated as a plain message;" msgstr "" -#: 91ea1db95e554f2fbd2c1e92eb2d1353 PyFlow.network_api.connect_tcp:9 of +#: 6c6c01958e5741e080edcb804b4d12d1 PyFlow.network_api.connect_tcp:10 of msgid "" -"an RSA-encrypted channel is negotiated right after connect unless " -"``is_enable_encrypto`` is False;" +"unless ``is_enable_encrypto`` is False, an encrypted channel is " +"negotiated right after connect: the handshake lines and the public-key " +"pushes stay plaintext, then every later message travels as a frame (RSA-" +"OAEP for small text payloads, an ECDH-keyed AES-GCM seal for everything " +"else, including file data), and each file/folder transfer sub-connection " +"is framed the same way once both sides hold the session keys (see " +"`_SecureChannel`);" msgstr "" -#: PyFlow.network_api.connect_tcp:11 dfcece05b6774c5496b99d6c08039fce of +#: 9702905f1f8a4750905b2ffb96f99ec8 PyFlow.network_api.connect_tcp:16 of msgid "" "file/folder transfer, message forwarding and port allocation are layered " -"on the same socket and share its command namespace." +"on the same socket and share its command namespace;" msgstr "" -#: 89db462eaa88489c9390ddfa67a77a73 PyFlow.network_api.connect_tcp:14 of +#: 3488995e2a8349a58393d9f2d1155b99 PyFlow.network_api.connect_tcp:18 of +msgid "" +"an interrupted transfer is resumed after a disconnect: both sides persist" +" their transfer stores under the protocol's ``.Flow`` directory and the " +"receiver asks the sender to continue the file from the bytes already on " +"disk (``resume_transfers``; the wire lines are ``/resume_trans`` and " +"``/forward_resume``)." +msgstr "" + +#: 4cc5743bdfe54148ad38f54f10e688c9 PyFlow.network_api.connect_tcp:24 of msgid "" "The forwarding extensions use the module-level parsers " "`parse_forwarded_message`, `parse_forward_items_and_addrs`, " -"`parse_forward_originator` and `forward_skip_message`." +"`parse_forward_originator` and `forward_skip_message`; the reconnect " +"logic uses `parse_resume_command`, `parse_forward_resume_command` and " +"`_resume_offset_for`." msgstr "" -#: 98c270e82fa8468487e1b4d25bab8c0c PyFlow.network_api.connect_tcp:18 of +#: 49796529cb7f49ee8131b257212b5420 PyFlow.network_api.connect_tcp:30 of msgid "" "Concepts live in ``docs/source/Network_APIs/TCP_Server_APIs.rst`` and " "``TCP_Client_APIs.rst``; argument, return and exception contracts live in" " the docstrings below." msgstr "" -#: 76126c02e928423b89dc4662d9a190f2 +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_resume_command:1 of +msgid "Split a ``/resume_trans `` line." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 14dcda8b059b480982e3fb03399e665b 99035a24f6e94207b84545f8c71a451e +#: cb62202c244d4c08974c674c13a02dca +msgid "Returns" +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_resume_command:3 of +msgid "``(fid, offset)``, or None when the line is malformed." +msgstr "" + +#: ../../source/api/PyFlow.network_api.connect_tcp.rst +#: 19eb6fca79324b0791f8ec7488a5246c +msgid "Return type" +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:1 of +msgid "Split a ``/forward_resume `` line." +msgstr "" + +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:3 of +msgid "``(target, fid, offset)``, or None when the line is malformed." +msgstr "" + +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:5 of +msgid "``(target, fid, offset)``, or None when the line is" +msgstr "" + +#: 4ead8d8f93644adeb812150e760f7792 +#: PyFlow.network_api.connect_tcp.parse_forward_resume_command:6 of +msgid "malformed." +msgstr "" + +#: 39274682c4bd46489ed6fe535b50ede5 #: PyFlow.network_api.connect_tcp.parse_forwarded_message:1 of msgid "Split a ``/send_msg_from `` relay envelope." msgstr "" #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0e9ae2e0bd0c44da835c0999abec5f08 1aaf58afc7f043919f411c02d435031d -#: 1c819a8207464e439fd4675d1b823409 1d2cff780d6642deb6ab5fbf32c34185 -#: 1e24bfa274504842b67c3cb0c7a37118 26160724c12740ecbe3cc707bc46c197 -#: 2edb81613e9c4bd0949f5d6efa1a542f 30a7ccf5e56e4640a7a6e592d13a4f7c -#: 3514f6292626456eb4b0c31a30e24cf5 38d82b9bc4414212a8458de940d3b69b -#: 406f1bd372c14cd897f0d2dc1fdc8fd7 4400798a6d9d41a89b686b015f53a454 -#: 54f261fe47134a9494f12b5053492006 5e9d8d1799714d389a6fd79edd0e5bac -#: 6239fd721a0f476aaf509ab580317c75 6658645eabff4ba6b0b326727f89a4f1 -#: 6f375e9a65e04034a4fd1475f3073e42 70b19bc5e5da467dbbae99d81fe54ed7 -#: 79e2d4be536b429cbbfe5016df915b72 7c3cf59acfe34a15a6c920a0f58ec56f -#: 822df543855349c2993aabd5596b5383 8245849b603f4313a3ea2423abd5c899 -#: 83eba13f6fae4ded929924151baa0c52 9449c184a2e145909d2e1f114534253d -#: 9a393c8c90d0446a97c34af1c173f83d 9cdc7d0b4bc2400498e9c57ed16ba459 -#: a2ddcff09d1641b5b269ec31031008f9 a5cbf7c6c5b0494b8652be7d28a7b3d1 -#: a9ec9ede7c8144ddb920261d29edc23d b5b42f99934e4b0b939671c6fb08f748 -#: b630deb98dea40c28f1cb88dcbfdb261 b6e3a01b0f044a15a7d322c63f58c262 -#: bb3b7e5558c74c8eb287944b93b9c664 bd95cc8d5960426e92ad149ce0ecaeb4 -#: be47c4f21d4d4515be0684c6c1215c0c cdebf66a7b714ef39236c1dc9773c8f7 -#: d02c1be3236b424f87b75728f76d672c d5b3f5bf790c4fc6aefb763d9c473474 -#: da6cef9244b1429881584994b097c71a e98998d054b74d0e820367ea5de54d02 -#: ea4e1b708c2f409f89bf4ca2a6e4fbf3 ebca3c62590345118f3fe5a8d85ce154 -#: ebcdb45484b64f7f9023808632316025 efca1ecd18f440db9489b40ae6480409 -#: f7766cda09fd4c0bb6b565f5fa4a3688 fe80dd07199943c784dd488826f958b7 +#: 4fa9ba6e763440b8ab00832520b4d305 501a0caef71d436e84469bc1ef9c1e5f +#: 70d6dae11a144ed7b7e9d8e16dbf478c acdf8b3b266f4eccb6ceca17a110603b msgid "Parameters" msgstr "" -#: 35b277cd5b2249dc8b38c36654b1f75a -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:3 +#: e42a6166c82d4861b25cb55f587db28c of msgid "Received line, e.g. ``/send_msg_from ('127.0.0.1', 3000) hello``." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0cd9914c895f4b308548863df6d8c13c 113c57937f6f402da7758e74266680ea -#: 139720899e024d348d0b43b9af2b2ef7 2cb731c57fb64497a6424e4e51fe17bb -#: 30c59afde30c44428a97266ca87baa21 3f574beaf02948d599ffd8c50922e530 -#: 40e4cbf377a94cf8803c13b2f01dbc77 4aa76ebde46243b18f2a5d811d902d1e -#: 4d5706674a0c40a99769b5cfba21b29d 5518a67cc7364710b2b0c03f6de9de1b -#: 564a8841a88d40e0a44b1b0d72a0b3a4 56e96f344ac14995adeb056f90d3e39a -#: 638d047aee4d45a689f4a54f8d2be451 6e5db10681f24a01a208604d8de1ecf4 -#: 6ea11f9fd50e46f8aef42a25872d8d47 833d97bdb57049979db335d24819041a -#: a00fef59262447aa931fe606e260a7ab a9795b94ba634cb8a7dc1fd6a7e6f326 -#: b1a77959b26540128ea564370170744f b1e2a43372ac48fe9a367121a736eaee -#: b2f18766a5ec40d69bfd15b13fa54aa2 b963bb66a63649d5b5cc0ce3d852aab4 -#: c1bd9b5e40e644e3a1f1198e5d2247c2 d558170070474bcb9d798b72d878f185 -#: d86bf79c265c42ec969d2c8058f20a3c d906d179eca24642883fb6ff991399b8 -#: ddfeae931eb14b529e08b61ae9de5aaf ecb12ada91914625a7c5e9894b67886f -#: f8e1381487764684b80cbc9d8f6a511c fa2587a106c540d1a870afc4a3ae97b7 -msgid "Returns" -msgstr "" - -#: 24de94d25531410aa507869ac615529b -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 of +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:7 +#: f25d1962656c4f339805427e2573f84f of msgid "" "``(sender_id, payload)`` where ``sender_id`` is the sender's " "``\"ip:port\"``, or None when the line is not a well-formed envelope." msgstr "" #: PyFlow.network_api.connect_tcp.parse_forwarded_message:9 -#: f4818c7037924b089072be17dbe65cda of +#: d0d7af37e4134902ae64e10b2e43b4c1 of msgid "``(sender_id, payload)`` where ``sender_id`` is the" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 -#: e4ce35611cb240c382217f2166803af1 of +#: 09b385f0a98640c981d8563427e44d7e +#: PyFlow.network_api.connect_tcp.parse_forwarded_message:10 of msgid "" "sender's ``\"ip:port\"``, or None when the line is not a well-formed " "envelope." msgstr "" -#: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f2c39309f3e47aa9157bf244f35d1e6 126027ff5c8b494e8223688394767c35 -#: 15e8f6af90d84f4c99e9a9706f995a3f 18eed5a02c0346f6966237e6812afce0 -#: 208eff4f470f474395ac42a58f179feb 308f9ffcdfe2443cb6fe0f3a79e7d4b3 -#: 30fd0d7f7d9547149d06568b9ae4b217 34500bb5a5ea4428ba3ba1f34f8555f3 -#: 357fa966af0e4661a01d3a18b3686c63 38f178d3602f47bcbf100a047fc22ccc -#: 4268152920654e59975b69aed4638761 43cc49d0a3b2478f8a24fcdea7c2ce78 -#: 448b06753df84443af4aae1dcb008d56 4530cc6fc87d4dbcb79dd0e90ea83694 -#: 496c6102672e49fc96cd7210ed1ec602 502647c8224842608ded5058bf1c6748 -#: 574093f9f9054b898b9ab8b20a239a40 5882a32ac8a34ab7b568b256092e1aca -#: 73e564d3b91d42388f95effb067d6218 7f2f462183d442c98c624d6750d86319 -#: 8203a323a9af48edb0f9e91ca6260ed6 87a376020e0a47fb90cc4f2d9b045d7c -#: 8f12aa18be1a4aaf97b8db14f282a929 a61c3c1917b8486bad659991683c48cb -#: a9e445f3a3094e3bb7957551bcf7fd21 c0afcff99bfc47f3ba7a3f0b3e836444 -#: c4d251b617f2419cb1093f6896b14cb8 d4bc332ce5f34c61b3105fb392b302e5 -#: e9a98b5852d84cf4939d9ea0f17b038c f17ca1aa780b447cb305e1db1c181efb -msgid "Return type" -msgstr "" - -#: 1ad7def88bd34ce7accca28c4d123b79 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:1 +#: f22254d8ca2d47ad8bc9c98664369d61 of msgid "Split forward-command tokens into items and destination addresses." msgstr "" -#: 67578e526f0b4dfc924c46a44e7bea78 -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 of +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:3 +#: b207f60051004834bab91ba392a88437 of msgid "" "A token of the form ``('ip', port)`` is a destination, everything else is" " a forwarded item (message text or a path). Used by the native message " @@ -177,252 +176,326 @@ msgid "" "extension." msgstr "" -#: 18a87e9cbc124ce5a6f91d61a72fc6de +#: 5329fb72f5954768a6cec05ff4cccfea #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:7 of msgid "Tokens after the command name." msgstr "" -#: 0e46577c966b41c4ad6f0aea95fd7e5c +#: 2aebf669048046ddb279a935bcfcfde4 #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:10 of msgid "" "``(items, addrs)`` in the order given; ``items`` holds texts and " "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 608bcdb865a94f869885cd560de7012e +#: 96b96bd19fe94312bddf340fad073cbc #: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:12 of msgid "``(items, addrs)`` in the order given; ``items`` holds texts and" msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 -#: e8c390dc356e4be9bb2f52cd0540e859 of +#: 8e82954621d748e2b412952a7fb2753b +#: PyFlow.network_api.connect_tcp.parse_forward_items_and_addrs:13 of msgid "paths, ``addrs`` holds ``(ip, port)`` tuples." msgstr "" -#: 0e422066050d4ba18799efa53c6b771e -#: PyFlow.network_api.connect_tcp.forward_skip_message:1 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:1 +#: a51324658c7943158d90ed706cecc41d of msgid "Build the console notice for a forward destination that cannot be served." msgstr "" -#: 1eb2f924bcbc4e3783e3a4706c93052f -#: PyFlow.network_api.connect_tcp.forward_skip_message:3 of +#: PyFlow.network_api.connect_tcp.forward_skip_message:3 +#: b541e8446e374bc8b38cd7912a1fa33c of msgid "Destination ``(ip, port)`` that is unreachable or is the server itself." msgstr "" -#: PyFlow.network_api.connect_tcp.forward_skip_message:7 -#: b7ceaa070f754fe88242c2b495b3ff9f of +#: 10e03f21d05e478d9cde0c7176f6e1b8 +#: PyFlow.network_api.connect_tcp.forward_skip_message:7 of msgid "One-line notice for the console." msgstr "" -#: 59d83fde0d964794ba76d45749bfc021 +#: 8005e532fe9d491ca8ddd996889d605d #: PyFlow.network_api.connect_tcp.parse_forward_originator:1 of msgid "Extract the originator's ``\"ip:port\"`` from a received transfer command." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 -#: b91ee97cb2574a19b8c87c99bf8ca181 of +#: 2cf3052a89c645e782430f1f05fb37a1 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:3 of msgid "" "The server's forward relay tags every pushed ``/file`` and " "``/file_folder`` command with the forwarding client's address tuple; a " "direct send carries the receiver's own address instead." msgstr "" -#: 20da4b9824cd4fd6bb0ef55ebc38158b +#: 335f6c1b16104395ba38a33188943d8a #: PyFlow.network_api.connect_tcp.parse_forward_originator:7 of msgid "Received transfer command." msgstr "" -#: 9f25fa22a7b14822b8cbc1fd929976b9 -#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 of +#: PyFlow.network_api.connect_tcp.parse_forward_originator:9 +#: e5bd1024ad3f47f19cafc4c83a844b60 of msgid "" "This instance's own ``\"ip:port\"``; a command carrying it is a direct " "send and yields None." msgstr "" -#: 6455c3bb288d4239811cb0104086c0fa +#: 65469492f844448fab269b701cbdb704 #: PyFlow.network_api.connect_tcp.parse_forward_originator:13 of msgid "" "Originator ``\"ip:port\"``, or None when the command carries no " "originator (direct send or non-transfer command)." msgstr "" -#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 -#: a466d04757ec40f1a2888518b8fb1d9a of +#: 04a0882a3a5e4099a114728b4d1c79c0 +#: PyFlow.network_api.connect_tcp.parse_forward_originator:15 of msgid "Originator ``\"ip:port\"``, or None when the command carries no" msgstr "" #: PyFlow.network_api.connect_tcp.parse_forward_originator:16 -#: da8c46fb38624c7d97d91970aee4667c of +#: a2d34276c4f54c69981f9b51f36cc31d of msgid "originator (direct send or non-transfer command)." msgstr "" -#: 201f6bd5376a4ebaa7488dd3b58197c0 +#: 31646cd2d4f049a38b7910ac6836d2f9 +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:1 of +msgid "A command passed to `call_extension_functions` is not registered." +msgstr "" + +#: 42bee6e5f57b43cba7c5b4c4a1769e9a +#: PyFlow.network_api.connect_tcp.CommandNotFoundError:3 of +msgid "" +"Raised when the first token of the command matches no handler registered " +"with `register_command`, on either instance class." +msgstr "" + +#: 7297b41c47664243b9677b32e21de07e #: PyFlow.network_api.connect_tcp.TCP_Server_Base:1 of msgid "TCP server: accept clients, dispatch commands, relay messages and files." msgstr "" -#: 4f7013d76f9d447b974f22cca228ba0f +#: 0d632c9f5b234888a691b03ade8ff7da #: PyFlow.network_api.connect_tcp.TCP_Server_Base:3 of msgid "" "Each accepted connection is served by `handle_client`, either in its own " "thread (the default) or by a coroutine on an asyncio event loop when " -"``is_asynic_clients_io`` is True: a line starting with ``/`` goes to " -"`handle_command` (built-in commands plus the handlers registered with " -"`register_command`), any other line is a plain message delivered to the " -"listeners registered with `add_message_listener` and stored in " -"``messages_dict``." +"``is_asynic_clients_io`` is True: every inbound line is delivered to the " +"listeners registered with `add_message_listener` first; a line starting " +"with ``/`` then goes to `handle_command` (built-in commands plus the " +"handlers registered with `register_command`), any other line is a plain " +"message stored in ``messages_dict``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 -#: fd2aa2103a434e7b84e9f5300dfb2637 of +#: 2870b0163d68487daf7526e91eb49ff6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:13 of msgid "Address the server socket binds to." msgstr "" -#: 0887ce96e330478f83984d935911cd2b 13fa6bd77a314fcbae42aeef584d47b6 -#: 1d012f62b99a4b0d8802295d814667dd 1d5b594e02824d74b812b69dc7b34a88 -#: 3b8af6dc474d493eb9749cb07384c5d1 4916b5bac8044e249473dae03d0af5e5 -#: 6a138e9d5ed24b6b9a9f213ffa6d07bb 7c114dabd42344d790a98003f7d68a6a -#: 889f9fb97d4b483cbfd9ae6bbb3e1dbb 89e6193e8e8c45f3ba6d49b9ec578812 #: PyFlow.network_api.connect_tcp.TCP_Client_Base #: PyFlow.network_api.connect_tcp.TCP_Server_Base -#: a0a81405abb64b70834a292dfa52ea47 a32afd5e800648f08c2ed1582462900f -#: a4c849cfce9b4544a50162a1abd07ffc e953785e3c774cb783e506a118b6f5f9 -#: efd7bf86f2f3403a843bdc7079ed87ae f87fe645a0c846168779119b106eb83b of +#: cf754e752b6c445989b3301b807fc9eb of msgid "type" msgstr "" -#: 194d7e538b9142bb9cadf40639c7dfc2 8d779f308c7343fca45fb6b7c544b6f8 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: 568be916ae0340289a6569e718e7cbf2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:16 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:106 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:15 -#: a043713065174240b3b3cb2839829b42 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:100 of msgid "str" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 -#: eaf91e01d29744a4b66b30d163b14bd4 of +#: 6ac74cca7b0f443ca89f3d2c3bbe1aaa +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:19 of msgid "First port considered for binding and for allocation." msgstr "" -#: 143512a7a9624b79853380f79b9db5e0 6093b43271e041dfb256e660e61561c5 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 +#: 9ecf88c5193c470b98dc95d184c94f92 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:22 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:21 of msgid "int" msgstr "" -#: 0f4f0acdd1a64e9cb4eb06b5fc12103e +#: 6746407aac194c4880c7cbf82b7fa2fb #: PyFlow.network_api.connect_tcp.TCP_Server_Base:25 of msgid "" "Accepted connections keyed by ``(ip, port)``; each value holds " "``socket``, ``address``, ``id`` and ``connected_time``." msgstr "" -#: 6fcc166b59cb4ae7a6a6e30f2dbd2784 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 of +#: 7ba2aaf3fe4c42739121eb3ca2bcc79a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:89 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:98 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:28 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:92 of msgid "dict" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 -#: d85332af5e73403388989eacf82a251d of +#: 93556efee2aa445684af3fdc1532548a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:32 of msgid "True while the accept loop runs." msgstr "" -#: 0effb5fc02cf402ab9d27f4a51954fd1 168f4d3c8da74ebab98953585b27b866 -#: 21bd44747d4e4c9aa4a0afa0f559707d 3c8b6ad08eac44ba9eacbb2fb9752304 -#: 420ec28762864e58ad5f3a63f2811a0f 87eb97e54ef847398f653aa5b65b0191 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: 0ab0667a38254203929e173ab5024f1d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:40 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:46 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:52 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:58 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:65 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:72 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:79 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:34 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:41 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:47 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:53 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:59 -#: e1e2580e801a44cc962b509779f690fc f827c454ead24d7587ae4125b1f60fda -#: f8f0e0ce3c4841278a15e583a0ec5f92 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:66 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:73 of msgid "bool" msgstr "" -#: 62103bebe6fe47aa8a3830133baa0a70 +#: 9023ee78c5fe4680a3875c881abe3307 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:38 of msgid "" "Whether clients are served by coroutines on an event loop instead of one " "thread per client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:42 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 -#: c291fba3b400472996751ffdc24251b7 d0ade3e16cf044fca75a0e1bdf17038c of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:45 of msgid "Whether the RSA channel is negotiated." msgstr "" -#: 8bb4af4279e44eef8df452f4429780ff -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:48 +#: 3c5a67d3c5824c15b42b71fbadddf5d3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:50 #: PyFlow.network_api.connect_tcp.TCP_Server_Base:51 -#: c9414c44325b4b5eaed34bf2a7e49ed4 of +#: a5ac1b25d44547ba836c5dc354438315 of msgid "Whether execution-process lines are logged as well." msgstr "" -#: 5bdaf96cd6894bc4a179ae3ddc66c29c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:54 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 -#: a50b56a084674a89bb56dd9791348a75 of +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:57 of msgid "Whether the instance logs anything at all." msgstr "" -#: 75856a665d5045349622c29bee22fe17 +#: 3114d37d38af4cfcaa75397192202b93 62437fad8325442b91f177e93b8be7ef +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:62 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:63 of +msgid "" +"Whether every running file transfer is tracked in " +"``file_recv_progress``/``file_upload_progress``." +msgstr "" + +#: 58bd8f0892f044a583a276490dc2a7f5 855f8e2ee2a449398779d56b269628d6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:70 of +msgid "" +"Whether the real-time network speed is measured into " +"``upload_network_speed``/``recv_network_speed``." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:83 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:77 +#: afff1dd047f4479b84d46859c7da90b8 ce793576b862473cb130a29582aab5fd of +msgid "" +"Running downloads keyed by fid; each value is ``[received bytes, total " +"bytes, current speed, file path, peer]`` (the speed is None until the " +"transfer has moved its first chunk, and while speed measurement is off; " +"``peer`` is the sender's ``(ip, port)``)." +msgstr "" + +#: 36c2c0e7900d436a977b8895e671c9f0 659caaa0c8bc40d3a9ce8d0905787584 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:93 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:87 of +msgid "" +"Running uploads keyed by fid; each value is ``[sent bytes, total bytes, " +"current speed, file path, peer]``, with ``peer`` the receiver's ``(ip, " +"port)``. A forwarded transfer stores the original peer on both sides, " +"never the relay." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:96 +#: f9528e6c490d4807b949f6730c6ece8e of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when a connection drops and read back on the next reconnect " +"(``resume_transfers``)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:110 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:104 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second sent, or None when not measured." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:113 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:120 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:107 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:114 +#: d926b4f3eb4b40a4acb21f780a4dc227 of +msgid "float | None" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:117 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base:111 +#: ed04a3bf285b4f57bb6a5de0c4f7284f of +msgid "Bytes per second received, or None when not measured." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:1 of msgid "Create the server and, unless extended, start accepting clients." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:3 -#: a2cce435d92d46e5b0b2cd59d43c8759 of +#: bf58d54a167d45de9a18641877ada912 of msgid "Address the server socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 -#: d4c7cd9cc01e4371961f0950fd861b12 of +#: 2f4d0c4bfd8246d4984d4c843510775d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:6 of msgid "First port to bind; also the base of the allocation range." msgstr "" -#: 716408a19bf349878edfd5f1948f57ec +#: 47138ce8f587467aa353e302f473df48 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:8 of msgid "" "Maximum concurrent clients served in thread mode; ignored when " "``is_asynic_clients_io`` is True. Defaults to 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 -#: c37fcc062f6947228f3dc0b85ec5a5ca of +#: 8786a9d2b6b449209be813778d785712 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:11 of msgid "Step between candidate ports. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 -#: e683b27a8b884c5b99511f99e20b6bf9 of +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:13 of msgid "Number of ports per step. Defaults to 100." msgstr "" -#: 6291e503f9bf4c78a9c226058a67bce1 +#: 973382c423524d44a569c318399e0b99 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:15 -#: e59cefed7c4e4148b863b89e4d17004e of +#: d5f8f341d98d478289d9a226f37c1003 of msgid "Concurrent file transfers allowed. Defaults to 10." msgstr "" -#: 792cebf4ce084bd9b222b9ee83eeb5f4 +#: 4fe9a7607dbc4eebbce4e62f9306c76f #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:18 of msgid "" "Reserve a port range across processes, so several instances on one host " "do not collide. Defaults to False." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 -#: befe96138f8544cbb8320f33af43af3e of +#: 8aa56addc6ae4a7790dc957d1e1c2b60 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:21 of msgid "Start the console command thread. Defaults to True." msgstr "" -#: 10c1ed53a097472297ade439439e218f 3bc54f27f3db4bce846f5ec756f0e68f +#: 242566ff64584fba88e4fed8bb189110 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:28 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:24 of msgid "" @@ -430,301 +503,440 @@ msgid "" " 10." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 -#: f0a3afe6bc0c4eb2ad2e9e5ae43e2d88 of +#: 87d1cd7d6569498b8af8bc7064235784 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:27 of msgid "" "When True, do not call `start_TCP_Server`; the caller starts the server " "when ready. Defaults to False." msgstr "" -#: 577dd2f594554ceab51324eaedf4b1b3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:30 +#: ac43634ddb1a4d15a9f3d0f58d011441 of msgid "" "Negotiate the RSA-encrypted channel for every connection. Defaults to " "True." msgstr "" -#: 1ea6dc3b1a34463881e1aa7e96a14525 +#: 1ffccca56902418ba98ee0c6776ad8fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:37 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 -#: ecd4aa80607e4f988ac59b64e85c8fbe of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:33 of msgid "" "``[pub_key_path, pvt_key_path]`` pair used instead of the default key " "lookup; an invalid pair is ignored." msgstr "" -#: 0b92e71977dc4312b9e31fab903eadf2 +#: 420bbdf8d6bb400fbd3548bea03354ac #: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:36 of msgid "" "Buffering ceiling in MiB for the in-memory forward pump; past it the " "uploader is told to pause. Defaults to 2048." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 -#: e14dae3d183249e19a0f6cf671ead02b of +#: 94e4a7e67e3047fd9d565f9a5d8122ab 9dcb36b97a004812bbcf264efa812441 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:39 of +msgid "" +"Bytes read per receive on the control connection, covering commands and " +"messages. Defaults to 4096." +msgstr "" + +#: 116dc6d56dd44f4ebaab990a3658359d 397abb5fbc1a46db90a7829daac02465 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:42 of +msgid "" +"Chunk size in bytes streamed when sending or receiving a file or folder. " +"Defaults to 65536 (64 KiB)." +msgstr "" + +#: 446099293d824f27aed7245f3c77df69 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:45 of msgid "" "Serve clients with asyncio coroutines on an event loop instead of one " "thread per client, so a single server can hold thousands of concurrent " "connections. Defaults to False." msgstr "" -#: 07311d6c7a2f4516a4209df5c7798be6 9f213be174d243d4af26f79ae9624945 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:44 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:44 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:50 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:50 of msgid "" "Log execution-process lines in addition to command and result lines. " "Defaults to False." msgstr "" -#: 28ea5071c3344615b114f12ad5be447c 497004294ca244138115a713c0ffed15 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:47 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:47 of +#: 4fe9a7607dbc4eebbce4e62f9306c76f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:53 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:53 of msgid "" "Log at all; False silences every line this instance would print. Defaults" " to True." msgstr "" +#: 1608cb9ad7104c82a43f23bb929f7d84 744b24d9e233457fb87cc8faefc5a498 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:56 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:56 of +msgid "" +"Track every running file transfer in ``file_recv_progress`` (downloads) " +"and ``file_upload_progress`` (uploads): each entry holds the bytes " +"transferred so far, the total size and the current speed (None while " +"``is_enable_real_time_network_speed`` is False). An entry appears when a " +"transfer starts and is dropped when it ends. Defaults to True." +msgstr "" + +#: 3658f6b3ec994d15b9321a10ae33b351 769ed811a0cb4b18aeacdd39e4b4bbe2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:64 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:64 of +msgid "" +"Measure the real-time network speed of every send and receive — the " +"control layer and every temporary connection (file transfers included) — " +"into ``upload_network_speed`` and ``recv_network_speed`` (bytes per " +"second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False " +"nothing is measured and every speed value is None. Defaults to True." +msgstr "" + #: ../../source/api/PyFlow.network_api.connect_tcp.rst -#: 0f0e9eea68114cf3b085d08796aaf552 3f8c413bab284fb78ac0b2ef8b8fb44a -#: 4a7a4c0862a84c53b2ccf0de3b00d495 4c3773b74abf40118b9ed681d9bef66a -#: 9f4fa9dc8d5045e39702036409f07a5d aa175c9daeab453a848bb2ef9f2e3dcf -#: cf96ad3305794cd7b9578ecb55ecd8b9 fbbf706646e24207aaf3b2532903a31b +#: 63ab5a2f2327475ba324e245f8e6e2ac msgid "Raises" msgstr "" -#: 0c72321c656641a5b684299b915cbb39 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:52 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:51 -#: d72a9dcf6bc748e5898640448e229b3b of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:81 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.__init__:73 +#: ed59ec69b9a1430597e6d8758051aff5 of msgid "" "If the ``.Flow`` directories or ``decode_command_table.json`` cannot " "be created or read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 -#: e2bb545e7ee1419286f58495abc4bcd2 of +#: 031d3e96394c454093561375a377dcce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:1 of +msgid "Pause an outbound transfer of this instance." +msgstr "" + +#: 342e6dfc6f6a4399914bc72372aa5f2d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. A " +"forward relay's writer toward ``peer`` is paused the same way the " +"``/pause_trans`` line pauses it." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:3 of +msgid "Transfer id the outbound leg is keyed by." +msgstr "" + +#: 7ecc0c956c8b408688fca517eb6370fd +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:10 of +msgid "" +"Restrict the pause to the leg or relay writer toward this ``(ip, port)``;" +" None addresses every match." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:14 +#: bdee1944910b4ee3908cf225a151a5fd of +msgid "" +"True when a running leg (or relay writer) was marked paused; False " +"when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 99ba2aa702f74621ba4dd31b8c045467 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:16 of +msgid "True when a running leg (or relay writer) was marked paused;" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans:17 +#: c85ed4c1a84443a98394146efcf04315 of +msgid "" +"False when nothing matched — the switch is still armed, so a leg later " +"started under this fid starts paused." +msgstr "" + +#: 2771724616054f628d60add2c7407e7b 3a0594b22c6849c88310243022e8ee23 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:1 of +msgid "Resume an outbound transfer paused with `pause_trans`." +msgstr "" + +#: 7a864ecc76fe40459eeff353522482fb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg or relay writer toward this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans:9 of +msgid "True when a live leg (or relay writer) was resumed." +msgstr "" + +#: 364557403e3d480896c0ffc57a19df04 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:1 of +msgid "Ask a connected client to pause its transfer toward this server." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:3 +#: f13c2e0e5310443080b0f63c773d8497 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (see `pause_trans` on the receiving side)." +msgstr "" + +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:3 of +msgid "Connected client ``(ip, port)``." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:5 of +msgid "Transfer id of that client's outbound leg." +msgstr "" + +#: 5ea8eea489fc43108a439d54fba31068 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:8 of +msgid "True when the line was written; False when ``peer`` is not connected." +msgstr "" + +#: 38905ec7539d42e0839907c32dd8667f +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:13 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:10 of +msgid "True when the line was written; False when ``peer`` is not" +msgstr "" + +#: 1c7b88e29a0143a39e13441769186ef4 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pause_trans_remote:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:11 of +msgid "connected." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_trans_remote:1 +#: adfc486a05ae4063bda6a61f2a6f3c36 of +msgid "Ask a connected client to resume a transfer paused earlier." +msgstr "" + +#: 810bc26336b24ad1acba3f56d466f8e9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:1 of msgid "Reserve this server's port range under the cross-process lock." msgstr "" +#: 5540b6efb5864c188e080ec7aad5c3ca #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 -#: c9ae1464a03b44049e826b9b73e2aca2 d23fda91e3e645e081dd5bbd5332fc4c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:3 of msgid "No-op unless ``is_hand_alloc_port`` is True." msgstr "" -#: 0b8bb2090cd04385a9d960dd2808f5bc 55b8a82ae1ce4769a1c62b35d253810e -#: 6d17c5fb7b4d484ba017edb4c5d5535e +#: 356ed2e8333d49b98ed6834612b4b56d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 -#: c3818bbf57ac448cb073fb780326fdf7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:6 of msgid "Step between candidate ports." msgstr "" -#: 1080747700804d04ae169eef511d5bb5 45799e3c1b6e446a86b111e06365ca9b -#: 5bfd1aa496dc41b7ab2abd78f134c389 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.alloc_port:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:8 -#: efa8e8819eec4e1ba0d90562f34755b5 of +#: e18848eedc5d4d8abd97d73a0984a5d3 of msgid "Number of ports per step." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 -#: c1cf751ac2774558925ef1ffd1a6c3dc of +#: 11e0523d1b194702a07a92748468da25 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.free_port:1 of msgid "Release this server's reserved port range." msgstr "" +#: 801c063c5fa447bda1dbf7f5ccbc6a9a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_lock:1 -#: b2b2a77e9deb4423955004a9e3390aca of +#: of msgid "Create the lock file that reserves the server port range for this process." msgstr "" -#: 658bc1e35a794bf5a22c70ffbef94b87 +#: 672bb7a9496c43ac8b706a3d0062ddfd #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:1 #: of msgid "Report whether the server port range is reserved by some process." msgstr "" -#: 39bb21b4d3a0404fb64295a73c2ad5ba 5dc09f28266e4a3bb083923d8784f09c +#: 39423e052b70403ba07a713aa9e3cb4a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.is_server_port_temp_info_file_locked:3 #: of msgid "True while the lock file exists." msgstr "" -#: 6512b0b8da7041e8a917014e5562583c +#: 5b6cf828ffb24e098a0c86a09818da73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.server_port_temp_info_file_unlock:1 #: of msgid "Remove the lock file that reserves the server port range." msgstr "" -#: 90520dc2f5704cdaba37211d6390b03d +#: 479bdf5518dc4a029ecf47ad44bdcd5d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:1 of msgid "Allocate the next free server port range and record it on disk." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 -#: cf0980ef8455426781e617a911f73732 of +#: 34c085a1bfca4dedafc749bfdcf14ad5 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:3 of msgid "" "``port`` is moved past the ranges already recorded by other servers, so " "the instance ends up with a range of its own." msgstr "" -#: 1e5f1ba9b8bf4d28971b92ef12f747f2 +#: 197b30e318d741c2b1f8afc925e91e5c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_alloc_port:11 of msgid "If the server port info file cannot be read or written." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 -#: bf4bb338fcf846a29910656081787945 of +#: 1c97c8ef484b42ab86d36b3742bf3879 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.hand_free_port:1 of msgid "Drop this server's entry from the on-disk port range record." msgstr "" -#: 30208c231b534eedbe843d42a3cad90d +#: 9fc07e857fa048e2956e64bf78f6e386 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:1 of msgid "Allocate a transfer port, waiting until one is free." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 -#: f219ec3cd1d1448fb4e0171853a7d779 of +#: 505d7b9fb1024bc8ba886e5b0a38fbf2 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:3 of msgid "" "Allocated port, or 0 when allocation is disabled " "(``is_hand_alloc_port`` False)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:5 -#: af35fb0d306d447ca2a70b0f2b63ecee of +#: e85fdf7f7a594e0b9aed565b4a3ab42f of msgid "Allocated port, or 0 when allocation is disabled" msgstr "" -#: 94b2dff9085247fda189e063a4fa4a7f +#: 153357eb91794cb692467afe5e94b41c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.palloc:6 of msgid "(``is_hand_alloc_port`` False)." msgstr "" -#: 06c8b24821f94f48b265dd90995e10a9 57f02c9c5f32443e82feac04411b32ed +#: 26c5c3768e1446e78c9efc5f8038b23d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:1 of msgid "Release a port obtained from `palloc`." msgstr "" -#: 750aeace3a2043978210096a24199700 +#: 0e0379de669843778f6827973c29372e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 -#: a400ec85715c462e941f3f590f646046 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.pfree:3 of msgid "Port to release." msgstr "" +#: 6a8d4efd9f9a45e399525e2f169035ee #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 -#: c6c5882e52c74fb1a5aa68e621922150 e95eb44c45ea42a5b63026f73274f990 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:1 of msgid "Allocate the next port above the base, or the first free one in range." msgstr "" -#: 2aec0e66e9e44175a6d6a36917137cf9 +#: 73e9e2ddd451402a93d10dbac6ac9374 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 14bd404133c744e68356290e50c91f4c +#: 9d96a242eab8433ca750d670a5f63b82 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:5 of msgid "Allocated port; None when the upward range is exhausted; 0 when" msgstr "" +#: 7b05e18fccbe4ab081d3cd22d59a48e0 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_palloc:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 -#: a2a1781441e64797a0d7942463680610 bccdcb4c96de4d6a9f6c4318d0b1f55e of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:6 of msgid "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 9b0a4b0fa07b4f7e8e4476f99d191837 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:1 -#: a4c53c6cf9d24f1ca624f8ade02cfb07 of +#: f2d9abe435cf49f6825bb72a68013934 of msgid "Release a port obtained from `file_palloc` and step the cursor back." msgstr "" -#: 24467ee3998b40bd9563059c6610e4e9 2a1c562ca62f40158d89d6f16896ed18 +#: 6c1fb07a212d4bf19717407b0c7184d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_pfree:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 -#: ace99e97fef7403faf20dc5040a47bfa ba3e6daae9e34590bc0f2abc98c02da3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:3 of msgid "Port to release. Ignored when allocation is disabled." msgstr "" -#: 053f2e52a148421eb080c1df3d3de1cc 9052b949aa354df7968cacc9ed930921 +#: 1afd81c685234a20aa41c5cde93d327d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:1 of msgid "Allocate the next port below the base, or the first free one in range." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 -#: eb3a97b7706a47dda4cfb5e12930ba02 of +#: 3fc63f6d51aa4c0fb22fd0f945f9cfd7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when " "allocation is disabled (``is_hand_alloc_port`` False)." msgstr "" -#: 3c8cc24113bd420eb7f373cde6a27ef2 +#: 74a441ccfa5e421dadd215ef0725a25f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 -#: f70a4f056d6c49b2b953824ffab19db7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_palloc:5 of msgid "Allocated port; None when the downward range is exhausted; 0 when" msgstr "" -#: 383142a0285745bb8ef4b95b1d597151 9f78428fda474dffac2f3cdf4c3a2aeb +#: 9c4b9bddd98c463f9e140bd2d8425dad #: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_pfree:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.spy_pfree:1 of msgid "Release a port obtained from `spy_palloc` and step the cursor back." msgstr "" -#: 57c8111cd86f49c7af67d8e9a177a591 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:1 -#: e435af0f27b641168044b3cac4130ac5 of +#: c66c76cab8564da4b6b6cb855fd63fd5 of msgid "Register a custom command handler." msgstr "" -#: 39f637bfe6ff4822952d67419861841d 51f84d06854b4b96b7ce1fb2e778b5e5 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:3 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of msgid "" "Command to intercept, e.g. \"/my_command\"; matched case-insensitively " "against the first token." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:6 -#: b53c2039d55947d689c2cfe09cac93c2 of +#: c7c29a3836c9493e9c8804cc5896144a of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back to the sender as the response." msgstr "" -#: 15398a9c312e459a897c07b18dc9fbaa +#: 7c64d0c0b9ac44b995811a0fdaa0dfaf #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:10 of msgid "" "\"server\" for commands arriving from clients, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 7ff63de06e854f88b1cebc42b464397d 8f139fd48e9c496287f9df897ccf01d6 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:13 +#: a0c074a9da664c5eb5fa63deb6765c36 of msgid "" "Run the handler on the worker pool instead of the reader thread. Defaults" " to False." msgstr "" -#: 1a0a724bef6140ceb235cbeaea95c1d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:17 -#: e73cb64f1ef544db8009b026ab5c376c of +#: e6c616f887334cb6925c03de2ad6f64c of msgid "" "False when ``where_to_run`` is neither \"server\" nor \"client\"; the" " handler is then not registered." @@ -732,60 +944,107 @@ msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:19 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:19 -#: e1cba64f5b384d169c366d8e16078683 eaab849e83884bd6be80fa08867ccde2 of +#: f125f1386b434f3a8199b1ceb8c44eca of msgid "False when ``where_to_run`` is neither \"server\" nor" msgstr "" -#: 4cbf71104b8544d18962b7a9adca8b7e 82c461f38cc44bc9914cb7009a5cf3e1 +#: 1a68dac068db434eb76e28015005f29c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:20 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.register_command:20 of msgid "\"client\"; the handler is then not registered." msgstr "" -#: 15aa55a075a64bb98f5819a8a5d37113 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 of -msgid "Register ``listener(client_id, message)`` for every inbound plain message." +#: 25c1023e97b64226a58cdf83f8ba07bf 9ebd0da560d747168cebc59ca93b1cb1 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:1 of +msgid "Call one registered extension command handler directly from code." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 -#: f914714947174f2298278112a91d82b0 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:3 +#: b14f4ed43e6c43c39579c1c16b169645 of msgid "" -"Plain messages are the lines received from clients that do not start with" -" ``/``; commands go through the registered command handlers instead." +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines clients send. " +"The handler runs on the calling thread — ``run_in_thread`` only affects " +"the console and inbound dispatch paths — and is called with ``None`` for " +"both ``client_socket`` and ``client_address``, since a direct call names " +"no peer." msgstr "" -#: 1b5e4524170242099c808039098d64c3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:11 +#: cdec2f24d2dc47bc8c505b7472dc3bf7 of +msgid "" +"Command line to run, e.g. ``\"/my_command arg\"``; the handler receives " +"it unchanged." +msgstr "" + +#: 4ad873e4e9da4574bc068029455f62ec +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:15 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:15 +#: of +msgid "Whatever the handler returns." +msgstr "" + +#: 0ab70b2e8ed040d4908d0900da96f6c2 0d85b81af0634a448e6a74d63c06045f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:18 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:18 +#: of +msgid "If no registered handler matches the first token of ``command``." +msgstr "" + +#: 1f5b21975ad2499a86fe21c69bfd7ca0 42f8d27a5499457da7302224dcc8a521 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:19 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.call_extension_functions:19 +#: of +msgid "If ``command`` cannot be split (unbalanced quotes)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:1 +#: ef5d20f1a16945368383a8cdbc3daa19 of +msgid "Register ``listener(client_id, message)`` for every inbound line." +msgstr "" + +#: 2459179e833b4e7db8e1d70571ac793a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:3 of +msgid "" +"Every line received from a client is reported, commands included " +"(``/help``, ``/file ...``, the crypto handshake lines, ...), so the " +"listener observes all inbound traffic; dispatch is unaffected, a command " +"still goes through the command handlers." +msgstr "" + +#: 9ec5fafe8ded489785400e3e489b8573 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_message_listener:8 of msgid "" "``listener(client_id, message)`` where ``client_id`` is the sender's " "``\"ip:port\"``. It runs on the receive thread, so it must not block, and" " exceptions raised inside it are swallowed." msgstr "" -#: 2e65864bfdd2429298dbf86682b3be81 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:1 -#: e562b99848544a8cb47afb41478d1b66 of +#: edb8edc2eb3f433186b54807a8ac43ad of msgid "Unregister a listener previously added by `add_message_listener`." msgstr "" -#: 346bd1c9d44045868b59b7643f1cf09e 8ff591c39e334e1eab8d05267532faed +#: 6fd7bb75a29e4973ac2bd05119255039 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_message_listener:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 -#: a0e48bdcb67e49498a113a58a504553c ab196c3b77b143069faa85a52626d946 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_message_listener:3 of msgid "Listener to remove; an unknown one is ignored." msgstr "" -#: 46010db8ce4d4eb1b06348f29e115846 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:1 +#: cf95477e5794404fbdf4e877a132ba1c of msgid "" "Register ``listener(client_id, full_path, name, size, command)`` per " "saved file." msgstr "" -#: 72536042242c4ea9bd2e6efa63fc9336 +#: 9c57d09f6d3d437890ae3ad306071701 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:3 of msgid "" "Fired after a file uploaded by a client (a direct send, or a forwarded " @@ -793,8 +1052,8 @@ msgid "" "``file_transfer_dir``." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 -#: f4ba3546e2b048d49d9c274ef8d8ac98 of +#: 6c938b7c8be3464f9925527b6deb4e1d +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.add_file_listener:7 of msgid "" "``listener(client_id, full_path, name, size, command)``; ``client_id`` is" " the uploader's ``\"ip:port\"`` and ``command`` the wire command that " @@ -803,196 +1062,185 @@ msgid "" "block." msgstr "" -#: 2e1706c637c54db9b8ed55ba98665535 3d6b3f43b6094b2e9776fcb9e4ce7bcb +#: 57b1e98125974187b986386da7991dd0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.remove_file_listener:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.remove_file_listener:1 of msgid "Unregister a listener previously added by `add_file_listener`." msgstr "" -#: 0a8d57625bba4ce4949fc23bce63f033 +#: 58f1ccd078ea406dab00d6d4be886a76 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 -#: c27185227a5f434f9641501d1d3bca2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:1 of msgid "Run a callable on the instance's worker pool." msgstr "" -#: 0c5aed09b63647cd87a3234ef9a4903c 40fade944d8d43b18599150134015443 +#: 6e05c7f46b244ae195c32ee52797fa37 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:3 of msgid "Callable to run." msgstr "" -#: 6bcb8f96e0584f66bbb94fe2573a7f61 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:5 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:5 -#: e959076fdf3843fc9c53ccb8492adfe6 of +#: e1c79706c9414895bdf7bf183bf5d41a of msgid "Positional arguments forwarded to ``func``." msgstr "" -#: 41d755cbd3cf48e7a0bc9d2b1aa3ab14 628a65eab1354dda83077715a47e63fb +#: 9221436fa83a4831942cf5be4e37e2cb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:7 of msgid "Keyword arguments forwarded to ``func``." msgstr "" -#: 1c03aa271c37431d974f08f11c93d7af 4b1078858cf64a1e92b36fa109fc1409 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:10 +#: a6b26d6cf54d4fafac2950cbe33ba56f of msgid "" "Handle for the submitted call; its worker slot is released when the " "call finishes." msgstr "" -#: 169f874c0ebb40d5aecd2549e60b4600 1e45486e3fd84627b015bf5a9a0a24b4 +#: 60f19983f7384aefbb6c97b84dd25f93 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:12 of msgid "Handle for the submitted call; its worker" msgstr "" -#: 037748a51dd94d43a3939fa8ec538d66 655c7802ef7c42a686c74d426531db8b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.submit_task:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.submit_task:13 +#: eadf6af0a0954798933dc427ba8e107e of msgid "slot is released when the call finishes." msgstr "" -#: 7b0b391fc53d42fb8f331d8e2da2be54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:1 -#: d6578909a33e4eef8afe892b33e0f70b of +#: fece61298a354d6db119309b29c6751d of msgid "Start a temporary listener for a side channel (not the main protocol)." msgstr "" -#: 1164584733744eb2aa574d6f61476c2d +#: 01d42ba32c2b41f482dd077cfb950f9b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 -#: c132c5365e7c487c92b4072a0020b52c of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:3 of msgid "" "``handler(client_socket, address)`` started in its own thread for every " "accepted connection." msgstr "" -#: 03583460bc824965b9152433dfdfb097 +#: 5e1b84445ee34c9cac00e1a2c9ef297b #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:6 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 -#: e81f361ea0fb46ee9c6760b0c6ef11c1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:6 of msgid "Port to bind; None allocates one with `palloc`." msgstr "" -#: 4f2f3f063e9c4834a77fbdb1a46d65dc +#: 9c69c4dd1d904078af48c6308ba35895 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 -#: b655787e48384873b4446ee1147bdedd of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:8 of msgid "Listen backlog. Defaults to 1." msgstr "" -#: 31cd65b92bb846f6b9c97b003fa00db5 +#: 47f98fd15e6144bd845d175cd039a6c2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 -#: ec56b80af0a843a991cbe77c5ee9ae45 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:11 of msgid "" "``(port, thread, stop_event)``; setting ``stop_event`` ends the loop," " which closes the socket and frees the port." msgstr "" -#: 7b73372b2ada4ce5b210b527015d925c 86cfce9d36f04328ba76e88df87fbcd8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:13 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:13 +#: ecf3d32c44db40a8a13545d623ffe2c9 of msgid "``(port, thread, stop_event)``; setting ``stop_event`` ends the" msgstr "" -#: 11b0347a0ebd4ae3931ed1f77c26a04e 9017aeb8480241f3a5f426c718bc4ee0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:14 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:14 +#: abce9546b7444c6383c9020c4133ec63 of msgid "loop, which closes the socket and frees the port." msgstr "" -#: 3c32a346019741da9aa2a3e409a7b0e2 82f16e3e9ba1468d8a87c91db28cc45e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_server:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_server:17 +#: a270cfabdac64296b8a33ad4d662896f of msgid "If ``port`` is None and no port can be allocated." msgstr "" +#: 031d3e96394c454093561375a377dcce #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:1 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 -#: d63b5db9eab6478ca088c9a5e90163fc f0869b5be0ab40e4a2a7eca275922557 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:1 of msgid "Open a temporary outbound connection for a side channel." msgstr "" -#: 3d194b9f95794116b17720aa74ce0878 +#: 112fda54e1eb4981b4272df61c5416e2 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 -#: d0bb03d9590540fd980dd79c28d98e97 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:3 of msgid "Host to connect to." msgstr "" -#: 98a5441019de48258a099f2ec25751f5 +#: 59d3c414b4304673be5d3232d2291680 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 -#: b443afa67dc84e1a8ac501ad5c6b0ff1 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:5 of msgid "Port to connect to." msgstr "" -#: 537482efdcc0447e81bd001ad2d4d85a -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:7 +#: c5766672f68f47c9908e68d2ed3be7f3 of msgid "Local port to bind; None lets the OS choose." msgstr "" -#: 2230b0e486fc4229acc03f78ec4b1e09 300e61efcfef4a2f8c87725e183ceda8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:10 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:9 +#: bfc1b713e9fc4fe797e50c357f472e76 of msgid "``on_data(data, client_socket)`` called for every received chunk." msgstr "" -#: 2f63095ce33849b78465729923d04ff0 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:14 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:13 -#: e07d5e5deb1a4fb086664ed896076feb of +#: c563d04fcd7a41f1a2aeace42974430a of msgid "" "``(client_socket, thread, stop_event)``; setting ``stop_event`` ends " "the receiver thread." msgstr "" +#: 0e1b9679f3104a9caab601e6bc7c0905 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:16 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 -#: bf9994c99c8a48139d4c00d0dcfeca63 dbf60e58abd04e02b50316b1cb4b7b2f of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:15 of msgid "``(client_socket, thread, stop_event)``; setting ``stop_event``" msgstr "" -#: 6af1621f80734591950e545b955c4bbe #: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:17 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.create_temporary_client:16 -#: e69a51e576e446c59185c2eceae72657 of +#: c76fce92c3f944c1857df89bbc134540 of msgid "ends the receiver thread." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 -#: c291ec3d31094e589a1bfc5713b47ee3 of +#: 5ea5fd66c3d3434292e4d8e1dd1da094 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:1 of msgid "Send one message to every connected client." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 -#: c28f38641c704c1e912c602ced57fc9e of +#: 32945f04e0564f9d88495506f0ab4f90 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:3 of msgid "Clients whose send fails are disconnected and removed from ``clients``." msgstr "" -#: 3f3e7a6a5de746518e9ddd135983d073 +#: 00de0b1f60b14189b1629f8146db68a6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:5 of msgid "Payload passed to `send_message`." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.broadcast:7 -#: cae2a2c29d96447d8b1056e36bbf5572 of +#: a91c8f6921c7435e990516c2134efcf8 of msgid "``(ip, port)`` to leave out, typically the client the message came from." msgstr "" -#: 9b2b7c4e77844a82bfd61276bf46f6d7 +#: 9d57c62f1fd94c1dacfe32aa50cc9665 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:1 #: of msgid "Send the messages of a console line to the clients named in it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_msg_to_specific_client:3 -#: cabc278e7f6a49e6bd6e533f632d0f99 of +#: e7fbf4bbd84b4920a2b9591fabcaf2d9 of msgid "" "``/send_msg`` line as typed: message text followed by one or more ``(ip, " "port)`` identifiers; each message is delivered to the identifiers that " @@ -1000,17 +1248,17 @@ msgid "" "notice." msgstr "" -#: 888e165ca1554b4db63e714e3adc63f1 +#: 9d4819fe4ca94a1b81c9e0423ff98212 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:1 of -msgid "Write one line to a client socket, encrypting when the channel is up." +msgid "Write one message to a client socket, framing it when the channel is up." msgstr "" -#: 64d6f6cc29de4d4290671afc59d808c7 +#: 1c7b88e29a0143a39e13441769186ef4 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:3 of msgid "Target connection." msgstr "" -#: 73953d67bcbf4bfabae7b0ff91bfce8c 7e2e221f6a6b43a08f534ca2d8cfb6e8 +#: 6f8bd9adaf2b4c44a9446b049144fe21 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:6 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:5 of msgid "" @@ -1018,62 +1266,73 @@ msgid "" " are." msgstr "" -#: 240dadd589af42e18e15d2c53b5c96b0 +#: 5c03983cb460497fb72f126c1d8a2bc1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:9 of msgid "" "True when the payload was written, False for an unsupported payload " "type." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 -#: dbfc49c3c67c48d5860a61f8ded20950 of +#: 0b11a149117c4a1fb6bcf2fba3d1a515 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:11 of msgid "True when the payload was written, False for an unsupported" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 -#: cab2f5321ba54adca315d34d921a09b5 of +#: 602950a9f5ad48ea92ab60aea3b26488 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:12 of msgid "payload type." msgstr "" -#: 4519dac81e714164a0edbf6ac75c9c19 +#: 149f767d72dc4da7b1d88fed768d2474 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:15 of msgid "If the server is not running or no socket was passed." msgstr "" -#: 7ea1b30273604db4854189502fdf734e +#: 07dac2d20d7041779c8b189d45ee2e64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.send_message:16 of msgid "If the socket write fails (the original error is re-raised)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:1 -#: b228437e9cb4461e9ceb078f084544eb of +#: caf2377ee7f348ab8c95bf2a27c44be4 of msgid "Read up to ``msg_length`` bytes from a client socket." msgstr "" -#: 292c2ed074e14a5eb184dceb245cab6f 58a8806cd0bb4dc9895b7f74a1b45765 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:3 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:3 +#: c702e4a63a5240ea97feb5bc393b4d09 e9256fbce5d848b59ae2e6d0ce88ce24 of +msgid "" +"A socket speaking frames (see `_SecureChannel`) returns decrypted " +"plaintext, served from the channel's buffer; a socket without one is read" +" raw. A read that started while the channel was raw is classified by the " +"channel when it returns, so bytes of a flip that landed during the read " +"never land in the line reader." +msgstr "" + +#: 214af2667d0f443eb16c0a4aaf723b2e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:9 of msgid "Connection to read from." msgstr "" -#: 547ccf662a6945738e8c761628807ab1 624220029a624009adb07a49140d8a2c -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:5 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:5 of +#: 7c3eb31687804ba5a59acc140ba50230 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:11 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:11 of msgid "Maximum number of bytes to read." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:8 -#: b0973e75b118425db7e7bfc966e5eb87 ff5195026f8143fea9240d4f21e81981 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.receive_message:14 of msgid "Received bytes, empty when the peer closed the connection." msgstr "" -#: 7acd066bfa87415094144b0e0c1ea0d4 +#: 7103cfcec26c44999cb5464251ee461c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:1 of msgid "Serve one accepted client until it disconnects." msgstr "" -#: 53591274f0824492afab6874b284c33e +#: 65f9de7f44774aa6aef81fcbe4dc1c64 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:3 of msgid "" "Registers the client, greets it, announces the encryption mode and reads " @@ -1083,8 +1342,8 @@ msgid "" "ends for any reason." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 -#: fba3167476a94b62af90bfc4101d1ed6 of +#: 87d5085c31a14ad38b060c48f8cf1262 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:9 of msgid "" "With ``is_asynic_clients_io`` False (the default) the call blocks and " "owns its thread; with it True the client is served by a coroutine on the " @@ -1093,22 +1352,22 @@ msgid "" "no event loop runs is closed with a console notice." msgstr "" -#: 72edaf343723458fb9b2fe0f40bc01b8 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:15 +#: db3915757e2842c8afee97b2d471411e of msgid "Accepted connection." msgstr "" -#: 6a2427e7b7de4d609bf61e3fad46b413 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_client:17 +#: fae378e888be4821a14ed2483cfde1e0 of msgid "Peer ``(ip, port)``; used as the client id and as the key in ``clients``." msgstr "" -#: 061015c431a54fafb45ea722ae696003 +#: 32886e2babcf4283924034c600453c4a #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:1 of msgid "Dispatch one command line received from a client." msgstr "" -#: 9cc9ee25bc464440a4ac2bca19e5a413 +#: 8972b8c4edf149fd9a4008832c85ed31 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:3 of msgid "" "Built-in commands (``/help``, ``/time``, ``/clients``, ``/quit``, " @@ -1119,24 +1378,23 @@ msgid "" "close the connection; an unknown command is only reported on the console." msgstr "" -#: 9a970df310fc4b59b113bb6160f24fd2 +#: 208294924333477a8e7d65aa3130777e #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:10 of msgid "Connection the line came from." msgstr "" -#: 8856eb18fd044b60b869be64e5f4576e +#: 306e5026cfc1441d8c754f0e02866cf3 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:12 of msgid "Peer ``(ip, port)``." msgstr "" -#: 6ea3bacf1baf4eadb98d5e38236ecf90 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:12 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:14 -#: e212b51318ea4d46ab6354b818dc262b of +#: a2a3a1fd57e14260a53675457fdff0b4 of msgid "Line including its leading ``/``." msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:17 of msgid "" "Response for that client, or None when no response is due (crypto " @@ -1145,11 +1403,11 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:19 -#: b3f201060ae548098d8284d4c18c0560 of +#: ed04a3bf285b4f57bb6a5de0c4f7284f of msgid "Response for that client, or None when no response is due" msgstr "" -#: 0dc75edb2f174aadbc9a87fea9271420 +#: 8d727a2aaab14beaa1b6858b59b0821d #: PyFlow.network_api.connect_tcp.TCP_Server_Base.handle_command:20 of msgid "" "(crypto lines, file transfers, ``/quit``, which answers on the socket " @@ -1157,114 +1415,108 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:1 -#: b4ee832e0ad64d189740b45a297d713d of +#: a784dfdc5ded411d985426e36f6e5435 of msgid "Send one plain message to a connected target, tagged with its origin." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:3 -#: ec8cc922a2ee4e70bdff9a8e81b74e98 of +#: b545977244dc402aa8586264d2d933f3 of msgid "" "Public API for forward extensions: the message is wrapped in a " "``/send_msg_from `` envelope so the receiver can " "attribute it to the originator (see `parse_forwarded_message`)." msgstr "" -#: 660b6f4493ec4c9994af44960900cb10 +#: 8ee5275fbf894581ade9e6f30d5d4aff #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:7 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 -#: b8a3838c85624f3dbe705afac78acc47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:7 of msgid "Destination ``(ip, port)``." msgstr "" -#: 1dfa946975cf4768891292e84a2bbc63 +#: 38ffd8a7079d4794811e3504c01052f8 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:9 of msgid "Payload to deliver." msgstr "" -#: 09f6b3913160404b9927d5e70252d9bc 5251c2b3867b4dc1b8dd8d09ea570d90 +#: 3b48d6e3b84b4dde9a09f3c2f07c8b61 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:15 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 -#: a8ee713ff78b42bd8adb5743ab369aef of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:13 of msgid "Originating client ``(ip, port)``." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:14 -#: ad5e4419a1d04b27bec64cf1aee14c53 of +#: d2471a90e269464c977239f406051120 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the envelope was sent." msgstr "" -#: 2fd94dad15884a56b9657090a33988f9 9e706f8851a74b569ade8deb4f8f70ab +#: 320d99b8923f4eaa886ffe0a16bfc6d9 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:24 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:16 of msgid "False when ``target`` is not connected (a console notice is" msgstr "" -#: 59049e3514b74a7ba90fb8886ecca185 +#: 1a97f59b270f404096d9c2b37ab09a8c #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_message_to:17 of msgid "printed); True when the envelope was sent." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 -#: b9019e7dae074d64a66ae1c81967b9b8 of +#: 6baab06dc12e4ecc80d1a16c26c2a19a +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:1 of msgid "Build the tagged wire command that pushes one forwarded item." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 -#: fcde926ccf5640b2b2ac6aab009aa4d0 of +#: 0c3f9dcbcf8f413fbd5befefb960c402 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:3 of msgid "" "Public API for forward extensions. The originator tuple sits before the " "trailing transfer id, where the receiver's existing parsers ignore it and" " `parse_forward_originator` recovers it for attribution." msgstr "" -#: 3cee0d37a9e5460a90b7c9b1abe53a92 +#: 3cf58937a2d04172bf544119279d85c1 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 -#: d5cb9e15787a435ab586217498d98e2b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:7 of msgid "\"file\" or \"file_folder\"." msgstr "" -#: 8efbb4663727491e8ee77edc824ce1c0 +#: 621a93603c8549c0ba047bee6aae5a38 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:11 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 -#: e8aeb2b89d5f4969aeaf2244f06a1a47 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:9 of msgid "Relative folder path (folders only)." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:13 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:11 -#: b439157e6df44d7bac2a4367c5fb66ee b9cb86fb0ad642e18ec19debb44a2648 of +#: f0f56fb642874c3889fb0dacfed4f4ef of msgid "File or folder name." msgstr "" -#: 5f249d30e8934ed0ae07c1ca2666c6c6 +#: 72d2b6fdd324482eaea9803def1fe2da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:17 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 -#: df45d1036cb9437a853551afb3f31775 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:15 of msgid "Transfer id shared by the pushed item." msgstr "" -#: 9bc7aaf1a36a4311a736f5528525d33a +#: 0aa1bd5b053544e98ae4ab3ae1add5f7 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:19 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 -#: f806614c8aeb428292d6ca51db8ca35b of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:17 of msgid "Receiver-side destination directory." msgstr "" -#: 1f3c679edcf34e71a946e8668ca27a58 +#: 93e666db45e745619b90c744e1646b73 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_target_command:20 of msgid "Command line to hand to `send_message`." msgstr "" -#: 3499106d953f41789e53f24bfcae3af5 +#: 56d8327bb7414a5e85292f8f2ace9d42 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:1 of msgid "Push one forwarded file or folder item to a connected target." msgstr "" -#: 959c24d8afff4486ad5f787311bf3c8b +#: 3098afa7f4ac43a184d081dda8faa6ba #: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:3 of msgid "" "Public API for forward extensions: sends the line built by " @@ -1272,24 +1524,157 @@ msgid "" "`parse_forward_originator`." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 -#: cb11d22918824fb09fa82fd432aeb74a of +#: 9b9634061040430484cd2596f43a8feb +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:22 of msgid "" "False when ``target`` is not connected (a console notice is printed);" " True when the command was sent." msgstr "" -#: 66262977fc014465964289448673a5b9 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 of +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.forward_item_to:25 +#: b8bb8c432f7649d5a35480fec0509a51 of msgid "printed); True when the command was sent." msgstr "" -#: 1df1cd85678d4149bdac92c3591c9e50 -#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 of +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:1 of +msgid "Receive one file over a transfer sub-connection." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:3 +#: d3367c6f97aa4bf4b9cb3d79b3117fce of +msgid "" +"``peer`` is the transfer's original sender (the sender for an inbound " +"transfer, never a relay): it is stored with the progress entry so a later" +" reconnect can ask that peer to continue the file." +msgstr "" + +#: 5c4faf52e8bb4808805bae58d30ac0cc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:8 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode_recv:7 +#: de641d48c530435bb4adc04755a47a6d of +msgid "" +"``resume_entry`` continues an interrupted transfer: the listener " +"announces itself, asks the sender to continue from the bytes already on " +"disk (``RESUME_LINE``) and appends the incoming chunks to the partial " +"file instead of truncating it." +msgstr "" + +#: 51eade0145d74a2bbfc51070bc779703 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:1 of +msgid "Send one file over a transfer sub-connection." +msgstr "" + +#: 87862abb10ad423f820952355f5936bc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:3 +#: d6a618c007ec433fa10a44b0a7a90fe4 of +msgid "" +"``control_socket``/``crypto`` carry the listener's mode stamp (\"plain\" " +"or \"enc:\"): an encrypted leg aborts when the session key " +"material is missing rather than downgrading silently." +msgstr "" + +#: 97e1a0538f544c2a8e755c78805fda7c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:7 +#: a405431dfd62434b82c7052edc456123 of +msgid "" +"``fid`` is the transfer's id — the caller's own transfer id for a plain " +"send, the relay id for a forwarded upload — and keys this leg in " +"``file_upload_progress``; every leg with a fid can be paused with " +"``/pause_trans`` for that fid. None (a leg without a protocol transfer " +"id, such as a public-key push) tracks no progress." +msgstr "" + +#: 6cb58bfd1dde4b49ba3525af014e44c7 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (never a relay): it is " +"stored with the progress entry so a later reconnect can be resumed. " +"``resume_offset`` continues an interrupted transfer from the byte the " +"receiver already holds: the file is read from there instead of its first " +"byte." +msgstr "" + +#: 1634dbe84a95421a92a660f7c6fdd10e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:1 of +msgid "Continue the interrupted transfers of a peer that is back." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:3 +#: eb46142fa4e44147ad3ad8c680d5bee0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and, for " +"every download this instance was receiving from ``peer``, opens a fresh " +"transfer listener and asks the sender to continue the file from the bytes" +" already on disk. Restored uploads need no action here: the peer drives " +"their resume from its own side." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:9 +#: b7d54977ca494a8b9968365dffd9bd3d of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer that is " +"connected right now." +msgstr "" + +#: 15c0118df8da4454a7fea8d529989237 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_transfers:13 of +msgid "Number of resumed receive legs started." +msgstr "" + +#: 52cb873f015542b6a94506cebfe735a1 737ed182911443bc8cfff3c4d094b9a9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:1 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:1 of +msgid "Continue one interrupted transfer this instance was sending." +msgstr "" + +#: 50f292ac853841c9b082eb3c3ff4d6f4 6c968a5b77b342ed891883336cfcc255 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:3 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:3 of +msgid "" +"Runs when a receiver asks to continue a transfer (``/resume_trans``, see " +"`resume_transfers` on the receiving side): the leg is re-established " +"against the receiver's fresh listener and the source file is read from " +"the byte offset the receiver already holds. Also the public API for " +"resuming one transfer on demand." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:9 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:9 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "Receiver ``(ip, port)`` the request came from; None skips the peer check." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:12 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:12 of +msgid "Transfer id of the interrupted transfer." +msgstr "" + +#: 7124e1ce01df4fcea9516bed4ca55dc7 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:14 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:14 +#: d94da1700d0e46028f7bf114d7c5da62 of +msgid "Byte offset the receiver already holds." +msgstr "" + +#: 1a97f59b270f404096d9c2b37ab09a8c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_trans:17 +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.resume_trans:17 of +msgid "True when the resume leg was started." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:1 +#: b03f4edeca5f4cc19f6d695aac3690de of msgid "Bind the server socket, then accept clients until `stop` runs." msgstr "" -#: 42bb4623926449f5b91a451bcac30a2f +#: 7e027ea659ab48e19ea346cb284fe144 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.start_TCP_Server:3 of msgid "" "Blocks the calling thread. A console command thread is started when " @@ -1300,12 +1685,12 @@ msgid "" "Socket errors and the end of the accept loop both end in `stop`." msgstr "" -#: 3d3320ce03544f23ac6f43883e5a580c +#: 291f5a8cc4f648ee9910e5cd45074675 #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:1 of msgid "Read console commands until the server stops." msgstr "" -#: 5f7369176edb4567b3eb5332588b8c57 +#: 1ba2e428d432496688ef23f1c07562da #: PyFlow.network_api.connect_tcp.TCP_Server_Base.console_input:3 of msgid "" "Handles ``/stop``, ``/status``, ``/clients``, ``/send_msg``, ``/file``, " @@ -1317,12 +1702,12 @@ msgid "" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:1 -#: ccbb242b51984c9f8ce9fb519c202485 of +#: eb90f49c77e64006a0c9ae861ff849b1 of msgid "Stop the server and release everything it owns." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Server_Base.stop:3 -#: e379bbd3f7b249c6b296f371548a5b1e of +#: a059b1e71106487999c83c2e2042f509 of msgid "" "Closes the server socket and every client connection, flushes the message" " and event stores, releases the allocated port range, clears ``running`` " @@ -1330,152 +1715,192 @@ msgid "" " Safe to call more than once." msgstr "" -#: 06fe9e3a48914447af6464acedea1fa0 +#: 32b06ea315b3404caa3a05c4aed0ce64 #: PyFlow.network_api.connect_tcp.TCP_Client_Base:1 of msgid "" "TCP client: connect to a server, dispatch commands, send and receive " "messages." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 -#: ef04371450674badb666b7fb31c203da of +#: 2b30f5c9ecd24fc89cdcd58000ee1e99 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:3 of msgid "" -"Lines received from the server go through `receive_messages`: a line " -"starting with ``/`` is handled by `handle_server_command` (protocol " -"commands plus the handlers registered for the \"server\" side), any other" -" line is a plain message delivered to the listeners registered with " -"`add_message_listener` and stored in ``messages_dict``. With " -"``is_input_command_in_console`` the console thread `interactive_mode` " -"sends typed lines to the server." +"Lines received from the server go through `receive_messages`: every line " +"is delivered to the listeners registered with `add_message_listener` " +"first (commands included; a forwarded ``/send_msg_from`` envelope is " +"delivered as its payload), then a line starting with ``/`` is handled by " +"`handle_server_command` (protocol commands plus the handlers registered " +"for the \"server\" side), any other line is stored in ``messages_dict`` " +"as a plain message. With ``is_input_command_in_console`` the console " +"thread `interactive_mode` sends typed lines to the server." msgstr "" -#: 840ff55e5e444cfbb85251e9c4123178 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:12 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:14 +#: b9532c86786c43d5aea58b24157fefed of msgid "Server address this client connects to." msgstr "" -#: 1f65ef8a745743ebb31ebc5805c5b02f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:18 of +#: 2cfa1e3e1674407ba1e2683e76fef65d +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:20 of msgid "Server port this client connects to." msgstr "" -#: 5956a034ca2347f384f682b52d927ee3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:24 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:26 +#: af04fdee2c95431a9b0c17f96e50c18c of msgid "Local address the socket binds to." msgstr "" -#: 1d2b7be8ff994d15b9a3f63c0e4fab11 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:30 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 +#: b1d4b5606e1c48b6a915815527542758 of msgid "Local port, None when the OS chose one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:32 -#: d616019e80a741638b6ac020d6abb336 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:34 +#: d926b4f3eb4b40a4acb21f780a4dc227 of msgid "int | None" msgstr "" -#: 0a015a4f44194fe2b25bbd4dfe52d1eb -#: PyFlow.network_api.connect_tcp.TCP_Client_Base:36 of +#: 500cfd177cf5453d887f6904b73b7851 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:38 of msgid "True while the connection is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 -#: da7ca1204aea47779bbaaa809f79da93 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:76 +#: fd832e1d72b642838382d529c3e1f22c of +msgid "" +"Whether `start_TCP_client` reconnects after the connection drops (and " +"resumes the interrupted transfers)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base:102 +#: c194bbee7cf14d268c330e06f94ae973 of +msgid "" +"Path under the protocol's ``.Flow`` directory where the two stores are " +"written when the connection drops and read back on the next reconnect " +"(`resume_transfers`)." +msgstr "" + +#: 40f2a9e1b730422db3dd58bc2a6046e3 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:1 of msgid "Create the client and, unless extended, connect and start reading." msgstr "" -#: 9e0577d19b76432089a46a53a2bbf7be +#: 0552aa36b7b74474af8f43b380dbee54 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:3 of msgid "Server address to connect to; required before `connect` is called." msgstr "" -#: 8400b2487cfb4cff8a72f452e3b4c83e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:6 +#: d246ff9aaf154bfa91b5c4c9d293afd5 of msgid "Local address the socket binds to. Defaults to \"127.0.0.1\"." msgstr "" -#: 7cb2047b830c4996832b4623812a687b -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:9 +#: e981b68ebbea46e9b556b09f4b5cd44a of msgid "Server port. Defaults to 65432." msgstr "" -#: 7a0404b673f84a1191af5479097f8cf5 +#: 766bf4c138234fe081bbd2668dcb2a5d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:11 of msgid "Local port to bind; None lets the OS choose an ephemeral port." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 -#: df784379acc1474aba6566c969dbb7bc of +#: 5d661c0f91f64ef39cacb1a5466d752c +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:14 of msgid "" "Socket timeout in seconds for connect and receive. Must be None when " "``is_wait_server`` is True." msgstr "" -#: 2b8bf92e3eb049ee8e994aa8b6d92fa5 +#: 9478d02062284ecaa7838f931ab80780 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:17 of msgid "Step between candidate ports in the allocation range. Defaults to 1." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 -#: fa74d746eefe4cb6862068fdbf384dd8 of +#: 2e1695ae510b43758793257124fd23c2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:22 of msgid "Enter interactive mode after connecting. Defaults to True." msgstr "" -#: 95ebbc90f84a41ada4b6edbec2c7a95e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:25 +#: e02da86957dd4f45bf84ede4e9c82cda of msgid "Keep retrying while the server is not reachable. Defaults to True." msgstr "" -#: 259f9e8d0d1547ae81e047e8ec24875d -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:31 +#: e1fb7f67e1714a61a9e8fe500555c700 of msgid "" "When True, do not call `start_TCP_client`; the caller connects when " "ready. Defaults to False." msgstr "" -#: 794bfe7ef8594729b0e87230d3ed9e49 +#: 1634dbe84a95421a92a660f7c6fdd10e #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:34 of msgid "Negotiate the RSA-encrypted channel with the server. Defaults to True." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:40 -#: e3f9232109d34798af1f681b250ec7d5 of +#: cff66a7ac1ad410f96ed1ee03cb1cf53 of msgid "" "Buffer ceiling in MiB, kept for parity with the server class; the " "client's forward path does not read it today. Defaults to 2048." msgstr "" -#: 71b662106e594538b8a5fcb9bc190b1f -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:51 of +#: 14c4889553fb42f7b0393a4a7ab46b4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:72 of +msgid "" +"Reconnect (and resume the interrupted transfers, see `resume_transfers`) " +"when the connection drops while `start_TCP_client` runs. The transfers " +"that died with the connection are persisted to the protocol's ``.Flow`` " +"directory and read back on the next connect. Defaults to False: a dropped" +" connection ends the client." +msgstr "" + +#: 0f06ff3b6db940da96ec09bee3dba526 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.__init__:80 of msgid "If ``is_wait_server`` is True and ``timeout`` is not None." msgstr "" -#: 4388cbc6302341adbdfa566d93526ef1 +#: 5dd677b9627d4b84b53dc7a6b2848b3f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:6 of msgid "" "``handler(client_socket, client_address, command)`` called with the raw " "line; a non-None return value is sent back as the response." msgstr "" -#: 14fcd0c8f3554ae983ac746cf3e58621 +#: 0a57a7875bb94767904ff8d93fa77eb8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.register_command:10 of msgid "" "\"server\" for commands pushed by the server, \"client\" for commands " "typed on this instance's console." msgstr "" -#: 88087ef71067485dbd40d569a7b950d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.call_extension_functions:3 +#: acb1af86a6184624a47ac6cc3b7127d0 of +msgid "" +"The handler is selected by the first token of ``command``, matched case-" +"insensitively against the names given to `register_command`: the console " +"group is searched first, then the group fed by the lines the server " +"sends. The handler runs on the calling thread — ``run_in_thread`` only " +"affects the console and inbound dispatch paths — and is called with this " +"client's socket and id, the context its dispatch paths give it." +msgstr "" + +#: 876e8fe2a6d645829ba12ddbad5006df #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:1 of -msgid "Register ``listener(sender_id, message)`` for every inbound plain message." +msgid "Register ``listener(sender_id, message)`` for every inbound line." msgstr "" -#: 50556c2d788d4e39a4a7cfed81ef6d6d +#: 2658650e027a4697b248f261903a4e29 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:3 of -msgid "Mirrors the server-side contract; commands are not reported here." +msgid "" +"Every line received from the server is reported, commands included, so " +"the listener observes all inbound traffic; a message another client " +"forwarded here is reported as its payload, attributed to the forwarder." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:5 -#: e6bec65449634cff953afd74d0e23e7a of +#: 412834182c9442adaf0b85e24c200ccc +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_message_listener:7 of msgid "" "``listener(sender_id, message)``; ``sender_id`` is the author's " "``\"ip:port\"`` — the forwarding client for a message another client " @@ -1485,21 +1910,21 @@ msgid "" "swallowed." msgstr "" -#: 38c576fe994b4a77830eaba36ca063b3 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:1 +#: fc8a83e0b5f84273a8287b122c1a9a3e of msgid "" "Register ``listener(full_path, name, size, command)`` per saved inbound " "file." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 -#: e258540084d64816a08e0783810c4e3e of +#: 34e3386853564aab9a824e96438fc3e5 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:3 of msgid "" "Fired after a file pushed by the server (a direct send, or a forwarded " "file/folder item) has been fully written to ``file_transfer_dir``." msgstr "" -#: 4e10b4a74e9142e0868ab1b0b423f359 +#: 63f925709b83433e967610672b6fbc79 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.add_file_listener:6 of msgid "" "``listener(full_path, name, size, command)``; ``command`` is the wire " @@ -1508,115 +1933,200 @@ msgid "" "it must not block." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 -#: afdf1e13067b4914a6aead736d7604e3 of +#: 4bc88415dfff40a3884ee0284b0ccc3f +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:3 of +msgid "" +"The sending leg with this fid stops at its next chunk and stays open " +"until `start_trans` (or the peer's ``/start_trans``) resumes it. This " +"covers every outgoing transfer — a plain upload as much as a forward " +"upload — and is what the ``/pause_trans`` line does when it arrives from " +"a peer." +msgstr "" + +#: 7e190ff27df349ae90eb7bd98a0b6b5b +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:11 of +msgid "" +"Restrict the pause to the leg whose original receiver is this ``(ip, " +"port)``; None pauses whichever leg holds the fid." +msgstr "" + +#: 5479763134c04a418df6a9e5011a9dcf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:16 of +msgid "" +"True when a running leg was marked paused; False when nothing matched" +" — the switch is still armed, so a leg started later under this fid " +"starts paused." +msgstr "" + +#: 2bc5d7e5dfa94eb29b49f12562f57c88 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:18 of +msgid "True when a running leg was marked paused; False when" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans:19 +#: a9c7cb3036f8409faad4c1db964d8a91 of +msgid "" +"nothing matched — the switch is still armed, so a leg started later under" +" this fid starts paused." +msgstr "" + +#: 59fa8126f08348bb9368c35b5d2336e2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:5 of +msgid "" +"Restrict the resume to the leg whose original receiver is this ``(ip, " +"port)``; None addresses every match." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans:9 of +msgid "True when a running leg was resumed." +msgstr "" + +#: 37e6dd691f544a80b9e0949883a2e5a8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:1 of +msgid "Ask the server to pause its transfer toward this client." +msgstr "" + +#: 89fa1c905614496ea12a4cfde9eb3cce +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:3 of +msgid "" +"Sends the ``/pause_trans `` line the peers use for transfer flow " +"control (a forwarded upload this client relays is throttled this way)." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:6 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:3 +#: b541e8446e374bc8b38cd7912a1fa33c of +msgid "The server's ``(ip, port)``; None accepts the connected server." +msgstr "" + +#: 72d2b6fdd324482eaea9803def1fe2da +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:6 of +msgid "Transfer id of the server's outbound leg." +msgstr "" + +#: 39423e052b70403ba07a713aa9e3cb4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.pause_trans_remote:12 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:9 of +msgid "True when the line was written." +msgstr "" + +#: 149f767d72dc4da7b1d88fed768d2474 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_trans_remote:1 of +msgid "Ask the server to resume a transfer paused earlier." +msgstr "" + +#: 0e91f82d8856443497c399f97643b757 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:1 of msgid "Reserve this client's port range under the cross-process lock." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 -#: cd973d56799848ecbd65c434c9f5f0ae of +#: 6029a28126344e45b24394cb56b2f8f8 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.alloc_port:3 of msgid "No-op until the server assigns a range (see ``/client_alloc_port_range``)." msgstr "" -#: 29e4db224e2d4208a5fc08a1523f9e6b +#: 32bed401c3574959ba5ed08fc9078401 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:1 of msgid "Release this client's reserved port range." msgstr "" -#: 7b0f2f6530984dcc888286f471f14747 +#: 9f86b7aac4f44886be9cd87b56072b63 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.free_port:3 of msgid "No-op unless a range was assigned (``is_hand_alloc_port`` True)." msgstr "" +#: 8154f96d9ec74bd588971a806d42f8c1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_lock:1 -#: c6e04e800074445da45886940c77a9f8 of +#: of msgid "Create the lock file that reserves the client port range for this process." msgstr "" -#: 2c7b09854c254d0bbfa62d2a356cfb24 +#: 69c2dd5d5d1d497c8bac1e62ab4fc30a #: PyFlow.network_api.connect_tcp.TCP_Client_Base.is_client_port_temp_info_file_locked:1 #: of msgid "Report whether the client port range is reserved by some process." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.client_port_temp_info_file_unlock:1 -#: b2cbf44d95154896ab2df64bf8be1a3d of +#: c88f37ef2d5c47bda346e804508d6ec0 of msgid "Remove the lock file that reserves the client port range." msgstr "" -#: 690717115cb64dfeb32f56302992451c +#: 478443e187814a6ca7ad798277db023f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:1 of msgid "Allocate the next free client port range and record it on disk." msgstr "" -#: 2e8d17873f8b4b419f2f6cd1f2000a62 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:3 +#: a8736540f4c3402fad9508e619d559d7 of msgid "" "``port`` is moved past the ranges already recorded by other clients on " "this host, so each instance ends up with a range of its own." msgstr "" -#: 2d7cb151d3bc4798914cbe3d73391c16 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_alloc_port:11 +#: bc44b1604e02467280b59cb8ad63d0af of msgid "If the client port info file cannot be read or written." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.hand_free_port:1 -#: b6079f909975409c86477341dcf2990c of +#: e48dff576a074109a135db168b5dbe98 of msgid "Drop this client's entry from the on-disk port range record." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 -#: c7fc083bff234cb7b377bc7adbb65ca5 of +#: 3aa62e8843c6495c862f43fc6dda9d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:1 of msgid "Allocate a port, waiting until one is free." msgstr "" -#: 85129bb5393542e498835f3ba6dc981a +#: 2f7752fa51d946b1a4a566b38f046e80 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.palloc:3 of msgid "Allocated port, or 0 when no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 -#: e77dc25d62bc4eedbd153b7420d109f4 of +#: 503ab40fc32c4d548f65fa3272b2f4d2 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:3 of msgid "" "Allocated port; None when the upward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:5 -#: c452f87d6e18446cbbb2f48b1dc47b9b of +#: b9fd549c95f24c2080d87cec92514db6 of msgid "Allocated port; None when the upward range is exhausted; 0 when no" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 -#: e195a16298f14417b95ed3dc3ad60fac of +#: 151a65f1c1984e4196c750108d0611cb +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_palloc:6 of msgid "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 -#: f7330894d1a041ca9a31ca1b390d5af7 of +#: 0c6201bb2d7e45d3a4916d7e50a21e10 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:3 of msgid "" "Allocated port; None when the downward range is exhausted; 0 when no " "allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 -#: a8d7d910fb874925acb423d08187908d of +#: 76c766a9c61f4075a762ccf55038a65e +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.spy_palloc:6 of msgid "no allocation range was assigned." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 -#: c76dd143ea224bb69081222ac4228f8f of +#: 8d500513e8854ba4bb91c8905a9adb73 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.create_temporary_client:7 of msgid "Local port to bind; None allocates one with `palloc`." msgstr "" -#: 5a8b77d5b1e243d9b5b24039b6ff25d0 +#: 840360623c8a4c2bbafe8fe7bbf9209c #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:1 of msgid "Connect to the server and start reading from it." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:3 -#: b59d15dc7c7844a5bd0226eb081c9887 of +#: df94288e660b48f6809358b3dc234ec9 of msgid "" "Binds ``client_port`` when one was configured, then retries while " "``is_wait_server`` is True and the server is not reachable yet. Once the " @@ -1624,7 +2134,7 @@ msgid "" "negotiated, which closes the connection when the two sides disagree." msgstr "" -#: 8711ef70ac704a48b05e13ded3546471 +#: 22fccba0ab36499a9a7f4427abe5e9f4 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:8 of msgid "" "True when the connection is established (and, if encryption is " @@ -1632,105 +2142,107 @@ msgid "" "failed or the mode negotiation closed the connection." msgstr "" -#: 850616ca4a614020b9627a3c39a54555 +#: 0270d0a2d42740a9889106339d9f2dbb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:10 of msgid "True when the connection is established (and, if encryption is" msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.connect:11 -#: cd0e7073f18d4d2ba990f1bfda735fd4 of +#: c194691cedfb48c6bfd97d9bdc6f2246 of msgid "" "enabled, the key exchange has been started); False when the attempt " "failed or the mode negotiation closed the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 -#: b7b9e013f50348379a0208a7702b9b1f of +#: 4dc38e3ef3b74b8e8c27378242a1925a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:1 of msgid "Read from the server until the connection ends." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 -#: ae819668995f44878eaa9c4a8db02583 of +#: 431649a0d703476dadc6afa8adbe53d4 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_messages:3 of msgid "" -"Runs on the receive thread: plain lines are reported to the message " -"listeners and stored in ``messages_dict`` (``/send_msg_from`` envelopes " -"are attributed to their sender first), other ``/`` lines go to " -"`handle_server_command`. Any end of the connection clears ``running`` and" -" releases the port range." +"Runs on the receive thread: every inbound line is reported to the message" +" listeners (commands included); a plain message is also stored in " +"``messages_dict``, while a ``/send_msg_from`` envelope is reported and " +"stored as its payload attributed to the forwarding client, and other " +"``/`` lines additionally go to `handle_server_command`. Any end of the " +"connection clears ``running`` and releases the port range." msgstr "" -#: 32feafb4504a473dbbe6b0957d3658f0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:1 +#: cf284b59f7f849039404ced20f8e12db of msgid "Write one line to a socket, encrypting when the channel is up." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 -#: c639152d8792432ba220c33c860f1211 of +#: 40ba2ede2d3f4666b82107af129d24d0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:3 of msgid "Target connection; the client passes ``self.client_socket``." msgstr "" -#: 5b421459787b4210b8bce3e7003cf35b +#: 2e663941eaf142cb96738add05f9ef4d #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:10 of msgid "" "True when the payload was written; False when the client is not " "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 1684a06aa826439784ce149aece2f637 +#: 38905ec7539d42e0839907c32dd8667f #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:12 of msgid "True when the payload was written; False when the client is not" msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 -#: bc5ff108fa3d46afb45fd86d4106ac2f of +#: 3f7e2e6fedda476f996132c3f677f2f0 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message:13 of msgid "running, no socket was passed, or the payload type is unsupported." msgstr "" -#: 3b27239d40244e35817e0806e3363df0 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:1 +#: a9220a130e694e0aba1d3b6320dff498 of msgid "Send the payload of a console line to the server." msgstr "" -#: 66bc43727101429bacd6a76534c53f7b +#: 2e208e83a89e4dac9793460a8808a042 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:3 of msgid "" "Console line such as ``/send_msg hello``; the first token (the command " "name) is dropped and the second one is sent." msgstr "" -#: 4cb6da8a7d464be983bf467e65fe55b0 +#: 39c8e70ca92b43b8ac687bc0aa7f4073 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.send_message_to_server:7 of msgid "If the line has fewer than two tokens." msgstr "" -#: 369743f21d0f4656aa801c8f29b4129b +#: 8d47f30ae7b0451f8ecfe207ec835ff3 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.receive_message:1 of msgid "Read up to ``msg_length`` bytes from a socket." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 -#: f6749336c57b4a82b5c0b19f27bd8906 of +#: 10a39005f45c46728ef9a000eeaf9109 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:1 of msgid "Dispatch one command line pushed by the server." msgstr "" -#: 510b3d71451048138e11fe92fdb160b4 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.handle_server_command:3 +#: a7e781fde939475cb081204adac16ded of msgid "" "Handles the protocol's own lines: ``/crypto_mode`` (a mismatch closes the" " connection), ``/client_alloc_port_range``, the ``/crypto_*`` exchange " "lines, and the transfer lines ``/file``, ``/file_folder``, " -"``/forward_upload``, ``/pause_trans``, ``/start_trans``, " +"``/server_file_transfer_port``, ``/forward_upload``, ``/pause_trans``, " +"``/start_trans``, ``/resume_trans``, ``/forward_resume`` and " "``/forward_error``. Any other name goes to the handlers registered for " "the \"server\" side via `register_command`; an unknown command is only " "reported on the console." msgstr "" -#: 7724aab357eb408dbbf018c214f8eba0 +#: 91942d88960c4793b5eab8c3654c1400 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:1 of msgid "Forward plain messages to other connected clients through the server." msgstr "" -#: 12403f5be7704258849974d103865b9c +#: 75bb9147a7464a278e19af9d03b04ecb #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:3 of msgid "" "The console command ``/forward_send_msg`` uses this; the client must be " @@ -1738,40 +2250,40 @@ msgid "" " so the receiving client can attribute it back to this one." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 -#: fc0907a1c7484f66a7b2cc1a99d24dc0 of +#: 0f3c201936df45b687dc5532531b4a4a +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:7 of msgid "Message texts to forward." msgstr "" -#: 8d07efc16f6c45d7b9d1d4f85f945317 +#: 277bbcb2143943b5b983badb00c3f4fa #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:9 of msgid "Destination ``(ip, port)`` tuples." msgstr "" -#: 4afafed2326a42e391e3b098cfea4f06 +#: 5ea8eea489fc43108a439d54fba31068 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:12 of msgid "" "True when the request was written to the server; False when the " "client is not connected." msgstr "" -#: 85c761742fa5450f846373591e4af1ff +#: 2bc5d7e5dfa94eb29b49f12562f57c88 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:14 of msgid "True when the request was written to the server; False when the" msgstr "" -#: 6ae9ff84b7d64c30abd31cde1715b783 +#: 45d974ad946b408b91d41bcce65abcc8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_messages:15 of msgid "client is not connected." msgstr "" -#: 7b79bd0e677c42fd921308a34e9a0929 -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:1 +#: c9401da7c37e40e5978c80e4876b11a0 of msgid "Read console lines and act on them until the client stops." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 -#: d91a5c812cdb4705a2fa27ac33ef693a of +#: 793bcfd02c014200b0ec47f8e15b4d91 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.interactive_mode:3 of msgid "" "``/quit`` closes the connection; ``/send_msg``, ``/file``, " "``/multiple_file``, ``/file_folder``, ``/multiple_file_folder``, " @@ -1781,38 +2293,77 @@ msgid "" "it stands. Ctrl-C and EOF close the connection." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 -#: dc2c54034ec64b61a3af655e86bc81a2 of +#: 7ba721f9d59742b99e89e3b6e249e754 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode:13 of +msgid "" +"``peer`` is the transfer's original receiver (the target of a forward, " +"never the relay): it is stored with the progress entry so a later " +"reconnect can be resumed. ``resume_offset`` continues an interrupted " +"transfer from the byte the receiver already holds: the file is read from " +"there instead of its first byte." +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:3 +#: a3c59554b8de41b280df7536b307bed0 of +msgid "" +"Reads the persisted stores back (`_load_transfer_progress`) and drives " +"every download that can be continued: a file the server was sending is" +msgstr "" + +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:6 +#: fae378e888be4821a14ed2483cfde1e0 of +msgid "" +"Peer ``(ip, port)`` that just connected; None resumes every peer the " +"client can reach." +msgstr "" + +#: 48061103ed9d4bcaae8a8a837b363557 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.resume_transfers:10 of +msgid "Number of resumed transfers started or requested." +msgstr "" + +#: 6dbae803a56c442588b28af664b7a0e9 +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_file_console:1 of msgid "" "/forward_file ... ... [dest] (client " "only)." msgstr "" -#: 303ae7e9e20444e38b303177bef0fb36 +#: 05cad8b03e0747dc804ffbfda3122fe1 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.forward_folder_console:1 of msgid "" "/forward_folder ... ... [dest] " "(client only)." msgstr "" -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 -#: ec2b9ff3c5cf4fb5a79e29242221fe67 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.file_transfer_mode_recv:3 +#: f6f606236f434f0287a969ccbe5ba2c5 of +msgid "" +"``peer`` is the transfer's original sender (the server for a pushed file," +" the originating client for a forwarded one — never the relay): it is " +"stored with the progress entry so a later reconnect can ask that peer to " +"continue the file." +msgstr "" + +#: 6e9a9717a782419baecca63fd1f46baf +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:1 of msgid "Close the connection and release everything the client owns." msgstr "" -#: 43645acb6c524c348b870d288aafae5e -#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 of +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.close:3 +#: ba6c5badecf6465db6036735870ed305 of msgid "" "Stops the receive loop, releases the port range, flushes the message and " -"event stores and closes the socket. Safe to call more than once." +"event stores, persists the interrupted transfers and closes the socket. " +"Safe to call more than once." msgstr "" #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:1 -#: afb1904037404a6c99f6b7ae2df119e2 of +#: c91a3245b93f46abbb49dbef7bcfeb1c of msgid "Connect to the server and start the client loop." msgstr "" -#: 6f912c76416e4f37a750eda0c126da35 +#: 0c83552867484ea780fcff8d34e5c2d8 #: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:3 of msgid "" "Enters `interactive_mode` when ``is_input_command_in_console`` is True, " @@ -1822,6 +2373,15 @@ msgid "" "while still connecting returns quietly, because that stop was asked for." msgstr "" +#: PyFlow.network_api.connect_tcp.TCP_Client_Base.start_TCP_client:9 +#: eec663f58484446ebce460e6402d7b5f of +msgid "" +"With ``is_auto_reconnect`` True a dropped connection does not end the " +"client: it reconnects (waiting for the server when ``is_wait_server`` is " +"set) and every session carries the interrupted transfers of the previous " +"one (`resume_transfers`). A close or ``/quit`` still stops the client." +msgstr "" + #~ msgid "" #~ "Concepts live in " #~ "``docs/Network_APIs/TCP_Server_APIs.rst`` and " @@ -1917,3 +2477,117 @@ msgstr "" #~ " `close`." #~ msgstr "" +#~ msgid "" +#~ "one message per line, terminated by " +#~ "a newline; a line that starts with" +#~ " ``/`` is a command and goes to" +#~ " the command handlers, anything else " +#~ "is a plain message reported to the" +#~ " registered message listeners;" +#~ msgstr "" + +#~ msgid "" +#~ "an RSA-encrypted channel is negotiated" +#~ " right after connect unless " +#~ "``is_enable_encrypto`` is False;" +#~ msgstr "" + +#~ msgid "" +#~ "file/folder transfer, message forwarding and" +#~ " port allocation are layered on the" +#~ " same socket and share its command" +#~ " namespace." +#~ msgstr "" + +#~ msgid "" +#~ "The forwarding extensions use the " +#~ "module-level parsers `parse_forwarded_message`, " +#~ "`parse_forward_items_and_addrs`, `parse_forward_originator` " +#~ "and `forward_skip_message`." +#~ msgstr "" + +#~ msgid "" +#~ "Each accepted connection is served by" +#~ " `handle_client`, either in its own " +#~ "thread (the default) or by a " +#~ "coroutine on an asyncio event loop " +#~ "when ``is_asynic_clients_io`` is True: a " +#~ "line starting with ``/`` goes to " +#~ "`handle_command` (built-in commands plus " +#~ "the handlers registered with " +#~ "`register_command`), any other line is a" +#~ " plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(client_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "" +#~ "Plain messages are the lines received" +#~ " from clients that do not start " +#~ "with ``/``; commands go through the " +#~ "registered command handlers instead." +#~ msgstr "" + +#~ msgid "Write one line to a client socket, encrypting when the channel is up." +#~ msgstr "" + +#~ msgid "" +#~ "Lines received from the server go " +#~ "through `receive_messages`: a line starting" +#~ " with ``/`` is handled by " +#~ "`handle_server_command` (protocol commands plus " +#~ "the handlers registered for the " +#~ "\"server\" side), any other line is " +#~ "a plain message delivered to the " +#~ "listeners registered with `add_message_listener` " +#~ "and stored in ``messages_dict``. With " +#~ "``is_input_command_in_console`` the console thread" +#~ " `interactive_mode` sends typed lines to" +#~ " the server." +#~ msgstr "" + +#~ msgid "" +#~ "Register ``listener(sender_id, message)`` for " +#~ "every inbound plain message." +#~ msgstr "" + +#~ msgid "Mirrors the server-side contract; commands are not reported here." +#~ msgstr "" + +#~ msgid "" +#~ "Runs on the receive thread: plain " +#~ "lines are reported to the message " +#~ "listeners and stored in ``messages_dict`` " +#~ "(``/send_msg_from`` envelopes are attributed " +#~ "to their sender first), other ``/`` " +#~ "lines go to `handle_server_command`. Any " +#~ "end of the connection clears ``running``" +#~ " and releases the port range." +#~ msgstr "" + +#~ msgid "" +#~ "Handles the protocol's own lines: " +#~ "``/crypto_mode`` (a mismatch closes the " +#~ "connection), ``/client_alloc_port_range``, the " +#~ "``/crypto_*`` exchange lines, and the " +#~ "transfer lines ``/file``, ``/file_folder``, " +#~ "``/forward_upload``, ``/pause_trans``, ``/start_trans``," +#~ " ``/forward_error``. Any other name goes" +#~ " to the handlers registered for the" +#~ " \"server\" side via `register_command`; an" +#~ " unknown command is only reported on" +#~ " the console." +#~ msgstr "" + +#~ msgid "" +#~ "Stops the receive loop, releases the " +#~ "port range, flushes the message and " +#~ "event stores and closes the socket. " +#~ "Safe to call more than once." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po index ca5690f..cf19d10 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.network_api.rsa_crypto.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-10-01 18:19+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -20,21 +20,21 @@ msgstr "" "Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.network_api.rsa_crypto.rst:2 -#: a48a4f614e834981afd42e2cb723ce06 +#: def9740b5a2e4aaeb2aeed8b4f02c0ec msgid "PyFlow.network\\_api.rsa\\_crypto module" msgstr "" -#: PyFlow.network_api.rsa_crypto:1 e529881eccb0440c888d5c69244133f9 of +#: 46d3090efafd4504870cf72a4bea22ab PyFlow.network_api.rsa_crypto:1 of msgid "crypto_api (C/OpenSSL) RSA integration for PyFlow's TCP layer." msgstr "" -#: PyFlow.network_api.rsa_crypto:3 d9d01596a65340fb84c25298550845cf of +#: 5b1ff4a00b0f46258cda2e7440368de1 PyFlow.network_api.rsa_crypto:3 of msgid "" "A thin ctypes binding to the shared ``libcrypto_api`` plus the key " "lifecycle required by the encrypted TCP channel:" msgstr "" -#: 232e71aebc434fb6bece23f593557e9f PyFlow.network_api.rsa_crypto:6 of +#: PyFlow.network_api.rsa_crypto:6 a5a0d6d600604683990a92555a49a3fe of msgid "" "Reuse an existing RSA keypair from ``~/.ssh`` (PEM private key) when one " "is present and parseable, otherwise generate a fresh keypair into " @@ -42,7 +42,7 @@ msgid "" "honoured when both files parse and the pair matches." msgstr "" -#: 29d30af10f8c4180890f876bb14b00e3 PyFlow.network_api.rsa_crypto:10 of +#: PyFlow.network_api.rsa_crypto:10 bb413dc908624589a3e57f8a2c702728 of msgid "" "Anti-MITM identity check (TOFU): every connection exchanges public keys " "in plaintext. Each side records the peer in " @@ -52,14 +52,21 @@ msgid "" "endpoint is re-registered under the new ``(ip, port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto:16 d4873e3b840e4e7fbe4c6f85850dc2a7 of +#: PyFlow.network_api.rsa_crypto:16 aec1a7998276428881efcfac6fe4cebe of msgid "" "RSA-OAEP encrypt/decrypt with the ``_VALID`` plaintext signature so a " "stale key (for example a rotated ``~/.ssh`` pair) is detected and the " "peers re-exchange their public keys." msgstr "" -#: 49f63152bca249588cf98871d5bafa64 PyFlow.network_api.rsa_crypto:20 of +#: 392850c432f2466ab9ecfd64770e648d PyFlow.network_api.rsa_crypto:19 of +msgid "" +"ECDH key agreement (P-256/P-384/P-521) with HKDF-SHA256 session-key " +"derivation and AES-256-GCM ``seal``/``open`` (``EcdhKeyPair``, " +"``EcdhPubKey``, ``hkdf_sha256``)." +msgstr "" + +#: 55cfc03aeb3f4d6ba37b10a01dfcdccc PyFlow.network_api.rsa_crypto:23 of msgid "" "The C library is compiled into the installed package by ``setup.py`` (a C" " compiler and OpenSSL development headers are needed at install time); a " @@ -67,21 +74,33 @@ msgid "" "still supported. See ``load_library`` for the search paths." msgstr "" -#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 -#: a3ac757cc1fa4c73be13eaa020c8e60b of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoLibraryError:1 of msgid "Raised when the shared libcrypto_api cannot be loaded." msgstr "" -#: 9c5bbad270ac48cd997b23cd4f284152 PyFlow.network_api.rsa_crypto.RsaKey:1 of +#: 67af7d5c5f41474fba915352e506a8b4 +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:1 of +msgid "Raised when a ``pf_*`` call fails." +msgstr "" + +#: 2c3651ee5dc94886986aa9804b164e3d +#: PyFlow.network_api.rsa_crypto.CryptoOperationError:3 of +msgid "" +"``code`` is the ``pf_err_t`` value (one of the ``PF_ERR_*`` module " +"constants), or ``None`` when the failing call returned no code." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.RsaKey:1 e620122ff0bc48dd985c4b6a0b3b41ce of msgid "Owns an ``pf_rsa_key_t*`` handle; frees it on GC." msgstr "" -#: 0eab5b9b31774196a46b7d400341a404 +#: 1a7d8e9db5a3435486d716b13f2a2a56 #: PyFlow.network_api.rsa_crypto.load_library:1 of msgid "Locate and load the shared crypto_api library (cached)." msgstr "" -#: 8bcac9994a6048e4920e23b8f94bb000 +#: 287fcfd81df2461d8e4bceebf61b7e40 #: PyFlow.network_api.rsa_crypto.load_library:3 of msgid "" "Search order: the library ``setup.py`` compiles into the installed " @@ -92,25 +111,98 @@ msgid "" "reported only if no other candidate works." msgstr "" -#: PyFlow.network_api.rsa_crypto.get_local_mac:1 -#: b555d90eff7c445a8a28cb3de88bd581 of +#: PyFlow.network_api.rsa_crypto.EcdhPubKey:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_pubkey_t*`` handle; frees it on GC." +msgstr "" + +#: 556fdf46d6c543e0ab06e2d4fabad7f1 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:1 of +msgid "Parse a peer public key from a PEM string." +msgstr "" + +#: 88cd040e91194a3785bf56d7c52d3543 +#: PyFlow.network_api.rsa_crypto.EcdhPubKey.from_pem:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_PARSE`` for " +"malformed PEM or a point that is not on the curve (the C library verifies" +" the point)." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:1 e620122ff0bc48dd985c4b6a0b3b41ce +#: of +msgid "Owns a ``pf_ecdh_keypair_t*`` handle; frees it on GC." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair:3 f12b2d8d1d4846edbf60d64c34860558 +#: of +msgid "" +"``curve`` is one of ``\"P-256\"``/``\"P-384\"``/``\"P-521\"`` (``None`` " +"selects P-256). OpenSSL key objects are not safe for concurrent use, so " +"``public_pem``/``seal``/``open`` are serialised by an internal lock." +msgstr "" + +#: 07643e7c481f49cba8b4ab33bd4174e0 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.public_pem:1 of +msgid "Export our public key as a PEM SubjectPublicKeyInfo string." +msgstr "" + +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:1 +#: ce09888aa11f4f01a8d4bdb80f94321f of +msgid "Encrypt ``plain`` to ``peer`` with an ECDH-derived AES-256-GCM key." +msgstr "" + +#: 965e41e97f5547c3a0bc77531ae3b3f9 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.seal:3 of +msgid "" +"Returns the wire blob, exactly ``PF_ECDH_SEAL_OVERHEAD`` bytes longer " +"than ``plain``. Raises ``CryptoOperationError``." +msgstr "" + +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:1 of +msgid "Inverse of :meth:`seal`, using ``peer``'s public key." +msgstr "" + +#: 4212d23f4b14479b971145af1bc12fa5 +#: PyFlow.network_api.rsa_crypto.EcdhKeyPair.open:3 of +msgid "" +"Raises ``CryptoOperationError`` with ``.code == PF_ERR_AUTH_FAILED`` when" +" the tag does not verify (tampered ciphertext, wrong peer key or " +"mismatched AAD)." +msgstr "" + +#: 7fec5dc58def4bbc886ca30568df0661 PyFlow.network_api.rsa_crypto.hkdf_sha256:1 +#: of +msgid "HKDF-SHA256 (RFC 5869 extract-and-expand) over ``ikm``." +msgstr "" + +#: 462a97910aff4e9aae066e31f55d5233 PyFlow.network_api.rsa_crypto.hkdf_sha256:3 +#: of +msgid "" +"``salt`` and ``info`` may be empty. ``out_len`` must be in " +"``1.._HKDF_SHA256_MAX_OUT``. Raises ``CryptoOperationError``." +msgstr "" + +#: 670f4a719bf24c24b48ecb5d73b373ce +#: PyFlow.network_api.rsa_crypto.get_local_mac:1 of msgid "Return a stable 48-bit machine identifier as colon-separated hex." msgstr "" -#: 311d6e5bcdba40d1b05fd63528abcf74 -#: PyFlow.network_api.rsa_crypto.get_local_mac:3 of +#: PyFlow.network_api.rsa_crypto.get_local_mac:3 +#: f1306bb875d34b558f7418278fded413 of msgid "" "Uses ``uuid.getnode()`` (the real hardware MAC when one is available). " "Server and client on the same host share this value; the ``_`` " "prefix in the key file names keeps them apart." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto:1 b385913eca73436ab76b76787114e163 +#: 333763d798c54d52a9a56a3e4e3e2155 PyFlow.network_api.rsa_crypto.RsaCrypto:1 #: of msgid "Key lifecycle plus RSA-OAEP encrypt/decrypt for one role." msgstr "" -#: 7c2b4fafe779449a8245780da7a4ef91 PyFlow.network_api.rsa_crypto.RsaCrypto:3 +#: PyFlow.network_api.rsa_crypto.RsaCrypto:3 f52515121ac74575aaa36d45dd0341a2 #: of msgid "" "``role`` is ``\"server\"`` or ``\"client\"`` and is used to name the " @@ -119,13 +211,13 @@ msgid "" " in ``pub_key/pub_key.json`` (TOFU, see ``verify_peer_pub``)." msgstr "" -#: 1e24448b89684701a1fa13b02e9d0d84 +#: 56fed5bcfe194b7f90a0c662ae36d6c0 #: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:1 of msgid "Create the crypto wrapper for ``role`` (\"server\" or \"client\")." msgstr "" -#: 00101f4b9ef44a83b2e51f9974a3d92a -#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.__init__:3 +#: ca4e27664ccf40ce935d991db43f7c69 of msgid "" "``custom_keys`` may be a ``[pub_key_path, pvt_key_path]`` pair to use a " "user-supplied RSA keypair instead of the default lookup (``~/.ssh`` / " @@ -134,78 +226,78 @@ msgid "" "used instead." msgstr "" -#: 4e9b33835a9448bca28d9e2e3a782d77 +#: 7d89122ff0f54090b67209e3b08ae29c #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:1 of msgid "Load the RSA keypair (see module docstring) and cache handles." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.ensure_keys:3 -#: e7fd217ab95d483084e4c7d58b715349 of +#: d5e494e00be44891b33cb8e0ecfb8081 of msgid "" "Runs under ``_key_lock``: the private-key handle must never be replaced " "(or freed on GC) while another thread is decrypting." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.reload_own_key:1 -#: c1e8b452b697431aaafee424e1edd3e2 of +#: f6f7d6ec8837464dad2dc647e6141a99 of msgid "Re-read the private key (e.g. after a ~/.ssh rotation)." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:1 -#: fabae86a23844d9cba130ff2f2adc080 of +#: e95d18da34d14376987a62f6cbbec778 of msgid "" "Path of the exchanged public key file for ``peer_role`` at ``(peer_ip, " "peer_port)``." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 -#: fa9eee0dbc724d0bbfa8e36bcdd89ba4 of +#: 52dc6fb74f0c4175bfa2a2acc23cda0d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.peer_pem_path:4 of msgid "" "The IP is sanitized for the filesystem (``:`` -> ``_`` so IPv6 literals " "are safe on every platform, including Windows)." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 -#: ce570f7fdb834fc3982aa0ec0e98b896 of +#: 731d92a1b64342dfbf7c467af0a4c00e +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:1 of msgid "TOFU check-and-record for a peer public key." msgstr "" -#: 2879d5b42eed4eaca2af859a86db52e8 +#: 634283c14fb44424bf148a34d156fb71 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:3 of msgid "" "``peer_pem`` is the PEM text received on this connection, ``(peer_ip, " "peer_port)`` the endpoint it came from. Returns ``(ok, reason)``:" msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 -#: b6f7afce352240b8ba2cf6a4e38aa457 of +#: 6bb58c88f8454d7daca92b5a478ae788 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:7 of msgid "" "key already registered under any endpoint -> accept, and re-register it " "under the current endpoint when it moved (IPs are dynamic and ports are " "user-changeable);" msgstr "" -#: 014d219898a04debb9eace0ea28aaa83 +#: 74e2bcc89bae4fe5aecf99e6208e21d1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:10 of msgid "" "key unknown but the endpoint already holds a *different* key -> reject (a" " trusted endpoint suddenly presenting a new key);" msgstr "" -#: 5aabe21775144f3fb2e5b4ae5a190569 -#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 of +#: PyFlow.network_api.rsa_crypto.RsaCrypto.verify_peer_pub:12 +#: f856b875adc34f4a80c2b21cd506b143 of msgid "" "key and endpoint both unknown -> accept and record (first connection is " "trusted, TOFU)." msgstr "" -#: 2bcc3b43a6d54e91b48a51fdf715a346 +#: 556fdf46d6c543e0ab06e2d4fabad7f1 #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:1 of msgid "Move a freshly received public key file into the key cache." msgstr "" #: PyFlow.network_api.rsa_crypto.RsaCrypto.store_peer_pem:3 -#: a32f32a711ec453684a2fa927aaaa06e of +#: a47e84f5d21949bf98e24834f18bed76 of msgid "" "Idempotent under concurrency: several transfers may deliver the same peer" " key at once (multi-connection handshakes, several client processes " @@ -214,13 +306,13 @@ msgid "" "destination is in place." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 -#: c54c296562484982abff2e1436305b98 of +#: 135944d28da54948862e515eb828072d +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:1 of msgid "Encrypt ``plaintext`` with the peer's public key file." msgstr "" -#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 -#: f7f5e3490fb44e85919611c0b3b9ecc7 of +#: 4b4dded0ad904ce2bb87c9a43c8f87e5 +#: PyFlow.network_api.rsa_crypto.RsaCrypto.encrypt_for_peer:3 of msgid "" "Returns the ASCII wire body (no trailing newline): each chunk is RSA-OAEP" " encrypted and base64 encoded, chunks joined with ``|``. Raises if no " @@ -229,12 +321,12 @@ msgid "" "encrypt (no-GIL safe)." msgstr "" -#: 8860142532044e87aa78adc123c33d62 +#: 8f1687f4ab984c029859fd1f9cfb968c #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:1 of msgid "Decrypt a wire body with our private key." msgstr "" -#: 888f7928d8274beda354f5b657613fec +#: 8a1d1504bf4248fa9e1288776d19810b #: PyFlow.network_api.rsa_crypto.RsaCrypto.decrypt_with_own:3 of msgid "" "Returns ``(True, plaintext)`` on success, or ``(False, None)`` when the " diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po index 09e6e0e..0e48182 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_client.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -17,30 +17,32 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_client.rst:2 -#: 8379b786205a4447995cf82b275ee87a +#: 09f60d1b11ac4e92b480fa6284489970 msgid "PyFlow.transfer\\_web.setup\\_client module" msgstr "" -#: 8412539bd9af49e8976ccf5c028061d4 PyFlow.transfer_web.setup_client:1 of +#: 2f786e174934474a93c6498878a68612 PyFlow.transfer_web.setup_client:1 of msgid "PyFlow TCP client web launcher." msgstr "" -#: PyFlow.transfer_web.setup_client:3 d2ed4df91a474301aee43eaf09e1ac87 of +#: 24fa9f33454d4afc9d15c80a0299922d PyFlow.transfer_web.setup_client:3 of msgid "" "Starts a lightweight Flask backend on 127.0.0.1 and opens the connect UI " "in the browser. The user enters the server address (an http/https domain" " or a bare IP); the backend asks the server's web backend for the TCP " "server address/port, starts the TCP client, and keeps the backend running" -" to relay the user's frontend actions. The account of the server logs in" -" from the same backend: saved credentials in " -"``.Flow_Web/client_login.json`` are replayed on every start, and the " -"login window appears whenever no session could be restored." +" to relay the user's frontend actions. A server that needs accounts (a " +"verification mailbox is configured) makes the same backend log in: saved " +"credentials in ``.Flow_Web/client_login.json`` are replayed on every " +"start, and the login window appears whenever no session could be " +"restored. A server without a mailbox needs no accounts, so the login " +"window and the account controls are skipped." msgstr "" -#: PyFlow.transfer_web.setup_client.main:1 fd5a9b075a2a4b9a97dbad26743e0403 of +#: PyFlow.transfer_web.setup_client.main:1 ca4ce7c686c84b44ae429e4de15b9afd of msgid "Start the client web backend and serve its UI." msgstr "" @@ -57,3 +59,21 @@ msgstr "" #~ " actions." #~ msgstr "" +#~ msgid "" +#~ "Starts a lightweight Flask backend on" +#~ " 127.0.0.1 and opens the connect UI" +#~ " in the browser. The user enters " +#~ "the server address (an http/https domain" +#~ " or a bare IP); the backend " +#~ "asks the server's web backend for " +#~ "the TCP server address/port, starts the" +#~ " TCP client, and keeps the backend" +#~ " running to relay the user's frontend" +#~ " actions. The account of the server" +#~ " logs in from the same backend: " +#~ "saved credentials in ``.Flow_Web/client_login.json``" +#~ " are replayed on every start, and " +#~ "the login window appears whenever no " +#~ "session could be restored." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po index c885004..3327803 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.setup_server.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -17,43 +17,45 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.setup_server.rst:2 -#: 88492dfde47b4dbb914aaba07f359440 +#: e6642bb55a204188b0abd0b07207713e msgid "PyFlow.transfer\\_web.setup\\_server module" msgstr "" -#: 103789700f8d41aa80e1cb374abb02a3 PyFlow.transfer_web.setup_server:1 of +#: 5966876a4564470ea674311ddb3ef63e PyFlow.transfer_web.setup_server:1 of msgid "PyFlow TCP server web launcher." msgstr "" -#: 581fc0a8029c44f7998895401060a79b PyFlow.transfer_web.setup_server:3 of +#: 588fea0dc68a4a308f9a7cfb6fe5d819 PyFlow.transfer_web.setup_server:3 of msgid "Checks ``transfer_web/.Flow_Web/setup_server.json``:" msgstr "" -#: 60412e56b0d44018bbc88cd258e2c48b PyFlow.transfer_web.setup_server:5 of +#: PyFlow.transfer_web.setup_server:5 c3df4df524da40b18a58607efd9b5e4a of msgid "" "missing -> opens the server startup-configuration UI in the browser; the" " UI saves the config (same shape as ``flow_setup``'s ``setup.json``) and " "starts the TCP server class;" msgstr "" -#: 15dae71f4c1243ecb188218cd72eb7c2 PyFlow.transfer_web.setup_server:8 of +#: 211850fce6d34d50ae152bce6d1aa3af PyFlow.transfer_web.setup_server:8 of msgid "present -> starts the TCP server class directly from the saved config." msgstr "" -#: 921ebc855440467cacd9d366085db41a PyFlow.transfer_web.setup_server:10 of +#: 7170b50dcaf2462f918af2271f247c84 PyFlow.transfer_web.setup_server:10 of msgid "" "After the TCP server is up, the lightweight Flask backend serves the " "status page and the client-facing API (``/api/server_info`` etc.) on the " -"server's address. Anonymous visitors also get the landing page with the " -"registration and password-reset flows; accounts live in the SQLite store " -"``.Flow_Web/flow_web.db``, and the verification mails are sent through " -"the mailbox configured in ``.Flow_Web/email_config.json``." +"server's address. Anonymous visitors also get the landing page; its " +"registration and password-reset flows exist while a verification mailbox " +"is configured (settings in ``.Flow_Web/email_config.json``, accounts in " +"the SQLite store ``.Flow_Web/flow_web.db``). That mailbox is also the " +"switch of the client side: with it clients log in with an account, " +"without it they connect without any account at all." msgstr "" -#: 2f09f9248b0e47e3ba9c9792d83a622b PyFlow.transfer_web.setup_server.main:1 of +#: PyFlow.transfer_web.setup_server.main:1 cbf05c29afe74ebd84b898146c971457 of msgid "Start the server web backend and serve its UI." msgstr "" @@ -65,3 +67,17 @@ msgstr "" #~ "server's address." #~ msgstr "" +#~ msgid "" +#~ "After the TCP server is up, the" +#~ " lightweight Flask backend serves the " +#~ "status page and the client-facing " +#~ "API (``/api/server_info`` etc.) on the " +#~ "server's address. Anonymous visitors also " +#~ "get the landing page with the " +#~ "registration and password-reset flows; " +#~ "accounts live in the SQLite store " +#~ "``.Flow_Web/flow_web.db``, and the verification " +#~ "mails are sent through the mailbox " +#~ "configured in ``.Flow_Web/email_config.json``." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po index ff5009c..9f65a88 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.mail_service.po @@ -8,47 +8,49 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst:2 -#: 86d4061dc1f542ac95555aa2deab1101 +#: ffcd351a76b74899a0105947d1049e12 msgid "PyFlow.transfer\\_web.web\\_backend.mail\\_service module" msgstr "" -#: 99f2cb604d5c450c9cda427b22b2c8cb -#: PyFlow.transfer_web.web_backend.mail_service:1 of +#: PyFlow.transfer_web.web_backend.mail_service:1 +#: c6f6b5571d954e7b986a3355033cd30c of msgid "SMTP delivery of account verification codes for the web tool." msgstr "" -#: 1d2a4d079f6c44f182332c5b44d0705a +#: 9764afd408ca43ce829f03d7d4ca675b #: PyFlow.transfer_web.web_backend.mail_service:3 of msgid "" "The administrator configures the outgoing mailbox from the server's " "startup-configuration page. The settings are validated with a real SMTP " "login and only then written to ``.Flow_Web/email_config.json``; while no " "validated configuration is present the service refuses to send, so a " -"server can never silently drop verification codes." +"server can never silently drop verification codes. The same page takes " +"the mailbox away again (`disable`), which switches the server back to " +"internal use." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 -#: e0597ff2442b43dd87c4efaef6c574c5 of +#: 5fdca457edd340eab7c9f05558a37dc5 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:1 of msgid "Validate untrusted SMTP settings and return them in canonical form." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 069dae5e8fb0426e897adc279499319b 4c58519a459f4b9486f0a571939d4834 -#: 83045ebe35d54d76b13e40961c070d4f eb5501cac4f240b19f2d4f5e5443e3c6 +#: 1cad23766791477aa6fb46051363ef81 73b1f3a5025140ec8701e976293f7af0 +#: 817b9cde77bb4327ad3b9f8356d27f4c a9b0b41ab3fd438c8cb2551b61e1af31 msgid "Parameters" msgstr "" -#: 14138866fd924a0083c8e6562b3860ff +#: 1b2b400edc914a76977297cb9ef6da5d #: PyFlow.transfer_web.web_backend.mail_service.normalize_config:3 of msgid "" "Settings with ``host``, ``port``, ``username``, ``password``, ``from`` " @@ -57,152 +59,183 @@ msgid "" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 170588e452e5431e815fad88a5b5537b 887b6607974c4ea8b99b628ea3efbf45 -#: a16996418f0e4e5ab58b7244ded5e63b c0463031a23c4f799b6a8217f31cc1b1 +#: 097b6a08fc5548d1a5a4568b07bf4326 1388175dc5e64a8eb1a99affd4807d9f +#: 334d15f3b1264e0b8abfc34e8fee985e 8f894b6967fd4867b82c726e85c83dc9 msgid "Returns" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 -#: dafcbdb3cccc40fa89a38363dd5680b0 of +#: 4695369c64494340bb98d06f4029f854 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:8 of msgid "" "The same settings with a string host, an integer port, a lowercase " "encryption mode and an explicit sender." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 -#: a68a2cdaeea44ccdb70c8e49efbcb5dd of +#: 5c191d5d632a4a71a814aa300592c904 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:10 of msgid "The same settings with a string host, an integer port, a lowercase" msgstr "" -#: 2bd9bb82ad2749df9c60df8271733a8c -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 of +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:11 +#: f98ed07dd1474127973e40ea5d133476 of msgid "encryption mode and an explicit sender." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 24fb33faf10542c7a1d5bcd8bc20e135 53904db2f0da42c6ac410c40a9e555a0 -#: 59876b786ae244308cb80d0e15975404 a636a96a44754c789c671d6e95914aea +#: 2ceb9aabd15149e2a74ab44ffc0e7e3b 4f9ea7be9a9d4179b3371b7ffaaf9c64 +#: 75ab32112eb54385b832e99cc66c0f3b 951ba3e6400f48c2baaffe4aceb25ae3 msgid "Return type" msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.mail_service.rst -#: 4375f894dabe4fd49e5d470f602e7e4e 669fcb172313407fa0df09ca10280e22 -#: 9ce7848878e44efba62bd42bd640bdeb +#: 051ee4ae623e4c52aca28e50c43a8659 6c5929a2e83444a0b5026560f2c5af02 +#: 7d5aee61dcaa450790fdaa12bda90f1c b717337ce24a4644a8684f6c14ced1d5 msgid "Raises" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 -#: f6db2cc04ccd4bc0a06c34c8d5d00b29 of +#: 8e1b87a14fc44d6383f43b22bdb71770 +#: PyFlow.transfer_web.web_backend.mail_service.normalize_config:14 of msgid "If a setting is missing, malformed or out of range." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 -#: a46df3ad1b4d47838e7d86646e5e45d4 of +#: 9104ff2767b4468db4119f0de6103975 +#: PyFlow.transfer_web.web_backend.mail_service.MailService:1 of msgid "SMTP client delivering verification codes." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService:3 -#: a6a714e990194ee9b2c023afa0423ec6 of +#: b29996ad41f1488f8540e22a48f131fa of msgid "" "The stored configuration is read on construction, so a validated mailbox " "is available again after a restart." msgstr "" -#: 906ef645c3f0431c8d4f44bb661e3119 +#: 67ba292bfc8c40ee863f2bf892ff74cb #: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:1 of msgid "Create the service and load the stored configuration." msgstr "" -#: 886b800f093c4d758d14028b4233d623 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.__init__:3 +#: f7b0ac874bc34b408853f868c5c1a9cd of msgid "" "JSON file holding the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 10490a10be734ca58da591842794088d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:1 +#: cdbf836d9e9c4e2a948458972edbfbae of msgid "Report whether a validated configuration lets codes be sent." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 -#: a19f7729857a4995be526dded313b07d of +#: 6f529ae442fb4a4ba2e0fd72533d0e29 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.is_enabled:3 of msgid "True when the SMTP settings were validated and stored." msgstr "" -#: 646e8fd83be4421ab0d3b4d38fe2b1c8 +#: 93c564a9ccd64ebca089cbd00f434f9e #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:1 of msgid "Return the validated SMTP settings." msgstr "" -#: 1728b9dc41484d35851721b141e661be +#: 83356ba5ccea4bceae862cc0934959cf #: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:3 of msgid "" "Copy of the stored settings, or ``None`` while the service is not " "configured." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 -#: cb61516a7cac473fa2ab322e29340899 of +#: 77ff24f402974e8681e2273634e17e4c +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:5 of msgid "Copy of the stored settings, or ``None`` while the" msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 -#: ba7116251d3b4ce7b97a3e79808c4415 of +#: 383ba8fc4ed940f38097d10bfbc8ff84 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.get_config:6 of msgid "service is not configured." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:1 -#: a2161943624d40a39a45564117df6d9e of +#: c7110be43ff548edb573b0b645e49ef5 of msgid "Validate SMTP settings, store them and start the sending service." msgstr "" -#: 8d8686cd5b9b46d295719719f9b29929 +#: 99385960778b4785bb73f4db98d2dada #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:3 of msgid "Settings accepted by `normalize_config`." msgstr "" -#: 5aa35eba13e04367b7f99d754176a39d -#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:6 +#: d801399842874f19943e8d2eb6dd6e6d of msgid "The validated settings as stored." msgstr "" #: PyFlow.transfer_web.web_backend.mail_service.MailService.configure:9 -#: ab75660bdd60437dbb05953445043ce0 of +#: c4c8574eb0634811a9fd71b2e00233a9 of msgid "" "If a setting is missing or malformed, or the server refuses the " "connection or the login." msgstr "" -#: 4ebf6576a62643d9910acdfba3fcd799 +#: 5c332d9d6242449f97b7bddbe36a20cd +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:1 of +msgid "Remove the stored mailbox so no verification code can be sent." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:3 +#: bc6f8bbf1f0047cebea68882e633945d of +msgid "" +"This is the switch back to internal mode: with no mailbox the server " +"serves its clients without accounts again." +msgstr "" + +#: PyFlow.transfer_web.web_backend.mail_service.MailService.disable:6 +#: f669f3bdc1f44730a90a6127ff7db331 of +msgid "" +"If the stored file cannot be removed; the service then keeps its " +"settings and stays enabled." +msgstr "" + +#: 7b942af00fc54d9d836170d61972977e #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:1 of msgid "Send one verification code by email." msgstr "" -#: 8f04bd37dc8b4483af595c5e66f8fbf4 +#: 6cdc276558b54671b93a8a839f34a682 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:3 of msgid "Recipient address." msgstr "" -#: 57f0544cdf234e00b9f03da47566354f +#: 60f83153ebac42eeb7ba36ed193d0eb1 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:5 of msgid "Verification code to deliver." msgstr "" -#: 627ee080c93e46679b0eb1dea17640f6 +#: 25f348d2347c4274a624e6d13eb6dfd3 #: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:7 of msgid "" "\"register\", \"login\" or \"reset_password\"; decides the wording of the" " message." msgstr "" -#: 6733b65d0a2347e1918c983503394f49 -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 of +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:10 +#: f16d610fc9f14559af45cddea444add9 of msgid "Code lifetime in seconds, stated in the message." msgstr "" -#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 -#: ce7cf70f7a2d4deca8256ada1fc9b63d of +#: 134b78c9128942938629dd61e9048916 +#: PyFlow.transfer_web.web_backend.mail_service.MailService.send_code:13 of msgid "If the service is not configured, or the message cannot be delivered." msgstr "" +#~ msgid "" +#~ "The administrator configures the outgoing " +#~ "mailbox from the server's startup-" +#~ "configuration page. The settings are " +#~ "validated with a real SMTP login " +#~ "and only then written to " +#~ "``.Flow_Web/email_config.json``; while no validated" +#~ " configuration is present the service " +#~ "refuses to send, so a server can" +#~ " never silently drop verification codes." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po index 38bcc07..113178b 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_backend.server_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -17,24 +17,24 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst:2 -#: 7bc35f7e619347e0b976ca49c973de8f +#: 4e16e69f9ae9491a95bfcab9c70cfe24 msgid "PyFlow.transfer\\_web.web\\_backend.server\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:1 -#: fd1d19a74e7a4e14a3863a4f2d4e6eef of +#: 15eb6d4006b3429a8fa230a2b460b1c5 +#: PyFlow.transfer_web.web_backend.server_backend:1 of msgid "Flask backend wrapping the PyFlow TCP server for the web tool." msgstr "" -#: 6fa9dfd64064447c82ade7290b523d5c +#: 3c413c9e37f94c7485dba6d4f96b9bf2 #: PyFlow.transfer_web.web_backend.server_backend:3 of msgid "Two modes, one process:" msgstr "" -#: 8e61412bb72d49b086f03a2245cd959d +#: 557b793ac8e441db86cf59cad5e85371 #: PyFlow.transfer_web.web_backend.server_backend:5 of msgid "" "``config`` mode: serves the server startup-configuration UI. The UI " @@ -45,7 +45,7 @@ msgid "" msgstr "" #: PyFlow.transfer_web.web_backend.server_backend:10 -#: b15a182866794bf7bfe71605fc47a301 of +#: cb922669795b42c6ad5587b527c4356a of msgid "" "``status`` mode: serves the minimal status page plus the same " "sidebar/input UI as the client frontend (forwarding disabled; native " @@ -53,93 +53,105 @@ msgid "" "clients use to discover the TCP server address/port." msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend:15 -#: a297544539714d03afa00d1112541712 of +#: 0c6784517a194d65926c71b7ce7f4836 +#: PyFlow.transfer_web.web_backend.server_backend:15 of msgid "" "The backend monitors ``server.clients``: whenever a client connects or " "disconnects it broadcasts the current instance list to every connected " "client (``/web_clients_update``), and it re-checks the list every minute." msgstr "" -#: 9ad7bd78687141a8a282a951ddc57689 +#: 535e49236690482ebf574e6c65b10f39 #: PyFlow.transfer_web.web_backend.server_backend:20 of msgid "" "Inbound events (plain-text messages and file uploads arriving from " "clients) are captured on the TCP server's receive threads through " "``TCP_Server_Base``'s ``add_message_listener``/``add_file_listener`` " -"APIs, queued here, and polled by the frontend via ``/api/events``." +"APIs, queued here, and polled by the frontend via ``/api/events``. The " +"message listener reports every inbound line, protocol commands included; " +"the commands are dropped here, so the queue carries user messages only. A" +" file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 69da06074d1141308bd12409e851f506 -#: PyFlow.transfer_web.web_backend.server_backend:25 of +#: 6ee75a9919554a3cb05d55c0f9dba653 +#: PyFlow.transfer_web.web_backend.server_backend:30 of msgid "" "Authentication: anonymous visitors get a white landing page (the server " -"addresses, a login button, a registration button and a password-reset " -"button); the configuration and status pages need a session. Accounts " -"live in the SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`);" -" the first run seeds the ``admin``/``admin`` administrator and the " -"frontend warns on every login until those default credentials are " -"changed. Registration, password reset and code-based client logins are " -"delivered by the mailbox configured from the startup-configuration page " -"(see `mail_service`)." -msgstr "" - -#: 1fb7feafe6ba447e992cd3ebd42801c8 -#: PyFlow.transfer_web.web_backend.server_backend:34 of +"addresses and a login button; while a verification mailbox is configured," +" also a registration button and a password-reset button); the " +"configuration and status pages need a session. Accounts live in the " +"SQLite store ``.Flow_Web/flow_web.db`` (see `user_database`); the first " +"run seeds the ``admin``/``admin`` administrator and the frontend warns on" +" every login until those default credentials are changed. Registration, " +"password reset and code-based client logins are delivered by the mailbox " +"configured from the startup-configuration page (see `mail_service`)." +msgstr "" + +#: 14b91efc5192438eb9eb025aa4a50ef2 +#: PyFlow.transfer_web.web_backend.server_backend:40 of msgid "" -"Client accounts: the client web frontend logs in through " -"``/api/client_login`` with a username/email, the account password *and* a" -" mailed verification code — both factors are required — and receives a " -"session token. Re-entering the client web UI replays the saved " -"credentials and token through ``/api/client_verify``, which only accepts " -"them while they still open that account. The token binds the TCP " -"connection the client opens (``/web_bind``) to that account, and the " +"Client accounts: the verification mailbox is the switch of the whole " +"client side. While ``.Flow_Web/email_config.json`` holds a validated " +"mailbox the server is meant for public networks: the client web frontend " +"logs in through ``/api/client_login`` with a username/email, the account " +"password *and* a mailed verification code — both factors are required — " +"and receives a session token. Re-entering the client web UI replays the " +"saved credentials and token through ``/api/client_verify``, which only " +"accepts them while they still open that account. The token binds the TCP" +" connection the client opens (``/web_bind``) to that account, and the " "instance list pushed to a client is limited to its contacts, so accounts " -"that never exchanged a contact request cannot see each other." +"that never exchanged a contact request cannot see each other. Without a " +"mailbox the server is an internal tool: clients connect without " +"registration or login, every client sees every other connected instance, " +"and the client account routes are closed — only the console administrator" +" keeps an account." msgstr "" -#: 123122acd40847679e349c6e3b8d9c5e -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 of +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp:1 +#: ab4c37912c524489a26700248a06704c of msgid "Flask app + TCP_Server_Base wrapper for the web tool." msgstr "" #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:1 -#: b7ccb1c765d744b988819d0afbbab22d of +#: fb6d7d555b47497fa6861b7f8a6a5f5d of msgid "Create the Flask app and its stores." msgstr "" #: ../../source/api/PyFlow.transfer_web.web_backend.server_backend.rst -#: b841315945d14f34a8ef0541284d23e3 +#: 0fb91f29d163495c8c5e4b758c29cf92 msgid "Parameters" msgstr "" -#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 -#: c8c0a79297824242960049876ebd3e56 of +#: 79acd75ba91d4388972788215a4dcde7 +#: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:3 of msgid "" "Port of this web backend; defaults to ``DEFAULT_WEB_PORT``. A busy port " "falls back to the next free one." msgstr "" -#: 652d75ee0a3d4dd18396a8e2b5aa315e +#: 7dd94be740ee476ea378e766ecf5640b #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:6 of msgid "SQLite account database; defaults to ``.Flow_Web/flow_web.db``." msgstr "" -#: 34f17ede4f7c4556a62f8cc47f3c399d +#: 1db79ba202e74aeebefe1de0df4f3f3f #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.__init__:9 of msgid "" "JSON file with the SMTP settings; defaults to " "``.Flow_Web/email_config.json``." msgstr "" -#: 011de011008f44dc9c247510315a2341 +#: 7e707a76895243cbb7e49d4a943df5f2 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:1 #: of msgid "Read ``.Flow_Web/setup_server.json`` and start the TCP server." msgstr "" +#: 7a3de044fc304747a1be4161fe0f2e51 #: PyFlow.transfer_web.web_backend.server_backend.ServerWebApp.start_from_config:3 -#: baae3df9217643d0a41c83324c8f035d of +#: of msgid "" "The saved \"ftp\" share is restored as well, so a folder shared before " "the restart keeps being served." @@ -180,3 +192,52 @@ msgstr "" #~ msgid "Rename ``username`` and set its password (self-service)." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " file uploads arriving from clients) " +#~ "are captured on the TCP server's " +#~ "receive threads through ``TCP_Server_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Authentication: anonymous visitors get a " +#~ "white landing page (the server " +#~ "addresses, a login button, a " +#~ "registration button and a password-reset" +#~ " button); the configuration and status " +#~ "pages need a session. Accounts live " +#~ "in the SQLite store ``.Flow_Web/flow_web.db``" +#~ " (see `user_database`); the first run " +#~ "seeds the ``admin``/``admin`` administrator " +#~ "and the frontend warns on every " +#~ "login until those default credentials " +#~ "are changed. Registration, password reset " +#~ "and code-based client logins are " +#~ "delivered by the mailbox configured from" +#~ " the startup-configuration page (see " +#~ "`mail_service`)." +#~ msgstr "" + +#~ msgid "" +#~ "Client accounts: the client web frontend" +#~ " logs in through ``/api/client_login`` with" +#~ " a username/email, the account password " +#~ "*and* a mailed verification code — " +#~ "both factors are required — and " +#~ "receives a session token. Re-entering" +#~ " the client web UI replays the " +#~ "saved credentials and token through " +#~ "``/api/client_verify``, which only accepts " +#~ "them while they still open that " +#~ "account. The token binds the TCP " +#~ "connection the client opens (``/web_bind``)" +#~ " to that account, and the instance" +#~ " list pushed to a client is " +#~ "limited to its contacts, so accounts " +#~ "that never exchanged a contact request" +#~ " cannot see each other." +#~ msgstr "" + diff --git a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po index 7323a26..8d732fa 100644 --- a/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po +++ b/docs/source/locale/zh_TW/LC_MESSAGES/api/PyFlow.transfer_web.web_front.client_backend.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PyFlow \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-09-26 22:43+0800\n" +"POT-Creation-Date: 2026-10-20 09:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: zh_TW\n" @@ -17,19 +17,19 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.10.3\n" +"Generated-By: Babel 2.18.0\n" #: ../../source/api/PyFlow.transfer_web.web_front.client_backend.rst:2 -#: 411a61682c95447192de34eca6a7b40c +#: a7e084a5059341aa9b7419059c4fa4b0 msgid "PyFlow.transfer\\_web.web\\_front.client\\_backend module" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:1 -#: c5b03318abd74b32b6ffba1696f8b20b of +#: 22485674cb53445a86703fb118698523 +#: PyFlow.transfer_web.web_front.client_backend:1 of msgid "Flask backend wrapping the PyFlow TCP client for the web tool." msgstr "" -#: 13a2da9087074258858c4dd7a697671e +#: 31862d77d7184e55a1e729d7e72baed0 #: PyFlow.transfer_web.web_front.client_backend:3 of msgid "" "The launcher (``setup_client.py``) starts this backend and opens the " @@ -40,70 +40,123 @@ msgid "" "relay the user's frontend actions:" msgstr "" -#: 95d3503d45ac47ba8c8a9522aceb4764 +#: 1a028258cda844ee945b9522d51afb9d #: PyFlow.transfer_web.web_front.client_backend:10 of msgid "messages/files/folders to the server use the native transfer methods;" msgstr "" #: PyFlow.transfer_web.web_front.client_backend:11 -#: be1496ab996044798cfc05692616cd8a of +#: e160c2a0daf9498cbe2041a8e964ff47 of msgid "" "messages to other clients use the native ``/forward_send_msg`` forwarding" " (a client-only command relayed by the server);" msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:13 -#: a59ab775ca734b828f09313089028a9f of +#: 16da18234f0a499893b711e7b555b42a +#: PyFlow.transfer_web.web_front.client_backend:13 of msgid "" "files/folders to other clients are forwarded through the built-in " "``forward_extension_tcp`` extension." msgstr "" -#: PyFlow.transfer_web.web_front.client_backend:16 -#: ea807a0c324b430c8731aa632d099643 of +#: 79dee862a03f4d0c9bc9403f8d461465 +#: PyFlow.transfer_web.web_front.client_backend:16 of msgid "" "The sidebar instance list is kept fresh by the server's " "``/web_clients_update`` broadcasts; a reload button re-requests the list " "via ``/web_sync_clients``." msgstr "" -#: 3656f3e4bded46b596db7d1bdc666b90 +#: 13d20ecd894c4e26a28266b7ac128dfd #: PyFlow.transfer_web.web_front.client_backend:20 of msgid "" "Inbound events (plain-text messages and files pushed by the server, " "whether direct sends or client forwards) are captured on the TCP client's" " receive threads through ``TCP_Client_Base``'s " "``add_message_listener``/``add_file_listener`` APIs, queued here, and " -"polled by the frontend via ``/api/events``." +"polled by the frontend via ``/api/events``. The message listener reports" +" every inbound line, protocol commands included; a direct command from " +"the server is dropped here, so the queue carries user messages only. A " +"file event carries the token of the saved file as well, so the chat can " +"link the name to ``/api/open_location``: the route hands the path " +"recorded for that token to the file manager of this host." msgstr "" -#: 565c32267ec64ccbb0904ef2ec5609df -#: PyFlow.transfer_web.web_front.client_backend:26 of +#: 5c1c2971ea0e45d8a56544972cdc4ff4 +#: PyFlow.transfer_web.web_front.client_backend:31 of msgid "" -"Accounts: a connected client logs in with a server account before the " -"instance list is usable. A forced login needs both factors — the account" -" password and a verification code mailed to the account address — while a" -" client that starts again replays the saved credentials and session token" -" through ``/api/client_verify``. ``/api/login`` opens the session, the " +"Accounts: the connected server decides whether its clients need accounts." +" A server with a verification mailbox is public, so this backend forces " +"the account login before the instance list is usable; a server without " +"one is internal and everything account-related is skipped — no login " +"window, no contacts, and every client sees every other instance. A " +"forced login needs both factors — the account password and a verification" +" code mailed to the account address — while a client that starts again " +"replays the saved credentials and session token through " +"``/api/client_verify``. ``/api/login`` opens the session, the " "``/api/contacts/*`` and ``/api/contact_requests`` routes proxy the " "contact management to the server, and the session token is sent over TCP " "with ``/web_bind`` so the server can push the contact list of that " "account. The credentials are remembered in " -"``.Flow_Web/client_login.json`` (owner-readable only) and the login " -"window is shown whenever no session could be restored." +"``.Flow_Web/client_login.json`` (owner-readable only)." msgstr "" -#: 1e6c10d599f046398e16a7b47e0b8dab +#: 0913e15917534119b775fb5c545c439d #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp:1 of msgid "Flask app + TCP_Client_Base wrapper for the web tool." msgstr "" -#: 6c87b744956640d682bef32158496990 #: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:1 +#: bc85ca281f4e4df5a0f10290029fca34 of +msgid "Start the TCP client from ``.Flow_Web/setup_client.json``." +msgstr "" + +#: 612871943a7e45a2bacdc377aec78b77 +#: PyFlow.transfer_web.web_front.client_backend.ClientWebApp.start_from_config:3 #: of -msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +msgid "" +"The connected server reports whether its clients log in; only then is a " +"saved session replayed, and the login window is only shown then." msgstr "" #~ msgid "Read ``.Flow_Web/setup_client.json`` and start the TCP client." #~ msgstr "" +#~ msgid "" +#~ "Inbound events (plain-text messages and" +#~ " files pushed by the server, whether" +#~ " direct sends or client forwards) are" +#~ " captured on the TCP client's receive" +#~ " threads through ``TCP_Client_Base``'s " +#~ "``add_message_listener``/``add_file_listener`` APIs, " +#~ "queued here, and polled by the " +#~ "frontend via ``/api/events``." +#~ msgstr "" + +#~ msgid "" +#~ "Accounts: a connected client logs in " +#~ "with a server account before the " +#~ "instance list is usable. A forced " +#~ "login needs both factors — the " +#~ "account password and a verification code" +#~ " mailed to the account address — " +#~ "while a client that starts again " +#~ "replays the saved credentials and " +#~ "session token through ``/api/client_verify``. " +#~ "``/api/login`` opens the session, the " +#~ "``/api/contacts/*`` and ``/api/contact_requests`` " +#~ "routes proxy the contact management to" +#~ " the server, and the session token" +#~ " is sent over TCP with ``/web_bind``" +#~ " so the server can push the " +#~ "contact list of that account. The " +#~ "credentials are remembered in " +#~ "``.Flow_Web/client_login.json`` (owner-readable " +#~ "only) and the login window is " +#~ "shown whenever no session could be " +#~ "restored." +#~ msgstr "" + +#~ msgid "Start the TCP client from ``.Flow_Web/setup_client.json`` and log in." +#~ msgstr "" + From eb0adadbaae5dc75689eb53d6f036e4f2e846e6d Mon Sep 17 00:00:00 2001 From: F18-Ray Date: Thu, 22 Oct 2026 09:14:01 +0800 Subject: [PATCH 5/5] Docs: fix the docstring in the connect_tcp protocal including the internal APIs --- PyFlow/network_api/connect_tcp.py | 2179 ++++++++++++++++++++++------- 1 file changed, 1680 insertions(+), 499 deletions(-) diff --git a/PyFlow/network_api/connect_tcp.py b/PyFlow/network_api/connect_tcp.py index cc2f171..2aaf5a0 100644 --- a/PyFlow/network_api/connect_tcp.py +++ b/PyFlow/network_api/connect_tcp.py @@ -59,13 +59,11 @@ def _process_is_alive(pid): """Report whether the process recorded in a port-range entry still runs. Args: - pid (int | None): Process id from the record; ``None`` (a record written - before pids were stored) counts as alive so it is never dropped just - for lacking one. + pid (int | None): Process id from the record; ``None`` (a record written before pids were stored) counts as alive so it is never dropped just for lacking one. Returns: - bool: True when the process exists, or when that cannot be determined - (keeping an entry is harmless, dropping a live one is not). + bool: True when the process exists, or when that cannot be determined + (keeping an entry is harmless, dropping a live one is not). """ if not isinstance(pid, int) or pid <= 0: return True @@ -103,7 +101,7 @@ def _port_record_stale(entry): entry (dict): One record entry (``server_port_info`` / ``client_port_info``). Returns: - bool: True when the entry can be reclaimed. + bool: True when the entry can be reclaimed. """ pid = entry.get("pid") if pid is None: # pre-pid record: keep the older rule @@ -112,12 +110,22 @@ def _port_record_stale(entry): def _is_closed_socket_error(exc): - """True when the error means a socket that is already closed + """Return true when the error means a socket that is already closed. + + True when the error means a socket that is already closed + (EBADF / ENOTSOCK, Windows winsock WSAENOTSOCK 10038, ECONNRESET / - EPIPE from a peer that dropped the connection, or the "connection - error" RuntimeError raised by send_message after the instance - stopped): the normal teardown signal between a closing thread and a - receive thread, not a fault worth a traceback.""" + EPIPE from a peer that dropped the connection, or the "connection + error" RuntimeError raised by send_message after the instance + stopped): the normal teardown signal between a closing thread and a + receive thread, not a fault worth a traceback. + + Args: + exc (object): Value used by the operation. + + Returns: + bool | object: Result produced by the operation. + """ if isinstance(exc, RuntimeError) and str(exc) == "connection error": return True return isinstance(exc, OSError) and exc.errno in ( @@ -155,8 +163,8 @@ def _wait_writable(client_socket, timeout): timeout (float): Maximum seconds to wait. Must be > 0. Raises: - TimeoutError: If the socket stays unwritable for ``timeout`` seconds. - OSError: If the socket is closed or cannot be polled. + TimeoutError: If the socket stays unwritable for ``timeout`` seconds. + OSError: If the socket is closed or cannot be polled. """ with selectors.DefaultSelector() as selector: selector.register(client_socket, selectors.EVENT_WRITE) @@ -172,8 +180,14 @@ def _log_merge_lock(path): """Return this process's lock for the log at ``path``. Shared by every merge of that file in this process (see - `_publish_json_log`), so threads of one program never interleave their - read-merge-publish. + `_publish_json_log`), so threads of one program never interleave their + read-merge-publish. + + Args: + path (str): Value used by the operation. + + Returns: + object: Result produced by the operation. """ with _LOG_MERGE_LOCKS_LOCK: return _LOG_MERGE_LOCKS.setdefault(os.path.abspath(path), threading.RLock()) @@ -183,8 +197,14 @@ def _log_content(path): """Read the exact bytes of the log at ``path``, or None when it is absent. `_publish_json_log` compares the content it read against this before it - replaces the file: any publish by another process changes the bytes (an - entry is always added), so a match means nothing was published in between. + replaces the file: any publish by another process changes the bytes (an + entry is always added), so a match means nothing was published in between. + + Args: + path (str): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ try: with open(path, "rb") as f: @@ -197,10 +217,16 @@ def _read_json_log(path): """Parse the JSON log at ``path``: ``(data, content)``. ``({}, None)`` while the file does not exist. A log that is empty (a - publish cut short) or carries a trailing fragment (a crash, or a publish - by the versions that shared one ``.tmp`` path) is read up to its first - document: what is left is dropped, and the next publish rewrites the file - without it, so a broken log cannot poison every later flush. + publish cut short) or carries a trailing fragment (a crash, or a publish + by the versions that shared one ``.tmp`` path) is read up to its first + document: what is left is dropped, and the next publish rewrites the file + without it, so a broken log cannot poison every later flush. + + Args: + path (str): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. """ content = _log_content(path) if content is None: @@ -219,21 +245,21 @@ def _publish_json_log(path, snapshot, record_key): """Merge one snapshot into the JSON log at ``path``. The file is read, merged and published back atomically (``os.replace``), - so a reader never sees a truncated or partial log. - - Two writers must not lose each other's entries, which is what one shared - ``.tmp`` used to produce: one of them renamed a half-written file - into place, the log no longer parsed (``Extra data``) and every later - flush was dropped. Hence, per writer: - - * the temp file carries this writer's pid and thread id, so two writers - can never truncate or rename each other's file into place; - * ``_log_merge_lock`` serialises the merges of this process — several - instances in one program (or one test session) sharing a log lose - nothing; - * a merge whose file changed under it — another *process* published since - this writer read it — is redone from the new content instead of - clobbering that process's entries. + so a reader never sees a truncated or partial log. + + Two writers must not lose each other's entries, which is what one shared + ``.tmp`` used to produce: one of them renamed a half-written file + into place, the log no longer parsed (``Extra data``) and every later + flush was dropped. Hence, per writer: + + * the temp file carries this writer's pid and thread id, so two writers + can never truncate or rename each other's file into place; + * ``_log_merge_lock`` serialises the merges of this process — several + instances in one program (or one test session) sharing a log lose + nothing; + * a merge whose file changed under it — another *process* published since + this writer read it — is redone from the new content instead of + clobbering that process's entries. Args: path (str): JSON log file to merge into. @@ -241,7 +267,7 @@ def _publish_json_log(path, snapshot, record_key): record_key (callable): Maps one socket to its key in the log. Raises: - RuntimeError: When every attempt lost the race to another writer. + RuntimeError: When every attempt lost the race to another writer. """ with _log_merge_lock(path): for _ in range(LOG_MERGE_ATTEMPTS): @@ -266,34 +292,52 @@ def _publish_json_log(path, snapshot, record_key): def _log_line(enabled, parts): - """Print one command/result line when ``is_print_log`` allows it.""" + """Print one command/result line when ``is_print_log`` allows it. + + Args: + enabled (bool): Value used by the operation. + parts (list | dict): Value used by the operation. + """ if enabled: print(*parts) def _debug_line(enabled, is_debug, parts): - """Print one execution-process line; needs ``is_print_log`` and ``is_debug``.""" + """Print one execution-process line; needs ``is_print_log`` and ``is_debug``. + + Args: + enabled (bool): Value used by the operation. + is_debug (bool): Value used by the operation. + parts (list | dict): Value used by the operation. + """ if enabled and is_debug: print(*parts) def _parse_destination_path(command_part): """Extract the trailing destination directory from a received transfer + command, or None when the command carries no destination. - ```` is the file-client id appended by the sender; ```` is a - quoted client address tuple. The destination (when present) is the token - before ````, except for folder-creation commands, which carry no id - and put the destination last: - - /file - /file - /file - /file - /file_folder folder creation, default location - /file_folder folder creation with destination - /file_folder - /file_folder + ```` is the file-client id appended by the sender; ```` is a + quoted client address tuple. The destination (when present) is the token + before ````, except for folder-creation commands, which carry no id + and put the destination last: + + /file + /file + /file + /file + /file_folder folder creation, default location + /file_folder folder creation with destination + /file_folder + /file_folder + + Args: + command_part (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ if len(command_part) < 3: return None @@ -313,10 +357,16 @@ def _transfer_fid(command_part): """Return the fid a sender stamped on its transfer command, or None. Every user transfer command ends with the sender's transfer id - (``/file ``, ``/file_folder [] ``); it - keys that leg in ``file_recv_progress``/``file_upload_progress``. The - protocol-internal ``/crypto_pub_key`` push reports None: it is no user - file transfer. + (``/file ``, ``/file_folder [] ``); it + keys that leg in ``file_recv_progress``/``file_upload_progress``. The + protocol-internal ``/crypto_pub_key`` push reports None: it is no user + file transfer. + + Args: + command_part (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ if command_part and command_part[0] == "/crypto_pub_key": return None @@ -329,8 +379,11 @@ def _transfer_fid(command_part): def _peer_from_text(text): """Parse an ``"ip:port"`` peer string into an ``(ip, port)`` tuple. + Args: + text (object): Value used by the operation. + Returns: - tuple | None: The peer tuple, or None when the text carries none. + tuple | None: The peer tuple, or None when the text carries none. """ if not text: return None @@ -346,8 +399,11 @@ def _peer_from_text(text): def _peer_from_json(value): """Parse a persisted ``[ip, port]`` peer into an ``(ip, port)`` tuple. + Args: + value (object): Value used by the operation. + Returns: - tuple | None: The peer tuple, or None when the value is not a peer. + tuple | None: The peer tuple, or None when the value is not a peer. """ if isinstance(value, (list, tuple)) and len(value) == 2: try: @@ -361,14 +417,14 @@ def _resume_offset_for(entry): """Bytes of an interrupted transfer's file already on the receiver's disk. The length of the partial file is what the sender is asked to continue - from, so a missing (or unreadable) partial file restarts the transfer from - its first byte. + from, so a missing (or unreadable) partial file restarts the transfer from + its first byte. Args: entry (list): Progress entry ``[received, total, speed, path, peer]``. Returns: - int: Byte offset to continue from. + int: Byte offset to continue from. """ try: size = os.path.getsize(entry[3]) @@ -383,8 +439,13 @@ def _resume_offset_for(entry): def parse_resume_command(command): """Split a ``/resume_trans `` line. - Returns: - tuple | None: ``(fid, offset)``, or None when the line is malformed. + Args: + command (str): Wire line in ``/resume_trans `` format; + ``fid`` and ``offset`` must be integers. + + Returns: + tuple | None: ``(fid, offset)``, or None when the line is malformed. + """ try: parts = shlex.split(command) @@ -399,7 +460,14 @@ def parse_resume_command(command): def _pause_command_fid(command): - """Return the fid of a ``/pause_trans``/``/start_trans`` line, or None.""" + """Return the fid of a ``/pause_trans``/``/start_trans`` line, or None. + + Args: + command (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ try: return int(shlex.split(command)[1]) except (IndexError, ValueError): @@ -410,16 +478,16 @@ def _open_transfer_target(path, offset): """Open a transfer's destination file, ready to write from ``offset``. A resumed transfer continues a partial file: the file is opened for - update and positioned at the byte the sender continues from, so a late or - duplicated chunk overwrites its own place instead of corrupting the - stream. A fresh transfer (offset 0) truncates the file. + update and positioned at the byte the sender continues from, so a late or + duplicated chunk overwrites its own place instead of corrupting the + stream. A fresh transfer (offset 0) truncates the file. Args: path (str): Destination path of the transfer. offset (int): Byte offset the incoming stream starts at. Returns: - file: Open binary file positioned at ``offset``. + file: Open binary file positioned at ``offset``. """ if offset <= 0: return open(path, "wb") @@ -432,9 +500,15 @@ def _open_transfer_target(path, offset): def parse_forward_resume_command(command): """Split a ``/forward_resume `` line. - Returns: - tuple | None: ``(target, fid, offset)``, or None when the line is - malformed. + Args: + command (str): Wire line with a two-item tuple address, transfer ID, + and byte offset; the address host must be a string and both values + must be integers. + + Returns: + tuple | None: ``(target, fid, offset)``, or None when the line is + malformed. + """ try: parts = shlex.split(command) @@ -632,7 +706,14 @@ class _FrameError(Exception): def _pem_body_of(pem): - """Return the one-line base64 body of a PEM text (armor lines dropped).""" + """Return the one-line base64 body of a PEM text (armor lines dropped). + + Args: + pem (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ body = "".join( line.strip() for line in pem.splitlines() if line and not line.startswith("-----") ) @@ -640,7 +721,14 @@ def _pem_body_of(pem): def _pem_text_of(body): - """Rebuild a standard PEM text from its one-line base64 body.""" + """Rebuild a standard PEM text from its one-line base64 body. + + Args: + body (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ lines = [body[i : i + 64] for i in range(0, len(body), 64)] return "-----BEGIN PUBLIC KEY-----\n" + "\n".join(lines) + "\n-----END PUBLIC KEY-----\n" @@ -650,7 +738,14 @@ class _CryptoUnavailable(Exception): def _stamp_nonce(stamp): - """Parse a transfer mode stamp ("plain" / "enc:") -> nonce or None.""" + """Parse a transfer mode stamp ("plain" / "enc:") -> nonce or None. + + Args: + stamp (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ if stamp and stamp.startswith("enc:"): nonce = stamp[4:].strip() return nonce or None @@ -658,10 +753,19 @@ def _stamp_nonce(stamp): def _crypto_is_protocol_line(message): - """True for the protocol's own handshake/coordination lines. + """Return true for the protocol's own handshake/coordination lines. + + True for the protocol's own handshake/coordination lines. These must not reset the decode-failure streak: a re-exchange (and the - transfer-port coordination it needs) is not genuine peer traffic.""" + transfer-port coordination it needs) is not genuine peer traffic. + + Args: + message (object): Value used by the operation. + + Returns: + bool | object: Result produced by the operation. + """ if message.startswith("/crypto"): return True return message.startswith(("/server_file_transfer_port", "/forward_upload")) @@ -688,6 +792,11 @@ def __init__(self, rsa_crypto_obj, role, log=None, debug=None): self.peer_ecdh_event = threading.Event() def ensure_ecdh(self): + """Handle the operation. + + Returns: + object: Result produced by the operation. + """ with self.lock: if self.ecdh is None: self.ecdh = rsa_crypto.EcdhKeyPair() @@ -702,6 +811,14 @@ def reset_ecdh(self): self.peer_ecdh_event.clear() def set_peer_ecdh_b64(self, body): + """Handle the operation. + + Args: + body (object): Value used by the operation. + + Returns: + bool: Result produced by the operation. + """ try: peer = rsa_crypto.EcdhPubKey.from_pem(_pem_text_of(body.strip())) except Exception: @@ -713,14 +830,27 @@ def set_peer_ecdh_b64(self, body): return True def peer_ecdh_pub(self, timeout=0): - """The peer's ECDH public key, or None (waits up to ``timeout``).""" + """Return the peer's ECDH public key, or None (waits up to ``timeout``). + + The peer's ECDH public key, or None (waits up to ``timeout``). + + Args: + timeout (float): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ if not self.peer_ecdh_event.wait(timeout=max(0.0, timeout)): return None with self.lock: return self.peer_ecdh def publish_pub(self, channel): - """Send our session ECDH public key once frames are allowed both ways.""" + """Send our session ECDH public key once frames are allowed both ways. + + Args: + channel (object): Value used by the operation. + """ if channel is None or not channel.claim_ecdh_pub_send(): return try: @@ -734,8 +864,15 @@ def transfer_stamp(self, channel, force_plain=False): """Mode+nonce announced to a transfer connector ("plain"/"enc:"). Encrypted only when this side's channel flipped and both sides hold - the session ECDH material; key pushes force plaintext because they - carry the public keys themselves. + the session ECDH material; key pushes force plaintext because they + carry the public keys themselves. + + Args: + channel (object): Value used by the operation. + force_plain (bool): Value used by the operation. + + Returns: + object | str: Result produced by the operation. """ if force_plain or self.rsa is None or channel is None or not channel.secure: return "plain" @@ -750,8 +887,19 @@ def attach_transfer(self, sock, control_channel, stamp): """Channel for a stamped transfer leg, or None when it stays plaintext. Raises `_CryptoUnavailable` when the stamp says encrypted but the - session key material is not ready: the caller aborts the transfer - instead of silently downgrading it. + session key material is not ready: the caller aborts the transfer + instead of silently downgrading it. + + Args: + sock (object): Value used by the operation. + control_channel (object): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + + Raises: + _CryptoUnavailable: When the operation cannot complete. """ nonce = _stamp_nonce(stamp) if nonce is None: @@ -770,11 +918,24 @@ def attach_transfer(self, sock, control_channel, stamp): def _connector_transfer_crypto(session, control_channel, stamp): - """(session, peer_pem_path, nonce) for a connector-side transfer leg. + """Return (session, peer_pem_path, nonce) for a connector-side transfer leg. + + (session, peer_pem_path, nonce) for a connector-side transfer leg. Returns None for a plaintext leg; raises `_CryptoUnavailable` when the - stamp promises encryption but the session key material is missing, so the - caller aborts the transfer instead of downgrading it silently. + stamp promises encryption but the session key material is missing, so the + caller aborts the transfer instead of downgrading it silently. + + Args: + session (object): Value used by the operation. + control_channel (object): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + NoneType | list | tuple: Result produced by the operation. + + Raises: + _CryptoUnavailable: When the operation cannot complete. """ nonce = _stamp_nonce(stamp) if nonce is None: @@ -789,7 +950,15 @@ def _connector_transfer_crypto(session, control_channel, stamp): def _enable_connector_channel(sock, crypto): - """Framing channel for a freshly connected transfer socket, or None.""" + """Framing channel for a freshly connected transfer socket, or None. + + Args: + sock (object): Value used by the operation. + crypto (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ if crypto is None: return None session, peer_pem_path, nonce = crypto @@ -808,8 +977,14 @@ def _magic_tail_len(buf): """Length of the proper ``FRAME_MAGIC`` prefix ``buf`` ends with (0..2). A magic split across reads is held, never served as plaintext: the bytes - behind it belong to a frame, and frame bytes are not line traffic (see - `_SecureChannel.feed`). + behind it belong to a frame, and frame bytes are not line traffic (see + `_SecureChannel.feed`). + + Args: + buf (object): Value used by the operation. + + Returns: + int | object: Result produced by the operation. """ for length in range(len(FRAME_MAGIC) - 1, 0, -1): if buf.endswith(FRAME_MAGIC[:length]): @@ -867,7 +1042,13 @@ def __init__( self._plain = bytearray() # decrypted bytes ready for the reader def enable(self, local_nonce, peer_nonce, peer_pem_path=None): - """Start speaking frames (flip completed on both sides).""" + """Start speaking frames (flip completed on both sides). + + Args: + local_nonce (object): Value used by the operation. + peer_nonce (object): Value used by the operation. + peer_pem_path (str): Value used by the operation. + """ with self._lock: self.local_nonce = local_nonce self.peer_nonce = peer_nonce @@ -883,8 +1064,9 @@ def disable(self): """Drop back to raw mode (decode failure or peer re-exchange). The next handshake must announce frame readiness again, so the - peer-ready flag is cleared with the mode, and the owner's secure-socket - set is updated through ``on_disable``.""" + peer-ready flag is cleared with the mode, and the owner's secure-socket + set is updated through ``on_disable``. + """ with self._lock: was_secure = self.secure self.secure = False @@ -898,14 +1080,23 @@ def disable(self): pass def note_peer_frames_ready(self): - """The peer announced it may receive frames.""" + """Return the peer announced it may receive frames. + + The peer announced it may receive frames. + """ with self._lock: self.peer_frames_ready = True if self.secure: self.frames_allowed.set() def claim_ecdh_pub_send(self): - """True exactly once per session, when the peer can receive frames.""" + """Return true exactly once per session, when the peer can receive frames. + + True exactly once per session, when the peer can receive frames. + + Returns: + bool: Result produced by the operation. + """ with self._lock: if self.ecdh_pub_sent or not self.frames_allowed.is_set(): return False @@ -918,10 +1109,17 @@ def send(self, payload, force_rsa=False): """Frame and send one payload (str or bytes) on this socket. ``force_rsa`` is used for the ECDH public-key line, which must travel - in an RSA frame even if it is longer than the single-block limit (an - ECDH frame would be circular: the peer key it needs is this payload). + in an RSA frame even if it is longer than the single-block limit (an + ECDH frame would be circular: the peer key it needs is this payload). + + Raises on failure; the caller logs and reports the send failure. + + Args: + payload (bytes | str): Value used by the operation. + force_rsa (bool): Value used by the operation. - Raises on failure; the caller logs and reports the send failure. + Raises: + RuntimeError: When the operation cannot complete. """ if isinstance(payload, str): data = payload.encode("utf-8") @@ -945,6 +1143,14 @@ def send(self, payload, force_rsa=False): self._sendall(self._ecdh_frame(chunk, peer)) def _rsa_frame(self, text_bytes): + """Handle the operation. + + Args: + text_bytes (bytes | str): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._lock: nonce = self.local_nonce or "" seq = self.send_seq @@ -957,6 +1163,15 @@ def _rsa_frame(self, text_bytes): return self._wrap(FRAME_TYPE_RSA, body) def _ecdh_frame(self, chunk, peer): + """Handle the operation. + + Args: + chunk (bytes | str): Value used by the operation. + peer (tuple): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._lock: nonce = self.local_nonce or "" seq = self.send_seq @@ -967,6 +1182,15 @@ def _ecdh_frame(self, chunk, peer): @staticmethod def _wrap(frame_type, body): + """Handle the operation. + + Args: + frame_type (object): Value used by the operation. + body (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ return FRAME_MAGIC + bytes([frame_type]) + len(body).to_bytes(4, "big") + body # -- receive path -------------------------------------------------------- @@ -975,17 +1199,23 @@ def feed(self, data): """Parse received socket bytes; returns the bytes for the line reader. While the channel is framed every byte is parsed into the plaintext - buffer and an empty result comes back; while it is not, plaintext - bytes are returned for the line reader. Frame bytes are consumed in - both modes: a peer that has not processed a re-exchange yet keeps - sending frames after this side dropped framing, and such a stale - frame cannot be authenticated any more — its bytes must never reach - the line reader, which would echo them as a message and reset the - decode-failure streak. - - The parse shares the channel lock with ``enable``/``disable``, so a - flip that lands while the caller's read was in flight still - classifies the bytes by the state of that moment. + buffer and an empty result comes back; while it is not, plaintext + bytes are returned for the line reader. Frame bytes are consumed in + both modes: a peer that has not processed a re-exchange yet keeps + sending frames after this side dropped framing, and such a stale + frame cannot be authenticated any more — its bytes must never reach + the line reader, which would echo them as a message and reset the + decode-failure streak. + + The parse shares the channel lock with ``enable``/``disable``, so a + flip that lands while the caller's read was in flight still + classifies the bytes by the state of that moment. + + Args: + data (bytes | str): Value used by the operation. + + Returns: + object: Result produced by the operation. """ with self._lock: self._raw += data @@ -995,8 +1225,11 @@ def _parse_buffered(self): """Parse everything buffered; returns the bytes for the line reader. Must be called under the channel lock. A ``disable`` performed while - parsing (the peer's re-exchange line) is honoured: the bytes behind - it belong to the peer's raw stream and are returned as such. + parsing (the peer's re-exchange line) is honoured: the bytes behind + it belong to the peer's raw stream and are returned as such. + + Returns: + object: Result produced by the operation. """ plain = bytearray() while self._raw: @@ -1027,7 +1260,13 @@ def _consume_frame(self): """Consume one whole frame; False when more bytes are needed. A framed channel decrypts the body; a raw one drops it, because the - session keys were torn down with the framing. + session keys were torn down with the framing. + + Returns: + bool: Result produced by the operation. + + Raises: + _FrameError: When the operation cannot complete. """ if len(self._raw) < FRAME_HEADER_LEN: return False @@ -1053,6 +1292,12 @@ def _consume_plaintext_line(self): """Pass known plaintext protocol lines through; drop anything else. Returns False when the line is not complete yet. + + Returns: + bool: Result produced by the operation. + + Raises: + _FrameError: When the operation cannot complete. """ nl = self._raw.find(b"\n") if nl < 0: @@ -1077,7 +1322,14 @@ def _consume_plaintext_line(self): return True def _split_prefix(self, body): - """Split ``||`` off a frame body -> (nonce, seq) or None.""" + """Split ``||`` off a frame body -> (nonce, seq) or None. + + Args: + body (object): Value used by the operation. + + Returns: + NoneType | list | tuple: Result produced by the operation. + """ first = body.find(b"|") if first < 0: return None @@ -1092,7 +1344,17 @@ def _split_prefix(self, body): return nonce, seq, body[second + 1 :] def _check_replay(self, nonce, seq): - """True when the frame is fresh; a stale/duplicate frame is dropped.""" + """Return true when the frame is fresh; a stale/duplicate frame is dropped. + + True when the frame is fresh; a stale/duplicate frame is dropped. + + Args: + nonce (object): Value used by the operation. + seq (object): Value used by the operation. + + Returns: + bool: Result produced by the operation. + """ if nonce != self.peer_nonce: self._debug("crypto: replay dropped (nonce mismatch)") return False @@ -1106,6 +1368,14 @@ def _check_replay(self, nonce, seq): return True def _decode_rsa(self, body): + """Handle the operation. + + Args: + body (object): Value used by the operation. + + Raises: + _FrameError: When the operation cannot complete. + """ parts = self._split_prefix(body) if parts is None: raise _FrameError("malformed RSA frame") @@ -1122,6 +1392,14 @@ def _decode_rsa(self, body): self._plain += plain.encode("utf-8") if isinstance(plain, str) else bytes(plain) def _decode_ecdh(self, body): + """Handle the operation. + + Args: + body (object): Value used by the operation. + + Raises: + _FrameError: When the operation cannot complete. + """ parts = self._split_prefix(body) if parts is None: raise _FrameError("malformed ECDH frame") @@ -1140,7 +1418,14 @@ def _decode_ecdh(self, body): self._plain += plain def take(self, n): - """Up to ``n`` plaintext bytes; empty when none are buffered.""" + """Up to ``n`` plaintext bytes; empty when none are buffered. + + Args: + n (int): Value used by the operation. + + Returns: + bytes | object: Result produced by the operation. + """ with self._lock: if not self._plain: return b"" @@ -1152,10 +1437,13 @@ def drain_plaintext(self): """Bytes the line reader still gets after framing failed. The decrypted buffer plus the plaintext already buffered with the - frame that failed — the peer's re-exchange line, for example. Frame - bytes stay in the channel, where the stale-frame drop consumes them: - they must not be served as a line, and the channel may still need - them to resynchronise. + frame that failed — the peer's re-exchange line, for example. Frame + bytes stay in the channel, where the stale-frame drop consumes them: + they must not be served as a line, and the channel may still need + them to resynchronise. + + Returns: + object: Result produced by the operation. """ with self._lock: plain = bytearray(self._plain) @@ -1178,16 +1466,15 @@ def _custom_handler_for(command, handlers): Args: command (str): Command line whose first token names the handler. - handlers (list): The ``[{}, {}]`` registry, the console group and the - inbound group. + handlers (list): The ``[{}, {}]`` registry, the console group and the inbound group. Returns: - callable: The registered handler; with both groups registering the - name, the console group wins. + callable: The registered handler; with both groups registering the + name, the console group wins. Raises: - CommandNotFoundError: If neither group registers the first token. - ValueError: If ``command`` cannot be split (unbalanced quotes). + CommandNotFoundError: If neither group registers the first token. + ValueError: If ``command`` cannot be split (unbalanced quotes). """ cmd_parts = shlex.split(command.strip()) cmd_name = cmd_parts[0].lower() if cmd_parts else "" @@ -1318,6 +1605,7 @@ def __init__( second, averaged over ``NETWORK_SPEED_WINDOW`` seconds). With False nothing is measured and every speed value is None. Defaults to True. + Raises: OSError: If the ``.Flow`` directories or ``decode_command_table.json`` cannot be created or read. @@ -1494,20 +1782,18 @@ def _measure_network_speed(self, payload, is_upload): """Fold just-sent/received traffic into the real-time speed estimate. Every send and receive sample feeds this — control messages, file data - and relay traffic alike — so the speed attributes describe the - instance's current traffic as a rolling average over - ``NETWORK_SPEED_WINDOW`` seconds. + and relay traffic alike — so the speed attributes describe the + instance's current traffic as a rolling average over + ``NETWORK_SPEED_WINDOW`` seconds. Args: - payload (bytes | str | int): Bytes just written or read; a str - counts as its UTF-8 length, an int is a byte count already. - is_upload (bool): True for sent bytes (``upload_network_speed``), - False for received ones (``recv_network_speed``). + payload (bytes | str | int): Bytes just written or read; a str counts as its UTF-8 length, an int is a byte count already. + is_upload (bool): True for sent bytes (``upload_network_speed``), False for received ones (``recv_network_speed``). Returns: - float | None: The refreshed speed in bytes per second, or None when - ``is_enable_real_time_network_speed`` is False; both speed - attributes are None then. + float | None: The refreshed speed in bytes per second, or None when + ``is_enable_real_time_network_speed`` is False; both speed + attributes are None then. """ if not self.is_enable_real_time_network_speed: self.upload_network_speed = None @@ -1551,25 +1837,17 @@ def _file_progress_start(self, progress_dict, fid, total_bytes, path, peer=None, """Register one file transfer in a progress store. Args: - progress_dict (dict): ``self.file_recv_progress`` for an inbound - transfer, ``self.file_upload_progress`` for an outbound one. - fid (int | None): The transfer's fid; None tracks nothing (a leg - without a protocol transfer id, such as a key push). + progress_dict (dict): ``self.file_recv_progress`` for an inbound transfer, ``self.file_upload_progress`` for an outbound one. + fid (int | None): The transfer's fid; None tracks nothing (a leg without a protocol transfer id, such as a key push). total_bytes (int): Size of the file being transferred. - path (str): Local path of the file: the source of an outbound - transfer, the file being written for an inbound one. - peer (tuple | None): ``(ip, port)`` of the transfer's original - peer — the sender for an inbound transfer, the receiver for an - outbound one. A forwarded transfer stores the original peer on - both sides, never the relay; None marks a leg that cannot be - resumed (there is no peer to continue it with). - initial (int): Bytes already transferred when the leg starts; a - resumed transfer continues a partially transferred file. + path (str): Local path of the file: the source of an outbound transfer, the file being written for an inbound one. + peer (tuple | None): ``(ip, port)`` of the transfer's original peer — the sender for an inbound transfer, the receiver for an outbound one. A forwarded transfer stores the original peer on both sides, never the relay; None marks a leg that cannot be resumed (there is no peer to continue it with). + initial (int): Bytes already transferred when the leg starts; a resumed transfer continues a partially transferred file. Returns: - list | None: The ``[transferred, total, speed, path, peer]`` entry - the transfer updates, or None when tracking is off - (``is_enable_file_transfer_progress_bar`` False, or no fid). + list | None: The ``[transferred, total, speed, path, peer]`` entry + the transfer updates, or None when tracking is off + (``is_enable_file_transfer_progress_bar`` False, or no fid). """ if fid is None or not self.is_enable_file_transfer_progress_bar: return None @@ -1583,13 +1861,9 @@ def _file_progress_update(self, entry, byte_count, is_upload): """Fold one transferred chunk into a progress entry. Args: - entry (list | None): Entry from `_file_progress_start`, or None - when the transfer is not tracked. + entry (list | None): Entry from `_file_progress_start`, or None when the transfer is not tracked. byte_count (int): Bytes of the chunk just sent or received. - is_upload (bool): True for sent chunks, False for received ones. - - The speed slot mirrors the live measurement, so it stays None while - ``is_enable_real_time_network_speed`` is False. + is_upload (bool): True for sent chunks, False for received ones. The speed slot mirrors the live measurement, so it stays None while ``is_enable_real_time_network_speed`` is False. """ if entry is None: return @@ -1600,17 +1874,16 @@ def _file_progress_finish(self, progress_dict, fid, entry, keep=False): """Drop a finished transfer's progress entry, or keep it for a resume. A newer transfer may already hold the same fid (transfer ids are reused - as transfers end), so only this transfer's own entry is dropped. With - ``keep`` True an interrupted transfer keeps its entry — and the partial - file that entry points at — so the reconnect logic can continue it - (`resume_transfers`); the entry then lives until the transfer ends. + as transfers end), so only this transfer's own entry is dropped. With + ``keep`` True an interrupted transfer keeps its entry — and the partial + file that entry points at — so the reconnect logic can continue it + (`resume_transfers`); the entry then lives until the transfer ends. Args: progress_dict (dict): Store the entry belongs to. fid (int | None): Transfer id the entry is keyed by. entry (list | None): Entry to drop; None tracks nothing. - keep (bool): Keep the entry (and persist the stores) instead of - dropping it. Defaults to False. + keep (bool): Keep the entry (and persist the stores) instead of dropping it. Defaults to False. """ if entry is None: return @@ -1634,11 +1907,19 @@ def _transfer_progress_snapshot(self): """Return the JSON-ready form of every transfer still in play. Returns: - dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids - are string keys and every peer is an ``[ip, port]`` list. + dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids + are string keys and every peer is an ``[ip, port]`` list. """ def entries(store): + """Handle the operation. + + Args: + store (list | dict): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ return { str(fid): [ entry[0], @@ -1674,12 +1955,12 @@ def _persist_transfer_progress(self): """Write the transfer stores to the protocol's ``.Flow`` directory. Every in-flight transfer — uploads, downloads, and the relay records a - disconnected forward is resumed from — is written to - ``server_file_trans_progress.json`` when a connection drops, and the - file is what the reconnect logic reads back. Once nothing is left to - transfer the file is emptied; it is only rewritten while it exists, so - a run without an interrupted transfer never creates it. A write - failure is logged, never raised. + disconnected forward is resumed from — is written to + ``server_file_trans_progress.json`` when a connection drops, and the + file is what the reconnect logic reads back. Once nothing is left to + transfer the file is emptied; it is only rewritten while it exists, so + a run without an interrupted transfer never creates it. A write + failure is logged, never raised. """ snapshot = self._transfer_progress_snapshot() with self._transfer_progress_lock: @@ -1701,12 +1982,12 @@ def _load_transfer_progress(self): """Read the persisted interrupted transfers back into the stores. Every entry read back keeps the bytes it had already transferred, so - the reconnect logic can ask the sender to continue from there; every - relay record comes back so a disconnected forward can be routed again. - Entries a live transfer (or a relay) already owns are left alone. + the reconnect logic can ask the sender to continue from there; every + relay record comes back so a disconnected forward can be routed again. + Entries a live transfer (or a relay) already owns are left alone. Returns: - int: Number of transfer entries and relay records restored. + int: Number of transfer entries and relay records restored. """ with self._transfer_progress_lock: try: @@ -1758,12 +2039,11 @@ def _forward_relay_targets(self, fid, peer=None): Args: fid (int): Relay fid, or one of its per-target transfer ids. - peer (tuple | None): Restrict to the writer serving this peer; - None addresses every writer of the relay. + peer (tuple | None): Restrict to the writer serving this peer; None addresses every writer of the relay. Returns: - tuple: ``(relay, [targets])``; ``(None, [])`` when no live relay - writer matches. + tuple: ``(relay, [targets])``; ``(None, [])`` when no live relay + writer matches. """ with self._forward_relays_lock: relay = self._forward_relays.get(fid) @@ -1779,8 +2059,13 @@ def _forward_relay_targets(self, fid, peer=None): def _mark_transfer_pause(self, fid, paused, peer=None): """Set or clear one transfer's pause switch (see `pause_trans`). + Args: + fid (int): Value used by the operation. + paused (bool): Value used by the operation. + peer (tuple): Value used by the operation. + Returns: - bool: True when a live relay writer or outbound leg was found. + bool: True when a live relay writer or outbound leg was found. """ relay, targets = self._forward_relay_targets(fid, peer) if targets: @@ -1835,14 +2120,24 @@ def start_trans(self, fid, peer=None): return self._mark_transfer_pause(fid, False, peer) def _register_transfer_socket(self, fid, sock): - """Record the socket of a leg, so a dead session can be cleared out.""" + """Record the socket of a leg, so a dead session can be cleared out. + + Args: + fid (int): Value used by the operation. + sock (object): Value used by the operation. + """ if fid is None: return with self._transfer_progress_lock: self._active_transfer_sockets[fid] = sock def _release_transfer_socket(self, fid, sock): - """Forget a leg's socket once the leg is over (its own, not a newer one's).""" + """Forget a leg's socket once the leg is over (its own, not a newer one's). + + Args: + fid (int): Value used by the operation. + sock (object): Value used by the operation. + """ if fid is None: return with self._transfer_progress_lock: @@ -1853,16 +2148,14 @@ def _drop_stale_transfers(self, peer=None): """Close the legs a peer's previous session left behind. A peer that (re)connects proves that the legs of its earlier session - are over: their sockets are shut down so the stored transfers can be - resumed without two legs writing the same transfer. + are over: their sockets are shut down so the stored transfers can be + resumed without two legs writing the same transfer. Args: - peer (tuple | None): Restrict to the legs whose progress entry - names this ``(ip, port)``; None clears every leg of the - instance (a fresh session replaces all of them). + peer (tuple | None): Restrict to the legs whose progress entry names this ``(ip, port)``; None clears every leg of the instance (a fresh session replaces all of them). Returns: - int: Number of legs closed. + int: Number of legs closed. """ stale = [] for store in (self.file_upload_progress, self.file_recv_progress): @@ -1927,8 +2220,11 @@ def _wait_transfer_paused(self, fid): """Block a sending leg while its fid is marked paused. Runs before every chunk so ``/pause_trans`` stops the stream without - closing the transfer; the wait ends when the leg is resumed, when the - instance stops, or when the fid is not paused at all. + closing the transfer; the wait ends when the leg is resumed, when the + instance stops, or when the fid is not paused at all. + + Args: + fid (int): Value used by the operation. """ if fid is None: return @@ -1946,8 +2242,8 @@ def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): timeout (float): Seconds to wait. Returns: - tuple | None: ``(port, stamp)`` announced for this fid, or None - when the announcement does not arrive in time. + tuple | None: ``(port, stamp)`` announced for this fid, or None + when the announcement does not arrive in time. """ deadline = time.time() + timeout while time.time() < deadline: @@ -1963,7 +2259,11 @@ def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): return None def _forget_transfer_port(self, fid): - """Drop pending port announcements of a fid an older session left behind.""" + """Drop pending port announcements of a fid an older session left behind. + + Args: + fid (int): Value used by the operation. + """ if fid is None: return with self.file_transfer_server_port_lock: @@ -1975,12 +2275,16 @@ def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): """Wait until a control channel may carry framed protocol lines. The reconnect flows run right after a session is established, when the - crypto handshake may still be completing; a resume line sent then would - travel plaintext and be dropped by the peer's framing guard. Without - encryption there is nothing to wait for. + crypto handshake may still be completing; a resume line sent then would + travel plaintext and be dropped by the peer's framing guard. Without + encryption there is nothing to wait for. + + Args: + control_socket (socket.socket): Value used by the operation. + timeout (float): Value used by the operation. Returns: - bool: True when the channel speaks frames (or encryption is off). + bool: True when the channel speaks frames (or encryption is off). """ if not self.is_enable_encrypto or self.crypto is None: return True @@ -2378,6 +2682,12 @@ def remove_file_listener(self, listener): pass def _notify_message_received(self, client_id, message): + """Handle the operation. + + Args: + client_id (object): Value used by the operation. + message (object): Value used by the operation. + """ with self._event_listeners_lock: listeners = list(self._message_listeners) for listener in listeners: @@ -2388,6 +2698,15 @@ def _notify_message_received(self, client_id, message): self._log_exc() def _notify_file_received(self, client_id, full_path, name, size, command): + """Handle the operation. + + Args: + client_id (object): Value used by the operation. + full_path (str): Value used by the operation. + name (object): Value used by the operation. + size (int): Value used by the operation. + command (object): Value used by the operation. + """ with self._event_listeners_lock: listeners = list(self._file_listeners) for listener in listeners: @@ -2401,8 +2720,14 @@ def _socket_key(self, sock): """Serializable key for a sender socket (its peer address). Forwarded records already carry the originator's address as a - string and are used as-is; a socket that cannot answer - ``getpeername`` (already closed) falls back to its repr. + string and are used as-is; a socket that cannot answer + ``getpeername`` (already closed) falls back to its repr. + + Args: + sock (object): Value used by the operation. + + Returns: + object: Result produced by the operation. """ if isinstance(sock, str): return sock @@ -2416,20 +2741,33 @@ def _remember_socket_key(self, sock): """Capture the log key of ``sock`` while it is known to be alive. A record stays buffered after its connection goes away, and the - flush that persists it must still file it under the sender's - address: by then the closed socket no longer answers - ``getpeername`` and would be logged as ``str(sock)``. The key is - forgotten once nothing is buffered under it any more (see - ``_flush_dict_locked``). + flush that persists it must still file it under the sender's + address: by then the closed socket no longer answers + ``getpeername`` and would be logged as ``str(sock)``. The key is + forgotten once nothing is buffered under it any more (see + ``_flush_dict_locked``). + + Args: + sock (object): Value used by the operation. """ with self._socket_keys_lock: if sock not in self._socket_keys: self._socket_keys[sock] = self._socket_key(sock) def _record_key(self, sock): - """The JSON-log key for ``sock``: the address captured when it was + """Return the JSON-log key for ``sock``: the address captured when it was. + + The JSON-log key for ``sock``: the address captured when it was + recorded, or the live peer address for a socket inserted without a - record.""" + record. + + Args: + sock (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ key = self._socket_keys.get(sock) if key is not None: return key @@ -2439,8 +2777,12 @@ def _record_message(self, sock, content): """Store one inbound plain-text message under the sender's socket. External code reads ``messages_dict`` (or the JSON log) instead of - registering a message listener. The entry is ``[content, timestamp]`` - with the timestamp of arrival. + registering a message listener. The entry is ``[content, timestamp]`` + with the timestamp of arrival. + + Args: + sock (object): Value used by the operation. + content (object): Value used by the operation. """ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with self._messages_dict_lock: @@ -2456,10 +2798,14 @@ def _record_event(self, sock, command): """Store one inbound command as an event under the sender's socket. The event content is the original wire command from the peer (file - transfers, folder transfers, extension commands, ...). External code - reads ``events_dict`` (or the JSON log) instead of registering a - listener. File-transfer events get their completion timestamp via - ``_update_event_timestamp``. + transfers, folder transfers, extension commands, ...). External code + reads ``events_dict`` (or the JSON log) instead of registering a + listener. File-transfer events get their completion timestamp via + ``_update_event_timestamp``. + + Args: + sock (object): Value used by the operation. + command (object): Value used by the operation. """ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with self._events_dict_lock: @@ -2473,8 +2819,13 @@ def _update_event_timestamp(self, sock, command, timestamp): """Stamp the completion time onto the recorded event for ``command``. File transfers finish on a worker thread after the receive thread - recorded the command, so the event's timestamp is refreshed here with - the moment the transfer actually completed. + recorded the command, so the event's timestamp is refreshed here with + the moment the transfer actually completed. + + Args: + sock (object): Value used by the operation. + command (object): Value used by the operation. + timestamp (object): Value used by the operation. """ with self._events_dict_lock: entries = self.events_dict.get(sock) @@ -2488,10 +2839,17 @@ def _splice_event_command(self, command, **parts): """Return the command to record as an event. The wire command is recorded verbatim whenever it is available. When - this end cannot see the original command (a transfer relayed by the - server, or a protocol-internal control line), splice a readable - command from the available parts so the event still identifies the - transfer. + this end cannot see the original command (a transfer relayed by the + server, or a protocol-internal control line), splice a readable + command from the available parts so the event still identifies the + transfer. + + Args: + command (object): Value used by the operation. + **parts (list | dict): Value used by the operation. + + Returns: + object: Result produced by the operation. """ if command: return command @@ -2508,7 +2866,14 @@ def _splice_event_command(self, command, **parts): def _flush_dict_locked(self, d, size_attr, path): """Flush ``d`` (socket -> [[content, ts], ...]) into its JSON log and - clear it. The caller must hold the dict's lock.""" + + clear it. The caller must hold the dict's lock. + + Args: + d (list | dict): Value used by the operation. + size_attr (object): Value used by the operation. + path (str): Value used by the operation. + """ if not d: return snapshot = dict(d) @@ -2522,12 +2887,14 @@ def _flush_dict_locked(self, d, size_attr, path): self._socket_keys.pop(sock, None) def _flush_messages_dict(self): + """Handle the operation.""" with self._messages_dict_lock: self._flush_dict_locked( self.messages_dict, "_messages_dict_size", self.messages_log_file ) def _flush_events_dict(self): + """Handle the operation.""" with self._events_dict_lock: self._flush_dict_locked(self.events_dict, "_events_dict_size", self.events_log_file) @@ -2535,10 +2902,14 @@ def _merge_json_log(self, path, snapshot): """Merge ``snapshot`` into the JSON log at ``path`` (append per socket). Publishes through `_publish_json_log`: a temp file named after this - writer, and an optimistic re-merge when another instance published in - between, so concurrent flushes of several instances sharing one log - neither corrupt nor lose each other. A failure is logged, never raised - into the caller. + writer, and an optimistic re-merge when another instance published in + between, so concurrent flushes of several instances sharing one log + neither corrupt nor lose each other. A failure is logged, never raised + into the caller. + + Args: + path (str): Value used by the operation. + snapshot (list | dict): Value used by the operation. """ try: _publish_json_log(path, snapshot, self._record_key) @@ -2590,6 +2961,7 @@ def create_temporary_server(self, handler, port=None, max_connections=1): stop_event = threading.Event() def server_loop(): + """Handle the operation.""" while not stop_event.is_set(): try: server_socket.settimeout(1.0) @@ -2629,6 +3001,7 @@ def create_temporary_client(self, server_host, server_port, bind_port=None, on_d stop_event = threading.Event() def receiver(): + """Handle the operation.""" while not stop_event.is_set(): try: client_sock.settimeout(1.0) @@ -2730,8 +3103,15 @@ def _crypto_get_send_lock(self, client_socket): """Per-socket lock serialising encrypt+send for one connection. A control socket's `_SecureChannel` shares this exact lock object, so - a frame write can never interleave with a raw write on the same - socket (and vice versa) during the flip.""" + a frame write can never interleave with a raw write on the same + socket (and vice versa) during the flip. + + Args: + client_socket (socket.socket): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._crypto_lock: lock = self._crypto_send_locks.get(client_socket) if lock is None: @@ -2805,10 +3185,10 @@ def _sendall(self, client_socket, data): data (bytes): Payload to write in full. Raises: - OSError: If the socket write fails or the peer closed the - connection. - TimeoutError: If a non-blocking socket stays unwritable for - ``SEND_WAIT_TIMEOUT`` seconds. + OSError: If the socket write fails or the peer closed the + connection. + TimeoutError: If a non-blocking socket stays unwritable for + ``SEND_WAIT_TIMEOUT`` seconds. """ if not self.is_asynic_clients_io: # blocking socket: a single sendall is enough client_socket.sendall(data) @@ -2825,7 +3205,12 @@ def _sendall(self, client_socket, data): view = view[sent:] def _send_raw(self, client_socket, text): - """Send a plaintext crypto-protocol message, bypassing encryption.""" + """Send a plaintext crypto-protocol message, bypassing encryption. + + Args: + client_socket (socket.socket): Value used by the operation. + text (object): Value used by the operation. + """ data = text.strip() if not data.endswith("\n"): data += "\n" @@ -2834,12 +3219,28 @@ def _send_raw(self, client_socket, text): self._measure_network_speed(encoded, is_upload=True) def _crypto_mark_encrypted(self, client_socket, peer_role, peer_pem_path): + """Handle the operation. + + Args: + client_socket (socket.socket): Value used by the operation. + peer_role (object): Value used by the operation. + peer_pem_path (str): Value used by the operation. + """ with self._crypto_lock: self._encrypted_sockets.add(client_socket) self._crypto_peer[client_socket] = (peer_role, peer_pem_path) def _crypto_session_for(self, client_address): - """The crypto session of one client address (created on demand).""" + """Get or create the crypto session for a client address. + + The crypto session of one client address (created on demand). + + Args: + client_address (tuple): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._crypto_lock: session = self._crypto_sessions.get(client_address) if session is None and self.crypto is not None: @@ -2848,7 +3249,16 @@ def _crypto_session_for(self, client_address): return session def _crypto_control_state(self, client_socket): - """(session, channel) of one control socket; (None, None) when unknown.""" + """Return (session, channel) of one control socket; (None, None) when unknown. + + (session, channel) of one control socket; (None, None) when unknown. + + Args: + client_socket (socket.socket): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ with self._crypto_lock: addr = self._crypto_sock_addr.get(client_socket) session = self._crypto_sessions.get(addr) if addr is not None else None @@ -2856,7 +3266,11 @@ def _crypto_control_state(self, client_socket): return session, channel def _crypto_after_flip(self, client_socket): - """Announce frame readiness (plaintext) and publish the session ECDH key.""" + """Announce frame readiness (plaintext) and publish the session ECDH key. + + Args: + client_socket (socket.socket): Value used by the operation. + """ _session, channel = self._crypto_control_state(client_socket) if channel is None: return @@ -2868,20 +3282,41 @@ def _crypto_after_flip(self, client_socket): self._crypto_publish_ecdh_pub(client_socket) def _crypto_publish_ecdh_pub(self, client_socket): - """Send our session ECDH public key once frames are allowed both ways.""" + """Send our session ECDH public key once frames are allowed both ways. + + Args: + client_socket (socket.socket): Value used by the operation. + """ session, channel = self._crypto_control_state(client_socket) if session is not None: session.publish_pub(channel) def _crypto_transfer_stamp(self, control_socket, force_plain=False): - """Mode+nonce a listener announces to a transfer connector.""" + """Mode+nonce a listener announces to a transfer connector. + + Args: + control_socket (socket.socket): Value used by the operation. + force_plain (bool): Value used by the operation. + + Returns: + object | str: Result produced by the operation. + """ session, channel = self._crypto_control_state(control_socket) if session is None: return "plain" return session.transfer_stamp(channel, force_plain) def _crypto_attach_transfer_in(self, sock, control_socket, stamp): - """Framing channel for an accepted transfer socket (listener side).""" + """Framing channel for an accepted transfer socket (listener side). + + Args: + sock (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ session, control_channel = self._crypto_control_state(control_socket) if session is None: return None @@ -2893,7 +3328,16 @@ def _crypto_attach_transfer_in(self, sock, control_socket, stamp): return channel def _crypto_attach_transfer_out(self, sock, control_socket, stamp): - """Framing channel for a connected transfer socket (connector side).""" + """Framing channel for a connected transfer socket (connector side). + + Args: + sock (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ session, control_channel = self._crypto_control_state(control_socket) crypto = _connector_transfer_crypto(session, control_channel, stamp) channel = _enable_connector_channel(sock, crypto) @@ -2904,14 +3348,25 @@ def _crypto_attach_transfer_out(self, sock, control_socket, stamp): return channel def _crypto_drop_channel(self, sock): - """Forget a finished transfer socket's channel.""" + """Forget a finished transfer socket's channel. + + Args: + sock (object): Value used by the operation. + """ with self._crypto_lock: self._channels.pop(sock, None) self._encrypted_sockets.discard(sock) @staticmethod def _new_crypto_state(force=False): - """Fresh per-connection crypto handshake state.""" + """Fresh per-connection crypto handshake state. + + Args: + force (bool): Value used by the operation. + + Returns: + dict: Result produced by the operation. + """ return { "force": force, "peer_nonce": None, @@ -2969,8 +3424,15 @@ def receive_message(self, client_socket, msg_length): # receive message return plain # plaintext mode: the line reader gets the bytes def _crypto_channel_error(self, client_socket): - """A frame failed to decode: re-exchange on a control socket, close a - transfer socket (its leg has no handshake to recover with).""" + """Handle a frame decode failure on a control or transfer socket. + + A frame failed to decode: re-exchange on a control socket, close a + + transfer socket (its leg has no handshake to recover with). + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: is_control = client_socket in self._crypto_sock_addr if is_control: @@ -2983,7 +3445,13 @@ def _crypto_channel_error(self, client_socket): pass def _crypto_note_healthy(self, client_socket): - """A frame decoded cleanly: reset the streak that feeds the breaker.""" + """Reset the decode-failure count after a valid frame. + + A frame decoded cleanly: reset the streak that feeds the breaker. + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: addr = self._crypto_sock_addr.get(client_socket) state = self._crypto_state.get(addr) if addr is not None else None @@ -2992,12 +3460,16 @@ def _crypto_note_healthy(self, client_socket): def _crypto_on_decode_failure(self, client_socket): """Decryption failed (stale/wrong key): drop encryption, reload + our own key and ask the peer to re-exchange public keys. - A circuit breaker closes the connection after - ``MAX_DECODE_FAILURES`` consecutive failures on one connection, - so a garbage-injection or persistent-mismatch storm cannot spin - the re-exchange loop forever. + A circuit breaker closes the connection after + ``MAX_DECODE_FAILURES`` consecutive failures on one connection, + so a garbage-injection or persistent-mismatch storm cannot spin + the re-exchange loop forever. + + Args: + client_socket (socket.socket): Value used by the operation. """ with self._crypto_lock: channel = self._channels.get(client_socket) @@ -3053,20 +3525,37 @@ def _crypto_on_decode_failure(self, client_socket): self._log_exc() def _crypto_drop_secure(self, client_socket): - """Framing stopped: keep the secure-socket set and peer map truthful.""" + """Framing stopped: keep the secure-socket set and peer map truthful. + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: self._encrypted_sockets.discard(client_socket) self._crypto_peer.pop(client_socket, None) @staticmethod def _crypto_fresh_nonce(): + """Handle the operation. + + Returns: + object: Result produced by the operation. + """ return secrets.token_hex(16) def _crypto_on_client_hello(self, client_socket, client_address, client_nonce, force): """Server side of /crypto_key_exchange: record the client's + session nonce, reply that we need its public key (every - connection re-exchanges), then wait for it and announce - readiness.""" + connection re-exchanges), then wait for it and announce + readiness. + + Args: + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. + client_nonce (object): Value used by the operation. + force (bool): Value used by the operation. + """ self.crypto.ensure_keys() my_nonce = self._crypto_fresh_nonce() with self._crypto_lock: @@ -3088,8 +3577,14 @@ def _crypto_on_client_hello(self, client_socket, client_address, client_nonce, f def _crypto_try_server_flip(self, client_socket, state): """Flip the socket to framed encryption once the peer key passed the + TOFU check and both sides announced readiness (no plaintext/framed - interleaving).""" + interleaving). + + Args: + client_socket (socket.socket): Value used by the operation. + state (object): Value used by the operation. + """ # no send may interleave with the flip with self._crypto_get_send_lock(client_socket): with self._crypto_lock: @@ -3112,8 +3607,15 @@ def _crypto_try_server_flip(self, client_socket, state): def _crypto_wait_server_ready(self, client_socket, client_address, state): """Wait until the client's public key arrived and passed the + TOFU check, then announce readiness. The socket flips to - encrypted mode only when the client's /crypto_ready arrives too.""" + encrypted mode only when the client's /crypto_ready arrives too. + + Args: + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. + state (object): Value used by the operation. + """ with self._crypto_lock: peer_pub_event = state.get("peer_pub_event") if peer_pub_event is None or not peer_pub_event.wait(timeout=60): @@ -3134,7 +3636,16 @@ def _crypto_wait_server_ready(self, client_socket, client_address, state): def _crypto_push_pub_to_client(self, client_socket, client_address): """Push our public key file to the client via the file-transfer - mechanism (server is the sender).""" + + mechanism (server is the sender). + + Args: + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. + + Returns: + bool: Result produced by the operation. + """ while True: # serialise pushes: wait for an in-flight push instead of silently skipping it with self._crypto_lock: if client_socket not in self._crypto_push_active: @@ -3183,10 +3694,16 @@ def _crypto_push_pub_to_client(self, client_socket, client_address): def _crypto_store_received_pub(self, full_path, peer_role, client_address): """TOFU-check a public key received via the file-transfer + mechanism and cache it under the peer endpoint. - The check runs ``verify_peer_pub`` against ``pub_key.json``; on - failure the peer connection is rejected and dropped. + The check runs ``verify_peer_pub`` against ``pub_key.json``; on + failure the peer connection is rejected and dropped. + + Args: + full_path (str): Value used by the operation. + peer_role (object): Value used by the operation. + client_address (tuple): Value used by the operation. """ if self.crypto is None: return @@ -3308,11 +3825,19 @@ async def _async_receive(self, client_socket, loop): """Read up to ``recv_messages_chunk_len`` plaintext bytes from one accepted client. Mirrors `receive_message` for the asyncio path: framed bytes are - decrypted off the event loop (RSA/ECDH are CPU-bound) and served from - the channel's buffer; a socket without a channel is read raw. As in - `receive_message`, the channel classifies what the read returned, so a - flip that landed during the read never leaks frame bytes into the line - reader.""" + decrypted off the event loop (RSA/ECDH are CPU-bound) and served from + the channel's buffer; a socket without a channel is read raw. As in + `receive_message`, the channel classifies what the read returned, so a + flip that landed during the read never leaks frame bytes into the line + reader. + + Args: + client_socket (socket.socket): Value used by the operation. + loop (object): Value used by the operation. + + Returns: + bytes | object: Result produced by the operation. + """ while True: with self._crypto_lock: channel = self._channels.get(client_socket) @@ -3340,8 +3865,12 @@ async def _handle_client_async(self, client_socket, client_address): """Serve one accepted client until it disconnects, as a coroutine. The socket is read through the event loop while the line dispatch and - every write run on worker threads, so a blocking command handler, - listener or peer cannot stall the other connections. + every write run on worker threads, so a blocking command handler, + listener or peer cannot stall the other connections. + + Args: + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. """ loop = asyncio.get_running_loop() client_id = self._register_client(client_socket, client_address) @@ -3391,7 +3920,7 @@ def _register_client(self, client_socket, client_address): client_address (tuple): Peer ``(ip, port)``. Returns: - str: Client id, ``":"``. + str: Client id, ``":"``. """ client_id = f"{client_address[0]}:{client_address[1]}" with self.client_lock: # add new client @@ -3433,8 +3962,8 @@ def _announce_client(self, client_socket, client_id): client_id (str): Client id used in the console log. Returns: - bool: True when the peer was greeted, False when it was already gone - (the caller closes the connection either way). + bool: True when the peer was greeted, False when it was already gone + (the caller closes the connection either way). """ welcome_msg = f"Welcome!: {client_id}\n" # send welcome message try: @@ -3482,7 +4011,7 @@ def _process_client_line(self, client_socket, client_address, client_id, message message (str): One line with its newline removed. Returns: - str | None: Response for that client, or None when none is due. + str | None: Response for that client, or None when none is due. """ if not _crypto_is_protocol_line(message): # genuine peer traffic: reset the streak that feeds the breaker @@ -3792,13 +4321,21 @@ def _handle_forward_send_msg(self, sock, addr, cmd): """Relay plain messages to every reachable destination client. Server side of the client-only ``/forward_send_msg`` command (typed on - a client console and relayed here over the wire). Every message is - wrapped in a ``/send_msg_from `` envelope carrying the - originator's address so receivers can attribute it. The messages are - recorded under the originator's socket (``sock``), exactly as if the - originator had sent them to the server. Destinations that are - unreachable -- or the server itself, which is never in the client - table -- are skipped and the rest are still served. + a client console and relayed here over the wire). Every message is + wrapped in a ``/send_msg_from `` envelope carrying the + originator's address so receivers can attribute it. The messages are + recorded under the originator's socket (``sock``), exactly as if the + originator had sent them to the server. Destinations that are + unreachable -- or the server itself, which is never in the client + table -- are skipped and the rest are still served. + + Args: + sock (object): Value used by the operation. + addr (tuple): Value used by the operation. + cmd (object): Value used by the operation. + + Returns: + NoneType: Result produced by the operation. """ parts = shlex.split(cmd) items, addrs = parse_forward_items_and_addrs(parts[1:]) @@ -3908,6 +4445,17 @@ def forward_item_to( return True def _execute_custom_handler(self, handler, command, client_socket=None, client_address=None): + """Handle the operation. + + Args: + handler (callable): Value used by the operation. + command (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ try: result = handler(client_socket, client_address, command) if result is not None: @@ -3931,6 +4479,13 @@ def _execute_custom_handler(self, handler, command, client_socket=None, client_a def file_folder_transfer_server_recv_server_start_thread( # start a file folder server thread on server self, command, client_id, client_socket ): + """Start a server-side folder receive operation. + + Args: + command (object): Value used by the operation. + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + """ command_part = shlex.split(command) relative_folder_path = command_part[1] # >= 4 tokens means a file transfer (/file_folder [] ); @@ -3946,6 +4501,13 @@ def file_folder_transfer_server_recv_server_start_thread( # start a file folder def file_transfer_server_recv_server_start_thread( # start a file server thread on server self, client_id, client_socket, command ): + """Start a server-side file receive operation. + + Args: + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + command (object): Value used by the operation. + """ file_transfer_server_recv_server_start_thread = threading.Thread( target=self.file_transfer_server_recv_server_start, args=(client_id, client_socket, command), @@ -3956,6 +4518,15 @@ def file_transfer_server_recv_server_start_thread( # start a file server thread def file_transfer_server_recv_server_start( # deal with file transfer request server on server from client and receive file from client self, client_id, client_socket, command, new_save_path=None, file_name=None ): + """Receive a file sent by a connected client. + + Args: + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + command (object): Value used by the operation. + new_save_path (str): Value used by the operation. + file_name (str): Value used by the operation. + """ file_transfer_server_port = self.palloc() self.file_transfer_mode_recv( self.host, @@ -3983,14 +4554,20 @@ def file_transfer_mode_recv( ): """Receive one file over a transfer sub-connection. - ``peer`` is the transfer's original sender (the sender for an inbound - transfer, never a relay): it is stored with the progress entry so a - later reconnect can ask that peer to continue the file. + Args: + server_file_address (str): Local address for the transfer listener. + server_file_port (int): Local port for the transfer listener. + client_socket (socket.socket): Sender's control socket. + client_id (str): Sender identifier in ``"ip:port"`` form. + new_save_path (str | None): Relative directory for folder contents. + file_name (str | None): Destination filename, when specified. + command (str): Wire command that initiated the transfer. + peer (tuple | None): Original sender ``(ip, port)`` for resuming. + resume_entry (list | None): Saved progress entry for a resumed file. - ``resume_entry`` continues an interrupted transfer: the listener - announces itself, asks the sender to continue from the bytes already - on disk (``RESUME_LINE``) and appends the incoming chunks to the - partial file instead of truncating it. + Returns: + None | bool: None after starting or finishing; False when a resume request + cannot be sent. """ file_running = True client_file_socket = None @@ -3998,6 +4575,7 @@ def file_transfer_mode_recv( save_path = None def close_socket(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket nonlocal server_file_socket @@ -4007,6 +4585,7 @@ def close_socket(): server_file_socket.close() def setting_file_save_path(): + """Handle the operation.""" nonlocal save_path save_path = self.file_transfer_dir if new_save_path or destination_path: @@ -4028,6 +4607,11 @@ def setting_file_save_path(): return None def file_transfer_client_recv(client_id): + """Handle the operation. + + Args: + client_id (object): Value used by the operation. + """ nonlocal file_running nonlocal client_file_socket nonlocal server_file_socket @@ -4279,6 +4863,11 @@ def file_transfer_client_recv(client_id): server_file_socket.close() def diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(self, message): + """Send grouped files and folders to their listed clients. + + Args: + message (object): Value used by the operation. + """ command_part = shlex.split(message) del command_part[0] # optional destination directory is the last argument, after the @@ -4362,6 +4951,11 @@ def diff_multiple_file_diff_multiple_client_transfer_server_recv_client_start(se ) def multiple_file_multiple_client_transfer_server_recv_client_start(self, message): + """Send requested files or folders to each listed client. + + Args: + message (object): Value used by the operation. + """ command_part = shlex.split(message) command_type = command_part[0] del command_part[0] @@ -4424,6 +5018,11 @@ def multiple_file_multiple_client_transfer_server_recv_client_start(self, messag self._log(f"start to send folder command: {folder_transfer_command_message}") def folder_file_transfer_server_recv_client_start(self, message): + """Send a folder's contents to one connected client. + + Args: + message (object): Value used by the operation. + """ command_part = shlex.split(message) folder_path = command_part[1] if command_part[-1].startswith("(") and command_part[-1].endswith(")"): @@ -4439,6 +5038,12 @@ def folder_file_transfer_server_recv_client_start(self, message): base_path = os.path.dirname(folder_path) def get_relative_path(base_path, abs_path): + """Handle the operation. + + Args: + base_path (str): Value used by the operation. + abs_path (str): Value used by the operation. + """ base = os.path.normpath(base_path) abs_ = os.path.normpath(abs_path) common = os.path.commonpath([base, abs_]) @@ -4451,6 +5056,13 @@ def get_relative_path(base_path, abs_path): return "/" + rel def send_folder_transfer_command(folder_path, file_name=None, abspath=None): + """Handle the operation. + + Args: + folder_path (str): Value used by the operation. + file_name (str): Value used by the operation. + abspath (str): Value used by the operation. + """ folder_transfer_command_message = "/file_folder {}".format(shlex.quote(folder_path)) if file_name: each_file_transfer_command_message = "/file_folder {} {} {}".format( @@ -4471,6 +5083,13 @@ def send_folder_transfer_command(folder_path, file_name=None, abspath=None): self._log(f"start to send folder command: {folder_transfer_command_message}") def start_file_transfer_with_limit(rel_dir, file, root): + """Handle the operation. + + Args: + rel_dir (str): Value used by the operation. + file (str): Value used by the operation. + root (object): Value used by the operation. + """ cmd = "/file_folder {} {} {}".format( shlex.quote(rel_dir), shlex.quote(file), shlex.quote(str(client_addr)) ) @@ -4478,6 +5097,7 @@ def start_file_transfer_with_limit(rel_dir, file, root): cmd += " {}".format(shlex.quote(destination_path)) def limited_transfer(): + """Handle the operation.""" self.file_semaphore.acquire() try: self.file_transfer_server_recv_client_start(cmd, root) @@ -4489,6 +5109,7 @@ def limited_transfer(): self._log(f"start to send file: {cmd} (limit {self.max_file_transfer_thread_num})") def get_all_files_in_folder(): + """Handle the operation.""" for root, dirs, files in os.walk(folder_path): rel_dir = get_relative_path(base_path, root) if root != folder_path: @@ -4502,6 +5123,12 @@ def get_all_files_in_folder(): get_all_files_in_folder() def file_transfer_server_recv_client_start_thread(self, message, file_folder_abspath=None): + """Start a thread to send a file or folder item to a client. + + Args: + message (object): Value used by the operation. + file_folder_abspath (str): Value used by the operation. + """ file_transfer_server_recv_client_start_thread = threading.Thread( target=self.file_transfer_server_recv_client_start, args=(message, file_folder_abspath), @@ -4510,6 +5137,12 @@ def file_transfer_server_recv_client_start_thread(self, message, file_folder_abs file_transfer_server_recv_client_start_thread.start() def file_transfer_server_recv_client_start(self, message, file_folder_abspath): + """Send a file or folder item to the addressed connected client. + + Args: + message (object): Value used by the operation. + file_folder_abspath (str): Value used by the operation. + """ client_id = None command_part = shlex.split(message) # optional destination directory comes after the client address tuple @@ -4589,27 +5222,26 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist ): """Send one file over a transfer sub-connection. - ``control_socket``/``crypto`` carry the listener's mode stamp - ("plain" or "enc:"): an encrypted leg aborts when the session - key material is missing rather than downgrading silently. - - ``fid`` is the transfer's id — the caller's own transfer id for a plain - send, the relay id for a forwarded upload — and keys this leg in - ``file_upload_progress``; every leg with a fid can be paused with - ``/pause_trans`` for that fid. None (a leg without a protocol transfer - id, such as a public-key push) tracks no progress. + Args: + filename (str): Source file path. + server_address (str): Transfer listener address. + server_port (int): Transfer listener port. + client_port (int): Local port to bind for the transfer. + control_socket (socket.socket | None): Control socket carrying the mode stamp. + crypto (str | None): ``"plain"`` or encrypted transfer stamp. + fid (int | None): Transfer ID used for progress and pause tracking. + peer (tuple | None): Original receiver ``(ip, port)`` for resuming. + resume_offset (int): Byte offset to resume from; defaults to zero. - ``peer`` is the transfer's original receiver (never a relay): it is - stored with the progress entry so a later reconnect can be resumed. - ``resume_offset`` continues an interrupted transfer from the byte the - receiver already holds: the file is read from there instead of its - first byte. + Returns: + bool: True when the receiver acknowledges the file; otherwise False. """ self._log(f"start to send file: {filename}") client_file_socket = None reset_time = 0 def close_socket(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket file_running = False @@ -4645,6 +5277,7 @@ def close_socket(): file_receive_data_from_server = "" def receive_file_transfer_messages(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket nonlocal file_receive_data_from_server @@ -4866,9 +5499,16 @@ def resume_transfers(self, peer=None): def _resume_receive_leg(self, control_socket, peer_addr, fid, entry, command): """Receive the rest of one interrupted transfer, appending to its file. + Args: + control_socket (socket.socket): Value used by the operation. + peer_addr (tuple): Value used by the operation. + fid (int): Value used by the operation. + entry (object): Value used by the operation. + command (object): Value used by the operation. + Returns: - bool: True when the sender was asked to continue, False when the - request could not be sent. + bool: True when the sender was asked to continue, False when the + request could not be sent. """ self._log(f"resume: continuing transfer {fid} with {peer_addr} into {entry[3]}") entry[0] = _resume_offset_for(entry) # the offset the sender is asked for @@ -4931,7 +5571,17 @@ def resume_trans(self, peer_addr, fid, offset): return True def _run_resume_send_leg(self, path, peer_addr, port, stamp, control_socket, fid, offset): - """Run one resumed sending leg on its own thread.""" + """Run one resumed sending leg on its own thread. + + Args: + path (str): Value used by the operation. + peer_addr (tuple): Value used by the operation. + port (int): Value used by the operation. + stamp (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + fid (int): Value used by the operation. + offset (int): Value used by the operation. + """ client_port = self.palloc() try: self.file_transfer_mode( @@ -4952,8 +5602,16 @@ def _resume_request(self, client_address, fid, offset): """Route one client's ``/resume_trans`` to the transfer it names. The fid identifies either this server's own outbound leg to that - client, or a target leg of a forward relay — the relay record then - names the originator, which is asked to re-forward to this client. + client, or a target leg of a forward relay — the relay record then + names the originator, which is asked to re-forward to this client. + + Args: + client_address (tuple): Value used by the operation. + fid (int): Value used by the operation. + offset (int): Value used by the operation. + + Returns: + object: Result produced by the operation. """ with self._forward_relays_lock: record = self._forward_resume_records.get(fid) @@ -4972,9 +5630,17 @@ def _route_forward_resume(self, record, target_addr, offset): """Ask a forwarded transfer's originator to continue it for one target. The server only relays: the record of the dead relay names the - originating client, which re-drives the item to this target from the - offset the target already holds (``/forward_resume``). An originator - that is not back yet gets the request as soon as it reconnects. + originating client, which re-drives the item to this target from the + offset the target already holds (``/forward_resume``). An originator + that is not back yet gets the request as soon as it reconnects. + + Args: + record (object): Value used by the operation. + target_addr (object): Value used by the operation. + offset (int): Value used by the operation. + + Returns: + bool | object: Result produced by the operation. """ originator = record.get("originator") originator_fid = record.get("fid") @@ -5003,7 +5669,11 @@ def _route_forward_resume(self, record, target_addr, offset): return self.send_message(info["socket"], request) def _flush_pending_relay_resumes(self, client_address): - """Send the forwarded-resume requests that waited for this originator.""" + """Send the forwarded-resume requests that waited for this originator. + + Args: + client_address (tuple): Value used by the operation. + """ with self._forward_relays_lock: pending = self._pending_relay_resumes.pop(tuple(client_address), None) if not pending: @@ -5019,7 +5689,11 @@ def _flush_pending_relay_resumes(self, client_address): ) def _resume_after_connect(self, client_address): - """Continue this peer's interrupted transfers after it (re)connected.""" + """Continue this peer's interrupted transfers after it (re)connected. + + Args: + client_address (tuple): Value used by the operation. + """ self._drop_stale_transfers(peer=tuple(client_address)) self._flush_pending_relay_resumes(tuple(client_address)) self.resume_transfers(peer=tuple(client_address)) @@ -5027,17 +5701,36 @@ def _resume_after_connect(self, client_address): # ---- native in-memory forward relay (server side) ---------------------- def _forward_alloc_fid(self): + """Handle the operation. + + Returns: + object: Result produced by the operation. + """ with self._forward_fid_lock: self._forward_fid += 1 return self._forward_fid def _forward_notify_error(self, sock, msg): + """Handle the operation. + + Args: + sock (object): Value used by the operation. + msg (object): Value used by the operation. + """ try: self.send_message(sock, f"/forward_error {msg}") except Exception: pass def _forward_parse_items_addrs(self, tokens): + """Handle the operation. + + Args: + tokens (list | dict): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ items = [] addrs = [] for token in tokens: @@ -5059,10 +5752,15 @@ def _forward_item_handler(self, sock, addr, cmd): """Server-side entry for /forward_item [resume=] <...> . The server never touches disk: it only relays the uploaded byte - stream to every reachable target client from memory. ``resume=`` - marks a repeated forward of a file the target already holds partially: - the uploader starts at that offset, so the relay expects - ``size - offset`` bytes of stream. + stream to every reachable target client from memory. ``resume=`` + marks a repeated forward of a file the target already holds partially: + the uploader starts at that offset, so the relay expects + ``size - offset`` bytes of stream. + + Args: + sock (object): Value used by the operation. + addr (tuple): Value used by the operation. + cmd (object): Value used by the operation. """ try: parts = shlex.split(cmd) @@ -5125,8 +5823,17 @@ def _forward_item_handler(self, sock, addr, cmd): def _forward_read_sign(self, sock, sign, timeout=15): """Read from a target transfer socket until ``sign`` is seen. - Reads through `receive_message`, so a framed transfer connection - yields decrypted bytes here like any other plaintext leg.""" + Reads through `receive_message`, so a framed transfer connection + yields decrypted bytes here like any other plaintext leg. + + Args: + sock (object): Value used by the operation. + sign (object): Value used by the operation. + timeout (float): Value used by the operation. + + Returns: + bool: Result produced by the operation. + """ buf = b"" target = sign.encode("utf-8") err = self.error_sign.encode("utf-8") @@ -5146,6 +5853,18 @@ def _forward_read_sign(self, sock, sign, timeout=15): return False def _forward_recv_exact(self, sock, n): + """Handle the operation. + + Args: + sock (object): Value used by the operation. + n (int): Value used by the operation. + + Returns: + object: Result produced by the operation. + + Raises: + ConnectionError: When the operation cannot complete. + """ buf = b"" while len(buf) < n: data = self.receive_message(sock, n - len(buf)) @@ -5158,8 +5877,16 @@ def _handle_pause_command(self, client_address, command, paused): """Apply a client's ``/pause_trans``/``/start_trans`` on this side. A client throttles the writer that feeds it (a forward relay's writer - for its target) or, without a relay, this server's own outbound leg to - that client (see `pause_trans`). + for its target) or, without a relay, this server's own outbound leg to + that client (see `pause_trans`). + + Args: + client_address (tuple): Value used by the operation. + command (object): Value used by the operation. + paused (bool): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ fid = _pause_command_fid(command) if fid is None: @@ -5178,10 +5905,21 @@ def _forward_relay( resume_offset=0, ): """Relay one file/folder item to every target, streaming from the + uploader's transfer connection with bounded in-memory buffering. - Every pushed command is tagged with the originator's address (see - ``forward_item_to``) so the receivers can attribute the transfer. + Every pushed command is tagged with the originator's address (see + ``forward_item_to``) so the receivers can attribute the transfer. + + Args: + forwarder_sock (object): Value used by the operation. + originator_addr (tuple): Value used by the operation. + kind (object): Value used by the operation. + rel_dir (str): Value used by the operation. + fname (object): Value used by the operation. + targets (object): Value used by the operation. + destination_path (str): Value used by the operation. + resume_offset (object): Value used by the operation. """ fid = self._forward_alloc_fid() tfids = [self._forward_alloc_fid() for _ in targets] @@ -5291,14 +6029,23 @@ def _forward_pump( """Pump the uploader's byte stream to every target from memory. The total bytes held in the per-target queues never exceeds - ``max_mem_buff``: once it does, the uploader is told to pause - (``/pause_trans``) and the reader stops pulling; as the writers - drain below the low-water mark the uploader is resumed - (``/start_trans``). + ``max_mem_buff``: once it does, the uploader is told to pause + (``/pause_trans``) and the reader stops pulling; as the writers + drain below the low-water mark the uploader is resumed + (``/start_trans``). + + Args: + up_sock (object): Value used by the operation. + target_conns (object): Value used by the operation. + forwarder_sock (object): Value used by the operation. + fid (int): Value used by the operation. + fname (object): Value used by the operation. + relay (object): Value used by the operation. + resume_offset (object): Value used by the operation. Returns: - int: Targets that acknowledged the whole item (they are the ones - the relay's resume record can be dropped for). + int: Targets that acknowledged the whole item (they are the ones + the relay's resume record can be dropped for). """ max_bytes = max(1, self.max_mem_buff) low_water = max(1, max_bytes // 2) @@ -5310,6 +6057,11 @@ def _forward_pump( result = {"ok": 0} def enqueue(chunk): + """Handle the operation. + + Args: + chunk (bytes | str): Value used by the operation. + """ with cond: state["buffered"] += len(chunk) * len(target_conns) for q in queues.values(): @@ -5322,6 +6074,13 @@ def enqueue(chunk): pass def writer(tfid, target, sock): + """Handle the operation. + + Args: + tfid (int): Value used by the operation. + target (tuple): Value used by the operation. + sock (object): Value used by the operation. + """ q = queues[tfid] while True: with cond: @@ -5355,6 +6114,7 @@ def writer(tfid, target, sock): pass def reader(): + """Handle the operation.""" try: name_len_b = self._forward_recv_exact(up_sock, 4) name_len = int.from_bytes(name_len_b, "big") @@ -5471,10 +6231,10 @@ async def _accept_clients_async(self): """Accept clients until the server stops, one coroutine per client. Runs the whole client side on one event loop: the listening socket is - used in non-blocking mode, and every accepted connection is handled by - `handle_client` on this loop, so the connection count is bounded only by - the file-descriptor limit. `stop` completes ``_async_wakeup`` to release - the loop; its remaining client coroutines are cancelled when it ends. + used in non-blocking mode, and every accepted connection is handled by + `handle_client` on this loop, so the connection count is bounded only by + the file-descriptor limit. `stop` completes ``_async_wakeup`` to release + the loop; its remaining client coroutines are cancelled when it ends. """ loop = asyncio.get_running_loop() self._async_loop = loop @@ -5793,6 +6553,7 @@ def __init__( the connection are persisted to the protocol's ``.Flow`` directory and read back on the next connect. Defaults to False: a dropped connection ends the client. + Raises: ValueError: If ``is_wait_server`` is True and ``timeout`` is not None. OSError: If the ``.Flow`` directories or ``decode_command_table.json`` @@ -6084,6 +6845,12 @@ def remove_file_listener(self, listener): pass def _notify_message_received(self, sender, message): + """Handle the operation. + + Args: + sender (object): Value used by the operation. + message (object): Value used by the operation. + """ with self._event_listeners_lock: listeners = list(self._message_listeners) for listener in listeners: @@ -6094,6 +6861,14 @@ def _notify_message_received(self, sender, message): self._log_exc() def _notify_file_received(self, full_path, name, size, command): + """Handle the operation. + + Args: + full_path (str): Value used by the operation. + name (object): Value used by the operation. + size (int): Value used by the operation. + command (object): Value used by the operation. + """ with self._event_listeners_lock: listeners = list(self._file_listeners) for listener in listeners: @@ -6107,8 +6882,14 @@ def _socket_key(self, sock): """Serializable key for a sender socket (its peer address). Forwarded records already carry the originator's address as a - string and are used as-is; a socket that cannot answer - ``getpeername`` (already closed) falls back to its repr. + string and are used as-is; a socket that cannot answer + ``getpeername`` (already closed) falls back to its repr. + + Args: + sock (object): Value used by the operation. + + Returns: + object: Result produced by the operation. """ if isinstance(sock, str): return sock @@ -6122,20 +6903,33 @@ def _remember_socket_key(self, sock): """Capture the log key of ``sock`` while it is known to be alive. A record stays buffered after its connection goes away, and the - flush that persists it must still file it under the sender's - address: by then the closed socket no longer answers - ``getpeername`` and would be logged as ``str(sock)``. The key is - forgotten once nothing is buffered under it any more (see - ``_flush_dict_locked``). + flush that persists it must still file it under the sender's + address: by then the closed socket no longer answers + ``getpeername`` and would be logged as ``str(sock)``. The key is + forgotten once nothing is buffered under it any more (see + ``_flush_dict_locked``). + + Args: + sock (object): Value used by the operation. """ with self._socket_keys_lock: if sock not in self._socket_keys: self._socket_keys[sock] = self._socket_key(sock) def _record_key(self, sock): - """The JSON-log key for ``sock``: the address captured when it was + """Return the JSON-log key for ``sock``: the address captured when it was. + + The JSON-log key for ``sock``: the address captured when it was + recorded, or the live peer address for a socket inserted without a - record.""" + record. + + Args: + sock (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ key = self._socket_keys.get(sock) if key is not None: return key @@ -6145,8 +6939,12 @@ def _record_message(self, sock, content): """Store one inbound plain-text message under the sender's socket. External code reads ``messages_dict`` (or the JSON log) instead of - registering a message listener. The entry is ``[content, timestamp]`` - with the timestamp of arrival. + registering a message listener. The entry is ``[content, timestamp]`` + with the timestamp of arrival. + + Args: + sock (object): Value used by the operation. + content (object): Value used by the operation. """ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with self._messages_dict_lock: @@ -6162,10 +6960,14 @@ def _record_event(self, sock, command): """Store one inbound command as an event under the sender's socket. The event content is the original wire command from the peer (file - transfers, folder transfers, extension commands, ...). External code - reads ``events_dict`` (or the JSON log) instead of registering a - listener. File-transfer events get their completion timestamp via - ``_update_event_timestamp``. + transfers, folder transfers, extension commands, ...). External code + reads ``events_dict`` (or the JSON log) instead of registering a + listener. File-transfer events get their completion timestamp via + ``_update_event_timestamp``. + + Args: + sock (object): Value used by the operation. + command (object): Value used by the operation. """ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") with self._events_dict_lock: @@ -6179,8 +6981,13 @@ def _update_event_timestamp(self, sock, command, timestamp): """Stamp the completion time onto the recorded event for ``command``. File transfers finish on a worker thread after the receive thread - recorded the command, so the event's timestamp is refreshed here with - the moment the transfer actually completed. + recorded the command, so the event's timestamp is refreshed here with + the moment the transfer actually completed. + + Args: + sock (object): Value used by the operation. + command (object): Value used by the operation. + timestamp (object): Value used by the operation. """ with self._events_dict_lock: entries = self.events_dict.get(sock) @@ -6194,10 +7001,17 @@ def _splice_event_command(self, command, **parts): """Return the command to record as an event. The wire command is recorded verbatim whenever it is available. When - this end cannot see the original command (a transfer relayed by the - server, or a protocol-internal control line), splice a readable - command from the available parts so the event still identifies the - transfer. + this end cannot see the original command (a transfer relayed by the + server, or a protocol-internal control line), splice a readable + command from the available parts so the event still identifies the + transfer. + + Args: + command (object): Value used by the operation. + **parts (list | dict): Value used by the operation. + + Returns: + object: Result produced by the operation. """ if command: return command @@ -6214,7 +7028,14 @@ def _splice_event_command(self, command, **parts): def _flush_dict_locked(self, d, size_attr, path): """Flush ``d`` (socket -> [[content, ts], ...]) into its JSON log and - clear it. The caller must hold the dict's lock.""" + + clear it. The caller must hold the dict's lock. + + Args: + d (list | dict): Value used by the operation. + size_attr (object): Value used by the operation. + path (str): Value used by the operation. + """ if not d: return snapshot = dict(d) @@ -6228,12 +7049,14 @@ def _flush_dict_locked(self, d, size_attr, path): self._socket_keys.pop(sock, None) def _flush_messages_dict(self): + """Handle the operation.""" with self._messages_dict_lock: self._flush_dict_locked( self.messages_dict, "_messages_dict_size", self.messages_log_file ) def _flush_events_dict(self): + """Handle the operation.""" with self._events_dict_lock: self._flush_dict_locked(self.events_dict, "_events_dict_size", self.events_log_file) @@ -6241,10 +7064,14 @@ def _merge_json_log(self, path, snapshot): """Merge ``snapshot`` into the JSON log at ``path`` (append per socket). Publishes through `_publish_json_log`: a temp file named after this - writer, and an optimistic re-merge when another instance published in - between, so concurrent flushes of several instances sharing one log - neither corrupt nor lose each other. A failure is logged, never raised - into the caller. + writer, and an optimistic re-merge when another instance published in + between, so concurrent flushes of several instances sharing one log + neither corrupt nor lose each other. A failure is logged, never raised + into the caller. + + Args: + path (str): Value used by the operation. + snapshot (list | dict): Value used by the operation. """ try: _publish_json_log(path, snapshot, self._record_key) @@ -6294,20 +7121,18 @@ def _measure_network_speed(self, payload, is_upload): """Fold just-sent/received traffic into the real-time speed estimate. Every send and receive sample feeds this — control messages, file data - and relay traffic alike — so the speed attributes describe the - instance's current traffic as a rolling average over - ``NETWORK_SPEED_WINDOW`` seconds. + and relay traffic alike — so the speed attributes describe the + instance's current traffic as a rolling average over + ``NETWORK_SPEED_WINDOW`` seconds. Args: - payload (bytes | str | int): Bytes just written or read; a str - counts as its UTF-8 length, an int is a byte count already. - is_upload (bool): True for sent bytes (``upload_network_speed``), - False for received ones (``recv_network_speed``). + payload (bytes | str | int): Bytes just written or read; a str counts as its UTF-8 length, an int is a byte count already. + is_upload (bool): True for sent bytes (``upload_network_speed``), False for received ones (``recv_network_speed``). Returns: - float | None: The refreshed speed in bytes per second, or None when - ``is_enable_real_time_network_speed`` is False; both speed - attributes are None then. + float | None: The refreshed speed in bytes per second, or None when + ``is_enable_real_time_network_speed`` is False; both speed + attributes are None then. """ if not self.is_enable_real_time_network_speed: self.upload_network_speed = None @@ -6351,25 +7176,17 @@ def _file_progress_start(self, progress_dict, fid, total_bytes, path, peer=None, """Register one file transfer in a progress store. Args: - progress_dict (dict): ``self.file_recv_progress`` for an inbound - transfer, ``self.file_upload_progress`` for an outbound one. - fid (int | None): The transfer's fid; None tracks nothing (a leg - without a protocol transfer id, such as a key push). + progress_dict (dict): ``self.file_recv_progress`` for an inbound transfer, ``self.file_upload_progress`` for an outbound one. + fid (int | None): The transfer's fid; None tracks nothing (a leg without a protocol transfer id, such as a key push). total_bytes (int): Size of the file being transferred. - path (str): Local path of the file: the source of an outbound - transfer, the file being written for an inbound one. - peer (tuple | None): ``(ip, port)`` of the transfer's original - peer — the sender for an inbound transfer, the receiver for an - outbound one. A forwarded transfer stores the original peer on - both sides, never the relay; None marks a leg that cannot be - resumed (there is no peer to continue it with). - initial (int): Bytes already transferred when the leg starts; a - resumed transfer continues a partially transferred file. + path (str): Local path of the file: the source of an outbound transfer, the file being written for an inbound one. + peer (tuple | None): ``(ip, port)`` of the transfer's original peer — the sender for an inbound transfer, the receiver for an outbound one. A forwarded transfer stores the original peer on both sides, never the relay; None marks a leg that cannot be resumed (there is no peer to continue it with). + initial (int): Bytes already transferred when the leg starts; a resumed transfer continues a partially transferred file. Returns: - list | None: The ``[transferred, total, speed, path, peer]`` entry - the transfer updates, or None when tracking is off - (``is_enable_file_transfer_progress_bar`` False, or no fid). + list | None: The ``[transferred, total, speed, path, peer]`` entry + the transfer updates, or None when tracking is off + (``is_enable_file_transfer_progress_bar`` False, or no fid). """ if fid is None or not self.is_enable_file_transfer_progress_bar: return None @@ -6383,13 +7200,9 @@ def _file_progress_update(self, entry, byte_count, is_upload): """Fold one transferred chunk into a progress entry. Args: - entry (list | None): Entry from `_file_progress_start`, or None - when the transfer is not tracked. + entry (list | None): Entry from `_file_progress_start`, or None when the transfer is not tracked. byte_count (int): Bytes of the chunk just sent or received. - is_upload (bool): True for sent chunks, False for received ones. - - The speed slot mirrors the live measurement, so it stays None while - ``is_enable_real_time_network_speed`` is False. + is_upload (bool): True for sent chunks, False for received ones. The speed slot mirrors the live measurement, so it stays None while ``is_enable_real_time_network_speed`` is False. """ if entry is None: return @@ -6400,17 +7213,16 @@ def _file_progress_finish(self, progress_dict, fid, entry, keep=False): """Drop a finished transfer's progress entry, or keep it for a resume. A newer transfer may already hold the same fid (transfer ids are reused - as transfers end), so only this transfer's own entry is dropped. With - ``keep`` True an interrupted transfer keeps its entry — and the partial - file that entry points at — so the reconnect logic can continue it - (`resume_transfers`); the entry then lives until the transfer ends. + as transfers end), so only this transfer's own entry is dropped. With + ``keep`` True an interrupted transfer keeps its entry — and the partial + file that entry points at — so the reconnect logic can continue it + (`resume_transfers`); the entry then lives until the transfer ends. Args: progress_dict (dict): Store the entry belongs to. fid (int | None): Transfer id the entry is keyed by. entry (list | None): Entry to drop; None tracks nothing. - keep (bool): Keep the entry (and persist the stores) instead of - dropping it. Defaults to False. + keep (bool): Keep the entry (and persist the stores) instead of dropping it. Defaults to False. """ if entry is None: return @@ -6434,11 +7246,19 @@ def _transfer_progress_snapshot(self): """Return the JSON-ready form of every transfer still in play. Returns: - dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids - are string keys and every peer is an ``[ip, port]`` list. + dict: ``{"upload": ..., "download": ..., "relays": ...}``; fids + are string keys and every peer is an ``[ip, port]`` list. """ def entries(store): + """Handle the operation. + + Args: + store (list | dict): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ return { str(fid): [ entry[0], @@ -6473,12 +7293,12 @@ def _persist_transfer_progress(self): """Write the transfer stores to the protocol's ``.Flow`` directory. Every in-flight transfer — uploads, downloads, and the relay records - of the forwards this client started — is written to - ``client_file_trans_progress.json`` when a connection drops, and the - file is what the reconnect logic reads back. Once nothing is left to - transfer the file is emptied; it is only rewritten while it exists, so - a run without an interrupted transfer never creates it. A write - failure is logged, never raised. + of the forwards this client started — is written to + ``client_file_trans_progress.json`` when a connection drops, and the + file is what the reconnect logic reads back. Once nothing is left to + transfer the file is emptied; it is only rewritten while it exists, so + a run without an interrupted transfer never creates it. A write + failure is logged, never raised. """ snapshot = self._transfer_progress_snapshot() with self._transfer_progress_lock: @@ -6500,12 +7320,12 @@ def _load_transfer_progress(self): """Read the persisted interrupted transfers back into the stores. Every entry read back keeps the bytes it had already transferred, so - the reconnect logic can ask the sender to continue from there; every - relay record comes back so an interrupted forward can be re-driven. - Entries a live transfer (or a relay) already owns are left alone. + the reconnect logic can ask the sender to continue from there; every + relay record comes back so an interrupted forward can be re-driven. + Entries a live transfer (or a relay) already owns are left alone. Returns: - int: Number of transfer entries and relay records restored. + int: Number of transfer entries and relay records restored. """ with self._transfer_progress_lock: try: @@ -6554,8 +7374,13 @@ def _load_transfer_progress(self): def _mark_transfer_pause(self, fid, paused, peer=None): """Set or clear one transfer's pause switch (see `pause_trans`). + Args: + fid (int): Value used by the operation. + paused (bool): Value used by the operation. + peer (tuple): Value used by the operation. + Returns: - bool: True when a running outbound leg was found. + bool: True when a running outbound leg was found. """ with self._transfer_progress_lock: live = fid in self._active_transfer_fids @@ -6639,14 +7464,24 @@ def start_trans_remote(self, peer, fid): return self.send_message(self.client_socket, f"/start_trans {fid}") def _register_transfer_socket(self, fid, sock): - """Record the socket of a leg, so a dead session can be cleared out.""" + """Record the socket of a leg, so a dead session can be cleared out. + + Args: + fid (int): Value used by the operation. + sock (object): Value used by the operation. + """ if fid is None: return with self._transfer_progress_lock: self._active_transfer_sockets[fid] = sock def _release_transfer_socket(self, fid, sock): - """Forget a leg's socket once the leg is over (its own, not a newer one's).""" + """Forget a leg's socket once the leg is over (its own, not a newer one's). + + Args: + fid (int): Value used by the operation. + sock (object): Value used by the operation. + """ if fid is None: return with self._transfer_progress_lock: @@ -6657,16 +7492,14 @@ def _drop_stale_transfers(self, peer=None): """Close the legs a peer's previous session left behind. A peer that (re)connects proves that the legs of its earlier session - are over: their sockets are shut down so the stored transfers can be - resumed without two legs writing the same transfer. + are over: their sockets are shut down so the stored transfers can be + resumed without two legs writing the same transfer. Args: - peer (tuple | None): Restrict to the legs whose progress entry - names this ``(ip, port)``; None clears every leg of the - instance (a fresh session replaces all of them). + peer (tuple | None): Restrict to the legs whose progress entry names this ``(ip, port)``; None clears every leg of the instance (a fresh session replaces all of them). Returns: - int: Number of legs closed. + int: Number of legs closed. """ stale = [] for store in (self.file_upload_progress, self.file_recv_progress): @@ -6694,8 +7527,11 @@ def _wait_transfer_paused(self, fid): """Block a sending leg while its fid is marked paused. Runs before every chunk so ``/pause_trans`` stops the stream without - closing the transfer; the wait ends when the leg is resumed, when the - instance stops, or when the fid is not paused at all. + closing the transfer; the wait ends when the leg is resumed, when the + instance stops, or when the fid is not paused at all. + + Args: + fid (int): Value used by the operation. """ if fid is None: return @@ -6713,8 +7549,8 @@ def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): timeout (float): Seconds to wait. Returns: - tuple | None: ``(port, stamp)`` announced for this fid, or None - when the announcement does not arrive in time. + tuple | None: ``(port, stamp)`` announced for this fid, or None + when the announcement does not arrive in time. """ deadline = time.time() + timeout while time.time() < deadline: @@ -6730,7 +7566,11 @@ def _wait_transfer_server_port(self, fid, timeout=RESUME_PORT_TIMEOUT): return None def _forget_transfer_port(self, fid): - """Drop pending port announcements of a fid an older session left behind.""" + """Drop pending port announcements of a fid an older session left behind. + + Args: + fid (int): Value used by the operation. + """ if fid is None: return with self.file_transfer_server_port_lock: @@ -6742,12 +7582,16 @@ def _wait_control_secure(self, control_socket, timeout=RESUME_SECURE_TIMEOUT): """Wait until a control channel may carry framed protocol lines. The reconnect flows run right after a session is established, when the - crypto handshake may still be completing; a resume line sent then would - travel plaintext and be dropped by the peer's framing guard. Without - encryption there is nothing to wait for. + crypto handshake may still be completing; a resume line sent then would + travel plaintext and be dropped by the peer's framing guard. Without + encryption there is nothing to wait for. + + Args: + control_socket (socket.socket): Value used by the operation. + timeout (float): Value used by the operation. Returns: - bool: True when the channel speaks frames (or encryption is off). + bool: True when the channel speaks frames (or encryption is off). """ if not self.is_enable_encrypto or self.crypto is None: return True @@ -7053,6 +7897,7 @@ def create_temporary_server(self, handler, port=None, max_connections=1): stop_event = threading.Event() def server_loop(): + """Handle the operation.""" while not stop_event.is_set(): try: server_socket.settimeout(1.0) @@ -7096,6 +7941,7 @@ def create_temporary_client(self, server_host, server_port, bind_port=None, on_d stop_event = threading.Event() def receiver(): + """Handle the operation.""" while not stop_event.is_set(): try: client_sock.settimeout(1.0) @@ -7118,8 +7964,11 @@ def _crypto_negotiate_mode(self): """Announce our encryption mode and wait for the server's. Returns True only when both sides agree on ``is_enable_encrypto``. - On a mismatch (or a missing announcement) the connection is - closed and False is returned. + On a mismatch (or a missing announcement) the connection is + closed and False is returned. + + Returns: + bool: Result produced by the operation. """ self._send_raw(self.client_socket, f"/crypto_mode {1 if self.is_enable_encrypto else 0}") if not self._crypto_mode_event.wait(timeout=self._crypto_mode_timeout): @@ -7425,7 +8274,12 @@ def receive_message(self, client_socket, msg_length): # receive msg return plain # plaintext mode: the line reader gets the bytes def _send_raw(self, client_socket, text): - """Send a plaintext crypto-protocol message, bypassing encryption.""" + """Send a plaintext crypto-protocol message, bypassing encryption. + + Args: + client_socket (socket.socket): Value used by the operation. + text (object): Value used by the operation. + """ data = text.strip() if not data.endswith("\n"): data += "\n" @@ -7434,25 +8288,54 @@ def _send_raw(self, client_socket, text): self._measure_network_speed(encoded, is_upload=True) def _crypto_mark_encrypted(self, client_socket, peer_role, peer_pem_path): + """Handle the operation. + + Args: + client_socket (socket.socket): Value used by the operation. + peer_role (object): Value used by the operation. + peer_pem_path (str): Value used by the operation. + """ with self._crypto_lock: self._encrypted_sockets.add(client_socket) self._crypto_peer[client_socket] = (peer_role, peer_pem_path) def _crypto_session_ensure(self): - """The client's crypto session context (created on demand).""" + """Get or create the client's crypto session. + + The client's crypto session context (created on demand). + + Returns: + object: Result produced by the operation. + """ with self._crypto_lock: if self._crypto_session is None and self.crypto is not None: self._crypto_session = _CryptoSession(self.crypto, "client", self._log, self._debug) return self._crypto_session def _crypto_control_state(self, client_socket): - """(session, channel) of one socket; (None, None) when unknown.""" + """Return (session, channel) of one socket; (None, None) when unknown. + + (session, channel) of one socket; (None, None) when unknown. + + Args: + client_socket (socket.socket): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ with self._crypto_lock: return self._crypto_session, self._channels.get(client_socket) def _crypto_channel_error(self, client_socket): - """A frame failed to decode: re-exchange on the control socket, close a - transfer socket (its leg has no handshake to recover with).""" + """Handle a frame decode failure on a control or transfer socket. + + A frame failed to decode: re-exchange on the control socket, close a + + transfer socket (its leg has no handshake to recover with). + + Args: + client_socket (socket.socket): Value used by the operation. + """ if client_socket is self.client_socket: self._crypto_on_decode_failure(client_socket) return @@ -7463,7 +8346,11 @@ def _crypto_channel_error(self, client_socket): pass def _crypto_after_flip(self, client_socket): - """Announce frame readiness (plaintext) and publish the session ECDH key.""" + """Announce frame readiness (plaintext) and publish the session ECDH key. + + Args: + client_socket (socket.socket): Value used by the operation. + """ _session, channel = self._crypto_control_state(client_socket) if channel is None: return @@ -7475,20 +8362,41 @@ def _crypto_after_flip(self, client_socket): self._crypto_publish_ecdh_pub(client_socket) def _crypto_publish_ecdh_pub(self, client_socket): - """Send our session ECDH public key once frames are allowed both ways.""" + """Send our session ECDH public key once frames are allowed both ways. + + Args: + client_socket (socket.socket): Value used by the operation. + """ session, channel = self._crypto_control_state(client_socket) if session is not None: session.publish_pub(channel) def _crypto_transfer_stamp(self, control_socket, force_plain=False): - """Mode+nonce a listener announces to a transfer connector.""" + """Mode+nonce a listener announces to a transfer connector. + + Args: + control_socket (socket.socket): Value used by the operation. + force_plain (bool): Value used by the operation. + + Returns: + object | str: Result produced by the operation. + """ session, channel = self._crypto_control_state(control_socket) if session is None: return "plain" return session.transfer_stamp(channel, force_plain) def _crypto_attach_transfer_in(self, sock, control_socket, stamp): - """Framing channel for an accepted transfer socket (listener side).""" + """Framing channel for an accepted transfer socket (listener side). + + Args: + sock (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ session, control_channel = self._crypto_control_state(control_socket) if session is None: return None @@ -7500,18 +8408,37 @@ def _crypto_attach_transfer_in(self, sock, control_socket, stamp): return channel def _crypto_drop_secure(self, client_socket): - """Framing stopped: keep the secure-socket set and peer map truthful.""" + """Framing stopped: keep the secure-socket set and peer map truthful. + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: self._encrypted_sockets.discard(client_socket) self._crypto_peer.pop(client_socket, None) def _crypto_note_healthy(self, client_socket): - """A frame decoded cleanly: reset the streak that feeds the breaker.""" + """Reset the decode-failure count after a valid frame. + + A frame decoded cleanly: reset the streak that feeds the breaker. + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: self._crypto_decode_failures = 0 def _crypto_attach_transfer_out(self, sock, control_socket, stamp): - """Framing channel for a connected transfer socket (connector side).""" + """Framing channel for a connected transfer socket (connector side). + + Args: + sock (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + stamp (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ session, control_channel = self._crypto_control_state(control_socket) crypto = _connector_transfer_crypto(session, control_channel, stamp) channel = _enable_connector_channel(sock, crypto) @@ -7522,18 +8449,27 @@ def _crypto_attach_transfer_out(self, sock, control_socket, stamp): return channel def _crypto_drop_channel(self, sock): - """Forget a finished transfer socket's channel.""" + """Forget a finished transfer socket's channel. + + Args: + sock (object): Value used by the operation. + """ with self._crypto_lock: self._channels.pop(sock, None) self._encrypted_sockets.discard(sock) def _crypto_on_decode_failure(self, client_socket): """Decryption failed (stale/wrong key): drop encryption, reload + our own key and re-run the public-key exchange (forced). - A circuit breaker closes the connection after - ``MAX_DECODE_FAILURES`` consecutive failures, so a garbage or - persistent-mismatch storm cannot spin the loop forever.""" + A circuit breaker closes the connection after + ``MAX_DECODE_FAILURES`` consecutive failures, so a garbage or + persistent-mismatch storm cannot spin the loop forever. + + Args: + client_socket (socket.socket): Value used by the operation. + """ with self._crypto_lock: channel = self._channels.get(client_socket) if channel is not None: @@ -7575,12 +8511,28 @@ def _crypto_start_exchange(self): threading.Thread(target=self._crypto_exchange_thread, daemon=True).start() def _crypto_still_current(self, gen): - """True while ``gen`` is still the latest handshake generation.""" + """Return true while ``gen`` is still the latest handshake generation. + + True while ``gen`` is still the latest handshake generation. + + Args: + gen (object): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._crypto_lock: return self._crypto_handshake_gen == gen def _crypto_exchange_thread(self, force=False): - """Drive the client half of the handshake to completion.""" + """Drive the client half of the handshake to completion. + + Args: + force (bool): Value used by the operation. + + Raises: + TimeoutError: When the operation cannot complete. + """ try: self.crypto.ensure_keys() session = self._crypto_session_ensure() @@ -7632,8 +8584,14 @@ def _crypto_exchange_thread(self, force=False): def _crypto_on_server_hello(self, server_nonce, force): """Server initiated the handshake (re-exchange after a decode + failure): record its session nonce, ack that we need its key - (every connection re-exchanges), then run our half.""" + (every connection re-exchanges), then run our half. + + Args: + server_nonce (object): Value used by the operation. + force (bool): Value used by the operation. + """ with self._crypto_lock: self._crypto_force = force self._crypto_server_nonce = server_nonce @@ -7650,8 +8608,10 @@ def _crypto_on_server_hello(self, server_nonce, force): def _crypto_try_flip(self): """Flip to framed encryption only when the server key passed the + TOFU check and both sides announced readiness (no plaintext/framed - interleaving).""" + interleaving). + """ with self._crypto_send_lock: # no send may interleave with the flip with self._crypto_lock: if not ( @@ -7677,13 +8637,24 @@ def _crypto_try_flip(self): @staticmethod def _crypto_fresh_nonce(): + """Handle the operation. + + Returns: + object: Result produced by the operation. + """ return secrets.token_hex(16) def _crypto_after_ack(self, server_needs, force): """Server replied to our hello: push our key and request the + server's key (if it needs us to), then signal the exchange - thread. Runs under ``_crypto_lock`` so a concurrent handshake - cannot interleave (no-GIL safe).""" + thread. Runs under ``_crypto_lock`` so a concurrent handshake + cannot interleave (no-GIL safe). + + Args: + server_needs (object): Value used by the operation. + force (bool): Value used by the operation. + """ with self._crypto_lock: gen = self._crypto_handshake_gen need_push = force or server_needs == "1" @@ -7700,6 +8671,7 @@ def _crypto_after_ack(self, server_needs, force): self._send_raw(self.client_socket, "/crypto_pub_key_request") def _wait_done(): + """Handle the operation.""" with self._crypto_lock: pub_event = self._crypto_server_pub_event if not pub_event.wait(timeout=90): @@ -7730,7 +8702,12 @@ def _wait_done(): def _crypto_push_pub_key(self): """Push our public key file to the server via the file-transfer - mechanism (client is the sender).""" + + mechanism (client is the sender). + + Returns: + bool: Result produced by the operation. + """ while ( True ): # serialise pushes: wait for a concurrent push (double handshake) instead of skipping it @@ -7781,9 +8758,15 @@ def _crypto_push_pub_key(self): def _crypto_store_received_pub(self, full_path, peer_role, server_addr): """TOFU-check the server's public key received via the file + transfer mechanism and cache it under the server endpoint. - On failure the connection is rejected and closed. + On failure the connection is rejected and closed. + + Args: + full_path (str): Value used by the operation. + peer_role (object): Value used by the operation. + server_addr (tuple): Value used by the operation. """ if self.crypto is None: return @@ -8013,8 +8996,14 @@ def _console_forward_send_msg(self, command): """Client console entry point for ``/forward_send_msg`` (client-only). The forwarding command is only meaningful on a client: it parses the - typed request and asks the server (which runs the same-named relay) - to push each message to every listed destination. + typed request and asks the server (which runs the same-named relay) + to push each message to every listed destination. + + Args: + command (object): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ parts = shlex.split(command) items, addrs = parse_forward_items_and_addrs(parts[1:]) @@ -8046,6 +9035,17 @@ def forward_messages(self, messages, addrs): return self.send_message(self.client_socket, request) def _execute_custom_handler(self, handler, command, client_socket=None, client_address=None): + """Handle the operation. + + Args: + handler (callable): Value used by the operation. + command (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + client_address (tuple): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. + """ try: result = handler(client_socket, client_address, command) if result is not None: @@ -8151,6 +9151,11 @@ def interactive_mode(self): # Interactive mode self.close() def multiple_folder_file_transfer_client_recv_client_start(self, message): + """Start folder transfers for each path in a client command. + + Args: + message (object): Value used by the operation. + """ transfer_folder_file_list = shlex.split(message)[1:] destination_path = None if len(transfer_folder_file_list) >= 2 and not os.path.isdir(transfer_folder_file_list[-1]): @@ -8167,6 +9172,11 @@ def multiple_folder_file_transfer_client_recv_client_start(self, message): folder_file_transfer_client_recv_client_start_thread.start() def folder_file_transfer_client_recv_client_start(self, message): + """Send a folder's contents to the connected server. + + Args: + message (object): Value used by the operation. + """ command_part = shlex.split(message) folder_path = command_part[1] destination_path = command_part[2] if len(command_part) >= 3 else None @@ -8176,6 +9186,12 @@ def folder_file_transfer_client_recv_client_start(self, message): base_path = os.path.dirname(folder_path) def get_relative_path(base_path, abs_path): + """Handle the operation. + + Args: + base_path (str): Value used by the operation. + abs_path (str): Value used by the operation. + """ base = os.path.normpath(base_path) abs_ = os.path.normpath(abs_path) common = os.path.commonpath([base, abs_]) @@ -8188,6 +9204,13 @@ def get_relative_path(base_path, abs_path): return "/" + rel def send_folder_transfer_command(folder_path, file_name=None, abspath=None): + """Handle the operation. + + Args: + folder_path (str): Value used by the operation. + file_name (str): Value used by the operation. + abspath (str): Value used by the operation. + """ folder_transfer_command_message = "/file_folder {}".format(shlex.quote(folder_path)) if file_name: each_file_transfer_command_message = "/file_folder {} {}".format( @@ -8208,11 +9231,19 @@ def send_folder_transfer_command(folder_path, file_name=None, abspath=None): self._log(f"start to send folder command: {folder_transfer_command_message}") def start_file_transfer_with_limit(rel_dir, file, root): + """Handle the operation. + + Args: + rel_dir (str): Value used by the operation. + file (str): Value used by the operation. + root (object): Value used by the operation. + """ cmd = f"/file_folder {shlex.quote(rel_dir)} {shlex.quote(file)}" if destination_path: cmd += " {}".format(shlex.quote(destination_path)) def limited_transfer(): + """Handle the operation.""" self.file_semaphore.acquire() try: self.file_transfer_client_recv_client_start(cmd, root) @@ -8224,6 +9255,7 @@ def limited_transfer(): self._log(f"start to send file: {cmd} (limit {self.max_thread_num})") def get_all_files_in_folder(): + """Handle the operation.""" for root, dirs, files in os.walk(folder_path): rel_dir = get_relative_path(base_path, root) if root != folder_path: @@ -8237,6 +9269,11 @@ def get_all_files_in_folder(): get_all_files_in_folder() def multiple_file_transfer_client_recv_client_start(self, message): + """Start file transfers for each path in a client command. + + Args: + message (object): Value used by the operation. + """ file_list = shlex.split(message)[1:] destination_path = None if len(file_list) >= 2 and not os.path.isfile(file_list[-1]): @@ -8259,6 +9296,12 @@ def limited_transfer(cmd=each_file_transfer_command_message): self._log(f"start to send file command: {each_file_transfer_command_message}") def file_transfer_client_recv_client_start_thread(self, message, file_folder_abspath=None): + """Start a thread to send a file or folder item to the server. + + Args: + message (object): Value used by the operation. + file_folder_abspath (str): Value used by the operation. + """ file_transfer_client_recv_client_start_thread = threading.Thread( target=self.file_transfer_client_recv_client_start, args=(message, file_folder_abspath), @@ -8267,6 +9310,12 @@ def file_transfer_client_recv_client_start_thread(self, message, file_folder_abs file_transfer_client_recv_client_start_thread.start() def file_transfer_client_recv_client_start(self, message, file_folder_abspath): + """Send a file or folder item to the connected server. + + Args: + message (object): Value used by the operation. + file_folder_abspath (str): Value used by the operation. + """ client_id = None with self.file_client_id_lock: client_id = copy.copy(self.file_client_id) @@ -8330,27 +9379,26 @@ def file_transfer_mode( # noqa: PLR0911 - peer-close and timeout exits are dist ): """Send one file over a transfer sub-connection. - ``control_socket``/``crypto`` carry the listener's mode stamp - ("plain" or "enc:"): an encrypted leg aborts when the session - key material is missing rather than downgrading silently. - - ``fid`` is the transfer's id — the caller's own transfer id for a plain - send, the relay id for a forwarded upload — and keys this leg in - ``file_upload_progress``; every leg with a fid can be paused with - ``/pause_trans`` for that fid. None (a leg without a protocol transfer - id, such as a public-key push) tracks no progress. + Args: + filename (str): Source file path. + server_address (str): Transfer listener address. + server_port (int): Transfer listener port. + client_port (int): Local port to bind for the transfer. + control_socket (socket.socket | None): Control socket carrying the mode stamp. + crypto (str | None): ``"plain"`` or encrypted transfer stamp. + fid (int | None): Transfer ID used for progress and pause tracking. + peer (tuple | None): Original receiver ``(ip, port)`` for resuming. + resume_offset (int): Byte offset to resume from; defaults to zero. - ``peer`` is the transfer's original receiver (the target of a forward, - never the relay): it is stored with the progress entry so a later - reconnect can be resumed. ``resume_offset`` continues an interrupted - transfer from the byte the receiver already holds: the file is read - from there instead of its first byte. + Returns: + bool: True when the receiver acknowledges the file; otherwise False. """ self._log(f"start to send file: {filename}") client_file_socket = None reset_time = 0 def close_socket(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket file_running = False @@ -8386,6 +9434,7 @@ def close_socket(): file_receive_data_from_server = "" def receive_file_transfer_messages(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket nonlocal file_receive_data_from_server @@ -8601,8 +9650,16 @@ def _request_forward_resume(self, fid, entry, originator): """Ask the server to have a forward's originator continue a transfer. The local path is registered before the request goes out: the fresh - relay leg arrives under a new fid but writes the same path, and - `_take_pending_resume` hands its offset to that leg. + relay leg arrives under a new fid but writes the same path, and + `_take_pending_resume` hands its offset to that leg. + + Args: + fid (int): Value used by the operation. + entry (object): Value used by the operation. + originator (object): Value used by the operation. + + Returns: + bool: Result produced by the operation. """ offset = _resume_offset_for(entry) with self._forward_resume_lock: @@ -8621,10 +9678,16 @@ def _take_pending_resume(self, path): """Return the offset a pending resume of this path starts at, or None. A forward target that lost a transfer asks its originator to re-send - it; the fresh leg the server then pushes carries a new transfer id but - lands on the same path, so the state registered by the request is what - the leg appends from — and the interrupted entry it replaces is - dropped here. + it; the fresh leg the server then pushes carries a new transfer id but + lands on the same path, so the state registered by the request is what + the leg appends from — and the interrupted entry it replaces is + dropped here. + + Args: + path (str): Value used by the operation. + + Returns: + NoneType | object: Result produced by the operation. """ with self._forward_resume_lock: pending = self._resume_pending_paths.pop(path, None) @@ -8640,9 +9703,15 @@ def _take_pending_resume(self, path): def _resume_receive_leg(self, control_socket, peer_addr, fid, entry): """Receive the rest of one interrupted transfer, appending to its file. + Args: + control_socket (socket.socket): Value used by the operation. + peer_addr (tuple): Value used by the operation. + fid (int): Value used by the operation. + entry (object): Value used by the operation. + Returns: - bool: True when the sender was asked to continue, False when the - request could not be sent. + bool: True when the sender was asked to continue, False when the + request could not be sent. """ entry[0] = _resume_offset_for(entry) # the offset the sender is asked for self._log(f"resume: continuing transfer {fid} with {peer_addr} into {entry[3]}") @@ -8703,7 +9772,17 @@ def resume_trans(self, peer_addr, fid, offset): return True def _run_resume_send_leg(self, path, peer_addr, port, stamp, control_socket, fid, offset): - """Run one resumed sending leg on its own thread.""" + """Run one resumed sending leg on its own thread. + + Args: + path (str): Value used by the operation. + peer_addr (tuple): Value used by the operation. + port (int): Value used by the operation. + stamp (object): Value used by the operation. + control_socket (socket.socket): Value used by the operation. + fid (int): Value used by the operation. + offset (int): Value used by the operation. + """ client_port = self.palloc() try: self.file_transfer_mode( @@ -8721,7 +9800,14 @@ def _run_resume_send_leg(self, path, peer_addr, port, stamp, control_socket, fid self.pfree(client_port) def _forward_resume_record(self, fid): - """Return the relay record a forwarded resume for ``fid`` belongs to.""" + """Return the relay record a forwarded resume for ``fid`` belongs to. + + Args: + fid (int): Value used by the operation. + + Returns: + object: Result produced by the operation. + """ with self._forward_resume_lock: return self._forward_resume_records.get(fid) @@ -8729,9 +9815,9 @@ def _resume_forward(self, target, fid, offset): """Re-drive a forwarded transfer to one target, from ``offset``. Runs when the server relays a target's resume request - (``/forward_resume``): the recorded relay says what the transfer was, - so the item is forwarded again — only to the target that asked, and - only the remainder of the file it already holds partially. + (``/forward_resume``): the recorded relay says what the transfer was, + so the item is forwarded again — only to the target that asked, and + only the remainder of the file it already holds partially. Args: target (tuple): Target client ``(ip, port)`` that lost the file. @@ -8739,7 +9825,7 @@ def _resume_forward(self, target, fid, offset): offset (int): Byte offset the target already holds. Returns: - bool: True when the re-forward was started. + bool: True when the re-forward was started. """ record = self._forward_resume_record(fid) with self._forward_resume_lock: @@ -8773,6 +9859,14 @@ def _resume_forward(self, target, fid, offset): # ---- native in-memory forward (client side) ---------------------------- def _forward_parse(self, tokens): + """Handle the operation. + + Args: + tokens (list | dict): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. + """ items = [] addrs = [] for token in tokens: @@ -8794,7 +9888,13 @@ def _forward_parse_command(self, tokens): """Split forward console tokens into (items, addrs, destination_path). Files/folders come first and address tuples last; an optional - destination directory, when present, is the very last argument. + destination directory, when present, is the very last argument. + + Args: + tokens (list | dict): Value used by the operation. + + Returns: + list | tuple: Result produced by the operation. """ destination_path = None if tokens and not (tokens[-1].startswith("(") and tokens[-1].endswith(")")): @@ -8804,7 +9904,12 @@ def _forward_parse_command(self, tokens): return items, addrs, destination_path def forward_file_console(self, message): - """/forward_file ... ... [dest] (client only).""" + """Parse a client command and forward its files. + + Args: + message (str): ``/forward_file`` command with file paths, target address + tuples, and an optional destination directory. + """ parts = shlex.split(message) items, addrs, destination_path = self._forward_parse_command(parts[1:]) files = [p for p in items if os.path.isfile(p)] @@ -8823,7 +9928,12 @@ def forward_file_console(self, message): ).start() def forward_folder_console(self, message): - """/forward_folder ... ... [dest] (client only).""" + """Parse a client command and forward its folders. + + Args: + message (str): ``/forward_folder`` command with folder paths, target address + tuples, and an optional destination directory. + """ parts = shlex.split(message) items, addrs, destination_path = self._forward_parse_command(parts[1:]) folders = [p for p in items if os.path.isdir(p)] @@ -8842,6 +9952,14 @@ def forward_folder_console(self, message): ).start() def _forward_driver(self, items, addrs, folder_mode, destination_path=None): + """Handle the operation. + + Args: + items (list | dict): Value used by the operation. + addrs (list | dict): Value used by the operation. + folder_mode (bool): Value used by the operation. + destination_path (str): Value used by the operation. + """ try: if not folder_mode: for path in items: @@ -8867,6 +9985,15 @@ def _forward_driver(self, items, addrs, folder_mode, destination_path=None): self._log_exc() def _forward_rel_path(self, base_path, abs_path): + """Handle the operation. + + Args: + base_path (str): Value used by the operation. + abs_path (str): Value used by the operation. + + Returns: + object | str: Result produced by the operation. + """ base = os.path.normpath(base_path) abs_ = os.path.normpath(abs_path) common = os.path.commonpath([base, abs_]) @@ -8883,9 +10010,21 @@ def _forward_one( """Forward one item to every target through the server's relay. The relay the server answers with is recorded under its fid so a - target that lost the transfer can have it re-driven after a reconnect - (`_resume_forward`); ``resume_offset`` re-sends only the remainder of - a file the target already holds partially. + target that lost the transfer can have it re-driven after a reconnect + (`_resume_forward`); ``resume_offset`` re-sends only the remainder of + a file the target already holds partially. + + Args: + kind (object): Value used by the operation. + rel_dir (str): Value used by the operation. + fname (object): Value used by the operation. + abspath (str): Value used by the operation. + addrs (list | dict): Value used by the operation. + destination_path (str): Value used by the operation. + resume_offset (object): Value used by the operation. + + Returns: + bool | object: Result produced by the operation. """ if not os.path.isfile(abspath): self._log(f"forward: {abspath} is not a valid file, skipped") @@ -8955,6 +10094,13 @@ def _forward_one( def file_folder_transfer_client_recv_server_start_thread( self, command, client_id, client_socket ): + """Start a client-side folder receive operation. + + Args: + command (object): Value used by the operation. + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + """ command_part = shlex.split(command) relative_folder_path = command_part[1] # >= 4 tokens means a file transfer (/file_folder [] ); @@ -8968,6 +10114,13 @@ def file_folder_transfer_client_recv_server_start_thread( folder_transfer_client_recv_server_start_thread.start() def file_transfer_client_recv_server_start_thread(self, client_id, client_socket, command): + """Start a client-side file receive operation. + + Args: + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + command (object): Value used by the operation. + """ file_transfer_client_recv_server_start_thread = threading.Thread( target=self.file_transfer_client_recv_server_start, args=(client_id, client_socket, command), @@ -8978,6 +10131,15 @@ def file_transfer_client_recv_server_start_thread(self, client_id, client_socket def file_transfer_client_recv_server_start( self, client_id, client_socket, command, new_save_path=None, file_name=None ): + """Receive a file pushed by the server. + + Args: + client_id (object): Value used by the operation. + client_socket (socket.socket): Value used by the operation. + command (object): Value used by the operation. + new_save_path (str): Value used by the operation. + file_name (str): Value used by the operation. + """ file_transfer_server_port = self.palloc() self.file_transfer_mode_recv( self.host, @@ -8992,7 +10154,11 @@ def file_transfer_client_recv_server_start( self.pfree(file_transfer_server_port) def _own_address_text(self): - """Return this client's own ``"ip:port"`` as the server sees it, when known.""" + """Return this client's own ``"ip:port"`` as the server sees it, when known. + + Returns: + NoneType | object: Result produced by the operation. + """ if self.client_socket is not None: try: address = self.client_socket.getsockname() @@ -9007,12 +10173,15 @@ def _command_peer(self, command): """Return the sender a received transfer command belongs to. A file pushed by the server itself carries this client's own address, - which `parse_forward_originator` filters out: the sender is then the - server. A forwarded item carries the originating client's address — - the original peer a resume asks to continue the transfer. + which `parse_forward_originator` filters out: the sender is then the + server. A forwarded item carries the originating client's address — + the original peer a resume asks to continue the transfer. + + Args: + command (object): Value used by the operation. Returns: - tuple: ``(ip, port)`` of the transfer's original sender. + tuple: ``(ip, port)`` of the transfer's original sender. """ originator = parse_forward_originator(command, own_address=self._own_address_text()) peer = _peer_from_text(originator) if originator else None @@ -9032,15 +10201,20 @@ def file_transfer_mode_recv( ): """Receive one file over a transfer sub-connection. - ``peer`` is the transfer's original sender (the server for a pushed - file, the originating client for a forwarded one — never the relay): - it is stored with the progress entry so a later reconnect can ask that - peer to continue the file. + Args: + server_file_address (str): Local address for the transfer listener. + server_file_port (int): Local port for the transfer listener. + client_socket (socket.socket): Server control socket. + client_id (str): Sender identifier supplied by the server. + new_save_path (str | None): Relative directory for folder contents. + file_name (str | None): Destination filename, when specified. + command (str): Wire command that initiated the transfer. + peer (tuple | None): Original sender ``(ip, port)`` for resuming. + resume_entry (list | None): Saved progress entry for a resumed file. - ``resume_entry`` continues an interrupted transfer: the listener - announces itself, asks the sender to continue from the bytes already - on disk (``RESUME_LINE``) and appends the incoming chunks to the - partial file instead of truncating it. + Returns: + None | bool: None after starting or finishing; False when a resume request + cannot be sent. """ file_running = True client_file_socket = None @@ -9048,6 +10222,7 @@ def file_transfer_mode_recv( save_path = None def close_socket(): + """Handle the operation.""" nonlocal file_running nonlocal client_file_socket nonlocal server_file_socket @@ -9057,6 +10232,7 @@ def close_socket(): server_file_socket.close() def setting_file_save_path(): + """Handle the operation.""" nonlocal save_path save_path = self.file_transfer_dir if new_save_path or destination_path: @@ -9078,6 +10254,11 @@ def setting_file_save_path(): return None def file_transfer_client_recv(client_id): + """Handle the operation. + + Args: + client_id (object): Value used by the operation. + """ nonlocal file_running nonlocal client_file_socket nonlocal server_file_socket @@ -9352,15 +10533,15 @@ def _release_client_socket(self): """Close the socket a finished session left behind. An auto-reconnect binds the configured ``client_port`` again, so the - dead session's socket must go away completely: it is closed abortively - (``SO_LINGER`` on with a zero timeout, which the TCP stack turns into a - RST and which skips ``TIME_WAIT`` entirely). A socket that only gets - shut down keeps the port, and an ordinary close leaves the local port - in ``TIME_WAIT`` — Windows then refuses to bind or connect from it - again (``WSAEADDRINUSE``) for the whole two-minute delay. - - The receive thread of that session has already ended when this runs, so - nothing needs the shutdown a graceful close would perform. + dead session's socket must go away completely: it is closed abortively + (``SO_LINGER`` on with a zero timeout, which the TCP stack turns into a + RST and which skips ``TIME_WAIT`` entirely). A socket that only gets + shut down keeps the port, and an ordinary close leaves the local port + in ``TIME_WAIT`` — Windows then refuses to bind or connect from it + again (``WSAEADDRINUSE``) for the whole two-minute delay. + + The receive thread of that session has already ended when this runs, so + nothing needs the shutdown a graceful close would perform. """ sock = self.client_socket if sock is None: