sbeam/src/SuperBeam/RequestHandlers.py

185 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
"""SuperBeam Handlers
The handlers are automatically registered during the creation of the
:class:`SuperBeamServer` instance.
Each class handler method needs to be a ``staticmethod``. The callee will call
the `handle()` with the ``httpd`` instance of the :class:`SuperBeamServer` as
required argument.
"""
import os
import json
import uuid
class BaseTextHandler(object):
mimetype = 'text/mime'
@staticmethod
def handle(httpd):
raise Exception(f'Not implemented: Unable to handle {httpd} '
'({BaseTextHandler.mimetype}')
class OctetStreamHandler(object):
mimetype = 'application/octet-stream'
@staticmethod
def handle(httpd):
raise Exception(f'Not implemented: Unable to handle {httpd} '
'({OctetStreamHandler.mimetype}')
class ChunkTemplateHandler(BaseTextHandler):
"""TODO
"""
URI = ('/', '/index.htm', 'index')
class ThumbHandler(object):
"""TODO
"""
mimetype = 'image/png'
URI = ('/getthumb',)
@staticmethod
def handle(httpd):
raise Exception(f'Not implemented: Unable to handle {httpd} '
'({ThumbHandler.mimetype}')
class LegacyListHandler(BaseTextHandler):
"""Legacy list handler for SuperBeam - plain text with file metadata
URI: ``/superlist``
"""
URI = ('/superlist',)
@staticmethod
def handle(httpd):
raise Exception(f'Not implemented: Unable to handle {httpd} '
'({LegacyListHandler.mimetype}')
class JsonListHandler(object):
"""Json List Handler - Metadata of served files as json
URI: ``/jsonlist``
"""
mimetype = 'application/json'
URI = ('/jsonlist',)
@staticmethod
def _make_jsonlist(files):
filestats = []
totalsize = 0
for file_ in files:
statinfo = os.stat(file_)
filename = os.path.basename(file_)
filepath = os.path.dirname(file_)
filestats.append({
'created': str(int(statinfo.st_ctime) * 1000),
'modified': str(int(statinfo.st_mtime) * 1000),
'name': filename,
'path': filepath,
'size': str(statinfo.st_size),
'type': "Image" # TODO dynamic
})
totalsize += statinfo.st_size
jsonlist = {
'device': 'ANYONMOUS',
'empty_dirs': [],
'files': filestats,
'uuid': str(uuid.uuid4()),
'version': 4130
}
return json.dumps(jsonlist), totalsize
@staticmethod
def handle(httpd):
jsonlist, totalsize = JsonListHandler._make_jsonlist(httpd.files)
httpd.send_response(200)
httpd.send_header('Content-Type', 'application/json')
httpd.end_headers()
response = bytes(jsonlist, 'utf-8')
httpd.wfile.write(response)
httpd.total_file_size = totalsize
class SingleFileHandler(OctetStreamHandler):
"""TODO
"""
URI = ('/get/',)
class ZipFileHandler(object):
"""TODO
"""
mimetype = 'application/zip'
URI = ('/getzip',)
@staticmethod
def handle(httpd):
raise Exception('ZipFileHandler not implemeted.')
class SuperStreamHandler(OctetStreamHandler):
"""Serve SuperBeam data stream
Writes all files listed in `SuperBeamServer.files` as single stream. The
client needs to request ``/jsonlist`` or ``/superlist`` prior to the
download to be able to split the stream into single files.
URI: ``/getstream``
"""
URI = ('/getstream',)
@staticmethod
def _get_streamsize(files):
totalsize = 0
for file_ in files:
statinfo = os.stat(file_)
totalsize += statinfo.st_size
return totalsize
@staticmethod
def _stream_file_content(files):
for file_ in files:
with open(file_, 'rb') as f_handle:
yield f_handle.read()
@staticmethod
def handle(httpd):
httpd.send_response(200)
httpd.send_header('ylfrettub', '1')
httpd.send_header('Content-Type', 'application/octet-stream')
httpd.send_header('Content-Length',
str(SuperStreamHandler._get_streamsize(httpd.files)))
httpd.send_header('Content-Disposition', 'attachment; '
'filename="RedHotChillyStream"')
httpd.end_headers()
for chunk in SuperStreamHandler._stream_file_content(httpd.files):
httpd.wfile.write(chunk)
class AssetHandler(OctetStreamHandler):
"""TODO
"""
URI = ('*',)
class ApkRequestHandler(object):
"""TODO
"""
mimetype = 'application/vnd.android.package-archive'
URI = ('/getapk',)
@staticmethod
def handle(httpd):
raise Exception(f'Not implemented: Unable to handle {httpd} '
'({ApkRequestHandler.mimetype}')