// Copyright 2017 Johan Brandhorst. All Rights Reserved. // See LICENSE for licensing terms. package main import ( "crypto/tls" "net/http" "path" "strings" "time" "github.com/gorilla/websocket" "github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/lpar/gzipped" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" "github.com/johanbrandhorst/wasm-experiments/grpc/backend" "github.com/johanbrandhorst/wasm-experiments/grpc/frontend/bundle" web "github.com/johanbrandhorst/wasm-experiments/grpc/proto" ) var logger *logrus.Logger func init() { logger = logrus.StandardLogger() logrus.SetLevel(logrus.DebugLevel) logrus.SetFormatter(&logrus.TextFormatter{ ForceColors: true, FullTimestamp: true, TimestampFormat: time.RFC3339Nano, DisableSorting: true, }) // Should only be done from init functions grpclog.SetLoggerV2(grpclog.NewLoggerV2(logger.Out, logger.Out, logger.Out)) } func main() { gs := grpc.NewServer() web.RegisterBackendServer(gs, &backend.Backend{}) wrappedServer := grpcweb.WrapServer(gs, grpcweb.WithWebsockets(true)) handler := func(resp http.ResponseWriter, req *http.Request) { // Redirect gRPC and gRPC-Web requests to the gRPC-Web Websocket Proxy server if req.ProtoMajor == 2 && strings.Contains(req.Header.Get("Content-Type"), "application/grpc") || websocket.IsWebSocketUpgrade(req) { wrappedServer.ServeHTTP(resp, req) } else { // Serve the GopherJS client wasmContentTypeSetter(folderReader(gzipped.FileServer(bundle.Assets))).ServeHTTP(resp, req) } } addr := "localhost:10000" httpsSrv := &http.Server{ Addr: addr, Handler: http.HandlerFunc(handler), // Some security settings ReadHeaderTimeout: 5 * time.Second, IdleTimeout: 120 * time.Second, TLSConfig: &tls.Config{ PreferServerCipherSuites: true, CurvePreferences: []tls.CurveID{ tls.CurveP256, tls.X25519, }, }, } logger.Info("Serving on https://" + addr) logger.Fatal(httpsSrv.ListenAndServeTLS("./cert.pem", "./key.pem")) } func wasmContentTypeSetter(fn http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { if strings.Contains(req.URL.Path, ".wasm") { w.Header().Set("content-type", "application/wasm") } fn.ServeHTTP(w, req) } } func folderReader(fn http.Handler) http.HandlerFunc { return func(w http.ResponseWriter, req *http.Request) { if strings.HasSuffix(req.URL.Path, "/") { // Use contents of index.html for directory, if present. req.URL.Path = path.Join(req.URL.Path, "index.html") } if req.URL.Path == "/test.wasm" { w.Header().Set("content-type", "application/wasm") } fn.ServeHTTP(w, req) } }