This commit is contained in:
parent
603d08cc61
commit
2c89f3d0c3
@ -7,6 +7,7 @@ psycopg2-binary
|
|||||||
sqlalchemy
|
sqlalchemy
|
||||||
flask_sqlalchemy
|
flask_sqlalchemy
|
||||||
marshmallow
|
marshmallow
|
||||||
|
marshmallow_enum
|
||||||
marshmallow-sqlalchemy
|
marshmallow-sqlalchemy
|
||||||
flask-marshmallow
|
flask-marshmallow
|
||||||
py-healthcheck
|
py-healthcheck
|
||||||
|
@ -8,7 +8,8 @@ from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
|||||||
from healthcheck import HealthCheck
|
from healthcheck import HealthCheck
|
||||||
|
|
||||||
from errorhandlers import register_all_error_handlers
|
from errorhandlers import register_all_error_handlers
|
||||||
from config import *
|
from config import SENTRY_DSN, RELEASE_ID, RELEASEMODE, POSTGRES_DB, PORT, POSTGRES_HOSTNAME, POSTGRES_PASSWORD, \
|
||||||
|
POSTGRES_USERNAME, DEBUG, JWT_SECRET_KEY
|
||||||
from db import db
|
from db import db
|
||||||
from jwtman import jwtman
|
from jwtman import jwtman
|
||||||
from fbcrypt import bcrypt
|
from fbcrypt import bcrypt
|
||||||
|
99
src/kuberclient.py
Normal file
99
src/kuberclient.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Kubernetes Client Tools
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = "@tormakris"
|
||||||
|
__copyright__ = "Copyright 2020, videON Team"
|
||||||
|
__module_name__ = "kuberclient"
|
||||||
|
__version__text__ = "1"
|
||||||
|
|
||||||
|
from kubernetes import client, config
|
||||||
|
|
||||||
|
|
||||||
|
class Kubectl:
|
||||||
|
def __init__(self, name: str, resourcetype: str = "ingest", stream_key: str = "test", push_urls: str = "",
|
||||||
|
ffmpeg_args: str = "", encode_push_urls: str = ""):
|
||||||
|
config.load_incluster_config()
|
||||||
|
self.name = name
|
||||||
|
self.streamtype = resourcetype.lower(),
|
||||||
|
self.stream_key = stream_key,
|
||||||
|
self.push_urls = push_urls,
|
||||||
|
self.ffmpeg_args = ffmpeg_args,
|
||||||
|
self.encode_push_url = encode_push_urls
|
||||||
|
|
||||||
|
def __delete_pod(self):
|
||||||
|
foundpods = client.CoreV1Api().list_namespaced_pod("videon", label_selector=f"app in ({self.name})")
|
||||||
|
for pod in foundpods.items:
|
||||||
|
client.CoreV1Api().delete_namespaced_pod(pod.metadata.name, "videon")
|
||||||
|
|
||||||
|
def __create_configmap(self):
|
||||||
|
configmap = client.V1ConfigMap(api_version="v1", kind="ConfigMap",
|
||||||
|
data={"TYPE": self.streamtype, "STREAM_KEY": self.stream_key,
|
||||||
|
"PUSH_URLS": self.push_urls, "FFMPEG_ARGS": self.ffmpeg_args,
|
||||||
|
"ENCODE_PUSH_URL": self.encode_push_url})
|
||||||
|
client.CoreV1Api().create_namespaced_config_map(namespace="videon", name=self.name, body=configmap)
|
||||||
|
|
||||||
|
def __update_configmap(self):
|
||||||
|
configmap = client.V1ConfigMap(api_version="v1", kind="ConfigMap",
|
||||||
|
data={"TYPE": self.streamtype, "STREAM_KEY": self.stream_key,
|
||||||
|
"PUSH_URLS": self.push_urls, "FFMPEG_ARGS": self.ffmpeg_args,
|
||||||
|
"ENCODE_PUSH_URL": self.encode_push_url})
|
||||||
|
client.CoreV1Api().patch_namespaced_config_map(namespace="videon",name=self.name, body=configmap)
|
||||||
|
|
||||||
|
def __create_deployment(self):
|
||||||
|
envs = [client.V1EnvFromSource(config_map_ref=client.V1ConfigMapEnvSource(name=self.name))]
|
||||||
|
container = client.V1Container(
|
||||||
|
name=self.name,
|
||||||
|
image="registry.kmlabz.com/videon/nginx-streamer",
|
||||||
|
image_pull_policy="Always",
|
||||||
|
ports=[client.V1ContainerPort(container_port=1935)],
|
||||||
|
env_from=envs,
|
||||||
|
)
|
||||||
|
# Template
|
||||||
|
template = client.V1PodTemplateSpec(
|
||||||
|
metadata=client.V1ObjectMeta(labels={"app": self.name}),
|
||||||
|
spec=client.V1PodSpec(containers=[container]))
|
||||||
|
# Spec
|
||||||
|
spec = client.V1DeploymentSpec(
|
||||||
|
replicas=1,
|
||||||
|
template=template)
|
||||||
|
# Deployment
|
||||||
|
deployment = client.V1Deployment(
|
||||||
|
api_version="apps/v1",
|
||||||
|
kind="Deployment",
|
||||||
|
metadata=client.V1ObjectMeta(name=self.name),
|
||||||
|
spec=spec)
|
||||||
|
# Creation of the Deployment in specified namespace
|
||||||
|
client.AppsV1Api().create_namespaced_deployment(
|
||||||
|
namespace="videon", body=deployment
|
||||||
|
)
|
||||||
|
|
||||||
|
def __create_service(self):
|
||||||
|
core_v1_api = client.CoreV1Api()
|
||||||
|
body = client.V1Service(
|
||||||
|
api_version="v1",
|
||||||
|
kind="Service",
|
||||||
|
metadata=client.V1ObjectMeta(
|
||||||
|
name=self.name
|
||||||
|
),
|
||||||
|
spec=client.V1ServiceSpec(
|
||||||
|
selector={"app": self.name},
|
||||||
|
ports=[client.V1ServicePort(
|
||||||
|
port=1935,
|
||||||
|
target_port=1935
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Creation of the Service in specified namespace
|
||||||
|
core_v1_api.create_namespaced_service(namespace="videon", body=body)
|
||||||
|
|
||||||
|
def create_resource(self):
|
||||||
|
self.__create_configmap()
|
||||||
|
self.__create_deployment()
|
||||||
|
self.__create_service()
|
||||||
|
|
||||||
|
def update_resource(self):
|
||||||
|
self.__update_configmap()
|
||||||
|
self.__delete_pod()
|
18
src/listdiffer.py
Normal file
18
src/listdiffer.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Python list differs
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = '@tormakris'
|
||||||
|
__copyright__ = "Copyright 2020, videON Team"
|
||||||
|
__module_name__ = "listdiffer"
|
||||||
|
__version__text__ = "1"
|
||||||
|
|
||||||
|
|
||||||
|
def elementsinfirstlistbutnotinsecond(li1, li2):
|
||||||
|
return list(set(li1) - set(li2))
|
||||||
|
|
||||||
|
|
||||||
|
def elementsinsecondlistbutnotinfirst(li1, li2):
|
||||||
|
return list(set(li2)-set(li1))
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from uuid import uuid4
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
|
from sqlalchemy.orm import backref
|
||||||
from sqlalchemy.sql import func
|
from sqlalchemy.sql import func
|
||||||
from flask_bcrypt import generate_password_hash, check_password_hash
|
from flask_bcrypt import generate_password_hash, check_password_hash
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ __module_name__ = "models"
|
|||||||
__version__text__ = "1"
|
__version__text__ = "1"
|
||||||
|
|
||||||
|
|
||||||
class User(db.Model):
|
class VideonUser(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
|
|
||||||
name = db.Column(db.String, nullable=False, unique=True)
|
name = db.Column(db.String, nullable=False, unique=True)
|
||||||
@ -42,18 +42,23 @@ class StreamResourceTypeEnum(Enum):
|
|||||||
|
|
||||||
|
|
||||||
class StreamResource(db.Model):
|
class StreamResource(db.Model):
|
||||||
id = db.Column(UUID(as_uuid=True), primary_key=True, unique=True, nullable=False, default=uuid4)
|
id = db.Column(UUID(as_uuid=True), primary_key=True, unique=True, nullable=False,
|
||||||
|
server_default=db.text("uuid_generate_v4()"))
|
||||||
resource_type = db.Column(db.Enum(StreamResourceTypeEnum), nullable=False)
|
resource_type = db.Column(db.Enum(StreamResourceTypeEnum), nullable=False)
|
||||||
url = db.Column(db.String, nullable=True)
|
url = db.Column(db.String, nullable=False)
|
||||||
output_urls = db.relationship('OuputUrls', backref='streamresource', lazy=False)
|
|
||||||
bitrate = db.Column(db.Integer, nullable=True)
|
bitrate = db.Column(db.Integer, nullable=True)
|
||||||
width = db.Column(db.Integer, nullable=True)
|
width = db.Column(db.Integer, nullable=True)
|
||||||
height = db.Column(db.Integer, nullable=True)
|
height = db.Column(db.Integer, nullable=True)
|
||||||
parent_id = db.Column(db.Integer, db.ForeignKey('stream_resource.id'), nullable=True)
|
parent_id = db.Column(UUID(as_uuid=True), db.ForeignKey('stream_resource.id'), nullable=True)
|
||||||
children = db.relationship('StreamResource', lazy=False)
|
children = db.relationship('StreamResource', lazy=False)
|
||||||
|
owner_id = db.Column(db.Integer, db.ForeignKey('videon_user.id'), nullable=False)
|
||||||
|
owner = db.relationship('VideonUser', backref=backref("stream_resource", cascade="all, delete"), lazy=False)
|
||||||
|
x = db.Column(db.Integer, nullable=False)
|
||||||
|
y = db.Column(db.Integer, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class OuputUrls(db.Model):
|
class OutputUrls(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
output_url = db.Column(db.String, nullable=False)
|
output_url = db.Column(db.String, nullable=False)
|
||||||
streamresource_id = db.Column(db.Integer, db.ForeignKey('stream_resource.id'), nullable=False)
|
streamresource_id = db.Column(UUID(as_uuid=True), db.ForeignKey('stream_resource.id'), nullable=False)
|
||||||
|
streamresource = db.relationship('StreamResource', backref=backref('output_urls', cascade="all, delete"), lazy=False)
|
||||||
|
358
src/resources.py
358
src/resources.py
@ -1,15 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from uuid import uuid4
|
from uuid import UUID
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from flask_jwt_extended import create_access_token, jwt_required
|
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
|
||||||
from flask_restful import Resource
|
from flask_restful import Resource
|
||||||
from flask import request, current_app, abort
|
from flask import request, current_app, abort
|
||||||
|
|
||||||
from db import db
|
from db import db
|
||||||
from models import User
|
from models import VideonUser, StreamResource, StreamResourceTypeEnum, OutputUrls
|
||||||
from schemas import UserSchema, UserMetadataSchema
|
from schemas import UserSchema, UserMetadataSchema, StreamResourceSchema, IngestInputSchema, EncodeInputSchema, \
|
||||||
|
RestreamInputSchema
|
||||||
from config import REGISTER_DISABLED
|
from config import REGISTER_DISABLED
|
||||||
|
import listdiffer
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Flask Restful endpoints
|
Flask Restful endpoints
|
||||||
@ -20,6 +22,9 @@ __copyright__ = "Copyright 2020, videON Team"
|
|||||||
__module_name__ = "resources"
|
__module_name__ = "resources"
|
||||||
__version__text__ = "1"
|
__version__text__ = "1"
|
||||||
|
|
||||||
|
INVALID_JSON_SCHEMA_MSG = "invalid json schema"
|
||||||
|
DB_ERROR_MSG = "db session error"
|
||||||
|
|
||||||
|
|
||||||
class SignupApi(Resource):
|
class SignupApi(Resource):
|
||||||
"""
|
"""
|
||||||
@ -39,18 +44,17 @@ class SignupApi(Resource):
|
|||||||
userobj = self.userschema.load(body)
|
userobj = self.userschema.load(body)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.warning(e)
|
current_app.logger.warning(e)
|
||||||
abort(417, "invalid json schema")
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
user = User(name=userobj['name'], password=userobj['password'])
|
user = VideonUser(name=userobj['name'], password=userobj['password'])
|
||||||
try:
|
try:
|
||||||
user.hash_password()
|
user.hash_password()
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
|
||||||
current_app.logger.warning(e)
|
current_app.logger.warning(e)
|
||||||
abort(503, "user already exists")
|
abort(503, "user already exists")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
return self.usermetadataschema.dump(user), 200
|
return self.usermetadataschema.dump(user), 200
|
||||||
|
|
||||||
|
|
||||||
@ -69,9 +73,9 @@ class LoginApi(Resource):
|
|||||||
userobj = self.userschema.load(body)
|
userobj = self.userschema.load(body)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.warning(e)
|
current_app.logger.warning(e)
|
||||||
abort(417, "invalid json schema")
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
user = User.query.filter_by(name=userobj['name']).first_or_404()
|
user = VideonUser.query.filter_by(name=userobj['name']).first_or_404()
|
||||||
authorized = user.check_password(userobj['password'])
|
authorized = user.check_password(userobj['password'])
|
||||||
if not authorized:
|
if not authorized:
|
||||||
abort(401, "username or password incorrect")
|
abort(401, "username or password incorrect")
|
||||||
@ -79,14 +83,13 @@ class LoginApi(Resource):
|
|||||||
try:
|
try:
|
||||||
user.last_logon = datetime.datetime.now()
|
user.last_logon = datetime.datetime.now()
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
|
||||||
current_app.logger.exception(e)
|
current_app.logger.exception(e)
|
||||||
abort(503, "db session error")
|
abort(503, DB_ERROR_MSG)
|
||||||
|
|
||||||
expires = datetime.timedelta(days=7)
|
expires = datetime.timedelta(days=7)
|
||||||
access_token = create_access_token(identity=str(user.name), expires_delta=expires)
|
access_token = create_access_token(identity=str(user.name), expires_delta=expires)
|
||||||
|
db.session.commit()
|
||||||
return {'token': access_token}, 200
|
return {'token': access_token}, 200
|
||||||
|
|
||||||
|
|
||||||
@ -97,7 +100,7 @@ class UsersApi(Resource):
|
|||||||
usermetadataschema = UserMetadataSchema(many=True)
|
usermetadataschema = UserMetadataSchema(many=True)
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
users = User.query.all()
|
users = VideonUser.query.all()
|
||||||
return self.usermetadataschema.dump(users), 200
|
return self.usermetadataschema.dump(users), 200
|
||||||
|
|
||||||
|
|
||||||
@ -111,7 +114,7 @@ class UserParameterApi(Resource):
|
|||||||
:param username: Username of user (url parameter)
|
:param username: Username of user (url parameter)
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
user = User.query.filter_by(name=username).first_or_404()
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
return self.usermetadataschema.dump(user), 200
|
return self.usermetadataschema.dump(user), 200
|
||||||
|
|
||||||
def delete(self, username: str):
|
def delete(self, username: str):
|
||||||
@ -120,16 +123,15 @@ class UserParameterApi(Resource):
|
|||||||
:param username: Username of user (url parameter)
|
:param username: Username of user (url parameter)
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
user = User.query.filter_by(name=username).first_or_404()
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
db.session.delete(user)
|
db.session.delete(user)
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
|
||||||
current_app.logger.exception(e)
|
current_app.logger.exception(e)
|
||||||
abort(503, "db session error")
|
abort(503, DB_ERROR_MSG)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
return self.usermetadataschema.dump(user), 200
|
return self.usermetadataschema.dump(user), 200
|
||||||
|
|
||||||
def put(self, username: str):
|
def put(self, username: str):
|
||||||
@ -139,22 +141,21 @@ class UserParameterApi(Resource):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
body = request.get_json()
|
body = request.get_json()
|
||||||
user = User.query.filter_by(name=username).first_or_404()
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
try:
|
try:
|
||||||
userobj = self.userschema.load(body)
|
userobj = self.userschema.load(body)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.warning(e)
|
current_app.logger.warning(e)
|
||||||
abort(417, "invalid json schema")
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user.password = userobj['password']
|
user.password = userobj['password']
|
||||||
user.hash_password()
|
user.hash_password()
|
||||||
db.session.commit()
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
db.session.rollback()
|
|
||||||
current_app.logger.exception(e)
|
current_app.logger.exception(e)
|
||||||
abort(503, "db session error")
|
abort(503, DB_ERROR_MSG)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
return self.usermetadataschema.dump(user), 200
|
return self.usermetadataschema.dump(user), 200
|
||||||
|
|
||||||
|
|
||||||
@ -162,71 +163,352 @@ class CreateIngestResource(Resource):
|
|||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createIngest
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createIngest
|
||||||
"""
|
"""
|
||||||
|
ingestinputschema = IngestInputSchema(many=False)
|
||||||
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
pass
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
ingestobj = self.ingestinputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
ingest = StreamResource(resource_type=StreamResourceTypeEnum['INGEST'],
|
||||||
|
url="rtmp://zelenka.tormakristof.eu:6969/origin/asdasd", x=ingestobj['x'],y=ingestobj['y'])
|
||||||
|
|
||||||
|
# username = get_jwt_identity()
|
||||||
|
username = "jozska"
|
||||||
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
|
ingest.owner_id = user.id
|
||||||
|
try:
|
||||||
|
db.session.add(ingest)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "object already exists")
|
||||||
|
|
||||||
|
if 'outputNeighbours' in ingestobj:
|
||||||
|
for neighbour in ingestobj['outputNeighbours']:
|
||||||
|
neighbourobj = StreamResource.query.filter_by(id=neighbour).first_or_404()
|
||||||
|
if neighbourobj.resource_type == StreamResourceTypeEnum.INGEST:
|
||||||
|
abort(400, "ingest cannot be a downstream component")
|
||||||
|
try:
|
||||||
|
neighbourobj.parent_id = ingest.id
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not set neighbourhood")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(ingest), 200
|
||||||
|
|
||||||
|
|
||||||
class CreateRestreamResource(Resource):
|
class CreateRestreamResource(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createRestream
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createRestream
|
||||||
"""
|
"""
|
||||||
|
restreaminputschema = RestreamInputSchema(many=False)
|
||||||
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
pass
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
restreamobj = self.restreaminputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
restream = StreamResource(resource_type=StreamResourceTypeEnum['RESTREAM'],
|
||||||
|
url="rtmp://zelenka.tormakristof.eu:6969/origin/asdasd",x=restreamobj['x'],y=restreamobj['y'])
|
||||||
|
|
||||||
|
# username = get_jwt_identity()
|
||||||
|
username = "jozska"
|
||||||
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
|
restream.owner_id = user.id
|
||||||
|
if 'inputNeighbour' in restreamobj:
|
||||||
|
restream.parent_id = restreamobj['inputNeighbour']
|
||||||
|
try:
|
||||||
|
db.session.add(restream)
|
||||||
|
db.session.commit()
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "object already exists")
|
||||||
|
for url in restreamobj['outputURLs']:
|
||||||
|
try:
|
||||||
|
outputurl = OutputUrls(output_url=url, streamresource_id=restream.id)
|
||||||
|
db.session.add(outputurl)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not add all outputurls")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(restream), 200
|
||||||
|
|
||||||
|
|
||||||
class CreateEncodeResource(Resource):
|
class CreateEncodeResource(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createEncode
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/createEncode
|
||||||
"""
|
"""
|
||||||
|
encodeinputschema = EncodeInputSchema(many=False)
|
||||||
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
pass
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
encoderobj = self.encodeinputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
encoder = StreamResource(resource_type=StreamResourceTypeEnum['ENCODE'],
|
||||||
|
url="rtmp://zelenka.tormakristof.eu:6969/origin/asdasd",x=encoderobj['x'],y=encoderobj['y'])
|
||||||
|
|
||||||
|
# username = get_jwt_identity()
|
||||||
|
username = "jozska"
|
||||||
|
user = VideonUser.query.filter_by(name=username).first_or_404()
|
||||||
|
encoder.owner_id = user.id
|
||||||
|
|
||||||
|
if 'inputNeighbour' in encoderobj:
|
||||||
|
encoder.parent_id = encoderobj['inputNeighbour']
|
||||||
|
|
||||||
|
if 'bitrate' in encoderobj:
|
||||||
|
encoder.bitrate = encoderobj['bitrate']
|
||||||
|
|
||||||
|
if 'width' in encoderobj:
|
||||||
|
encoder.bitrate = encoderobj['width']
|
||||||
|
|
||||||
|
if 'height' in encoderobj:
|
||||||
|
encoder.bitrate = encoderobj['height']
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.add(encoder)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "object already exists")
|
||||||
|
|
||||||
|
for neighbour in encoderobj['outputNeighbours']:
|
||||||
|
neighbour = StreamResource.query.filter_by(id=neighbour).first_or_404()
|
||||||
|
if neighbour.resource_type == StreamResourceTypeEnum.INGEST:
|
||||||
|
abort(400, "ingest cannot be a downstream component")
|
||||||
|
try:
|
||||||
|
neighbour.parent_id = encoder.id
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not add all neighbours")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(encoder), 200
|
||||||
|
|
||||||
|
|
||||||
class GetAllStreamResources(Resource):
|
class GetAllStreamResources(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/getResource
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/getResource
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
streamresourceschema = StreamResourceSchema(many=True)
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
pass
|
streamreousrces = StreamResource.query.all()
|
||||||
|
return self.streamresourceschema.dump(streamreousrces), 200
|
||||||
|
|
||||||
|
|
||||||
class ManipulateStreamResource(Resource):
|
class ManipulateStreamResource(Resource):
|
||||||
def get(self, resourceid: uuid4):
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
|
def get(self, resourceid: str):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/getAResource
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/getAResource
|
||||||
:param resourceid:
|
:param resourceid:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
pass
|
streamreousrce = StreamResource.query.filter_by(id=UUID(resourceid)).first_or_404()
|
||||||
|
return self.streamresourceschema.dump(streamreousrce), 200
|
||||||
|
|
||||||
def delete(self, resourceid: uuid4):
|
def delete(self, resourceid: str):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/deleteResource
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/deleteResource
|
||||||
:param resourceid:
|
:param resourceid:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
pass
|
streamreousrce = StreamResource.query.filter_by(id=UUID(resourceid)).first_or_404()
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.delete(streamreousrce)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.exception(e)
|
||||||
|
abort(503, DB_ERROR_MSG)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(streamreousrce), 200
|
||||||
|
|
||||||
|
|
||||||
class ModifyIngressResource(Resource):
|
class ModifyIngressResource(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editIngress
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editIngress
|
||||||
"""
|
"""
|
||||||
def put(self, resourceid: uuid4):
|
ingestinputschema = IngestInputSchema(many=False)
|
||||||
pass
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
|
def put(self, resourceid: str):
|
||||||
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
ingestobj = self.ingestinputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
ingest = StreamResource.query.filter_by(id=resourceid).first_or_404()
|
||||||
|
ingest.x = ingestobj['x']
|
||||||
|
ingest.y = ingestobj['y']
|
||||||
|
|
||||||
|
currentoutputneighbours = ingest.children
|
||||||
|
currentoutputneighboursids = [outputneighbour.id for outputneighbour in currentoutputneighbours]
|
||||||
|
|
||||||
|
if 'outputNeighbours' in ingestobj:
|
||||||
|
for removeneighbours in listdiffer.elementsinfirstlistbutnotinsecond(currentoutputneighboursids,
|
||||||
|
ingestobj['outputNeighbours']):
|
||||||
|
neighbourobj = StreamResource.query.filter_by(id=removeneighbours).first_or_404()
|
||||||
|
try:
|
||||||
|
neighbourobj.parent_id = None
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not remove neighbourhood")
|
||||||
|
|
||||||
|
for addneighbours in listdiffer.elementsinsecondlistbutnotinfirst(currentoutputneighboursids,
|
||||||
|
ingestobj['outputNeighbours']):
|
||||||
|
neighbourobj = StreamResource.query.filter_by(id=addneighbours).first_or_404()
|
||||||
|
if neighbourobj.resource_type == StreamResourceTypeEnum.INGEST:
|
||||||
|
abort(400, "ingest cannot be a downstream component")
|
||||||
|
try:
|
||||||
|
neighbourobj.parent_id = ingest.id
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not remove neighbourhood")
|
||||||
|
else:
|
||||||
|
if currentoutputneighbours:
|
||||||
|
for currentneighbour in currentoutputneighbours:
|
||||||
|
try:
|
||||||
|
currentneighbour.parent_id = None
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not remove neighbourhood")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(ingest), 200
|
||||||
|
|
||||||
|
|
||||||
class ModifyRestreamResource(Resource):
|
class ModifyRestreamResource(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editRestream
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editRestream
|
||||||
"""
|
"""
|
||||||
def put(self, resourceid: uuid4):
|
restreaminputschema = RestreamInputSchema(many=False)
|
||||||
pass
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
|
def put(self, resourceid: str):
|
||||||
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
restreamobj = self.restreaminputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
restream = StreamResource.query.filter_by(id=resourceid).first_or_404()
|
||||||
|
restream.x = restreamobj['x']
|
||||||
|
restream.y = restreamobj['y']
|
||||||
|
|
||||||
|
if 'inputNeighbour' in restreamobj:
|
||||||
|
try:
|
||||||
|
restream.parent_id = restreamobj['inputNeighbour']
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not set parent id")
|
||||||
|
|
||||||
|
currentoutputurls = OutputUrls.query.filter_by(streamresource_id=restream.id).all()
|
||||||
|
currentoutputurlurls = [currentoutputurl.output_url for currentoutputurl in currentoutputurls]
|
||||||
|
|
||||||
|
for deleteoutputurl in listdiffer.elementsinfirstlistbutnotinsecond(currentoutputurlurls,
|
||||||
|
restreamobj['outputURLs']):
|
||||||
|
elementtodelete = OutputUrls.query.filter_by(output_url=deleteoutputurl,
|
||||||
|
streamresource_id=restream.id).first_or_404()
|
||||||
|
try:
|
||||||
|
db.session.delete(elementtodelete)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not delete url")
|
||||||
|
for addoutputurl in listdiffer.elementsinsecondlistbutnotinfirst(currentoutputurlurls,
|
||||||
|
restreamobj['outputURLs']):
|
||||||
|
elementtoadd = OutputUrls(output_url=addoutputurl, streamresource_id=restream.id)
|
||||||
|
try:
|
||||||
|
db.session.add(elementtoadd)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "object already exists")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(restream), 200
|
||||||
|
|
||||||
|
|
||||||
class ModifyEncodeResource(Resource):
|
class ModifyEncodeResource(Resource):
|
||||||
"""
|
"""
|
||||||
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editEncode
|
See: https://swagger.kmlabz.com/?urls.primaryName=videON%20Backend#/backend/editEncode
|
||||||
"""
|
"""
|
||||||
def put(self, resourceid: uuid4):
|
encodeinputschema = EncodeInputSchema(many=False)
|
||||||
pass
|
streamresourceschema = StreamResourceSchema(many=False)
|
||||||
|
|
||||||
|
def put(self, resourceid: str):
|
||||||
|
body = request.get_json()
|
||||||
|
|
||||||
|
try:
|
||||||
|
encodeobj = self.encodeinputschema.load(body)
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(417, INVALID_JSON_SCHEMA_MSG)
|
||||||
|
|
||||||
|
encode = StreamResource.query.filter_by(id=resourceid).first_or_404()
|
||||||
|
encode.x = encodeobj['x']
|
||||||
|
encode.y = encodeobj['y']
|
||||||
|
|
||||||
|
if 'inputNeighbour' in encodeobj:
|
||||||
|
encode.parent_id = encodeobj['inputNeighbour']
|
||||||
|
|
||||||
|
if 'bitrate' in encodeobj:
|
||||||
|
encode.bitrate = encodeobj['bitrate']
|
||||||
|
|
||||||
|
if 'width' in encodeobj:
|
||||||
|
encode.bitrate = encodeobj['width']
|
||||||
|
|
||||||
|
if 'height' in encodeobj:
|
||||||
|
encode.bitrate = encodeobj['height']
|
||||||
|
|
||||||
|
currentoutputneighbours = encode.children
|
||||||
|
currentoutputneighboursids = []
|
||||||
|
for outputneighbour in currentoutputneighbours:
|
||||||
|
currentoutputneighboursids.append(outputneighbour.id)
|
||||||
|
|
||||||
|
if 'outputNeighbours' in encodeobj:
|
||||||
|
for removeneighbours in listdiffer.elementsinfirstlistbutnotinsecond(currentoutputneighbours,
|
||||||
|
encodeobj['outputNeighbours']):
|
||||||
|
neighbourobj = StreamResource.query.filter_by(id=removeneighbours).first_or_404()
|
||||||
|
neighbourobj.parent_id = None
|
||||||
|
|
||||||
|
for addneighbours in listdiffer.elementsinsecondlistbutnotinfirst(currentoutputneighbours,
|
||||||
|
encodeobj['outputNeighbours']):
|
||||||
|
neighbourobj = StreamResource.query.filter_by(id=addneighbours).first_or_404()
|
||||||
|
if neighbourobj.resource_type == StreamResourceTypeEnum.INGEST:
|
||||||
|
abort(400, "ingest cannot be a downstream component")
|
||||||
|
neighbourobj.parent_id = encode.id
|
||||||
|
else:
|
||||||
|
if currentoutputneighbours:
|
||||||
|
for currentneighbour in currentoutputneighbours:
|
||||||
|
try:
|
||||||
|
currentneighbour.parent_id = None
|
||||||
|
except Exception as e:
|
||||||
|
current_app.logger.warning(e)
|
||||||
|
abort(503, "could not remove neighbourhood")
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return self.streamresourceschema.dump(encode), 200
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from flask_marshmallow.sqla import auto_field
|
from flask_marshmallow.sqla import auto_field
|
||||||
|
from marshmallow_enum import EnumField
|
||||||
|
|
||||||
from models import User, StreamResource
|
from models import VideonUser, StreamResource, StreamResourceTypeEnum, OutputUrls
|
||||||
from marshm import ma
|
from marshm import ma
|
||||||
|
from db import db
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
|
|
||||||
@ -33,13 +35,17 @@ class UserMetadataSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
Marshmallow schema generated
|
Marshmallow schema generated
|
||||||
"""
|
"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = VideonUser
|
||||||
exclude = ('timestamp', 'password', 'id',)
|
exclude = ('timestamp', 'password', 'id',)
|
||||||
|
sqla_session = db.session
|
||||||
creation_date = auto_field("timestamp", dump_only=False)
|
creation_date = auto_field("timestamp", dump_only=False)
|
||||||
|
streamresources = auto_field
|
||||||
|
|
||||||
|
|
||||||
class IngestInputSchema(ma.Schema):
|
class IngestInputSchema(ma.Schema):
|
||||||
outputNeighbours = fields.List(fields.UUID(), required=True)
|
outputNeighbours = fields.List(fields.UUID(), required=False)
|
||||||
|
x = fields.Integer(required=True)
|
||||||
|
y = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class EncodeInputSchema(ma.Schema):
|
class EncodeInputSchema(ma.Schema):
|
||||||
@ -48,11 +54,35 @@ class EncodeInputSchema(ma.Schema):
|
|||||||
bitrate = fields.Integer(required=False)
|
bitrate = fields.Integer(required=False)
|
||||||
width = fields.Integer(required=False)
|
width = fields.Integer(required=False)
|
||||||
height = fields.Integer(required=False)
|
height = fields.Integer(required=False)
|
||||||
|
x = fields.Integer(required=True)
|
||||||
|
y = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class RestreamInputSchema(ma.Schema):
|
class RestreamInputSchema(ma.Schema):
|
||||||
inputNeighbour = fields.UUID(required=True)
|
inputNeighbour = fields.UUID(required=False)
|
||||||
outputURLs = fields.List(fields.String(), required=True)
|
outputURLs = fields.List(fields.String(), required=True)
|
||||||
|
x = fields.Integer(required=True)
|
||||||
|
y = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class OutputUrlSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
"""
|
||||||
|
Marshmallow schema generated
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
model = OutputUrls
|
||||||
|
fields = ('output_url', )
|
||||||
|
sqla_session = db.session
|
||||||
|
|
||||||
|
|
||||||
|
class StreamResourceIdSchema(ma.SQLAlchemyAutoSchema):
|
||||||
|
"""
|
||||||
|
Marshmallow schema generated
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
model = StreamResource
|
||||||
|
fields = ('id',)
|
||||||
|
sqla_session = db.session
|
||||||
|
|
||||||
|
|
||||||
class StreamResourceSchema(ma.SQLAlchemyAutoSchema):
|
class StreamResourceSchema(ma.SQLAlchemyAutoSchema):
|
||||||
@ -61,7 +91,9 @@ class StreamResourceSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
"""
|
"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = StreamResource
|
model = StreamResource
|
||||||
exclude = ('output_urls', 'parent_id', 'children',)
|
exclude = ('parent_id',)
|
||||||
outputURLs = auto_field('output_urls', dump_only=False)
|
sqla_session = db.session
|
||||||
inputNeighbour = auto_field('parent_id', dump_only=False)
|
resource_type = EnumField(StreamResourceTypeEnum, by_value=True, dump_only=True)
|
||||||
outputNeighbours = auto_field('children', dump_only=False)
|
output_urls = ma.Pluck(OutputUrlSchema, field_name='output_url', many=True, dump_only=True)
|
||||||
|
inputNeighbour = auto_field('parent_id', dump_only=True)
|
||||||
|
children = ma.Pluck(StreamResourceIdSchema, field_name='id', many=True, dump_only=True)
|
||||||
|
Loading…
Reference in New Issue
Block a user