QuecManager v2.3.2 Release Candidate

This commit is contained in:
Russel Yasol
2025-09-07 18:36:18 +08:00
parent 64f06fc056
commit 08a1cd8d7b
88 changed files with 800 additions and 456 deletions

View File

@@ -2,10 +2,10 @@
# AT Queue Client for OpenWRT
# Located in /www/cgi-bin/services/at_queue_client
AUTH_FILE="/tmp/auth_success"
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager.sh"
HOST_DIR=$(pwd)
QUEUE_MANAGER="${HOST_DIR}/cgi-bin/services/at_queue_manager.sh"
POLL_INTERVAL=0.01
usage() {
@@ -27,15 +27,13 @@ output_json() {
# URL decode function
urldecode() {
local encoded="$1"
logger -t at_queue -p daemon.debug "urldecode: input='$encoded'"
# Handle %2B -> + and %22 -> " conversions
local decoded="${encoded//%2B/+}"
decoded="${decoded//%22/\"}"
# Then handle other encoded characters
decoded=$(printf '%b' "${decoded//%/\\x}")
logger -t at_queue -p daemon.debug "urldecode: output='$decoded'"
echo "$decoded"
}
@@ -43,28 +41,28 @@ urldecode() {
get_command_id() {
local response="$1"
echo "DEBUG: Raw response: '$response'" >&2
# Strip any headers from response
local json_response=$(echo "$response" | sed -n '/^{/,$p')
echo "DEBUG: JSON portion: '$json_response'" >&2
# Try to extract command_id using grep and sed instead of jsonfilter
local cmd_id=$(echo "$json_response" | grep -o '"command_id":"[^"]*"' | sed 's/"command_id":"//;s/"$//')
if [ -n "$cmd_id" ]; then
echo "$cmd_id"
return 0
fi
# Fallback to jsonfilter if available
echo "DEBUG: Trying jsonfilter as fallback" >&2
local cmd_id_jsonfilter=$(echo "$json_response" | jsonfilter -e '@.command_id' 2>/dev/null)
if [ -n "$cmd_id_jsonfilter" ]; then
echo "$cmd_id_jsonfilter"
return 0
fi
echo "ERROR: Failed to extract command ID from response" >&2
return 1
}
@@ -72,20 +70,16 @@ get_command_id() {
# Normalize AT command
normalize_at_command() {
local cmd="$1"
logger -t at_queue -p daemon.debug "normalize: input='$cmd'"
# URL decode the command
cmd=$(urldecode "$cmd")
logger -t at_queue -p daemon.debug "normalize: after urldecode='$cmd'"
# Remove any carriage returns or newlines
cmd=$(echo "$cmd" | tr -d '\r\n')
logger -t at_queue -p daemon.debug "normalize: after cleanup='$cmd'"
# Trim leading/trailing whitespace while preserving quotes
cmd=$(echo "$cmd" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
logger -t at_queue -p daemon.debug "normalize: final output='$cmd'"
echo "$cmd"
}
@@ -93,12 +87,12 @@ normalize_at_command() {
submit_command() {
local cmd="$1"
local priority=10
# Set high priority for QSCAN commands for faster processing
if echo "$cmd" | grep -qi "AT+QSCAN"; then
priority=1
fi
# Submit using appropriate method
if [ "${SCRIPT_NAME}" != "" ]; then
# CGI mode - direct execution
@@ -114,11 +108,10 @@ submit_command() {
check_result() {
local cmd_id="$1"
local show_headers="${2:-1}" # Add parameter for header control
if [ -f "$RESULTS_DIR/$cmd_id.json" ]; then
local result_content=$(cat "$RESULTS_DIR/$cmd_id.json")
if [ -z "$result_content" ]; then
logger -t at_queue -p daemon.error "Empty result file for command ID: $cmd_id"
local error_json="{\"error\":\"Empty result file\",\"command_id\":\"$cmd_id\"}"
output_json "$error_json" "$show_headers"
return 1
@@ -137,37 +130,37 @@ wait_for_completion() {
local timeout="$2"
local show_headers="${3:-1}"
local result_file="$RESULTS_DIR/$cmd_id.json"
if [ -z "$cmd_id" ]; then
local error_json="{\"error\":\"Invalid command ID\"}"
output_json "$error_json" "$show_headers"
return 1
fi
# First quick check
if [ -f "$result_file" ]; then
output_json "$(cat "$result_file")" "$show_headers"
return 0
fi
# Wait with shorter polling interval
local start_time=$(date +%s)
local current_time
while true; do
if [ -f "$result_file" ]; then
output_json "$(cat "$result_file")" "$show_headers"
return 0
fi
current_time=$(date +%s)
if [ $((current_time - start_time)) -ge "$timeout" ]; then
break
fi
sleep $POLL_INTERVAL
done
local error_json=$(cat << EOF
{
"error": "Timeout waiting for completion",
@@ -183,33 +176,19 @@ EOF
# CGI request handling
if [ "${SCRIPT_NAME}" != "" ]; then
# Output headers only once at the beginning
echo "Content-Type: application/json"
echo "Content-Type: application/json"
echo ""
# Get Token from Authorization Header
TOKEN="${HTTP_AUTHORIZATION}"
if [ ! -f $AUTH_FILE ]; then
output_json "{\"error\":\"Unauthenticated Request\"}" "0"
# Check for Authorization Header
if [ -z "${HTTP_AUTHORIZATION}" ]; then
output_json "{\"error\":\"Unauthorized\"}" "0"
exit 1
fi
if [ -z "$TOKEN" ] || "${TOKEN}" = "" || [ $(grep "${TOKEN}" "${AUTH_FILE}" | wc -l) -eq 0 ]; then
output_json "{\"response\": { \"status\": \"error\", \"raw_output\": \"Not Authorized\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Not Authorized\"}" "0"
exit 1
fi
# Check if token is within 2 hours
TOKEN_LINE=$(grep "${TOKEN}" "${AUTH_FILE}")
TOKEN_DATE=$(echo "$TOKEN_LINE" | awk '{print $1}' | sed 's/T/ /')
TOKEN_TIME=$(date -d "$TOKEN_DATE" +%s 2>/dev/null)
NOW_TIME=$(date +%s)
MAX_AGE=$((2 * 3600)) # 2 hours in seconds
if [ -z "$TOKEN_TIME" ] || [ $((NOW_TIME - TOKEN_TIME)) -gt $MAX_AGE ]; then
output_json "{ \"response\": { \"status\": \"error\", \"raw_output\": \"Token expired. Reauthenticate to get new token.\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Token expired\"}" "0"
# Cleanup/Remove token from file
sed -i -e "s/.*${TOKEN}.*//g" /tmp/auth_success 2>/dev/null
exit 1
AUTH_RESPONSE=$(/bin/sh ${HOST_DIR}/cgi-bin/quecmanager/auth-token.sh process "${HTTP_AUTHORIZATION}")
AUTH_RESPONSE_STATUS=$?
if [ $AUTH_RESPONSE_STATUS -ne 0 ]; then
output_json $AUTH_RESPONSE "0"
exit $AUTH_RESPONSE_STATUS
fi
# Parse query string

View File

@@ -0,0 +1,84 @@
#!/bin/sh
# Exit Codes: 0 = Success, 1 = Not Authorized, 2 = Auth File Not Found, 3 = Token Removal Failed
EXIT_CODE=0
AUTH_FILE="/tmp/quecmanager/auth_success"
cleanup() {
MAX_AGE=$((2 * 3600)) # 2 hours in seconds
NOW_TIME=$(date +%s)
TMP_FILE=$(mktemp)
# AUTH_FILE cleanup process, Remove any token lines older than 2 hours from AUTH_FILE
if [ -f $AUTH_FILE ]; then
while read -r line; do
if [ -n "$(echo "$line" | tr -d '[:space:]')" ]; then
# Extract the date from the line and convert it to a timestamp
TOKEN_DATE=$(echo "$line" | awk '{print $1}' | sed 's/T/ /')
TOKEN_TIME=$(date -d "$TOKEN_DATE" +%s 2>/dev/null)
# If date is valid and not older than MAX_AGE, keep the line
if [ -n "$TOKEN_TIME" ] && [ $((NOW_TIME - TOKEN_TIME)) -le $MAX_AGE ]; then
echo "$line" >> "$TMP_FILE"
fi
fi
done < "$AUTH_FILE"
mv "$TMP_FILE" "$AUTH_FILE"
fi
}
removeToken() {
TOKEN=$1
# Remove token from file
if [ -f $AUTH_FILE ] && [ -n "${TOKEN}" ]; then
sed -i -e "s/.*${TOKEN}.*//g" ${AUTH_FILE} 2>/dev/null
echo '{"state":"success", "message":"Logged out successfully"}'
EXIT_CODE=0
else
echo '{"state":"failed", "message":"Token Removal Failed"}'
EXIT_CODE=3
fi
}
process() {
if [ -n "$1" ]; then
TOKEN=$1
else
TOKEN=$(head -c 16 /dev/urandom | hexdump -v -e '/1 "%02x"')
touch ${AUTH_FILE}
echo "$(date +"%Y-%m-%dT%H:%M:%S") ${TOKEN}" >> ${AUTH_FILE}
echo "" >> ${AUTH_FILE}
fi
if [ ! -f $AUTH_FILE ]; then
echo '{"state":"failed", "message":"Authentication file not found"}'
EXIT_CODE=2
fi
if [ $EXIT_CODE -eq 0 ] && ( [ -z "$TOKEN" ] || [ "$TOKEN" = "" ] || [ $(grep "${TOKEN}" "${AUTH_FILE}" | wc -l) -eq 0 ] ); then
echo "{\"response\": { \"status\": \"error\", \"raw_output\": \"Not Authorized\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Not Authorized\"}"
EXIT_CODE=1
fi
if [ $EXIT_CODE -eq 0 ] && grep -q "$TOKEN" "$AUTH_FILE"; then
echo "{\"state\":\"success\", \"token\":\"$TOKEN\"}"
EXIT_CODE=0
fi
}
case $1 in
removeToken)
removeToken $2
;;
cleanup)
cleanup
;;
process)
cleanup
process $2
;;
*)
cleanup
process $1
;;
esac
exit $EXIT_CODE

View File

@@ -7,12 +7,11 @@ echo ""
# Read POST data
read -r POST_DATA
# Debug log for generated hash
DEBUG_LOG="/tmp/auth.log"
AUTH_FILE="/tmp/auth_success"
# Extract the password from POST data (URL encoded)
USER="root"
INPUT_PASSWORD=$(echo "$POST_DATA" | grep -o 'password=[^&]*' | cut -d= -f2-)
RESPONSE=""
HOST_DIR=$(pwd)
# URL-decode the password while preserving most special characters
# First decode percent-encoded sequences
@@ -51,46 +50,13 @@ SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
# Use printf to avoid issues with special characters in echo
GENERATED_HASH=$(printf '%s' "$INPUT_PASSWORD" | openssl passwd -1 -salt "$SALT" -stdin)
# Log generated hash for debugging
printf "Generated hash: %s\n" "$GENERATED_HASH" >> "$DEBUG_LOG"
# Check if the request for AUTH contains the Authorization Header so as to assure we're not at an initial login
SUPPLIED_TOKEN="${HTTP_AUTHORIZATION}"
# Compare the generated hash with the one in the shadow file
if [ "$GENERATED_HASH" = "$USER_HASH" ]; then
# If the token is supplied, use it; otherwise, generate a new one and store it in the auth file
if [ "$SUPPLIED_TOKEN" != "" ]; then
TOKEN="$SUPPLIED_TOKEN"
else
TOKEN=$(head -c 16 /dev/urandom | hexdump -v -e '/1 "%02x"')
CREATED_DATE=$(date +"%Y-%m-%dT%H:%M:%S")
touch ${AUTH_FILE}
echo "${CREATED_DATE} ${TOKEN}" >> ${AUTH_FILE}
echo "" >> ${AUTH_FILE}
fi
echo "{\"state\":\"success\",\"token\":\"${TOKEN}\"}"
RESPONSE=$(/bin/sh ${HOST_DIR}/cgi-bin/quecmanager/auth-token.sh process "$SUPPLIED_TOKEN")
else
# Remove token from file
if [ -n ${TOKEN} ]; then
sed -i -e "s/.*${TOKEN}.*//g" ${AUTH_FILE} 2>/dev/null
fi
echo '{"state":"failed", "message":"Authentication failed"}'
RESPONSE=$(/bin/sh ${HOST_DIR}/cgi-bin/quecmanager/auth-token.sh removeToken "$SUPPLIED_TOKEN")
fi
# AUTH_FILE cleanup process, Remove any token lines older than 2 hours from AUTH_FILE
MAX_AGE=$((2 * 3600)) # 2 hours in seconds
NOW_TIME=$(date +%s)
TMP_FILE=$(mktemp)
while read -r line; do
if [ -n "$(echo "$line" | tr -d '[:space:]')" ]; then
# Extract the date from the line and convert it to a timestamp
TOKEN_DATE=$(echo "$line" | awk '{print $1}' | sed 's/T/ /')
TOKEN_TIME=$(date -d "$TOKEN_DATE" +%s 2>/dev/null)
# If date is valid and not older than MAX_AGE, keep the line
if [ -n "$TOKEN_TIME" ] && [ $((NOW_TIME - TOKEN_TIME)) -le $MAX_AGE ]; then
echo "$line" >> "$TMP_FILE"
fi
fi
done < "$AUTH_FILE"
mv "$TMP_FILE" "$AUTH_FILE"
echo "$RESPONSE"

View File

@@ -0,0 +1,303 @@
#!/bin/sh
# OpenWrt-Compatible Improved fetch_data.sh
# Optimized for OpenWrt/BusyBox environment with enhanced performance
# Set content-type for JSON response
printf "Content-type: application/json\r\n"
printf "\r\n"
# Load centralized logging
. /www/cgi-bin/services/quecmanager_logger.sh
# Configuration
QUEUE_DIR="/tmp/at_queue"
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager.sh"
SCRIPT_NAME_LOG="fetch_data"
# Performance settings - OpenWrt optimized
BATCH_TIMEOUT=45 # Timeout for batch operations
INDIVIDUAL_TIMEOUT=15 # Timeout for individual commands
TOKEN_RETRY_LIMIT=8 # Reduced retries for faster failure
TOKEN_RETRY_DELAY=0.1 # Faster retry intervals
# Minimal logging for performance
log_fetch() {
local level="$1"
local message="$2"
# Only log errors to centralized system for performance
case "$level" in
"error")
qm_log_error "service" "$SCRIPT_NAME_LOG" "$message"
;;
"debug")
[ "${DEBUG_MODE:-0}" = "1" ] && logger -t fetch_data -p "daemon.debug" "$message"
;;
esac
}
# Ensure queue directory exists
mkdir -p "$QUEUE_DIR"
# OpenWrt-compatible JSON escaping using shell builtins
escape_json() {
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\x1b/\\u001b/g' | tr -d '\r\n\f\b'
}
# OpenWrt-compatible URL encoding
urlencode_simple() {
local string="$1"
# Encode most common special characters for BusyBox compatibility
string="${string// /%20}"
string="${string//+/%2B}"
string="${string//\"/%22}"
string="${string//=/%3D}"
string="${string//&/%26}"
string="${string//#/%23}"
string="${string//?/%3F}"
string="${string//;/%3B}"
string="${string//,/%2C}"
echo "$string"
}
# Fast AT command execution with OpenWrt timeout handling
execute_at_command() {
local cmd="$1"
local timeout="${2:-$INDIVIDUAL_TIMEOUT}"
local output=""
local status=1
# OpenWrt-compatible timeout implementation
if command -v timeout >/dev/null 2>&1; then
# Use timeout command if available
output=$(timeout "$timeout" sms_tool at "$cmd" 2>&1)
status=$?
else
# BusyBox-compatible timeout implementation
(
sms_tool at "$cmd" 2>&1 &
local cmd_pid=$!
# Background timeout
(sleep "$timeout" && kill -TERM $cmd_pid 2>/dev/null) &
local timeout_pid=$!
wait $cmd_pid
local cmd_status=$?
kill $timeout_pid 2>/dev/null
exit $cmd_status
)
status=$?
output=$(cat)
fi
if [ $status -eq 0 ] && [ -n "$output" ]; then
echo "$output"
return 0
fi
return 1
}
# Intelligent command grouping for batch processing
group_commands() {
local commands="$1"
# Separate quick vs slow commands for optimized processing
local quick_commands=""
local slow_commands=""
for cmd in $commands; do
case "$cmd" in
*"?"*|*"CREG"*|*"CGREG"*|*"CEREG"*|*"CPIN"*|*"CFUN"*)
quick_commands="$quick_commands $cmd"
;;
*)
slow_commands="$slow_commands $cmd"
;;
esac
done
# Process quick commands first with shorter timeout
if [ -n "$quick_commands" ]; then
process_command_batch "$quick_commands" 10
fi
# Then process slower commands
if [ -n "$slow_commands" ]; then
process_command_batch "$slow_commands" $INDIVIDUAL_TIMEOUT
fi
}
# Process a batch of commands using the queue manager
process_command_batch() {
local commands="$1"
local timeout="${2:-$INDIVIDUAL_TIMEOUT}"
local first=1
for cmd in $commands; do
[ $first -eq 0 ] && printf ','
first=0
# Use queue manager for better performance and queuing
local escaped_cmd=$(urlencode_simple "$cmd")
local priority=5 # Medium priority for batch operations
# Submit to queue manager
local response=$(REQUEST_METHOD="GET" QUERY_STRING="command=$escaped_cmd&priority=$priority&timeout=$timeout" "$QUEUE_MANAGER" 2>/dev/null)
# Extract command ID
local cmd_id=""
if [ -n "$response" ]; then
cmd_id=$(echo "$response" | grep -o '"command_id":"[^"]*"' | cut -d'"' -f4)
[ -z "$cmd_id" ] && cmd_id=$(echo "$response" | grep -o '"id":"[^"]*"' | cut -d'"' -f4)
fi
local escaped_cmd_display=$(escape_json "$cmd")
if [ -n "$cmd_id" ]; then
# Wait for result with polling
local result_file="/tmp/at_queue/results/$cmd_id"
local wait_time=0
local max_wait=$timeout
while [ $wait_time -lt $max_wait ]; do
if [ -f "$result_file" ]; then
local result_content=$(cat "$result_file" 2>/dev/null)
if [ -n "$result_content" ]; then
# Extract response from result
local cmd_response=$(echo "$result_content" | grep -o '"response":"[^"]*"' | cut -d'"' -f4)
local cmd_status=$(echo "$result_content" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
if [ "$cmd_status" = "success" ] && [ -n "$cmd_response" ]; then
printf '{"command":"%s","response":"%s","status":"success"}' \
"$escaped_cmd_display" "$(escape_json "$cmd_response")"
else
printf '{"command":"%s","response":"Command failed","status":"error"}' \
"$escaped_cmd_display"
fi
# Cleanup result file
rm -f "$result_file" 2>/dev/null
break
fi
fi
sleep 0.2
wait_time=$((wait_time + 1))
done
# If we didn't get a result, report timeout
if [ $wait_time -ge $max_wait ]; then
printf '{"command":"%s","response":"Command timed out","status":"timeout"}' \
"$escaped_cmd_display"
rm -f "$result_file" 2>/dev/null
fi
else
# Direct execution fallback if queue manager fails
local output=$(execute_at_command "$cmd" "$timeout")
local cmd_status=$?
if [ $cmd_status -eq 0 ] && [ -n "$output" ]; then
printf '{"command":"%s","response":"%s","status":"success"}' \
"$escaped_cmd_display" "$(escape_json "$output")"
else
printf '{"command":"%s","response":"Direct execution failed","status":"error"}' \
"$escaped_cmd_display"
fi
fi
done
}
# Enhanced batch processing with optimizations
process_all_commands() {
local commands="$1"
local priority="${2:-5}"
printf '['
group_commands "$commands"
printf ']\r\n'
return 0
}
# Cleanup on exit
cleanup() {
exit 0
}
# Set up signal handlers
trap cleanup INT TERM
# Enhanced command sets with better organization
COMMAND_SET_1='AT+QUIMSLOT? AT+CNUM AT+COPS? AT+CIMI AT+ICCID AT+CGSN AT+CPIN? AT+CGDCONT? AT+CREG? AT+CFUN? AT+QENG="servingcell" AT+QTEMP AT+CGCONTRDP'
COMMAND_SET_2='AT+QCAINFO=1;+QCAINFO;+QCAINFO=0 AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
COMMAND_SET_3='AT+CGMI AT+CGMM AT+QGMR AT+CNUM AT+CIMI AT+ICCID AT+CGSN AT+QMAP="LANIP" AT+QMAP="WWAN" AT+QGETCAPABILITY'
COMMAND_SET_4='AT+QMAP="MPDN_RULE" AT+QMAP="DHCPV4DNS" AT+QCFG="usbnet" AT+QNWCFG="3gpp_rel"'
COMMAND_SET_5='AT+QRSRP AT+QRSRQ AT+QSINR AT+QCAINFO AT+QSPN'
COMMAND_SET_6='AT+CEREG=2;+CEREG? AT+C5GREG=2;+C5GREG? AT+CPIN? AT+CGDCONT? AT+CGCONTRDP AT+QMAP="WWAN" AT+QRSRP AT+QTEMP'
COMMAND_SET_7='AT+QNWPREFCFG="policy_band" AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band"'
COMMAND_SET_8='AT+QNWLOCK="common/4g" AT+QNWLOCK="common/5g" AT+QNWLOCK="save_ctrl"'
COMMAND_SET_9='AT+QNWCFG="lte_time_advance",1;+QNWCFG="lte_time_advance" AT+QNWCFG="nr5g_time_advance",1;+QNWCFG="nr5g_time_advance"'
COMMAND_SET_10='AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QMBNCFG="AutoSel" AT+QMBNCFG="list"'
# Parse command set with validation - OpenWrt compatible
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[0-9]\+' | cut -d'=' -f2 | tr -cd '0-9')
if [ -z "$COMMAND_SET" ] || [ "$COMMAND_SET" -lt 1 ] || [ "$COMMAND_SET" -gt 10 ]; then
COMMAND_SET=1
fi
# Select appropriate command set
case "$COMMAND_SET" in
1) COMMANDS="$COMMAND_SET_1" ;;
2) COMMANDS="$COMMAND_SET_2" ;;
3) COMMANDS="$COMMAND_SET_3" ;;
4) COMMANDS="$COMMAND_SET_4" ;;
5) COMMANDS="$COMMAND_SET_5" ;;
6) COMMANDS="$COMMAND_SET_6" ;;
7) COMMANDS="$COMMAND_SET_7" ;;
8) COMMANDS="$COMMAND_SET_8" ;;
9) COMMANDS="$COMMAND_SET_9" ;;
10) COMMANDS="$COMMAND_SET_10" ;;
esac
# Set priority based on command type
PRIORITY=5 # Medium-high priority for data fetching
# Check for high priority commands
if echo "$COMMANDS" | grep -qi "QSCAN"; then
PRIORITY=1
elif echo "$COMMANDS" | grep -qi "COPS\|CFUN"; then
PRIORITY=3
fi
# Execute batch processing with timeout protection
(
# Set overall timeout for the entire script using OpenWrt-compatible method
if command -v timeout >/dev/null 2>&1; then
timeout $BATCH_TIMEOUT sh -c '
process_all_commands "$1" "$2"
' _ "$COMMANDS" "$PRIORITY"
else
# BusyBox timeout fallback
(
process_all_commands "$COMMANDS" "$PRIORITY" &
local main_pid=$!
(sleep $BATCH_TIMEOUT && kill -TERM $main_pid 2>/dev/null) &
local timeout_pid=$!
wait $main_pid
local exit_status=$?
kill $timeout_pid 2>/dev/null
if [ $exit_status -eq 143 ] || [ $exit_status -eq 124 ]; then
printf '[{"command":"batch","response":"Script execution timed out","status":"timeout"}]\r\n'
fi
)
fi
) || {
# Handle script timeout
printf '[{"command":"batch","response":"Script execution timed out","status":"timeout"}]\r\n'
}

