github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-server/servermain/servermain.go (about)

     1  package servermain
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"io/ioutil"
     8  	"log"
     9  	"os"
    10  	"path"
    11  	"strconv"
    12  
    13  	"github.com/olahol/melody"
    14  	"github.com/onrik/logrus/filename"
    15  	"github.com/sirupsen/logrus"
    16  	"github.com/stamp/mdns"
    17  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/ca"
    18  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/handlers"
    19  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/logic"
    20  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/models"
    21  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/store"
    22  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/webserver"
    23  	"github.com/stampzilla/stampzilla-go/nodes/stampzilla-server/websocket"
    24  )
    25  
    26  // Main contains deps used by server that will be exposed so we can write good end to end tests
    27  type Main struct {
    28  	Config     *models.Config
    29  	Store      *store.Store
    30  	HTTPServer *webserver.Webserver
    31  	TLSServer  *webserver.Webserver
    32  	CA         *ca.CA
    33  }
    34  
    35  // New creates a new main
    36  func New(config *models.Config) *Main {
    37  	return &Main{
    38  		Config: config,
    39  	}
    40  }
    41  
    42  func (c *Main) Run() {
    43  	done := c.HTTPServer.Start(":"+c.Config.Port, nil)
    44  	tlsDone := c.TLSServer.Start(":"+c.Config.TLSPort, c.TLSConfig())
    45  
    46  	// Setup and start mDNS
    47  	if port, err := strconv.Atoi(c.Config.Port); err == nil {
    48  		host, _ := os.Hostname()
    49  		info := []string{"stampzilla-go"}
    50  		mdnsService, _ := mdns.NewMDNSService(host, "_stampzilla._tcp", "", "", port, nil, info)
    51  		mdnsServer, _ := mdns.NewServer(&mdns.Config{Zone: mdnsService})
    52  		defer mdnsServer.Shutdown()
    53  	}
    54  
    55  	// start logic
    56  
    57  	ctx, cancel := context.WithCancel(context.Background())
    58  	c.Store.Logic.Start(ctx)
    59  	c.Store.Scheduler.Start(ctx)
    60  
    61  	<-done
    62  	<-tlsDone
    63  	cancel() // stop logic
    64  	c.Store.Logic.Wait()
    65  	c.Config.Save("config.json")
    66  }
    67  
    68  func (m *Main) TLSConfig() *tls.Config {
    69  	caCert, err := ioutil.ReadFile(path.Join("certificates", "ca.crt"))
    70  	if err != nil {
    71  		log.Fatal(err)
    72  	}
    73  	caCertPool := x509.NewCertPool()
    74  	caCertPool.AppendCertsFromPEM(caCert)
    75  	return &tls.Config{
    76  		// Dynamic load certificates
    77  		GetCertificate: m.CA.GetCertificate,
    78  
    79  		// Needed to verify client certificates
    80  		ClientCAs: caCertPool,
    81  		//Certificates: []tls.Certificate{*c.CA.TLS},
    82  		ClientAuth: tls.VerifyClientCertIfGiven,
    83  	}
    84  }
    85  
    86  // Init initializes the web handlers. Could be used to start server or to test it
    87  func (m *Main) Init() {
    88  	var err error
    89  
    90  	filenameHook := filename.NewHook()
    91  	logrus.AddHook(filenameHook)
    92  
    93  	if m.Config.LogLevel != "" {
    94  		lvl, err := logrus.ParseLevel(m.Config.LogLevel)
    95  		if err != nil {
    96  			logrus.Fatal(err)
    97  			return
    98  		}
    99  		logrus.SetLevel(lvl)
   100  	}
   101  
   102  	m.CA, err = ca.LoadOrCreate()
   103  	if err != nil {
   104  		logrus.Fatal(err)
   105  	}
   106  
   107  	insecureMelody := melody.New()
   108  	//TODO i dont like melody anymore.. raw gorilla seems fine?
   109  	insecureMelody.Config.MaxMessageSize = 0
   110  	secureMelody := melody.New()
   111  	//TODO i dont like melody anymore.. raw gorilla seems fine?
   112  	secureMelody.Config.MaxMessageSize = 0
   113  
   114  	insecureSender := websocket.NewWebsocketSender(insecureMelody)
   115  	secureSender := websocket.NewWebsocketSender(secureMelody)
   116  
   117  	sss := logic.NewSavedStateStore()
   118  	l := logic.New(sss, secureSender)
   119  	scheduler := logic.NewScheduler(sss, secureSender)
   120  	m.Store = store.New(l, scheduler, sss)
   121  	m.CA.SetStore(m.Store)
   122  
   123  	if err = m.Store.Load(); err != nil {
   124  		log.Fatalf("Failed to load state from disk: %s", err)
   125  	}
   126  	m.HTTPServer = webserver.New(
   127  		m.Store,
   128  		m.Config,
   129  		handlers.NewInSecureWebsockerHandler(m.Store, m.Config, insecureSender, m.CA),
   130  		insecureMelody,
   131  	)
   132  	m.TLSServer = webserver.New(
   133  		m.Store,
   134  		m.Config,
   135  		handlers.NewSecureWebsockerHandler(m.Store, m.Config, secureSender, m.CA),
   136  		secureMelody,
   137  	)
   138  
   139  	m.Config.Save("config.json")
   140  
   141  	m.Store.OnUpdate(handlers.BroadcastUpdate(secureSender))
   142  }