Skip to content

Instantly share code, notes, and snippets.

@mrdaemon
Created July 7, 2011 04:08
Show Gist options
  • Save mrdaemon/1068873 to your computer and use it in GitHub Desktop.
Save mrdaemon/1068873 to your computer and use it in GitHub Desktop.
#!/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 <alex@lab.underwares.org>"
__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