View File

@@ -1,10 +0,0 @@
#!/bin/sh
echo "Content-Type: application/json"
echo "Cache-Control: no-cache, no-store, must-revalidate"
echo "Pragma: no-cache"
echo "Expires: 0"
echo ""
# Basic response indicating the server is up
echo '{"alive": true}'

View File

@@ -1,8 +1,9 @@
#!/bin/sh
# Get token from Request Header Authorization
USER_TOKEN="${HTTP_AUTHORIZATION}"
# Remove token from file
sed -i -e "s/.*${USER_TOKEN}.*//g" /tmp/auth_success 2>/dev/null
HOST_DIR=$(pwd)
AUTH_RESPONSE=$(/bin/sh ${HOST_DIR}/cgi-bin/quecmanager/auth-token.sh removeToken "${HTTP_AUTHORIZATION}")
EXIT_CODE=$?
echo "Content-Type: application/json"
echo "Cache-Control: no-cache, no-store, must-revalidate"
@@ -12,4 +13,5 @@ echo ""
echo '{"state":"success", "message":"Logged out successfully"}'
echo $AUTH_RESPONSE
exit $EXIT_CODE

View File

@@ -4,38 +4,18 @@
echo "Content-type: application/json"
echo ""
TOKEN="${HTTP_AUTHORIZATION}"
# Read POST data
read -r POST_DATA
# Debug log for generated hash
DEBUG_LOG="/tmp/password_change.log"
AUTH_FILE="/tmp/auth_success"
HOST_DIR=$(pwd)
# Get Token from Authorization Header on Request
if [ ! -f $AUTH_FILE ]; then
echo "{\"error\":\"Unauthenticated Request\"}"
exit 1
fi
if [ -z "$TOKEN" ] || "${TOKEN}" = "" || [ $(grep "${TOKEN}" "${AUTH_FILE}" | wc -l) -eq 0 ]; then
echo "{\"response\": { \"status\": \"error\", \"raw_output\": \"Not Authorized\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Not Authorized\"}"
exit 1
fi
# Check if token is within 2 hours
TOKEN_LINE=$(grep "${TOKEN}" "${AUTH_FILE}")
TOKEN_DATE=$(echo "$TOKEN_LINE" | awk '{print $1}' | sed 's/T/ /')
TOKEN_TIME=$(date -d "$TOKEN_DATE" +%s 2>/dev/null)
NOW_TIME=$(date +%s)
MAX_AGE=$((2 * 3600)) # 2 hours in seconds
if [ -z "$TOKEN_TIME" ] || [ $((NOW_TIME - TOKEN_TIME)) -gt $MAX_AGE ]; then
echo "{ \"response\": { \"status\": \"error\", \"raw_output\": \"Token expired. Reauthenticate to get new token.\" }, \"command\": {\"timestamp\": \"$(date +%Y%m%d'T'%H%M%S)\"}, \"error\":\"Token expired\"}"
# Cleanup/Remove token from file
sed -i -e "s/.*${TOKEN}.*//g" /tmp/auth_success 2>/dev/null
exit 1
AUTH_RESPONSE=$(/bin/sh ${HOST_DIR}/cgi-bin/quecmanager/auth-token.sh process "$HTTP_AUTHORIZATION")
AUTH_RESPONSE_STATUS=$?
if [ $AUTH_RESPONSE_STATUS -ne 0 ]; then
echo $AUTH_RESPONSE
exit $AUTH_RESPONSE_STATUS
fi

View File

@@ -1,9 +1,9 @@
#!/bin/sh
# Ping Settings Configuration Script
# Manages ping service (enable/disable) and daemon settings
# Manages ping service (enable/disable) and daemon settings with dynamic service management
# Author: dr-dolomite
# Date: 2025-08-04
# Date: 2025-08-31
# Handle OPTIONS request first (before any headers)
if [ "${REQUEST_METHOD:-GET}" = "OPTIONS" ]; then
@@ -29,9 +29,7 @@ CONFIG_FILE="$CONFIG_DIR/ping_settings.conf"
FALLBACK_CONFIG_DIR="/tmp/quecmanager/settings"
FALLBACK_CONFIG_FILE="$FALLBACK_CONFIG_DIR/ping_settings.conf"
LOG_FILE="/tmp/ping_settings.log"
PID_FILE="/tmp/quecmanager/ping_daemon.pid"
# Prefer the new services location, fall back to the legacy path for compatibility
DAEMON_RELATIVE_PATHS="/cgi-bin/services/ping_daemon.sh"
SERVICES_INIT="/etc/init.d/quecmanager_services"
# Logging function
log_message() {
@@ -72,77 +70,9 @@ resolve_config_for_read() {
return 0
}
# Determine daemon path (absolute) based on typical web root layouts
resolve_daemon_path() {
# Common locations where CGI/WWW is mounted
for rel in $DAEMON_RELATIVE_PATHS; do
for base in \
/www \
/; do
if [ -x "$base$rel" ]; then
echo "$base$rel"
return 0
fi
done
# Also try as-is if busybox httpd cwd matches web root
if [ -x "$rel" ]; then
echo "$rel"
return 0
fi
done
# Nothing found; return first candidate as a best-effort path
set -- $DAEMON_RELATIVE_PATHS
echo "$1"
}
daemon_running() {
if [ -f "$PID_FILE" ]; then
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
if [ -n "${pid:-}" ] && kill -0 "$pid" 2>/dev/null; then
return 0
fi
fi
return 1
}
start_daemon() {
# Ensure /tmp/quecmanager exists for PID
[ -d "/tmp/quecmanager" ] || mkdir -p "/tmp/quecmanager"
if daemon_running; then
log_message "Daemon already running"
return 0
fi
local daemon_path
daemon_path="$(resolve_daemon_path)"
if [ ! -x "$daemon_path" ]; then
# Try to make it executable if present
if [ -f "$daemon_path" ]; then
chmod +x "$daemon_path" 2>/dev/null || true
fi
fi
if [ -x "$daemon_path" ]; then
nohup "$daemon_path" >/dev/null 2>&1 &
log_message "Started ping daemon: $daemon_path (pid $!)"
return 0
else
log_message "Daemon script not found or not executable: $daemon_path"
return 1
fi
}
stop_daemon() {
if daemon_running; then
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
if [ -n "${pid:-}" ]; then
kill "$pid" 2>/dev/null || true
sleep 0.2
kill -9 "$pid" 2>/dev/null || true
fi
fi
rm -f "$PID_FILE" 2>/dev/null || true
# Check if ping daemon is running
is_ping_daemon_running() {
pgrep -f "ping_daemon.sh" >/dev/null 2>&1
}
# Get current ping setting
@@ -202,6 +132,117 @@ save_config() {
log_message "Saved ping config (fallback): enabled=$enabled host=$host interval=$interval"
}
# Add ping daemon to services init script (remove the static version and add dynamic version)
add_ping_daemon_to_services() {
if [ ! -f "$SERVICES_INIT" ]; then
log_message "Services init file not found: $SERVICES_INIT"
return 1
fi
# First, remove any existing ping daemon block (both static and dynamic)
remove_ping_daemon_from_services
# Add the dynamic ping daemon block before "All QuecManager services Started"
local temp_file="/tmp/services_temp_$$"
awk '
/echo "All QuecManager services Started"/ {
print " # Start ping daemon"
print " echo \"Starting Ping Daemon...\""
print " procd_open_instance"
print " procd_set_param command /www/cgi-bin/services/ping_daemon.sh"
print " procd_set_param respawn"
print " procd_set_param stdout 1"
print " procd_set_param stderr 1"
print " procd_close_instance"
print " echo \"Ping Daemon started\""
print ""
}
{ print }
' "$SERVICES_INIT" > "$temp_file"
if [ -s "$temp_file" ]; then
mv "$temp_file" "$SERVICES_INIT"
chmod +x "$SERVICES_INIT"
log_message "Added ping daemon to services init script"
return 0
else
rm -f "$temp_file"
log_message "Failed to add ping daemon to services"
return 1
fi
}
# Remove ping daemon from services init script (both static and dynamic versions)
remove_ping_daemon_from_services() {
if [ ! -f "$SERVICES_INIT" ]; then
log_message "Services init file not found: $SERVICES_INIT"
return 1
fi
local temp_file="/tmp/services_temp_$$"
# Remove both the old static ping daemon block and any dynamic ping daemon block
awk '
# Skip the old static ping daemon block
/# Start ping daemon if enabled in configuration/ {
skip_static=1
next
}
skip_static && /echo "Ping Daemon started"/ {
skip_static=0
next
}
skip_static && /echo "Ping configuration not found/ {
skip_static=0
next
}
skip_static { next }
# Skip the new dynamic ping daemon block
/# Start ping daemon$/ {
skip_dynamic=1
next
}
skip_dynamic && /^$/ {
skip_dynamic=0
next
}
skip_dynamic { next }
# Print everything else
!skip_static && !skip_dynamic { print }
' "$SERVICES_INIT" > "$temp_file"
if [ -s "$temp_file" ]; then
mv "$temp_file" "$SERVICES_INIT"
chmod +x "$SERVICES_INIT"
log_message "Removed ping daemon from services init script"
return 0
else
rm -f "$temp_file"
log_message "Failed to remove ping daemon from services"
return 1
fi
}
# Restart QuecManager services
restart_services() {
log_message "Restarting QuecManager services..."
# Stop services
if [ -x "$SERVICES_INIT" ]; then
"$SERVICES_INIT" stop >/dev/null 2>&1
sleep 2
"$SERVICES_INIT" start >/dev/null 2>&1
log_message "Services restarted successfully"
return 0
else
log_message "Cannot restart services - init script not found or not executable"
return 1
fi
}
# Delete ping configuration (reset to default)
delete_ping_setting() {
local removed=1
@@ -223,7 +264,7 @@ handle_get() {
log_message "GET request received"
get_config_values
local running=false
if daemon_running; then running=true; fi
if is_ping_daemon_running; then running=true; fi
local is_default=true
if [ -f "$CONFIG_FILE" ] && grep -q "^PING_ENABLED=" "$CONFIG_FILE"; then
is_default=false
@@ -264,35 +305,34 @@ handle_post() {
send_error "INVALID_INTERVAL" "Interval must be between 1 and 3600 seconds."
fi
# Capture previous values to decide on restart
# Get current config to compare
get_config_values
local prev_enabled="$ENABLED"
local prev_host="$HOST"
local prev_interval="$INTERVAL"
# Save new configuration
save_config "$enabled" "$host" "$interval" || send_error "WRITE_FAILED" "Failed to save configuration"
# Handle service changes using dynamic management like memory
if [ "$enabled" = "true" ]; then
if daemon_running; then
# Restart only if effective parameters changed
if [ "$prev_host" != "$host" ] || [ "$prev_interval" != "$interval" ] || [ "$prev_enabled" != "$enabled" ]; then
log_message "Config change detected (host/interval/enabled). Restarting daemon."
stop_daemon
start_daemon || log_message "Failed to restart daemon"
else
log_message "No change requiring restart; daemon remains running"
fi
else
start_daemon || log_message "Failed to start daemon"
# Enable ping daemon
add_ping_daemon_to_services
if [ "$prev_enabled" != "true" ] || [ "$prev_host" != "$host" ] || [ "$prev_interval" != "$interval" ]; then
restart_services
fi
else
stop_daemon
# Disable ping daemon
remove_ping_daemon_from_services
restart_services
fi
get_config_values
# Return current status
sleep 1 # Give services time to start/stop
local running=false
if daemon_running; then running=true; fi
send_success "Ping setting updated successfully" "{\"enabled\":$ENABLED,\"host\":\"$HOST\",\"interval\":$INTERVAL,\"running\":$running}"
if is_ping_daemon_running; then running=true; fi
send_success "Ping setting updated successfully" "{\"enabled\":$enabled,\"host\":\"$host\",\"interval\":$interval,\"running\":$running}"
else
send_error "NO_DATA" "No data provided"
fi
@@ -301,13 +341,15 @@ handle_post() {
# Handle DELETE request - Reset to default (delete configuration)
handle_delete() {
log_message "DELETE request received"
stop_daemon
if delete_ping_setting; then
# Default is enabled
send_success "Ping setting reset to default" "{\"enabled\":true,\"isDefault\":true,\"running\":false}"
else
send_error "NOT_FOUND" "Ping setting configuration not found"
fi
# Remove ping daemon from services and restart
remove_ping_daemon_from_services
restart_services
# Remove config files
delete_ping_setting
send_success "Ping setting reset to default (disabled)" "{\"enabled\":false,\"running\":false,\"isDefault\":true}"
}
# Main execution