archivebox_server.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/env python3
  2. __package__ = 'archivebox.cli'
  3. from typing import Iterable
  4. import rich_click as click
  5. from rich import print
  6. from archivebox.misc.util import docstring, enforce_types
  7. from archivebox.config.common import SERVER_CONFIG
  8. @enforce_types
  9. def server(runserver_args: Iterable[str]=(SERVER_CONFIG.BIND_ADDR,),
  10. reload: bool=False,
  11. init: bool=False,
  12. debug: bool=False,
  13. daemonize: bool=False,
  14. nothreading: bool=False) -> None:
  15. """Run the ArchiveBox HTTP server"""
  16. runserver_args = list(runserver_args)
  17. if init:
  18. from archivebox.cli.archivebox_init import init as archivebox_init
  19. archivebox_init(quick=True)
  20. print()
  21. from archivebox.misc.checks import check_data_folder
  22. check_data_folder()
  23. from django.core.management import call_command
  24. from django.contrib.auth.models import User
  25. from archivebox.config.common import SHELL_CONFIG
  26. if not User.objects.filter(is_superuser=True).exclude(username='system').exists():
  27. print()
  28. print('[violet]Hint:[/violet] To create an [bold]admin username & password[/bold] for the [deep_sky_blue3][underline][link=http://{host}:{port}/admin]Admin UI[/link][/underline][/deep_sky_blue3], run:')
  29. print(' [green]archivebox manage createsuperuser[/green]')
  30. print()
  31. host = '127.0.0.1'
  32. port = '8000'
  33. try:
  34. host_and_port = [arg for arg in runserver_args if arg.replace('.', '').replace(':', '').isdigit()][0]
  35. if ':' in host_and_port:
  36. host, port = host_and_port.split(':')
  37. else:
  38. if '.' in host_and_port:
  39. host = host_and_port
  40. else:
  41. port = host_and_port
  42. except IndexError:
  43. pass
  44. if SHELL_CONFIG.DEBUG:
  45. print('[green][+] Starting ArchiveBox webserver in DEBUG mode...[/green]')
  46. print(f' [blink][green]>[/green][/blink] Starting ArchiveBox webserver on [deep_sky_blue4][link=http://{host}:{port}]http://{host}:{port}[/link][/deep_sky_blue4]')
  47. print(f' [green]>[/green] Log in to ArchiveBox Admin UI on [deep_sky_blue3][link=http://{host}:{port}/admin]http://{host}:{port}/admin[/link][/deep_sky_blue3]')
  48. print(' > Writing ArchiveBox error log to ./logs/errors.log')
  49. if not reload:
  50. runserver_args.append('--noreload') # '--insecure'
  51. if nothreading:
  52. runserver_args.append('--nothreading')
  53. call_command("runserver", *runserver_args)
  54. else:
  55. from archivebox.workers.supervisord_util import (
  56. get_existing_supervisord_process,
  57. get_worker,
  58. start_server_workers,
  59. tail_multiple_worker_logs,
  60. is_port_in_use,
  61. )
  62. from archivebox.workers.orchestrator import Orchestrator
  63. import sys
  64. # Check if port is already in use
  65. if is_port_in_use(host, int(port)):
  66. print(f'[red][X] Error: Port {port} is already in use[/red]')
  67. print(f' Another process (possibly daphne) is already listening on {host}:{port}')
  68. print(f' Stop the conflicting process or choose a different port')
  69. sys.exit(1)
  70. # Check if orchestrator is already running for this data directory
  71. if Orchestrator.is_running():
  72. print(f'[red][X] Error: ArchiveBox orchestrator is already running for this data directory[/red]')
  73. print(f' Stop the existing orchestrator before starting a new server')
  74. print(f' To stop: pkill -f "archivebox manage orchestrator"')
  75. sys.exit(1)
  76. # Check if supervisord is already running
  77. supervisor = get_existing_supervisord_process()
  78. if supervisor:
  79. daphne_proc = get_worker(supervisor, 'worker_daphne')
  80. # If daphne is already running, error out
  81. if daphne_proc and daphne_proc.get('statename') == 'RUNNING':
  82. orchestrator_proc = get_worker(supervisor, 'worker_orchestrator')
  83. print('[red][X] Error: ArchiveBox server is already running[/red]')
  84. print(f' [green]√[/green] Web server (worker_daphne) is RUNNING on [deep_sky_blue4][link=http://{host}:{port}]http://{host}:{port}[/link][/deep_sky_blue4]')
  85. if orchestrator_proc and orchestrator_proc.get('statename') == 'RUNNING':
  86. print(f' [green]√[/green] Background worker (worker_orchestrator) is RUNNING')
  87. print()
  88. print('[yellow]To stop the existing server, run:[/yellow]')
  89. print(' pkill -f "archivebox server"')
  90. print(' pkill -f supervisord')
  91. sys.exit(1)
  92. # Otherwise, daphne is not running - fall through to start it
  93. # No existing workers found - start new ones
  94. print('[green][+] Starting ArchiveBox webserver...[/green]')
  95. print(f' [blink][green]>[/green][/blink] Starting ArchiveBox webserver on [deep_sky_blue4][link=http://{host}:{port}]http://{host}:{port}[/link][/deep_sky_blue4]')
  96. print(f' [green]>[/green] Log in to ArchiveBox Admin UI on [deep_sky_blue3][link=http://{host}:{port}/admin]http://{host}:{port}/admin[/link][/deep_sky_blue3]')
  97. print(' > Writing ArchiveBox error log to ./logs/errors.log')
  98. print()
  99. start_server_workers(host=host, port=port, daemonize=daemonize)
  100. print("\n[i][green][🟩] ArchiveBox server shut down gracefully.[/green][/i]")
  101. @click.command()
  102. @click.argument('runserver_args', nargs=-1)
  103. @click.option('--reload', is_flag=True, help='Enable auto-reloading when code or templates change')
  104. @click.option('--debug', is_flag=True, help='Enable DEBUG=True mode with more verbose errors')
  105. @click.option('--nothreading', is_flag=True, help='Force runserver to run in single-threaded mode')
  106. @click.option('--init', is_flag=True, help='Run a full archivebox init/upgrade before starting the server')
  107. @click.option('--daemonize', is_flag=True, help='Run the server in the background as a daemon')
  108. @docstring(server.__doc__)
  109. def main(**kwargs):
  110. server(**kwargs)
  111. if __name__ == '__main__':
  112. main()