Add exit call

Former-commit-id: 4a89915826
This commit is contained in:
Owen
2025-11-03 14:15:16 -08:00
parent a7979259f3
commit 36fc3ea253
2 changed files with 46 additions and 0 deletions

View File

@@ -44,6 +44,7 @@ type API struct {
listener net.Listener listener net.Listener
server *http.Server server *http.Server
connectionChan chan ConnectionRequest connectionChan chan ConnectionRequest
shutdownChan chan struct{}
statusMu sync.RWMutex statusMu sync.RWMutex
peerStatuses map[int]*PeerStatus peerStatuses map[int]*PeerStatus
connectedAt time.Time connectedAt time.Time
@@ -57,6 +58,7 @@ func NewAPI(addr string) *API {
s := &API{ s := &API{
addr: addr, addr: addr,
connectionChan: make(chan ConnectionRequest, 1), connectionChan: make(chan ConnectionRequest, 1),
shutdownChan: make(chan struct{}, 1),
peerStatuses: make(map[int]*PeerStatus), peerStatuses: make(map[int]*PeerStatus),
} }
@@ -68,6 +70,7 @@ func NewAPISocket(socketPath string) *API {
s := &API{ s := &API{
socketPath: socketPath, socketPath: socketPath,
connectionChan: make(chan ConnectionRequest, 1), connectionChan: make(chan ConnectionRequest, 1),
shutdownChan: make(chan struct{}, 1),
peerStatuses: make(map[int]*PeerStatus), peerStatuses: make(map[int]*PeerStatus),
} }
@@ -79,6 +82,7 @@ func (s *API) Start() error {
mux := http.NewServeMux() mux := http.NewServeMux()
mux.HandleFunc("/connect", s.handleConnect) mux.HandleFunc("/connect", s.handleConnect)
mux.HandleFunc("/status", s.handleStatus) mux.HandleFunc("/status", s.handleStatus)
mux.HandleFunc("/exit", s.handleExit)
s.server = &http.Server{ s.server = &http.Server{
Handler: mux, Handler: mux,
@@ -132,6 +136,11 @@ func (s *API) GetConnectionChannel() <-chan ConnectionRequest {
return s.connectionChan return s.connectionChan
} }
// GetShutdownChannel returns the channel for receiving shutdown requests
func (s *API) GetShutdownChannel() <-chan struct{} {
return s.shutdownChan
}
// UpdatePeerStatus updates the status of a peer including endpoint and relay info // UpdatePeerStatus updates the status of a peer including endpoint and relay info
func (s *API) UpdatePeerStatus(siteID int, connected bool, rtt time.Duration, endpoint string, isRelay bool) { func (s *API) UpdatePeerStatus(siteID int, connected bool, rtt time.Duration, endpoint string, isRelay bool) {
s.statusMu.Lock() s.statusMu.Lock()
@@ -255,3 +264,28 @@ func (s *API) handleStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp) json.NewEncoder(w).Encode(resp)
} }
// handleExit handles the /exit endpoint
func (s *API) handleExit(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
logger.Info("Received exit request via API")
// Send shutdown signal
select {
case s.shutdownChan <- struct{}{}:
// Signal sent successfully
default:
// Channel already has a signal, don't block
}
// Return a success response
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "shutdown initiated",
})
}

View File

@@ -58,6 +58,10 @@ type Config struct {
} }
func Run(ctx context.Context, config Config) { func Run(ctx context.Context, config Config) {
// Create a cancellable context for internal shutdown control
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// Extract commonly used values from config for convenience // Extract commonly used values from config for convenience
var ( var (
endpoint = config.Endpoint endpoint = config.Endpoint
@@ -108,6 +112,14 @@ func Run(ctx context.Context, config Config) {
if err := apiServer.Start(); err != nil { if err := apiServer.Start(); err != nil {
logger.Fatal("Failed to start HTTP server: %v", err) logger.Fatal("Failed to start HTTP server: %v", err)
} }
// Listen for shutdown requests from the API
go func() {
<-apiServer.GetShutdownChannel()
logger.Info("Shutdown requested via API")
// Cancel the context to trigger graceful shutdown
cancel()
}()
} }
// // Use a goroutine to handle connection requests // // Use a goroutine to handle connection requests