Skip to content

Instantly share code, notes, and snippets.

@Lajule
Last active April 12, 2023 00:25
Show Gist options
  • Save Lajule/e7f98d5839056d83bb286764a307570a to your computer and use it in GitHub Desktop.
Save Lajule/e7f98d5839056d83bb286764a307570a to your computer and use it in GitHub Desktop.
Golang HTTP Server
package server
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"html/template"
"io/fs"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
)
type Server struct {
http.Server
}
func NewServer(bindAddr, caCert string, views, assets fs.FS) *Server {
router := gin.Default()
if views != nil {
templates := template.New("")
if err := fs.WalkDir(views, ".", func(path string, info fs.DirEntry, e error) error {
if e != nil {
return fmt.Errorf("failed accessing path: %w", e)
}
if info.IsDir() {
return nil
}
file, err := fs.ReadFile(views, path)
if err != nil {
return fmt.Errorf("failed reading file: %w", err)
}
if _, err := templates.Parse(string(file)); err != nil {
return fmt.Errorf("failed parsing template: %w", err)
}
return nil
}); err != nil {
log.Fatalf("failed creating views resources: %v", err)
}
router.SetHTMLTemplate(templates)
}
if assets != nil {
router.StaticFS("/assets", http.FS(assets))
}
var tlsConfig *tls.Config
if len(caCert) > 0 {
pool := x509.NewCertPool()
data, err := os.ReadFile(caCert)
if err != nil {
log.Fatalf("failed opening trusted SSL Certificate Authorities file: %v", err)
}
if !pool.AppendCertsFromPEM(data) {
log.Fatal("failed parsing CA certificate")
}
tlsConfig = &tls.Config{
RootCAs: pool,
ClientAuth: tls.RequireAndVerifyClientCert,
MinVersion: tls.VersionTLS12,
}
}
return &Server{
Server: http.Server{
Addr: bindAddr,
Handler: router,
TLSConfig: tlsConfig,
},
}
}
func (srv *Server) Start(clientCert, clientKey string, gracefulShutdownTimeout time.Duration) {
go func() {
var fn string
var err error
if len(clientCert) > 0 && len(clientKey) > 0 {
fn = "ListenAndServeTLS"
err = srv.ListenAndServeTLS(clientCert, clientKey)
} else {
fn = "ListenAndServe"
err = srv.ListenAndServe()
}
if err != http.ErrServerClosed {
log.Fatalf("failed listenning and serving (%v): %v", fn, err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), gracefulShutdownTimeout)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("server forced to shutdown: %v", err)
}
log.Println("server exiting...")
}
@Lajule
Copy link
Author

Lajule commented Sep 5, 2022

package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/Lajule/tmp/server"
)

func main() {
	srv := server.NewServer(":8080", "", nil, nil)

	srv.Handler.(*gin.Engine).GET("/", func(c *gin.Context) {
		c.Status(http.StatusOK)
	})

	srv.Start("", "", 5*time.Second)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment