QuecManager non-beta
Its about time I did this!
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
RESULT_FILE="/tmp/qscan_result.json"
|
||||
WORKER_SCRIPT="/www/cgi-bin/quecmanager/experimental/cell_scanner/cell_scan_worker.sh"
|
||||
PID_FILE="/tmp/cell_scan.pid"
|
||||
SCAN_COMMAND="AT+QSCAN=3,1"
|
||||
SCAN_TIMEOUT=200
|
||||
LOCK_ID="CELL_SCAN_$(date +%s)_$$"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t at_queue -p "daemon.$level" "cell_scan: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
log_message "Sending response: status=$status, message=$message"
|
||||
printf '{"status":"%s","message":"%s"}\n' "$status" "$message"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to check if worker is running
|
||||
check_worker_running() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log_message "Worker process $pid is running"
|
||||
return 0
|
||||
fi
|
||||
log_message "Removing stale PID file for process $pid"
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Enhanced JSON string escaping function
|
||||
escape_json() {
|
||||
printf '%s' "$1" | awk '
|
||||
BEGIN { RS="\n"; ORS="\\n" }
|
||||
{
|
||||
gsub(/\\/, "\\\\")
|
||||
gsub(/"/, "\\\"")
|
||||
gsub(/\r/, "")
|
||||
gsub(/\t/, "\\t")
|
||||
gsub(/\f/, "\\f")
|
||||
gsub(/\b/, "\\b")
|
||||
print
|
||||
}
|
||||
' | sed 's/\\n$//'
|
||||
}
|
||||
|
||||
# Acquire token directly with high priority
|
||||
acquire_token() {
|
||||
local priority=1 # Highest priority for cell scan
|
||||
local max_attempts=10
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token file exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> 30 seconds old)
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
# Remove expired token
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
# Preempt lower priority token
|
||||
log_message "Preempting token from $current_holder (priority: $current_priority)" "info"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Try again - higher priority token exists
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$LOCK_ID\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got the token
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$LOCK_ID" ]; then
|
||||
log_message "Successfully acquired token with priority $priority" "info"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
{
|
||||
# If scan is running, return running status
|
||||
if check_worker_running; then
|
||||
output_json "running" "Cell scan is in progress"
|
||||
fi
|
||||
|
||||
# Start new scan
|
||||
rm -f "$RESULT_FILE"
|
||||
log_message "Starting new cell scan" "info"
|
||||
|
||||
# Ensure worker script is executable
|
||||
chmod +x "$WORKER_SCRIPT" 2>/dev/null
|
||||
|
||||
# Start worker script with proper parameters
|
||||
log_message "Attempting to start worker script: $WORKER_SCRIPT" "info"
|
||||
|
||||
# Check if worker script exists
|
||||
if [ ! -f "$WORKER_SCRIPT" ]; then
|
||||
log_message "Worker script not found: $WORKER_SCRIPT" "error"
|
||||
output_json "error" "Worker script not found"
|
||||
fi
|
||||
|
||||
# Ensure QUEUE_DIR exists
|
||||
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR"
|
||||
chmod 755 "$QUEUE_DIR"
|
||||
chmod 755 "$RESULTS_DIR"
|
||||
|
||||
# Start worker with debug logging
|
||||
WORKER_PID=$
|
||||
(sh "$WORKER_SCRIPT" >/tmp/cell_scan_worker.log 2>&1) &
|
||||
WORKER_PID=$!
|
||||
log_message "Worker script started with PID $WORKER_PID" "info"
|
||||
|
||||
# The worker process runs in the background and completes quickly
|
||||
# We don't need to check if it's still running as it might finish before we check
|
||||
log_message "Worker process $WORKER_PID started in background" "info"
|
||||
|
||||
# Instead of checking if the process is running, check if it created the result file
|
||||
sleep 2
|
||||
if [ -f "$RESULT_FILE" ]; then
|
||||
log_message "Worker successfully created result file" "info"
|
||||
else
|
||||
log_message "Waiting for worker to create result file..." "info"
|
||||
# If no result file yet, check for errors
|
||||
if [ -f "/tmp/cell_scan_worker.log" ]; then
|
||||
WORKER_LOG=$(cat "/tmp/cell_scan_worker.log" | head -20)
|
||||
log_message "Worker log: $WORKER_LOG" "info"
|
||||
fi
|
||||
fi
|
||||
output_json "running" "Started new cell scan"
|
||||
} || {
|
||||
# Error handler
|
||||
log_message "Script failed with error" "error"
|
||||
output_json "error" "Internal error occurred"
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
RESULT_FILE="/tmp/qscan_result.json"
|
||||
PID_FILE="/tmp/cell_scan.pid"
|
||||
SCAN_COMMAND="AT+QSCAN=3,1"
|
||||
SCAN_TIMEOUT=200
|
||||
LOCK_ID="CELL_SCAN_$(date +%s)_$$"
|
||||
|
||||
# Enable shell debugging for better logging
|
||||
set -x
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t at_queue -p "daemon.$level" "cell_scan_worker: $1"
|
||||
}
|
||||
|
||||
# Function to clean up stale temporary files
|
||||
cleanup_stale_files() {
|
||||
log_message "Cleaning up stale temporary files" "info"
|
||||
|
||||
# Clean up old start_time files (older than 1 hour)
|
||||
find "$QUEUE_DIR" -name "start_time.qscan_*" -type f -mmin +60 -delete 2>/dev/null
|
||||
|
||||
# Clean up any start_time files that match our current process just in case
|
||||
find "$QUEUE_DIR" -name "start_time.qscan_*_$" -type f -delete 2>/dev/null
|
||||
|
||||
log_message "Stale file cleanup completed" "info"
|
||||
}
|
||||
|
||||
# Function to check directories and permissions
|
||||
check_environment() {
|
||||
log_message "Checking environment" "info"
|
||||
|
||||
# Clean up stale files first
|
||||
cleanup_stale_files
|
||||
|
||||
# Check if directories exist, create if they don't
|
||||
if [ ! -d "$QUEUE_DIR" ]; then
|
||||
mkdir -p "$QUEUE_DIR"
|
||||
log_message "Created queue directory: $QUEUE_DIR" "info"
|
||||
fi
|
||||
|
||||
if [ ! -d "$RESULTS_DIR" ]; then
|
||||
mkdir -p "$RESULTS_DIR"
|
||||
log_message "Created results directory: $RESULTS_DIR" "info"
|
||||
fi
|
||||
|
||||
# Check permissions
|
||||
chmod 755 "$QUEUE_DIR" 2>/dev/null
|
||||
chmod 755 "$RESULTS_DIR" 2>/dev/null
|
||||
|
||||
# Check if sms_tool exists and is executable
|
||||
if ! which sms_tool >/dev/null 2>&1; then
|
||||
log_message "sms_tool not found in PATH" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test directory write permissions
|
||||
if ! touch "$QUEUE_DIR/test_$$" 2>/dev/null; then
|
||||
log_message "Cannot write to $QUEUE_DIR" "error"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$QUEUE_DIR/test_$$" 2>/dev/null
|
||||
|
||||
if ! touch "$RESULTS_DIR/test_$$" 2>/dev/null; then
|
||||
log_message "Cannot write to $RESULTS_DIR" "error"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$RESULTS_DIR/test_$$" 2>/dev/null
|
||||
|
||||
log_message "Environment check passed" "info"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to clean AT command output
|
||||
clean_output() {
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
"OK" | "" | *"ERROR"*)
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "$line"
|
||||
;;
|
||||
esac
|
||||
done | sed 's/\r//g' | tr '\n' '\r' | sed 's/\r$//' | tr '\r' '\n'
|
||||
}
|
||||
|
||||
# Enhanced JSON string escaping function
|
||||
escape_json() {
|
||||
printf '%s' "$1" | awk '
|
||||
BEGIN { RS="\n"; ORS="\\n" }
|
||||
{
|
||||
gsub(/\\/, "\\\\")
|
||||
gsub(/"/, "\\\"")
|
||||
gsub(/\r/, "")
|
||||
gsub(/\t/, "\\t")
|
||||
gsub(/\f/, "\\f")
|
||||
gsub(/\b/, "\\b")
|
||||
print
|
||||
}
|
||||
' | sed 's/\\n$//'
|
||||
}
|
||||
|
||||
# Function to check if scan is already running
|
||||
check_running() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log_message "Cell scan already running (PID: $pid)" "warn"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Acquire token directly with high priority
|
||||
acquire_token() {
|
||||
local priority=1 # Highest priority for cell scan
|
||||
local max_attempts=10
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token file exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> 30 seconds old)
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
# Remove expired token
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
# Preempt lower priority token
|
||||
log_message "Preempting token from $current_holder (priority: $current_priority)" "info"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Try again
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$LOCK_ID\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got the token
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$LOCK_ID" ]; then
|
||||
log_message "Successfully acquired token with priority $priority" "info"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Release token directly
|
||||
release_token() {
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$LOCK_ID" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token" "info"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($LOCK_ID)" "warn"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
# Start logging
|
||||
log_message "Worker script started" "info"
|
||||
|
||||
# Check if already running
|
||||
if check_running; then
|
||||
log_message "Cell scan already running, exiting" "warn"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create PID file
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE" 2>/dev/null
|
||||
log_message "Created PID file: $$" "info"
|
||||
|
||||
# Set up cleanup on exit
|
||||
trap 'log_message "Cleaning up and exiting" "info"; release_token; rm -f "$PID_FILE"; exit' INT TERM EXIT
|
||||
|
||||
# Acquire token for AT command execution
|
||||
if ! acquire_token; then
|
||||
log_message "Failed to acquire token, exiting" "error"
|
||||
rm -f "$PID_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "Token acquired, executing scan command: $SCAN_COMMAND" "info"
|
||||
|
||||
# Execute scan with native timeout option (without relying on timeout command)
|
||||
# Use the -t option of sms_tool instead of the timeout command
|
||||
log_message "Executing command with timeout: $SCAN_TIMEOUT seconds" "info"
|
||||
SCAN_OUTPUT=$(sms_tool at "$SCAN_COMMAND" -t $SCAN_TIMEOUT 2>&1 | clean_output)
|
||||
SCAN_STATUS=$?
|
||||
log_message "Command execution completed with status: $SCAN_STATUS" "info"
|
||||
|
||||
# Process and store result
|
||||
if [ $SCAN_STATUS -eq 0 ]; then
|
||||
# Check if output contains valid scan data or error
|
||||
if echo "$SCAN_OUTPUT" | grep -q "+QSCAN"; then
|
||||
# Set timestamp
|
||||
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# Valid scan data found - don't add the "Scan completed but no valid data" prefix
|
||||
log_message "Scan completed with valid data" "info"
|
||||
|
||||
# Create the result file with proper JSON formatting
|
||||
printf '{"status":"success","timestamp":"%s","output":%s}\n' \
|
||||
"$TIMESTAMP" \
|
||||
"$(printf '%s' "$SCAN_OUTPUT" | sed 's/"/\\"/g' | jq -R -s '.')" > "$RESULT_FILE"
|
||||
chmod 644 "$RESULT_FILE" 2>/dev/null
|
||||
else
|
||||
# No valid scan data, but command completed
|
||||
log_message "Command completed but no valid scan data found: $SCAN_OUTPUT" "warn"
|
||||
SCAN_OUTPUT="Scan completed but no valid data returned: $SCAN_OUTPUT"
|
||||
|
||||
# Create a result file indicating partial success
|
||||
printf '{"status":"partial","timestamp":"%s","output":%s}\n' \
|
||||
"$(date '+%Y-%m-%d %H:%M:%S')" \
|
||||
"$(printf '%s' "$SCAN_OUTPUT" | sed 's/"/\\"/g' | jq -R -s '.')" > "$RESULT_FILE"
|
||||
chmod 644 "$RESULT_FILE" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Generate a command ID for the AT queue results format - use actual PID instead of $
|
||||
local my_pid="$$"
|
||||
local cmd_id="qscan_$(date +%s)_${my_pid}"
|
||||
local end_time=$(date +%s)
|
||||
local start_time=$end_time
|
||||
local duration=0
|
||||
|
||||
# Store start time for future reference
|
||||
echo "$start_time" > "$QUEUE_DIR/start_time.$cmd_id"
|
||||
|
||||
log_message "Creating AT queue result with ID: $cmd_id" "info"
|
||||
|
||||
# Create JSON response in the AT queue format
|
||||
local response=$(cat << EOF
|
||||
{
|
||||
"command": {
|
||||
"id": "$cmd_id",
|
||||
"text": "$SCAN_COMMAND",
|
||||
"timestamp": "$(date -Iseconds)"
|
||||
},
|
||||
"response": {
|
||||
"status": "success",
|
||||
"raw_output": "$(escape_json "$SCAN_OUTPUT")",
|
||||
"completion_time": "$end_time",
|
||||
"duration_ms": $duration
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Save the response to the AT queue results directory
|
||||
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
|
||||
chmod 644 "$RESULTS_DIR/$cmd_id.json"
|
||||
|
||||
# Clean up temporary files
|
||||
rm -f "$QUEUE_DIR/start_time.$cmd_id"
|
||||
log_message "Cleaned up temporary files" "info"
|
||||
|
||||
# Release the token
|
||||
release_token
|
||||
return 0
|
||||
else
|
||||
log_message "Scan failed with status: $SCAN_STATUS" "error"
|
||||
printf '{"status":"error","timestamp":"%s","message":"Scan failed"}\n' \
|
||||
"$(date '+%Y-%m-%d %H:%M:%S')" > "$RESULT_FILE"
|
||||
chmod 644 "$RESULT_FILE" 2>/dev/null
|
||||
|
||||
# Release the token
|
||||
release_token
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute main function with proper error handling
|
||||
{
|
||||
log_message "Worker script started with PID $$" "info"
|
||||
|
||||
# Check environment before proceeding
|
||||
check_environment || {
|
||||
log_message "Environment check failed, aborting" "error"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main || {
|
||||
log_message "Main function failed with error $?" "error"
|
||||
release_token
|
||||
rm -f "$PID_FILE"
|
||||
exit 1
|
||||
}
|
||||
} 2>/tmp/cell_scan_worker_debug.log || {
|
||||
log_message "Script failed with error" "error"
|
||||
release_token
|
||||
rm -f "$PID_FILE"
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
RESULT_FILE="/tmp/qscan_result.json"
|
||||
PID_FILE="/tmp/cell_scan.pid"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t at_queue -p "daemon.$level" "check_scan: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
|
||||
if [ "$status" = "success" ] && [ -f "$RESULT_FILE" ]; then
|
||||
# Return the contents of the result file
|
||||
cat "$RESULT_FILE"
|
||||
else
|
||||
printf '{"status":"%s","message":"%s","timestamp":"","output":""}\n' "$status" "$message"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for scan token holder
|
||||
check_token_holder() {
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ -n "$current_holder" ] && echo "$current_holder" | grep -q "CELL_SCAN"; then
|
||||
log_message "Cell scan token is active: $current_holder" "debug"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if a scan is already in progress
|
||||
check_scan_progress() {
|
||||
# First check PID file
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log_message "Scan in progress (PID: $pid)" "info"
|
||||
output_json "running" "Scan in progress"
|
||||
exit 0
|
||||
else
|
||||
log_message "Removing stale PID file" "warn"
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also check token holder
|
||||
if check_token_holder; then
|
||||
log_message "Scan in progress (Token active)" "info"
|
||||
output_json "running" "Scan in progress (Token active)"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for existing results
|
||||
check_results() {
|
||||
if [ -f "$RESULT_FILE" ]; then
|
||||
# Check if the result file contains valid JSON data
|
||||
local result_content=$(cat "$RESULT_FILE" 2>/dev/null)
|
||||
if [ -n "$result_content" ] && echo "$result_content" | grep -q "status"; then
|
||||
# REMOVED AGE CHECK - Always return the file contents regardless of age
|
||||
log_message "Found valid result file, returning contents" "info"
|
||||
output_json "success" "Scan results available"
|
||||
exit 0
|
||||
else
|
||||
log_message "Result file exists but contains invalid data" "warn"
|
||||
rm -f "$RESULT_FILE" # Remove invalid result file
|
||||
output_json "idle" "Invalid previous scan results"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
{
|
||||
# First check if a scan is in progress
|
||||
check_scan_progress
|
||||
|
||||
# Then check for existing results
|
||||
check_results
|
||||
|
||||
# If no results and no running scan, indicate idle state
|
||||
log_message "No active scan or recent results" "info"
|
||||
output_json "idle" "No active scan"
|
||||
exit 0
|
||||
} || {
|
||||
# Error handler
|
||||
log_message "Failed to check scan status" "error"
|
||||
output_json "error" "Failed to check scan status"
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
JSON_FILE="/www/cgi-bin/quecmanager/mcc-mnc-list.json"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
logger -t fetch_mccmnc "$1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
printf '{"status":"%s","message":"%s"}\n' "$status" "$message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
{
|
||||
# Check if file exists
|
||||
if [ ! -f "$JSON_FILE" ]; then
|
||||
log_message "MCC-MNC list file not found"
|
||||
output_json "error" "MCC-MNC list file not found"
|
||||
fi
|
||||
|
||||
# Read and output the file
|
||||
cat "$JSON_FILE" 2>/dev/null || {
|
||||
log_message "Failed to read MCC-MNC list file"
|
||||
output_json "error" "Failed to read MCC-MNC list file"
|
||||
}
|
||||
} || {
|
||||
# Error handler
|
||||
log_message "Script failed with error"
|
||||
output_json "error" "Internal error occurred"
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content-type for JSON response
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Define paths and constants to match queue system
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
TEMP_FILE="/tmp/network_info_output.txt"
|
||||
LOCK_ID="NETWORK_INFO_$(date +%s)_$$"
|
||||
COMMAND_TIMEOUT=8 # Increased timeout
|
||||
MAX_TOKEN_WAIT=10
|
||||
PRIORITY=5 # Medium-high priority (between cell scan and normal commands)
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t at_queue -p "daemon.$level" "network_info: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON error
|
||||
output_error() {
|
||||
printf '{"status":"error","message":"%s","timestamp":"%s"}\n' "$1" "$(date '+%H:%M:%S')"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Enhanced JSON string escaping function
|
||||
escape_json() {
|
||||
printf '%s' "$1" | awk '
|
||||
BEGIN { RS="\n"; ORS="\\n" }
|
||||
{
|
||||
gsub(/\\/, "\\\\")
|
||||
gsub(/"/, "\\\"")
|
||||
gsub(/\r/, "")
|
||||
gsub(/\t/, "\\t")
|
||||
gsub(/\f/, "\\f")
|
||||
gsub(/\b/, "\\b")
|
||||
print
|
||||
}
|
||||
' | sed 's/\\n$//'
|
||||
}
|
||||
|
||||
# Acquire token directly with medium-high priority
|
||||
acquire_token() {
|
||||
local priority="$PRIORITY" # Medium-high priority for network info
|
||||
local max_attempts=$MAX_TOKEN_WAIT
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token file exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> 30 seconds old)
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
# Remove expired token
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
# Preempt lower priority token
|
||||
log_message "Preempting token from $current_holder (priority: $current_priority)" "info"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Try again - higher priority token exists
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$LOCK_ID\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got the token
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$LOCK_ID" ]; then
|
||||
log_message "Successfully acquired token with priority $priority" "info"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Release token directly
|
||||
release_token() {
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$LOCK_ID" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token" "info"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($LOCK_ID)" "warn"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to execute AT command with direct output capture
|
||||
execute_at_command() {
|
||||
local CMD="$1"
|
||||
local OUTPUT_FILE="$TEMP_FILE.cmd.$$"
|
||||
|
||||
log_message "Executing command: $CMD" "debug"
|
||||
|
||||
# Execute command and redirect output to file for reliable capture
|
||||
sms_tool at "$CMD" -t $COMMAND_TIMEOUT > "$OUTPUT_FILE" 2>&1
|
||||
local EXIT_CODE=$?
|
||||
|
||||
# Read the output regardless of exit code
|
||||
if [ -f "$OUTPUT_FILE" ]; then
|
||||
local OUTPUT=$(cat "$OUTPUT_FILE")
|
||||
rm -f "$OUTPUT_FILE"
|
||||
|
||||
if [ -n "$OUTPUT" ]; then
|
||||
# We have some output
|
||||
if echo "$OUTPUT" | grep -q "CME ERROR"; then
|
||||
log_message "Command returned CME ERROR: $OUTPUT" "warn"
|
||||
return 1
|
||||
elif echo "$OUTPUT" | grep -q "ERROR"; then
|
||||
log_message "Command returned ERROR: $OUTPUT" "warn"
|
||||
return 1
|
||||
else
|
||||
# Command produced output that doesn't contain ERROR
|
||||
log_message "Command executed successfully with output" "debug"
|
||||
echo "$OUTPUT"
|
||||
return 0
|
||||
fi
|
||||
elif [ $EXIT_CODE -eq 0 ]; then
|
||||
log_message "Command succeeded but returned empty output" "warn"
|
||||
echo "Command returned empty output"
|
||||
return 0
|
||||
else
|
||||
log_message "Command failed with exit code $EXIT_CODE and no output" "error"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_message "Failed to create output file" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check network mode from serving cell info
|
||||
check_network_mode() {
|
||||
local OUTPUT="$1"
|
||||
|
||||
# Check for both LTE and NR5G-NSA (NSA mode)
|
||||
if echo "$OUTPUT" | grep -q "\"LTE\"" && echo "$OUTPUT" | grep -q "\"NR5G-NSA\""; then
|
||||
log_message "Detected network mode: NRLTE (NSA)" "info"
|
||||
echo "NRLTE"
|
||||
# Check for LTE only
|
||||
elif echo "$OUTPUT" | grep -q "\"LTE\""; then
|
||||
log_message "Detected network mode: LTE" "info"
|
||||
echo "LTE"
|
||||
# Check for NR5G-SA
|
||||
elif echo "$OUTPUT" | grep -q "\"NR5G-SA\""; then
|
||||
log_message "Detected network mode: NR5G (SA)" "info"
|
||||
echo "NR5G"
|
||||
else
|
||||
log_message "Detected network mode: UNKNOWN from output: $OUTPUT" "warn"
|
||||
echo "UNKNOWN"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check NR5G measurement info setting
|
||||
check_nr5g_meas_info() {
|
||||
local OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
|
||||
local EXIT_CODE=$?
|
||||
|
||||
if [ $EXIT_CODE -eq 0 ] && echo "$OUTPUT" | grep -q "\"nr5g_meas_info\",1"; then
|
||||
log_message "NR5G measurement info is enabled" "debug"
|
||||
return 0
|
||||
else
|
||||
log_message "NR5G measurement info is disabled or check failed" "debug"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create JSON output safely
|
||||
format_output_json() {
|
||||
local MODE="$1"
|
||||
local SERVING_OUTPUT="$2"
|
||||
local NEIGHBOR_OUTPUT="$3"
|
||||
local MEAS_OUTPUT="$4"
|
||||
|
||||
# Basic JSON structure - start
|
||||
printf '{"status":"success","timestamp":"%s","mode":"%s"' "$(date '+%H:%M:%S')" "$MODE"
|
||||
|
||||
# Add raw data section
|
||||
printf ',"raw_data":{'
|
||||
|
||||
# Add serving cell output (always present)
|
||||
printf '"servingCell":%s' "$(printf '%s' "$SERVING_OUTPUT" | jq -R -s '.')"
|
||||
|
||||
# Add neighbor cells output if available
|
||||
if [ -n "$NEIGHBOR_OUTPUT" ]; then
|
||||
printf ',"neighborCells":%s' "$(printf '%s' "$NEIGHBOR_OUTPUT" | jq -R -s '.')"
|
||||
fi
|
||||
|
||||
# Add measurement info output if available
|
||||
if [ -n "$MEAS_OUTPUT" ]; then
|
||||
printf ',"meas":%s' "$(printf '%s' "$MEAS_OUTPUT" | jq -R -s '.')"
|
||||
fi
|
||||
|
||||
# Close raw data section
|
||||
printf '}'
|
||||
|
||||
# Close the whole JSON object
|
||||
printf '}\n'
|
||||
}
|
||||
|
||||
# Set up trap for cleanup
|
||||
trap 'log_message "Script interrupted, cleaning up" "warn"; release_token; rm -f "$TEMP_FILE" "$TEMP_FILE.cmd."*; exit 1' INT TERM EXIT
|
||||
|
||||
# Main execution
|
||||
{
|
||||
# Ensure directories exist
|
||||
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR"
|
||||
|
||||
log_message "Starting network info collection" "info"
|
||||
|
||||
# Acquire token for AT command execution before any output
|
||||
if ! acquire_token; then
|
||||
output_error "Failed to acquire token for command processing"
|
||||
fi
|
||||
|
||||
# Get the serving cell information first
|
||||
log_message "Getting serving cell information" "info"
|
||||
SERVING_OUTPUT=$(execute_at_command "AT+QENG=\"servingcell\"")
|
||||
EXIT_CODE=$?
|
||||
|
||||
# Check if we got valid serving cell info
|
||||
if [ $EXIT_CODE -ne 0 ] || [ -z "$SERVING_OUTPUT" ]; then
|
||||
log_message "Failed to get serving cell information, output: $SERVING_OUTPUT" "error"
|
||||
release_token
|
||||
output_error "Failed to get serving cell information"
|
||||
fi
|
||||
|
||||
log_message "Successfully got serving cell information" "info"
|
||||
|
||||
# Determine network mode from serving cell output
|
||||
NETWORK_MODE=$(check_network_mode "$SERVING_OUTPUT")
|
||||
|
||||
NEIGHBOR_OUTPUT=""
|
||||
MEAS_OUTPUT=""
|
||||
|
||||
case "$NETWORK_MODE" in
|
||||
"NRLTE")
|
||||
log_message "Processing NRLTE mode commands" "info"
|
||||
NEIGHBOR_OUTPUT=$(execute_at_command "AT+QENG=\"neighbourcell\"")
|
||||
|
||||
# Try to get measurement info
|
||||
if ! check_nr5g_meas_info; then
|
||||
log_message "Enabling NR5G measurement info" "info"
|
||||
execute_at_command "AT+QNWCFG=\"nr5g_meas_info\",1" > /dev/null
|
||||
sleep 1 # Give it time to take effect
|
||||
fi
|
||||
|
||||
log_message "Fetching NR5G measurement info" "info"
|
||||
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
|
||||
;;
|
||||
"LTE")
|
||||
log_message "Processing LTE mode commands" "info"
|
||||
NEIGHBOR_OUTPUT=$(execute_at_command "AT+QENG=\"neighbourcell\"")
|
||||
;;
|
||||
"NR5G")
|
||||
log_message "Processing NR5G mode commands" "info"
|
||||
|
||||
# Try to get measurement info
|
||||
if ! check_nr5g_meas_info; then
|
||||
log_message "Enabling NR5G measurement info" "info"
|
||||
execute_at_command "AT+QNWCFG=\"nr5g_meas_info\",1" > /dev/null
|
||||
sleep 1 # Give it time to take effect
|
||||
fi
|
||||
|
||||
log_message "Fetching NR5G measurement info" "info"
|
||||
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
|
||||
;;
|
||||
*)
|
||||
# Even if we don't recognize the mode, we'll still return the serving cell info
|
||||
log_message "Unknown network mode, only returning serving cell info" "warn"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Format and output JSON response
|
||||
log_message "Formatting JSON response" "info"
|
||||
format_output_json "$NETWORK_MODE" "$SERVING_OUTPUT" "$NEIGHBOR_OUTPUT" "$MEAS_OUTPUT"
|
||||
|
||||
# Release token and clean up
|
||||
release_token
|
||||
rm -f "$TEMP_FILE" "$TEMP_FILE.cmd."*
|
||||
|
||||
log_message "Network info collection completed" "info"
|
||||
|
||||
} || {
|
||||
# Error handler
|
||||
log_message "Script failed with error" "error"
|
||||
release_token
|
||||
rm -f "$TEMP_FILE" "$TEMP_FILE.cmd."*
|
||||
output_error "Internal error occurred"
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Configuration
|
||||
CONFIG_FILE="/etc/keep_alive_schedule.conf"
|
||||
STATUS_FILE="/tmp/keep_alive_status"
|
||||
SPEEDTEST_SCRIPT="/www/cgi-bin/home/speedtest/speedtest.sh"
|
||||
|
||||
# Function to convert HH:MM to minutes since midnight
|
||||
time_to_minutes() {
|
||||
echo "$1" | awk -F: '{print $1 * 60 + $2}'
|
||||
}
|
||||
|
||||
# Function to validate time interval
|
||||
validate_interval() {
|
||||
START_TIME=$1
|
||||
END_TIME=$2
|
||||
INTERVAL_MINUTES=$3
|
||||
|
||||
# Convert times to minutes
|
||||
START_MINUTES=$(time_to_minutes "$START_TIME")
|
||||
END_MINUTES=$(time_to_minutes "$END_TIME")
|
||||
|
||||
# Calculate duration between start and end time
|
||||
if [ $END_MINUTES -lt $START_MINUTES ]; then
|
||||
# Handle case where end time is on the next day
|
||||
DURATION=$((1440 - START_MINUTES + END_MINUTES))
|
||||
else
|
||||
DURATION=$((END_MINUTES - START_MINUTES))
|
||||
fi
|
||||
|
||||
# Check if interval is longer than duration
|
||||
if [ $INTERVAL_MINUTES -gt $DURATION ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to generate cron time expression
|
||||
generate_cron_time() {
|
||||
START_TIME=$1
|
||||
END_TIME=$2
|
||||
INTERVAL=$3
|
||||
|
||||
START_HOUR=$(echo "$START_TIME" | cut -d: -f1 | sed 's/^0//')
|
||||
START_MIN=$(echo "$START_TIME" | cut -d: -f2)
|
||||
END_HOUR=$(echo "$END_TIME" | cut -d: -f1 | sed 's/^0//')
|
||||
END_MIN=$(echo "$END_TIME" | cut -d: -f2)
|
||||
|
||||
# If end time is less than start time, it means we cross midnight
|
||||
if [ $(time_to_minutes "$END_TIME") -lt $(time_to_minutes "$START_TIME") ]; then
|
||||
# Create two cron entries for before and after midnight
|
||||
echo "*/$INTERVAL $START_HOUR-23 * * * $SPEEDTEST_SCRIPT"
|
||||
echo "*/$INTERVAL 0-$((END_HOUR - 1)) * * * $SPEEDTEST_SCRIPT"
|
||||
else
|
||||
echo "*/$INTERVAL $START_HOUR-$((END_HOUR - 1)) * * * $SPEEDTEST_SCRIPT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to urldecode
|
||||
urldecode() {
|
||||
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
|
||||
}
|
||||
|
||||
# Function to save configuration
|
||||
save_config() {
|
||||
echo "START_TIME=$1" >"$CONFIG_FILE"
|
||||
echo "END_TIME=$2" >>"$CONFIG_FILE"
|
||||
echo "INTERVAL=$3" >>"$CONFIG_FILE"
|
||||
echo "ENABLED=1" >>"$CONFIG_FILE"
|
||||
}
|
||||
|
||||
# Function to disable scheduling
|
||||
disable_scheduling() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
sed -i 's/ENABLED=1/ENABLED=0/' "$CONFIG_FILE"
|
||||
fi
|
||||
# Remove any existing cron jobs
|
||||
crontab -l | grep -v "$SPEEDTEST_SCRIPT" | crontab -
|
||||
}
|
||||
|
||||
# Function to get current status
|
||||
get_status() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
ENABLED=$(grep "ENABLED=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||
START_TIME=$(grep "START_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||
END_TIME=$(grep "END_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||
INTERVAL=$(grep "INTERVAL=" "$CONFIG_FILE" | cut -d'=' -f2)
|
||||
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\",\"interval\":$INTERVAL}"
|
||||
else
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"enabled\":0,\"start_time\":\"\",\"end_time\":\"\",\"interval\":0}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle POST requests
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Read POST data
|
||||
read -r POST_DATA
|
||||
|
||||
# Check if disabling is requested
|
||||
echo "$POST_DATA" | grep -q "disable=true"
|
||||
if [ $? -eq 0 ]; then
|
||||
disable_scheduling
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract times and interval
|
||||
START_TIME=$(echo "$POST_DATA" | grep -o 'start_time=[^&]*' | cut -d'=' -f2)
|
||||
END_TIME=$(echo "$POST_DATA" | grep -o 'end_time=[^&]*' | cut -d'=' -f2)
|
||||
INTERVAL=$(echo "$POST_DATA" | grep -o 'interval=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# Decode times
|
||||
START_TIME=$(urldecode "$START_TIME")
|
||||
END_TIME=$(urldecode "$END_TIME")
|
||||
INTERVAL=$(urldecode "$INTERVAL")
|
||||
|
||||
# Validate times
|
||||
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ] || [ -z "$INTERVAL" ]; then
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Missing start time, end time, or interval\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate interval is a number
|
||||
if ! echo "$INTERVAL" | grep -q '^[0-9]\+$'; then
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Interval must be a number in minutes\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate interval
|
||||
if ! validate_interval "$START_TIME" "$END_TIME" "$INTERVAL"; then
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Interval is longer than the time between start and end time\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create temporary file for new crontab
|
||||
TEMP_CRON=$(mktemp)
|
||||
|
||||
# Get existing crontab entries (excluding our script)
|
||||
crontab -l 2>/dev/null | grep -v "$SPEEDTEST_SCRIPT" >"$TEMP_CRON"
|
||||
|
||||
# Generate and add cron entries
|
||||
generate_cron_time "$START_TIME" "$END_TIME" "$INTERVAL" >>"$TEMP_CRON"
|
||||
|
||||
# Install new crontab
|
||||
crontab "$TEMP_CRON"
|
||||
rm "$TEMP_CRON"
|
||||
|
||||
# Save configuration
|
||||
save_config "$START_TIME" "$END_TIME" "$INTERVAL"
|
||||
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"status\":\"success\",\"message\":\"Keep-alive scheduling enabled\"}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse query string for GET requests
|
||||
if [ "$REQUEST_METHOD" = "GET" ]; then
|
||||
QUERY_STRING=$(echo "$QUERY_STRING" | sed 's/&/\n/g')
|
||||
for param in $QUERY_STRING; do
|
||||
case "$param" in
|
||||
status=*)
|
||||
get_status
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# If no valid request is made
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Invalid request\"}"
|
||||
exit 1
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set headers for JSON response
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Disable the service in UCI
|
||||
uci set quecmanager.quecwatch.enabled='0'
|
||||
|
||||
if ! uci commit quecmanager; then
|
||||
echo '{"status":"error","message":"Failed to update configuration"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to log cleanup events
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/quecwatch"
|
||||
local LOG_FILE="${LOG_DIR}/quecwatch.log"
|
||||
|
||||
# Ensure log directory exists
|
||||
mkdir -p "${LOG_DIR}"
|
||||
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t quecwatch "${level}: ${message}"
|
||||
}
|
||||
|
||||
# Stop the service
|
||||
if [ -x "/etc/init.d/quecwatch" ]; then
|
||||
if ! /etc/init.d/quecwatch stop; then
|
||||
log_message "ERROR" "Failed to stop service cleanly"
|
||||
|
||||
# Force kill any remaining processes
|
||||
if pkill -f "/www/cgi-bin/services/quecwatch.sh"; then
|
||||
log_message "INFO" "Forced termination of QuecWatch processes"
|
||||
fi
|
||||
else
|
||||
log_message "INFO" "Service stopped successfully"
|
||||
fi
|
||||
|
||||
# Disable the service
|
||||
if ! /etc/init.d/quecwatch disable; then
|
||||
log_message "WARN" "Failed to disable service"
|
||||
else
|
||||
log_message "INFO" "Service disabled successfully"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean up temporary files
|
||||
for file in "/tmp/quecwatch_status.json" "/tmp/quecwatch_retry_count" "/var/run/quecwatch.pid"; do
|
||||
if [ -f "$file" ]; then
|
||||
if rm -f "$file"; then
|
||||
log_message "INFO" "Removed temporary file: $file"
|
||||
else
|
||||
log_message "WARN" "Failed to remove temporary file: $file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Return success
|
||||
echo '{"status":"success","message":"QuecWatch disabled successfully"}'
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Read POST data
|
||||
read -r POST_DATA
|
||||
|
||||
# Function to extract value from JSON post data
|
||||
extract_json_value() {
|
||||
local key="$1"
|
||||
local default="$2"
|
||||
|
||||
# Try with jsonfilter
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
local value=$(echo "$POST_DATA" | jsonfilter -e "@.$key" 2>/dev/null)
|
||||
[ -n "$value" ] && echo "$value" && return 0
|
||||
fi
|
||||
|
||||
# Fallback to grep
|
||||
local value=$(echo "$POST_DATA" | grep -o "\"$key\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | cut -d'"' -f4)
|
||||
[ -n "$value" ] && echo "$value" && return 0
|
||||
|
||||
# Fallback to grep for numbers and booleans
|
||||
local value=$(echo "$POST_DATA" | grep -o "\"$key\"[[:space:]]*:[[:space:]]*[0-9a-zA-Z]*" | cut -d':' -f2 | tr -d '[:space:]')
|
||||
[ -n "$value" ] && echo "$value" && return 0
|
||||
|
||||
# Return default value
|
||||
echo "$default"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Extract parameters from POST data
|
||||
ping_target=$(extract_json_value "pingTarget" "8.8.8.8")
|
||||
ping_interval=$(extract_json_value "pingInterval" "60")
|
||||
ping_failures=$(extract_json_value "pingFailures" "3")
|
||||
max_retries=$(extract_json_value "maxRetries" "5")
|
||||
connection_refresh=$(extract_json_value "connectionRefresh" "false")
|
||||
auto_sim_failover=$(extract_json_value "autoSimFailover" "false")
|
||||
sim_failover_schedule=$(extract_json_value "simFailoverSchedule" "0")
|
||||
|
||||
# Validate numeric values
|
||||
validate_number() {
|
||||
local value="$1"
|
||||
local min="$2"
|
||||
local max="$3"
|
||||
local name="$4"
|
||||
|
||||
if ! echo "$value" | grep -q '^[0-9]\+$'; then
|
||||
echo '{"status":"error","message":"'"$name must be a number"'"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$value" -lt "$min" ] || [ "$value" -gt "$max" ]; then
|
||||
echo '{"status":"error","message":"'"$name must be between $min and $max"'"}'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate boolean values
|
||||
validate_boolean() {
|
||||
local value="$1"
|
||||
local name="$2"
|
||||
|
||||
if [ "$value" != "true" ] && [ "$value" != "false" ]; then
|
||||
echo '{"status":"error","message":"'"$name must be true or false"'"}'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate parameters
|
||||
validate_number "$ping_interval" 5 3600 "Ping interval"
|
||||
validate_number "$ping_failures" 1 10 "Ping failures"
|
||||
validate_number "$max_retries" 1 20 "Max retries"
|
||||
validate_number "$sim_failover_schedule" 0 1440 "SIM failover schedule"
|
||||
validate_boolean "$connection_refresh" "Connection refresh"
|
||||
validate_boolean "$auto_sim_failover" "Auto SIM failover"
|
||||
|
||||
# Function to setup UCI configuration
|
||||
setup_uci_config() {
|
||||
# Create section if it doesn't exist
|
||||
touch /etc/config/quecmanager
|
||||
|
||||
if ! uci -q get quecmanager.quecwatch >/dev/null; then
|
||||
uci set quecmanager.quecwatch=service
|
||||
fi
|
||||
|
||||
# Set UCI values
|
||||
uci set quecmanager.quecwatch.enabled='1'
|
||||
uci set quecmanager.quecwatch.ping_target="$ping_target"
|
||||
uci set quecmanager.quecwatch.ping_interval="$ping_interval"
|
||||
uci set quecmanager.quecwatch.ping_failures="$ping_failures"
|
||||
uci set quecmanager.quecwatch.max_retries="$max_retries"
|
||||
uci set quecmanager.quecwatch.current_retries='0'
|
||||
uci set quecmanager.quecwatch.connection_refresh="$connection_refresh"
|
||||
uci set quecmanager.quecwatch.refresh_count='3'
|
||||
uci set quecmanager.quecwatch.auto_sim_failover="$auto_sim_failover"
|
||||
uci set quecmanager.quecwatch.sim_failover_schedule="$sim_failover_schedule"
|
||||
|
||||
# Commit changes
|
||||
if ! uci commit quecmanager; then
|
||||
echo '{"status":"error","message":"Failed to save configuration"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Setup configuration
|
||||
if ! setup_uci_config; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enable and start the service
|
||||
if [ ! -f "/etc/init.d/quecwatch" ]; then
|
||||
echo '{"status":"error","message":"QuecWatch service script not found"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the service script is executable
|
||||
chmod +x /etc/init.d/quecwatch
|
||||
|
||||
# Enable the service
|
||||
if ! /etc/init.d/quecwatch enable; then
|
||||
echo '{"status":"error","message":"Failed to enable QuecWatch service"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start the service
|
||||
if ! /etc/init.d/quecwatch start; then
|
||||
echo '{"status":"error","message":"Failed to start QuecWatch service"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Return success response
|
||||
echo '{"status":"success","message":"QuecWatch enabled successfully"}'
|
||||
@@ -0,0 +1,139 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set headers for JSON response
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Load UCI functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Function to safely get UCI value with default
|
||||
get_uci_value() {
|
||||
local value
|
||||
config_get value quecwatch "$1" "$2"
|
||||
echo "${value:-$2}"
|
||||
}
|
||||
|
||||
# Function to format boolean for JSON
|
||||
format_boolean() {
|
||||
if [ "$1" = "1" ] || [ "$1" = "true" ]; then
|
||||
echo "true"
|
||||
else
|
||||
echo "false"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if service is running
|
||||
check_service_status() {
|
||||
if [ -f "/var/run/quecwatch.pid" ]; then
|
||||
pid=$(cat /var/run/quecwatch.pid 2>/dev/null)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
echo "stopped"
|
||||
}
|
||||
|
||||
# Function to get last log entry
|
||||
get_last_log() {
|
||||
local LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -n 1 "$LOG_FILE" | sed 's/"/\\"/g'
|
||||
else
|
||||
echo "No log entries found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current status
|
||||
get_current_status() {
|
||||
local STATUS_FILE="/tmp/quecwatch_status.json"
|
||||
local status="unknown"
|
||||
local message="Status not available"
|
||||
local retry="0"
|
||||
local maxRetries="0"
|
||||
local timestamp=$(date +%s)
|
||||
|
||||
if [ -f "$STATUS_FILE" ]; then
|
||||
# Try to extract values from status file
|
||||
if grep -q "status" "$STATUS_FILE"; then
|
||||
status=$(cat "$STATUS_FILE" | jsonfilter -e '@.status' 2>/dev/null)
|
||||
message=$(cat "$STATUS_FILE" | jsonfilter -e '@.message' 2>/dev/null)
|
||||
retry=$(cat "$STATUS_FILE" | jsonfilter -e '@.retry' 2>/dev/null)
|
||||
maxRetries=$(cat "$STATUS_FILE" | jsonfilter -e '@.maxRetries' 2>/dev/null)
|
||||
timestamp=$(cat "$STATUS_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use defaults if extraction failed
|
||||
[ -z "$status" ] && status="unknown"
|
||||
[ -z "$message" ] && message="Status not available"
|
||||
[ -z "$retry" ] && retry="0"
|
||||
[ -z "$maxRetries" ] && maxRetries="0"
|
||||
[ -z "$timestamp" ] && timestamp=$(date +%s)
|
||||
|
||||
echo "{\"status\":\"$status\",\"message\":\"$message\",\"retry\":$retry,\"maxRetries\":$maxRetries,\"timestamp\":$timestamp}"
|
||||
}
|
||||
|
||||
# Load QuecManager configuration
|
||||
config_load quecmanager
|
||||
|
||||
# Check if QuecWatch section exists
|
||||
if ! uci -q get quecmanager.quecwatch >/dev/null; then
|
||||
echo '{"status":"inactive","message":"QuecWatch is not configured"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get enabled status
|
||||
enabled=$(get_uci_value "enabled" "0")
|
||||
|
||||
# Get service status
|
||||
service_status=$(check_service_status)
|
||||
|
||||
# Get current status
|
||||
current_status=$(get_current_status)
|
||||
|
||||
# Get last log entry
|
||||
last_log=$(get_last_log)
|
||||
|
||||
# Fetch all configuration values
|
||||
ping_target=$(get_uci_value "ping_target" "8.8.8.8")
|
||||
ping_interval=$(get_uci_value "ping_interval" "60")
|
||||
ping_failures=$(get_uci_value "ping_failures" "3")
|
||||
max_retries=$(get_uci_value "max_retries" "5")
|
||||
current_retries=$(get_uci_value "current_retries" "0")
|
||||
connection_refresh=$(format_boolean $(get_uci_value "connection_refresh" "false"))
|
||||
refresh_count=$(get_uci_value "refresh_count" "3")
|
||||
auto_sim_failover=$(format_boolean $(get_uci_value "auto_sim_failover" "false"))
|
||||
sim_failover_schedule=$(get_uci_value "sim_failover_schedule" "0")
|
||||
|
||||
# Determine the overall status
|
||||
status="inactive"
|
||||
if [ "$enabled" = "1" ]; then
|
||||
if [ "$service_status" = "running" ]; then
|
||||
status="active"
|
||||
else
|
||||
status="error"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prepare JSON response
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"serviceStatus": "$service_status",
|
||||
"currentStatus": $current_status,
|
||||
"config": {
|
||||
"pingTarget": "$ping_target",
|
||||
"pingInterval": $ping_interval,
|
||||
"pingFailures": $ping_failures,
|
||||
"maxRetries": $max_retries,
|
||||
"currentRetries": $current_retries,
|
||||
"connectionRefresh": $connection_refresh,
|
||||
"refreshCount": $refresh_count,
|
||||
"autoSimFailover": $auto_sim_failover,
|
||||
"simFailoverSchedule": $sim_failover_schedule
|
||||
},
|
||||
"lastActivity": "$last_log"
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set headers for JSON response
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log message
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/quecwatch"
|
||||
local LOG_FILE="${LOG_DIR}/quecwatch.log"
|
||||
|
||||
# Ensure log directory exists
|
||||
mkdir -p "${LOG_DIR}"
|
||||
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t quecwatch "${level}: ${message}"
|
||||
}
|
||||
|
||||
# Reset retry counter
|
||||
if uci -q get quecmanager.quecwatch >/dev/null; then
|
||||
# Reset retry counter in UCI
|
||||
uci set quecmanager.quecwatch.current_retries='0'
|
||||
|
||||
# Make sure service is enabled
|
||||
uci set quecmanager.quecwatch.enabled='1'
|
||||
|
||||
# Commit changes
|
||||
if uci commit quecmanager; then
|
||||
log_message "INFO" "Retry counter reset to 0 and service enabled"
|
||||
|
||||
# Also update the retry count file for immediate effect
|
||||
echo "0" > "/tmp/quecwatch_retry_count"
|
||||
chmod 644 "/tmp/quecwatch_retry_count"
|
||||
|
||||
# Restart the service if it exists
|
||||
if [ -x "/etc/init.d/quecwatch" ]; then
|
||||
if /etc/init.d/quecwatch restart; then
|
||||
log_message "INFO" "Service restarted successfully"
|
||||
echo '{"status":"success","message":"Retry counter reset and service restarted successfully"}'
|
||||
else
|
||||
log_message "ERROR" "Failed to restart service"
|
||||
echo '{"status":"warning","message":"Retry counter reset but failed to restart service"}'
|
||||
fi
|
||||
else
|
||||
log_message "ERROR" "Service init script not found"
|
||||
echo '{"status":"warning","message":"Retry counter reset but service init script not found"}'
|
||||
fi
|
||||
else
|
||||
log_message "ERROR" "Failed to update configuration"
|
||||
echo '{"status":"error","message":"Failed to update configuration"}'
|
||||
fi
|
||||
else
|
||||
echo '{"status":"error","message":"QuecWatch configuration not found"}'
|
||||
fi
|
||||
Reference in New Issue
Block a user