Created
July 7, 2011 04:08
-
-
Save mrdaemon/1068873 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# ____ __ _ __ | |
# / __ \___ ________ _____/ /__________ (_) /______ _ | |
# / /_/ / _ \/ ___/ _ \/ ___/ __/ ___/ __ \/ / //_/ __ `/ | |
# / ____/ __/ / / __(__ ) /_/ / / /_/ / / ,< / /_/ / | |
#/_/ \___/_/ \___/____/\__/_/ \____/_/_/|_|\__,_/ | |
# | |
# Yet another threaded, multi-part file downloader | |
# | |
# Copyright (c) Alexandre Gauthier 2010-2011 | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License | |
# as published by the Free Software Foundation; either version 2 | |
# of the License, or (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software | |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
# MA 02110-1301, USA. | |
# | |
""" Protocols handler """ | |
__author__ = "Alexandre Gauthier <[email protected]>" | |
__copyright__ = "Copyright 2010-2011, Alexandre Gauthier" | |
__credits__ = "Contributions:" | |
__license__ = "GPLv2" | |
__version__ = "0.1-prototype" | |
__revision__ = "%revision%" | |
from ftplib import FTP | |
from ftplib import error_perm, all_errors, temp_error | |
import localerrors | |
class _Protocol(object): | |
""" Base protocol class | |
This is the base class extended by protocol implementations. | |
It serves as an API/interface as well: as long as your protocol | |
implements at the very least the method and public members | |
described below, it should work with Perestroika without problems. | |
""" | |
def __init__(self): | |
""" Instantiate a raw protocol base class | |
This is the raw protocol base class. | |
I sure hope you know what you're doing! | |
""" | |
self.name = "" | |
self.description = "" | |
self._defaultport = 0 | |
self._hostname = "" | |
self._port = 0 | |
self._timeout = 20 | |
def connect(self, hostname, port): | |
""" Connect to server | |
@param hostname: Hostname to connect to | |
@type hostname: string | |
@param port: TCP port to use | |
@type port: integer | |
""" | |
pass | |
def login(self, username, password): | |
""" Login to server | |
@param username: Username to login with | |
@type username: string | |
@param password: Password | |
@type password: string | |
""" | |
pass | |
def get_directory_listing(self, directory): | |
""" Obtain remote directory listing from server | |
@param directory: Directory to list (unix path) | |
@type directory: string | |
""" | |
pass | |
def get_file_size(self, file_): | |
""" Obtain total file size in bytes from the server | |
@param file_: remote filename (relative path) | |
@type file_: string | |
""" | |
pass | |
def download_file(self, file_, seek=0, stop=None): | |
""" Download file from server | |
"seek" and "stop" should specify in bytes where to begin | |
downloading, and where to stop, respectively. This is used | |
for resuming and multi-parting | |
@param file_: Remote File to download (relative) | |
@type file_: string | |
@param seek=0: Start downloading at this value, in bytes | |
@type seek=0: integer | |
@param stop=None: Keep downloading until this value (in bytes) | |
@type stop=None: | |
""" | |
pass | |
class FTPProtocol(_Protocol): | |
""" The File Transfer Protocol handler """ | |
def __init__(self, passive=True): | |
""" Instantiate FTP handler class | |
@param passive=True: Enable PASV (as opposed to PORT) mode | |
@type passive=True: boolean | |
""" | |
super(FTPProtocol, self).__init__() | |
self.name = "FTP" | |
self.description = "File Transfer Protocol" | |
self._ftp = FTP() | |
self._passive = passive | |
def connect(self, hostname, port=21): | |
""" Connect to FTP Server | |
@param hostname: Server hostname or address | |
@type hostname: string | |
@param port=21: TCP Port | |
@type port=21: integer | |
""" | |
try: | |
self._ftp.connect(hostname, port) | |
except Exception as conerr: | |
msg = "Unable to connect to %s on port %s" % ( | |
hostname, port) | |
details = "[%s] %s" % (conerr.errno, conerr.strerror) | |
raise localerrors.ConnectionError(msg, details) | |
return self._ftp.getwelcome() | |
def login(self, username="anonymous", password="anon@perestroika"): | |
""" Login to FTP server | |
If the username and passwords are left blank, anonymous | |
login is assumed. | |
@param username="anonymous": Username | |
@type username="anonymous": string | |
@param password="anon@perestroika": Password | |
@type password="anon@perestroika": string | |
""" | |
try: | |
motd = self._ftp.login(username, password) | |
except error_perm, autherr: | |
msg = "Login Failed for user %s." % (username) | |
details = autherr | |
raise localerrors.AuthenticationError(msg, details) | |
except all_errors, autherr: | |
msg = "Unexpected Protocol Error during login." | |
details = autherr | |
raise localerrors.ProtocolError(msg, details) | |
finally: | |
self._ftp.close() | |
return motd | |
def get_directory_listing(self, directory=""): | |
""" Obtain directory listing from server | |
To get current working directory, leave out the directory | |
parameter. | |
@param directory="": Directory to list (unix path) | |
@type directory="": string | |
""" | |
# TODO: Determine possible exceptions here. | |
try: | |
dir = self._ftp.dir(directory) | |
except temp_error, protocolerr: | |
msg = "Unable to get directory listing" | |
details = protocolerr | |
raise localerrors.ProtocolError(msg, details) | |
except Exception, err: | |
raise localerrors.PerestroikaException(err) | |
return dir |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment