Skip to content

Commit 4a974c0

Browse files
committed
fixes
1 parent c4a382e commit 4a974c0

File tree

3 files changed

+85
-25
lines changed

3 files changed

+85
-25
lines changed

bota/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ __*__
33
.DS*
44
src/**/package.json
55
package-lock.json
6-
*.egg-info
6+
*.egg-info
7+
gpt/

bota/src/bota/__main__.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
from os import path, makedirs
77

88
from .package_storage import get_package_storage
9-
from .vm import extractRepositoryName, install_scraper_in_vm, install_ui_scraper_in_vm
9+
from .vm import extractRepositoryName, install_desktop_app_in_vm, install_scraper_in_vm, install_ui_scraper_in_vm
1010

11-
@click.group(context_settings=dict(max_content_width=95))
11+
@click.group(context_settings=dict(max_content_width=160))
1212
def cli():
1313
"""Botasaurus CLI"""
1414
pass
@@ -1162,7 +1162,7 @@ def convert(self, value, param, ctx):
11621162
)
11631163
def install_scraper(repo_url, max_retry, name):
11641164
"""
1165-
Clones and installs a scraper from a given GitHub repository.
1165+
Clones and installs a scraper from a given GitHub repository
11661166
"""
11671167
repo_url = repo_url.strip()
11681168

@@ -1176,6 +1176,55 @@ def install_scraper(repo_url, max_retry, name):
11761176

11771177
install_scraper_in_vm(repo_url, folder_name, max_retry)
11781178

1179+
@cli.command()
1180+
@click.option(
1181+
"--debian-installer-url",
1182+
prompt="Enter the URL to download the .deb installer",
1183+
required=True,
1184+
type=str,
1185+
help="URL to download the .deb package for the desktop app",
1186+
)
1187+
@click.option(
1188+
"--port",
1189+
default=8000,
1190+
type=click.IntRange(1, 65535),
1191+
help="Port on which the desktop app will run. Defaults to 8000",
1192+
)
1193+
@click.option(
1194+
"--skip-apache-request-routing",
1195+
is_flag=True,
1196+
help="Skip setting up Apache request routing",
1197+
)
1198+
@click.option(
1199+
"--api-path-prefix",
1200+
default=None,
1201+
type=str,
1202+
help="Optional API path prefix for request routing",
1203+
)
1204+
def install_desktop_app(debian_installer_url, port, skip_apache_request_routing, api_path_prefix):
1205+
"""
1206+
Installs a desktop app in the VM using the provided .deb installer URL
1207+
"""
1208+
# This command will:
1209+
# 1. Download and install the specified .deb package
1210+
# 2. Setup systemctl to run app at all times
1211+
# 3. Optionally configures Apache to route requests
1212+
1213+
click.echo("------------")
1214+
click.echo("Performing the following steps to install the desktop app:")
1215+
click.echo(f" - Downloading and installing the desktop app from {debian_installer_url}")
1216+
click.echo(" - Setting up systemctl to run app at all times")
1217+
if not skip_apache_request_routing:
1218+
click.echo(" - Configuring Apache request routing")
1219+
click.echo("------------")
1220+
print(debian_installer_url, port, skip_apache_request_routing, api_path_prefix)
1221+
# Call the actual implementation (to be defined elsewhere)
1222+
install_desktop_app_in_vm(
1223+
debian_installer_url.strip(),
1224+
port,
1225+
skip_apache_request_routing,
1226+
api_path_prefix.strip() if api_path_prefix else None
1227+
)
11791228

11801229
@cli.command()
11811230
def switch_project():

bota/src/bota/vm.py

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ def get_vm_ip():
5252

5353
def create_visit_ip_text(ip):
5454
return "Hurray! your scraper is up and running. Visit http://{}/ to use it.".format(ip)
55-
5655
def wait_till_up(ip):
5756
"""
5857
Polls the given IP address every 10 seconds for 180 seconds to check if it's up.
@@ -63,11 +62,11 @@ def wait_till_up(ip):
6362
Raises:
6463
Exception: If the IP is not up after 180 seconds.
6564
"""
66-
timeout = 180 # Total time to wait in seconds
65+
timeout = 60 # Total time to wait in seconds
6766
interval = 1 # Time to wait between checks in seconds
68-
elapsed_time = 0
67+
end_time = time.time() + timeout
6968

70-
while elapsed_time <= timeout:
69+
while time.time() < end_time:
7170
try:
7271
# Attempt to connect to the IP address
7372
response = requests.get(f"http://{ip}/api", timeout=5)
@@ -80,7 +79,6 @@ def wait_till_up(ip):
8079
pass
8180

8281
time.sleep(interval)
83-
elapsed_time += interval
8482

