266 lines
5.5 KiB
Go
266 lines
5.5 KiB
Go
|
|
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)
|
||
|
|
}
|