Commit e37e2703 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Implement graceful server shutdown.

This gives the user a friendly message when the server shuts down.
parent 7707775c
...@@ -12,3 +12,7 @@ type client interface { ...@@ -12,3 +12,7 @@ type client interface {
pushConn(id string, conn upConnection, tracks []upTrack, label string) error pushConn(id string, conn upConnection, tracks []upTrack, label string) error
pushClient(id, username string, add bool) error pushClient(id, username string, add bool) error
} }
type kickable interface {
kick(message string) error
}
...@@ -64,7 +64,7 @@ type connectionFailedAction struct { ...@@ -64,7 +64,7 @@ type connectionFailedAction struct {
type permissionsChangedAction struct{} type permissionsChangedAction struct{}
type kickAction struct{ type kickAction struct {
message string message string
} }
...@@ -288,6 +288,16 @@ func (g *group) Range(f func(c client) bool) { ...@@ -288,6 +288,16 @@ func (g *group) Range(f func(c client) bool) {
} }
} }
func (g *group) shutdown(message string) {
g.Range(func(c client) bool {
cc, ok := c.(kickable)
if ok {
cc.kick(message)
}
return true
})
}
const maxChatHistory = 20 const maxChatHistory = 20
func (g *group) clearChatHistory() { func (g *group) clearChatHistory() {
......
...@@ -87,6 +87,7 @@ func main() { ...@@ -87,6 +87,7 @@ func main() {
webserver() webserver()
terminate := make(chan os.Signal, 1) terminate := make(chan os.Signal, 1)
signal.Notify(terminate, syscall.SIGINT) signal.Notify(terminate, syscall.SIGINT, syscall.SIGTERM)
<-terminate <-terminate
shutdown()
} }
...@@ -943,6 +943,10 @@ func setPermissions(g *group, id string, perm string) error { ...@@ -943,6 +943,10 @@ func setPermissions(g *group, id string, perm string) error {
return c.action(permissionsChangedAction{}) return c.action(permissionsChangedAction{})
} }
func (c *webClient) kick(message string) error {
return c.action(kickAction{message})
}
func kickClient(g *group, id string, message string) error { func kickClient(g *group, id string, message string) error {
g.mu.Lock() g.mu.Lock()
defer g.mu.Unlock() defer g.mu.Unlock()
...@@ -952,12 +956,12 @@ func kickClient(g *group, id string, message string) error { ...@@ -952,12 +956,12 @@ func kickClient(g *group, id string, message string) error {
return userError("no such user") return userError("no such user")
} }
c, ok := client.(*webClient) c, ok := client.(kickable)
if !ok { if !ok {
return userError("this is not a real user") return userError("this client is not kickable")
} }
return c.action(kickAction{message}) return c.kick(message)
} }
func handleClientMessage(c *webClient, m clientMessage) error { func handleClientMessage(c *webClient, m clientMessage) error {
......
...@@ -2,6 +2,7 @@ package main ...@@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
...@@ -19,6 +20,8 @@ import ( ...@@ -19,6 +20,8 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
) )
var server *http.Server
func webserver() { func webserver() {
http.Handle("/", mungeHandler{http.FileServer(http.Dir(staticRoot))}) http.Handle("/", mungeHandler{http.FileServer(http.Dir(staticRoot))})
http.HandleFunc("/group/", groupHandler) http.HandleFunc("/group/", groupHandler)
...@@ -39,17 +42,24 @@ func webserver() { ...@@ -39,17 +42,24 @@ func webserver() {
http.HandleFunc("/stats", statsHandler) http.HandleFunc("/stats", statsHandler)
go func() { go func() {
server := &http.Server{ server = &http.Server{
Addr: httpAddr, Addr: httpAddr,
ReadHeaderTimeout: 60 * time.Second, ReadHeaderTimeout: 60 * time.Second,
IdleTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second,
} }
server.RegisterOnShutdown(func() {
groups.mu.Lock()
defer groups.mu.Unlock()
for _, g := range groups.groups {
go g.shutdown("server is shutting down")
}
})
var err error var err error
err = server.ListenAndServeTLS( err = server.ListenAndServeTLS(
filepath.Join(dataDir, "cert.pem"), filepath.Join(dataDir, "cert.pem"),
filepath.Join(dataDir, "key.pem"), filepath.Join(dataDir, "key.pem"),
) )
if err != nil { if err != nil && err != http.ErrServerClosed {
log.Printf("ListenAndServeTLS: %v", err) log.Printf("ListenAndServeTLS: %v", err)
} }
}() }()
...@@ -457,3 +467,8 @@ func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, gr ...@@ -457,3 +467,8 @@ func serveGroupRecordings(w http.ResponseWriter, r *http.Request, f *os.File, gr
fmt.Fprintf(w, "</table>\n") fmt.Fprintf(w, "</table>\n")
fmt.Fprintf(w, "</body></html>\n") fmt.Fprintf(w, "</body></html>\n")
} }
func shutdown() {
ctx, _ := context.WithTimeout(context.Background(), 2*time.Second)
server.Shutdown(ctx)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment