import socket import urllib.request from enum import Enum from socket import timeout from urllib.error import URLError from urllib.request import Request from bs4 import BeautifulSoup from django.db import models from django.utils.functional import cached_property from ordered_model.models import OrderedModel class ServiceStatus(Enum): OK = 'ok' DOWN = 'down' UNKNOWN = 'unknown' class Service(OrderedModel): short_name = models.CharField(null=False, max_length=64) image = models.ImageField(null=True, blank=True, upload_to='services') description = models.TextField(null=True, blank=True) port = models.IntegerField(null=True, blank=True, help_text="Used for checking status") url = models.URLField() def __str__(self): return f"{self.short_name} ({self.url})" @cached_property def index_request(self): try: request = Request(self.url, headers={'User-Agent': 'its just me humble status page'}) return urllib.request.urlopen(request, timeout=1) except (URLError, timeout): return None def get_status(self): if self.port: a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) location = ("localhost", self.port) result_of_check = a_socket.connect_ex(location) if result_of_check == 0: return ServiceStatus.OK else: return ServiceStatus.DOWN if self.index_request and self.index_request.getcode() == 200: return ServiceStatus.OK else: return ServiceStatus.DOWN @cached_property def image_or_favicon(self): if self.image: return self.image.url if self.index_request: parsed_html = BeautifulSoup(self.index_request, features="html.parser") link_tags = parsed_html.find_all('link') for rel in ['apple-touch-icon', 'shortcut', 'icon']: for link_tag in link_tags: if rel in link_tag.attrs['rel']: result = link_tag.attrs['href'] if self.url not in result: return self.url + (result if result.startswith("/") else f"/{result}") else: return result