giampaolo / pyftpdlib

Extremely fast and scalable Python FTP server library
MIT License
1.67k stars 266 forks source link

FTP has no way to dynamically create new users and delete users after running #527

Closed BingYanchi closed 4 years ago

BingYanchi commented 4 years ago

Sometimes I need to add users and delete users while running.

Because of the blocking design, the while loop cannot be used to operate at runtime. So I used multi-threaded operation, but when the newly added user logged in, the following error occurred:

Unhandled exception in thread started by <bound method ftp_server.run of <ftp_server.ftp_server object at 0x000001E2B15DC390>>
Traceback (most recent call last):
  File "C:\Users\Bing_Yanchi\Desktop\Ark\ftp\ftp_server.py", line 16, in run
    self.server.serve_forever()
  File "C:\Program Files\python\lib\site-packages\pyftpdlib\servers.py", line 245, in serve_forever
    self.ioloop.loop(timeout, blocking)
  File "C:\Program Files\python\lib\site-packages\pyftpdlib\ioloop.py", line 348, in loop
    poll(soonest_timeout)
  File "C:\Program Files\python\lib\site-packages\pyftpdlib\ioloop.py", line 446, in poll
    r, w, e = select.select(self._r, self._w, [], timeout)
OSError: [WinError 10038] An operation was attempted on a non-socket.
AndreLaxe commented 4 years ago

Check this post : https://stackoverflow.com/a/24480146

You can create a class that run the server and add an _adduser function that you will call after the run function.

import thread

class ftp_server:
   def __init__(self):
       self.authorizer = DummyAuthorizer()
       self.authorizer.add_user('admin', 'password', '.', perm='elradfmwM')

   def run(self):
       self.handler = FTPHandler
       self.handler.authorizer = self.authorizer
       self.address = ('localhost', 21)
       self.server = FTPServer(self.address, self.handler)
       logging.basicConfig(filename='pyftpd.log', level=logging.INFO)
       self.server.serve_forever()

   def add_user(self,user,passwd,loc,privi):
       self.authorizer.add_user(str(user), str(passwd), str(loc), perm=str(privi))

this_ftp = ftp_server()

thread.Threading(this_ftp.run,()).start()
thread.Threading(this_ftp.add_user,('user','password',".",'elradfmwM')).start() #add user while server running
BingYanchi commented 4 years ago

Check this post : https://stackoverflow.com/a/24480146

You can create a class that run the server and add an _adduser function that you will call after the run function.

import thread

class ftp_server:
   def __init__(self):
       self.authorizer = DummyAuthorizer()
       self.authorizer.add_user('admin', 'password', '.', perm='elradfmwM')

   def run(self):
       self.handler = FTPHandler
       self.handler.authorizer = self.authorizer
       self.address = ('localhost', 21)
       self.server = FTPServer(self.address, self.handler)
       logging.basicConfig(filename='pyftpd.log', level=logging.INFO)
       self.server.serve_forever()

   def add_user(self,user,passwd,loc,privi):
       self.authorizer.add_user(str(user), str(passwd), str(loc), perm=str(privi))

this_ftp = ftp_server()

thread.Threading(this_ftp.run,()).start()
thread.Threading(this_ftp.add_user,('user','password',".",'elradfmwM')).start() #add user while server running

Are you sure this is Python 3 instead of Python 2?

AndreLaxe commented 4 years ago

Yep. It works with Python 3.

BingYanchi commented 4 years ago

Yep. It works with Python 3.

But are you sure Python 3 can import thread?

Is it that I need to install a certain library?

lurch commented 4 years ago

https://docs.python.org/2/library/thread.html says: "Note The thread module has been renamed to _thread in Python 3. The 2to3 tool will automatically adapt imports when converting your sources to Python 3; however, you should consider using the high-level threading module instead."

BingYanchi commented 4 years ago

https://docs.python.org/2/library/thread.html says: "Note The thread module has been renamed to _thread in Python 3. The 2to3 tool will automatically adapt imports when converting your sources to Python 3; however, you should consider using the high-level threading module instead."

import threading
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer

class ftp_server(threading.Thread):
   def __init__(self):
       super(ftp_server, self).__init__(name='ftp_server')
       self.authorizer = DummyAuthorizer()
       self.authorizer.add_user('admin', 'password', '.', perm='elradfmwM')

   def run(self):
       self.handler = FTPHandler
       self.handler.authorizer = self.authorizer
       self.address = ('localhost', 21)
       self.server = FTPServer(self.address, self.handler)
       self.server.serve_forever()

   def add_user(self,user,passwd,loc,privi):
       self.authorizer.add_user(str(user), str(passwd), str(loc), perm=str(privi))

if __name__ == '__main__':
    ftp_server().start
    ftp_server.add_user('user','password',".",'elradfmwM').start
PS D:\Github\ArkManager> & "C:/Program Files/python/python.exe" d:/Github/ArkManager/python/ftp.py
Traceback (most recent call last):
  File "d:/Github/ArkManager/python/ftp.py", line 24, in <module>
    ftp_server.add_user('user','password',".",'elradfmwM').start
TypeError: add_user() missing 1 required positional argument: 'privi'

I don't know how to solve this self problem.

giampaolo commented 4 years ago

You are not instantiating ftp_server class correctly. Instead of:

if __name__ == '__main__':
    ftp_server().start
    ftp_server.add_user('user','password',".",'elradfmwM').start

...do (not tested):

if __name__ == '__main__':
    server = ftp_server()
    server.add_user('user','password',".",'elradfmwM')
    server.start()

You don't need to inherit from threading.Thread though. I'm not sure what you're aiming at exactly.

BingYanchi commented 4 years ago

You are not instantiating ftp_server class correctly. Instead of:

if __name__ == '__main__':
    ftp_server().start
    ftp_server.add_user('user','password',".",'elradfmwM').start

...do (not tested):

if __name__ == '__main__':
    server = ftp_server()
    server.add_user('user','password',".",'elradfmwM')
    server.start()

You don't need to inherit from threading.Thread though. I'm not sure what you're aiming at exactly.

Thank! Perfectly solved my problem.