github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/litrpc/listener.go (about) 1 package litrpc 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/rpc" 10 "net/rpc/jsonrpc" 11 "strings" 12 13 "github.com/mit-dci/lit/logging" 14 15 "golang.org/x/net/websocket" 16 17 "github.com/mit-dci/lit/qln" 18 "github.com/mit-dci/lit/webui" 19 ) 20 21 /* 22 Remote Procedure Calls 23 RPCs are how people tell the lit node what to do. 24 It ends up being the root of ~everything in the executable. 25 26 */ 27 28 // A LitRPC is the user I/O interface; it owns and initialized a SPVCon and LitNode 29 // and listens and responds on RPC 30 31 type LitRPC struct { 32 Node *qln.LitNode 33 OffButton chan bool 34 } 35 36 func serveWS(ws *websocket.Conn) { 37 body, err := ioutil.ReadAll(ws.Request().Body) 38 if err != nil { 39 logging.Errorf("Error reading body: %v", err) 40 return 41 } 42 43 logging.Infof(string(body)) 44 ws.Request().Body = ioutil.NopCloser(bytes.NewBuffer(body)) 45 46 jsonrpc.ServeConn(ws) 47 } 48 49 func WebUIHandler(w http.ResponseWriter, r *http.Request) { 50 if r.URL.Path == "/" { 51 r.URL.Path = "/index.html" 52 } 53 54 bytes, err := webui.Asset(r.URL.Path[1:]) 55 if err != nil { 56 logging.Errorf("Error serving request [%s]: [%s]\n", r.URL.Path, err.Error()) 57 w.WriteHeader(404) 58 return 59 } 60 61 if strings.HasSuffix(r.URL.Path, ".html") { 62 w.Header().Add("Content-Type", "text/html") 63 } else if strings.HasSuffix(r.URL.Path, ".ico") { 64 w.Header().Add("Content-Type", "image/x-icon") 65 } else if strings.HasSuffix(r.URL.Path, ".js") { 66 w.Header().Add("Content-Type", "application/javascript") 67 } else if strings.HasSuffix(r.URL.Path, ".json") { 68 w.Header().Add("Content-Type", "application/json") 69 } else if strings.HasSuffix(r.URL.Path, ".css") { 70 w.Header().Add("Content-Type", "text/css") 71 } 72 73 w.WriteHeader(200) 74 w.Write(bytes) 75 } 76 77 // OiOoReadWriter is for One-In-One-Out Reader/Writer and I hope to god that it works. 78 type OiOoReadWriter struct { 79 from io.ReadCloser 80 to io.Writer 81 } 82 83 func (o OiOoReadWriter) Read(p []byte) (int, error) { 84 return o.from.Read(p) 85 } 86 87 func (o OiOoReadWriter) Write(p []byte) (int, error) { 88 return o.to.Write(p) 89 } 90 91 func (o OiOoReadWriter) Close() error { 92 return o.from.Close() 93 } 94 95 func serveOneoffs(rw http.ResponseWriter, req *http.Request) { 96 o := OiOoReadWriter{ 97 from: req.Body, 98 to: rw, 99 } 100 jsonrpc.ServeConn(o) 101 o.Close() 102 } 103 104 func RPCListen(rpcl *LitRPC, host string, port uint16) { 105 106 rpc.Register(rpcl) 107 listenString := fmt.Sprintf("%s:%d", host, port) 108 109 http.Handle("/ws", websocket.Handler(serveWS)) 110 http.HandleFunc("/static/", WebUIHandler) 111 http.HandleFunc("/", WebUIHandler) 112 http.HandleFunc("/oneoff", serveOneoffs) 113 logging.Fatal(http.ListenAndServe(listenString, nil)) 114 }