Skip to content

Commit e16031b

Browse files
author
Tom Softreck
committed
update
1 parent 8bf718f commit e16031b

File tree

4 files changed

+152
-5
lines changed

4 files changed

+152
-5
lines changed

Makefile

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
# LogLama Makefile
1+
# WebTask Makefile
2+
3+
# Load environment variables from .env file
4+
ifneq (,$(wildcard ./.env))
5+
include .env
6+
export $(shell sed 's/=.*//' .env)
7+
endif
28

39
# Default values that can be overridden
4-
PORT ?= 8081
5-
HOST ?= 127.0.0.1
10+
PORT ?= 9000
11+
HOST ?= 0.0.0.0
612
PYTHON ?= python3
713
LOG_DIR ?= ./logs
814
DB_PATH ?= $(LOG_DIR)/loglama.db
915
EXAMPLE_DB_PATH ?= $(LOG_DIR)/example.db
1016

11-
.PHONY: all setup install test test-unit test-integration test-ansible lint format clean run-api web run-example view-logs run-integration run-examples build publish publish-test check-publish help
17+
.PHONY: all setup install test test-unit test-integration test-ansible lint format clean run-api web run-example view-logs run-integration run-examples build publish publish-test check-publish help start stop restart status
1218

1319
all: help
1420

@@ -87,6 +93,25 @@ publish-full:
8793
@chmod +x scripts/publish.sh
8894
@./scripts/publish.sh
8995

96+
# Start the WebTask server
97+
start:
98+
@echo "Starting WebTask server on $(HOST):$(PORT)..."
99+
@poetry run webtask --host $(HOST) --port $(PORT)
100+
101+
# Stop the WebTask server
102+
stop:
103+
@echo "Stopping WebTask server on port $(PORT)..."
104+
@-pkill -f "webtask --host $(HOST) --port $(PORT)" || echo "No WebTask server found running on port $(PORT)"
105+
106+
# Restart the WebTask server
107+
restart: stop start
108+
109+
# Show status of WebTask server
110+
status:
111+
@pgrep -f "webtask --host $(HOST) --port $(PORT)" > /dev/null && \
112+
echo "WebTask server is running on $(HOST):$(PORT)" || \
113+
echo "WebTask server is not running on $(HOST):$(PORT)"
114+
90115
# Dry run of the publishing process
91116
publish-dry-run:
92117
@echo "Running dry run of publishing process..."

env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# WebTask Server Configuration
2+
HOST=0.0.0.0
3+
PORT=9000

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ packages = [{include = "webtask"}]
3030

3131
[tool.poetry.dependencies]
3232
python = "^3.7"
33+
psutil = "^5.9.0"
3334

3435
[tool.poetry.group.dev.dependencies]
3536
pytest = "^7.0"

