mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-04 05:01:37 +02:00
Fix A1 FTP uploads by replacing storbinary with manual transfer
The A1 printer's FTP server hangs when Python's storbinary() calls voidresp() to wait for the server's completion response. This caused upload timeouts on A1 and A1 Mini printers. Fix contributed by an A1 user - replaces storbinary() with manual chunked transfer using transfercmd() + sendall(): - Uses 1MB chunks (CHUNK_SIZE constant) for better throughput - Sets explicit 120s socket timeout on data connection - Manually closes connection after transfer, avoiding voidresp() hang Applied to all printer models since the manual approach is compatible with X1C/P1S/P1P as well (transfercmd is what storbinary uses internally).
This commit is contained in:
@@ -80,6 +80,9 @@ class BambuFTPClient:
|
||||
# Models that may need SSL mode fallback (try prot_p first, fall back to prot_c)
|
||||
# These models have varying FTP SSL behavior depending on firmware version
|
||||
A1_MODELS = ("A1", "A1 Mini")
|
||||
# Chunk size for manual upload transfer (1MB)
|
||||
# Larger chunks reduce overhead and work better with A1 printers
|
||||
CHUNK_SIZE = 1024 * 1024
|
||||
|
||||
# Cache for working FTP modes per printer IP
|
||||
# Maps IP -> "prot_p" or "prot_c"
|
||||
@@ -363,15 +366,37 @@ class BambuFTPClient:
|
||||
|
||||
uploaded = 0
|
||||
|
||||
def on_block(block: bytes):
|
||||
nonlocal uploaded
|
||||
uploaded += len(block)
|
||||
if progress_callback:
|
||||
progress_callback(uploaded, file_size)
|
||||
|
||||
# Use manual transfer instead of storbinary() for A1 compatibility
|
||||
# A1 printers have issues with storbinary's voidresp() hanging after transfer
|
||||
with open(local_path, "rb") as f:
|
||||
logger.debug(f"FTP STOR command starting for {remote_path}")
|
||||
self._ftp.storbinary(f"STOR {remote_path}", f, callback=on_block)
|
||||
conn = self._ftp.transfercmd(f"STOR {remote_path}")
|
||||
|
||||
# Set explicit socket options for reliable transfer
|
||||
conn.setblocking(True)
|
||||
conn.settimeout(120) # 2 minute timeout per chunk
|
||||
|
||||
try:
|
||||
while True:
|
||||
chunk = f.read(self.CHUNK_SIZE)
|
||||
if not chunk:
|
||||
logger.debug("FTP upload: final chunk reached")
|
||||
break
|
||||
|
||||
conn.sendall(chunk)
|
||||
uploaded += len(chunk)
|
||||
logger.debug(f"FTP upload progress: {uploaded}/{file_size} bytes")
|
||||
|
||||
if progress_callback:
|
||||
progress_callback(uploaded, file_size)
|
||||
|
||||
except OSError as e:
|
||||
logger.error(f"FTP connection lost during upload: {e}")
|
||||
conn.close()
|
||||
raise
|
||||
|
||||
conn.close()
|
||||
|
||||
logger.info(f"FTP upload complete: {remote_path}")
|
||||
return True
|
||||
except ftplib.error_perm as e:
|
||||
@@ -399,8 +424,24 @@ class BambuFTPClient:
|
||||
return False
|
||||
|
||||
try:
|
||||
buffer = BytesIO(data)
|
||||
self._ftp.storbinary(f"STOR {remote_path}", buffer)
|
||||
# Use manual transfer instead of storbinary() for A1 compatibility
|
||||
conn = self._ftp.transfercmd(f"STOR {remote_path}")
|
||||
conn.setblocking(True)
|
||||
conn.settimeout(120)
|
||||
|
||||
try:
|
||||
# Send data in chunks
|
||||
offset = 0
|
||||
while offset < len(data):
|
||||
chunk = data[offset : offset + self.CHUNK_SIZE]
|
||||
conn.sendall(chunk)
|
||||
offset += len(chunk)
|
||||
except OSError as e:
|
||||
logger.error(f"FTP connection lost during upload_bytes: {e}")
|
||||
conn.close()
|
||||
raise
|
||||
|
||||
conn.close()
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user