Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
89
backend/internal/api/server_keepalive.go
Normal file
89
backend/internal/api/server_keepalive.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (s *Server) enableKeepAlive(timeout time.Duration, onTimeout func()) {
|
||||
if timeout <= 0 || onTimeout == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.keepAliveEnabled = true
|
||||
s.keepAliveTimeout = timeout
|
||||
s.keepAliveOnTimeout = onTimeout
|
||||
s.keepAliveHeartbeat = make(chan struct{}, 1)
|
||||
s.keepAliveStop = make(chan struct{}, 1)
|
||||
|
||||
s.engine.GET("/keep-alive", s.handleKeepAlive)
|
||||
|
||||
go s.watchKeepAlive()
|
||||
}
|
||||
|
||||
func (s *Server) handleKeepAlive(c *gin.Context) {
|
||||
if s.localPassword != "" {
|
||||
provided := strings.TrimSpace(c.GetHeader("Authorization"))
|
||||
if provided != "" {
|
||||
parts := strings.SplitN(provided, " ", 2)
|
||||
if len(parts) == 2 && strings.EqualFold(parts[0], "bearer") {
|
||||
provided = parts[1]
|
||||
}
|
||||
}
|
||||
if provided == "" {
|
||||
provided = strings.TrimSpace(c.GetHeader("X-Local-Password"))
|
||||
}
|
||||
if subtle.ConstantTimeCompare([]byte(provided), []byte(s.localPassword)) != 1 {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid password"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.signalKeepAlive()
|
||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
}
|
||||
|
||||
func (s *Server) signalKeepAlive() {
|
||||
if !s.keepAliveEnabled {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case s.keepAliveHeartbeat <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) watchKeepAlive() {
|
||||
if !s.keepAliveEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
timer := time.NewTimer(s.keepAliveTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-timer.C:
|
||||
log.Warnf("keep-alive endpoint idle for %s, shutting down", s.keepAliveTimeout)
|
||||
if s.keepAliveOnTimeout != nil {
|
||||
s.keepAliveOnTimeout()
|
||||
}
|
||||
return
|
||||
case <-s.keepAliveHeartbeat:
|
||||
if !timer.Stop() {
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
}
|
||||
timer.Reset(s.keepAliveTimeout)
|
||||
case <-s.keepAliveStop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue