mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Add basic typing for multiple modules:
* log.py * video.py * watchdog.py * zeroconf.py
This commit is contained in:
parent
c6234bf548
commit
41f58c7692
@ -4,13 +4,14 @@ import threading
|
|||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import queue
|
import queue
|
||||||
import multiprocessing as mp
|
from multiprocessing.queues import Queue
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
|
from typing import Deque
|
||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
|
|
||||||
def listener_configurer():
|
def listener_configurer() -> None:
|
||||||
root = logging.getLogger()
|
root = logging.getLogger()
|
||||||
console_handler = logging.StreamHandler()
|
console_handler = logging.StreamHandler()
|
||||||
formatter = logging.Formatter(
|
formatter = logging.Formatter(
|
||||||
@ -21,14 +22,14 @@ def listener_configurer():
|
|||||||
root.setLevel(logging.INFO)
|
root.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def root_configurer(queue):
|
def root_configurer(queue: Queue) -> None:
|
||||||
h = handlers.QueueHandler(queue)
|
h = handlers.QueueHandler(queue)
|
||||||
root = logging.getLogger()
|
root = logging.getLogger()
|
||||||
root.addHandler(h)
|
root.addHandler(h)
|
||||||
root.setLevel(logging.INFO)
|
root.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
def log_process(log_queue):
|
def log_process(log_queue: Queue) -> None:
|
||||||
threading.current_thread().name = f"logger"
|
threading.current_thread().name = f"logger"
|
||||||
setproctitle("frigate.logger")
|
setproctitle("frigate.logger")
|
||||||
listener_configurer()
|
listener_configurer()
|
||||||
@ -43,34 +44,32 @@ def log_process(log_queue):
|
|||||||
|
|
||||||
# based on https://codereview.stackexchange.com/a/17959
|
# based on https://codereview.stackexchange.com/a/17959
|
||||||
class LogPipe(threading.Thread):
|
class LogPipe(threading.Thread):
|
||||||
def __init__(self, log_name, level):
|
def __init__(self, log_name: str):
|
||||||
"""Setup the object with a logger and a loglevel
|
"""Setup the object with a logger and start the thread"""
|
||||||
and start the thread
|
|
||||||
"""
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.daemon = False
|
self.daemon = False
|
||||||
self.logger = logging.getLogger(log_name)
|
self.logger = logging.getLogger(log_name)
|
||||||
self.level = level
|
self.level = logging.ERROR
|
||||||
self.deque = deque(maxlen=100)
|
self.deque: Deque[str] = deque(maxlen=100)
|
||||||
self.fdRead, self.fdWrite = os.pipe()
|
self.fdRead, self.fdWrite = os.pipe()
|
||||||
self.pipeReader = os.fdopen(self.fdRead)
|
self.pipeReader = os.fdopen(self.fdRead)
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self) -> int:
|
||||||
"""Return the write file descriptor of the pipe"""
|
"""Return the write file descriptor of the pipe"""
|
||||||
return self.fdWrite
|
return self.fdWrite
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
"""Run the thread, logging everything."""
|
"""Run the thread, logging everything."""
|
||||||
for line in iter(self.pipeReader.readline, ""):
|
for line in iter(self.pipeReader.readline, ""):
|
||||||
self.deque.append(line.strip("\n"))
|
self.deque.append(line.strip("\n"))
|
||||||
|
|
||||||
self.pipeReader.close()
|
self.pipeReader.close()
|
||||||
|
|
||||||
def dump(self):
|
def dump(self) -> None:
|
||||||
while len(self.deque) > 0:
|
while len(self.deque) > 0:
|
||||||
self.logger.log(self.level, self.deque.popleft())
|
self.logger.log(self.level, self.deque.popleft())
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
"""Close the write end of the pipe."""
|
"""Close the write end of the pipe."""
|
||||||
os.close(self.fdWrite)
|
os.close(self.fdWrite)
|
||||||
|
@ -1,6 +1,40 @@
|
|||||||
[mypy]
|
[mypy]
|
||||||
python_version = 3.9
|
python_version = 3.9
|
||||||
|
show_error_codes = true
|
||||||
|
follow_imports = silent
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
strict_equality = true
|
||||||
|
warn_incomplete_stub = true
|
||||||
|
warn_redundant_casts = true
|
||||||
|
warn_unused_configs = true
|
||||||
|
warn_unused_ignores = true
|
||||||
|
enable_error_code = ignore-without-code
|
||||||
|
check_untyped_defs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
disallow_subclassing_any = true
|
||||||
|
disallow_untyped_calls = true
|
||||||
|
disallow_untyped_decorators = true
|
||||||
|
disallow_untyped_defs = true
|
||||||
|
no_implicit_optional = true
|
||||||
|
warn_return_any = true
|
||||||
|
warn_unreachable = true
|
||||||
|
no_implicit_reexport = true
|
||||||
|
|
||||||
[mypy-frigate.*]
|
[mypy-frigate.*]
|
||||||
ignore_errors = true
|
ignore_errors = true
|
||||||
|
|
||||||
|
[mypy-frigate.const]
|
||||||
|
ignore_errors = false
|
||||||
|
|
||||||
|
[mypy-frigate.log]
|
||||||
|
ignore_errors = false
|
||||||
|
|
||||||
|
[mypy-frigate.version]
|
||||||
|
ignore_errors = false
|
||||||
|
|
||||||
|
[mypy-frigate.watchdog]
|
||||||
|
ignore_errors = false
|
||||||
|
disallow_untyped_calls = false
|
||||||
|
|
||||||
|
[mypy-frigate.zeroconf]
|
||||||
|
ignore_errors = false
|
||||||
|
@ -203,7 +203,7 @@ class CameraWatchdog(threading.Thread):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.capture_thread = None
|
self.capture_thread = None
|
||||||
self.ffmpeg_detect_process = None
|
self.ffmpeg_detect_process = None
|
||||||
self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect", logging.ERROR)
|
self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect")
|
||||||
self.ffmpeg_other_processes = []
|
self.ffmpeg_other_processes = []
|
||||||
self.camera_fps = camera_fps
|
self.camera_fps = camera_fps
|
||||||
self.ffmpeg_pid = ffmpeg_pid
|
self.ffmpeg_pid = ffmpeg_pid
|
||||||
@ -219,8 +219,7 @@ class CameraWatchdog(threading.Thread):
|
|||||||
if "detect" in c["roles"]:
|
if "detect" in c["roles"]:
|
||||||
continue
|
continue
|
||||||
logpipe = LogPipe(
|
logpipe = LogPipe(
|
||||||
f"ffmpeg.{self.camera_name}.{'_'.join(sorted(c['roles']))}",
|
f"ffmpeg.{self.camera_name}.{'_'.join(sorted(c['roles']))}"
|
||||||
logging.ERROR,
|
|
||||||
)
|
)
|
||||||
self.ffmpeg_other_processes.append(
|
self.ffmpeg_other_processes.append(
|
||||||
{
|
{
|
||||||
|
@ -5,21 +5,22 @@ import time
|
|||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
from frigate.util import (
|
from frigate.edgetpu import EdgeTPUProcess
|
||||||
restart_frigate,
|
from frigate.util import restart_frigate
|
||||||
)
|
from multiprocessing.synchronize import Event
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FrigateWatchdog(threading.Thread):
|
class FrigateWatchdog(threading.Thread):
|
||||||
def __init__(self, detectors, stop_event):
|
def __init__(self, detectors: Dict[str, EdgeTPUProcess], stop_event: Event):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.name = "frigate_watchdog"
|
self.name = "frigate_watchdog"
|
||||||
self.detectors = detectors
|
self.detectors = detectors
|
||||||
self.stop_event = stop_event
|
self.stop_event = stop_event
|
||||||
|
|
||||||
def run(self):
|
def run(self) -> None:
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
while not self.stop_event.wait(10):
|
while not self.stop_event.wait(10):
|
||||||
now = datetime.datetime.now().timestamp()
|
now = datetime.datetime.now().timestamp()
|
||||||
@ -32,7 +33,10 @@ class FrigateWatchdog(threading.Thread):
|
|||||||
"Detection appears to be stuck. Restarting detection process..."
|
"Detection appears to be stuck. Restarting detection process..."
|
||||||
)
|
)
|
||||||
detector.start_or_restart()
|
detector.start_or_restart()
|
||||||
elif not detector.detect_process.is_alive():
|
elif (
|
||||||
|
detector.detect_process is not None
|
||||||
|
and not detector.detect_process.is_alive()
|
||||||
|
):
|
||||||
logger.info("Detection appears to have stopped. Exiting frigate...")
|
logger.info("Detection appears to have stopped. Exiting frigate...")
|
||||||
restart_frigate()
|
restart_frigate()
|
||||||
|
|
||||||
|
@ -14,38 +14,41 @@ logger = logging.getLogger(__name__)
|
|||||||
ZEROCONF_TYPE = "_frigate._tcp.local."
|
ZEROCONF_TYPE = "_frigate._tcp.local."
|
||||||
|
|
||||||
# Taken from: http://stackoverflow.com/a/11735897
|
# Taken from: http://stackoverflow.com/a/11735897
|
||||||
def get_local_ip() -> str:
|
def get_local_ip() -> bytes:
|
||||||
"""Try to determine the local IP address of the machine."""
|
"""Try to determine the local IP address of the machine."""
|
||||||
|
host_ip_str = ""
|
||||||
try:
|
try:
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
|
||||||
# Use Google Public DNS server to determine own IP
|
# Use Google Public DNS server to determine own IP
|
||||||
sock.connect(("8.8.8.8", 80))
|
sock.connect(("8.8.8.8", 80))
|
||||||
|
|
||||||
return sock.getsockname()[0] # type: ignore
|
host_ip_str = sock.getsockname()[0]
|
||||||
except OSError:
|
except OSError:
|
||||||
try:
|
try:
|
||||||
return socket.gethostbyname(socket.gethostname())
|
host_ip_str = socket.gethostbyname(socket.gethostname())
|
||||||
except socket.gaierror:
|
except socket.gaierror:
|
||||||
return "127.0.0.1"
|
host_ip_str = "127.0.0.1"
|
||||||
finally:
|
finally:
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
|
try:
|
||||||
|
host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip_str)
|
||||||
|
except OSError:
|
||||||
|
host_ip_pton = socket.inet_pton(socket.AF_INET6, host_ip_str)
|
||||||
|
|
||||||
def broadcast_zeroconf(frigate_id):
|
return host_ip_pton
|
||||||
|
|
||||||
|
|
||||||
|
def broadcast_zeroconf(frigate_id: str) -> Zeroconf:
|
||||||
zeroconf = Zeroconf(interfaces=InterfaceChoice.Default, ip_version=IPVersion.V4Only)
|
zeroconf = Zeroconf(interfaces=InterfaceChoice.Default, ip_version=IPVersion.V4Only)
|
||||||
|
|
||||||
host_ip = get_local_ip()
|
host_ip = get_local_ip()
|
||||||
|
|
||||||
try:
|
|
||||||
host_ip_pton = socket.inet_pton(socket.AF_INET, host_ip)
|
|
||||||
except OSError:
|
|
||||||
host_ip_pton = socket.inet_pton(socket.AF_INET6, host_ip)
|
|
||||||
|
|
||||||
info = ServiceInfo(
|
info = ServiceInfo(
|
||||||
ZEROCONF_TYPE,
|
ZEROCONF_TYPE,
|
||||||
name=f"{frigate_id}.{ZEROCONF_TYPE}",
|
name=f"{frigate_id}.{ZEROCONF_TYPE}",
|
||||||
addresses=[host_ip_pton],
|
addresses=[host_ip],
|
||||||
port=5000,
|
port=5000,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,4 +59,4 @@ def broadcast_zeroconf(frigate_id):
|
|||||||
logger.error(
|
logger.error(
|
||||||
"Frigate instance with identical name present in the local network"
|
"Frigate instance with identical name present in the local network"
|
||||||
)
|
)
|
||||||
return zeroconf
|
return zeroconf
|
||||||
|
Loading…
Reference in New Issue
Block a user