package server import ( "bufio" "computer-network/admin" "computer-network/config" "fmt" "net" "sync" ) type Server struct { listener net.Listener config *config.Config handler *Handler mu sync.RWMutex running bool stopChan chan struct{} } func NewServer(cfg *config.Config) *Server { return &Server{ config: cfg, handler: NewHandler(cfg.GetRootDir()), stopChan: make(chan struct{}), } } func (s *Server) Start() error { s.mu.Lock() defer s.mu.Unlock() if s.running { return fmt.Errorf("server is already running") } var err error addr := fmt.Sprintf(":%d", s.config.GetPort()) s.listener, err = net.Listen("tcp", addr) if err != nil { return fmt.Errorf("failed to listen on port %d: %v", s.config.GetPort(), err) } s.running = true fmt.Printf("Web Server started on port %d\n", s.config.GetPort()) fmt.Printf("Root directory: %s\n", s.config.GetRootDir()) fmt.Printf("Admin console: http://localhost:%d\n", s.config.GetAdminPort()) go s.acceptConnections() return nil } func (s *Server) acceptConnections() { for { select { case <-s.stopChan: return default: conn, err := s.listener.Accept() if err != nil { select { case <-s.stopChan: return default: fmt.Printf("Error accepting connection: %v\n", err) continue } } go s.handler.HandleConnection(conn) } } } func (s *Server) Stop() error { s.mu.Lock() defer s.mu.Unlock() if !s.running { return fmt.Errorf("server is not running") } close(s.stopChan) s.running = false if s.listener != nil { err := s.listener.Close() if err != nil { fmt.Printf("Error closing listener: %v\n", err) } } fmt.Println("Web Server stopped") return nil } func (s *Server) IsRunning() bool { s.mu.RLock() defer s.mu.RUnlock() return s.running } func (s *Server) GetPort() int { return s.config.GetPort() } func (s *Server) UpdateConfig(cfg *config.Config) { s.mu.Lock() defer s.mu.Unlock() s.config = cfg s.handler = NewHandler(cfg.GetRootDir()) } type AdminServer struct { listener net.Listener config *config.Config adminHandler *admin.AdminHandler webServer *Server mu sync.RWMutex running bool stopChan chan struct{} } func NewAdminServer(cfg *config.Config) *AdminServer { return &AdminServer{ config: cfg, adminHandler: admin.NewAdminHandler(), stopChan: make(chan struct{}), } } func (as *AdminServer) SetWebServer(ws *Server) { as.mu.Lock() defer as.mu.Unlock() as.webServer = ws } func (as *AdminServer) Start() error { as.mu.Lock() defer as.mu.Unlock() if as.running { return fmt.Errorf("admin server is already running") } var err error addr := fmt.Sprintf(":%d", as.config.GetAdminPort()) as.listener, err = net.Listen("tcp", addr) if err != nil { return fmt.Errorf("failed to listen on admin port %d: %v", as.config.GetAdminPort(), err) } as.running = true fmt.Printf("Admin server started on port %d\n", as.config.GetAdminPort()) go as.acceptConnections() return nil } func (as *AdminServer) acceptConnections() { for { select { case <-as.stopChan: return default: conn, err := as.listener.Accept() if err != nil { select { case <-as.stopChan: return default: fmt.Printf("Error accepting admin connection: %v\n", err) continue } } go as.handleAdminConnection(conn) } } } func (as *AdminServer) handleAdminConnection(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) req, err := ParseRequest(reader) if err != nil { response := BuildErrorResponse(StatusBadRequest, "", as.config.GetRootDir()) SendResponse(conn, response) return } if !req.IsGET() && req.Method != "DELETE" { response := BuildErrorResponse(StatusNotImplemented, "", as.config.GetRootDir()) SendResponse(conn, response) return } path := req.GetPath() var response *Response switch path { case "/", "/index.html": httpResp := as.adminHandler.GetIndexPage() response = convertAdminResponse(httpResp) case "/api/logs": if req.IsGET() { httpResp := as.adminHandler.GetLogsJSON() response = convertAdminResponse(httpResp) } else if req.Method == "DELETE" { httpResp := as.adminHandler.ClearLogs() response = convertAdminResponse(httpResp) } else { response = BuildErrorResponse(StatusNotImplemented, "", as.config.GetRootDir()) } case "/logs": httpResp := as.adminHandler.GetLogsPage() response = convertAdminResponse(httpResp) case "/api/status": webServerRunning := as.webServer != nil && as.webServer.IsRunning() webServerPort := 9000 if as.webServer != nil { webServerPort = as.webServer.GetPort() } statusBody := fmt.Sprintf(`{"running":%t,"port":%d}`, webServerRunning, webServerPort) response = NewResponse("200 OK", statusBody, "application/json") default: response = BuildErrorResponse(StatusNotFound, "", as.config.GetRootDir()) } SendResponse(conn, response) } func (as *AdminServer) Stop() error { as.mu.Lock() defer as.mu.Unlock() if !as.running { return fmt.Errorf("admin server is not running") } close(as.stopChan) as.running = false if as.listener != nil { err := as.listener.Close() if err != nil { fmt.Printf("Error closing admin listener: %v\n", err) } } fmt.Println("Admin server stopped") return nil } func (as *AdminServer) IsRunning() bool { as.mu.RLock() defer as.mu.RUnlock() return as.running } func convertAdminResponse(resp *admin.HTTPResponse) *Response { return NewResponse(resp.StatusCode, resp.Body, resp.ContentType) }