Added missing cgi-bin directory
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type for JSON response
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
# Check if the file exists
|
||||
if [ -f "/etc/config/atcommands.user" ]; then
|
||||
# Start JSON object
|
||||
printf "{\n"
|
||||
awk -F';' '
|
||||
BEGIN { first = 1 }
|
||||
{
|
||||
gsub(/\r/, "", $0)
|
||||
if (!first) printf ",\n "
|
||||
else printf " "
|
||||
gsub(/"/, "\\\"", $1)
|
||||
gsub(/"/, "\\\"", $2)
|
||||
printf "\"%s\": \"%s\"", $1, $2
|
||||
first = 0
|
||||
}
|
||||
' /etc/config/atcommands.user
|
||||
printf "\n}"
|
||||
else
|
||||
echo '{"error": "No Data"}'
|
||||
fi
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Create a temporary file to store the processed data
|
||||
temp_file=$(mktemp)
|
||||
|
||||
# Process ARP entries and store in temporary file
|
||||
arp -a | while IFS= read -r line; do
|
||||
if [ -n "$line" ]; then
|
||||
# Extract hostname (or IP if hostname is "?"), IP, and MAC
|
||||
hostname=$(echo "$line" | awk '{print $1}')
|
||||
ip=$(echo "$line" | awk -F '[()]' '{print $2}')
|
||||
mac=$(echo "$line" | awk '{print $4}')
|
||||
|
||||
# Skip entries without valid MAC addresses
|
||||
if [ "$mac" = "<incomplete>" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# If hostname is "?", use the IP address instead
|
||||
if [ "$hostname" = "?" ]; then
|
||||
hostname="$ip"
|
||||
fi
|
||||
|
||||
# Store each entry in the temp file
|
||||
echo "$hostname:$ip:$mac" >> "$temp_file"
|
||||
fi
|
||||
done
|
||||
|
||||
# Initialize JSON array
|
||||
echo -n "["
|
||||
|
||||
# Process the temporary file to create JSON
|
||||
first=true
|
||||
while IFS=: read -r hostname ip mac; do
|
||||
if [ "$first" = true ]; then
|
||||
first=false
|
||||
else
|
||||
echo -n ","
|
||||
fi
|
||||
echo -n "{\"hostname\":\"$hostname\",\"ip\":\"$ip\",\"mac\":\"$mac\"}"
|
||||
done < "$temp_file"
|
||||
|
||||
# Close the JSON array
|
||||
echo "]"
|
||||
|
||||
# Clean up
|
||||
rm -f "$temp_file"
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/bin/sh
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
mtu_firewall_file="/etc/firewall.user.mtu"
|
||||
network_interface="rmnet_data0"
|
||||
lan_utils_script="/etc/data/lanUtils.sh"
|
||||
|
||||
get_current_mtu() {
|
||||
ip link show "$network_interface" | grep -o "mtu [0-9]*" | cut -d' ' -f2
|
||||
}
|
||||
|
||||
update_lanutils_mtu_config() {
|
||||
local action="$1"
|
||||
if [ "$action" = "add" ]; then
|
||||
# Add the MTU firewall file line if not already present
|
||||
if ! grep -q "local mtu_firewall_file=/etc/firewall.user.mtu" "$lan_utils_script"; then
|
||||
sed -i '/local ttl_firewall_file=\/etc\/firewall.user.ttl/a local mtu_firewall_file=/etc/firewall.user.mtu' "$lan_utils_script"
|
||||
fi
|
||||
elif [ "$action" = "remove" ]; then
|
||||
# Remove the MTU firewall file line if present
|
||||
sed -i '/local mtu_firewall_file=\/etc\/firewall.user.mtu/d' "$lan_utils_script"
|
||||
fi
|
||||
}
|
||||
|
||||
case "$REQUEST_METHOD" in
|
||||
GET)
|
||||
# Fetch current MTU
|
||||
current_mtu=$(get_current_mtu)
|
||||
current_mtu=${current_mtu:-1500}
|
||||
|
||||
# Check if custom MTU is configured
|
||||
if [ -f "$mtu_firewall_file" ]; then
|
||||
echo "{\"isEnabled\": true, \"currentValue\": $current_mtu}"
|
||||
else
|
||||
echo "{\"isEnabled\": false, \"currentValue\": $current_mtu}"
|
||||
fi
|
||||
;;
|
||||
|
||||
POST)
|
||||
read -r post_data
|
||||
mtu_value=$(echo "$post_data" | sed 's/mtu=//')
|
||||
|
||||
# Check for disable functionality
|
||||
if [ "$mtu_value" = "disable" ]; then
|
||||
# Remove the MTU configuration file
|
||||
rm -f "$mtu_firewall_file"
|
||||
|
||||
# Remove the MTU configuration line from lanUtils.sh
|
||||
update_lanutils_mtu_config "remove"
|
||||
|
||||
# Get the default MTU
|
||||
default_mtu=$(get_current_mtu)
|
||||
default_mtu=${default_mtu:-1500}
|
||||
|
||||
echo "{\"success\": true, \"message\": \"MTU configuration disabled\", \"currentValue\": $default_mtu}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate MTU input
|
||||
if ! [[ "$mtu_value" =~ ^[0-9]+$ ]]; then
|
||||
echo "{\"success\": false, \"error\": \"Invalid MTU value\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create firewall MTU configuration file with individual interface commands
|
||||
> "$mtu_firewall_file" # Clear the file
|
||||
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
|
||||
echo "ip link set $iface mtu $mtu_value" >> "$mtu_firewall_file"
|
||||
done
|
||||
|
||||
# Immediately apply MTU change
|
||||
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
|
||||
ip link set "$iface" mtu "$mtu_value"
|
||||
done
|
||||
|
||||
# Add the MTU configuration line to lanUtils.sh
|
||||
update_lanutils_mtu_config "add"
|
||||
|
||||
# Run lanUtils.sh to update network configuration
|
||||
if [ -f "$lan_utils_script" ]; then
|
||||
. "$lan_utils_script"
|
||||
fi
|
||||
|
||||
echo "{\"success\": true, \"message\": \"MTU configuration updated to $mtu_value\", \"currentValue\": $mtu_value}"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
ttl_file="/etc/firewall.user.ttl"
|
||||
lan_utils_script="/etc/data/lanUtils.sh"
|
||||
|
||||
setup_persistent_config() {
|
||||
if [ ! -f "$lan_utils_script" ]; then
|
||||
echo "{\"success\": false, \"error\": \"lanUtils.sh not found\"}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Backup the original script if not already done
|
||||
if [ ! -f "${lan_utils_script}.bak" ]; then
|
||||
cp "$lan_utils_script" "${lan_utils_script}.bak"
|
||||
fi
|
||||
|
||||
# Add the local ttl_firewall_file line if it's not already present
|
||||
if ! grep -q "local ttl_firewall_file" "$lan_utils_script"; then
|
||||
sed -i '/local tcpmss_firewall_filev6/a \ local ttl_firewall_file=/etc/firewall.user.ttl' "$lan_utils_script"
|
||||
fi
|
||||
|
||||
# Add the condition to include the ttl_firewall_file if it's not already present
|
||||
if ! grep -q "if \[ -f \"\$ttl_firewall_file\" \]; then" "$lan_utils_script"; then
|
||||
sed -i '/if \[ -f "\$tcpmss_firewall_filev6" \]; then/i \ if [ -f "\$ttl_firewall_file" ]; then\n cat \$ttl_firewall_file >> \$firewall_file\n fi' "$lan_utils_script"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_existing_rules() {
|
||||
local current_ttl=$1
|
||||
if [ -n "$current_ttl" ]; then
|
||||
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set "$current_ttl" 2>/dev/null
|
||||
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set "$current_ttl" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
case "$REQUEST_METHOD" in
|
||||
GET)
|
||||
# Ensure consistent JSON format for GET requests
|
||||
if [ -s "$ttl_file" ]; then
|
||||
ttl_value=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
|
||||
# Ensure ttl_value is a number, default to 0 if not
|
||||
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
|
||||
ttl_value=0
|
||||
fi
|
||||
echo "{\"isEnabled\": true, \"currentValue\": $ttl_value}"
|
||||
else
|
||||
echo "{\"isEnabled\": false, \"currentValue\": 0}"
|
||||
fi
|
||||
;;
|
||||
POST)
|
||||
read -r post_data
|
||||
ttl_value=$(echo "$post_data" | sed 's/ttl=//')
|
||||
|
||||
# Ensure ttl_file exists
|
||||
touch "$ttl_file" 2>/dev/null
|
||||
if [ ! -f "$ttl_file" ]; then
|
||||
echo "{\"success\": false, \"error\": \"Cannot create TTL file\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setup persistent configuration
|
||||
setup_persistent_config
|
||||
|
||||
# Get current TTL value for cleanup
|
||||
current_ttl=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
|
||||
|
||||
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
|
||||
echo "{\"success\": false, \"error\": \"Invalid TTL value\"}"
|
||||
elif [ "$ttl_value" = "0" ]; then
|
||||
clear_existing_rules "$current_ttl"
|
||||
> "$ttl_file"
|
||||
echo "{\"success\": true}"
|
||||
else
|
||||
# Clear existing rules
|
||||
clear_existing_rules "$current_ttl"
|
||||
|
||||
# Set new rules
|
||||
echo "iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set $ttl_value" > "$ttl_file"
|
||||
echo "ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set $ttl_value" >> "$ttl_file"
|
||||
|
||||
# Apply the rules
|
||||
iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set "$ttl_value"
|
||||
ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set "$ttl_value"
|
||||
|
||||
echo "{\"success\": true}"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,266 @@
|
||||
#!/bin/sh
|
||||
# AT Queue Client for OpenWRT
|
||||
# Located in /www/cgi-bin/services/at_queue_client
|
||||
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager.sh"
|
||||
POLL_INTERVAL=0.01
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [options] <AT command>"
|
||||
echo "Options:"
|
||||
echo " -w Wait for command completion"
|
||||
echo " -t Timeout in seconds (default: 240)"
|
||||
echo " -h Show this help message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Output JSON response
|
||||
output_json() {
|
||||
local content="$1"
|
||||
local headers="${2:-1}" # Default to showing headers
|
||||
echo "$content"
|
||||
}
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
# Extract command ID from response with improved error handling
|
||||
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
|
||||
}
|
||||
|
||||
# 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"
|
||||
}
|
||||
|
||||
# Submit command with priority handling
|
||||
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
|
||||
local escaped_cmd=$(echo "$cmd" | sed 's/"/\\"/g')
|
||||
QUERY_STRING="action=enqueue&command=${escaped_cmd}&priority=$priority" "$QUEUE_MANAGER"
|
||||
else
|
||||
# CLI mode
|
||||
"$QUEUE_MANAGER" enqueue "$cmd" "$priority"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if result exists with proper error handling
|
||||
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
|
||||
fi
|
||||
output_json "$result_content" "$show_headers"
|
||||
return 0
|
||||
fi
|
||||
local error_json="{\"error\":\"Result not found\",\"command_id\":\"$cmd_id\"}"
|
||||
output_json "$error_json" "$show_headers"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for command completion with optimized polling and better error handling
|
||||
wait_for_completion() {
|
||||
local cmd_id="$1"
|
||||
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",
|
||||
"command_id": "$cmd_id",
|
||||
"timeout": $timeout
|
||||
}
|
||||
EOF
|
||||
)
|
||||
output_json "$error_json" "$show_headers"
|
||||
return 1
|
||||
}
|
||||
|
||||
# CGI request handling
|
||||
if [ "${SCRIPT_NAME}" != "" ]; then
|
||||
# Output headers only once at the beginning
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
# Parse query string
|
||||
eval $(echo "$QUERY_STRING" | sed 's/&/;/g')
|
||||
|
||||
# Handle different actions
|
||||
if [ -n "$command_id" ]; then
|
||||
# Get result for specific command ID
|
||||
check_result "$command_id" "0" # Don't show headers
|
||||
elif [ -n "$command" ]; then
|
||||
# URL decode and normalize the command
|
||||
command=$(urldecode "$command")
|
||||
command=$(normalize_at_command "$command")
|
||||
|
||||
# Check if it's a valid AT command
|
||||
if echo "$command" | grep -qi "^AT"; then
|
||||
# Submit command and get response
|
||||
response=$(submit_command "$command")
|
||||
cmd_id=$(get_command_id "$response")
|
||||
|
||||
if [ "$wait" = "1" ]; then
|
||||
if [ -n "$cmd_id" ]; then
|
||||
wait_for_completion "$cmd_id" "${timeout:-180}" "0" # Don't show headers
|
||||
else
|
||||
output_json "{\"error\":\"Failed to get command ID from response\",\"response\":\"$response\"}" "0"
|
||||
fi
|
||||
else
|
||||
output_json "$response" "0" # Don't show headers
|
||||
fi
|
||||
else
|
||||
output_json "{\"error\":\"Invalid AT command format\"}" "0"
|
||||
fi
|
||||
else
|
||||
output_json "{\"error\":\"No command or command_id specified\"}" "0"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# CLI processing
|
||||
wait_mode=0
|
||||
timeout=180
|
||||
|
||||
while getopts "wt:h" opt; do
|
||||
case $opt in
|
||||
w) wait_mode=1 ;;
|
||||
t) timeout="$OPTARG" ;;
|
||||
h) usage ;;
|
||||
?) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
# Combine remaining arguments into AT command
|
||||
command="$*"
|
||||
|
||||
# Validate AT command format
|
||||
if ! echo "$command" | grep -qi "^AT"; then
|
||||
echo "Error: Command must start with 'AT'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Submit command and get response
|
||||
response=$(submit_command "$command")
|
||||
cmd_id=$(get_command_id "$response")
|
||||
|
||||
if [ -z "$cmd_id" ]; then
|
||||
echo "Error: Failed to get command ID"
|
||||
echo "Response: $response"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $wait_mode -eq 1 ]; then
|
||||
wait_for_completion "$cmd_id" "$timeout"
|
||||
else
|
||||
echo "$response"
|
||||
fi
|
||||
@@ -0,0 +1,195 @@
|
||||
#!/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"
|
||||
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager"
|
||||
LOCK_ID="FETCH_DATA_$(date +%s)_$$"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
|
||||
# Logging function (minimized)
|
||||
log_message() {
|
||||
# Only log errors and critical info
|
||||
if [ "$1" = "error" ] || [ "$1" = "crit" ]; then
|
||||
logger -t at_queue -p "daemon.$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
# 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 (avoid CGI overhead)
|
||||
acquire_token() {
|
||||
local priority="${1:-10}"
|
||||
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
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Try again
|
||||
sleep 0.1
|
||||
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
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Release token directly
|
||||
release_token() {
|
||||
# Only remove if it's our 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
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Direct AT command execution with minimal overhead
|
||||
execute_at_command() {
|
||||
local CMD="$1"
|
||||
sms_tool at "$CMD" -t 3 2>/dev/null
|
||||
}
|
||||
|
||||
# Batch process all commands with a single token
|
||||
process_all_commands() {
|
||||
local commands="$1"
|
||||
local priority="${2:-10}"
|
||||
local first=1
|
||||
|
||||
# Acquire a single token for all commands
|
||||
if ! acquire_token "$priority"; then
|
||||
log_message "error" "Failed to acquire token for batch processing"
|
||||
# Return all failed responses
|
||||
printf '['
|
||||
first=1
|
||||
for cmd in $commands; do
|
||||
[ $first -eq 0 ] && printf ','
|
||||
first=0
|
||||
ESCAPED_CMD=$(escape_json "$cmd")
|
||||
printf '{"command":"%s","response":"Failed to acquire token","status":"error"}' "${ESCAPED_CMD}"
|
||||
done
|
||||
printf ']\n'
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Process all commands with the single token
|
||||
printf '['
|
||||
for cmd in $commands; do
|
||||
[ $first -eq 0 ] && printf ','
|
||||
first=0
|
||||
|
||||
OUTPUT=$(execute_at_command "$cmd")
|
||||
local CMD_STATUS=$?
|
||||
|
||||
ESCAPED_CMD=$(escape_json "$cmd")
|
||||
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
|
||||
|
||||
if [ $CMD_STATUS -eq 0 ] && [ -n "$OUTPUT" ]; then
|
||||
printf '{"command":"%s","response":"%s","status":"success"}' \
|
||||
"${ESCAPED_CMD}" \
|
||||
"${ESCAPED_OUTPUT}"
|
||||
else
|
||||
printf '{"command":"%s","response":"Command failed","status":"error"}' \
|
||||
"${ESCAPED_CMD}"
|
||||
fi
|
||||
done
|
||||
printf ']\n'
|
||||
|
||||
# Release token after all commands are done
|
||||
release_token
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main execution with timeout and proper cleanup
|
||||
trap 'release_token; exit 1' INT TERM
|
||||
|
||||
# Command sets
|
||||
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 AT+QCAINFO AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
|
||||
COMMAND_SET_2='AT+CGDCONT? AT+CGCONTRDP AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QUIMSLOT? AT+CFUN=?'
|
||||
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"'
|
||||
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 AT+QNETRC?'
|
||||
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"'
|
||||
|
||||
# Get command set from query string with validation
|
||||
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[1-8]' | cut -d'=' -f2 | tr -cd '0-9')
|
||||
if [ -z "$COMMAND_SET" ] || [ "$COMMAND_SET" -lt 1 ] || [ "$COMMAND_SET" -gt 8 ]; then
|
||||
COMMAND_SET=1
|
||||
fi
|
||||
|
||||
# Select the 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";;
|
||||
esac
|
||||
|
||||
# Set priority based on content
|
||||
PRIORITY=10
|
||||
if echo "$COMMANDS" | grep -qi "AT+QSCAN"; then
|
||||
PRIORITY=1
|
||||
fi
|
||||
|
||||
# Process commands with timeout protection
|
||||
( sleep 60; kill -TERM $$ 2>/dev/null ) &
|
||||
TIMEOUT_PID=$!
|
||||
|
||||
process_all_commands "$COMMANDS" "$PRIORITY"
|
||||
|
||||
# Clean up
|
||||
kill $TIMEOUT_PID 2>/dev/null
|
||||
release_token
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set Content-Type for CGI script
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Read POST data
|
||||
read -r POST_DATA
|
||||
|
||||
# Debug log for generated hash
|
||||
DEBUG_LOG="/tmp/auth.log"
|
||||
|
||||
# Extract the password from POST data (URL encoded)
|
||||
USER="root"
|
||||
INPUT_PASSWORD=$(echo "$POST_DATA" | grep -o 'password=[^&]*' | cut -d= -f2-)
|
||||
|
||||
# URL-decode the password while preserving most special characters
|
||||
# First decode percent-encoded sequences
|
||||
urldecode() {
|
||||
local encoded="${1//+/ }"
|
||||
printf '%b' "${encoded//%/\\x}"
|
||||
}
|
||||
|
||||
# Decode the password
|
||||
INPUT_PASSWORD=$(urldecode "$INPUT_PASSWORD")
|
||||
|
||||
# Basic validation to reject & and $ characters
|
||||
if echo "$INPUT_PASSWORD" | grep -q '[&$]'; then
|
||||
echo '{"state":"failed", "message":"Password contains forbidden characters (& or $)"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Sanitize the password for shell usage
|
||||
INPUT_PASSWORD=$(printf '%s' "$INPUT_PASSWORD" | sed 's/[\"]/\\&/g')
|
||||
|
||||
# Extract the hashed password from /etc/shadow for the specified user
|
||||
USER_SHADOW_ENTRY=$(grep "^$USER:" /etc/shadow)
|
||||
|
||||
if [ -z "$USER_SHADOW_ENTRY" ]; then
|
||||
echo '{"state":"failed", "message":"User not found"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the password hash (it's the second field, colon-separated)
|
||||
USER_HASH=$(echo "$USER_SHADOW_ENTRY" | cut -d: -f2)
|
||||
|
||||
# Extract the salt (MD5 uses the $1$ prefix followed by the salt)
|
||||
SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
|
||||
|
||||
# Generate a hash from the input password using the same salt
|
||||
# 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"
|
||||
|
||||
# Compare the generated hash with the one in the shadow file
|
||||
if [ "$GENERATED_HASH" = "$USER_HASH" ]; then
|
||||
echo '{"state":"success"}'
|
||||
else
|
||||
echo '{"state":"failed", "message":"Authentication failed"}'
|
||||
fi
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/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 cell_lock "$1" "$2"
|
||||
echo "${value:-$2}"
|
||||
}
|
||||
|
||||
# Function to check if daemon is running
|
||||
check_service_status() {
|
||||
if [ -f "/var/run/cell_lock_scheduler.pid" ]; then
|
||||
pid=$(cat /var/run/cell_lock_scheduler.pid 2>/dev/null)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
echo "stopped"
|
||||
}
|
||||
|
||||
# Function to get current status with proper JSON handling
|
||||
get_current_status() {
|
||||
local STATUS_FILE="/tmp/cell_lock_status.json"
|
||||
local status="unknown"
|
||||
local message="Status not available"
|
||||
local active="0"
|
||||
local locked="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)
|
||||
# Extract message and remove any surrounding quotes
|
||||
message=$(cat "$STATUS_FILE" | jsonfilter -e '@.message' 2>/dev/null | sed 's/^"//;s/"$//')
|
||||
active=$(cat "$STATUS_FILE" | jsonfilter -e '@.active' 2>/dev/null)
|
||||
locked=$(cat "$STATUS_FILE" | jsonfilter -e '@.locked' 2>/dev/null)
|
||||
timestamp=$(cat "$STATUS_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
# Escape quotes and special characters in message
|
||||
message=$(echo "$message" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
||||
|
||||
# Return the status as a JSON object with properly quoted message
|
||||
echo "{\"status\":\"$status\",\"message\":\"$message\",\"active\":$active,\"locked\":$locked,\"timestamp\":$timestamp}"
|
||||
}
|
||||
|
||||
# Load configuration
|
||||
config_load quecmanager
|
||||
|
||||
# Check if cell lock section exists
|
||||
if ! uci -q get quecmanager.cell_lock >/dev/null; then
|
||||
echo '{"status":"inactive","message":"Cell lock is not configured","enabled":false,"startTime":"","endTime":"","active":false,"locked":false}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get service status
|
||||
service_status=$(check_service_status)
|
||||
|
||||
# Get current status
|
||||
current_status=$(get_current_status)
|
||||
|
||||
# Get configuration values
|
||||
enabled=$(get_uci_value "enabled" "0")
|
||||
start_time=$(get_uci_value "start_time" "")
|
||||
end_time=$(get_uci_value "end_time" "")
|
||||
active=$(get_uci_value "active" "0")
|
||||
lte_params=$(get_uci_value "lte_params" "")
|
||||
nr5g_params=$(get_uci_value "nr5g_params" "")
|
||||
lte_persist=$(get_uci_value "lte_persist" "0")
|
||||
nr5g_persist=$(get_uci_value "nr5g_persist" "0")
|
||||
|
||||
# Convert numeric values to boolean for JSON
|
||||
enabled_bool="false"
|
||||
active_bool="false"
|
||||
locked_bool="false"
|
||||
|
||||
[ "$enabled" = "1" ] && enabled_bool="true"
|
||||
[ "$active" = "1" ] && active_bool="true"
|
||||
|
||||
# Get locked status from current_status
|
||||
locked=$(echo "$current_status" | jsonfilter -e '@.locked' 2>/dev/null)
|
||||
[ "$locked" = "1" ] && locked_bool="true"
|
||||
|
||||
# Extract the message properly from current status
|
||||
message_value=$(echo "$current_status" | jsonfilter -e '@.message' 2>/dev/null | sed 's/^"//;s/"$//')
|
||||
|
||||
# Prepare JSON response in format expected by the component
|
||||
cat <<EOF
|
||||
{
|
||||
"enabled": $enabled_bool,
|
||||
"start_time": "$start_time",
|
||||
"end_time": "$end_time",
|
||||
"active": $active_bool,
|
||||
"status": "$(echo "$current_status" | jsonfilter -e '@.status')",
|
||||
"message": "$message_value",
|
||||
"locked": $locked_bool,
|
||||
"serviceStatus": "$service_status",
|
||||
"lteParams": "$lte_params",
|
||||
"nr5gParams": "$nr5g_params",
|
||||
"ltePersist": "$lte_persist",
|
||||
"nr5gPersist": "$nr5g_persist"
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,205 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
UCI_CONFIG="quecmanager"
|
||||
STATUS_FILE="/tmp/cell_lock_status.json"
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOG_DIR="/tmp/log/cell_lock"
|
||||
LOG_FILE="$LOG_DIR/cell_lock.log"
|
||||
DEBUG_FILE="$LOG_DIR/debug.log"
|
||||
|
||||
# Ensure log directory exists
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
local message="$1"
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Log to file
|
||||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||||
|
||||
# Debug logging
|
||||
echo "[$timestamp] [$level] $message" >> "$DEBUG_FILE"
|
||||
|
||||
# Log to system log
|
||||
logger -t cell_lock -p "daemon.$level" "$message"
|
||||
}
|
||||
|
||||
# Log request details for debugging
|
||||
log_request_info() {
|
||||
echo "==== NEW REQUEST ====" >> "$DEBUG_FILE"
|
||||
echo "METHOD: $REQUEST_METHOD" >> "$DEBUG_FILE"
|
||||
echo "QUERY_STRING: $QUERY_STRING" >> "$DEBUG_FILE"
|
||||
echo "CONTENT_LENGTH: $CONTENT_LENGTH" >> "$DEBUG_FILE"
|
||||
echo "CONTENT_TYPE: $CONTENT_TYPE" >> "$DEBUG_FILE"
|
||||
}
|
||||
|
||||
# Function to validate time format (HH:MM)
|
||||
validate_time_format() {
|
||||
local time="$1"
|
||||
local name="$2"
|
||||
|
||||
if ! echo "$time" | grep -q '^[0-2][0-9]:[0-5][0-9]$'; then
|
||||
echo "{\"status\":\"error\",\"message\":\"$name must be in format HH:MM (24-hour)\"}"
|
||||
log_message "$name has invalid format: $time" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Further validate hour (00-23)
|
||||
local hour=$(echo "$time" | cut -d':' -f1)
|
||||
if [ "$hour" -gt 23 ]; then
|
||||
echo "{\"status\":\"error\",\"message\":\"Hour in $name must be between 00-23\"}"
|
||||
log_message "$name has invalid hour: $hour" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Log request info for debugging
|
||||
log_request_info
|
||||
|
||||
# Handle GET requests for status
|
||||
if [ "$REQUEST_METHOD" = "GET" ]; then
|
||||
log_message "Handling GET request" "debug"
|
||||
|
||||
# Load UCI configuration
|
||||
if [ -f "/etc/config/quecmanager" ]; then
|
||||
ENABLED=$(uci -q get "$UCI_CONFIG.cell_lock.enabled" || echo "0")
|
||||
START_TIME=$(uci -q get "$UCI_CONFIG.cell_lock.start_time" || echo "")
|
||||
END_TIME=$(uci -q get "$UCI_CONFIG.cell_lock.end_time" || echo "")
|
||||
ACTIVE=$(uci -q get "$UCI_CONFIG.cell_lock.active" || echo "0")
|
||||
|
||||
# Convert to JSON boolean format
|
||||
[ "$ENABLED" = "1" ] && ENABLED="true" || ENABLED="false"
|
||||
[ "$ACTIVE" = "1" ] && ACTIVE="true" || ACTIVE="false"
|
||||
|
||||
# Get current status from status file
|
||||
STATUS="disabled"
|
||||
MESSAGE="\"Scheduler is disabled\""
|
||||
|
||||
if [ -f "$STATUS_FILE" ]; then
|
||||
STATUS=$(cat "$STATUS_FILE" | jsonfilter -e '@.status' 2>/dev/null)
|
||||
MESSAGE=$(cat "$STATUS_FILE" | jsonfilter -e '@.message' 2>/dev/null)
|
||||
if [ -n "$MESSAGE" ]; then
|
||||
MESSAGE="\"$MESSAGE\""
|
||||
else
|
||||
MESSAGE="\"Status not available\""
|
||||
fi
|
||||
fi
|
||||
|
||||
# Output JSON response
|
||||
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\",\"active\":$ACTIVE,\"status\":\"$STATUS\",\"message\":$MESSAGE}"
|
||||
log_message "Returned status response" "debug"
|
||||
else
|
||||
echo "{\"enabled\":false,\"start_time\":\"\",\"end_time\":\"\",\"active\":false,\"status\":\"unknown\",\"message\":\"Configuration not found\"}"
|
||||
log_message "No configuration found" "warn"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Handle POST requests for enabling/disabling scheduling
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
log_message "Handling POST request" "debug"
|
||||
|
||||
# Read POST data
|
||||
CONTENT_LENGTH=${CONTENT_LENGTH:-0}
|
||||
if [ $CONTENT_LENGTH -gt 0 ]; then
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
echo "POST_DATA: $POST_DATA" >> "$DEBUG_FILE"
|
||||
else
|
||||
POST_DATA=""
|
||||
echo "No POST_DATA (empty)" >> "$DEBUG_FILE"
|
||||
fi
|
||||
|
||||
# Try to parse JSON data
|
||||
if [ -n "$POST_DATA" ] && command -v jsonfilter >/dev/null 2>&1; then
|
||||
log_message "Attempting to parse JSON data" "debug"
|
||||
|
||||
# Try to extract values from JSON - allow for differently named fields
|
||||
ENABLED=$(echo "$POST_DATA" | jsonfilter -e '@.enabled' 2>/dev/null)
|
||||
if [ -z "$ENABLED" ]; then
|
||||
ENABLED=$(echo "$POST_DATA" | jsonfilter -e '@.enable' 2>/dev/null)
|
||||
fi
|
||||
|
||||
START_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.startTime' 2>/dev/null)
|
||||
if [ -z "$START_TIME" ]; then
|
||||
START_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.start_time' 2>/dev/null)
|
||||
fi
|
||||
|
||||
END_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.endTime' 2>/dev/null)
|
||||
if [ -z "$END_TIME" ]; then
|
||||
END_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.end_time' 2>/dev/null)
|
||||
fi
|
||||
|
||||
echo "Parsed JSON: enabled=$ENABLED, start=$START_TIME, end=$END_TIME" >> "$DEBUG_FILE"
|
||||
|
||||
# Handle enable/disable logic
|
||||
if [ "$ENABLED" = "true" ] || [ "$ENABLED" = "1" ]; then
|
||||
# Validate times for enable request
|
||||
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ]; then
|
||||
echo "{\"status\":\"error\",\"message\":\"Start time and end time are required\"}"
|
||||
log_message "Missing start or end time" "error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate time formats
|
||||
validate_time_format "$START_TIME" "Start time" || exit 1
|
||||
validate_time_format "$END_TIME" "End time" || exit 1
|
||||
|
||||
# Update configuration
|
||||
log_message "Enabling scheduling with start=$START_TIME, end=$END_TIME" "info"
|
||||
uci -q set "$UCI_CONFIG.cell_lock=scheduler"
|
||||
uci set "$UCI_CONFIG.cell_lock.enabled=1"
|
||||
uci set "$UCI_CONFIG.cell_lock.start_time=$START_TIME"
|
||||
uci set "$UCI_CONFIG.cell_lock.end_time=$END_TIME"
|
||||
uci commit "$UCI_CONFIG"
|
||||
|
||||
# Ensure service is running
|
||||
if [ -x "/etc/init.d/quecmanager_cell_locking" ]; then
|
||||
/etc/init.d/quecmanager_cell_locking enable
|
||||
/etc/init.d/quecmanager_cell_locking restart
|
||||
log_message "Started scheduler service" "info"
|
||||
else
|
||||
log_message "Service script not found" "error"
|
||||
echo "{\"status\":\"error\",\"message\":\"Service script not found\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "{\"status\":\"success\",\"message\":\"Scheduling enabled\",\"startTime\":\"$START_TIME\",\"endTime\":\"$END_TIME\"}"
|
||||
log_message "Successfully enabled scheduling" "info"
|
||||
else
|
||||
# Disable scheduling
|
||||
log_message "Disabling scheduling" "info"
|
||||
uci -q set "$UCI_CONFIG.cell_lock=scheduler"
|
||||
uci set "$UCI_CONFIG.cell_lock.enabled=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
|
||||
# Stop service
|
||||
if [ -x "/etc/init.d/quecmanager_cell_locking" ]; then
|
||||
/etc/init.d/quecmanager_cell_locking stop
|
||||
/etc/init.d/quecmanager_cell_locking disable
|
||||
log_message "Stopped scheduler service" "info"
|
||||
fi
|
||||
|
||||
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
|
||||
log_message "Successfully disabled scheduling" "info"
|
||||
fi
|
||||
else
|
||||
log_message "Failed to parse JSON data or no JSON data received" "error"
|
||||
echo "{\"status\":\"error\",\"message\":\"Invalid request or missing JSON data\"}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If no valid method was handled
|
||||
echo "{\"status\":\"error\",\"message\":\"Invalid request method\"}"
|
||||
log_message "Invalid request method: $REQUEST_METHOD" "error"
|
||||
exit 1
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Initialize error tracking
|
||||
has_error=false
|
||||
error_message=""
|
||||
|
||||
# Function to append to error message
|
||||
append_error() {
|
||||
if [ -z "$error_message" ]; then
|
||||
error_message="$1"
|
||||
else
|
||||
error_message="$error_message; $1"
|
||||
fi
|
||||
has_error=true
|
||||
}
|
||||
|
||||
# Function to log cleanup events
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/apnprofile"
|
||||
local LOG_FILE="${LOG_DIR}/apnprofile.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 apnprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
log_message "INFO" "Starting APN Profile cleanup process"
|
||||
|
||||
# Stop and disable the service
|
||||
if [ -f "/etc/init.d/apnprofile-service" ]; then
|
||||
if /etc/init.d/apnprofile-service stop; then
|
||||
log_message "INFO" "APN Profile service stopped"
|
||||
else
|
||||
append_error "Failed to stop APN Profile service"
|
||||
log_message "ERROR" "Failed to stop APN Profile service"
|
||||
fi
|
||||
|
||||
if /etc/init.d/apnprofile-service disable; then
|
||||
log_message "INFO" "APN Profile service disabled"
|
||||
else
|
||||
append_error "Failed to disable APN Profile service"
|
||||
log_message "ERROR" "Failed to disable APN Profile service"
|
||||
fi
|
||||
|
||||
# Remove the init.d script
|
||||
if rm -f "/etc/init.d/apnprofile-service"; then
|
||||
log_message "INFO" "Removed init.d script"
|
||||
else
|
||||
append_error "Failed to remove init.d script"
|
||||
log_message "ERROR" "Failed to remove init.d script"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove service script
|
||||
if [ -f "/www/cgi-bin/services/apnprofile.sh" ]; then
|
||||
if rm -f "/www/cgi-bin/services/apnprofile.sh"; then
|
||||
log_message "INFO" "Removed service script"
|
||||
else
|
||||
append_error "Failed to remove service script"
|
||||
log_message "ERROR" "Failed to remove service script"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove symlinks in rc.d if they exist
|
||||
for link in /etc/rc.d/S??apnprofile-service /etc/rc.d/K??apnprofile-service; do
|
||||
if [ -L "$link" ]; then
|
||||
if rm -f "$link"; then
|
||||
log_message "INFO" "Removed rc.d symlink: $link"
|
||||
else
|
||||
append_error "Failed to remove rc.d symlink: $link"
|
||||
log_message "ERROR" "Failed to remove rc.d symlink: $link"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove UCI configuration (only removes apn_profile section, leaves other sections intact)
|
||||
if uci -q get quecmanager.apn_profile >/dev/null; then
|
||||
if uci delete quecmanager.apn_profile && uci commit quecmanager; then
|
||||
log_message "INFO" "Removed UCI configuration"
|
||||
else
|
||||
append_error "Failed to remove UCI configuration"
|
||||
log_message "ERROR" "Failed to remove UCI configuration"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Kill any remaining processes
|
||||
if pkill -f "/www/cgi-bin/services/apnprofile.sh"; then
|
||||
log_message "INFO" "Killed remaining APN Profile processes"
|
||||
fi
|
||||
|
||||
# Clean up temporary files
|
||||
for file in \
|
||||
"/tmp/at_pipe.txt" \
|
||||
"/var/run/apnprofile.pid" \
|
||||
"/tmp/apn_result.txt" \
|
||||
"/tmp/debug.log" \
|
||||
"/tmp/inputICCID.txt" \
|
||||
"/tmp/outputICCID.txt" \
|
||||
"/tmp/inputAPN.txt" \
|
||||
"/tmp/outputAPN.txt"
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
if rm -f "$file"; then
|
||||
log_message "INFO" "Removed temporary file: $file"
|
||||
else
|
||||
append_error "Failed to remove temporary file: $file"
|
||||
log_message "ERROR" "Failed to remove temporary file: $file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
log_message "INFO" "APN Profile cleanup completed"
|
||||
|
||||
# Return appropriate JSON response
|
||||
if [ "$has_error" = true ]; then
|
||||
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
|
||||
else
|
||||
echo "{\"status\": \"success\", \"message\": \"APN Profile service successfully removed\"}"
|
||||
fi
|
||||
@@ -0,0 +1,144 @@
|
||||
#!/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 apn_profile "$1" "$2"
|
||||
echo "${value:-$2}"
|
||||
}
|
||||
|
||||
# Function to check if service is running
|
||||
check_service_status() {
|
||||
if [ -f "/var/run/apnprofile.pid" ]; then
|
||||
pid=$(cat /var/run/apnprofile.pid)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Double check using process search
|
||||
if pgrep -f "/www/cgi-bin/services/apnprofile.sh" >/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "stopped"
|
||||
}
|
||||
|
||||
# Function to get last log entry
|
||||
get_last_log() {
|
||||
local LOG_FILE="/tmp/log/apnprofile/apnprofile.log"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -n 1 "$LOG_FILE"
|
||||
else
|
||||
echo "No log entries found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if init.d service is enabled
|
||||
check_service_enabled() {
|
||||
if [ -f "/etc/init.d/apnprofile-service" ]; then
|
||||
if /etc/init.d/apnprofile-service enabled; then
|
||||
echo "true"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
echo "false"
|
||||
}
|
||||
|
||||
# Load QuecManager configuration
|
||||
config_load quecmanager
|
||||
|
||||
# Check if APN Profile section exists
|
||||
if ! uci -q get quecmanager.apn_profile >/dev/null; then
|
||||
echo '{"status": "inactive", "message": "APN Profile service is not configured"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get enabled status from UCI
|
||||
enabled=$(get_uci_value "enabled" "0")
|
||||
|
||||
if [ "$enabled" != "1" ]; then
|
||||
echo '{"status": "inactive", "message": "APN Profile service is disabled"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if service script exists
|
||||
if [ ! -f "/www/cgi-bin/services/apnprofile.sh" ]; then
|
||||
echo '{"status": "error", "message": "Service script is missing"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get service status information
|
||||
service_status=$(check_service_status)
|
||||
service_enabled=$(check_service_enabled)
|
||||
last_log=$(get_last_log)
|
||||
|
||||
# Fetch all configuration values from UCI
|
||||
iccid_profile1=$(get_uci_value "iccid_profile1" "")
|
||||
apn_profile1=$(get_uci_value "apn_profile1" "")
|
||||
pdp_type1=$(get_uci_value "pdp_type1" "")
|
||||
iccid_profile2=$(get_uci_value "iccid_profile2" "")
|
||||
apn_profile2=$(get_uci_value "apn_profile2" "")
|
||||
pdp_type2=$(get_uci_value "pdp_type2" "")
|
||||
|
||||
# Function to check if profile data exists
|
||||
validate_profile_data() {
|
||||
local iccid="$1"
|
||||
local apn="$2"
|
||||
local pdp="$3"
|
||||
|
||||
[ -n "$iccid" ] && [ -n "$apn" ] && [ -n "$pdp" ]
|
||||
}
|
||||
|
||||
# Build JSON response
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "active",
|
||||
"service": {
|
||||
"status": "${service_status}",
|
||||
"enabled": ${service_enabled},
|
||||
"script": "$([ -f "/www/cgi-bin/services/apnprofile.sh" ] && echo "present" || echo "missing")",
|
||||
"initScript": "$([ -f "/etc/init.d/apnprofile-service" ] && echo "present" || echo "missing")"
|
||||
},
|
||||
"profiles": {
|
||||
EOF
|
||||
|
||||
# Add Profile 1 if it exists
|
||||
if validate_profile_data "$iccid_profile1" "$apn_profile1" "$pdp_type1"; then
|
||||
cat <<EOF
|
||||
"profile1": {
|
||||
"iccid": "${iccid_profile1}",
|
||||
"apn": "${apn_profile1}",
|
||||
"pdpType": "${pdp_type1}"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Add Profile 2 if it exists
|
||||
if validate_profile_data "$iccid_profile2" "$apn_profile2" "$pdp_type2"; then
|
||||
# Add comma if Profile 1 was added
|
||||
[ -n "$iccid_profile1" ] && echo ","
|
||||
cat <<EOF
|
||||
"profile2": {
|
||||
"iccid": "${iccid_profile2}",
|
||||
"apn": "${apn_profile2}",
|
||||
"pdpType": "${pdp_type2}"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Close the profiles object and add last activity
|
||||
cat <<EOF
|
||||
},
|
||||
"lastActivity": "${last_log}"
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,345 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Read POST data
|
||||
read -r QUERY_STRING
|
||||
|
||||
# Function to urldecode
|
||||
urldecode() {
|
||||
local value="$1"
|
||||
value="${value//+/ }"
|
||||
value="${value//%/\\x}"
|
||||
printf '%b' "$value"
|
||||
}
|
||||
|
||||
# Extract values from POST data
|
||||
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
apnProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile1=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
pdpType1=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType1=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
apnProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile2=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
pdpType2=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType2=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
|
||||
# URL decode the values
|
||||
iccidProfile1=$(urldecode "$iccidProfile1")
|
||||
apnProfile1=$(urldecode "$apnProfile1")
|
||||
pdpType1=$(urldecode "$pdpType1")
|
||||
iccidProfile2=$(urldecode "$iccidProfile2")
|
||||
apnProfile2=$(urldecode "$apnProfile2")
|
||||
pdpType2=$(urldecode "$pdpType2")
|
||||
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Validate required first profile
|
||||
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
|
||||
echo '{"status": "error", "message": "Profile 1 is required"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/apnprofile"
|
||||
local LOG_FILE="${LOG_DIR}/apnprofile.log"
|
||||
|
||||
mkdir -p "${LOG_DIR}"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t apnprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
# Create required directories
|
||||
mkdir -p /www/cgi-bin/services
|
||||
mkdir -p /etc/init.d
|
||||
|
||||
# Function to create service script
|
||||
create_service_script() {
|
||||
cat > /www/cgi-bin/services/apnprofile.sh <<'EOL'
|
||||
#!/bin/sh
|
||||
|
||||
# Load UCI functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Define file paths
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
LOG_DIR="/tmp/log/apnprofile"
|
||||
LOG_FILE="${LOG_DIR}/apnprofile.log"
|
||||
PID_FILE="/var/run/apnprofile.pid"
|
||||
STATE_FILE="/tmp/apnprofile_state.json"
|
||||
|
||||
mkdir -p "${LOG_DIR}"
|
||||
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
|
||||
|
||||
# Save PID
|
||||
echo $$ > "${PID_FILE}"
|
||||
|
||||
# Enhanced logging function
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t apnprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
# AT command handling with locking
|
||||
handle_lock() {
|
||||
local max_wait=30
|
||||
local wait_count=0
|
||||
|
||||
while [ -f "$QUEUE_FILE" ] && grep -q "AT_COMMAND" "$QUEUE_FILE" && [ $wait_count -lt $max_wait ]; do
|
||||
sleep 1
|
||||
wait_count=$((wait_count + 1))
|
||||
done
|
||||
|
||||
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' "$$" "$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
|
||||
}
|
||||
|
||||
# Execute AT command with retries
|
||||
execute_at_command() {
|
||||
local command="$1"
|
||||
local result=""
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
handle_lock
|
||||
result=$(sms_tool at "$command" -t 4 2>&1)
|
||||
local status=$?
|
||||
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
|
||||
|
||||
if [ $status -eq 0 ] && [ -n "$result" ]; then
|
||||
echo "$result"
|
||||
return 0
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
[ $retry_count -lt $max_retries ] && sleep 2
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get current ICCID
|
||||
get_current_iccid() {
|
||||
local result=$(execute_at_command "AT+ICCID")
|
||||
if [ $? -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
|
||||
echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]'
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Set APN with error handling
|
||||
set_apn() {
|
||||
local pdp_type="$1"
|
||||
local apn="$2"
|
||||
|
||||
if [ -z "$pdp_type" ] || [ -z "$apn" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if execute_at_command "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to get current configuration hash
|
||||
get_config_hash() {
|
||||
config_load quecmanager
|
||||
local hash_input=""
|
||||
|
||||
# Get Profile 1
|
||||
config_get ICCID_PROFILE1 apn_profile iccid_profile1
|
||||
config_get APN_PROFILE1 apn_profile apn_profile1
|
||||
config_get PDP_TYPE1 apn_profile pdp_type1
|
||||
|
||||
# Get Profile 2
|
||||
config_get ICCID_PROFILE2 apn_profile iccid_profile2
|
||||
config_get APN_PROFILE2 apn_profile apn_profile2
|
||||
config_get PDP_TYPE2 apn_profile pdp_type2
|
||||
|
||||
hash_input="${ICCID_PROFILE1}${APN_PROFILE1}${PDP_TYPE1}${ICCID_PROFILE2}${APN_PROFILE2}${PDP_TYPE2}"
|
||||
echo "$hash_input" | md5sum | cut -d' ' -f1
|
||||
}
|
||||
|
||||
# Function to read state file
|
||||
read_state() {
|
||||
if [ -f "$STATE_FILE" ]; then
|
||||
cat "$STATE_FILE"
|
||||
else
|
||||
echo "{}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to write state file
|
||||
write_state() {
|
||||
local current_iccid="$1"
|
||||
local config_hash="$2"
|
||||
local status="$3"
|
||||
|
||||
printf '{"iccid":"%s","config_hash":"%s","status":"%s","timestamp":"%s"}' \
|
||||
"$current_iccid" "$config_hash" "$status" "$(date '+%Y-%m-%d %H:%M:%S')" > "$STATE_FILE"
|
||||
}
|
||||
|
||||
# Main service loop
|
||||
while true; do
|
||||
# Get current state
|
||||
current_state=$(read_state)
|
||||
current_iccid=$(get_current_iccid)
|
||||
config_hash=$(get_config_hash)
|
||||
|
||||
# Extract values from current state
|
||||
state_iccid=$(echo "$current_state" | sed -n 's/.*"iccid":"\([^"]*\)".*/\1/p')
|
||||
state_hash=$(echo "$current_state" | sed -n 's/.*"config_hash":"\([^"]*\)".*/\1/p')
|
||||
|
||||
needs_update=0
|
||||
|
||||
# Check if update is needed
|
||||
if [ ! -f "$STATE_FILE" ]; then
|
||||
log_message "INFO" "No state file found, will apply profile"
|
||||
needs_update=1
|
||||
elif [ "$current_iccid" != "$state_iccid" ]; then
|
||||
log_message "INFO" "ICCID changed from $state_iccid to $current_iccid"
|
||||
needs_update=1
|
||||
elif [ "$config_hash" != "$state_hash" ]; then
|
||||
log_message "INFO" "Configuration changed"
|
||||
needs_update=1
|
||||
fi
|
||||
|
||||
if [ $needs_update -eq 1 ] && [ -n "$current_iccid" ]; then
|
||||
config_load quecmanager
|
||||
|
||||
# Get Profile 1
|
||||
config_get ICCID_PROFILE1 apn_profile iccid_profile1
|
||||
config_get APN_PROFILE1 apn_profile apn_profile1
|
||||
config_get PDP_TYPE1 apn_profile pdp_type1
|
||||
|
||||
# Get Profile 2
|
||||
config_get ICCID_PROFILE2 apn_profile iccid_profile2
|
||||
config_get APN_PROFILE2 apn_profile apn_profile2
|
||||
config_get PDP_TYPE2 apn_profile pdp_type2
|
||||
|
||||
if [ "${current_iccid}" = "${ICCID_PROFILE1}" ]; then
|
||||
if set_apn "$PDP_TYPE1" "$APN_PROFILE1"; then
|
||||
log_message "INFO" "Successfully applied Profile 1"
|
||||
write_state "$current_iccid" "$config_hash" "success"
|
||||
else
|
||||
log_message "ERROR" "Failed to apply Profile 1"
|
||||
write_state "$current_iccid" "$config_hash" "error"
|
||||
fi
|
||||
elif [ -n "$ICCID_PROFILE2" ] && [ "${current_iccid}" = "${ICCID_PROFILE2}" ]; then
|
||||
if set_apn "$PDP_TYPE2" "$APN_PROFILE2"; then
|
||||
log_message "INFO" "Successfully applied Profile 2"
|
||||
write_state "$current_iccid" "$config_hash" "success"
|
||||
else
|
||||
log_message "ERROR" "Failed to apply Profile 2"
|
||||
write_state "$current_iccid" "$config_hash" "error"
|
||||
fi
|
||||
else
|
||||
log_message "INFO" "No matching ICCID profile found"
|
||||
write_state "$current_iccid" "$config_hash" "no_match"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 10
|
||||
done
|
||||
EOL
|
||||
|
||||
chmod 755 /www/cgi-bin/services/apnprofile.sh
|
||||
}
|
||||
|
||||
# Function to create init.d script
|
||||
create_init_script() {
|
||||
cat > /etc/init.d/apnprofile-service <<'EOL'
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
start_service() {
|
||||
local enabled
|
||||
|
||||
# Check if service is enabled in UCI
|
||||
config_load quecmanager
|
||||
config_get enabled apn_profile enabled '0'
|
||||
|
||||
[ "$enabled" != "1" ] && return 0
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /www/cgi-bin/services/apnprofile.sh
|
||||
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param nice 19
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "quecmanager"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
EOL
|
||||
|
||||
chmod 755 /etc/init.d/apnprofile-service
|
||||
}
|
||||
|
||||
# Initialize UCI configuration
|
||||
touch /etc/config/quecmanager
|
||||
|
||||
# Remove existing APN profile section if it exists
|
||||
uci -q delete quecmanager.apn_profile
|
||||
|
||||
# Create new APN profile section
|
||||
uci set quecmanager.apn_profile=service
|
||||
uci set quecmanager.apn_profile.enabled=1
|
||||
|
||||
# Set Profile 1 configuration
|
||||
uci set quecmanager.apn_profile.iccid_profile1="$iccidProfile1"
|
||||
uci set quecmanager.apn_profile.apn_profile1="$apnProfile1"
|
||||
uci set quecmanager.apn_profile.pdp_type1="$pdpType1"
|
||||
|
||||
# Set Profile 2 configuration if provided
|
||||
if [ -n "$iccidProfile2" ]; then
|
||||
uci set quecmanager.apn_profile.iccid_profile2="$iccidProfile2"
|
||||
uci set quecmanager.apn_profile.apn_profile2="$apnProfile2"
|
||||
uci set quecmanager.apn_profile.pdp_type2="$pdpType2"
|
||||
fi
|
||||
|
||||
# Commit UCI changes
|
||||
if ! uci commit quecmanager; then
|
||||
log_message "ERROR" "Failed to save UCI configuration"
|
||||
echo '{"status": "error", "message": "Failed to save UCI configuration"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "INFO" "UCI configuration saved successfully"
|
||||
|
||||
# Create service script if it doesn't exist
|
||||
if [ ! -f "/www/cgi-bin/services/apnprofile.sh" ]; then
|
||||
create_service_script
|
||||
log_message "INFO" "Created service script"
|
||||
fi
|
||||
|
||||
# Create init.d script if it doesn't exist
|
||||
if [ ! -f "/etc/init.d/apnprofile-service" ]; then
|
||||
create_init_script
|
||||
log_message "INFO" "Created init.d script"
|
||||
fi
|
||||
|
||||
# Enable and start the service
|
||||
/etc/init.d/apnprofile-service enable
|
||||
if /etc/init.d/apnprofile-service restart; then
|
||||
log_message "INFO" "Service started successfully"
|
||||
echo '{"status": "success", "message": "APN profiles saved and service started"}'
|
||||
else
|
||||
log_message "ERROR" "Failed to start service"
|
||||
echo '{"status": "error", "message": "Failed to start service"}'
|
||||
fi
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Initialize error tracking
|
||||
has_error=false
|
||||
error_message=""
|
||||
|
||||
# Function to append to error message
|
||||
append_error() {
|
||||
if [ -z "$error_message" ]; then
|
||||
error_message="$1"
|
||||
else
|
||||
error_message="$error_message; $1"
|
||||
fi
|
||||
has_error=true
|
||||
}
|
||||
|
||||
# Function to log cleanup events
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/imeiprofile"
|
||||
local LOG_FILE="${LOG_DIR}/imeiprofile.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 imeiprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
log_message "INFO" "Starting IMEI Profile cleanup process"
|
||||
|
||||
# Stop and disable the service
|
||||
if [ -f "/etc/init.d/imeiprofile-service" ]; then
|
||||
if /etc/init.d/imeiprofile-service stop; then
|
||||
log_message "INFO" "IMEI Profile service stopped"
|
||||
else
|
||||
append_error "Failed to stop IMEI Profile service"
|
||||
log_message "ERROR" "Failed to stop IMEI Profile service"
|
||||
fi
|
||||
|
||||
if /etc/init.d/imeiprofile-service disable; then
|
||||
log_message "INFO" "IMEI Profile service disabled"
|
||||
else
|
||||
append_error "Failed to disable IMEI Profile service"
|
||||
log_message "ERROR" "Failed to disable IMEI Profile service"
|
||||
fi
|
||||
|
||||
# Remove the init.d script
|
||||
if rm -f "/etc/init.d/imeiprofile-service"; then
|
||||
log_message "INFO" "Removed init.d script"
|
||||
else
|
||||
append_error "Failed to remove init.d script"
|
||||
log_message "ERROR" "Failed to remove init.d script"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove service script
|
||||
if [ -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
|
||||
if rm -f "/www/cgi-bin/services/imeiprofile.sh"; then
|
||||
log_message "INFO" "Removed service script"
|
||||
else
|
||||
append_error "Failed to remove service script"
|
||||
log_message "ERROR" "Failed to remove service script"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove symlinks in rc.d if they exist
|
||||
for link in /etc/rc.d/S??imeiprofile-service /etc/rc.d/K??imeiprofile-service; do
|
||||
if [ -L "$link" ]; then
|
||||
if rm -f "$link"; then
|
||||
log_message "INFO" "Removed rc.d symlink: $link"
|
||||
else
|
||||
append_error "Failed to remove rc.d symlink: $link"
|
||||
log_message "ERROR" "Failed to remove rc.d symlink: $link"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove UCI configuration
|
||||
if uci -q get quecmanager.imei_profile >/dev/null; then
|
||||
if uci delete quecmanager.imei_profile && uci commit quecmanager; then
|
||||
log_message "INFO" "Removed UCI configuration"
|
||||
else
|
||||
append_error "Failed to remove UCI configuration"
|
||||
log_message "ERROR" "Failed to remove UCI configuration"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Kill any remaining processes
|
||||
if pkill -f "/www/cgi-bin/services/imeiprofile.sh"; then
|
||||
log_message "INFO" "Killed remaining IMEI Profile processes"
|
||||
fi
|
||||
|
||||
# Clean up temporary files
|
||||
for file in \
|
||||
"/tmp/at_pipe.txt" \
|
||||
"/var/run/imeiprofile.pid" \
|
||||
"/tmp/imei_result.txt" \
|
||||
"/tmp/debug.log" \
|
||||
"/tmp/inputICCID.txt" \
|
||||
"/tmp/outputICCID.txt" \
|
||||
"/tmp/inputIMEI.txt" \
|
||||
"/tmp/outputIMEI.txt"
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
if rm -f "$file"; then
|
||||
log_message "INFO" "Removed temporary file: $file"
|
||||
else
|
||||
append_error "Failed to remove temporary file: $file"
|
||||
log_message "ERROR" "Failed to remove temporary file: $file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
log_message "INFO" "IMEI Profile cleanup completed"
|
||||
|
||||
# Return appropriate JSON response
|
||||
if [ "$has_error" = true ]; then
|
||||
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
|
||||
else
|
||||
echo "{\"status\": \"success\", \"message\": \"IMEI Profile service successfully removed\"}"
|
||||
fi
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/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 imei_profile "$1" "$2"
|
||||
echo "${value:-$2}"
|
||||
}
|
||||
|
||||
# Function to check if service is running
|
||||
check_service_status() {
|
||||
if [ -f "/var/run/imeiprofile.pid" ]; then
|
||||
pid=$(cat /var/run/imeiprofile.pid)
|
||||
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Double check using process search
|
||||
if pgrep -f "/www/cgi-bin/services/imeiprofile.sh" >/dev/null; then
|
||||
echo "running"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "stopped"
|
||||
}
|
||||
|
||||
# Function to get last log entry
|
||||
get_last_log() {
|
||||
local LOG_FILE="/tmp/log/imeiprofile/imeiprofile.log"
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -n 1 "$LOG_FILE"
|
||||
else
|
||||
echo "No log entries found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if init.d service is enabled
|
||||
check_service_enabled() {
|
||||
if [ -f "/etc/init.d/imeiprofile-service" ]; then
|
||||
if /etc/init.d/imeiprofile-service enabled; then
|
||||
echo "true"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
echo "false"
|
||||
}
|
||||
|
||||
# Load QuecManager configuration
|
||||
config_load quecmanager
|
||||
|
||||
# Check if IMEI Profile section exists
|
||||
if ! uci -q get quecmanager.imei_profile >/dev/null; then
|
||||
echo '{"status": "inactive", "message": "IMEI Profile service is not configured"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get enabled status from UCI
|
||||
enabled=$(get_uci_value "enabled" "0")
|
||||
|
||||
if [ "$enabled" != "1" ]; then
|
||||
echo '{"status": "inactive", "message": "IMEI Profile service is disabled"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if service script exists
|
||||
if [ ! -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
|
||||
echo '{"status": "error", "message": "Service script is missing"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get service status information
|
||||
service_status=$(check_service_status)
|
||||
service_enabled=$(check_service_enabled)
|
||||
last_log=$(get_last_log)
|
||||
|
||||
# Fetch configuration values from UCI
|
||||
iccid_profile1=$(get_uci_value "iccid_profile1" "")
|
||||
imei_profile1=$(get_uci_value "imei_profile1" "")
|
||||
iccid_profile2=$(get_uci_value "iccid_profile2" "")
|
||||
imei_profile2=$(get_uci_value "imei_profile2" "")
|
||||
|
||||
# Function to check if profile data exists
|
||||
validate_profile_data() {
|
||||
local iccid="$1"
|
||||
local imei="$2"
|
||||
[ -n "$iccid" ] && [ -n "$imei" ]
|
||||
}
|
||||
|
||||
# Build JSON response
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "active",
|
||||
"service": {
|
||||
"status": "${service_status}",
|
||||
"enabled": ${service_enabled},
|
||||
"script": "$([ -f "/www/cgi-bin/services/imeiprofile.sh" ] && echo "present" || echo "missing")",
|
||||
"initScript": "$([ -f "/etc/init.d/imeiprofile-service" ] && echo "present" || echo "missing")"
|
||||
},
|
||||
"profiles": {
|
||||
EOF
|
||||
|
||||
# Add Profile 1 if it exists
|
||||
if validate_profile_data "$iccid_profile1" "$imei_profile1"; then
|
||||
cat <<EOF
|
||||
"profile1": {
|
||||
"iccid": "${iccid_profile1}",
|
||||
"imei": "${imei_profile1}"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Add Profile 2 if it exists
|
||||
if validate_profile_data "$iccid_profile2" "$imei_profile2"; then
|
||||
# Add comma if Profile 1 was added
|
||||
[ -n "$iccid_profile1" ] && echo ","
|
||||
cat <<EOF
|
||||
"profile2": {
|
||||
"iccid": "${iccid_profile2}",
|
||||
"imei": "${imei_profile2}"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Close the profiles object and add last activity
|
||||
cat <<EOF
|
||||
},
|
||||
"lastActivity": "${last_log}"
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,291 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Read POST data
|
||||
read -r QUERY_STRING
|
||||
|
||||
# Function to urldecode
|
||||
urldecode() {
|
||||
local value="$1"
|
||||
value="${value//+/ }"
|
||||
value="${value//%/\\x}"
|
||||
printf '%b' "$value"
|
||||
}
|
||||
|
||||
# Extract values from POST data
|
||||
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
imeiProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile1=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
imeiProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile2=\([^&]*\).*/\1/p' | tr -d "'")
|
||||
|
||||
# URL decode the values
|
||||
iccidProfile1=$(urldecode "$iccidProfile1")
|
||||
imeiProfile1=$(urldecode "$imeiProfile1")
|
||||
iccidProfile2=$(urldecode "$iccidProfile2")
|
||||
imeiProfile2=$(urldecode "$imeiProfile2")
|
||||
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Validate required first profile
|
||||
if [ -z "$iccidProfile1" ] || [ -z "$imeiProfile1" ]; then
|
||||
echo '{"status": "error", "message": "Profile 1 is required"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local LOG_DIR="/tmp/log/imeiprofile"
|
||||
local LOG_FILE="${LOG_DIR}/imeiprofile.log"
|
||||
|
||||
mkdir -p "${LOG_DIR}"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t imeiprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
# Create required directories
|
||||
mkdir -p /www/cgi-bin/services
|
||||
|
||||
# Function to create service script
|
||||
create_service_script() {
|
||||
cat > /www/cgi-bin/services/imeiprofile.sh <<'EOL'
|
||||
#!/bin/sh
|
||||
|
||||
# Load UCI functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Define file paths
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
LOG_DIR="/tmp/log/imeiprofile"
|
||||
LOG_FILE="${LOG_DIR}/imeiprofile.log"
|
||||
PID_FILE="/var/run/imeiprofile.pid"
|
||||
|
||||
mkdir -p "${LOG_DIR}"
|
||||
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
|
||||
|
||||
# Save PID
|
||||
echo $$ > "${PID_FILE}"
|
||||
|
||||
# Enhanced logging function
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t imeiprofile "${level}: ${message}"
|
||||
}
|
||||
|
||||
# AT command handling with locking
|
||||
handle_lock() {
|
||||
local max_wait=30
|
||||
local wait_count=0
|
||||
|
||||
while [ -f "$QUEUE_FILE" ] && grep -q "AT_COMMAND" "$QUEUE_FILE" && [ $wait_count -lt $max_wait ]; do
|
||||
sleep 1
|
||||
wait_count=$((wait_count + 1))
|
||||
done
|
||||
|
||||
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' "$$" "$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
|
||||
}
|
||||
|
||||
# Execute AT command with retries
|
||||
execute_at_command() {
|
||||
local command="$1"
|
||||
local result=""
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
handle_lock
|
||||
result=$(sms_tool at "$command" -t 4 2>&1)
|
||||
local status=$?
|
||||
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
|
||||
|
||||
if [ $status -eq 0 ] && [ -n "$result" ]; then
|
||||
echo "$result"
|
||||
return 0
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
[ $retry_count -lt $max_retries ] && sleep 2
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get current ICCID
|
||||
get_current_iccid() {
|
||||
local result=$(execute_at_command "AT+ICCID")
|
||||
if [ $? -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
|
||||
echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]'
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get current IMEI
|
||||
get_current_imei() {
|
||||
local result=$(execute_at_command "AT+CGSN")
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "$result" | grep -v "AT+CGSN" | grep -v "OK" | tr -d '\r\n[:space:]'
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Set IMEI
|
||||
set_imei() {
|
||||
local imei="$1"
|
||||
if execute_at_command "AT+EGMR=1,7,\"$imei\";+QPOWD=1"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to safely get UCI value with default
|
||||
get_uci_value() {
|
||||
local value
|
||||
config_get value imei_profile "$1" "$2"
|
||||
echo "${value:-$2}"
|
||||
}
|
||||
|
||||
# Main service loop
|
||||
while true; do
|
||||
# Load current configuration
|
||||
config_load quecmanager
|
||||
|
||||
# Get Profile 1
|
||||
iccid_profile1=$(get_uci_value "iccid_profile1")
|
||||
imei_profile1=$(get_uci_value "imei_profile1")
|
||||
|
||||
# Get Profile 2
|
||||
iccid_profile2=$(get_uci_value "iccid_profile2")
|
||||
imei_profile2=$(get_uci_value "imei_profile2")
|
||||
|
||||
# Get current ICCID and IMEI
|
||||
current_iccid=$(get_current_iccid)
|
||||
current_imei=$(get_current_imei)
|
||||
|
||||
if [ $? -eq 0 ] && [ -n "$current_iccid" ] && [ -n "$current_imei" ]; then
|
||||
if [ "${current_iccid}" = "${iccid_profile1}" ]; then
|
||||
if [ "${current_imei}" != "${imei_profile1}" ]; then
|
||||
if set_imei "${imei_profile1}"; then
|
||||
log_message "INFO" "Successfully applied Profile 1 IMEI"
|
||||
else
|
||||
log_message "ERROR" "Failed to apply Profile 1 IMEI"
|
||||
fi
|
||||
fi
|
||||
elif [ -n "$iccid_profile2" ] && [ "${current_iccid}" = "${iccid_profile2}" ]; then
|
||||
if [ "${current_imei}" != "${imei_profile2}" ]; then
|
||||
if set_imei "${imei_profile2}"; then
|
||||
log_message "INFO" "Successfully applied Profile 2 IMEI"
|
||||
else
|
||||
log_message "ERROR" "Failed to apply Profile 2 IMEI"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_message "INFO" "No matching ICCID profile found"
|
||||
fi
|
||||
else
|
||||
log_message "ERROR" "Failed to get current ICCID or IMEI"
|
||||
fi
|
||||
|
||||
sleep 30
|
||||
done
|
||||
EOL
|
||||
|
||||
chmod 755 /www/cgi-bin/services/imeiprofile.sh
|
||||
}
|
||||
|
||||
# Function to create init.d script
|
||||
create_init_script() {
|
||||
cat > /etc/init.d/imeiprofile-service <<'EOL'
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
start_service() {
|
||||
local enabled
|
||||
|
||||
# Check if service is enabled in UCI
|
||||
config_load quecmanager
|
||||
config_get enabled imei_profile enabled '0'
|
||||
|
||||
[ "$enabled" != "1" ] && return 0
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /www/cgi-bin/services/imeiprofile.sh
|
||||
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param nice 19
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "quecmanager"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
EOL
|
||||
|
||||
chmod 755 /etc/init.d/imeiprofile-service
|
||||
}
|
||||
|
||||
# Initialize UCI configuration
|
||||
touch /etc/config/quecmanager
|
||||
|
||||
# Remove existing IMEI profile section if it exists
|
||||
uci -q delete quecmanager.imei_profile
|
||||
|
||||
# Create new IMEI profile section
|
||||
uci set quecmanager.imei_profile=service
|
||||
uci set quecmanager.imei_profile.enabled=1
|
||||
|
||||
# Set Profile 1 configuration
|
||||
uci set quecmanager.imei_profile.iccid_profile1="$iccidProfile1"
|
||||
uci set quecmanager.imei_profile.imei_profile1="$imeiProfile1"
|
||||
|
||||
# Set Profile 2 configuration if provided
|
||||
if [ -n "$iccidProfile2" ]; then
|
||||
uci set quecmanager.imei_profile.iccid_profile2="$iccidProfile2"
|
||||
uci set quecmanager.imei_profile.imei_profile2="$imeiProfile2"
|
||||
fi
|
||||
|
||||
# Commit UCI changes
|
||||
if ! uci commit quecmanager; then
|
||||
log_message "ERROR" "Failed to save UCI configuration"
|
||||
echo '{"status": "error", "message": "Failed to save UCI configuration"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_message "INFO" "UCI configuration saved successfully"
|
||||
|
||||
# Create service script if it doesn't exist
|
||||
if [ ! -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
|
||||
create_service_script
|
||||
log_message "INFO" "Created service script"
|
||||
fi
|
||||
|
||||
# Create init.d script if it doesn't exist
|
||||
if [ ! -f "/etc/init.d/imeiprofile-service" ]; then
|
||||
create_init_script
|
||||
log_message "INFO" "Created init.d script"
|
||||
fi
|
||||
|
||||
# Enable and start the service
|
||||
/etc/init.d/imeiprofile-service enable
|
||||
if /etc/init.d/imeiprofile-service restart; then
|
||||
log_message "INFO" "Service started successfully"
|
||||
echo '{"status": "success", "message": "IMEI profiles saved and service started"}'
|
||||
else
|
||||
log_message "ERROR" "Failed to start service"
|
||||
echo '{"status": "error", "message": "Failed to start service"}'
|
||||
fi
|
||||
@@ -0,0 +1,262 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Configuration
|
||||
CONFIG_FILE="/etc/cell_lock_schedule.conf"
|
||||
STATUS_FILE="/tmp/cell_lock_status"
|
||||
CELL_LOCK_SCRIPT="/usr/bin/set_cell_lock.sh"
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
LOG_FILE="/tmp/cell_lock.log"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
|
||||
logger -t cell_lock "${level}: ${message}"
|
||||
}
|
||||
|
||||
# Function to handle AT command queue
|
||||
handle_lock() {
|
||||
log_message "DEBUG" "Checking queue file status before lock"
|
||||
if [ ! -f "$QUEUE_FILE" ]; then
|
||||
log_message "DEBUG" "Queue file does not exist, creating it"
|
||||
touch "$QUEUE_FILE"
|
||||
fi
|
||||
|
||||
# Clean any stale entries
|
||||
if grep -q "\"command\":\"AT_COMMAND\"" "$QUEUE_FILE"; then
|
||||
local wait_count=0
|
||||
while [ $wait_count -lt 6 ]; do
|
||||
if ! grep -q "\"command\":\"AT_COMMAND\"" "$QUEUE_FILE"; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
wait_count=$((wait_count + 1))
|
||||
done
|
||||
[ $wait_count -eq 6 ] && sed -i "/\"command\":\"AT_COMMAND\"/d" "$QUEUE_FILE"
|
||||
fi
|
||||
|
||||
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
|
||||
"$$" \
|
||||
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
|
||||
}
|
||||
|
||||
# Function to execute AT command
|
||||
execute_at_command() {
|
||||
local command="$1"
|
||||
local result=""
|
||||
|
||||
log_message "DEBUG" "Executing AT command: ${command}"
|
||||
handle_lock
|
||||
|
||||
result=$(sms_tool at "$command" -t 4 2>&1)
|
||||
local status=$?
|
||||
|
||||
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
log_message "ERROR" "Command failed with status $status: $command"
|
||||
log_message "ERROR" "Command output: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "DEBUG" "Command successful. Output: $result"
|
||||
echo "$result"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to create set_cell_lock.sh script
|
||||
create_cell_lock_script() {
|
||||
if [ ! -f "$CELL_LOCK_SCRIPT" ]; then
|
||||
cat >"$CELL_LOCK_SCRIPT" <<'EOL'
|
||||
#!/bin/sh
|
||||
|
||||
ACTION=$1
|
||||
LTE_PARAMS=$2
|
||||
NR5G_PARAMS=$3
|
||||
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
LOG_FILE="/tmp/cell_lock.log"
|
||||
|
||||
# Import common functions
|
||||
. /etc/quecmanager/imei_profile/common_functions.sh || {
|
||||
echo "Failed to import common functions"
|
||||
exit 1
|
||||
}
|
||||
|
||||
case "$ACTION" in
|
||||
enable)
|
||||
# Enable LTE lock if parameters exist
|
||||
if [ -n "$LTE_PARAMS" ]; then
|
||||
execute_at_command "AT+QNWLOCK=\"common/4g\",$LTE_PARAMS"
|
||||
fi
|
||||
|
||||
# Enable NR5G lock if parameters exist
|
||||
if [ -n "$NR5G_PARAMS" ]; then
|
||||
execute_at_command "AT+QNWLOCK=\"common/5g\",$NR5G_PARAMS"
|
||||
fi
|
||||
;;
|
||||
|
||||
disable)
|
||||
# Disable LTE lock
|
||||
execute_at_command "AT+QNWLOCK=\"common/4g\",0"
|
||||
|
||||
# Disable NR5G lock
|
||||
execute_at_command "AT+QNWLOCK=\"common/5g\",0"
|
||||
;;
|
||||
|
||||
*)
|
||||
log_message "ERROR" "Invalid action: $ACTION"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Restart network registration to apply changes
|
||||
execute_at_command "AT+COPS=2"
|
||||
sleep 2
|
||||
execute_at_command "AT+COPS=0"
|
||||
exit 0
|
||||
EOL
|
||||
|
||||
chmod +x "$CELL_LOCK_SCRIPT"
|
||||
log_message "INFO" "Created cell lock script at $CELL_LOCK_SCRIPT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to remove set_cell_lock.sh script
|
||||
remove_cell_lock_script() {
|
||||
if [ -f "$CELL_LOCK_SCRIPT" ]; then
|
||||
rm "$CELL_LOCK_SCRIPT"
|
||||
log_message "INFO" "Removed cell lock 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 convert HH:MM to cron format
|
||||
convert_to_cron_time() {
|
||||
echo "$1" | awk -F: '{print $2, $1}'
|
||||
}
|
||||
|
||||
# Function to save configuration
|
||||
save_config() {
|
||||
echo "START_TIME=$1" >"$CONFIG_FILE"
|
||||
echo "END_TIME=$2" >>"$CONFIG_FILE"
|
||||
echo "ENABLED=1" >>"$CONFIG_FILE"
|
||||
log_message "INFO" "Saved configuration - Start: $1, End: $2"
|
||||
}
|
||||
|
||||
# Function to disable scheduling
|
||||
disable_scheduling() {
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
sed -i 's/ENABLED=1/ENABLED=0/' "$CONFIG_FILE"
|
||||
log_message "INFO" "Disabled scheduling"
|
||||
fi
|
||||
crontab -l | grep -v "set_cell_lock.sh" | crontab -
|
||||
remove_cell_lock_script
|
||||
}
|
||||
|
||||
# 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)
|
||||
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\"}"
|
||||
else
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"enabled\":0,\"start_time\":\"\",\"end_time\":\"\"}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle POST requests
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
read -r POST_DATA
|
||||
|
||||
if echo "$POST_DATA" | grep -q "disable=true"; then
|
||||
disable_scheduling
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
START_TIME=$(echo "$POST_DATA" | grep -o 'start_time=[^&]*' | cut -d'=' -f2)
|
||||
END_TIME=$(echo "$POST_DATA" | grep -o 'end_time=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
START_TIME=$(urldecode "$START_TIME")
|
||||
END_TIME=$(urldecode "$END_TIME")
|
||||
|
||||
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ]; then
|
||||
log_message "ERROR" "Missing start or end time"
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Missing start or end time\"}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
create_cell_lock_script
|
||||
|
||||
CRON_START=$(convert_to_cron_time "$START_TIME")
|
||||
CRON_END=$(convert_to_cron_time "$END_TIME")
|
||||
|
||||
save_config "$START_TIME" "$END_TIME"
|
||||
|
||||
# Check current cell lock status and get parameters
|
||||
LTE_STATUS=$(execute_at_command 'AT+QNWLOCK="common/4g"')
|
||||
NR5G_STATUS=$(execute_at_command 'AT+QNWLOCK="common/5g"')
|
||||
|
||||
LTE_PARAMS=$(echo "$LTE_STATUS" | grep -o '"common/4g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
NR5G_PARAMS=$(echo "$NR5G_STATUS" | grep -o '"common/5g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
|
||||
TEMP_CRON=$(mktemp)
|
||||
|
||||
crontab -l 2>/dev/null | grep -v "set_cell_lock.sh" >"$TEMP_CRON"
|
||||
|
||||
echo "$CRON_START * * * $CELL_LOCK_SCRIPT enable \"$LTE_PARAMS\" \"$NR5G_PARAMS\"" >>"$TEMP_CRON"
|
||||
echo "$CRON_END * * * $CELL_LOCK_SCRIPT disable" >>"$TEMP_CRON"
|
||||
|
||||
crontab "$TEMP_CRON"
|
||||
rm "$TEMP_CRON"
|
||||
|
||||
log_message "INFO" "Scheduling enabled with start time $START_TIME and end time $END_TIME"
|
||||
|
||||
echo "Status: 200 OK"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"status\":\"success\",\"message\":\"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
|
||||
log_message "ERROR" "Invalid request received"
|
||||
echo "Status: 400 Bad Request"
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
echo "{\"error\":\"Invalid request\"}"
|
||||
exit 1
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type
|
||||
printf "Content-Type: application/json\n\n"
|
||||
|
||||
# URL decode function
|
||||
urldecode() {
|
||||
echo "$*" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\\\x\1/g' | xargs -0 printf '%b'
|
||||
}
|
||||
|
||||
# Extract indexes from query string
|
||||
query=$(echo "$QUERY_STRING" | grep -o 'indexes=[^&]*' | cut -d= -f2)
|
||||
indexes=$(urldecode "$query")
|
||||
|
||||
# Function to output JSON response
|
||||
send_json() {
|
||||
printf '{"status":"%s","message":"%s"}\n' "$1" "$2"
|
||||
}
|
||||
|
||||
# Validate input
|
||||
if [ -z "$indexes" ]; then
|
||||
send_json "error" "No indexes provided"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize counters
|
||||
success=0
|
||||
failure=0
|
||||
|
||||
# Process each index
|
||||
echo "$indexes" | tr ',' '\n' | while read -r index; do
|
||||
if [ -n "$index" ] && [ "$index" -eq "$index" ] 2>/dev/null; then
|
||||
if sms_tool delete "$index" 2>/dev/null; then
|
||||
success=$((success + 1))
|
||||
else
|
||||
failure=$((failure + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Send response
|
||||
if [ $success -gt 0 ]; then
|
||||
if [ $failure -eq 0 ]; then
|
||||
send_json "success" "Successfully deleted $success message(s)"
|
||||
else
|
||||
send_json "partial" "Deleted $success message(s), failed to delete $failure message(s)"
|
||||
fi
|
||||
else
|
||||
send_json "error" "Failed to delete messages"
|
||||
fi
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
printf "Content-type: application/json\r\n\r\n"
|
||||
|
||||
# Execute the command and return the JSON response
|
||||
if command -v sms_tool > /dev/null 2>&1; then
|
||||
sms_tool -j recv
|
||||
else
|
||||
printf '{"error": "sms_tool not found"}\n'
|
||||
fi
|
||||
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Content-Type: application/json"
|
||||
echo "Cache-Control: no-cache"
|
||||
echo ""
|
||||
|
||||
# Function to URL decode the string
|
||||
urldecode() {
|
||||
local url_encoded="${1//+/ }"
|
||||
printf '%b' "${url_encoded//%/\\x}"
|
||||
}
|
||||
|
||||
# Function to escape JSON string
|
||||
escape_json() {
|
||||
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g; s/\r/\\r/g; s/\t/\\t/g'
|
||||
}
|
||||
|
||||
# Read POST data
|
||||
read -r QUERY_STRING
|
||||
|
||||
# Extract phone and message from POST data
|
||||
phone=$(echo "$QUERY_STRING" | grep -o 'phone=[^&]*' | cut -d= -f2)
|
||||
message=$(echo "$QUERY_STRING" | grep -o 'message=[^&]*' | cut -d= -f2)
|
||||
|
||||
# URL decode the message
|
||||
decoded_message=$(urldecode "$message")
|
||||
|
||||
# Validate inputs
|
||||
if [ -z "$phone" ] || [ -z "$message" ]; then
|
||||
echo '{"success":false,"error":"Phone number and message are required"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Validate phone number (only numbers allowed)
|
||||
if ! echo "$phone" | grep -q '^[0-9]\+$'; then
|
||||
echo '{"success":false,"error":"Invalid phone number format"}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Try to send SMS and capture output
|
||||
result=$(sms_tool send "$phone" "$decoded_message" 2>&1)
|
||||
escaped_result=$(escape_json "$result")
|
||||
|
||||
# Check if SMS was sent successfully by looking for "sms sent sucessfully"
|
||||
if echo "$result" | grep -q "sms sent sucessfully"; then
|
||||
# Extract the message ID if present
|
||||
message_id=$(echo "$result" | grep -o '[0-9]*$')
|
||||
echo "{\"success\":true,\"message\":\"SMS sent successfully\",\"messageId\":\"$message_id\",\"raw\":\"$escaped_result\"}"
|
||||
elif echo "$result" | grep -q "sms not sent, code 350"; then
|
||||
# Kill any hanging sms_tool process
|
||||
pkill -f "sms_tool send"
|
||||
echo '{"success":false,"error":"No prepaid credit available"}'
|
||||
else
|
||||
# Kill any hanging sms_tool process
|
||||
pkill -f "sms_tool send"
|
||||
echo "{\"success\":false,\"error\":\"Failed to send SMS\",\"raw\":\"$escaped_result\"}"
|
||||
fi
|
||||
@@ -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
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/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}'
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set the content type to JSON
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
# Ping 8.8.8.8 with 2 packets and capture the result
|
||||
if ping -c 2 8.8.8.8 > /dev/null 2>&1; then
|
||||
# Ping was successful
|
||||
echo '{"connection": "ACTIVE"}'
|
||||
else
|
||||
# Ping failed
|
||||
echo '{"connection": "INACTIVE"}'
|
||||
fi
|
||||
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-Type: application/json"
|
||||
echo
|
||||
|
||||
# Read the JSON file and get only the last entry using jq
|
||||
jq 'last' /www/signal_graphs/data_usage.json
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set common headers
|
||||
echo "Content-Type: application/json"
|
||||
echo "Access-Control-Allow-Origin: *"
|
||||
echo "Cache-Control: no-cache, no-store, must-revalidate"
|
||||
echo ""
|
||||
|
||||
# Lock file path
|
||||
LOCK_FILE="/tmp/hw_details.lock"
|
||||
LOCK_TIMEOUT=10 # Maximum wait time in seconds
|
||||
|
||||
# Function to acquire lock
|
||||
acquire_lock() {
|
||||
local start_time=$(date +%s)
|
||||
while [ -e "$LOCK_FILE" ]; do
|
||||
# Check if lock is stale (older than LOCK_TIMEOUT seconds)
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
local lock_time=$(stat -c %Y "$LOCK_FILE" 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
if [ $((current_time - lock_time)) -gt $LOCK_TIMEOUT ]; then
|
||||
rm -f "$LOCK_FILE"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if we've waited too long
|
||||
if [ $(($(date +%s) - start_time)) -gt $LOCK_TIMEOUT ]; then
|
||||
error_response "Timeout waiting for lock"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
# Create lock file with current PID
|
||||
echo $$ > "$LOCK_FILE"
|
||||
}
|
||||
|
||||
# Function to release lock
|
||||
release_lock() {
|
||||
rm -f "$LOCK_FILE"
|
||||
}
|
||||
|
||||
# Function to handle errors and return JSON
|
||||
error_response() {
|
||||
echo "{\"error\": \"$1\"}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to cleanup on exit
|
||||
cleanup() {
|
||||
release_lock
|
||||
exit $?
|
||||
}
|
||||
|
||||
# Set trap for cleanup
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Function to get memory information
|
||||
get_memory_info() {
|
||||
free_output=$(free -b)
|
||||
memory_info=$(echo "$free_output" | awk '/Mem:/ {print "{\"total\": " $2 ", \"used\": " $3 ", \"available\": " $7 "}"}')
|
||||
echo "$memory_info"
|
||||
}
|
||||
|
||||
# Function to get ethernet information
|
||||
get_ethernet_info() {
|
||||
interface=${1:-eth0}
|
||||
# Check if ethtool is installed
|
||||
if ! which ethtool >/dev/null 2>&1; then
|
||||
error_response "ethtool not found"
|
||||
fi
|
||||
|
||||
# Check if interface exists
|
||||
if ! ip link show "$interface" >/dev/null 2>&1; then
|
||||
error_response "Interface $interface not found"
|
||||
fi
|
||||
|
||||
# Run ethtool and capture output
|
||||
ethtool_output=$(ethtool "$interface" 2>/dev/null) || error_response "Failed to get ethernet information"
|
||||
|
||||
# Extract values using sed instead of grep -P
|
||||
speed=$(echo "$ethtool_output" | sed -n 's/.*Speed: \([^[:space:]]*\).*/\1/p' || echo "Unknown")
|
||||
link_status=$(echo "$ethtool_output" | sed -n 's/.*Link detected: \(yes\|no\).*/\1/p' || echo "unknown")
|
||||
auto_negotiation=$(echo "$ethtool_output" | sed -n 's/.*Auto-negotiation: \(on\|off\).*/\1/p' || echo "unknown")
|
||||
|
||||
# Output JSON
|
||||
echo "{\"link_speed\":\"$speed\",\"link_status\":\"$link_status\",\"auto_negotiation\":\"$auto_negotiation\"}"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
# Acquire lock before proceeding
|
||||
acquire_lock
|
||||
|
||||
# Parse query string for type and interface
|
||||
type=$(echo "$QUERY_STRING" | sed -n 's/.*type=\([^&]*\).*/\1/p')
|
||||
interface=$(echo "$QUERY_STRING" | sed -n 's/.*interface=\([^&]*\).*/\1/p')
|
||||
|
||||
# Default interface if not specified
|
||||
[ -z "$interface" ] && interface="eth0"
|
||||
|
||||
# Convert type to lowercase using tr
|
||||
type=$(echo "$type" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Check type parameter and call appropriate function
|
||||
case "$type" in
|
||||
"memory")
|
||||
get_memory_info
|
||||
;;
|
||||
"eth")
|
||||
get_ethernet_info "$interface"
|
||||
;;
|
||||
*)
|
||||
error_response "Invalid type. Use 'memory' or 'eth'"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Lock will be automatically released by the cleanup trap
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Ensure the script outputs proper CGI headers
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
# Directory where JSON files are stored (adjust as needed)
|
||||
JSON_DIR="/www/signal_graphs/"
|
||||
|
||||
# Function to safely read JSON file
|
||||
read_json_file() {
|
||||
local file="$1"
|
||||
if [ -f "$file" ]; then
|
||||
cat "$file"
|
||||
else
|
||||
echo "[]" # Return empty array if file doesn't exist
|
||||
fi
|
||||
}
|
||||
|
||||
# Collect signal metrics from JSON files
|
||||
RSRP=$(read_json_file "${JSON_DIR}/rsrp.json")
|
||||
RSRQ=$(read_json_file "${JSON_DIR}/rsrq.json")
|
||||
SINR=$(read_json_file "${JSON_DIR}/sinr.json")
|
||||
|
||||
# Combine metrics into a single JSON object
|
||||
printf '{
|
||||
"rsrp": %s,
|
||||
"rsrq": %s,
|
||||
"sinr": %s
|
||||
}' "$RSRP" "$RSRQ" "$SINR"
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set the content type to JSON
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
|
||||
# Ping 8.8.8.8 with 5 packets and capture the full output
|
||||
ping_result=$(ping -c 5 8.8.8.8)
|
||||
|
||||
# Check if ping was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract the average latency using awk
|
||||
avg_latency=$(echo "$ping_result" | awk '/avg/ {split($4, a, "/"); print int(a[2])}')
|
||||
|
||||
# If average latency was extracted, return it
|
||||
if [ ! -z "$avg_latency" ]; then
|
||||
echo "{\"connection\": \"ACTIVE\", \"latency\": $avg_latency}"
|
||||
else
|
||||
echo '{"connection": "ACTIVE", "latency": 0}'
|
||||
fi
|
||||
else
|
||||
# Ping failed
|
||||
echo '{"connection": "INACTIVE", "latency": 0}'
|
||||
fi
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/check_status.cgi
|
||||
|
||||
# Set content type to JSON
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
STATUS_FILE="/tmp/quecprofiles_status.json"
|
||||
TRACK_FILE="/tmp/quecprofiles_active"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "status_check: $1"
|
||||
}
|
||||
|
||||
# Function to output default "idle" JSON
|
||||
output_idle_json() {
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "idle",
|
||||
"message": "No active profile operations",
|
||||
"profile": "unknown",
|
||||
"progress": 0,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check if status file exists
|
||||
if [ -f "$STATUS_FILE" ]; then
|
||||
# Check if file is not empty
|
||||
if [ -s "$STATUS_FILE" ]; then
|
||||
# Cat the entire file content (more reliable than grep)
|
||||
status_content=$(cat "$STATUS_FILE")
|
||||
|
||||
# Log content for debugging
|
||||
log_message "Status file content: $status_content" "debug"
|
||||
|
||||
# Check if it looks like valid JSON
|
||||
if echo "$status_content" | grep -q "status"; then
|
||||
# Output the status file content
|
||||
cat "$STATUS_FILE"
|
||||
|
||||
# Extract status for logging only
|
||||
status=$(echo "$status_content" | sed -n 's/.*"status":"\([^"]*\)".*/\1/p')
|
||||
log_message "Status from file: $status" "info"
|
||||
exit 0
|
||||
else
|
||||
log_message "Status file exists but not valid JSON" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "Status file exists but empty" "warn"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we get here, either no file exists or it's invalid/old
|
||||
# Check if track file exists (as a fallback)
|
||||
if [ -f "$TRACK_FILE" ]; then
|
||||
status_info=$(cat "$TRACK_FILE")
|
||||
status=$(echo "$status_info" | cut -d':' -f1)
|
||||
profile=$(echo "$status_info" | cut -d':' -f2)
|
||||
progress=$(echo "$status_info" | cut -d':' -f3)
|
||||
|
||||
# Make sure the message reflects the actual status
|
||||
if [ "$status" = "success" ]; then
|
||||
message="Profile successfully applied"
|
||||
elif [ "$status" = "applying" ]; then
|
||||
message="Profile operation in progress"
|
||||
elif [ "$status" = "error" ]; then
|
||||
message="Profile operation failed"
|
||||
elif [ "$status" = "rebooting" ]; then
|
||||
message="Device is rebooting to apply changes"
|
||||
else
|
||||
message="Profile operation status: $status"
|
||||
fi
|
||||
|
||||
# Output JSON based on track file
|
||||
cat <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"profile": "$profile",
|
||||
"progress": $progress,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
log_message "Retrieved status from track file: $status" "info"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If no valid files found, output idle state
|
||||
output_idle_json
|
||||
@@ -0,0 +1,154 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/list_profiles.sh
|
||||
|
||||
# Set content type to JSON and ensure blank line is output
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "list_profiles: $1"
|
||||
# Also log to our error file
|
||||
echo "[$(date)] $level: $1" >>/tmp/list_profiles_error.log
|
||||
}
|
||||
|
||||
# Function to output JSON error response
|
||||
output_error() {
|
||||
local message="$1"
|
||||
echo "{\"status\":\"error\",\"message\":\"$message\",\"profiles\":[]}"
|
||||
log_message "$message" "error"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to sanitize string for JSON
|
||||
sanitize_for_json() {
|
||||
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed 's/\t/\\t/g' | tr -d '\r\n'
|
||||
}
|
||||
|
||||
# Check if UCI command exists
|
||||
if ! which uci >/dev/null 2>&1; then
|
||||
output_error "UCI command not found"
|
||||
fi
|
||||
|
||||
# Function to extract profiles from UCI config
|
||||
get_profiles() {
|
||||
log_message "Fetching profiles from UCI config"
|
||||
|
||||
# Check if UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "No profiles config found" "warn"
|
||||
echo "{\"status\":\"success\",\"profiles\":[]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Start JSON output
|
||||
local json_output=""
|
||||
local first=1
|
||||
local count=0
|
||||
|
||||
# Get all profile indices - make sure this succeeds
|
||||
local indices=$(uci -q show quecprofiles | grep -o '@profile\[[0-9]*\]' | sort -u)
|
||||
|
||||
# Debug output
|
||||
echo "Found indices: $indices" >>/tmp/list_profiles_error.log
|
||||
|
||||
if [ -z "$indices" ]; then
|
||||
log_message "No profile indices found" "warn"
|
||||
echo "{\"status\":\"success\",\"profiles\":[]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Process each profile
|
||||
for idx in $indices; do
|
||||
log_message "Processing profile index: $idx"
|
||||
|
||||
# Try different UCI get approaches
|
||||
local name
|
||||
name=$(uci -q get "quecprofiles.$idx.name" 2>/dev/null)
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Failed to get name for $idx, trying alternative method" "warn"
|
||||
local section=${idx#@profile[}
|
||||
section=${section%]}
|
||||
name=$(uci -q get "quecprofiles.@profile[$section].name" 2>/dev/null)
|
||||
fi
|
||||
|
||||
# Get profile details
|
||||
local iccid=$(uci -q get "quecprofiles.$idx.iccid" 2>/dev/null)
|
||||
local imei=$(uci -q get "quecprofiles.$idx.imei" 2>/dev/null)
|
||||
local apn=$(uci -q get "quecprofiles.$idx.apn" 2>/dev/null)
|
||||
local pdp_type=$(uci -q get "quecprofiles.$idx.pdp_type" 2>/dev/null)
|
||||
local lte_bands=$(uci -q get "quecprofiles.$idx.lte_bands" 2>/dev/null)
|
||||
local sa_nr5g_bands=$(uci -q get "quecprofiles.$idx.sa_nr5g_bands" 2>/dev/null)
|
||||
local nsa_nr5g_bands=$(uci -q get "quecprofiles.$idx.nsa_nr5g_bands" 2>/dev/null)
|
||||
local network_type=$(uci -q get "quecprofiles.$idx.network_type" 2>/dev/null)
|
||||
local ttl=$(uci -q get "quecprofiles.$idx.ttl" 2>/dev/null)
|
||||
|
||||
# Debug output
|
||||
log_message "Retrieved for $idx: name=$name, iccid=$iccid, apn=$apn"
|
||||
|
||||
# Skip if missing required fields
|
||||
if [ -z "$name" ] || [ -z "$iccid" ] || [ -z "$apn" ]; then
|
||||
log_message "Skipping invalid profile: $idx (missing required fields)" "warn"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Sanitize all values to ensure valid JSON
|
||||
name=$(sanitize_for_json "$name")
|
||||
iccid=$(sanitize_for_json "$iccid")
|
||||
imei=$(sanitize_for_json "${imei:-""}")
|
||||
apn=$(sanitize_for_json "$apn")
|
||||
pdp_type=$(sanitize_for_json "${pdp_type:-"IPV4V6"}")
|
||||
lte_bands=$(sanitize_for_json "${lte_bands:-""}")
|
||||
sa_nr5g_bands=$(sanitize_for_json "${sa_nr5g_bands:-""}")
|
||||
nsa_nr5g_bands=$(sanitize_for_json "${nsa_nr5g_bands:-""}")
|
||||
network_type=$(sanitize_for_json "${network_type:-"LTE"}")
|
||||
ttl=$(sanitize_for_json "${ttl:-0}")
|
||||
|
||||
# Create profile JSON
|
||||
local profile_json="{"
|
||||
profile_json="${profile_json}\"name\":\"${name}\","
|
||||
profile_json="${profile_json}\"iccid\":\"${iccid}\","
|
||||
profile_json="${profile_json}\"imei\":\"${imei}\","
|
||||
profile_json="${profile_json}\"apn\":\"${apn}\","
|
||||
profile_json="${profile_json}\"pdp_type\":\"${pdp_type}\","
|
||||
profile_json="${profile_json}\"lte_bands\":\"${lte_bands}\","
|
||||
profile_json="${profile_json}\"sa_nr5g_bands\":\"${sa_nr5g_bands}\","
|
||||
profile_json="${profile_json}\"nsa_nr5g_bands\":\"${nsa_nr5g_bands}\","
|
||||
profile_json="${profile_json}\"network_type\":\"${network_type}\","
|
||||
profile_json="${profile_json}\"ttl\":\"${ttl}\""
|
||||
profile_json="${profile_json}}"
|
||||
|
||||
# Add comma if not first
|
||||
if [ $first -eq 0 ]; then
|
||||
json_output="${json_output},"
|
||||
else
|
||||
first=0
|
||||
fi
|
||||
|
||||
# Add profile to output
|
||||
json_output="${json_output}${profile_json}"
|
||||
count=$((count+1))
|
||||
done
|
||||
|
||||
# Complete the JSON response
|
||||
local response="{\"status\":\"success\",\"profiles\":[${json_output}]}"
|
||||
|
||||
# Save the response for debugging
|
||||
echo "$response" > /tmp/list_profiles_response.json
|
||||
|
||||
echo "$response"
|
||||
log_message "Found and returned $count profiles"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Start fresh error log
|
||||
echo "=== List Profiles Run $(date) ===" > /tmp/list_profiles_error.log
|
||||
|
||||
# Main execution
|
||||
{
|
||||
get_profiles
|
||||
} || {
|
||||
# Error handler
|
||||
output_error "Failed to retrieve profiles"
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_create.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "create: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to validate ICCID (simple check)
|
||||
validate_iccid() {
|
||||
local iccid="$1"
|
||||
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
|
||||
return 1
|
||||
fi
|
||||
# Check that it's only digits
|
||||
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate IMEI (simple check)
|
||||
validate_imei() {
|
||||
local imei="$1"
|
||||
if [ -z "$imei" ]; then
|
||||
return 0 # IMEI is optional
|
||||
fi
|
||||
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate band list
|
||||
validate_bands() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
return 0 # Empty is valid
|
||||
fi
|
||||
# Check format (comma-separated numbers)
|
||||
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate network type
|
||||
validate_network_type() {
|
||||
local net_type="$1"
|
||||
case "$net_type" in
|
||||
"LTE" | "NR5G" | "LTE:NR5G")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to validate PDP type
|
||||
validate_pdp_type() {
|
||||
local pdp_type="$1"
|
||||
case "$pdp_type" in
|
||||
"IP" | "IPV6" | "IPV4V6")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Add function to validate TTL
|
||||
validate_ttl() {
|
||||
local ttl="$1"
|
||||
if [ -z "$ttl" ]; then
|
||||
return 0 # Empty is valid (will be treated as 0/disabled)
|
||||
fi
|
||||
# Check that TTL is a number between 0 and 255
|
||||
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if a profile with the same name or ICCID already exists
|
||||
check_duplicate_profile() {
|
||||
local name="$1"
|
||||
local iccid="$2"
|
||||
|
||||
# Check for duplicate name
|
||||
local existing_name=$(uci -q show quecprofiles | grep ".name='$name'" | head -n 1)
|
||||
if [ -n "$existing_name" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for duplicate ICCID
|
||||
local existing_iccid=$(uci -q show quecprofiles | grep ".iccid='$iccid'" | head -n 1)
|
||||
if [ -n "$existing_iccid" ]; then
|
||||
return 2
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to create new profile
|
||||
create_profile() {
|
||||
local name="$1"
|
||||
local iccid="$2"
|
||||
local imei="$3"
|
||||
local apn="$4"
|
||||
local pdp_type="$5"
|
||||
local lte_bands="$6"
|
||||
local sa_nr5g_bands="$7"
|
||||
local nsa_nr5g_bands="$8"
|
||||
local network_type="$9"
|
||||
local ttl="${10}"
|
||||
|
||||
# Generate a unique ID for the profile
|
||||
local profile_id="profile_$(date +%s)_$(head -c 4 /dev/urandom | hexdump -e '"%x"')"
|
||||
|
||||
# Add to UCI config
|
||||
uci -q batch <<EOF
|
||||
add quecprofiles profile
|
||||
set quecprofiles.@profile[-1].name='$name'
|
||||
set quecprofiles.@profile[-1].iccid='$iccid'
|
||||
set quecprofiles.@profile[-1].imei='$imei'
|
||||
set quecprofiles.@profile[-1].apn='$apn'
|
||||
set quecprofiles.@profile[-1].pdp_type='$pdp_type'
|
||||
set quecprofiles.@profile[-1].lte_bands='$lte_bands'
|
||||
set quecprofiles.@profile[-1].sa_nr5g_bands='$sa_nr5g_bands'
|
||||
set quecprofiles.@profile[-1].nsa_nr5g_bands='$nsa_nr5g_bands'
|
||||
set quecprofiles.@profile[-1].network_type='$network_type'
|
||||
set quecprofiles.@profile[-1].ttl='$ttl'
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully created profile '$name' for ICCID $iccid"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to create profile '$name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received create profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
# Create initial config file
|
||||
cat >/etc/config/quecprofiles <<EOF
|
||||
config quecprofiles 'settings'
|
||||
option check_interval '60'
|
||||
option enable_autoswitch '1'
|
||||
option apply_priority '20'
|
||||
EOF
|
||||
log_message "Created initial quecprofiles config file"
|
||||
fi
|
||||
|
||||
# Get POST data
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
|
||||
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
|
||||
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
|
||||
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
|
||||
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
|
||||
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
|
||||
|
||||
log_message "Parsed JSON data for profile: $name" "debug"
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
# This is less reliable but might work for simple cases
|
||||
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
|
||||
log_message "Basic parsing for profile: $name" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
else
|
||||
# URL parameters for GET requests (less secure, but supported for testing)
|
||||
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
|
||||
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
|
||||
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
|
||||
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
|
||||
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
|
||||
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode values
|
||||
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameters" "warn"
|
||||
fi
|
||||
|
||||
# Sanitize inputs
|
||||
name=$(sanitize "${name:-}")
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
imei=$(sanitize "${imei:-}")
|
||||
apn=$(sanitize "${apn:-}")
|
||||
pdp_type=$(sanitize "${pdp_type:-IP}")
|
||||
lte_bands=$(sanitize "${lte_bands:-}")
|
||||
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
|
||||
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
|
||||
network_type=$(sanitize "${network_type:-LTE}")
|
||||
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
|
||||
|
||||
# Output debug info
|
||||
log_message "Creating profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
|
||||
|
||||
# Validate required inputs
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Profile name is missing" "error"
|
||||
output_json "error" "Profile name is required"
|
||||
fi
|
||||
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required"
|
||||
fi
|
||||
|
||||
if [ -z "$apn" ]; then
|
||||
log_message "APN is missing" "error"
|
||||
output_json "error" "APN is required"
|
||||
fi
|
||||
|
||||
# Validate input formats
|
||||
if ! validate_iccid "$iccid"; then
|
||||
log_message "Invalid ICCID format: $iccid" "error"
|
||||
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
|
||||
fi
|
||||
|
||||
if ! validate_imei "$imei"; then
|
||||
log_message "Invalid IMEI format: $imei" "error"
|
||||
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
|
||||
fi
|
||||
|
||||
if ! validate_bands "$lte_bands"; then
|
||||
log_message "Invalid LTE bands format: $lte_bands" "error"
|
||||
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$sa_nr5g_bands"; then
|
||||
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$nsa_nr5g_bands"; then
|
||||
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
|
||||
fi
|
||||
|
||||
if ! validate_network_type "$network_type"; then
|
||||
log_message "Invalid network type: $network_type" "error"
|
||||
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
|
||||
fi
|
||||
|
||||
if ! validate_pdp_type "$pdp_type"; then
|
||||
log_message "Invalid PDP type: $pdp_type" "error"
|
||||
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
|
||||
fi
|
||||
|
||||
if ! validate_ttl "$ttl"; then
|
||||
log_message "Invalid TTL value: $ttl" "error"
|
||||
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
|
||||
fi
|
||||
|
||||
# Check for duplicates
|
||||
check_duplicate_profile "$name" "$iccid"
|
||||
dup_status=$?
|
||||
if [ $dup_status -eq 1 ]; then
|
||||
log_message "Duplicate profile name: $name" "error"
|
||||
output_json "error" "A profile with this name already exists"
|
||||
elif [ $dup_status -eq 2 ]; then
|
||||
log_message "Duplicate ICCID: $iccid" "error"
|
||||
output_json "error" "A profile with this ICCID already exists"
|
||||
fi
|
||||
|
||||
# Create the profile
|
||||
if create_profile "$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$sa_nr5g_bands" "$nsa_nr5g_bands" "$network_type" "$ttl"; then
|
||||
# Trigger immediate profile application
|
||||
touch "/tmp/quecprofiles_check"
|
||||
chmod 644 "/tmp/quecprofiles_check"
|
||||
log_message "Triggered immediate profile check after creation" "info"
|
||||
|
||||
# Create profile data JSON for return - WITHOUT outer curly braces
|
||||
profile_data="\"name\":\"$name\",\"iccid\":\"$iccid\",\"imei\":\"$imei\",\"apn\":\"$apn\",\"pdp_type\":\"$pdp_type\",\"lte_bands\":\"$lte_bands\",\"sa_nr5g_bands\":\"$sa_nr5g_bands\",\"nsa_nr5g_bands\":\"$nsa_nr5g_bands\",\"network_type\":\"$network_type\",\"ttl\":\"$ttl\""
|
||||
|
||||
# Wrap the data field in curly braces inside output_json
|
||||
output_json "success" "Profile created successfully" "{$profile_data}"
|
||||
else
|
||||
output_json "error" "Failed to create profile. Please check system logs."
|
||||
fi
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_delete.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "delete: $1"
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to find profile by ICCID
|
||||
find_profile_by_iccid() {
|
||||
local iccid="$1"
|
||||
# Get all profile indices
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
if [ "$current_iccid" = "$iccid" ]; then
|
||||
echo "$profile_index"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to delete a profile
|
||||
delete_profile() {
|
||||
local profile_index="$1"
|
||||
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Delete the profile from UCI config
|
||||
uci -q batch <<EOF
|
||||
delete quecprofiles.$profile_index
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully deleted profile '$profile_name'" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to delete profile '$profile_name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received delete profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "quecprofiles config does not exist" "error"
|
||||
output_json "error" "Configuration file not found"
|
||||
fi
|
||||
|
||||
# Get ICCID from request
|
||||
iccid=""
|
||||
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
elif [ -n "$QUERY_STRING" ]; then
|
||||
# URL parameters for GET or DELETE requests
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode value
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameter: iccid=$iccid" "debug"
|
||||
fi
|
||||
|
||||
# Sanitize input
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
|
||||
# Validate ICCID
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required to identify the profile"
|
||||
fi
|
||||
|
||||
# Find profile to delete
|
||||
profile_index=$(find_profile_by_iccid "$iccid")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Profile with ICCID $iccid not found" "error"
|
||||
output_json "error" "Profile not found"
|
||||
fi
|
||||
|
||||
# Get profile info for response
|
||||
profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Delete the profile
|
||||
if delete_profile "$profile_index"; then
|
||||
log_message "Profile deleted successfully: $profile_name" "info"
|
||||
output_json "success" "Profile deleted successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\"}"
|
||||
else
|
||||
log_message "Failed to delete profile: $profile_name" "error"
|
||||
output_json "error" "Failed to delete profile. Please check system logs."
|
||||
fi
|
||||
@@ -0,0 +1,392 @@
|
||||
#!/bin/sh
|
||||
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_edit.sh
|
||||
|
||||
# Set content type to JSON
|
||||
echo -n ""
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
CHECK_TRIGGER="/tmp/quecprofiles_check"
|
||||
APPLIED_FLAG="/tmp/quecprofiles_applied"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
logger -t quecprofiles -p "daemon.$level" "edit: $1"
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] edit: $1" >>/tmp/quec_profile_edit.log
|
||||
}
|
||||
|
||||
# Function to output JSON response
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local data="${3:-{}}"
|
||||
|
||||
# Debug log to file only
|
||||
echo "Generating JSON response: status=$status, message=$message" >>/tmp/quec_profile_debug.log
|
||||
echo "Data payload: $data" >>/tmp/quec_profile_debug.log
|
||||
|
||||
# Use printf for consistent output without newlines or extra characters
|
||||
printf '{"status":"%s","message":"%s","data":%s}' "$status" "$message" "$data"
|
||||
|
||||
# Add debug marker at end of JSON
|
||||
echo "" >>/tmp/quec_profile_debug.log
|
||||
echo "JSON response generated at $(date)" >>/tmp/quec_profile_debug.log
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to sanitize input
|
||||
sanitize() {
|
||||
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
|
||||
}
|
||||
|
||||
# Function to validate ICCID (simple check)
|
||||
validate_iccid() {
|
||||
local iccid="$1"
|
||||
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
|
||||
return 1
|
||||
fi
|
||||
# Check that it's only digits
|
||||
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate IMEI (simple check)
|
||||
validate_imei() {
|
||||
local imei="$1"
|
||||
if [ -z "$imei" ]; then
|
||||
return 0 # IMEI is optional
|
||||
fi
|
||||
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate band list
|
||||
validate_bands() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
return 0 # Empty is valid
|
||||
fi
|
||||
# Check format (comma-separated numbers)
|
||||
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to validate network type
|
||||
validate_network_type() {
|
||||
local net_type="$1"
|
||||
case "$net_type" in
|
||||
"LTE" | "NR5G" | "LTE:NR5G")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to validate PDP type
|
||||
validate_pdp_type() {
|
||||
local pdp_type="$1"
|
||||
case "$pdp_type" in
|
||||
"IP" | "IPV6" | "IPV4V6")
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_ttl() {
|
||||
local ttl="$1"
|
||||
if [ -z "$ttl" ]; then
|
||||
return 0 # Empty is valid (will be treated as 0/disabled)
|
||||
fi
|
||||
# Check that TTL is a number between 0 and 255
|
||||
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if a profile with given ICCID exists
|
||||
find_profile_by_iccid() {
|
||||
local iccid="$1"
|
||||
# Get all profile indices
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
if [ "$current_iccid" = "$iccid" ]; then
|
||||
echo "$profile_index"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to check for duplicate name (excluding current profile)
|
||||
check_duplicate_name() {
|
||||
local name="$1"
|
||||
local current_iccid="$2"
|
||||
|
||||
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
|
||||
|
||||
for profile_index in $profile_indices; do
|
||||
local iccid=$(uci -q get quecprofiles.$profile_index.iccid)
|
||||
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
|
||||
|
||||
# Skip the current profile we're editing
|
||||
if [ "$iccid" = "$current_iccid" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$profile_name" = "$name" ]; then
|
||||
return 0 # Found duplicate
|
||||
fi
|
||||
done
|
||||
|
||||
return 1 # No duplicate
|
||||
}
|
||||
|
||||
# Function to update an existing profile
|
||||
update_profile() {
|
||||
local profile_index="$1"
|
||||
local name="$2"
|
||||
local imei="$3"
|
||||
local apn="$4"
|
||||
local pdp_type="$5"
|
||||
local lte_bands="$6"
|
||||
local sa_nr5g_bands="$7"
|
||||
local nsa_nr5g_bands="$8"
|
||||
local network_type="$9"
|
||||
local ttl="${10}"
|
||||
|
||||
# Update the profile in UCI config
|
||||
uci -q batch <<EOF
|
||||
set quecprofiles.$profile_index.name='$name'
|
||||
set quecprofiles.$profile_index.imei='$imei'
|
||||
set quecprofiles.$profile_index.apn='$apn'
|
||||
set quecprofiles.$profile_index.pdp_type='$pdp_type'
|
||||
set quecprofiles.$profile_index.lte_bands='$lte_bands'
|
||||
set quecprofiles.$profile_index.sa_nr5g_bands='$sa_nr5g_bands'
|
||||
set quecprofiles.$profile_index.nsa_nr5g_bands='$nsa_nr5g_bands'
|
||||
set quecprofiles.$profile_index.network_type='$network_type'
|
||||
set quecprofiles.$profile_index.ttl='$ttl'
|
||||
commit quecprofiles
|
||||
EOF
|
||||
|
||||
# Check if the operation was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
log_message "Successfully updated profile '$name'" "info"
|
||||
|
||||
# Remove the applied flag file to force reapplication on next check
|
||||
rm -f "$APPLIED_FLAG"
|
||||
|
||||
# Touch the check trigger file to force daemon to check ASAP
|
||||
touch "$CHECK_TRIGGER"
|
||||
|
||||
log_message "Triggered profile check for updated profile '$name'" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to update profile '$name'" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Output debug info
|
||||
log_message "Received edit profile request" "debug"
|
||||
|
||||
# Ensure UCI config exists
|
||||
if [ ! -f /etc/config/quecprofiles ]; then
|
||||
log_message "quecprofiles config does not exist" "error"
|
||||
output_json "error" "Configuration file not found"
|
||||
fi
|
||||
|
||||
# Get POST data
|
||||
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||
# Get content length
|
||||
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
|
||||
|
||||
if [ -n "$CONTENT_LENGTH" ]; then
|
||||
# Read POST data
|
||||
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
|
||||
|
||||
# Debug log
|
||||
log_message "Received POST data: $POST_DATA" "debug"
|
||||
|
||||
# Parse JSON with jsonfilter if available
|
||||
if command -v jsonfilter >/dev/null 2>&1; then
|
||||
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
|
||||
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
|
||||
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
|
||||
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
|
||||
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
|
||||
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
|
||||
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
|
||||
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
|
||||
|
||||
log_message "Parsed JSON data for profile: $name" "debug"
|
||||
else
|
||||
# If jsonfilter is not available, try basic parsing
|
||||
# This is less reliable but might work for simple cases
|
||||
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
|
||||
|
||||
log_message "Basic parsing for profile: $name" "warn"
|
||||
fi
|
||||
else
|
||||
log_message "No content length specified" "error"
|
||||
output_json "error" "No data received"
|
||||
fi
|
||||
else
|
||||
# URL parameters for GET requests (less secure, but supported for testing)
|
||||
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
|
||||
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
|
||||
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
|
||||
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
|
||||
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
|
||||
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
|
||||
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
|
||||
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
|
||||
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
|
||||
|
||||
# URL decode values
|
||||
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
|
||||
|
||||
log_message "Using URL parameters" "warn"
|
||||
fi
|
||||
|
||||
# Sanitize inputs
|
||||
iccid=$(sanitize "${iccid:-}")
|
||||
name=$(sanitize "${name:-}")
|
||||
imei=$(sanitize "${imei:-}")
|
||||
apn=$(sanitize "${apn:-}")
|
||||
pdp_type=$(sanitize "${pdp_type:-IP}")
|
||||
lte_bands=$(sanitize "${lte_bands:-}")
|
||||
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
|
||||
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
|
||||
network_type=$(sanitize "${network_type:-LTE}")
|
||||
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
|
||||
|
||||
# Output debug info
|
||||
log_message "Editing profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
|
||||
|
||||
# Validate required inputs
|
||||
if [ -z "$iccid" ]; then
|
||||
log_message "ICCID is missing" "error"
|
||||
output_json "error" "ICCID is required to identify the profile"
|
||||
fi
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
log_message "Profile name is missing" "error"
|
||||
output_json "error" "Profile name is required"
|
||||
fi
|
||||
|
||||
if [ -z "$apn" ]; then
|
||||
log_message "APN is missing" "error"
|
||||
output_json "error" "APN is required"
|
||||
fi
|
||||
|
||||
# Validate input formats
|
||||
if ! validate_iccid "$iccid"; then
|
||||
log_message "Invalid ICCID format: $iccid" "error"
|
||||
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
|
||||
fi
|
||||
|
||||
if ! validate_imei "$imei"; then
|
||||
log_message "Invalid IMEI format: $imei" "error"
|
||||
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
|
||||
fi
|
||||
|
||||
if ! validate_bands "$lte_bands"; then
|
||||
log_message "Invalid LTE bands format: $lte_bands" "error"
|
||||
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$sa_nr5g_bands"; then
|
||||
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
|
||||
fi
|
||||
|
||||
if ! validate_bands "$nsa_nr5g_bands"; then
|
||||
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
|
||||
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
|
||||
fi
|
||||
|
||||
if ! validate_network_type "$network_type"; then
|
||||
log_message "Invalid network type: $network_type" "error"
|
||||
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
|
||||
fi
|
||||
|
||||
if ! validate_pdp_type "$pdp_type"; then
|
||||
log_message "Invalid PDP type: $pdp_type" "error"
|
||||
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
|
||||
fi
|
||||
|
||||
if ! validate_ttl "$ttl"; then
|
||||
log_message "Invalid TTL value: $ttl" "error"
|
||||
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
|
||||
fi
|
||||
|
||||
# Find profile to edit
|
||||
profile_index=$(find_profile_by_iccid "$iccid")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Profile with ICCID $iccid not found" "error"
|
||||
output_json "error" "Profile not found"
|
||||
fi
|
||||
|
||||
# Check for duplicate name
|
||||
if check_duplicate_name "$name" "$iccid"; then
|
||||
log_message "Duplicate profile name: $name" "error"
|
||||
output_json "error" "A profile with this name already exists"
|
||||
fi
|
||||
|
||||
# Update profile
|
||||
if update_profile "$profile_index" "$name" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"; then
|
||||
# Trigger immediate profile application
|
||||
touch "/tmp/quecprofiles_check"
|
||||
chmod 644 "/tmp/quecprofiles_check"
|
||||
log_message "Triggered immediate profile check after update" "info"
|
||||
|
||||
# Create a clean JSON response with properly escaped quotes
|
||||
printf '{"status":"success","message":"Profile updated successfully","data":{"name":"%s","iccid":"%s","imei":"%s","apn":"%s","pdp_type":"%s","lte_bands":"%s","nr5g_bands":"%s","network_type":"%s"}}' \
|
||||
"$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"
|
||||
|
||||
log_message "Profile updated successfully: $name" "info"
|
||||
|
||||
# Note: The conditional trigger is replaced with the direct trigger above
|
||||
else
|
||||
printf '{"status":"error","message":"Failed to update profile. Please check system logs."}'
|
||||
log_message "Failed to update profile: $name" "error"
|
||||
fi
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Set content type for JSON response
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# Get system uptime in seconds from /proc/uptime
|
||||
read uptime idle < /proc/uptime
|
||||
uptime=${uptime%.*} # Remove decimal part
|
||||
|
||||
# Calculate days, hours, minutes, seconds
|
||||
days=$((uptime/86400))
|
||||
hours=$(((uptime%86400)/3600))
|
||||
minutes=$(((uptime%3600)/60))
|
||||
seconds=$((uptime%60))
|
||||
|
||||
# Format uptime string
|
||||
uptime_str=""
|
||||
[ $days -gt 0 ] && uptime_str="${days}d "
|
||||
[ $hours -gt 0 ] && uptime_str="${uptime_str}${hours}h "
|
||||
[ $minutes -gt 0 ] && uptime_str="${uptime_str}${minutes}m "
|
||||
uptime_str="${uptime_str}${seconds}s"
|
||||
|
||||
# Create and output JSON response
|
||||
cat << EOF
|
||||
{
|
||||
"status": "success",
|
||||
"timestamp": "$(date -Iseconds)",
|
||||
"uptime": {
|
||||
"total_seconds": $uptime,
|
||||
"days": $days,
|
||||
"hours": $hours,
|
||||
"minutes": $minutes,
|
||||
"seconds": $seconds,
|
||||
"formatted": "${uptime_str}"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Send CGI headers first
|
||||
echo "Content-Type: application/json"
|
||||
echo "Cache-Control: no-cache"
|
||||
echo
|
||||
|
||||
# Initialize variables for file paths
|
||||
APN_SCRIPT="/etc/quecmanager/apn_profile/apnProfiles.sh"
|
||||
IMEI_SCRIPT="/etc/quecmanager/imei_profile/imeiProfiles.sh"
|
||||
|
||||
# Function to output JSON
|
||||
output_json() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
|
||||
}
|
||||
|
||||
# Function to execute script if it exists
|
||||
execute_if_exists() {
|
||||
local script_path="$1"
|
||||
|
||||
if [ -f "$script_path" ] && [ -x "$script_path" ]; then
|
||||
$script_path >/dev/null 2>&1
|
||||
return $?
|
||||
fi
|
||||
return 2
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
scripts_executed=0
|
||||
has_error=0
|
||||
|
||||
# Try to execute APN script
|
||||
execute_if_exists "$APN_SCRIPT"
|
||||
apn_result=$?
|
||||
if [ $apn_result -eq 0 ]; then
|
||||
scripts_executed=$(($scripts_executed + 1))
|
||||
elif [ $apn_result -eq 1 ]; then
|
||||
has_error=1
|
||||
fi
|
||||
|
||||
# Try to execute IMEI script
|
||||
execute_if_exists "$IMEI_SCRIPT"
|
||||
imei_result=$?
|
||||
if [ $imei_result -eq 0 ]; then
|
||||
scripts_executed=$(($scripts_executed + 1))
|
||||
elif [ $imei_result -eq 1 ]; then
|
||||
has_error=1
|
||||
fi
|
||||
|
||||
# Output appropriate message based on results
|
||||
if [ $scripts_executed -eq 0 ]; then
|
||||
output_json "info" "No scripts to restart"
|
||||
elif [ $has_error -eq 1 ]; then
|
||||
output_json "error" "Error executing one or more scripts"
|
||||
else
|
||||
output_json "success" "Scripts restarted successfully"
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
@@ -0,0 +1,672 @@
|
||||
#!/bin/sh
|
||||
# AT Queue Manager for OpenWRT with Preemption Support and Token System
|
||||
# Located in /www/cgi-bin/services/at_queue_manager
|
||||
|
||||
# Constants
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
QUEUE_FILE="$QUEUE_DIR/queue"
|
||||
ACTIVE_FILE="$QUEUE_DIR/active"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
LOCK_DIR="$QUEUE_DIR/lock"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
MAX_TIMEOUT=240
|
||||
CLEANUP_INTERVAL=300 # 5 minutes in seconds
|
||||
RESULTS_MAX_AGE=3600 # 1 hour in seconds
|
||||
POLL_INTERVAL=0.01
|
||||
PREEMPTION_THRESHOLD=2 # 3 seconds threshold for preemption
|
||||
TOKEN_TIMEOUT=30 # seconds before token expires
|
||||
|
||||
# Utility function for JSON escaping
|
||||
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$//'
|
||||
}
|
||||
|
||||
# Exclusive lock functions
|
||||
acquire_lock() {
|
||||
local timeout=10
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $timeout ]; do
|
||||
if mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||
logger -t at_queue -p daemon.debug "Lock acquired"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock after $timeout attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
release_lock() {
|
||||
if [ -d "$LOCK_DIR" ]; then
|
||||
rmdir "$LOCK_DIR" 2>/dev/null
|
||||
logger -t at_queue -p daemon.debug "Lock released"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.error "Lock directory doesn't exist"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Ensure required directories exist
|
||||
init_queue_system() {
|
||||
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR"
|
||||
touch "$QUEUE_FILE"
|
||||
chmod 755 "$QUEUE_DIR"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
chmod 755 "$RESULTS_DIR"
|
||||
logger -t at_queue -p daemon.info "Queue system initialized"
|
||||
}
|
||||
|
||||
# Cleanup old results and tracking files
|
||||
cleanup_old_results() {
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Clean up old execution tracking files
|
||||
find "$QUEUE_DIR" -name "pid.*" -type f -mmin +60 -delete 2>/dev/null
|
||||
find "$QUEUE_DIR" -name "*.exit" -type f -mmin +60 -delete 2>/dev/null
|
||||
find "$QUEUE_DIR" -name "start_time.*" -type f -mmin +60 -delete 2>/dev/null
|
||||
logger -t at_queue -p daemon.debug "Cleaned up old tracking files"
|
||||
|
||||
# Use find with -delete and basic timestamp check for OpenWRT
|
||||
find "$RESULTS_DIR" -name "*.json" -type f -mmin +60 -delete 2>/dev/null || {
|
||||
# Fallback method if find fails
|
||||
for file in "$RESULTS_DIR"/*.json; do
|
||||
[ -f "$file" ] || continue
|
||||
local file_time=$(stat -c %Y "$file")
|
||||
if [ $((current_time - file_time)) -gt $RESULTS_MAX_AGE ]; then
|
||||
rm -f "$file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Check for expired token
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local token_time=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
if [ $((current_time - token_time)) -gt $TOKEN_TIMEOUT ]; then
|
||||
local token_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
logger -t at_queue -p daemon.warn "Removing expired token from $token_holder"
|
||||
rm -f "$TOKEN_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Cleanup: Removed files older than 1 hour"
|
||||
}
|
||||
|
||||
# Generate unique command ID
|
||||
generate_command_id() {
|
||||
echo "$(date +%s)_$(head -c 8 /dev/urandom | hexdump -v -e '1/1 "%02x"')"
|
||||
}
|
||||
|
||||
# Start tracking command execution time
|
||||
start_execution_tracking() {
|
||||
local cmd_id="$1"
|
||||
local pid="$2"
|
||||
local start_time=$(date +%s)
|
||||
|
||||
echo "$start_time" > "$QUEUE_DIR/start_time.$cmd_id"
|
||||
echo "$pid" > "$QUEUE_DIR/pid.$cmd_id"
|
||||
chmod 644 "$QUEUE_DIR/start_time.$cmd_id"
|
||||
chmod 644 "$QUEUE_DIR/pid.$cmd_id"
|
||||
logger -t at_queue -p daemon.debug "Started tracking command $cmd_id (PID: $pid)"
|
||||
}
|
||||
|
||||
# Check if running command should be preempted
|
||||
should_preempt() {
|
||||
local current_cmd_id="$1"
|
||||
local new_priority="$2"
|
||||
|
||||
if [ ! -f "$QUEUE_DIR/start_time.$current_cmd_id" ]; then
|
||||
logger -t at_queue -p daemon.debug "No start time found for $current_cmd_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local start_time=$(cat "$QUEUE_DIR/start_time.$current_cmd_id")
|
||||
local current_time=$(date +%s)
|
||||
local execution_time=$((current_time - start_time))
|
||||
|
||||
# Get current command's priority
|
||||
local current_priority
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
current_priority=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.priority')
|
||||
else
|
||||
logger -t at_queue -p daemon.debug "No active command found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $execution_time -gt $PREEMPTION_THRESHOLD ] && [ $new_priority -lt $current_priority ]; then
|
||||
logger -t at_queue -p daemon.info "Command $current_cmd_id (priority $current_priority) running for ${execution_time}s is eligible for preemption by priority $new_priority"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.debug "Command $current_cmd_id not eligible for preemption (time: ${execution_time}s, current priority: $current_priority, new priority: $new_priority)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Handle command preemption
|
||||
preempt_command() {
|
||||
local cmd_id="$1"
|
||||
local pid_file="$QUEUE_DIR/pid.$cmd_id"
|
||||
|
||||
if [ -f "$pid_file" ]; then
|
||||
local pid=$(cat "$pid_file")
|
||||
logger -t at_queue -p daemon.info "Preempting command $cmd_id (PID: $pid)"
|
||||
|
||||
# Send SIGTERM first
|
||||
kill -TERM $pid 2>/dev/null
|
||||
|
||||
# Brief wait for graceful termination
|
||||
sleep 0.1
|
||||
|
||||
# Force kill if still running
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
kill -KILL $pid 2>/dev/null
|
||||
logger -t at_queue -p daemon.warn "Forced termination of command $cmd_id"
|
||||
fi
|
||||
|
||||
# Record preemption result
|
||||
write_preemption_result "$cmd_id"
|
||||
|
||||
# Cleanup command files
|
||||
rm -f "$pid_file" "$QUEUE_DIR/start_time.$cmd_id" "$QUEUE_DIR/$cmd_id.exit"
|
||||
[ -f "$ACTIVE_FILE" ] && rm -f "$ACTIVE_FILE"
|
||||
|
||||
logger -t at_queue -p daemon.info "Command $cmd_id preemption complete"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.warn "No PID file found for command $cmd_id"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Record result for preempted command
|
||||
write_preemption_result() {
|
||||
local cmd_id="$1"
|
||||
local end_time=$(date +%s%3N)
|
||||
local start_time
|
||||
|
||||
if [ -f "$QUEUE_DIR/start_time.$cmd_id" ]; then
|
||||
start_time=$(cat "$QUEUE_DIR/start_time.$cmd_id")000
|
||||
else
|
||||
start_time=$end_time
|
||||
fi
|
||||
|
||||
local duration=$((end_time - start_time))
|
||||
local command_text=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.command')
|
||||
|
||||
local response=$(cat << EOF
|
||||
{
|
||||
"command": {
|
||||
"id": "$cmd_id",
|
||||
"text": "$(escape_json "$command_text")",
|
||||
"timestamp": "$(date -Iseconds)"
|
||||
},
|
||||
"response": {
|
||||
"status": "preempted",
|
||||
"raw_output": "Command preempted by higher priority task",
|
||||
"completion_time": "$end_time",
|
||||
"duration_ms": $duration
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
|
||||
chmod 644 "$RESULTS_DIR/$cmd_id.json"
|
||||
logger -t at_queue -p daemon.info "Recorded preemption result for command $cmd_id (duration: ${duration}ms)"
|
||||
}
|
||||
|
||||
# Request a token for direct sms_tool execution
|
||||
request_token() {
|
||||
local requestor_id="$1"
|
||||
local priority="${2:-10}"
|
||||
local timeout="${3:-10}"
|
||||
|
||||
# Acquire lock first
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for token request"
|
||||
echo "{\"error\":\"Could not acquire lock\",\"status\":\"denied\"}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if token file exists (someone else has the token)
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority')
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> TOKEN_TIMEOUT seconds old)
|
||||
if [ $((current_time - timestamp)) -gt $TOKEN_TIMEOUT ]; then
|
||||
logger -t at_queue -p daemon.warn "Found expired token from $current_holder, releasing"
|
||||
rm -f "$TOKEN_FILE"
|
||||
# Check for priority preemption
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
logger -t at_queue -p daemon.info "Preempting token from $current_holder (priority: $current_priority) for $requestor_id (priority: $priority)"
|
||||
rm -f "$TOKEN_FILE"
|
||||
else
|
||||
# Token in use and cannot be preempted
|
||||
release_lock
|
||||
echo "{\"status\":\"denied\",\"holder\":\"$current_holder\",\"priority\":$current_priority}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also check if there's an active command from the queue
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
local active_id=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.id')
|
||||
local active_priority=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.priority')
|
||||
|
||||
# Only preempt if priority is higher
|
||||
if [ $priority -ge $active_priority ]; then
|
||||
release_lock
|
||||
echo "{\"status\":\"denied\",\"holder\":\"$active_id\",\"priority\":$active_priority}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Direct execution with higher priority than active queue command"
|
||||
fi
|
||||
|
||||
# Grant token
|
||||
local token_data="{\"id\":\"$requestor_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}"
|
||||
echo "$token_data" > "$TOKEN_FILE"
|
||||
chmod 644 "$TOKEN_FILE"
|
||||
|
||||
release_lock
|
||||
echo "{\"status\":\"granted\",\"id\":\"$requestor_id\",\"timeout\":$timeout}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Release a previously acquired token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for token release"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE"
|
||||
logger -t at_queue -p daemon.debug "Token released by $requestor_id"
|
||||
release_lock
|
||||
echo "{\"status\":\"released\"}"
|
||||
return 0
|
||||
else
|
||||
logger -t at_queue -p daemon.warn "Token release attempted by $requestor_id but held by $current_holder"
|
||||
fi
|
||||
else
|
||||
logger -t at_queue -p daemon.warn "Token release attempted but no token exists"
|
||||
fi
|
||||
|
||||
release_lock
|
||||
echo "{\"status\":\"not_found\"}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Add command to queue with preemption support
|
||||
enqueue_command() {
|
||||
local cmd="$1"
|
||||
local priority="${2:-10}"
|
||||
local cmd_id=$(generate_command_id)
|
||||
local timestamp=$(date -Iseconds)
|
||||
|
||||
# Ensure queue directory exists
|
||||
[ ! -d "$QUEUE_DIR" ] && init_queue_system
|
||||
|
||||
logger -t at_queue -p daemon.info "Enqueuing command: $cmd (priority: $priority, id: $cmd_id)"
|
||||
|
||||
# Acquire lock for queue modification
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for enqueuing command"
|
||||
echo "{\"error\":\"Queue lock acquisition failed\",\"command\":\"$cmd\"}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for active command that can be preempted
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
local active_cmd_id=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.id')
|
||||
if should_preempt "$active_cmd_id" "$priority"; then
|
||||
preempt_command "$active_cmd_id"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create command entry
|
||||
local entry="{\"id\":\"$cmd_id\",\"command\":\"$(escape_json "$cmd")\",\"priority\":$priority,\"timestamp\":\"$timestamp\"}"
|
||||
|
||||
if [ "$priority" = "1" ]; then
|
||||
# High priority - prepend to queue
|
||||
local temp_file=$(mktemp)
|
||||
echo "$entry" > "$temp_file"
|
||||
cat "$QUEUE_FILE" >> "$temp_file"
|
||||
mv "$temp_file" "$QUEUE_FILE"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
logger -t at_queue -p daemon.info "Added high priority command to front of queue"
|
||||
else
|
||||
# Normal priority - append to queue
|
||||
echo "$entry" >> "$QUEUE_FILE"
|
||||
logger -t at_queue -p daemon.info "Added normal priority command to end of queue"
|
||||
fi
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
|
||||
echo "{\"command_id\":\"$cmd_id\",\"status\":\"queued\"}"
|
||||
}
|
||||
|
||||
# Get next command from queue
|
||||
dequeue_command() {
|
||||
if [ ! -s "$QUEUE_FILE" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Acquire lock
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for dequeuing command"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local cmd_entry=$(head -n 1 "$QUEUE_FILE")
|
||||
local temp_file=$(mktemp)
|
||||
tail -n +2 "$QUEUE_FILE" > "$temp_file"
|
||||
mv "$temp_file" "$QUEUE_FILE"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
|
||||
echo "$cmd_entry" > "$ACTIVE_FILE"
|
||||
chmod 644 "$ACTIVE_FILE"
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
|
||||
logger -t at_queue -p daemon.debug "Dequeued command: $(echo "$cmd_entry" | jsonfilter -e '@.command')"
|
||||
echo "$cmd_entry"
|
||||
}
|
||||
|
||||
# Clean and format AT command output
|
||||
clean_output() {
|
||||
local output="$1"
|
||||
|
||||
# First format AT command responses for readability
|
||||
output=$(echo "$output" | sed -E '
|
||||
# Add newline after AT commands
|
||||
s/(AT\+[A-Z0-9]+[^ ]*) +/\1\n/g
|
||||
# Add newline before +RESPONSE lines
|
||||
s/ +(\+[A-Z0-9]+:)/\n\1/g
|
||||
# Add newline before OK/ERROR
|
||||
s/ +(OK|ERROR)$/\n\1/g
|
||||
')
|
||||
|
||||
# Then escape the formatted output for JSON
|
||||
output=$(escape_json "$output")
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
# Execute AT command with optimized timeout handling
|
||||
execute_with_timeout() {
|
||||
local command="$1"
|
||||
local timeout="$2"
|
||||
local cmd_id="$3"
|
||||
local output_file=$(mktemp)
|
||||
|
||||
# Start command in background with immediate output
|
||||
(sms_tool -D at "$command" > "$output_file" 2>&1; echo $? > "$QUEUE_DIR/$cmd_id.exit") &
|
||||
local pid=$!
|
||||
|
||||
# Start execution tracking
|
||||
start_execution_tracking "$cmd_id" "$pid"
|
||||
|
||||
logger -t at_queue -p daemon.debug "Started command execution: $command (PID: $pid)"
|
||||
|
||||
# Wait for completion with shorter polling interval
|
||||
local start_time=$(date +%s)
|
||||
local elapsed=0
|
||||
|
||||
while [ $elapsed -lt "$timeout" ]; do
|
||||
if [ -f "$QUEUE_DIR/$cmd_id.exit" ]; then
|
||||
local exit_code=$(cat "$QUEUE_DIR/$cmd_id.exit")
|
||||
local output=$(cat "$output_file")
|
||||
|
||||
# Cleanup
|
||||
rm -f "$QUEUE_DIR/pid.$cmd_id" "$QUEUE_DIR/$cmd_id.exit" "$output_file" "$QUEUE_DIR/start_time.$cmd_id"
|
||||
|
||||
logger -t at_queue -p daemon.debug "Command completed with exit code $exit_code"
|
||||
echo "$output"
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
elapsed=$(($(date +%s) - start_time))
|
||||
sleep $POLL_INTERVAL
|
||||
done
|
||||
|
||||
# Handle timeout
|
||||
if [ -f "$QUEUE_DIR/pid.$cmd_id" ]; then
|
||||
local pid=$(cat "$QUEUE_DIR/pid.$cmd_id")
|
||||
kill $pid 2>/dev/null
|
||||
sleep 0.1
|
||||
# Force kill if still running
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
kill -KILL $pid 2>/dev/null
|
||||
fi
|
||||
|
||||
local partial_output=$(cat "$output_file" 2>/dev/null || echo "")
|
||||
|
||||
# Cleanup
|
||||
rm -f "$QUEUE_DIR/pid.$cmd_id" "$QUEUE_DIR/$cmd_id.exit" "$output_file" "$QUEUE_DIR/start_time.$cmd_id"
|
||||
|
||||
logger -t at_queue -p daemon.warn "Command timed out after $timeout seconds"
|
||||
echo "${partial_output:-Command timed out after $timeout seconds}"
|
||||
fi
|
||||
|
||||
return 124
|
||||
}
|
||||
|
||||
# Execute AT command and handle response
|
||||
execute_command() {
|
||||
local cmd_entry="$1"
|
||||
local cmd_id=$(echo "$cmd_entry" | jsonfilter -e '@.id')
|
||||
local cmd_text=$(echo "$cmd_entry" | jsonfilter -e '@.command')
|
||||
local priority=$(echo "$cmd_entry" | jsonfilter -e '@.priority')
|
||||
|
||||
local start_time=$(date +%s%3N)
|
||||
|
||||
logger -t at_queue -p daemon.info "Executing command $cmd_id: $cmd_text (priority: $priority)"
|
||||
|
||||
# Execute command with timeout
|
||||
local result=$(execute_with_timeout "$cmd_text" $MAX_TIMEOUT "$cmd_id")
|
||||
local exit_code=$?
|
||||
local end_time=$(date +%s%3N)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Determine status and log level
|
||||
local status="error"
|
||||
local log_level="error"
|
||||
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
status="timeout"
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id timed out after ${duration}ms"
|
||||
elif echo "$result" | grep -q "OK"; then
|
||||
status="success"
|
||||
log_level="info"
|
||||
logger -t at_queue -p daemon.info "Command $cmd_id completed successfully in ${duration}ms"
|
||||
elif echo "$result" | grep -q "CME ERROR"; then
|
||||
status="cme_error"
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id failed with CME ERROR in ${duration}ms"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id failed with general error in ${duration}ms"
|
||||
fi
|
||||
|
||||
# Clean and escape the output
|
||||
local clean_result=$(clean_output "$result")
|
||||
|
||||
# Create JSON response
|
||||
local response=$(cat << EOF
|
||||
{
|
||||
"command": {
|
||||
"id": "$cmd_id",
|
||||
"text": "$(escape_json "$cmd_text")",
|
||||
"timestamp": "$(date -Iseconds)"
|
||||
},
|
||||
"response": {
|
||||
"status": "$status",
|
||||
"raw_output": "$clean_result",
|
||||
"completion_time": "$end_time",
|
||||
"duration_ms": $duration
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Acquire lock for writing result
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for writing result"
|
||||
else
|
||||
# Save response
|
||||
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
|
||||
chmod 644 "$RESULTS_DIR/$cmd_id.json"
|
||||
|
||||
# Clean up active file
|
||||
rm -f "$ACTIVE_FILE"
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
fi
|
||||
|
||||
echo "$response"
|
||||
}
|
||||
|
||||
# Main queue processing function
|
||||
process_queue() {
|
||||
init_queue_system
|
||||
local last_cleanup=$(date +%s)
|
||||
local last_log=$(date +%s) # Add a timestamp for less frequent logging
|
||||
|
||||
# Make sure the lock directory doesn't exist at startup
|
||||
[ -d "$LOCK_DIR" ] && rmdir "$LOCK_DIR" 2>/dev/null
|
||||
|
||||
logger -t at_queue -p daemon.info "Started queue processing daemon"
|
||||
|
||||
while true; do
|
||||
# Quick cleanup check
|
||||
local current_time=$(date +%s)
|
||||
if [ $((current_time - last_cleanup)) -ge $CLEANUP_INTERVAL ]; then
|
||||
cleanup_old_results
|
||||
last_cleanup=$current_time
|
||||
fi
|
||||
|
||||
# Skip processing if token is granted to someone
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local token_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
local token_time=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token
|
||||
if [ $((current_time - token_time)) -gt $TOKEN_TIMEOUT ]; then
|
||||
logger -t at_queue -p daemon.warn "Removing expired token from $token_holder"
|
||||
rm -f "$TOKEN_FILE"
|
||||
else
|
||||
# Log pause status only every 5 seconds to reduce log spam
|
||||
if [ $((current_time - last_log)) -ge 5 ]; then
|
||||
logger -t at_queue -p daemon.debug "Queue processing paused, token held by $token_holder"
|
||||
last_log=$current_time
|
||||
fi
|
||||
sleep $POLL_INTERVAL
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Process queue if not empty and no active command
|
||||
if [ -s "$QUEUE_FILE" ] && [ ! -f "$ACTIVE_FILE" ]; then
|
||||
local cmd_entry=$(dequeue_command)
|
||||
if [ -n "$cmd_entry" ]; then
|
||||
execute_command "$cmd_entry"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep $POLL_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# CGI command handling
|
||||
if [ "${SCRIPT_NAME}" != "" ]; then
|
||||
# Output headers
|
||||
if [ "$HTTP_HEADERS" != "0" ]; then
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Parse query string for CGI mode
|
||||
eval $(echo "$QUERY_STRING" | sed 's/&/;/g')
|
||||
|
||||
case "$action" in
|
||||
"enqueue")
|
||||
if [ -n "$command" ]; then
|
||||
logger -t at_queue -p daemon.info "CGI: Received enqueue request for command: $command"
|
||||
enqueue_command "$command" "$priority"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "CGI: Empty command received"
|
||||
echo "{\"error\":\"No command specified\"}"
|
||||
fi
|
||||
;;
|
||||
"status")
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
logger -t at_queue -p daemon.debug "CGI: Status request - queue active"
|
||||
cat "$ACTIVE_FILE"
|
||||
else
|
||||
logger -t at_queue -p daemon.debug "CGI: Status request - queue idle"
|
||||
echo "{\"status\":\"idle\"}"
|
||||
fi
|
||||
;;
|
||||
"request_token")
|
||||
if [ -n "$id" ]; then
|
||||
logger -t at_queue -p daemon.info "Token request from $id (priority: ${priority:-10})"
|
||||
request_token "$id" "${priority:-10}" "${timeout:-10}"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Token request missing ID"
|
||||
echo "{\"error\":\"No requestor ID specified\",\"status\":\"denied\"}"
|
||||
fi
|
||||
;;
|
||||
"release_token")
|
||||
if [ -n "$id" ]; then
|
||||
logger -t at_queue -p daemon.info "Token release from $id"
|
||||
release_token "$id"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Token release missing ID"
|
||||
echo "{\"error\":\"No requestor ID specified\",\"status\":\"denied\"}"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
logger -t at_queue -p daemon.error "CGI: Invalid action received: $action"
|
||||
echo "{\"error\":\"Invalid action\"}"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# CLI command handling
|
||||
if [ "$1" = "enqueue" ] && [ -n "$2" ]; then
|
||||
enqueue_command "$2" "${3:-10}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# If not run as CGI, start queue processing
|
||||
if [ "${SCRIPT_NAME}" = "" ] && [ -z "$1" ]; then
|
||||
process_queue
|
||||
fi
|
||||
@@ -0,0 +1,198 @@
|
||||
#!/bin/sh
|
||||
# Configuration
|
||||
LOGDIR="/www/signal_graphs"
|
||||
MAX_ENTRIES=10
|
||||
INTERVAL=60
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOCK_FILE="/tmp/signal_metrics.lock"
|
||||
METRICS_PID_FILE="/tmp/signal_metrics.pid"
|
||||
MAX_TOKEN_WAIT=5 # seconds to wait for token acquisition
|
||||
|
||||
# Ensure required directories exist
|
||||
mkdir -p "$LOGDIR" "$QUEUE_DIR"
|
||||
|
||||
# Check if another instance is running
|
||||
check_running() {
|
||||
if [ -f "$METRICS_PID_FILE" ]; then
|
||||
pid=$(cat "$METRICS_PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
rm -f "$METRICS_PID_FILE" 2>/dev/null
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Acquire token directly (minimized version)
|
||||
acquire_token() {
|
||||
local metrics_id="METRICS_$(date +%s)_$$"
|
||||
local priority=20 # Lowest priority for metrics
|
||||
local max_attempts=20
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
# Check current token
|
||||
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
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Wait and try again
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token
|
||||
echo "{\"id\":\"$metrics_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got it
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$metrics_id" ]; then
|
||||
echo "$metrics_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Release token directly
|
||||
release_token() {
|
||||
local metrics_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$metrics_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute AT command directly
|
||||
execute_at_command() {
|
||||
local CMD="$1"
|
||||
sms_tool at "$CMD" -t 3 2>/dev/null
|
||||
}
|
||||
|
||||
# Process all metrics commands with a single token
|
||||
process_all_metrics() {
|
||||
# Try to get token
|
||||
local metrics_id=$(acquire_token)
|
||||
if [ -z "$metrics_id" ]; then
|
||||
logger -t at_queue -p daemon.warn "Could not acquire token for metrics - will try again later"
|
||||
return 1
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Processing all metrics with token $metrics_id"
|
||||
|
||||
# Execute all metrics commands with the single token
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# RSRP
|
||||
local rsrp_output=$(execute_at_command "AT+QRSRP")
|
||||
if [ -n "$rsrp_output" ] && echo "$rsrp_output" | grep -q "QRSRP"; then
|
||||
local logfile="$LOGDIR/rsrp.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$rsrp_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# RSRQ
|
||||
local rsrq_output=$(execute_at_command "AT+QRSRQ")
|
||||
if [ -n "$rsrq_output" ] && echo "$rsrq_output" | grep -q "QRSRQ"; then
|
||||
local logfile="$LOGDIR/rsrq.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$rsrq_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# SINR
|
||||
local sinr_output=$(execute_at_command "AT+QSINR")
|
||||
if [ -n "$sinr_output" ] && echo "$sinr_output" | grep -q "QSINR"; then
|
||||
local logfile="$LOGDIR/sinr.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$sinr_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# Data usage
|
||||
local usage_output=$(execute_at_command "AT+QGDCNT?;+QGDNRCNT?")
|
||||
if [ -n "$usage_output" ] && echo "$usage_output" | grep -q "QGDCNT\|QGDNRCNT"; then
|
||||
local logfile="$LOGDIR/data_usage.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$usage_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$metrics_id"
|
||||
logger -t at_queue -p daemon.info "Metrics processing completed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main continuous logging function with proper locking
|
||||
start_continuous_logging() {
|
||||
# Check if already running
|
||||
if check_running; then
|
||||
logger -t at_queue -p daemon.error "Signal metrics logging already running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$METRICS_PID_FILE"
|
||||
chmod 644 "$METRICS_PID_FILE"
|
||||
|
||||
sleep 20 # Initial delay to allow system startup
|
||||
logger -t at_queue -p daemon.info "Starting continuous signal metrics logging (PID: $$)"
|
||||
|
||||
trap 'logger -t at_queue -p daemon.info "Stopping signal metrics logging"; rm -f "$METRICS_PID_FILE"; exit 0' INT TERM
|
||||
|
||||
while true; do
|
||||
process_all_metrics
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
}
|
||||
|
||||
# Start the continuous logging
|
||||
start_continuous_logging
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
||||
#!/bin/sh
|
||||
|
||||
# QuecWatch Daemon
|
||||
# Monitors cellular connectivity and performs recovery actions
|
||||
|
||||
# Load UCI configuration functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOG_DIR="/tmp/log/quecwatch"
|
||||
LOG_FILE="$LOG_DIR/quecwatch.log"
|
||||
PID_FILE="/var/run/quecwatch.pid"
|
||||
STATUS_FILE="/tmp/quecwatch_status.json"
|
||||
RETRY_COUNT_FILE="/tmp/quecwatch_retry_count"
|
||||
UCI_CONFIG="quecmanager"
|
||||
MAX_TOKEN_WAIT=10 # Maximum seconds to wait for token acquisition
|
||||
TOKEN_PRIORITY=15 # Medium priority (between profiles and metrics)
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
local message="$1"
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Log to file
|
||||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||||
|
||||
# Log to system log
|
||||
logger -t quecwatch -p "daemon.$level" "$message"
|
||||
}
|
||||
|
||||
# Function to update status
|
||||
update_status() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local retry="${3:-$CURRENT_RETRIES}"
|
||||
local max="${4:-$MAX_RETRIES}"
|
||||
|
||||
# Create JSON status
|
||||
cat > "$STATUS_FILE" <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"retry": $retry,
|
||||
"maxRetries": $max,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
chmod 644 "$STATUS_FILE"
|
||||
|
||||
log_message "Status updated: $status - $message" "debug"
|
||||
}
|
||||
|
||||
# Function to acquire token for AT commands
|
||||
acquire_token() {
|
||||
local requestor_id="QUECWATCH_$(date +%s)_$$"
|
||||
local priority="$TOKEN_PRIORITY"
|
||||
local max_attempts=$MAX_TOKEN_WAIT
|
||||
local attempt=0
|
||||
|
||||
log_message "Attempting to acquire token with priority $priority" "debug"
|
||||
|
||||
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
|
||||
log_message "Found expired token from $current_holder, removing" "debug"
|
||||
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)" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Check if the token is held by a QuecProfile or cell scan
|
||||
if echo "$current_holder" | grep -q "CELL_SCAN"; then
|
||||
log_message "Token held by cell scan (priority: $current_priority), waiting..." "debug"
|
||||
elif echo "$current_holder" | grep -q "QUECPROFILES"; then
|
||||
log_message "Token held by profile application (priority: $current_priority), waiting..." "debug"
|
||||
else
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$requestor_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" = "$requestor_id" ]; then
|
||||
log_message "Successfully acquired token with ID $requestor_id" "debug"
|
||||
echo "$requestor_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to release token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token $requestor_id" "debug"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($requestor_id)" "warn"
|
||||
else
|
||||
log_message "Token file doesn't exist, nothing to release" "debug"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to execute AT command with token
|
||||
execute_at_command() {
|
||||
local cmd="$1"
|
||||
local timeout="${2:-5}"
|
||||
local token_id="$3"
|
||||
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "No valid token provided for command: $cmd" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Executing AT command: $cmd (timeout: ${timeout}s)" "debug"
|
||||
|
||||
# Execute the command with proper timeout
|
||||
local output
|
||||
local status=1
|
||||
|
||||
output=$(sms_tool at "$cmd" -t "$timeout" 2>&1)
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
log_message "AT command failed: $cmd (exit code: $status)" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check internet connectivity
|
||||
check_internet() {
|
||||
local ping_target
|
||||
local ping_count=3
|
||||
|
||||
# Get ping target from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
config_get ping_target quecwatch ping_target
|
||||
|
||||
if [ -z "$ping_target" ]; then
|
||||
log_message "No ping target configured" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Checking internet connectivity to $ping_target" "debug"
|
||||
|
||||
if ping -c $ping_count "$ping_target" > /dev/null 2>&1; then
|
||||
log_message "Internet connectivity check successful" "debug"
|
||||
return 0
|
||||
else
|
||||
log_message "Internet connectivity check failed" "warn"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current SIM slot
|
||||
get_current_sim() {
|
||||
local token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for SIM slot check" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Checking current SIM slot" "debug"
|
||||
|
||||
local result=$(execute_at_command "AT+QUIMSLOT?" 5 "$token_id")
|
||||
local status=$?
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
if [ $status -eq 0 ] && [ -n "$result" ]; then
|
||||
# Extract SIM slot number from response
|
||||
local current_sim=$(echo "$result" | grep -o '+QUIMSLOT: [0-9]' | cut -d' ' -f2)
|
||||
|
||||
if [ -n "$current_sim" ]; then
|
||||
log_message "Current SIM slot: $current_sim" "debug"
|
||||
echo "$current_sim"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "Failed to get current SIM slot" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to switch SIM card
|
||||
switch_sim_card() {
|
||||
local current_sim
|
||||
local target_sim
|
||||
local token_id
|
||||
|
||||
log_message "Starting SIM card switch operation" "info"
|
||||
|
||||
# Get current SIM slot
|
||||
current_sim=$(get_current_sim)
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Failed to get current SIM slot, cannot switch" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine target SIM
|
||||
if [ "$current_sim" = "1" ]; then
|
||||
target_sim=2
|
||||
else
|
||||
target_sim=1
|
||||
fi
|
||||
|
||||
log_message "Attempting to switch from SIM $current_sim to SIM $target_sim" "info"
|
||||
|
||||
# Get token for AT commands
|
||||
token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for SIM switch" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detach from network
|
||||
log_message "Detaching from network" "debug"
|
||||
execute_at_command "AT+COPS=2" 10 "$token_id"
|
||||
sleep 2
|
||||
|
||||
# Switch SIM slot
|
||||
log_message "Switching to SIM slot $target_sim" "debug"
|
||||
local switch_result=$(execute_at_command "AT+QUIMSLOT=$target_sim" 10 "$token_id")
|
||||
local switch_status=$?
|
||||
|
||||
# If switch failed, return error
|
||||
if [ $switch_status -ne 0 ]; then
|
||||
log_message "Failed to switch to SIM $target_sim" "error"
|
||||
release_token "$token_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
|
||||
# Reattach to network
|
||||
log_message "Reattaching to network" "debug"
|
||||
execute_at_command "AT+COPS=0" 10 "$token_id"
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
# Verify switch
|
||||
sleep 10
|
||||
local new_sim=$(get_current_sim)
|
||||
if [ "$new_sim" = "$target_sim" ]; then
|
||||
log_message "Successfully switched to SIM $target_sim" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to verify SIM switch, current SIM is $new_sim" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to perform connection recovery
|
||||
perform_connection_recovery() {
|
||||
local token_id
|
||||
|
||||
log_message "Starting connection recovery" "info"
|
||||
|
||||
# Get token for AT commands
|
||||
token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for connection recovery" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detach from network
|
||||
log_message "Detaching from network" "debug"
|
||||
execute_at_command "AT+COPS=2" 10 "$token_id"
|
||||
sleep 2
|
||||
|
||||
# Reattach to network
|
||||
log_message "Reattaching to network" "debug"
|
||||
execute_at_command "AT+COPS=0" 15 "$token_id"
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
# Verify recovery
|
||||
sleep 10
|
||||
if check_internet; then
|
||||
log_message "Connection recovery successful" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Connection recovery failed" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Load configuration
|
||||
load_config() {
|
||||
# Initialize variables
|
||||
PING_TARGET=""
|
||||
PING_INTERVAL=60
|
||||
PING_FAILURES=3
|
||||
MAX_RETRIES=5
|
||||
CURRENT_RETRIES=0
|
||||
CONNECTION_REFRESH=0
|
||||
REFRESH_COUNT=3
|
||||
AUTO_SIM_FAILOVER=0
|
||||
SIM_FAILOVER_SCHEDULE=0
|
||||
|
||||
# Load from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
|
||||
# Get settings with defaults
|
||||
config_get PING_TARGET quecwatch ping_target
|
||||
config_get PING_INTERVAL quecwatch ping_interval 60
|
||||
config_get PING_FAILURES quecwatch ping_failures 3
|
||||
config_get MAX_RETRIES quecwatch max_retries 5
|
||||
config_get CURRENT_RETRIES quecwatch current_retries 0
|
||||
config_get_bool CONNECTION_REFRESH quecwatch connection_refresh 0
|
||||
config_get REFRESH_COUNT quecwatch refresh_count 3
|
||||
config_get_bool AUTO_SIM_FAILOVER quecwatch auto_sim_failover 0
|
||||
config_get SIM_FAILOVER_SCHEDULE quecwatch sim_failover_schedule 0
|
||||
|
||||
# Validate required settings
|
||||
if [ -z "$PING_TARGET" ]; then
|
||||
log_message "No ping target configured, using default (8.8.8.8)" "warn"
|
||||
PING_TARGET="8.8.8.8"
|
||||
uci set "$UCI_CONFIG.quecwatch.ping_target=$PING_TARGET"
|
||||
uci commit "$UCI_CONFIG"
|
||||
fi
|
||||
|
||||
# Load persisted retry count if available
|
||||
if [ -f "$RETRY_COUNT_FILE" ]; then
|
||||
CURRENT_RETRIES=$(cat "$RETRY_COUNT_FILE")
|
||||
fi
|
||||
|
||||
log_message "Configuration loaded: ping_target=$PING_TARGET, interval=$PING_INTERVAL, failures=$PING_FAILURES, max_retries=$MAX_RETRIES, current_retries=$CURRENT_RETRIES" "info"
|
||||
}
|
||||
|
||||
# Save retry count to both UCI and file
|
||||
save_retry_count() {
|
||||
local count=$1
|
||||
|
||||
# Update UCI
|
||||
uci set "$UCI_CONFIG.quecwatch.current_retries=$count"
|
||||
uci commit "$UCI_CONFIG"
|
||||
|
||||
# Update file for crash recovery
|
||||
echo "$count" > "$RETRY_COUNT_FILE"
|
||||
chmod 644 "$RETRY_COUNT_FILE"
|
||||
|
||||
log_message "Updated retry count to $count" "debug"
|
||||
}
|
||||
|
||||
# Main monitoring function
|
||||
main() {
|
||||
log_message "QuecWatch daemon starting (PID: $$)" "info"
|
||||
|
||||
# Load configuration
|
||||
load_config
|
||||
|
||||
# Initial status update
|
||||
update_status "active" "Monitoring started"
|
||||
|
||||
# Track consecutive failures
|
||||
local failure_count=0
|
||||
|
||||
# For scheduled SIM failover
|
||||
local sim_failover_interval=0
|
||||
local initial_sim=""
|
||||
|
||||
# If auto SIM failover is enabled, store initial SIM slot
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ]; then
|
||||
initial_sim=$(get_current_sim)
|
||||
if [ -n "$initial_sim" ]; then
|
||||
log_message "Auto SIM failover enabled, initial SIM slot: $initial_sim" "info"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
log_message "Starting monitoring cycle" "debug"
|
||||
|
||||
# Check internet connectivity
|
||||
if ! check_internet; then
|
||||
failure_count=$((failure_count + 1))
|
||||
log_message "Connectivity check failed ($failure_count/$PING_FAILURES)" "warn"
|
||||
|
||||
# Update status
|
||||
update_status "warning" "Connection check failed: $failure_count/$PING_FAILURES failures"
|
||||
|
||||
# Check if failure threshold is reached
|
||||
if [ $failure_count -ge $PING_FAILURES ]; then
|
||||
# Reset failure counter
|
||||
failure_count=0
|
||||
|
||||
# Increment retry counter
|
||||
CURRENT_RETRIES=$((CURRENT_RETRIES + 1))
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
|
||||
log_message "Failure threshold reached. Current retry: $CURRENT_RETRIES/$MAX_RETRIES" "warn"
|
||||
update_status "error" "Connection lost, attempt $CURRENT_RETRIES/$MAX_RETRIES to recover"
|
||||
|
||||
# Check if max retries reached
|
||||
if [ $CURRENT_RETRIES -ge $MAX_RETRIES ]; then
|
||||
log_message "Maximum retries reached" "error"
|
||||
|
||||
# Try SIM failover if enabled
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ]; then
|
||||
log_message "Attempting SIM failover" "info"
|
||||
update_status "failover" "Maximum retries reached, attempting SIM failover"
|
||||
|
||||
if switch_sim_card && check_internet; then
|
||||
log_message "SIM failover successful, connection restored" "info"
|
||||
update_status "recovered" "Connection restored via SIM failover"
|
||||
|
||||
# Reset retry counter
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
else
|
||||
log_message "SIM failover failed, system will reboot" "error"
|
||||
update_status "rebooting" "SIM failover failed, system will reboot"
|
||||
|
||||
# Wait briefly and reboot
|
||||
sleep 5
|
||||
reboot
|
||||
fi
|
||||
else
|
||||
log_message "Auto SIM failover disabled, system will reboot" "error"
|
||||
update_status "rebooting" "Maximum retries reached, system will reboot"
|
||||
|
||||
# Wait briefly and reboot
|
||||
sleep 5
|
||||
reboot
|
||||
fi
|
||||
else
|
||||
# Try connection recovery
|
||||
log_message "Attempting connection recovery" "info"
|
||||
update_status "recovering" "Attempting to restore connection"
|
||||
|
||||
if perform_connection_recovery; then
|
||||
log_message "Connection recovery successful" "info"
|
||||
update_status "recovered" "Connection restored"
|
||||
|
||||
# Reset retry counter
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Connection is good
|
||||
if [ $failure_count -gt 0 ] || [ $CURRENT_RETRIES -gt 0 ]; then
|
||||
log_message "Connection restored" "info"
|
||||
update_status "stable" "Connection restored"
|
||||
|
||||
# Reset counters
|
||||
failure_count=0
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
fi
|
||||
|
||||
# Scheduled SIM failover check
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ] && [ "$SIM_FAILOVER_SCHEDULE" -gt 0 ] && [ -n "$initial_sim" ]; then
|
||||
# Get current SIM to check if we're on the backup
|
||||
local current_sim=$(get_current_sim)
|
||||
|
||||
# If we're on backup SIM, check if it's time to try primary again
|
||||
if [ -n "$current_sim" ] && [ "$current_sim" != "$initial_sim" ]; then
|
||||
sim_failover_interval=$((sim_failover_interval + 1))
|
||||
|
||||
# Check if we've reached the scheduled time
|
||||
if [ $((sim_failover_interval * PING_INTERVAL)) -ge $((SIM_FAILOVER_SCHEDULE * 60)) ]; then
|
||||
log_message "Scheduled check: attempting to switch back to primary SIM $initial_sim" "info"
|
||||
update_status "switchback" "Attempting to switch back to primary SIM"
|
||||
|
||||
# Try switching back
|
||||
if switch_sim_card && check_internet; then
|
||||
log_message "Successfully switched back to primary SIM" "info"
|
||||
update_status "stable" "Successfully switched back to primary SIM"
|
||||
else
|
||||
log_message "Failed to switch back to primary SIM, staying on backup" "warn"
|
||||
update_status "stable" "Staying on backup SIM - primary SIM check failed"
|
||||
|
||||
# Switch back to backup SIM
|
||||
current_sim=$(get_current_sim)
|
||||
if [ -n "$current_sim" ] && [ "$current_sim" = "$initial_sim" ]; then
|
||||
switch_sim_card
|
||||
fi
|
||||
fi
|
||||
|
||||
# Reset failover interval
|
||||
sim_failover_interval=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Sleep for the configured interval
|
||||
sleep $PING_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Set up trap for clean shutdown
|
||||
trap 'log_message "Received signal, exiting" "info"; update_status "stopped" "Daemon stopped"; rm -f "$PID_FILE"; exit 0' INT TERM
|
||||
|
||||
# Start the main function
|
||||
main
|
||||
@@ -0,0 +1,429 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Cell Lock Scheduler Daemon
|
||||
# Monitors schedule and applies/restores cell locks as needed
|
||||
|
||||
# Load UCI configuration functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOG_DIR="/tmp/log/cell_lock"
|
||||
LOG_FILE="$LOG_DIR/cell_lock.log"
|
||||
PID_FILE="/var/run/cell_lock_scheduler.pid"
|
||||
STATUS_FILE="/tmp/cell_lock_status.json"
|
||||
UCI_CONFIG="quecmanager"
|
||||
CHECK_INTERVAL=60 # Check schedule every minute
|
||||
MAX_TOKEN_WAIT=15 # Maximum seconds to wait for token acquisition
|
||||
TOKEN_PRIORITY=5 # Higher priority than QuecWatch (which is 15)
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE"
|
||||
|
||||
# Function to log messages
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
local message="$1"
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Log to file
|
||||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||||
|
||||
# Log to system log
|
||||
logger -t cell_lock -p "daemon.$level" "$message"
|
||||
}
|
||||
|
||||
# Function to update status
|
||||
update_status() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local active="${3:-0}"
|
||||
local locked="${4:-0}"
|
||||
|
||||
# Create JSON status
|
||||
cat > "$STATUS_FILE" <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"active": $active,
|
||||
"locked": $locked,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
chmod 644 "$STATUS_FILE"
|
||||
|
||||
log_message "Status updated: $status - $message" "debug"
|
||||
}
|
||||
|
||||
# Function to acquire token for AT commands
|
||||
acquire_token() {
|
||||
local requestor_id="CELLLOCK_$(date +%s)_$$"
|
||||
local priority="$TOKEN_PRIORITY"
|
||||
local max_attempts=$MAX_TOKEN_WAIT
|
||||
local attempt=0
|
||||
|
||||
log_message "Attempting to acquire token with priority $priority" "debug"
|
||||
|
||||
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
|
||||
log_message "Found expired token from $current_holder, removing" "debug"
|
||||
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)" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Check if the token is held by a cell scan
|
||||
if echo "$current_holder" | grep -q "CELL_SCAN"; then
|
||||
log_message "Token held by cell scan (priority: $current_priority), waiting..." "debug"
|
||||
else
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$requestor_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" = "$requestor_id" ]; then
|
||||
log_message "Successfully acquired token with ID $requestor_id" "debug"
|
||||
echo "$requestor_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to release token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token $requestor_id" "debug"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($requestor_id)" "warn"
|
||||
else
|
||||
log_message "Token file doesn't exist, nothing to release" "debug"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to execute AT command with token
|
||||
execute_at_command() {
|
||||
local cmd="$1"
|
||||
local timeout="${2:-10}"
|
||||
local token_id="$3"
|
||||
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "No valid token provided for command: $cmd" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Executing AT command: $cmd (timeout: ${timeout}s)" "debug"
|
||||
|
||||
# Execute the command with proper timeout
|
||||
local output
|
||||
local status=1
|
||||
|
||||
output=$(sms_tool at "$cmd" -t "$timeout" 2>&1)
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
log_message "AT command failed: $cmd (exit code: $status)" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check current lock status
|
||||
check_lock_status() {
|
||||
local token_id="$1"
|
||||
|
||||
log_message "Checking current cell lock status" "debug"
|
||||
|
||||
# Check LTE lock status
|
||||
local lte_status=$(execute_at_command 'AT+QNWLOCK="common/4g"' 5 "$token_id")
|
||||
local nr5g_status=$(execute_at_command 'AT+QNWLOCK="common/5g"' 5 "$token_id")
|
||||
|
||||
# Check if any lock is active
|
||||
if echo "$lte_status" | grep -q '"common/4g",0'; then
|
||||
if echo "$nr5g_status" | grep -q '"common/5g",0'; then
|
||||
log_message "No active cell locks detected" "debug"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "Active cell locks detected" "debug"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to get current lock parameters and save to UCI
|
||||
store_current_lock_params() {
|
||||
local token_id="$1"
|
||||
|
||||
log_message "Storing current lock parameters" "debug"
|
||||
|
||||
# Get LTE lock status
|
||||
local lte_status=$(execute_at_command 'AT+QNWLOCK="common/4g"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters
|
||||
local lte_params=$(echo "$lte_status" | grep -o '"common/4g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.lte_params='$lte_params'"
|
||||
log_message "Stored LTE parameters: $lte_params" "debug"
|
||||
fi
|
||||
|
||||
# Get NR5G lock status
|
||||
local nr5g_status=$(execute_at_command 'AT+QNWLOCK="common/5g"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters
|
||||
local nr5g_params=$(echo "$nr5g_status" | grep -o '"common/5g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.nr5g_params='$nr5g_params'"
|
||||
log_message "Stored NR5G parameters: $nr5g_params" "debug"
|
||||
fi
|
||||
|
||||
# Get persist settings
|
||||
local persist_status=$(execute_at_command 'AT+QNWLOCK="save_ctrl"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters (LTE persist is at index 1, NR5G persist is at index 2)
|
||||
local persist_params=$(echo "$persist_status" | grep -o '"save_ctrl",[^[:space:]]*' | cut -d',' -f2-)
|
||||
local lte_persist=$(echo "$persist_params" | cut -d',' -f1)
|
||||
local nr5g_persist=$(echo "$persist_params" | cut -d',' -f2)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.lte_persist='$lte_persist'"
|
||||
uci set "$UCI_CONFIG.cell_lock.nr5g_persist='$nr5g_persist'"
|
||||
log_message "Stored persist settings: LTE=$lte_persist, NR5G=$nr5g_persist" "debug"
|
||||
fi
|
||||
|
||||
# Commit changes
|
||||
uci commit "$UCI_CONFIG"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if time is in range
|
||||
is_time_in_range() {
|
||||
local current_time_minutes=$1
|
||||
local start_time_minutes=$2
|
||||
local end_time_minutes=$3
|
||||
|
||||
# Handle case where end time is on the next day
|
||||
if [ $end_time_minutes -lt $start_time_minutes ]; then
|
||||
if [ $current_time_minutes -ge $start_time_minutes ] || [ $current_time_minutes -lt $end_time_minutes ]; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if [ $current_time_minutes -ge $start_time_minutes ] && [ $current_time_minutes -lt $end_time_minutes ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to convert HH:MM to minutes
|
||||
time_to_minutes() {
|
||||
local time="$1"
|
||||
local hours=$(echo "$time" | cut -d':' -f1)
|
||||
local minutes=$(echo "$time" | cut -d':' -f2)
|
||||
|
||||
echo $((hours * 60 + minutes))
|
||||
}
|
||||
|
||||
# Function to check schedule and manage cell locks
|
||||
check_schedule() {
|
||||
local enabled
|
||||
local start_time
|
||||
local end_time
|
||||
local current_active
|
||||
|
||||
# Get current scheduler state from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
config_get_bool enabled cell_lock enabled 0
|
||||
|
||||
if [ "$enabled" -ne 1 ]; then
|
||||
log_message "Cell lock scheduler is disabled" "debug"
|
||||
update_status "disabled" "Scheduler is disabled" 0 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get schedule from UCI
|
||||
config_get start_time cell_lock start_time
|
||||
config_get end_time cell_lock end_time
|
||||
config_get current_active cell_lock active 0
|
||||
|
||||
if [ -z "$start_time" ] || [ -z "$end_time" ]; then
|
||||
log_message "Missing start or end time in configuration" "error"
|
||||
update_status "error" "Missing schedule configuration" 0 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get current time
|
||||
local current_time=$(date "+%H:%M")
|
||||
|
||||
# Convert times to minutes for comparison
|
||||
local current_minutes=$(time_to_minutes "$current_time")
|
||||
local start_minutes=$(time_to_minutes "$start_time")
|
||||
local end_minutes=$(time_to_minutes "$end_time")
|
||||
|
||||
# Get token for AT commands
|
||||
local token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for checking schedule" "error"
|
||||
update_status "error" "Failed to acquire token for checking schedule" 0 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if any cell lock is currently active
|
||||
local lock_active=0
|
||||
check_lock_status "$token_id" && lock_active=1
|
||||
|
||||
# Check if current time is in the scheduled range
|
||||
if is_time_in_range "$current_minutes" "$start_minutes" "$end_minutes"; then
|
||||
# We're in the active window
|
||||
if [ "$current_active" -ne 1 ]; then
|
||||
# We just entered the window, need to save current state
|
||||
log_message "Entering scheduled window" "info"
|
||||
|
||||
# Store current lock parameters if a lock is active
|
||||
if [ $lock_active -eq 1 ]; then
|
||||
log_message "Storing current cell lock parameters" "info"
|
||||
store_current_lock_params "$token_id"
|
||||
else
|
||||
log_message "No active cell locks to store" "info"
|
||||
update_status "inactive" "Schedule active but no cell locks configured" 1 0
|
||||
release_token "$token_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update status
|
||||
uci set "$UCI_CONFIG.cell_lock.active=1"
|
||||
uci commit "$UCI_CONFIG"
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
else
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
}
|
||||
else
|
||||
# We're outside the active window
|
||||
if [ "$current_active" -eq 1 ]; then
|
||||
# We just exited the window
|
||||
log_message "Exiting scheduled window" "info"
|
||||
|
||||
# Update status
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
update_status "inactive" "Outside scheduled hours" 0 $lock_active
|
||||
} else {
|
||||
update_status "inactive" "Outside scheduled hours" 0 $lock_active
|
||||
}
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log_message "Cell lock scheduler daemon starting (PID: $$)" "info"
|
||||
|
||||
# Ensure UCI section exists
|
||||
if ! uci -q get "$UCI_CONFIG.cell_lock" >/dev/null; then
|
||||
uci set "$UCI_CONFIG.cell_lock=scheduler"
|
||||
uci set "$UCI_CONFIG.cell_lock.enabled=0"
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
log_message "Created cell lock UCI configuration" "info"
|
||||
fi
|
||||
|
||||
# Initialize status
|
||||
update_status "starting" "Cell lock scheduler daemon starting" 0 0
|
||||
|
||||
# Get token and check if any locks are active
|
||||
local token_id=$(acquire_token)
|
||||
if [ -n "$token_id" ]; then
|
||||
local lock_active=0
|
||||
check_lock_status "$token_id" && lock_active=1
|
||||
release_token "$token_id"
|
||||
|
||||
# Update status based on current state
|
||||
local enabled=$(uci -q get "$UCI_CONFIG.cell_lock.enabled")
|
||||
if [ "$enabled" = "1" ]; then
|
||||
# Get schedule from UCI
|
||||
local start_time=$(uci -q get "$UCI_CONFIG.cell_lock.start_time")
|
||||
local end_time=$(uci -q get "$UCI_CONFIG.cell_lock.end_time")
|
||||
|
||||
if [ -n "$start_time" ] && [ -n "$end_time" ]; then
|
||||
# Check if we're currently in the schedule window
|
||||
local current_time=$(date "+%H:%M")
|
||||
local current_minutes=$(time_to_minutes "$current_time")
|
||||
local start_minutes=$(time_to_minutes "$start_time")
|
||||
local end_minutes=$(time_to_minutes "$end_time")
|
||||
|
||||
if is_time_in_range "$current_minutes" "$start_minutes" "$end_minutes"; then
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
uci set "$UCI_CONFIG.cell_lock.active=1"
|
||||
uci commit "$UCI_CONFIG"
|
||||
} else {
|
||||
update_status "inactive" "Cell lock scheduler is enabled but outside scheduled hours" 0 $lock_active
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
}
|
||||
} else {
|
||||
update_status "error" "Missing schedule configuration" 0 $lock_active
|
||||
}
|
||||
} else {
|
||||
update_status "disabled" "Cell lock scheduler is disabled" 0 $lock_active
|
||||
}
|
||||
} else {
|
||||
log_message "Failed to acquire token for initial status check" "error"
|
||||
}
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
check_schedule
|
||||
sleep $CHECK_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Set up trap for clean shutdown
|
||||
trap 'log_message "Received signal, exiting" "info"; update_status "stopped" "Daemon stopped" 0 0; rm -f "$PID_FILE"; exit 0' INT TERM
|
||||
|
||||
# Start the main function
|
||||
main
|
||||
File diff suppressed because one or more lines are too long
@@ -12,8 +12,8 @@ e:I[99165,[],"OutletBoundary"]
|
||||
10:I[99165,[],"MetadataBoundary"]
|
||||
12:I[99165,[],"ViewportBoundary"]
|
||||
14:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","about",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["about",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["about",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","about","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$La",null,{"Component":"$b","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@c","$@d"]}],null,["$","$Le",null,{"children":"$Lf"}]]}],{},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","BSKC_qZkYyipuB2zOenkG",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],null]}]]}],false]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","about",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["about",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["about",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","about","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$La",null,{"Component":"$b","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@c","$@d"]}],null,["$","$Le",null,{"children":"$Lf"}]]}],{},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","RZohU-9AWPF-9t-zmaIRM",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],null]}]]}],false]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
c:{}
|
||||
d:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[30233,["7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","advanced-settings","at-terminal",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["at-terminal",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["at-terminal",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","at-terminal","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","bj2A73QxjlYnOYfFw8cO4",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","advanced-settings","at-terminal",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["at-terminal",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["at-terminal",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","at-terminal","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","hm9QRsQDmkQ3tAbrgPcdY",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[39966,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","advanced-settings","connectivity",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["connectivity",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["connectivity",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","connectivity","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","DTnEPxio4LFqOIRh4jg54",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","advanced-settings","connectivity",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["connectivity",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["connectivity",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","connectivity","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","w8TAMqIS2JBthNV_YVtwR",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[34819,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","advanced-settings","mtu",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["mtu",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["mtu",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","mtu","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","ScZBASEMrtUqrI39H0niV",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","advanced-settings","mtu",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["mtu",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["mtu",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","mtu","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","cA5c4vNH7cwC7Joq-Y4Yd",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[83143,["7780","static/chunks/7780-d44d1f6d676771d4.js","1630","static/chunks
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","advanced-settings","ttl-settings",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["ttl-settings",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["ttl-settings",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","ttl-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","llJFJ7mfZbQX4KYjHnA13",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","advanced-settings","ttl-settings",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["advanced-settings",{"children":["ttl-settings",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["advanced-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["ttl-settings",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","advanced-settings","children","ttl-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","HdT6-waxZQsLw7x1rwFLT",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[75808,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","cell-settings","band-locking",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["band-locking",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["band-locking",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","band-locking","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","2Y24FMa69p9yW_OKggC-6",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","cell-settings","band-locking",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["band-locking",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["band-locking",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","band-locking","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","I5l4teEHIa5cqKxE86yKb",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[46142,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","cell-settings","basic-settings",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["basic-settings",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["basic-settings",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","basic-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","TWo8kQLQAE_sIuiA-dq55",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","cell-settings","basic-settings",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["basic-settings",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["basic-settings",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","basic-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","rn7mp_whi-jobAxB20m3t",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[19496,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","cell-settings","cell-locking",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["cell-locking",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["cell-locking",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","cell-locking","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","rx4uHCwkz952NZVSiHHzU",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","cell-settings","cell-locking",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["cell-locking",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["cell-locking",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","cell-locking","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","phyXo461-jaRS48xx1Jkp",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[70231,["7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","cell-settings","imei-mangling",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["imei-mangling",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["imei-mangling",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","imei-mangling","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","NJz0A4i3VoodXZwAtTIsu",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","cell-settings","imei-mangling",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["imei-mangling",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["imei-mangling",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","imei-mangling","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","k1fgfTjUyxtiLVHjAy59c",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[33776,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","cell-settings","sms",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["sms",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["sms",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","sms","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","Ma0Wa-HkTE40td21wg4-O",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","cell-settings","sms",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["cell-settings",{"children":["sms",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["cell-settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["sms",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","cell-settings","children","sms","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","5G7-X9ijwG_lbiG668Bul",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,13 +8,13 @@
|
||||
8:I[96609,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks/8885-1b9ab3cbb10cf437.js","7563","static/chunks/7563-33b7de2a93dcbe27.js","9464","static/chunks/9464-f5c3c85ad60907ac.js","9477","static/chunks/9477-215fa25b7251af44.js","6357","static/chunks/6357-9bebe3918fcef1e5.js","7414","static/chunks/7414-d6480d4dfb8a2ef8.js","4767","static/chunks/4767-88886265e4e59e78.js","1954","static/chunks/app/dashboard/layout-5311362b3a63fe81.js"],"default"]
|
||||
a:I[31753,["9477","static/chunks/9477-215fa25b7251af44.js","3075","static/chunks/app/dashboard/experimental/layout-6508e2a223029fa4.js"],"default"]
|
||||
c:I[5329,[],"ClientPageRoot"]
|
||||
d:I[37277,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","2101","static/chunks/b1b46485-5c61721f784038c7.js","7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks/8885-1b9ab3cbb10cf437.js","7563","static/chunks/7563-33b7de2a93dcbe27.js","9679","static/chunks/9679-e42f7aaecc29c6da.js","3048","static/chunks/3048-a6b509fac24a1f29.js","7231","static/chunks/7231-9bf29e950cdd6225.js","5014","static/chunks/app/dashboard/experimental/cell-scanner/page-a4709c7977b627a1.js"],"default"]
|
||||
d:I[88388,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","2101","static/chunks/b1b46485-5c61721f784038c7.js","7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks/8885-1b9ab3cbb10cf437.js","7563","static/chunks/7563-33b7de2a93dcbe27.js","9679","static/chunks/9679-e42f7aaecc29c6da.js","3048","static/chunks/3048-a6b509fac24a1f29.js","3453","static/chunks/3453-59569df86cb1327e.js","2394","static/chunks/2394-bec269701e2d0c16.js","5014","static/chunks/app/dashboard/experimental/cell-scanner/page-2c4956be7a457748.js"],"default"]
|
||||
10:I[99165,[],"OutletBoundary"]
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","experimental","cell-scanner",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["cell-scanner",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["cell-scanner",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","cell-scanner","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","-VsjM1sVW_65u4kXCmmrZ",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","experimental","cell-scanner",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["cell-scanner",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["cell-scanner",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","cell-scanner","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","7hjQOimHf9dxD0FQquY-1",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,13 +8,13 @@
|
||||
8:I[96609,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/chunks/7780-d44d1f6d676771d4.js","8885","static/chunks/8885-1b9ab3cbb10cf437.js","7563","static/chunks/7563-33b7de2a93dcbe27.js","9464","static/chunks/9464-f5c3c85ad60907ac.js","9477","static/chunks/9477-215fa25b7251af44.js","6357","static/chunks/6357-9bebe3918fcef1e5.js","7414","static/chunks/7414-d6480d4dfb8a2ef8.js","4767","static/chunks/4767-88886265e4e59e78.js","1954","static/chunks/app/dashboard/layout-5311362b3a63fe81.js"],"default"]
|
||||
a:I[31753,["9477","static/chunks/9477-215fa25b7251af44.js","3075","static/chunks/app/dashboard/experimental/layout-6508e2a223029fa4.js"],"default"]
|
||||
c:I[5329,[],"ClientPageRoot"]
|
||||
d:I[3099,["7780","static/chunks/7780-d44d1f6d676771d4.js","9007","static/chunks/9007-7f45a2e4a42c9be9.js","666","static/chunks/app/dashboard/experimental/freq-calculator/page-72839bc94c5707d7.js"],"default"]
|
||||
d:I[14332,["7780","static/chunks/7780-d44d1f6d676771d4.js","3453","static/chunks/3453-59569df86cb1327e.js","5755","static/chunks/5755-b330e14a84ee51bb.js","666","static/chunks/app/dashboard/experimental/freq-calculator/page-76fc91defa16e132.js"],"default"]
|
||||
10:I[99165,[],"OutletBoundary"]
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","experimental","freq-calculator",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["freq-calculator",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["freq-calculator",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","freq-calculator","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","o7VWYjimCCCFZCRLxFY0B",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","experimental","freq-calculator",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["freq-calculator",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["freq-calculator",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","freq-calculator","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","WFkxhM9vtqBB8f3DnNJXD",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[53302,["7780","static/chunks/7780-d44d1f6d676771d4.js","3376","static/chunks
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","experimental","keep-alive",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["keep-alive",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["keep-alive",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","keep-alive","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","Jc6BKIfIAvXV2gGVtiA7o",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","experimental","keep-alive",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["keep-alive",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["keep-alive",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","keep-alive","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","nNAnT0dUxnVk-Ph9jYfei",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[22256,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","experimental","quecprofiles",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["quecprofiles",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["quecprofiles",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","quecprofiles","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","mX9IoPGvofCyUh35BvXKU",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","experimental","quecprofiles",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["quecprofiles",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["quecprofiles",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","quecprofiles","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","8vIgfmEVWfTGJjm3M-nNQ",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[79824,["9980","static/chunks/7b0cf0b7-aa73cc75e53c5793.js","7780","static/ch
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","experimental","quecwatch",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["quecwatch",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["quecwatch",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","quecwatch","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","F6_JxCamNLO0up-1ooNFl",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","experimental","quecwatch",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["experimental",{"children":["quecwatch",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["experimental",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["quecwatch",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","experimental","children","quecwatch","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","ElzUMD5BvsKfchaBLPpgj",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,8 +12,8 @@ e:I[99165,[],"OutletBoundary"]
|
||||
10:I[99165,[],"MetadataBoundary"]
|
||||
12:I[99165,[],"ViewportBoundary"]
|
||||
14:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","home",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["home",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["home",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","home","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$La",null,{"Component":"$b","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@c","$@d"]}],null,["$","$Le",null,{"children":"$Lf"}]]}],{},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","GYJHm61crn73UefHwIPLZ",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],null]}]]}],false]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","home",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["home",{"children":["__PAGE__",{}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["home",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","home","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$La",null,{"Component":"$b","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@c","$@d"]}],null,["$","$Le",null,{"children":"$Lf"}]]}],{},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","U3UvBGQEqKu6QhYa39Aeu",{"children":[["$","$L10",null,{"children":"$L11"}],["$","$L12",null,{"children":"$L13"}],null]}]]}],false]],"m":"$undefined","G":["$14","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
c:{}
|
||||
d:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[69835,["5293","static/chunks/app/dashboard/settings/games/tetris/page-e289ae
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","settings","games","tetris",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["settings",{"children":["games",{"children":["tetris",{"children":["__PAGE__",{}]}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["games",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","games","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["tetris",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","games","children","tetris","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","H1PNDKs2SrYf3O9ZBQBcb",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","settings","games","tetris",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["settings",{"children":["games",{"children":["tetris",{"children":["__PAGE__",{}]}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["games",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","games","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["tetris",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","games","children","tetris","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","6vtC0dcYv-bf4zHwoY17i",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@ d:I[16212,["7780","static/chunks/7780-d44d1f6d676771d4.js","2162","static/chunks
|
||||
12:I[99165,[],"MetadataBoundary"]
|
||||
14:I[99165,[],"ViewportBoundary"]
|
||||
16:I[25339,[],""]
|
||||
:HL["/_next/static/css/562f52882551f4eb.css","style"]
|
||||
0:{"P":null,"b":"Kt0Xe6YYT_RuYVm3o2asX","p":"","c":["","dashboard","settings","security",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["settings",{"children":["security",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/562f52882551f4eb.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["security",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","security","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","OEnv4zQg6abQWeUBOn0ly",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
:HL["/_next/static/css/2adbd6ec1a3f6224.css","style"]
|
||||
0:{"P":null,"b":"xeZlQ8jLyR2FPwewgDcLc","p":"","c":["","dashboard","settings","security",""],"i":false,"f":[[["",{"children":["dashboard",{"children":["settings",{"children":["security",{"children":["__PAGE__",{}]}]}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2adbd6ec1a3f6224.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","suppressHydrationWarning":true,"children":["$","body",null,{"className":"antialiased __className_9dae3d","children":[["$","$L2",null,{"attribute":"class","defaultTheme":"system","enableSystem":true,"disableTransitionOnChange":true,"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[],[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}],["$","$L6",null,{}]]}]}]]}],{"children":["dashboard",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$8","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":{},"promise":"$@9"}]]}],{"children":["settings",["$","$1","c",{"children":[null,["$","$L7",null,{"Component":"$a","slots":{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promise":"$@b"}]]}],{"children":["security",["$","$1","c",{"children":[null,["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children","dashboard","children","settings","children","security","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$Lc",null,{"Component":"$d","searchParams":{},"params":"$0:f:0:1:2:children:1:props:children:1:props:params","promises":["$@e","$@f"]}],null,["$","$L10",null,{"children":"$L11"}]]}],{},null,false]},null,false]},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,["$","$1","RQdZxJ6HUnmyI7JAynOFO",{"children":[["$","$L12",null,{"children":"$L13"}],["$","$L14",null,{"children":"$L15"}],null]}]]}],false]],"m":"$undefined","G":["$16","$undefined"],"s":false,"S":true}
|
||||
9:{}
|
||||
b:{}
|
||||
e:{}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user