138 lines
3.5 KiB
Bash
138 lines
3.5 KiB
Bash
#!/bin/bash
|
|
# Minimal HTTP server using bash and socat/nc
|
|
|
|
# Send HTTP response
|
|
send_response() {
|
|
local status="$1"
|
|
local content_type="${2:-application/json}"
|
|
local body="$3"
|
|
|
|
local length=${#body}
|
|
|
|
printf "HTTP/1.1 %s\r\n" "$status"
|
|
printf "Content-Type: %s\r\n" "$content_type"
|
|
printf "Content-Length: %d\r\n" "$length"
|
|
printf "Access-Control-Allow-Origin: *\r\n"
|
|
printf "Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS\r\n"
|
|
printf "Access-Control-Allow-Headers: Content-Type\r\n"
|
|
printf "Connection: close\r\n"
|
|
printf "\r\n"
|
|
printf "%s" "$body"
|
|
}
|
|
|
|
send_json() {
|
|
send_response "$1" "application/json" "$2"
|
|
}
|
|
|
|
send_error() {
|
|
local status="$1"
|
|
local message="$2"
|
|
send_json "$status" "{\"error\":\"$message\"}"
|
|
}
|
|
|
|
# Handle a single HTTP request
|
|
handle_request() {
|
|
local request_line=""
|
|
local content_length=0
|
|
local body=""
|
|
|
|
# Read request line
|
|
read -r request_line
|
|
request_line=$(echo "$request_line" | tr -d '\r')
|
|
|
|
# Parse method and path
|
|
local method=$(echo "$request_line" | cut -d' ' -f1)
|
|
local path=$(echo "$request_line" | cut -d' ' -f2)
|
|
|
|
# Read headers
|
|
while read -r header; do
|
|
header=$(echo "$header" | tr -d '\r')
|
|
[ -z "$header" ] && break
|
|
|
|
# Extract content-length
|
|
if echo "$header" | grep -qi "^content-length:"; then
|
|
content_length=$(echo "$header" | cut -d':' -f2 | tr -d ' ')
|
|
fi
|
|
done
|
|
|
|
# Read body if present
|
|
if [ "$content_length" -gt 0 ] 2>/dev/null; then
|
|
body=$(head -c "$content_length")
|
|
fi
|
|
|
|
# Route request
|
|
route_request "$method" "$path" "$body"
|
|
}
|
|
|
|
# Route requests to handlers
|
|
route_request() {
|
|
local method="$1"
|
|
local path="$2"
|
|
local body="$3"
|
|
|
|
# Handle CORS preflight
|
|
if [ "$method" = "OPTIONS" ]; then
|
|
send_response "204 No Content" "text/plain" ""
|
|
return
|
|
fi
|
|
|
|
# API routes
|
|
case "$path" in
|
|
/api/machines/register)
|
|
if [ "$method" = "POST" ]; then
|
|
handle_register "$body"
|
|
else
|
|
send_error "405 Method Not Allowed" "Use POST"
|
|
fi
|
|
;;
|
|
/api/machines)
|
|
if [ "$method" = "GET" ]; then
|
|
handle_list_machines
|
|
else
|
|
send_error "405 Method Not Allowed" "Use GET"
|
|
fi
|
|
;;
|
|
/api/machines/*)
|
|
local machine_id="${path#/api/machines/}"
|
|
if [ "$method" = "DELETE" ]; then
|
|
handle_delete_machine "$machine_id"
|
|
elif [ "$method" = "GET" ]; then
|
|
handle_get_machine "$machine_id"
|
|
else
|
|
send_error "405 Method Not Allowed" "Use GET or DELETE"
|
|
fi
|
|
;;
|
|
/health)
|
|
send_json "200 OK" '{"status":"healthy"}'
|
|
;;
|
|
*)
|
|
send_error "404 Not Found" "Endpoint not found"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Start HTTP server
|
|
http_server() {
|
|
local port="$1"
|
|
|
|
# Check for socat
|
|
if command -v socat &>/dev/null; then
|
|
echo "Using socat..."
|
|
while true; do
|
|
socat TCP-LISTEN:"$port",reuseaddr,fork EXEC:"$0 --handle-request"
|
|
done
|
|
else
|
|
echo "Error: socat not found. Install with: apt-get install socat"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Handle --handle-request flag (called by socat)
|
|
if [ "$1" = "--handle-request" ]; then
|
|
SKILL_DIR="$(dirname "$(dirname "$0")")"
|
|
source "$SKILL_DIR/lib/machines.sh"
|
|
DATA_DIR="${FLEET_DATA_DIR:-/data/fleet}"
|
|
export DATA_DIR
|
|
handle_request
|
|
fi
|