Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from txrestapi.resource import APIResource
- from twisted.web.server import Site
- from twisted.web.static import File
- from twisted.protocols.basic import FileSender
- from twisted.python.log import err
- from twisted.web.server import NOT_DONE_YET
- from twisted.internet import reactor
- from txrestapi.methods import GET, POST, PUT, ALL
- from BReader import BackwardsReader
- import json
- import os
- import shutil
- import magic
- from WrapSSH import *
- import pprint
- # TODO: Abstract utility functions into their own module.
- # Builds a dict that references a given key in a list of dicts,
- # for quick retrieval.
- def build_dict(seq, key):
- return dict((d[key], dict(d, index=i)) for (i, d) in enumerate(seq))
- # Would be nice to turn the things below into classes, but they won't serialize
- # nicely :S (Yes, this class is currently useless...)
- class TransferDir(object):
- host = ""
- path = ""
- short = ""
- friendly = ""
- def __init__(self, host, path, short=None, friendly=None):
- self.host = host
- self.path = path
- self.short = short
- self.friendly = friendly
- # Statically defined stuffs..this whole section needs a rethink, but since
- # we're just prototyping...
- # TODO: Overhaul/abstract/rethink sources and destinations so that both local
- # and remote files can be handled.
- sourcedirs = [
- {
- 'id': '1',
- 'host': 'localhost',
- 'path': './dirs/dira',
- 'short': 'src_a',
- 'friendly': 'File Source A'
- },
- {
- 'id': '2',
- 'host': 'localhost',
- 'path': './dirs/dirb',
- 'short': 'src_b',
- 'friendly': 'File Source B'
- },
- {
- 'id': '3',
- 'host': 'localhost',
- 'path': './dirs/dirc',
- 'short': 'src_c',
- 'friendly': 'File Source C'
- },
- {
- 'id': '4',
- 'host': 'localhost',
- 'path': './dirs/coma',
- 'short': 'com_a',
- 'friendly': 'File Common A'
- },
- {
- 'id': '4',
- 'host': 'localhost',
- 'path': './dirs/coma',
- 'short': 'com_b',
- 'friendly': 'File Common B'
- },
- {
- 'id': '5',
- 'host': 'Taris',
- 'path': '/home/####/testdir',
- 'short': 'tar_a',
- 'friendly': 'Taris Store A'
- }
- ]
- destdirs = [
- {
- 'id': '1',
- 'host': 'localhost',
- 'path': './dirs/dird',
- 'short': 'src_d',
- 'friendly': 'File Destination D'
- },
- {
- 'id': '2',
- 'host': 'localhost',
- 'path': './dirs/coma',
- 'short': 'com_a',
- 'friendly': 'File Common A'
- },
- {
- 'id': '3',
- 'host': 'localhost',
- 'path': './dirs/coma',
- 'short': 'com_b',
- 'friendly': 'File Common B'
- },
- {
- 'id': '4',
- 'host': 'Taris',
- 'path': '/home/####/testdir',
- 'short': 'tar_a',
- 'friendly': 'Taris Store A'
- }
- ]
- sshhosts = [
- {
- 'name': 'a',
- 'addr': 'a',
- 'port': 0,
- 'user': 'a',
- 'auth': 'a',
- 'cred': 'a'
- },
- {
- 'name': 'Taris',
- 'addr': 'taris.##.##',
- 'port': 22,
- 'user': '#####',
- 'auth': 'pass',
- 'cred': "#####"
- }
- ]
- # Build a quick dictionary to make lookup operations O(1),
- # since these could could happen frequently.
- indexed_sources = build_dict(sourcedirs, 'id')
- indexed_dests = build_dict(destdirs, 'id')
- indexed_hosts = build_dict(sshhosts, 'name')
- errornf = {'error': 'Resource not found'}
- # End of the statics
- class BwcResource(APIResource):
- # Class utility funcs:
- def get_file_list(self, indexed_dir, key):
- try:
- directory = indexed_dir[key]
- path = directory.get('path')
- listing = os.listdir(path)
- return listing
- except KeyError, e:
- print("Invalid indexed_dir key")
- raise e
- ###########################################################################
- # Static Content
- ###########################################################################
- # Serves the Angular App
- @ALL('^/static/')
- def static_callback(self, request):
- return File('./webapp')
- ###########################################################################
- # Transfers section
- ###########################################################################
- # List available transfer sources
- @GET('^/api/transfer/sources(/)?$')
- def transfer_sources(self, request):
- return json.dumps(sourcedirs)
- # List available transfer destinations
- @GET('^/api/transfer/destinations(/)?$')
- def transfer_destinations(self, request):
- return json.dumps(destdirs)
- # Fetch a single source's details by key
- @GET('^/api/transfer/sources/(?P<key>[^/]+)/details(/)?')
- def transfer_sources_details(self, request, key):
- return json.dumps(indexed_sources[key])
- # Fetch a single destination's details by key
- @GET('^/api/transfer/destinations/(?P<key>[^/]+)/details(/)?')
- def transfer_dests_details(self, request, key):
- return json.dumps(indexed_dests[key])
- # List contents of the requested source directory
- @GET('^/api/transfer/sources/(?P<key>[^/]+)/listing(/)?')
- def transfer_sources_listing(self, request, key):
- source = indexed_sources[key]
- hostname = source.get('host')
- # If this is a local path
- if hostname == "localhost":
- try:
- listing = self.get_file_list(indexed_sources, key)
- return json.dumps(listing)
- except KeyError:
- print("Tried to access nonexistent key "+key
- + " of indexed_sources\n")
- return json.dumps({'error':
- "Tried to access nonexistant key"})
- # Else it must be a remote!
- # TODO: Add a proper try wrapper
- else:
- host = indexed_hosts[hostname]
- path = indexed_sources[key].get('path')
- wrap = WrapSSH(
- host.get('addr'),
- host.get('port'),
- host.get('user'),
- host.get('auth'),
- host.get('cred')
- )
- return json.dumps(wrap.list(path))
- # List contents of the requested destination directory
- @GET('^/api/transfer/destinations/(?P<key>[^/]+)/listing(/)?')
- def transfer_destinations_listing(self, request, key):
- try:
- listing = self.get_file_list(indexed_dests, key)
- return json.dumps(listing)
- except KeyError:
- print("Tried to access nonexistent key "+key+" of indexed_dests\n")
- return json.dumps({'error': "Tried to access nonexistant key"})
- # Move a file
- # QUESTION: What should the behavior be if the destination already exists?
- @POST('^/api/transfer/move')
- def transfer_move_file(self, request):
- data = json.loads(request.content.getvalue())
- srcpath = indexed_sources[data["srckey"]].get('path')+'/'+data["srcfile"]
- destpath = indexed_dests[data["destkey"]].get('path')+'/'+data["destfile"]
- result = shutil.move(srcpath, destpath)
- return json.dumps({'status': 'success', 'result': result})
- # Download a file
- @POST('^/api/transfer/download')
- def transfer_download_file(self, request):
- data = json.loads(request.content.getvalue())
- source = indexed_sources[data["srckey"]]
- srcpath = source.get('path')+'/'+data["srcfile"]
- hostname = source.get('host')
- # If this is a local path
- if hostname == "localhost":
- mime = magic.Magic(mime=True)
- mimetype = mime.from_file(srcpath)
- rangedFile = File(srcpath, defaultType=mimetype)
- return rangedFile.render_GET(request)
- else:
- host = indexed_hosts[hostname]
- wrap = WrapSSH(
- host.get('addr'),
- host.get('port'),
- host.get('user'),
- host.get('auth'),
- host.get('cred')
- )
- # Bunch of magic to avoid having to cache file locally.
- stats = wrap.stat(srcpath)
- fp = wrap.fp(srcpath)
- beginning = fp.tell()
- mime = magic.Magic(mime=True)
- mimetype = mime.from_buffer(fp.read(1024))
- fp.seek(beginning)
- thing = SSHResource(fp, stats.st_size, mimetype, data['srcfile'])
- return thing.render(request)
- # Tail a file
- # QUESTION: Should we just fork to the OS's tail instead? Simpler, but
- # less efficient
- # TODO: Return an error/notification if the file is not a tailable type.
- @POST('^/api/transfer/tail')
- def transfer_tail_file(self, request):
- LINES = 10
- data = json.loads(request.content.getvalue())
- source = indexed_sources[data["srckey"]]
- hostname = source.get('host')
- path = source.get('path') + '/'+data["srcfile"]
- # If this is a local path
- if hostname == "localhost":
- try:
- br = BackwardsReader(path)
- out = ""
- for x in range(LINES):
- out = br.readline() + out
- return json.dumps({'status': 'success', 'result': out})
- except UnicodeDecodeError:
- return json.dumps({'status': 'fail', 'result':
- 'File could not be tailed: UnicodeDecodeError'})
- # Else it must be a remote!
- # TODO: Add a proper try wrapper
- else:
- host = indexed_hosts[hostname]
- path = indexed_sources[data["srckey"]].get('path') + '/'+data["srcfile"]
- print(path+'\n')
- wrap = WrapSSH(
- host.get('addr'),
- host.get('port'),
- host.get('user'),
- host.get('auth'),
- host.get('cred')
- )
- return json.dumps({'status': 'success',
- 'result': wrap.tail(path, LINES)})
- # Email a file
- @POST('^/api/transfer/email')
- def transfer_email_file(self, request):
- ## Example email code from Dave's app
- # ''' This method emails the admin invoice report '''
- # from_dir = self.get_gadget(BMW.ID_DISP_DIR).GetStringSelection()
- # if from_dir == '':
- # self.send_message('A listing directory must be selected', 'error')
- # report = self.get_gadget(BMW.EDISelection).GetStringSelection()
- # if report == '':
- # self.send_message('A file must be selected', 'error')
- # return
- # from_dir = BMS.DIR_DICT[from_dir]
- # email_add = self.cfg['telnet']['email']
- # telnet_conn = BMF.connect_and_cd(self.cfg['telnet'], BMF.get_env(self), self.cfg['sudo'],
- # self.single_opts['curr_db_name'], from_dir)
- # email = '''/appl/bwc/%s/scripts/email %s "%s" "Your file is enclosed." %s /appl/bwc/%s/%s/%s email''' \
- # % (self.single_opts['curr_db_name'], email_add, "File Emailed",
- # email_add, self.single_opts['curr_db_name'], from_dir, report)
- # telnet_conn.send(email)
- # BMF.process_telnet_conn(telnet_conn, self.cfg['telnet']['prompt'])
- # self.send_message('Successfully emailed %s' % report, 'info')
- return json.dumps({'error': "Unimplemented"})
- ###########################################################################
- # Defaults
- ###########################################################################
- # Pointless response to a call to the root of the API.
- @ALL('^/api(/)?$')
- def api_callback(self, request):
- return "Root of the API. Should probably tell you how to use me?"
- # Response to a call to the root of the server.
- @ALL('^/.*')
- def default_callback(self, request):
- return "This is the default response. It doesn't do anything fun."
- # Float the Boat
- # site = Site(api, timeout=None)
- api = BwcResource()
- site = Site(api, timeout=None)
- reactor.listenTCP(8880, site)
- reactor.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement