155 lines
6.1 KiB
Python
155 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
밍글 스튜디오 웹사이트 로컬 개발 서버
|
|
Python 기반 HTTP 서버로 개발 및 테스트 지원
|
|
"""
|
|
|
|
import http.server
|
|
import socketserver
|
|
import webbrowser
|
|
import os
|
|
import sys
|
|
import socket
|
|
from pathlib import Path
|
|
|
|
# 한글 출력을 위한 인코딩 설정
|
|
if os.name == 'nt': # Windows
|
|
import locale
|
|
import codecs
|
|
# UTF-8 강제 설정
|
|
try:
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
sys.stderr.reconfigure(encoding='utf-8')
|
|
except:
|
|
# Python 3.6 이하 버전 호환
|
|
sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())
|
|
sys.stderr = codecs.getwriter('utf-8')(sys.stderr.detach())
|
|
|
|
# 서버 설정
|
|
PORT = 3000
|
|
HOST = '0.0.0.0' # 모든 인터페이스에서 접근 가능
|
|
|
|
class CustomHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
"""커스텀 HTTP 요청 핸들러"""
|
|
|
|
def end_headers(self):
|
|
# CORS 헤더 추가 (개발용)
|
|
self.send_header('Access-Control-Allow-Origin', '*')
|
|
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
|
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
|
# 캐시 비활성화 (개발용)
|
|
self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
|
|
self.send_header('Pragma', 'no-cache')
|
|
self.send_header('Expires', '0')
|
|
super().end_headers()
|
|
|
|
def do_GET(self):
|
|
"""GET 요청 처리"""
|
|
original_path = self.path
|
|
|
|
# .html로 직접 접근하는 경우 리다이렉트
|
|
if self.path.endswith('.html') and self.path != '/index.html':
|
|
clean_path = self.path[:-5] # .html 제거
|
|
self.send_response(301)
|
|
self.send_header('Location', clean_path)
|
|
self.end_headers()
|
|
return
|
|
|
|
# .html 확장자 없이 접근 시 자동으로 .html 추가
|
|
if not self.path.endswith('/') and '.' not in os.path.basename(self.path):
|
|
html_path = self.path + '.html'
|
|
if os.path.exists(html_path.lstrip('/')):
|
|
self.path = html_path
|
|
|
|
# 기본 파일 처리
|
|
if self.path == '/':
|
|
self.path = '/index.html'
|
|
|
|
super().do_GET()
|
|
|
|
def log_message(self, format, *args):
|
|
"""로그 메시지 포맷팅"""
|
|
print(f"[{self.log_date_time_string()}] {format % args}")
|
|
|
|
def find_available_port(start_port=8001):
|
|
"""사용 가능한 포트 찾기"""
|
|
for port in range(start_port, start_port + 20): # 더 많은 포트 시도
|
|
try:
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 주소 재사용
|
|
sock.bind(('localhost', port)) # 실제로 바인드 테스트
|
|
sock.close()
|
|
print(f"Available port found: {port}")
|
|
return port # 성공하면 해당 포트 반환
|
|
except OSError:
|
|
continue # 포트가 사용 중이면 다음 포트 시도
|
|
|
|
print(f"No available port found in range {start_port}-{start_port+19}")
|
|
return start_port # 찾지 못하면 기본값 반환
|
|
|
|
def main():
|
|
"""메인 서버 실행 함수"""
|
|
# 현재 디렉토리가 프로젝트 루트인지 확인
|
|
if not os.path.exists('index.html'):
|
|
print("Error: index.html file not found.")
|
|
print("Please run from project root directory.")
|
|
sys.exit(1)
|
|
|
|
# 사용 가능한 포트 찾기
|
|
available_port = find_available_port(PORT)
|
|
|
|
try:
|
|
# 서버 시작
|
|
httpd = socketserver.TCPServer((HOST, available_port), CustomHTTPRequestHandler)
|
|
httpd.allow_reuse_address = True # 주소 재사용 허용
|
|
with httpd:
|
|
# 로컬 및 외부 접근 주소 표시
|
|
import socket
|
|
local_ip = socket.gethostbyname(socket.gethostname())
|
|
|
|
print("Mingle Studio Development Server Started!")
|
|
print("="*60)
|
|
print(f"Local Access: http://localhost:{available_port}")
|
|
print(f"Network Access: http://{local_ip}:{available_port}")
|
|
print(f"Root Directory: {os.getcwd()}")
|
|
print("="*60)
|
|
print("Main Pages:")
|
|
print(f" Home: http://localhost:{available_port}/")
|
|
print(f" About: http://localhost:{available_port}/about")
|
|
print(f" Services: http://localhost:{available_port}/services")
|
|
print(f" Portfolio: http://localhost:{available_port}/portfolio")
|
|
print(f" Gallery: http://localhost:{available_port}/gallery")
|
|
print(f" Contact: http://localhost:{available_port}/contact")
|
|
print(f" Q&A: http://localhost:{available_port}/qna")
|
|
print("="*60)
|
|
print("External Access Setup:")
|
|
print(f" 1. Setup port forwarding for port {available_port} on router")
|
|
print(f" 2. Access via public IP: http://[PUBLIC_IP]:{available_port}")
|
|
print(f" 3. Same network: http://{local_ip}:{available_port}")
|
|
print("="*60)
|
|
print("Tip: Press Ctrl+C to stop the server.")
|
|
print("Opening browser automatically...")
|
|
|
|
# 기본 브라우저에서 자동으로 열기 (로컬호스트로)
|
|
webbrowser.open(f"http://localhost:{available_port}")
|
|
|
|
# 서버 실행
|
|
httpd.serve_forever()
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n\nServer stopped.")
|
|
print("Goodbye!")
|
|
except OSError as e:
|
|
if e.errno == 10048: # WinError 10048
|
|
print(f"\nError: Port {available_port} is already in use.")
|
|
print("Try different port or check the following:")
|
|
print("1. Check if another server is running")
|
|
print("2. Kill Python process in Task Manager")
|
|
print(f"3. Run in command prompt: netstat -ano | findstr :{available_port}")
|
|
else:
|
|
print(f"Server error: {e}")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |