mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-29 00:55:32 +00:00
Broken! Do not execute!
This commit is contained in:
52
helpers/evmux.go
Normal file
52
helpers/evmux.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type EventMux[T any] struct {
|
||||||
|
// INFO: This is a simple event multiplexer that allows to subscribe to events and to publish them.
|
||||||
|
mu sync.Mutex
|
||||||
|
subscribers []chan T
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventMux[T any]() *EventMux[T] {
|
||||||
|
return &EventMux[T]{
|
||||||
|
subscribers: make([]chan T, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventMux[T]) Subscribe(size uint) chan T {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
subscriber := make(chan T, size)
|
||||||
|
e.subscribers = append(e.subscribers, subscriber)
|
||||||
|
return subscriber
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventMux[T]) Unsubscribe(subscriber chan T) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
for i, s := range e.subscribers {
|
||||||
|
if s == subscriber {
|
||||||
|
close(s)
|
||||||
|
e.subscribers = append(e.subscribers[:i], e.subscribers[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventMux[T]) Publish(event T) {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
for _, subscriber := range e.subscribers {
|
||||||
|
subscriber <- event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EventMux[T]) Close() {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
for _, subscriber := range e.subscribers {
|
||||||
|
close(subscriber)
|
||||||
|
}
|
||||||
|
e.subscribers = make([]chan T, 0)
|
||||||
|
}
|
||||||
30
kgpz_web.go
30
kgpz_web.go
@@ -42,8 +42,11 @@ func Bootstrap(k *app.KGPZ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Start(k *app.KGPZ, s *server.Server) {
|
func Start(k *app.KGPZ, s *server.Server) {
|
||||||
|
s.Start()
|
||||||
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
done := make(chan bool, 1)
|
done := make(chan bool, 1)
|
||||||
|
serversignals := s.Events.Subscribe(1)
|
||||||
|
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
@@ -52,17 +55,30 @@ func Start(k *app.KGPZ, s *server.Server) {
|
|||||||
fmt.Println("Received signal. Cleaning up.")
|
fmt.Println("Received signal. Cleaning up.")
|
||||||
// INFO: here we add cleanup functions
|
// INFO: here we add cleanup functions
|
||||||
s.Kill()
|
s.Kill()
|
||||||
|
s.BreakUntil(serversignals, server.Killed)
|
||||||
|
fmt.Println("Server killed.")
|
||||||
k.Shutdown()
|
k.Shutdown()
|
||||||
done <- true
|
done <- true
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// INFO: if the server fails to start this exits the program
|
// Interactive listening for input
|
||||||
// We handle graceful server recovery in the server itself.
|
if k.IsDebug() {
|
||||||
go func() {
|
go func() {
|
||||||
s.Start()
|
for {
|
||||||
<-s.Killed
|
var input string
|
||||||
fmt.Println("Server exited. Cleaning up.")
|
fmt.Scanln(&input)
|
||||||
}()
|
if input == "r" {
|
||||||
|
fmt.Println("Restarting server.")
|
||||||
|
s.Restart()
|
||||||
|
} else if input == "p" {
|
||||||
|
fmt.Println("Pulling repo.")
|
||||||
|
k.Pull()
|
||||||
|
} else if input == "q" {
|
||||||
|
done <- true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
<-done
|
<-done
|
||||||
fmt.Println("Cleanup finished. Exiting.")
|
fmt.Println("Cleanup finished. Exiting.")
|
||||||
|
|||||||
120
server/server.go
120
server/server.go
@@ -6,6 +6,21 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/app"
|
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/app"
|
||||||
|
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Created ServerState = iota
|
||||||
|
Running
|
||||||
|
Restarting
|
||||||
|
ShuttingDown
|
||||||
|
ShutDown
|
||||||
|
ShuttedDown
|
||||||
|
Kill
|
||||||
|
Killing
|
||||||
|
Killed
|
||||||
)
|
)
|
||||||
|
|
||||||
// INFO: Server is a meta-package that handles the current router, which it starts in a goroutine.
|
// INFO: Server is a meta-package that handles the current router, which it starts in a goroutine.
|
||||||
@@ -16,9 +31,7 @@ import (
|
|||||||
// - we reload all clients
|
// - we reload all clients
|
||||||
// - if data validity catastrophically fails, we restart the router to map error pages.
|
// - if data validity catastrophically fails, we restart the router to map error pages.
|
||||||
type Server struct {
|
type Server struct {
|
||||||
running chan bool
|
Events helpers.EventMux[ServerState]
|
||||||
alive chan bool
|
|
||||||
Killed chan bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(k *app.KGPZ) *Server {
|
func Start(k *app.KGPZ) *Server {
|
||||||
@@ -26,81 +39,102 @@ func Start(k *app.KGPZ) *Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start() {
|
func (s *Server) Start() {
|
||||||
srv := &http.Server{Addr: ":8080"}
|
srv := &http.Server{Addr: ":8081"}
|
||||||
s.running = make(chan bool, 1)
|
s.killHandler(srv)
|
||||||
s.alive = make(chan bool, 1)
|
s.shutdownHandler(srv)
|
||||||
s.Killed = s.killHandler(srv, s.alive)
|
s.runnerHandler(srv)
|
||||||
shuttingdown := s.shutdownHandler(srv, s.running)
|
s.restartHandler()
|
||||||
shutdown := s.runnerHandler(srv, shuttingdown)
|
|
||||||
s.restartHandler(shutdown)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Restart() {
|
func (s *Server) Restart() {
|
||||||
s.running <- false
|
s.Events.Publish(ShutDown)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Kill() {
|
func (s *Server) Kill() {
|
||||||
s.alive <- false
|
s.Events.Publish(Kill)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) killHandler(srv *http.Server, alive chan bool) chan bool {
|
func (s *Server) restartHandler() {
|
||||||
kill := make(chan bool, 1)
|
shutdown := s.Events.Subscribe(1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
<-alive
|
s.BreakUntil(shutdown, ShuttedDown)
|
||||||
|
s.Events.Publish(Restarting)
|
||||||
if err := srv.Shutdown(nil); err != nil {
|
|
||||||
fmt.Println("Error shutting down server")
|
|
||||||
}
|
|
||||||
|
|
||||||
kill <- true
|
|
||||||
}()
|
|
||||||
|
|
||||||
return kill
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) restartHandler(shutdown chan bool) {
|
|
||||||
go func() {
|
|
||||||
<-shutdown
|
|
||||||
s.Start()
|
s.Start()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) runnerHandler(srv *http.Server, shuttingdown chan bool) chan bool {
|
func (s *Server) runnerHandler(srv *http.Server) {
|
||||||
shutdown := make(chan bool, 1)
|
|
||||||
|
|
||||||
|
shutttingdown := s.Events.Subscribe(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
s.Events.Publish(Running)
|
||||||
// EXAMPLE:
|
// EXAMPLE:
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
io.WriteString(w, "hello world\n")
|
io.WriteString(w, "hello world\n")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
srv.Handler = mux
|
||||||
|
|
||||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
fmt.Println("Error starting server")
|
fmt.Println("Error starting server")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
<-shuttingdown
|
loop:
|
||||||
shutdown <- true
|
for {
|
||||||
|
msg := <-shutttingdown
|
||||||
|
if msg == ShuttingDown {
|
||||||
|
s.Events.Publish(ShuttedDown)
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
if msg == Killing {
|
||||||
|
s.Events.Publish(Killed)
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return shutdown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) shutdownHandler(srv *http.Server, running chan bool) chan bool {
|
func (s *Server) shutdownHandler(srv *http.Server) {
|
||||||
shuttingdown := make(chan bool, 1)
|
|
||||||
|
|
||||||
|
shutdown := s.Events.Subscribe(1)
|
||||||
go func() {
|
go func() {
|
||||||
<-running
|
s.BreakUntil(shutdown, ShutDown)
|
||||||
|
fmt.Println("Shutting down server")
|
||||||
if err := srv.Shutdown(nil); err != nil {
|
if err := srv.Shutdown(nil); err != nil {
|
||||||
fmt.Println("Error shutting down server")
|
fmt.Println("Error shutting down server")
|
||||||
}
|
}
|
||||||
|
|
||||||
shuttingdown <- true
|
s.Events.Publish(ShuttingDown)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return shuttingdown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Shutdown() {
|
func (s *Server) killHandler(srv *http.Server) {
|
||||||
|
|
||||||
|
kill := s.Events.Subscribe(1)
|
||||||
|
go func() {
|
||||||
|
s.BreakUntil(kill, Kill)
|
||||||
|
fmt.Println("Killing server")
|
||||||
|
if err := srv.Shutdown(nil); err != nil {
|
||||||
|
fmt.Println("Error shutting down server")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Events.Publish(Killing)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) BreakUntil(c chan ServerState, state ServerState) {
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
msg := <-c
|
||||||
|
if msg == state {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Events.Unsubscribe(c)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user