updated
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Windows Print Service - Complete Self-Contained Version
|
||||
Includes all dependencies and libraries for Windows systems
|
||||
Fixed for Windows Service Error 1053 - Proper Service Implementation
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -12,6 +12,7 @@ import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import time
|
||||
import signal
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import threading
|
||||
@@ -24,6 +25,10 @@ import zipfile
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from socketserver import ThreadingMixIn
|
||||
|
||||
# Global variables for service control
|
||||
service_running = True
|
||||
httpd_server = None
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
"""Handle requests in a separate thread."""
|
||||
daemon_threads = True
|
||||
@@ -467,48 +472,171 @@ pause
|
||||
with open('install_service_complete.bat', 'w') as f:
|
||||
f.write(service_script)
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
"""Handle shutdown signals gracefully."""
|
||||
global service_running, httpd_server
|
||||
logging.info(f"Received signal {signum}, shutting down gracefully...")
|
||||
service_running = False
|
||||
|
||||
if httpd_server:
|
||||
# Shutdown server in a separate thread to avoid blocking
|
||||
def shutdown_server():
|
||||
try:
|
||||
httpd_server.shutdown()
|
||||
httpd_server.server_close()
|
||||
except Exception as e:
|
||||
logging.error(f"Error during server shutdown: {e}")
|
||||
|
||||
shutdown_thread = threading.Thread(target=shutdown_server)
|
||||
shutdown_thread.daemon = True
|
||||
shutdown_thread.start()
|
||||
shutdown_thread.join(timeout=5)
|
||||
|
||||
logging.info("Service shutdown complete")
|
||||
sys.exit(0)
|
||||
|
||||
def setup_signal_handlers():
|
||||
"""Setup signal handlers for graceful shutdown."""
|
||||
if hasattr(signal, 'SIGTERM'):
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
if hasattr(signal, 'SIGINT'):
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
if hasattr(signal, 'SIGBREAK'): # Windows specific
|
||||
signal.signal(signal.SIGBREAK, signal_handler)
|
||||
|
||||
def main():
|
||||
"""Main service function."""
|
||||
global start_time
|
||||
"""Main service function with proper Windows service support."""
|
||||
global start_time, service_running, httpd_server
|
||||
start_time = time.time()
|
||||
|
||||
# Setup logging
|
||||
# Setup logging first
|
||||
setup_logging()
|
||||
logging.info("Starting Windows Print Service (Complete Version)")
|
||||
logging.info("=== Starting Windows Print Service (Complete Version) ===")
|
||||
logging.info(f"Python version: {sys.version}")
|
||||
logging.info(f"Platform: {sys.platform}")
|
||||
logging.info(f"Process ID: {os.getpid()}")
|
||||
logging.info(f"Command line args: {sys.argv}")
|
||||
|
||||
# Create service installer
|
||||
create_windows_service()
|
||||
# Setup signal handlers for graceful shutdown
|
||||
setup_signal_handlers()
|
||||
|
||||
# Determine run mode
|
||||
run_mode = "standalone"
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] in ['--service', 'service']:
|
||||
run_mode = "windows_service"
|
||||
elif sys.argv[1] in ['--standalone', 'standalone']:
|
||||
run_mode = "standalone"
|
||||
elif sys.argv[1] in ['--test', 'test']:
|
||||
run_mode = "test"
|
||||
|
||||
logging.info(f"Running in '{run_mode}' mode")
|
||||
|
||||
if run_mode == "test":
|
||||
# Test mode - just verify setup and exit
|
||||
logging.info("=== SERVICE TEST MODE ===")
|
||||
test_service_setup()
|
||||
return
|
||||
|
||||
try:
|
||||
# Start HTTP server
|
||||
server_address = ('localhost', 8765)
|
||||
httpd = ThreadingHTTPServer(server_address, PrintServiceHandler)
|
||||
|
||||
# Try to bind to the port
|
||||
try:
|
||||
httpd_server = ThreadingHTTPServer(server_address, PrintServiceHandler)
|
||||
except OSError as e:
|
||||
if "Address already in use" in str(e):
|
||||
logging.error(f"Port 8765 is already in use. Another service instance may be running.")
|
||||
logging.error("Stop the existing service or use a different port.")
|
||||
return
|
||||
else:
|
||||
raise
|
||||
|
||||
logging.info(f"Print service started on http://{server_address[0]}:{server_address[1]}")
|
||||
logging.info("Available endpoints:")
|
||||
logging.info(" GET /health - Health check")
|
||||
logging.info(" GET /printers - List available printers")
|
||||
logging.info(" GET /printers - List available printers")
|
||||
logging.info(" GET /status - Service status")
|
||||
logging.info(" POST /print_pdf - Print PDF file")
|
||||
|
||||
# Keep track of requests
|
||||
httpd.request_count = 0
|
||||
httpd_server.request_count = 0
|
||||
|
||||
# Start server
|
||||
httpd.serve_forever()
|
||||
# Service main loop
|
||||
logging.info("Service is ready and listening...")
|
||||
|
||||
if run_mode == "standalone":
|
||||
logging.info("*** STANDALONE MODE - Press Ctrl+C to stop ***")
|
||||
logging.info("Test the service at: http://localhost:8765/health")
|
||||
|
||||
while service_running:
|
||||
try:
|
||||
# Handle requests with timeout to check service_running periodically
|
||||
httpd_server.timeout = 1.0
|
||||
httpd_server.handle_request()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Service stopped by user (Ctrl+C)")
|
||||
break
|
||||
except Exception as e:
|
||||
logging.error(f"Request handling error: {e}")
|
||||
# Continue running unless it's a critical error
|
||||
if not service_running:
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Service stopped by user")
|
||||
except Exception as e:
|
||||
logging.error(f"Service error: {e}")
|
||||
logging.error(f"Critical service error: {e}")
|
||||
import traceback
|
||||
logging.error(f"Traceback: {traceback.format_exc()}")
|
||||
finally:
|
||||
# Cleanup
|
||||
if httpd_server:
|
||||
try:
|
||||
httpd_server.server_close()
|
||||
except:
|
||||
pass
|
||||
|
||||
logging.info("=== Windows Print Service shutdown complete ===")
|
||||
|
||||
# Exit cleanly
|
||||
sys.exit(0)
|
||||
|
||||
def test_service_setup():
|
||||
"""Test service setup and configuration."""
|
||||
logging.info("Testing service setup...")
|
||||
|
||||
# Test printer detection
|
||||
try:
|
||||
# Create a temporary handler instance to test printer detection
|
||||
import tempfile
|
||||
temp_handler = PrintServiceHandler()
|
||||
temp_handler.temp_dir = tempfile.mkdtemp(prefix="test_service_")
|
||||
|
||||
printers = temp_handler.get_available_printers()
|
||||
logging.info(f"Found {len(printers)} printers:")
|
||||
for printer in printers[:5]: # Show first 5
|
||||
logging.info(f" - {printer.get('name', 'Unknown')}")
|
||||
|
||||
# Cleanup temp directory
|
||||
try:
|
||||
httpd.server_close()
|
||||
import shutil
|
||||
shutil.rmtree(temp_handler.temp_dir)
|
||||
except:
|
||||
pass
|
||||
logging.info("Windows Print Service shutdown complete")
|
||||
|
||||
except Exception as e:
|
||||
logging.warning(f"Printer detection test failed: {e}")
|
||||
|
||||
# Test port availability
|
||||
try:
|
||||
import socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(('localhost', 8765))
|
||||
logging.info("Port 8765 is available ✓")
|
||||
except OSError as e:
|
||||
logging.error(f"Port 8765 test failed: {e}")
|
||||
|
||||
logging.info("Service setup test completed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user