88
99import uvicorn
1010from fastapi import FastAPI , WebSocket , WebSocketDisconnect
11- from watchdog .events import FileSystemEvent , FileSystemEventHandler
12- from watchdog .observers import Observer
1311
1412from eval_protocol .dataset_logger import default_logger
1513from eval_protocol .utils .vite_server import ViteServer
1917logger = logging .getLogger (__name__ )
2018
2119
22- class FileWatcher (FileSystemEventHandler ):
23- """File system watcher that tracks file changes."""
24-
25- def __init__ (self , websocket_manager ):
26- self .websocket_manager : WebSocketManager = websocket_manager
27- self .ignored_patterns = {
28- ".git" ,
29- "__pycache__" ,
30- ".pytest_cache" ,
31- "node_modules" ,
32- ".DS_Store" ,
33- "*.pyc" ,
34- "*.pyo" ,
35- "*.pyd" ,
36- ".coverage" ,
37- "*.log" ,
38- "*.tmp" ,
39- "*.swp" ,
40- "*.swo" ,
41- "*~" ,
42- }
43-
44- def should_ignore (self , path : str ) -> bool :
45- """Check if a path should be ignored."""
46- path_lower = path .lower ()
47- for pattern in self .ignored_patterns :
48- if pattern .startswith ("*" ):
49- if path_lower .endswith (pattern [1 :]):
50- return True
51- elif pattern in path_lower :
52- return True
53- return False
54-
55- def on_created (self , event : FileSystemEvent ):
56- if not event .is_directory and not self .should_ignore (event .src_path ):
57- self .websocket_manager .broadcast_file_update ("file_created" , event .src_path )
58-
59- def on_modified (self , event : FileSystemEvent ):
60- if not event .is_directory and not self .should_ignore (event .src_path ):
61- self .websocket_manager .broadcast_file_update ("file_changed" , event .src_path )
62-
63- def on_deleted (self , event : FileSystemEvent ):
64- if not event .is_directory and not self .should_ignore (event .src_path ):
65- self .websocket_manager .broadcast_file_update ("file_deleted" , event .src_path )
66-
67-
6820class WebSocketManager :
6921 """Manages WebSocket connections and broadcasts messages."""
7022
@@ -142,7 +94,6 @@ class LogsServer(ViteServer):
14294 Enhanced server for serving Vite-built SPA with file watching and WebSocket support.
14395
14496 This server extends ViteServer to add:
145- - File system watching
14697 - WebSocket connections for real-time updates
14798 - Live log streaming
14899 """
@@ -155,31 +106,21 @@ def __init__(
155106 host : str = "localhost" ,
156107 port : Optional [int ] = 8000 ,
157108 index_file : str = "index.html" ,
158- watch_paths : Optional [List [str ]] = None ,
159109 ):
160110 # Initialize WebSocket manager
161111 self .websocket_manager = WebSocketManager ()
162112
163- # Set up file watching
164- self .watch_paths = watch_paths or [os .getcwd ()]
165- self .observer = Observer ()
166- self .file_watcher = FileWatcher (self .websocket_manager )
167- self ._file_watching_started = False
168-
169113 @asynccontextmanager
170114 async def lifespan (app : FastAPI ):
171- self .start_file_watching ()
172115 self .websocket_manager ._loop = asyncio .get_running_loop ()
173116 yield
174- self .stop_file_watching ()
175117
176118 super ().__init__ (build_dir , host , port , index_file , lifespan = lifespan )
177119
178120 # Add WebSocket endpoint
179121 self ._setup_websocket_routes ()
180122
181123 logger .info (f"LogsServer initialized on { host } :{ port } " )
182- logger .info (f"Watching paths: { self .watch_paths } " )
183124
184125 def _setup_websocket_routes (self ):
185126 """Set up WebSocket routes for real-time communication."""
@@ -207,32 +148,6 @@ async def status():
207148 "watch_paths" : self .watch_paths ,
208149 }
209150
210- def start_file_watching (self ):
211- """Start watching file system for changes."""
212- # Check if file watching has already been started
213- if self ._file_watching_started :
214- logger .info ("File watching already started, skipping" )
215- return
216-
217- for path in self .watch_paths :
218- if os .path .exists (path ):
219- self .observer .schedule (self .file_watcher , path , recursive = True )
220- logger .info (f"Started watching: { path } " )
221- else :
222- logger .warning (f"Watch path does not exist: { path } " )
223-
224- self .observer .start ()
225- self ._file_watching_started = True
226- logger .info ("File watching started" )
227-
228- def stop_file_watching (self ):
229- """Stop watching file system."""
230- if self ._file_watching_started :
231- self .observer .stop ()
232- self .observer .join ()
233- self ._file_watching_started = False
234- logger .info ("File watching stopped" )
235-
236151 async def run_async (self ):
237152 """
238153 Run the logs server asynchronously with file watching.
@@ -241,9 +156,6 @@ async def run_async(self):
241156 reload: Whether to enable auto-reload (default: False)
242157 """
243158 try :
244- # Start file watching
245- self .start_file_watching ()
246-
247159 logger .info (f"Starting LogsServer on { self .host } :{ self .port } " )
248160 logger .info (f"Serving files from: { self .build_dir } " )
249161 logger .info ("WebSocket endpoint available at /ws" )
@@ -263,8 +175,6 @@ async def run_async(self):
263175
264176 except KeyboardInterrupt :
265177 logger .info ("Shutting down LogsServer..." )
266- finally :
267- self .stop_file_watching ()
268178
269179 def run (self ):
270180 """
@@ -280,20 +190,5 @@ def run(self):
280190app = server .app
281191
282192
283- def serve_logs ():
284- """
285- Convenience function to create and run a LogsServer.
286-
287- Args:
288- build_dir: Path to the Vite build output directory
289- host: Host to bind the server to
290- port: Port to bind the server to (default: 4789 for logs)
291- index_file: Name of the main index file
292- watch_paths: List of paths to watch for file changes
293- reload: Whether to enable auto-reload
294- """
295- server .run ()
296-
297-
298193if __name__ == "__main__" :
299- serve_logs ()
194+ server . run ()
0 commit comments