From 15a900d009720eea660d2c41f4122722661d1903 Mon Sep 17 00:00:00 2001 From: inexcode Date: Wed, 24 Aug 2022 03:05:06 +0400 Subject: [PATCH] Add Jitsi to services --- selfprivacy_api/services/__init__.py | 14 +- .../services/generic_status_getter.py | 32 ++++ selfprivacy_api/services/jitsi/__init__.py | 142 ++++++++++++++++++ selfprivacy_api/services/jitsi/icon.py | 5 + .../services/mailserver/__init__.py | 39 +---- selfprivacy_api/services/mailserver/icon.py | 2 +- tests/test_graphql/test_system/turned_on.json | 3 + 7 files changed, 192 insertions(+), 45 deletions(-) create mode 100644 selfprivacy_api/services/jitsi/__init__.py create mode 100644 selfprivacy_api/services/jitsi/icon.py diff --git a/selfprivacy_api/services/__init__.py b/selfprivacy_api/services/__init__.py index 30f28a6..a688734 100644 --- a/selfprivacy_api/services/__init__.py +++ b/selfprivacy_api/services/__init__.py @@ -3,6 +3,7 @@ import typing from selfprivacy_api.services.bitwarden import Bitwarden from selfprivacy_api.services.gitea import Gitea +from selfprivacy_api.services.jitsi import Jitsi from selfprivacy_api.services.mailserver import MailServer from selfprivacy_api.services.nextcloud import Nextcloud from selfprivacy_api.services.pleroma import Pleroma @@ -17,6 +18,7 @@ services: list[Service] = [ Nextcloud(), Pleroma(), Ocserv(), + Jitsi(), ] @@ -59,18 +61,6 @@ def get_all_required_dns_records() -> list[ServiceDnsRecord]: content=ip6, ttl=3600, ), - ServiceDnsRecord( - type="A", - name="meet", - content=ip4, - ttl=3600, - ), - ServiceDnsRecord( - type="AAAA", - name="meet", - content=ip6, - ttl=3600, - ), ] for service in get_enabled_services(): dns_records += service.get_dns_records() diff --git a/selfprivacy_api/services/generic_status_getter.py b/selfprivacy_api/services/generic_status_getter.py index c17f4d6..46720af 100644 --- a/selfprivacy_api/services/generic_status_getter.py +++ b/selfprivacy_api/services/generic_status_getter.py @@ -26,3 +26,35 @@ def get_service_status(service: str) -> ServiceStatus: if b"ActiveState=reloading" in service_status: return ServiceStatus.RELOADING return ServiceStatus.OFF + + +def get_service_status_from_several_units(services: list[str]) -> ServiceStatus: + """ + Fetch all service statuses for all services and return the worst status. + Statuses from worst to best: + - OFF + - FAILED + - RELOADING + - ACTIVATING + - DEACTIVATING + - INACTIVE + - ACTIVE + """ + service_statuses = [] + for service in services: + service_statuses.append(get_service_status(service)) + if ServiceStatus.OFF in service_statuses: + return ServiceStatus.OFF + if ServiceStatus.FAILED in service_statuses: + return ServiceStatus.FAILED + if ServiceStatus.RELOADING in service_statuses: + return ServiceStatus.RELOADING + if ServiceStatus.ACTIVATING in service_statuses: + return ServiceStatus.ACTIVATING + if ServiceStatus.DEACTIVATING in service_statuses: + return ServiceStatus.DEACTIVATING + if ServiceStatus.INACTIVE in service_statuses: + return ServiceStatus.INACTIVE + if ServiceStatus.ACTIVE in service_statuses: + return ServiceStatus.ACTIVE + return ServiceStatus.OFF diff --git a/selfprivacy_api/services/jitsi/__init__.py b/selfprivacy_api/services/jitsi/__init__.py new file mode 100644 index 0000000..6b3a973 --- /dev/null +++ b/selfprivacy_api/services/jitsi/__init__.py @@ -0,0 +1,142 @@ +"""Class representing Jitsi service""" +import base64 +import subprocess +import typing + +from selfprivacy_api.jobs import Job, Jobs +from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service +from selfprivacy_api.services.generic_size_counter import get_storage_usage +from selfprivacy_api.services.generic_status_getter import ( + get_service_status, + get_service_status_from_several_units, +) +from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus +from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain +from selfprivacy_api.utils.block_devices import BlockDevice +from selfprivacy_api.utils.huey import huey +import selfprivacy_api.utils.network as network_utils +from selfprivacy_api.services.jitsi.icon import JITSI_ICON + + +class Jitsi(Service): + """Class representing Jitsi service""" + + @staticmethod + def get_id() -> str: + """Return service id.""" + return "jitsi" + + @staticmethod + def get_display_name() -> str: + """Return service display name.""" + return "Jitsi" + + @staticmethod + def get_description() -> str: + """Return service description.""" + return "Jitsi is a free and open-source video conferencing solution." + + @staticmethod + def get_svg_icon() -> str: + """Read SVG icon from file and return it as base64 encoded string.""" + return base64.b64encode(JITSI_ICON.encode("utf-8")).decode("utf-8") + + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + domain = get_domain() + return f"https://meet.{domain}" + + @staticmethod + def is_movable() -> bool: + return False + + @staticmethod + def is_required() -> bool: + return False + + @staticmethod + def is_enabled() -> bool: + with ReadUserData() as user_data: + return user_data.get("jitsi", {}).get("enable", False) + + @staticmethod + def get_status() -> ServiceStatus: + return get_service_status_from_several_units( + ["jitsi-videobridge.service", "jicofo.service"] + ) + + @staticmethod + def enable(): + """Enable Jitsi service.""" + with WriteUserData() as user_data: + if "jitsi" not in user_data: + user_data["jitsi"] = {} + user_data["jitsi"]["enable"] = True + + @staticmethod + def disable(): + """Disable Gitea service.""" + with WriteUserData() as user_data: + if "jitsi" not in user_data: + user_data["jitsi"] = {} + user_data["jitsi"]["enable"] = False + + @staticmethod + def stop(): + subprocess.run(["systemctl", "stop", "jitsi-videobridge.service"]) + subprocess.run(["systemctl", "stop", "jicofo.service"]) + + @staticmethod + def start(): + subprocess.run(["systemctl", "start", "jitsi-videobridge.service"]) + subprocess.run(["systemctl", "start", "jicofo.service"]) + + @staticmethod + def restart(): + subprocess.run(["systemctl", "restart", "jitsi-videobridge.service"]) + subprocess.run(["systemctl", "restart", "jicofo.service"]) + + @staticmethod + def get_configuration(): + return {} + + @staticmethod + def set_configuration(config_items): + return super().set_configuration(config_items) + + @staticmethod + def get_logs(): + return "" + + @staticmethod + def get_storage_usage() -> int: + storage_usage = 0 + storage_usage += get_storage_usage("/var/lib/jitsi-meet") + return storage_usage + + @staticmethod + def get_location() -> str: + return "sda1" + + @staticmethod + def get_dns_records() -> typing.List[ServiceDnsRecord]: + ip4 = network_utils.get_ip4() + ip6 = network_utils.get_ip6() + return [ + ServiceDnsRecord( + type="A", + name="meet", + content=ip4, + ttl=3600, + ), + ServiceDnsRecord( + type="AAAA", + name="meet", + content=ip6, + ttl=3600, + ), + ] + + def move_to_volume(self, volume: BlockDevice) -> Job: + raise NotImplementedError("jitsi service is not movable") diff --git a/selfprivacy_api/services/jitsi/icon.py b/selfprivacy_api/services/jitsi/icon.py new file mode 100644 index 0000000..08bcbb1 --- /dev/null +++ b/selfprivacy_api/services/jitsi/icon.py @@ -0,0 +1,5 @@ +JITSI_ICON = """ + + + +""" diff --git a/selfprivacy_api/services/mailserver/__init__.py b/selfprivacy_api/services/mailserver/__init__.py index 34972a9..1a72f33 100644 --- a/selfprivacy_api/services/mailserver/__init__.py +++ b/selfprivacy_api/services/mailserver/__init__.py @@ -7,7 +7,10 @@ import typing from selfprivacy_api.jobs import Job, JobStatus, Jobs from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service from selfprivacy_api.services.generic_size_counter import get_storage_usage -from selfprivacy_api.services.generic_status_getter import get_service_status +from selfprivacy_api.services.generic_status_getter import ( + get_service_status, + get_service_status_from_several_units, +) from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus import selfprivacy_api.utils as utils from selfprivacy_api.utils.block_devices import BlockDevice @@ -54,37 +57,9 @@ class MailServer(Service): @staticmethod def get_status() -> ServiceStatus: - imap_status = get_service_status("dovecot2.service") - smtp_status = get_service_status("postfix.service") - - if imap_status == ServiceStatus.ACTIVE and smtp_status == ServiceStatus.ACTIVE: - return ServiceStatus.ACTIVE - elif imap_status == ServiceStatus.FAILED or smtp_status == ServiceStatus.FAILED: - return ServiceStatus.FAILED - elif ( - imap_status == ServiceStatus.RELOADING - or smtp_status == ServiceStatus.RELOADING - ): - return ServiceStatus.RELOADING - elif ( - imap_status == ServiceStatus.ACTIVATING - or smtp_status == ServiceStatus.ACTIVATING - ): - return ServiceStatus.ACTIVATING - elif ( - imap_status == ServiceStatus.DEACTIVATING - or smtp_status == ServiceStatus.DEACTIVATING - ): - return ServiceStatus.DEACTIVATING - elif ( - imap_status == ServiceStatus.INACTIVE - or smtp_status == ServiceStatus.INACTIVE - ): - return ServiceStatus.INACTIVE - elif imap_status == ServiceStatus.OFF or smtp_status == ServiceStatus.OFF: - return ServiceStatus.OFF - else: - return ServiceStatus.FAILED + return get_service_status_from_several_units( + ["dovecot2.service", "postfix.service"] + ) @staticmethod def enable(): diff --git a/selfprivacy_api/services/mailserver/icon.py b/selfprivacy_api/services/mailserver/icon.py index cb5b639..a688ef3 100644 --- a/selfprivacy_api/services/mailserver/icon.py +++ b/selfprivacy_api/services/mailserver/icon.py @@ -1,5 +1,5 @@ MAILSERVER_ICON = """ - + """ diff --git a/tests/test_graphql/test_system/turned_on.json b/tests/test_graphql/test_system/turned_on.json index 99a023c..821875b 100644 --- a/tests/test_graphql/test_system/turned_on.json +++ b/tests/test_graphql/test_system/turned_on.json @@ -41,6 +41,9 @@ "pleroma": { "enable": true }, + "jitsi": { + "enable": true + }, "autoUpgrade": { "enable": true, "allowReboot": true