sbeam/sbeam.py

124 lines
3.8 KiB
Python
Executable File

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2018 jpk <jpk+dev@goatpr0n.de>
#
# Distributed under terms of the MIT license.
"""
> GET /getstream HTTP/1.1
> Host: 192.168.178.50:8080
> User-Agent: sbeam
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< ylfrettub: 1
< Content-Disposition: attachment; filename="RedHotChillyStream"
< Date: Fri, 09 Aug 2019 12:57:20 GMT
< Content-Length: 8137967
< Content-Type: application/octet-stream
Server QR Code = http://superbe.am/q?ATKyqMA=
Base64 = 01 32 b2 a8 c0 = 01 50 178 168 192
"""
import os
import click
import requests
import SuperBeam
@click.group()
def cli():
pass
@cli.command()
@click.option('--recursive', default=True, is_flag=True,
help='Recurse into sub directories')
@click.argument('filename', nargs=-1, type=click.Path(exists=True))
def serve(recursive, filename):
"""Start a SuperBeam serve to serve FILENAME [FILENAME ...].
FILENAME can be one or more files or directories.
"""
filelist = SuperBeam.build_filelist(filename, recursive)
SuperBeam.serve_forever(filelist)
@cli.command()
@click.argument('host', default='127.0.0.1')
def superlist(host):
"""Fetch superlist from HOST running SupberBeam.
HOST is the IP of the SuperBeam server.
"""
with requests.get(f'http://{host}:8080/superlist',
headers={'User-Agent': 'sbeam'}) as response:
assert response.status_code == 200
return response.text.split('\n')
@cli.command()
@click.argument('host', default='127.0.0.1')
@click.argument('filename', default='received.bin')
def receive(host, filename):
"""Download a SuperBeam stream from HOST and save as FILENAME.
HOST is the IP of the SuperBeam server. The SuperBeam stream will be saved
as FILENAME. To split the files into individual files, the `split-stream`
command with the Superlist from the `superlist` command has to be used.
"""
with requests.get(f'http://{host}:8080/getstream', stream=True,
headers={'User-Agent': 'sbeam'}) as response:
assert response.status_code == 200
with open(filename, 'wb') as handle:
for chunk in response.iter_content(chunk_size=8196):
handle.write(chunk)
@cli.command()
@click.argument('filename', default='received.bin', type=click.File('r'))
@click.argument('superlist', default='superlist', type=click.File('r'))
@click.argument('directory', default='received', type=click.File('w'))
def split_stream(filename, superlist, directory):
"""Split FILENAME with SUPERLIST into single files.
The SuperBeam stream FILENAME from the `receive` command is split into
individual files as described by SUPERLIST. The SUPERLIST can be downloaded
with the `superlist` command. The individual files are stored in DIRECTORY.
"""
with open(filename, 'rb') as blob:
for item in superlist:
if not item:
break
filename, filesize, filepath, timestamp = item.split('||')
fullpath = os.path.join(directory, filepath[1:])
os.makedirs(fullpath, exist_ok=True)
print(f'Saving {filename} ({filesize} bytes) to disk...')
with open(os.path.join(fullpath, filename), 'wb') as handle:
handle.write(blob.read(int(filesize)))
@cli.command()
def tui():
SuperBeam.tui.run()
if __name__ == '__main__':
cli()
# to_download = 0
# superlist = get_superlist()
# try:
# for item in superlist:
# to_download += int(item.split('||')[1])
# except IndexError:
# print(f'Download stream contains {len(superlist) - 1} items.')
# finally:
# print(f'Target download size is {to_download} bytes.')
# save_stream('data.gz')
# split_stream('data.gz', 'received', superlist)