Twisted — простое событие завершения файла для FTP-сервера

Я хочу использовать Twisted для некоторого базового FTP-сервера, как в этом примере :

from twisted.protocols.ftp  import FTPFactory, FTPRealm
from twisted.cred.portal    import Portal
from twisted.cred.checkers  import AllowAnonymousAccess, FilePasswordDB
from twisted.internet       import reactor

#pass.dat looks like this:
# jeff:bozo
# grimmtooth:bozo2

p = Portal(FTPRealm('./'), (AllowAnonymousAccess(), FilePasswordDB("pass.dat")))
f = FTPFactory(p)
reactor.listenTCP(21, f)
reactor.run()

... с одной простой настройкой: я хочу запустить событие, когда загрузка файла (STOR) успешно завершена, чтобы мой пользовательский код мог адекватно обрабатывать этот файл.

Я не нашел документации для FTPFactory или FTP, которая помогла бы мне в этом. Должен ли я перегружать объект FTP или какой-либо другой объект? Как все подключить?

В прошлом я делал простые пользовательские HTTP-серверы с искажениями, и это было приятно легко, но я почти не могу найти материала о FTP.


person Ekevoo    schedule 20.03.2012    source источник


Ответы (2)


Во-первых, это всего лишь модификация ответа Ракиса. Без его ответа этого не было бы. Его просто не будет работать на моей установке. Также может быть, что API изменился, так как это 5 лет спустя.

class MyFTP (ftp.FTP):

    def ftp_STOR(self, path):

        d = super(MyFTP, self).ftp_STOR(path)

        def onStorComplete(d):
            print 'STORED', repr(d), path
            return d

        d.addCallback(onStorComplete)

        return d

f = ftp.FTPFactory( some_portal_object )
f.protocol = MyFTP
person Daniel F    schedule 28.07.2017
comment
Я не могу проверить это (прошло прошло 5 лет), поэтому я просто поверю вам и приму этот ответ. - person Ekevoo; 03.08.2017

Похоже, что следующее может помочь

from twisted.protocols import ftp

class MyFTP (ftp.FTP):
    def ftp_STOR(self, path):
        d = super(MyFTP, self).ftp_STOR(path)

        d.addCallback( lambda _: self.onStorComplete(path) )

        return d

    def onStorComplete(self, path):
        # XXX your code here

 f = ftp.FTPFactory( some_portal_object )
 f.protocol = MyFTP
person Rakis    schedule 20.03.2012
comment
Это не так; обратный вызов был вызван до начала передачи файла (и передача зацикливается с использованием Filezilla). Кроме того, мой файл не сохраняется. :\ - person Ekevoo; 20.03.2012
comment
ftp_STOR определенно возвращает Deferred, который срабатывает только после завершения передачи. Возможно, что-то еще не так с вашей программой. - person Jean-Paul Calderone; 20.03.2012
comment
Я основан на примере, который я связал по моему вопросу. Я замечаю, что все попытки записи терпят неудачу. Я исследую это немного дальше… - person Ekevoo; 21.03.2012
comment
Так что, видимо, этот пример не записывает на диск. :( Я подумываю просто подождать, пока FTP API + документы созреют, и просто использовать подход к объединению. - person Ekevoo; 23.03.2012
comment
Готов поспорить, что причина, по которой пример Экеву не записывает на диск, заключается в том, что он использует FTPRealm('./'), как ln. 36 примера. Это устанавливает anonymousRoot класса FTPRealm, но оставляет значение userHome по умолчанию /home (как показано в source, который выглядит как плохой дизайн, который был никогда не фиксировалось). Я бы предложил использовать FTPRealm(anonymousRoot='./', userHome='./someDir'). - person alukach; 14.04.2014
comment
Я также столкнулся с проблемой, что это не полностью загружает файл. Сервер находится в Linux, а клиент — WinSCP в Windows. Когда я использую его без MyFTP, он работает. Но когда я использую класс, как написано выше, загрузка останавливается на 100%, и только когда я затем отменяю загрузку, файл появляется на сервере. В приведенном выше коде чего-то не хватает. - person Daniel F; 28.07.2017
comment
Мне пришлось изменить код, добавить его как ответ, потому что я не был уверен, можно ли изменить код Ракиса в его ответе. - person Daniel F; 28.07.2017