640 lines
22 KiB
Bash
Executable File
640 lines
22 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
SCRIPT_DIR="$HOME/Documents/Photon"
|
|
CONFIG_FILE="${SCRIPT_DIR}/photon.conf"
|
|
LOCKFILE="${SCRIPT_DIR}/.photon-upload.lock"
|
|
LOGFILE="${SCRIPT_DIR}/photon-upload.log"
|
|
|
|
# When launched as a GUI app there is no TTY — redirect stdout/stderr to the
|
|
# log file immediately so nothing tries to write to a closed fd.
|
|
mkdir -p "$SCRIPT_DIR"
|
|
exec >>"$LOGFILE" 2>&1
|
|
|
|
# Ensure Homebrew binaries are in PATH when launched as a GUI app
|
|
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
|
|
|
|
# Debug: Log script invocation
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Script invoked with args: $*" >> /tmp/photon-upload-debug.log
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') PID: $$, PPID: $PPID" >> /tmp/photon-upload-debug.log
|
|
|
|
# Load configuration (mandatory)
|
|
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] Config file not found: $CONFIG_FILE" >> "$LOGFILE"
|
|
osascript -e "display alert \"Photon Uploader\" message \"Config file not found:\\n$CONFIG_FILE\" as critical buttons {\"OK\"} default button \"OK\""
|
|
exit 1
|
|
fi
|
|
source "$CONFIG_FILE"
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] Config loaded: $CONFIG_FILE" >> "$LOGFILE"
|
|
|
|
# Logging function
|
|
log() {
|
|
local level="$1"
|
|
shift
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> "$LOGFILE"
|
|
}
|
|
|
|
# Check dependencies
|
|
check_dependencies() {
|
|
local missing_deps=()
|
|
|
|
log "INFO" "Checking dependencies..."
|
|
|
|
for cmd in fswatch openssl ssh scp; do
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
missing_deps+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
|
log "ERROR" "Missing dependencies: ${missing_deps[*]}"
|
|
log "INFO" "Install with: brew install ${missing_deps[*]}"
|
|
exit 1
|
|
fi
|
|
|
|
log "INFO" "All dependencies found"
|
|
}
|
|
|
|
# Create necessary directories
|
|
setup_directories() {
|
|
log "INFO" "Setting up directories..."
|
|
|
|
for dir in "$DIR_TO_MONITOR" "$DIR_TO_MOVE" "$DIR_ARCHIVE"; do
|
|
if [[ ! -d "$dir" ]]; then
|
|
log "INFO" "Creating directory: $dir"
|
|
mkdir -p "$dir" || {
|
|
log "ERROR" "Failed to create directory: $dir"
|
|
exit 1
|
|
}
|
|
fi
|
|
done
|
|
|
|
log "INFO" "Directory setup complete"
|
|
}
|
|
|
|
# Function to generate a random filename
|
|
# generate_random_filename() {
|
|
# local extension="$1"
|
|
# local timestamp=$(date +%s)
|
|
# local random_part=$(openssl rand -hex 4)
|
|
# echo "${timestamp}_${random_part}.${extension}"
|
|
# }
|
|
|
|
generate_random_filename() {
|
|
local extension="$1"
|
|
local random_part=$(openssl rand -base64 6 | tr -dc 'A-Za-z' | head -c 8)
|
|
echo "${random_part}.${extension}"
|
|
}
|
|
|
|
# Send system notification
|
|
send_notification() {
|
|
if [[ "$ENABLE_NOTIFICATIONS" != "true" ]]; then return; fi
|
|
local NOTIFY_HELPER
|
|
NOTIFY_HELPER="$(dirname "$(dirname "$0")")/Helpers/PhotonNotify.app"
|
|
if [[ -d "$NOTIFY_HELPER" ]]; then
|
|
open -n -jg "$NOTIFY_HELPER" --args "$1" "$2"
|
|
elif command -v osascript >/dev/null; then
|
|
osascript -e "display notification \"$2\" with title \"Photon Uploader\" subtitle \"$1\""
|
|
fi
|
|
}
|
|
|
|
# Check if file extension is supported
|
|
is_supported_file() {
|
|
local file="$1"
|
|
local extension="${file##*.}"
|
|
# Convert to lowercase (bash 3.2 compatible)
|
|
extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]')
|
|
[[ ",$SUPPORTED_EXTENSIONS," == *",$extension,"* ]]
|
|
}
|
|
|
|
# Validate SSH key authentication setup
|
|
validate_ssh_key() {
|
|
if [[ ! -f "$SSH_KEY_PATH" ]]; then
|
|
log "ERROR" "SSH key not found at: $SSH_KEY_PATH"
|
|
log "INFO" "Generate SSH key with: ssh-keygen -t rsa -b 4096 -f $SSH_KEY_PATH -N ''"
|
|
log "INFO" "Then copy public key to server: ssh-copy-id -i ${SSH_KEY_PATH}.pub -p $PORT $USER@$SERVER"
|
|
return 1
|
|
fi
|
|
|
|
# Check key permissions
|
|
local key_perms=$(stat -f "%Lp" "$SSH_KEY_PATH" 2>/dev/null || echo "000")
|
|
if [[ "$key_perms" != "600" ]]; then
|
|
log "WARN" "Fixing SSH key permissions: $SSH_KEY_PATH"
|
|
chmod 600 "$SSH_KEY_PATH"
|
|
fi
|
|
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [DEBUG] Using SSH key authentication: $SSH_KEY_PATH" >> "$LOGFILE"
|
|
return 0
|
|
}
|
|
|
|
# Function to process uploaded files
|
|
process_file() {
|
|
local file_path="$1"
|
|
local file_name=$(basename "$file_path")
|
|
|
|
# Skip hidden files and directories
|
|
if [[ "$file_name" == .* ]] || [[ -d "$file_path" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Check if file exists and is readable
|
|
if [[ ! -f "$file_path" ]] || [[ ! -r "$file_path" ]]; then
|
|
log "WARN" "File not accessible: $file_path"
|
|
return 1
|
|
fi
|
|
|
|
# Check if file is already being processed
|
|
if is_file_being_processed "$file_path"; then
|
|
log "INFO" "File already being processed: $file_path"
|
|
return 0
|
|
fi
|
|
|
|
# Check if file type is supported
|
|
if ! is_supported_file "$file_name"; then
|
|
log "INFO" "Unsupported file type: $file_path"
|
|
mark_processing_complete "$file_path"
|
|
return 0
|
|
fi
|
|
|
|
# Wait for file to be completely written (common with screenshots)
|
|
local file_size=0
|
|
local new_size=1
|
|
while [[ $file_size -ne $new_size ]]; do
|
|
file_size=$new_size
|
|
sleep 0.5
|
|
new_size=$(stat -f%z "$file_path" 2>/dev/null || echo 0)
|
|
done
|
|
|
|
log "INFO" "Processing file: $file_path"
|
|
|
|
local extension="${file_name##*.}"
|
|
local new_filename=$(generate_random_filename "$extension")
|
|
local staged_path="$DIR_TO_MOVE/$new_filename"
|
|
|
|
# Move file to staging area
|
|
if ! cp "$file_path" "$staged_path"; then
|
|
log "ERROR" "Failed to stage file: $file_path"
|
|
mark_processing_complete "$file_path"
|
|
return 1
|
|
fi
|
|
|
|
# Upload file
|
|
if upload_file "$staged_path" "$new_filename"; then
|
|
mark_processing_complete "$file_path"
|
|
return 0
|
|
else
|
|
mark_processing_complete "$file_path"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Upload file with improved error handling
|
|
upload_file() {
|
|
local file_path="$1"
|
|
local filename="$2"
|
|
local url="$BASE_URL/$filename"
|
|
|
|
log "INFO" "Uploading: $filename"
|
|
|
|
# Validate SSH key before attempting upload
|
|
if ! validate_ssh_key; then
|
|
log "ERROR" "SSH key validation failed"
|
|
return 1
|
|
fi
|
|
|
|
# Upload using SSH key authentication
|
|
if scp -P "$PORT" -i "$SSH_KEY_PATH" -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$file_path" "$USER@$SERVER:$REMOTE_DIR"; then
|
|
upload_success=true
|
|
else
|
|
upload_success=false
|
|
fi
|
|
|
|
if [[ "$upload_success" == "true" ]]; then
|
|
log "INFO" "Upload successful: $filename"
|
|
|
|
# Copy URL to clipboard
|
|
echo "$url" | pbcopy
|
|
log "INFO" "URL copied to clipboard: $url"
|
|
|
|
# Send notification
|
|
send_notification "" "$filename uploaded successfully"
|
|
generate_thumbnails
|
|
|
|
# Archive or cleanup
|
|
if [[ "$CLEANUP_AFTER_UPLOAD" == "true" ]]; then
|
|
if [[ -d "$DIR_ARCHIVE" ]]; then
|
|
mv "$file_path" "$DIR_ARCHIVE/"
|
|
log "INFO" "File archived: $filename"
|
|
else
|
|
rm "$file_path"
|
|
log "INFO" "File removed: $filename"
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
else
|
|
log "ERROR" "Upload failed: $filename"
|
|
send_notification "Failed" "Upload failed for $filename"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
generate_thumbnails() {
|
|
log "INFO" "Requesting thumbnail generation..."
|
|
|
|
if [[ -z "${PHOTON_DOMAIN:-}" ]]; then
|
|
log "ERROR" "PHOTON_DOMAIN not configured"
|
|
return 1
|
|
fi
|
|
|
|
local response
|
|
if response=$(curl -s "https://${PHOTON_DOMAIN}/job/generate_thumbnails" 2>&1); then
|
|
log "INFO" "Thumbnail generation response: $response"
|
|
|
|
# Parse JSON response to check status
|
|
if echo "$response" | grep -q '"status":"success"'; then
|
|
log "INFO" "Thumbnail generation completed successfully"
|
|
return 0
|
|
else
|
|
log "WARN" "Thumbnail generation may have failed: $response"
|
|
return 1
|
|
fi
|
|
else
|
|
log "ERROR" "Failed to connect to thumbnail service: $response"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Handle concurrent uploads (bash 3.2 compatible)
|
|
ACTIVE_UPLOADS_DIR="${SCRIPT_DIR}/.active_uploads"
|
|
PROCESSING_DIR="${SCRIPT_DIR}/.processing"
|
|
|
|
# Function to check if file is already being processed
|
|
is_file_being_processed() {
|
|
local file_path="$1"
|
|
local file_hash=$(echo "$file_path" | shasum -a 256 | cut -d' ' -f1)
|
|
local processing_file="$PROCESSING_DIR/$file_hash"
|
|
|
|
# Check if processing file exists and is recent (less than 60 seconds old)
|
|
if [[ -f "$processing_file" ]]; then
|
|
local processing_time=$(stat -f%m "$processing_file" 2>/dev/null || echo 0)
|
|
local current_time=$(date +%s)
|
|
if (( current_time - processing_time < 60 )); then
|
|
return 0 # Still being processed
|
|
else
|
|
rm -f "$processing_file" 2>/dev/null || true # Stale processing file
|
|
fi
|
|
fi
|
|
|
|
# Create processing marker atomically to prevent race conditions
|
|
mkdir -p "$PROCESSING_DIR"
|
|
if (set -C; echo $$ > "$processing_file") 2>/dev/null; then
|
|
return 1 # Not being processed, marker created
|
|
else
|
|
return 0 # Already being processed by another instance
|
|
fi
|
|
}
|
|
|
|
# Function to mark file processing as complete
|
|
mark_processing_complete() {
|
|
local file_path="$1"
|
|
local file_hash=$(echo "$file_path" | shasum -a 256 | cut -d' ' -f1)
|
|
local processing_file="$PROCESSING_DIR/$file_hash"
|
|
rm -f "$processing_file" 2>/dev/null || true
|
|
}
|
|
|
|
# Signal handlers
|
|
cleanup() {
|
|
log "INFO" "Shutting down..."
|
|
[[ -f "$LOCKFILE" ]] && rm -f "$LOCKFILE"
|
|
|
|
# Kill any fswatch processes monitoring our directory
|
|
if command -v pkill >/dev/null 2>&1; then
|
|
pkill -f "fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true
|
|
fi
|
|
|
|
# Wait for active uploads to complete
|
|
if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
|
|
for upload_file in "$ACTIVE_UPLOADS_DIR"/*; do
|
|
[[ -f "$upload_file" ]] || continue
|
|
local pid=$(basename "$upload_file")
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
local filename=""
|
|
if [[ -r "$upload_file" ]]; then
|
|
filename=$(cat "$upload_file" 2>/dev/null || echo "unknown")
|
|
else
|
|
filename="unknown"
|
|
fi
|
|
log "INFO" "Waiting for upload to complete: $filename"
|
|
wait "$pid" 2>/dev/null || true
|
|
fi
|
|
rm -f "$upload_file" 2>/dev/null || true
|
|
done
|
|
rmdir "$ACTIVE_UPLOADS_DIR" 2>/dev/null || true
|
|
fi
|
|
|
|
# Clean up processing directory
|
|
if [[ -d "$PROCESSING_DIR" ]]; then
|
|
rm -rf "$PROCESSING_DIR" 2>/dev/null || true
|
|
fi
|
|
|
|
exit 0
|
|
}
|
|
|
|
# Main function
|
|
main() {
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Entering main function" >> /tmp/photon-upload-debug.log
|
|
log "INFO" "Starting screenshot upload service"
|
|
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Checking for existing lockfile" >> /tmp/photon-upload-debug.log
|
|
# Enhanced lock creation with better race condition protection
|
|
local max_attempts=5
|
|
local attempt=1
|
|
local lock_acquired=false
|
|
|
|
while [[ $attempt -le $max_attempts ]] && [[ "$lock_acquired" == "false" ]]; do
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock attempt $attempt" >> /tmp/photon-upload-debug.log
|
|
|
|
if (set -C; echo $$ > "$LOCKFILE") 2>/dev/null; then
|
|
lock_acquired=true
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock acquired on attempt $attempt" >> /tmp/photon-upload-debug.log
|
|
else
|
|
existing_pid=$(cat "$LOCKFILE" 2>/dev/null || echo "")
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Lock exists, checking PID: $existing_pid" >> /tmp/photon-upload-debug.log
|
|
|
|
if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
|
|
log "ERROR" "Another instance is already running (PID: $existing_pid)"
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Existing process $existing_pid is alive, exiting" >> /tmp/photon-upload-debug.log
|
|
exit 1
|
|
else
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Stale lock file, removing" >> /tmp/photon-upload-debug.log
|
|
rm -f "$LOCKFILE" 2>/dev/null || true
|
|
sleep 0.1
|
|
fi
|
|
fi
|
|
((attempt++))
|
|
done
|
|
|
|
if [[ "$lock_acquired" == "false" ]]; then
|
|
log "ERROR" "Unable to acquire lockfile after $max_attempts attempts"
|
|
exit 1
|
|
fi
|
|
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Created lockfile with PID: $$" >> /tmp/photon-upload-debug.log
|
|
log "INFO" "Created lockfile with PID: $$"
|
|
|
|
# Set up signal handlers for this monitoring process only
|
|
trap cleanup SIGINT SIGTERM EXIT
|
|
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Calling check_dependencies" >> /tmp/photon-upload-debug.log
|
|
# Check dependencies and setup
|
|
check_dependencies
|
|
setup_directories
|
|
|
|
# Validate SSH key authentication
|
|
log "INFO" "Validating SSH key authentication..."
|
|
if ! validate_ssh_key; then
|
|
log "ERROR" "SSH key authentication setup failed"
|
|
exit 1
|
|
fi
|
|
log "INFO" "SSH key authentication validated successfully"
|
|
|
|
# Create active uploads tracking directory
|
|
mkdir -p "$ACTIVE_UPLOADS_DIR"
|
|
log "INFO" "Created tracking directory: $ACTIVE_UPLOADS_DIR"
|
|
|
|
log "INFO" "Monitoring directory: $DIR_TO_MONITOR"
|
|
log "INFO" "Supported file types: $SUPPORTED_EXTENSIONS"
|
|
|
|
# Test fswatch before starting the main loop
|
|
log "INFO" "Testing fswatch compatibility..."
|
|
if ! fswatch --version >/dev/null 2>&1; then
|
|
log "ERROR" "fswatch not working properly"
|
|
exit 1
|
|
fi
|
|
log "INFO" "fswatch test passed"
|
|
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') About to start fswatch monitoring" >> /tmp/photon-upload-debug.log
|
|
log "INFO" "Starting file monitoring with fswatch..."
|
|
|
|
# Create named pipe for fswatch to avoid subshell issues
|
|
local fswatch_pipe="/tmp/fswatch-$$"
|
|
mkfifo "$fswatch_pipe"
|
|
|
|
# Start fswatch in background writing to pipe
|
|
fswatch -0 "$DIR_TO_MONITOR" > "$fswatch_pipe" &
|
|
local fswatch_pid=$!
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Started fswatch PID: $fswatch_pid" >> /tmp/photon-upload-debug.log
|
|
|
|
# Cleanup function for pipe
|
|
cleanup_pipe() {
|
|
kill -TERM "$fswatch_pid" 2>/dev/null || true
|
|
rm -f "$fswatch_pipe"
|
|
}
|
|
trap cleanup_pipe EXIT
|
|
|
|
# Read events from pipe without subshell
|
|
while read -d "" event; do
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') fswatch event: $event" >> /tmp/photon-upload-debug.log
|
|
|
|
# Skip directories and hidden files immediately
|
|
if [[ -d "$event" ]] || [[ "$(basename "$event")" == .* ]]; then
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Skipping directory/hidden file: $event" >> /tmp/photon-upload-debug.log
|
|
continue
|
|
fi
|
|
|
|
# Add small delay to allow multiple rapid events to settle
|
|
sleep 0.2
|
|
|
|
# Limit concurrent uploads
|
|
while true; do
|
|
local active_count=0
|
|
if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
|
|
for upload_file in "$ACTIVE_UPLOADS_DIR"/*; do
|
|
[[ -f "$upload_file" ]] || continue
|
|
local pid=$(basename "$upload_file")
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
((active_count++))
|
|
else
|
|
rm -f "$upload_file"
|
|
fi
|
|
done
|
|
fi
|
|
[[ $active_count -lt $MAX_CONCURRENT_UPLOADS ]] && break
|
|
sleep 0.1
|
|
done
|
|
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Starting background process for: $event" >> /tmp/photon-upload-debug.log
|
|
|
|
# Process file in background
|
|
(
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background worker PID $$ processing: $event" >> /tmp/photon-upload-debug.log
|
|
process_file "$event"
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background worker PID $$ finished: $event" >> /tmp/photon-upload-debug.log
|
|
rm -f "$ACTIVE_UPLOADS_DIR/$$" 2>/dev/null || true
|
|
) &
|
|
|
|
local upload_pid=$!
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Spawned upload worker: $upload_pid for $(basename "$event")" >> /tmp/photon-upload-debug.log
|
|
echo "$(basename "$event")" > "$ACTIVE_UPLOADS_DIR/$upload_pid"
|
|
done < "$fswatch_pipe"
|
|
}
|
|
|
|
# Help function
|
|
show_help() {
|
|
cat << EOF
|
|
Screenshot Upload Service
|
|
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Options:
|
|
-h, --help Show this help message
|
|
-c, --config Specify config file path
|
|
-d, --daemon Run in background
|
|
-s, --stop Stop running daemon
|
|
-t, --test Test upload with a sample file
|
|
--status Show service status and related processes
|
|
|
|
Configuration:
|
|
Edit $CONFIG_FILE to customize settings
|
|
|
|
EOF
|
|
}
|
|
|
|
# Parse command line arguments
|
|
BACKGROUND_MODE=false
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
-c|--config)
|
|
CONFIG_FILE="$2"
|
|
shift 2
|
|
;;
|
|
-d|--daemon)
|
|
# Ensure log directory exists
|
|
mkdir -p "$(dirname "$LOGFILE")"
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Starting daemon mode" >> /tmp/photon-upload-debug.log
|
|
# Start daemon with logging
|
|
nohup "$0" --background >> "$LOGFILE" 2>&1 &
|
|
daemon_pid=$!
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Spawned background process: $daemon_pid" >> /tmp/photon-upload-debug.log
|
|
echo "Started in background with PID: $daemon_pid"
|
|
echo "Monitor with: tail -f $LOGFILE"
|
|
exit 0
|
|
;;
|
|
--background)
|
|
# Internal flag used by daemon mode - don't document in help
|
|
# This prevents infinite daemon loops
|
|
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') Background mode activated, breaking from arg parse" >> /tmp/photon-upload-debug.log
|
|
BACKGROUND_MODE=true
|
|
shift
|
|
break
|
|
;;
|
|
-s|--stop)
|
|
if [[ -f "$LOCKFILE" ]]; then
|
|
pid=$(cat "$LOCKFILE")
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
echo "Stopping service with PID: $pid"
|
|
kill -TERM "$pid"
|
|
|
|
# Also kill any related fswatch processes
|
|
if command -v pkill >/dev/null 2>&1; then
|
|
pkill -f "fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true
|
|
echo "Stopped related fswatch processes"
|
|
fi
|
|
|
|
# Wait a moment for graceful shutdown
|
|
sleep 2
|
|
|
|
# Force kill if still running
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
kill -KILL "$pid" 2>/dev/null || true
|
|
echo "Force killed process $pid"
|
|
fi
|
|
|
|
echo "Service stopped"
|
|
else
|
|
echo "Service not running (PID $pid not found)"
|
|
rm -f "$LOCKFILE"
|
|
fi
|
|
else
|
|
echo "No lockfile found, checking for orphaned processes..."
|
|
|
|
# Look for orphaned upload or fswatch processes
|
|
if command -v pgrep >/dev/null 2>&1; then
|
|
orphaned_pids=$(pgrep -f "upload.*background|fswatch.*$DIR_TO_MONITOR" 2>/dev/null || true)
|
|
if [[ -n "$orphaned_pids" ]]; then
|
|
echo "Found orphaned processes: $orphaned_pids"
|
|
kill -TERM $orphaned_pids 2>/dev/null || true
|
|
sleep 2
|
|
kill -KILL $orphaned_pids 2>/dev/null || true
|
|
echo "Cleaned up orphaned processes"
|
|
else
|
|
echo "No running processes found"
|
|
fi
|
|
else
|
|
echo "Service may not be running"
|
|
fi
|
|
fi
|
|
exit 0
|
|
;;
|
|
-t|--test)
|
|
echo "Testing upload functionality..."
|
|
check_dependencies
|
|
# Create a test file
|
|
test_file="/tmp/test_$(date +%s).txt"
|
|
echo "Test upload $(date)" > "$test_file"
|
|
process_file "$test_file"
|
|
rm -f "$test_file"
|
|
exit 0
|
|
;;
|
|
--status)
|
|
echo "Screenshot Upload Service Status"
|
|
echo "================================"
|
|
|
|
if [[ -f "$LOCKFILE" ]]; then
|
|
lock_pid=$(cat "$LOCKFILE")
|
|
echo "Lock file: $LOCKFILE (PID: $lock_pid)"
|
|
|
|
if kill -0 "$lock_pid" 2>/dev/null; then
|
|
echo "Main process: RUNNING (PID: $lock_pid)"
|
|
else
|
|
echo "Main process: DEAD (stale lock file)"
|
|
fi
|
|
else
|
|
echo "Lock file: NOT FOUND"
|
|
fi
|
|
|
|
echo ""
|
|
echo "Related processes:"
|
|
if ps aux | grep -E "(upload|fswatch.*$DIR_TO_MONITOR)" | grep -v grep | grep -v status; then
|
|
true
|
|
else
|
|
echo "No related processes found"
|
|
fi
|
|
|
|
echo ""
|
|
if [[ -d "$ACTIVE_UPLOADS_DIR" ]]; then
|
|
upload_count=$(ls -1 "$ACTIVE_UPLOADS_DIR" 2>/dev/null | wc -l | tr -d ' ')
|
|
echo "Active uploads: $upload_count"
|
|
else
|
|
echo "Active uploads: 0"
|
|
fi
|
|
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Run main function
|
|
main
|