commit 929428279c98ea50e14590a263079e96d4a532ce Author: Arti Zirk Date: Wed May 24 21:17:08 2017 +0300 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c65a729 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv/ +__pycache__ diff --git a/echo360/__init__.py b/echo360/__init__.py new file mode 100644 index 0000000..80ffce2 --- /dev/null +++ b/echo360/__init__.py @@ -0,0 +1,33 @@ +import json +from pathlib import Path + +import falcon + +from .tools import JsonRequest, JsonResponse, error_handler +from .controllers import * + +class AboutResource(): + + def on_get(self, req, resp): + r = {"about": { + "name": "echo360py API", + "version": "1", + "docs": "TODO" + } + } + resp.body = json.dumps(r, indent=4) + + +app = application = falcon.API(request_type=JsonRequest, response_type=JsonResponse) +app.add_error_handler(ValueError, error_handler) +app.add_route("/", AboutResource()) + +app.add_route("/Task", TaskResource()) +app.add_route("/Tasks", TasksCollection()) +app.add_route("/Tasks/{TaskId}", TasksCollection()) + +app.add_route("/Videos/{VideoUuid}/Streams/{StreamId}", StreamCollection()) + +FilesStoragePath = Path("files") +FilesStoragePath.mkdir(parents=True, exist_ok=True) +app.add_route("/File/{FileId}", FileCollection(FilesStoragePath)) diff --git a/echo360/controllers.py b/echo360/controllers.py new file mode 100644 index 0000000..e067e42 --- /dev/null +++ b/echo360/controllers.py @@ -0,0 +1,90 @@ +from enum import IntEnum +from pathlib import Path +from falcon import HTTPNotFound + +class TaskStatus(IntEnum): + Created = 0 + Starting = 1 + Running = 2 + Finished = 3 + Error = 4 + +tasks = [ + { + "TaskId":0, + "Progress":0, + "SourceStreamId":0, + "DestinationStreamId":1, + "TaskStatus":TaskStatus.Created + } +] + +streams = [ + { + "StreamId":0, + "MimeType":"application/x-shockwave-flash", + "Uris":[ + {"Uri":"http://10.42.0.1:8080/File/00000000.swf"}, + {"Uri":"http://10.42.0.1:8080/File/00015000.swf"}, + {"Uri":"http://10.42.0.1:8080/File/00030000.swf"} + ] + }, + { + "StreamId":1, + "MimeType":"video/x-m4v", + "Uris":[] + } +] + +class TaskResource(): + def on_get(self, req, resp): + for task in tasks: + if task["TaskStatus"] in (TaskStatus.Created, TaskStatus.Error): + #task["TaskStatus"] = TaskStatus.Starting + resp.json = task + return + + else: + raise HTTPNotFound() + +class TasksCollection(): + + def on_get(self, req, resp, TaskId=None): + if TaskId: + TaskId = int(TaskId) + try: + resp.json = tasks[TaskId] + except IndexError: + raise HTTPNotFound() + else: + resp.json = tasks + + def on_post(self, req, resp): + task = req.json + tasks.append(task) + + + +class StreamCollection(): + + def on_get(self, req, resp, VideoUuid, StreamId): + print(VideoUuid, StreamId) + StreamId = int(StreamId) + try: + resp.json = streams[StreamId] + except IndexError: + raise HTTPNotFound() + +class FileCollection(): + def __init__(self, path): + self.path = path + + def on_get(self, req, resp, FileId): + File = Path(FileId).name + File = self.path/File + try: + with File.open("rb") as f: + resp.content_type = "application/octet-stream" + resp.body= f.read() + except FileNotFoundError: + raise HTTPNotFound() diff --git a/echo360/tools.py b/echo360/tools.py new file mode 100644 index 0000000..dbfa204 --- /dev/null +++ b/echo360/tools.py @@ -0,0 +1,51 @@ +import json + +from falcon import Request as FalconRequest +from falcon import Response as FalconResponse +from falcon.errors import HTTPBadRequest, HTTPMissingParam, HTTPError +import falcon.status_codes as status + + +class JsonRequest(FalconRequest): + + #__slots__ = set(FalconRequest.__slots__ + ("_json", "_args")) + + + @property + def json(self): + if not hasattr(self, "_json"): + if not self.client_accepts_json: + raise falcon.HTTPUnsupportedMediaType( + 'This API only supports the JSON formated data') + try: + self._json = json.loads(self.stream.read().decode('utf8')) + except json.decoder.JSONDecodeError as err: + raise HTTPBadRequest("JSONDecodeError", str(err)) + return self._json + + +class JsonResponse(FalconResponse): + + #__slots__ = set(FalconRequest.__slots__ + ("_json",)) + + + @property + def json(self): + return self._json + + @json.setter + def json(self, value): + self._json = value + self.body = json.dumps(value, indent=4) + +def error_handler(ex, req, resp, params): + raise HTTPBadRequest(type(ex).__name__, str(ex)) + +class TODOException(HTTPError): + + def __init__(self, **kwargs): + super(TODOException, self).__init__(status.HTTP_NOT_IMPLEMENTED, **kwargs) + + @property + def has_representation(self): + return False diff --git a/files/00000000.swf b/files/00000000.swf new file mode 100644 index 0000000..f73704b Binary files /dev/null and b/files/00000000.swf differ diff --git a/files/00015000.swf b/files/00015000.swf new file mode 100644 index 0000000..69d20cf Binary files /dev/null and b/files/00015000.swf differ diff --git a/files/00030000.swf b/files/00030000.swf new file mode 100644 index 0000000..5eb2ee2 Binary files /dev/null and b/files/00030000.swf differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e32366e --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +falcon diff --git a/uwsgi.ini b/uwsgi.ini new file mode 100644 index 0000000..75451cd --- /dev/null +++ b/uwsgi.ini @@ -0,0 +1,23 @@ +[uwsgi] +plugin=http +plugin=python3 +plugin=python +master=true +virtualenv=venv +processes=1 +need-app=true + +[dev] +ini=:uwsgi +http=:8080 +#static-map2=/=../web +#static-index=index.html +mount=/api/v1=wsgi.py +manage-script-name = true +py-autoreload=1 + +[prod] +ini=:uwsgi +module=echo360 +chdir=/srv/http/echo360py/ +socket=/run/uwsgi/echo360py diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..d33eb07 --- /dev/null +++ b/wsgi.py @@ -0,0 +1,8 @@ +from echo360 import application + +if __name__ == "__main__": + from wsgiref.simple_server import make_server + + httpd = make_server('0.0.0.0', 8080, application) + print("Serving on http://0.0.0.0:8080/") + httpd.serve_forever()