webtask/server.py

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,51 @@
22
webtask HTTP Server
33
"""
44

5+
import json
6+
import psutil
7+
import socket
8+
import time
59
import webbrowser
610
import threading
711
from http.server import HTTPServer, SimpleHTTPRequestHandler
812
from pathlib import Path
9-
from typing import Any, Optional
13+
from typing import Any, Dict, List, Optional, Union
1014

1115

1216
class WebTaskHandler(SimpleHTTPRequestHandler):
1317
"""Custom HTTP handler for webtask"""
18+
19+
# Define API routes as a class variable to ensure they're available immediately
20+
api_routes = {}
21+
1422
def __init__(self, *args: Any, **kwargs: Any) -> None:
23+
# Initialize the routes before calling parent's __init__
24+
self.api_routes = {
25+
'/api/processes': self.handle_processes,
26+
'/api/system': self.handle_system_info,
27+
'/api/services': self.handle_services,
28+
'/api/disk': self.handle_disk_usage,
29+
}
1530
static_dir = Path(__file__).parent / "static"
1631
super().__init__(*args, directory=str(static_dir), **kwargs)
32+
33+
def do_GET(self) -> None:
34+
"""Handle GET requests, routing API calls or serving static files."""
35+
if self.path in self.api_routes:
36+
self.api_routes[self.path]()
37+
else:
38+
# Default to serving static files
39+
super().do_GET()
40+
41+
def send_json_response(self, data: Union[Dict, List], status_code: int = 200) -> None:
42+
"""Send a JSON response with the given data and status code."""
43+
self.send_response(status_code)
44+
self.send_header('Content-Type', 'application/json')
45+
self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
46+
self.send_header('Pragma', 'no-cache')
47+
self.send_header('Expires', '0')
48+
self.end_headers()
49+
self.wfile.write(json.dumps(data).encode('utf-8'))
1750

1851
def end_headers(self) -> None:
1952
self.send_header(
@@ -24,7 +57,92 @@ def end_headers(self) -> None:
2457
self.send_header('Expires', '0')
2558
super().end_headers()
2659

60+
def handle_processes(self) -> None:
61+
"""Return a list of running processes."""
62+
processes = []
63+
for proc in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent', 'memory_percent']):
64+
try:
65+
processes.append({
66+
'pid': proc.info['pid'],
67+
'name': proc.info['name'],
68+
'user': proc.info['username'],
69+
'cpu': proc.info['cpu_percent'],
70+
'memory': proc.info['memory_percent']
71+
})
72+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
73+
pass
74+
self.send_json_response(processes)
75+
76+
def handle_system_info(self) -> None:
77+
"""Return system information."""
78+
cpu_percent = psutil.cpu_percent(interval=1)
79+
memory = psutil.virtual_memory()
80+
disk = psutil.disk_usage('/')
81+
82+
system_info = {
83+
'cpu': {
84+
'percent': cpu_percent,
85+
'cores': psutil.cpu_count(),
86+
'load_avg': [x / psutil.cpu_count() * 100 for x in psutil.getloadavg()]
87+
},
88+
'memory': {
89+
'total': memory.total,
90+
'available': memory.available,
91+
'used': memory.used,
92+
'percent': memory.percent
93+
},
94+
'disk': {
95+
'total': disk.total,
96+
'used': disk.used,
97+
'free': disk.free,
98+
'percent': disk.percent
99+
},
100+
'hostname': socket.gethostname(),
101+
'uptime': int(time.time() - psutil.boot_time())
102+
}
103+
self.send_json_response(system_info)
104+
105+
def handle_services(self) -> None:
106+
"""Return a list of running services."""
107+
services = []
108+
# This is a simplified example - you might need to adjust based on the OS
109+
try:
110+
if hasattr(psutil, 'win_service_iter'):
111+
for service in psutil.win_service_iter():
112+
services.append({
113+
'name': service.name(),
114+
'display_name': service.display_name(),
115+
'status': service.status()
116+
})
117+
else:
118+
# Fallback for non-Windows systems
119+
services = [{'name': 'service1', 'status': 'running'},
120+
{'name': 'service2', 'status': 'stopped'}]
121+
except Exception as e:
122+
services = [{'error': f'Service listing error: {str(e)}'}]
123+
self.send_json_response(services)
124+
125+
def handle_disk_usage(self) -> None:
126+
"""Return disk usage information."""
127+
partitions = []
128+
for partition in psutil.disk_partitions():
129+
try:
130+
usage = psutil.disk_usage(partition.mountpoint)
131+
partitions.append({
132+
'device': partition.device,
133+
'mountpoint': partition.mountpoint,
134+
'fstype': partition.fstype,
135+
'total': usage.total,
136+
'used': usage.used,
137+
'free': usage.free,
138+
'percent': usage.percent
139+
})
140+
except Exception as e:
141+
print(f"Error getting disk usage for {partition.mountpoint}: {e}")
142+
self.send_json_response(partitions)
143+
27144
def log_message(self, format: str, *args: Any) -> None:
145+
"""Override to prevent logging every request to stderr."""
28146
pass
29147

30148

0 commit comments

Comments
 (0)