Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion bot/vikingbot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
"""

import warnings
from importlib.metadata import PackageNotFoundError, version as _pkg_version

try:
__version__ = _pkg_version("openviking")
except PackageNotFoundError:
__version__ = "0.0.0+unknown"

__version__ = "0.1.3"
__logo__ = "🐈"

# Suppress RequestsDependencyWarning from requests module
Expand Down
29 changes: 29 additions & 0 deletions bot/vikingbot/cli/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import json
import os
import select
import socket
import sys
import time
import warnings
Expand Down Expand Up @@ -83,6 +84,32 @@ def _init_bot_data(config):
set_bot_data_path(config.bot_data_path)


def _abort_if_port_in_use(port: int, label: str) -> None:
"""Exit with a clear message if anything is already listening on ``port``.

Without this check, a stale process holding the port keeps serving
traffic while a freshly-started gateway silently fails to bind — the
operator believes they upgraded but the old (potentially unpatched)
binary is still answering requests.
"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.5)
try:
s.connect(("127.0.0.1", port))
in_use = True
except (ConnectionRefusedError, socket.timeout, OSError):
in_use = False
if in_use:
print(
f"Error: {label} port {port} is already in use.\n"
f" A previous process is still bound — refusing to start a duplicate.\n"
f" Identify it: lsof -nP -iTCP:{port} -sTCP:LISTEN\n"
f" Kill it, then retry.",
file=sys.stderr,
)
sys.exit(1)


# ---------------------------------------------------------------------------
# CLI input: prompt_toolkit for editing, paste, history, and display
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -249,6 +276,8 @@ def gateway(
):
"""Start the vikingbot gateway with OpenAPI chat enabled by default."""

_abort_if_port_in_use(port, "vikingbot gateway")

if verbose:
import logging

Expand Down
30 changes: 30 additions & 0 deletions openviking/server/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import argparse
import os
import shutil
import socket
import subprocess
import sys
import time
Expand Down Expand Up @@ -34,6 +35,34 @@ def _get_version() -> str:
return "unknown"


VIKINGBOT_DEFAULT_PORT = 18790


def _abort_if_port_in_use(port: int, label: str) -> None:
"""Exit with a clear message if anything is already listening on ``port``.

Without this, ``--with-bot`` would spawn a vikingbot subprocess that
silently fails to bind while a stale process keeps serving traffic —
the operator believes they upgraded but the old binary still answers.
"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.5)
try:
s.connect(("127.0.0.1", port))
in_use = True
except (ConnectionRefusedError, socket.timeout, OSError):
in_use = False
if in_use:
print(
f"Error: {label} port {port} is already in use.\n"
f" A previous process is still bound — refusing to start a duplicate.\n"
f" Identify it: lsof -nP -iTCP:{port} -sTCP:LISTEN\n"
f" Kill it, then retry.",
file=sys.stderr,
)
sys.exit(1)


def _normalize_host_arg(host: Optional[str]) -> Optional[str]:
"""Normalize special CLI host values."""
if host is None:
Expand Down Expand Up @@ -170,6 +199,7 @@ def main():

bot_process: Optional[BotProcess] = None
if config.with_bot:
_abort_if_port_in_use(VIKINGBOT_DEFAULT_PORT, "vikingbot gateway")
print(f"Bot API proxy enabled, forwarding to {config.bot_api_url}")
# Determine if bot logging should be enabled
enable_bot_logging = args.enable_bot_logging
Expand Down
Loading