@@ -10,6 +10,7 @@ import (
1010 "io/ioutil"
1111 "net"
1212 "net/http"
13+ "os"
1314 "path/filepath"
1415 "strings"
1516 "sync"
@@ -125,7 +126,7 @@ func (g *Shushtar) Run() error {
125126 return fmt .Errorf ("please set a strong password for the UI, " +
126127 "at least %d characters long" , uiPasswordMinLength )
127128 }
128-
129+
129130 // Initiate our listeners. For now, we only support listening on one
130131 // port at a time because we can only pass in one pre-configured RPC
131132 // listener into lnd.
@@ -427,7 +428,7 @@ func (g *Shushtar) startGrpcWebProxy() error {
427428 if err != nil {
428429 return fmt .Errorf ("could not load statik file system: %v" , err )
429430 }
430- staticFileServer := http .FileServer (statikFS )
431+ staticFileServer := http .FileServer (& ClientRouteWrapper { statikFS } )
431432
432433 // Create the gRPC web proxy that connects to lnd internally using the
433434 // admin macaroon and converts the browser's gRPC web calls into native
@@ -622,3 +623,22 @@ func readMacaroon(macPath string) (grpc.DialOption, error) {
622623 cred := macaroons .NewMacaroonCredential (mac )
623624 return grpc .WithPerRPCCredentials (cred ), nil
624625}
626+
627+ // ClientRouteWrapper is a wrapper around a FileSystem which properly handles
628+ // URL routes that are defined in the client app but unknown to the backend
629+ // http server
630+ type ClientRouteWrapper struct {
631+ assets http.FileSystem
632+ }
633+
634+ // Open intercepts requests to open files. If the file does not exist and there
635+ // is no file extension, then assume this is a client side route and return the
636+ // contents of index.html
637+ func (i * ClientRouteWrapper ) Open (name string ) (http.File , error ) {
638+ ret , err := i .assets .Open (name )
639+ if ! os .IsNotExist (err ) || filepath .Ext (name ) != "" {
640+ return ret , err
641+ }
642+
643+ return i .assets .Open ("/index.html" )
644+ }
0 commit comments