2021-05-21 05:49:02 +02:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
2021-07-20 02:09:14 +02:00
|
|
|
"github.com/lbryio/reflector.go/store"
|
|
|
|
|
|
|
|
"github.com/lbryio/lbry.go/v2/extras/stop"
|
|
|
|
|
2021-05-28 01:19:57 +02:00
|
|
|
"github.com/bluele/gcache"
|
2021-06-12 00:56:57 +02:00
|
|
|
nice "github.com/ekyoung/gin-nice-recovery"
|
2021-05-21 05:49:02 +02:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Server is an instance of a peer server that houses the listener and store.
|
|
|
|
type Server struct {
|
2021-05-28 01:19:57 +02:00
|
|
|
store store.BlobStore
|
|
|
|
grp *stop.Group
|
|
|
|
concurrentRequests int
|
|
|
|
missesCache gcache.Cache
|
2021-05-21 05:49:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewServer returns an initialized Server pointer.
|
2021-05-28 01:19:57 +02:00
|
|
|
func NewServer(store store.BlobStore, requestQueueSize int) *Server {
|
2021-05-21 05:49:02 +02:00
|
|
|
return &Server{
|
2021-05-28 01:19:57 +02:00
|
|
|
store: store,
|
|
|
|
grp: stop.New(),
|
|
|
|
concurrentRequests: requestQueueSize,
|
|
|
|
missesCache: gcache.New(2000).Expiration(5 * time.Minute).ARC().Build(),
|
2021-05-21 05:49:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Shutdown gracefully shuts down the peer server.
|
|
|
|
func (s *Server) Shutdown() {
|
|
|
|
log.Debug("shutting down HTTP server")
|
|
|
|
s.grp.StopAndWait()
|
|
|
|
log.Debug("HTTP server stopped")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start starts the server listener to handle connections.
|
|
|
|
func (s *Server) Start(address string) error {
|
|
|
|
gin.SetMode(gin.ReleaseMode)
|
|
|
|
router := gin.Default()
|
|
|
|
router.GET("/blob", s.getBlob)
|
|
|
|
router.HEAD("/blob", s.hasBlob)
|
2021-06-12 00:56:57 +02:00
|
|
|
// Install nice.Recovery, passing the handler to call after recovery
|
|
|
|
router.Use(nice.Recovery(s.recoveryHandler))
|
2021-05-21 05:49:02 +02:00
|
|
|
srv := &http.Server{
|
|
|
|
Addr: address,
|
|
|
|
Handler: router,
|
|
|
|
}
|
|
|
|
go s.listenForShutdown(srv)
|
2021-05-28 01:19:57 +02:00
|
|
|
go InitWorkers(s, s.concurrentRequests)
|
2021-05-21 05:49:02 +02:00
|
|
|
// Initializing the server in a goroutine so that
|
|
|
|
// it won't block the graceful shutdown handling below
|
|
|
|
s.grp.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer s.grp.Done()
|
|
|
|
log.Println("HTTP server listening on " + address)
|
|
|
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
|
|
log.Fatalf("listen: %s\n", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) listenForShutdown(listener *http.Server) {
|
|
|
|
<-s.grp.Ch()
|
|
|
|
// The context is used to inform the server it has 5 seconds to finish
|
|
|
|
// the request it is currently handling
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
if err := listener.Shutdown(ctx); err != nil {
|
|
|
|
log.Fatal("Server forced to shutdown:", err)
|
|
|
|
}
|
|
|
|
}
|