MicroPython stuff
This commit is contained in:
163
code/MicroPython/ftp.py
Normal file
163
code/MicroPython/ftp.py
Normal file
@@ -0,0 +1,163 @@
|
||||
import socket
|
||||
import network
|
||||
import os
|
||||
import _thread
|
||||
|
||||
DATA_PORT = 13333
|
||||
|
||||
ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
ftpsocket.bind(socket.getaddrinfo("0.0.0.0", 21)[0][4])
|
||||
datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4])
|
||||
|
||||
ftpsocket.listen(1)
|
||||
datasocket.listen(1)
|
||||
datasocket.settimeout(10)
|
||||
|
||||
dataclient = None
|
||||
|
||||
|
||||
def send_list_data(cwd, dataclient):
|
||||
for file in os.listdir(cwd):
|
||||
stat = os.stat(get_absolute_path(cwd, file))
|
||||
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
|
||||
file_size = stat[6]
|
||||
description = "{} 1 owner group {:>13} Jan 1 1980 {}\r\n".format(
|
||||
file_permissions, file_size, file
|
||||
)
|
||||
dataclient.sendall(description)
|
||||
|
||||
|
||||
def send_file_data(path, dataclient):
|
||||
with open(path) as file:
|
||||
chunk = file.read(128)
|
||||
while len(chunk) > 0:
|
||||
dataclient.sendall(chunk)
|
||||
chunk = file.read(128)
|
||||
|
||||
|
||||
def save_file_data(path, dataclient):
|
||||
with open(path, "w") as file:
|
||||
chunk = dataclient.read(128)
|
||||
while len(chunk) > 0:
|
||||
file.write(chunk)
|
||||
chunk = dataclient.read(128)
|
||||
|
||||
|
||||
def get_absolute_path(cwd, payload):
|
||||
# if it doesn't start with / consider
|
||||
# it a relative path
|
||||
if not payload.startswith("/"):
|
||||
payload = cwd + "/" + payload
|
||||
# and don't leave any trailing /
|
||||
return payload.rstrip("/")
|
||||
|
||||
|
||||
def ftp():
|
||||
try:
|
||||
dataclient = None
|
||||
while True:
|
||||
cwd = "/"
|
||||
cl, remote_addr = ftpsocket.accept()
|
||||
cl.settimeout(300)
|
||||
try:
|
||||
print("FTP connection from:", remote_addr)
|
||||
cl.sendall("220 Hello, this is the ESP8266.\r\n")
|
||||
while True:
|
||||
data = cl.readline().decode("utf-8").replace("\r\n", "")
|
||||
if len(data) <= 0:
|
||||
print("Client is dead")
|
||||
break
|
||||
|
||||
command, payload = (data.split(" ") + [""])[:2]
|
||||
command = command.upper()
|
||||
|
||||
print("Command={}, Payload={}".format(command, payload))
|
||||
|
||||
if command == "USER":
|
||||
cl.sendall("230 Logged in.\r\n")
|
||||
elif command == "SYST":
|
||||
cl.sendall("215 ESP8266 MicroPython\r\n")
|
||||
elif command == "SYST":
|
||||
cl.sendall("502\r\n")
|
||||
elif command == "PWD":
|
||||
cl.sendall('257 "{}"\r\n'.format(cwd))
|
||||
elif command == "CWD":
|
||||
path = get_absolute_path(cwd, payload)
|
||||
try:
|
||||
files = os.listdir(path)
|
||||
cwd = path
|
||||
cl.sendall('250 Directory changed successfully\r\n')
|
||||
except:
|
||||
cl.sendall('550 Failed to change directory\r\n')
|
||||
elif command == "EPSV":
|
||||
cl.sendall('502\r\n')
|
||||
elif command == "TYPE":
|
||||
# probably should switch between binary and not
|
||||
cl.sendall('200 Transfer mode set\r\n')
|
||||
elif command == "SIZE":
|
||||
path = get_absolute_path(cwd, payload)
|
||||
try:
|
||||
size = os.stat(path)[6]
|
||||
cl.sendall('213 {}\r\n'.format(size))
|
||||
except:
|
||||
cl.sendall('550 Could not get file size\r\n')
|
||||
elif command == "QUIT":
|
||||
cl.sendall('221 Bye.\r\n')
|
||||
elif command == "PASV":
|
||||
addr = network.WLAN().ifconfig()[0]
|
||||
cl.sendall(
|
||||
'227 Entering Passive Mode ({},{},{}).\r\n'.format(
|
||||
addr.replace('.', ','), DATA_PORT >> 8, DATA_PORT % 256
|
||||
)
|
||||
)
|
||||
dataclient, data_addr = datasocket.accept()
|
||||
print("FTP Data connection from:", data_addr)
|
||||
elif command == "LIST":
|
||||
try:
|
||||
send_list_data(cwd, dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("150 Here comes the directory listing.\r\n")
|
||||
cl.sendall("226 Listed.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to list directory\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
elif command == "RETR":
|
||||
try:
|
||||
send_file_data(get_absolute_path(cwd, payload), dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("150 Opening data connection.\r\n")
|
||||
cl.sendall("226 Transfer complete.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to send file\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
elif command == "STOR":
|
||||
try:
|
||||
cl.sendall("150 Ok to send data.\r\n")
|
||||
save_file_data(get_absolute_path(cwd, payload), dataclient)
|
||||
dataclient.close()
|
||||
cl.sendall("226 Transfer complete.\r\n")
|
||||
except:
|
||||
cl.sendall('550 Failed to send file\r\n')
|
||||
finally:
|
||||
dataclient.close()
|
||||
else:
|
||||
cl.sendall("502 Unsupported command.\r\n")
|
||||
print("Unsupported command {} with payload {}".format(command, payload))
|
||||
|
||||
finally:
|
||||
cl.close()
|
||||
finally:
|
||||
datasocket.close()
|
||||
ftpsocket.close()
|
||||
if dataclient is not None:
|
||||
dataclient.close()
|
||||
|
||||
|
||||
_thread.start_new_thread(ftp, ())
|
||||
Reference in New Issue
Block a user