diff --git a/packetserver/http/database.py b/packetserver/http/database.py new file mode 100644 index 0000000..e69de29 diff --git a/packetserver/runners/http_server.py b/packetserver/runners/http_server.py index 1a577c9..b0859f9 100644 --- a/packetserver/runners/http_server.py +++ b/packetserver/runners/http_server.py @@ -1,15 +1,95 @@ -# runners/http_server.py -import uvicorn -from packetserver.http.server import app -from packetserver.database import open_db # adjust to your actual DB opener +#!/usr/bin/env python3 +""" +PacketServer HTTP Server Runner + +Standalone runner with --db support (local FileStorage or ZEO). + +Examples: + python packetserver/runners/http_server.py --db /path/to/Data.fs --port 8080 + python packetserver/runners/http_server.py --db zeo.host.com:8100 +""" + +import argparse +import sys + +import uvicorn +import ZODB.FileStorage +import ZODB.DB +from packetserver.http.server import app + +# Global DB and connection for reuse in the FastAPI dependency +_db = None +_connection = None + + +def open_database(db_arg: str) -> ZODB.DB.DB: + """ + Open a ZODB database from either a local FileStorage path or ZEO address. + Reuses the same logic as http_user_manager.py. + """ + if ":" in db_arg and db_arg.count(":") == 1 and "." in db_arg.split(":")[0]: + import ZEO + host, port_str = db_arg.split(":") + try: + port = int(port_str) + except ValueError: + raise ValueError(f"Invalid port in ZEO address: {db_arg}") + storage = ZEO.client_storage(host, port) + return ZODB.DB(storage) + else: + # Local FileStorage path + storage = ZODB.FileStorage.FileStorage(db_arg) + return ZODB.DB(storage) + + +def get_db_connection(): + """Helper used in http/server.py dependency (get_current_http_user)""" + global _connection + if _connection is None or _connection.closed: + if _db is None: + raise RuntimeError("Database not opened – run the runner properly") + _connection = _db.open() + return _connection + + +# Monkey-patch the dependency helper so server.py can use it without changes +from packetserver.http import server +server.get_db_connection = get_db_connection # replaces any previous definition + + +def main(): + parser = argparse.ArgumentParser(description="Run the PacketServer HTTP API server") + parser.add_argument("--db", required=True, help="DB path (local /path/to/Data.fs) or ZEO (host:port)") + parser.add_argument("--host", default="0.0.0.0", help="Bind host (default: 0.0.0.0)") + parser.add_argument("--port", type=int, default=8080, help="Port to listen on (default: 8080)") + parser.add_argument("--reload", action="store_true", help="Enable auto-reload during development") + + args = parser.parse_args() + + global _db + try: + _db = open_database(args.db) + print(f"Opened database: {args.db}") + except Exception as e: + print(f"Failed to open database {args.db}: {e}") + sys.exit(1) + + # Open initial connection (will be reused/closed on shutdown) + get_db_connection() + + try: + uvicorn.run( + "packetserver.http.server:app", + host=args.host, + port=args.port, + reload=args.reload, + ) + finally: + if _connection and not _connection.closed: + _connection.close() + if _db: + _db.close() -# Ensure DB is open (same as main server) -open_db() # or however you initialize the global DB connection if __name__ == "__main__": - uvicorn.run( - "packetserver.http.server:app", - host="0.0.0.0", - port=8080, - reload=True, # convenient during development - ) \ No newline at end of file + main() \ No newline at end of file diff --git a/packetserver/runners/http_user_manager.py b/packetserver/runners/http_user_manager.py index 765cb33..3311479 100644 --- a/packetserver/runners/http_user_manager.py +++ b/packetserver/runners/http_user_manager.py @@ -5,8 +5,8 @@ PacketServer HTTP User Management CLI Supports local FileStorage or ZEO databases via --db. Examples: - python runners/http_user_manager.py --db /path/to/Data.fs add W1AW secret - python runners/http_user_manager.py --db zeo.host.com:8100 list + python packetserver/runners/http_user_manager.py --db /path/to/Data.fs add W1AW secret + python packetserver/runners/http_user_manager.py --db zeo.host.com:8100 list """ import argparse @@ -21,7 +21,9 @@ from persistent.mapping import PersistentMapping # Import our HTTP package internals from packetserver.http.auth import HttpUser, ph # ph = PasswordHasher -from packetserver.http.database import HTTP_USERS_KEY + +# Define the key directly here (no separate database.py module needed) +HTTP_USERS_KEY = "httpUsers" def open_database(db_arg: str) -> ZODB.DB.DB: @@ -46,6 +48,7 @@ def open_database(db_arg: str) -> ZODB.DB.DB: def get_or_create_http_users(root): if HTTP_USERS_KEY not in root: root[HTTP_USERS_KEY] = PersistentMapping() + transaction.commit() # safe during initial creation return root[HTTP_USERS_KEY]