8583
# If the function hasn't returned after the loop, raise an exception
8684
raise Exception(f"The VM at http://{ip}/ is not up after {timeout} seconds. Please check the logs using "
@@ -479,6 +477,7 @@ def install_scraper_in_vm(git_repo_url, folder_name, max_retry):
479477
install_scraper(git_repo_url, folder_name, max_retry)
480478
click.echo("Successfully installed the Scraper.")
481479
# todo check status is it running or error?
480+
482481
def get_filename_from_url(url):
483482
from urllib.parse import urlparse
484483
return os.path.basename(urlparse(url).path.rstrip("/"))
@@ -490,8 +489,11 @@ def install_desktop_app_in_vm(
490489
api_path_prefix
491490
):
492491
# Validate api_path_prefix
493-
api_path_prefix = api_path_prefix if api_path_prefix else ""
494-
if api_path_prefix:
492+
api_path_prefix = os.path.normpath(api_path_prefix) if api_path_prefix else ""
493+
494+
if api_path_prefix == ".":
495+
api_path_prefix = ""
496+
elif api_path_prefix:
495497
if not api_path_prefix.startswith("/"):
496498
api_path_prefix = "/" + api_path_prefix
497499
if api_path_prefix.endswith("/"):
@@ -506,8 +508,7 @@ def install_desktop_app_in_vm(
506508
default_name = get_filename_from_url(debian_installer_url)
507509

508510
delete_installer(default_name)
509-
wget_command = f"wget {debian_installer_url}"
510-
subprocess.run(wget_command, shell=True, check=True, stderr=subprocess.STDOUT)
511+
subprocess.run(["wget", debian_installer_url], check=True, stderr=subprocess.STDOUT)
511512
install_command = f"sudo apt --fix-broken install ./{default_name} -y"
512513
subprocess.run(install_command, shell=True, check=True, stderr=subprocess.STDOUT)
513514
package_name = subprocess.check_output(f"dpkg-deb -f ./{default_name} Package", shell=True).decode().strip()
@@ -531,7 +532,8 @@ def install_desktop_app_in_vm(
531532
package_service_name = f"{package_name}.service"
532533
package_service_content = f"""[Unit]
533534
Description={package_name} Service
534-
After=network.target
535+
After=network.target {xvfb_service_name}
536+
Requires={xvfb_service_name}
535537
StartLimitInterval=0
536538
[Service]
537539
Type=simple
@@ -565,7 +567,7 @@ def install_desktop_app_in_vm(
565567
click.echo("Now, Checking API Status...")
566568
ip = get_vm_ip()
567569
wait_till_desktop_api_up(ip, api_path_prefix)
568-
click.echo(f"Hurray! your desktop app is up and running. Visit http://{ip}{api_path_prefix}/ to see the API Docs.")
570+
click.echo(f"Hurray! your desktop app is up and running. Visit http://{ip}{api_path_prefix or "/"} to see the API Docs.")
569571

570572
def delete_installer(default_name):
571573
if os.path.exists(default_name):
@@ -577,8 +579,8 @@ def setup_apache_load_balancer_desktop_app(port, api_path_prefix):
577579
DocumentRoot /var/www/html
578580
ErrorLog ${{APACHE_LOG_DIR}}/error.log
579581
CustomLog ${{APACHE_LOG_DIR}}/access.log combined
580-
ProxyPass {api_path_prefix}/ http://127.0.0.1:{port}{api_path_prefix}/
581-
ProxyPassReverse {api_path_prefix}/ http://127.0.0.1:{port}{api_path_prefix}/
582+
ProxyPass {api_path_prefix or "/"} http://127.0.0.1:{port}{api_path_prefix or "/"}
583+
ProxyPassReverse {api_path_prefix or "/"} http://127.0.0.1:{port}{api_path_prefix or "/"}
582584
</VirtualHost>"""
583585
write_file_sudo(apache_conf, "/etc/apache2/sites-available/000-default.conf")
584586

@@ -587,7 +589,12 @@ def validate_url(url):
587589
response = requests.head(url, allow_redirects=True, timeout=20)
588590
response.raise_for_status()
589591
except requests.exceptions.RequestException as e:
590-
raise Exception(f"URL validation failed: {e}")
592+
# Retry with GET if HEAD fails (some servers don't support HEAD)
593+
try:
594+
response = requests.get(url, allow_redirects=True, timeout=20)
595+
response.raise_for_status()
596+
except requests.exceptions.RequestException as e2:
597+
raise Exception(f"The URL {url} does not point to a valid Debian installer.")
591598

592599
def wait_till_desktop_api_up(ip, api_path_prefix):
593600
"""
@@ -600,14 +607,17 @@ def wait_till_desktop_api_up(ip, api_path_prefix):
600607
Raises:
601608
Exception: If the IP is not up after 180 seconds.
602609
"""
603-
timeout = 180 # Total time to wait in seconds
610+
timeout = 60 # Total time to wait in seconds
604611
interval = 1 # Time to wait between checks in seconds
605-
elapsed_time = 0
612+
end_time = time.time() + timeout
606613

607-
while elapsed_time <= timeout:
614+
while time.time() < end_time:
608615
try:
609616
# Attempt to connect to the IP address
610-
response = requests.get(f"http://{ip}{api_path_prefix}/ui/app-props", timeout=5)
617+
if api_path_prefix:
618+
response = requests.get(f"http://{ip}{api_path_prefix}/ui/app-props", timeout=5)
619+
else:
620+
response = requests.get(f"http://{ip}/ui/app-props", timeout=5)
611621

612622
# If the response is successful, return without raising an exception
613623
if response.status_code == 200:
@@ -617,10 +627,10 @@ def wait_till_desktop_api_up(ip, api_path_prefix):
617627
pass
618628

619629
time.sleep(interval)
620-
elapsed_time += interval
621-
622630
# If the function hasn't returned after the loop, raise an exception
623-
raise Exception(f"The Desktop App at http://{ip}/ is not up after {timeout} seconds.")
631+
raise Exception(
632+
f"The Desktop Api at http://{ip}/ is not up after {timeout} seconds. Are you sure you have enabled the Api in api-config.ts?"
633+
)
624634

625635
# python -m bota.vm
626636
if __name__ == "__main__":

0 commit comments

Comments
 (0)