0

I'm creating a simple ftp server / client using pyftpdlib and ftplib in order to receive data from a remote computer. I used a ThrottledHandler in order to limit the bandwidth, and I need to change the limit from time to time. The thing is, when I deploy the server to remote, I won't be able to reach it easily, to change the bandwidth limit or stopping / starting the server. So here is my question:

Is there a way to make a callback to a server function that changes the bandwidth limit from the client side, while the server is up and running?

Note: The code is working without any problems right now.

server code:

import os

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.handlers import DTPHandler
from pyftpdlib.handlers import ThrottledDTPHandler
from pyftpdlib.servers import FTPServer

authorizer = DummyAuthorizer()
authorizer.add_user("name", "password", "home_dir", perm="elr",
                    msg_login="name has logged in.",
                    msg_quit="name has left the server."
                    )

throttled_handler = ThrottledDTPHandler
throttled_handler.read_limit = 1024 * 1024  # kbps
throttled_handler.write_limit = 1024 * 1024  # kbps

handler = FTPHandler
handler.use_gmt_times = False
handler.authorizer = authorizer
handler.dtp_handler = throttled_handler

server = FTPServer((IP, PORT), handler)
server.serve_forever()

and the client code:

from ftplib import FTP
import os
import datetime

output_folder = "destination_dir"

# Option 1
def listFiles():
    print("\n Files in current directory:")
    file_list = ftp.nlst()
    print(file_list)


# Option 2
def moveInto(folder_name):
    if folder_name != "..":
        if not folder_name in ftp.nlst():
            print("This folder does not exist.")
            return
    ftp.cwd(folder_name)
    return


# Option 3 and 4
def copyAll(copy_path=output_folder):
    file_list = []
    ftp.retrlines("LIST", callback=file_list.append)
    for item in file_list:
        # Following lines parse the item details.
        file_parts = list(filter(lambda x: x != "", item.split(" ")))
        file_name = file_parts[-1]
        file_date = file_parts[-4:-1]

        if not "." in file_name:
            new_path = os.path.join(copy_path, file_name)
            ftp.cwd(file_name)
            if not os.path.exists(new_path):
                os.mkdir(new_path)
                print("Folder named {} has been created.".format(file_name))
            copyAll(new_path)

        else:
            new_file_path = os.path.join(copy_path, file_name)
            if not os.path.exists(new_file_path):
                new_file = open(os.path.join(copy_path, file_name), "wb")
                ftp.retrbinary("RETR {}".format(file_name), new_file.write)
                new_file.close()
                correctModifiedDate(os.path.join(copy_path, file_name), file_date)
                print("File named {} has been copied.".format(file_name))

    if ftp.pwd() != "/":
        ftp.cwd("..")
    return


def correctModifiedDate(file_path, correct_date):
    # TODO: implement the correction of last modified date.
    # print(correct_date)
    pass


ftp = FTP("")
ftp.connect(IP, PORT)
ftp.login("name", "password")
print("You have connected to the ftp server.")
while True:
    print("\ncommands:")
    choice = input("1. List files\n"
                   "2. Move into\n"
                   "3. Copy all current folder structure\n"
                   "4. Continuously copy all current folder structure\n"
                   "5. Quit "
                   )

    if str(choice) == "1":
        listFiles()

    elif str(choice) == "2":
        folder = input("folder name: ")
        moveInto(folder)

    elif str(choice) == "3":
        copyAll()

    elif str(choice) == "4":
        while True:
            copyAll()

    elif str(choice) == "5":
        exit_choice = input("\nAre you sure you want to leave the server? Y/N ")
        if exit_choice.upper() == "Y":
            break

    else:
        print("You have entered an invalid choice...")
  • You could rewrite the server as a method that includes **kwargs to takes in the bandwidth variables when you start the script. If you also make separate startup/shutdown methods, you can run these commands remotely via ssh. – mhdev Feb 24 '20 at 13:55
  • I'm would "suggest" spinning up a thread with an rpc server, or even simpler, a basic socket server that lets you call a callback with the 2 values either via rpc, or as a string sent and parsed in the socket server. –  Aug 03 '20 at 18:00

0 Answers0