1 package main 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "flag" 7 "fmt" 8 "io" 9 "net/http" 10 "net/url" 11 "os" 12 "strconv" 13 "time" 14 15 "golang.org/x/net/websocket" 16 "vimagination.zapto.org/jsonrpc" 17 "vimagination.zapto.org/tsserver" 18 ) 19 20 func main() { 21 if err := run(); err != nil { 22 fmt.Fprintln(os.Stderr, err) 23 os.Exit(1) 24 } 25 } 26 27 func run() error { 28 var js bool 29 30 flag.BoolVar(&js, "js", false, "use JS versions") 31 flag.Parse() 32 33 m := http.NewServeMux() 34 35 if js { 36 m.Handle("/lib/", http.StripPrefix("/lib/", http.FileServer(http.Dir("../lib.js")))) 37 } else { 38 m.Handle("/lib/", http.StripPrefix("/lib/", http.FileServer(http.FS(tsserver.WrapFS(os.DirFS("../lib.ts")))))) 39 } 40 m.Handle("/", http.FileServer(http.FS(tsserver.WrapFS(os.DirFS("./"))))) 41 m.Handle("/static", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("123")) })) 42 m.Handle("/echo", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 43 ct := r.Header.Get("Content-Type") 44 if ct != "" { 45 w.Header().Add("Content-Type", ct) 46 } 47 io.Copy(w, r.Body) 48 r.Body.Close() 49 })) 50 m.Handle("/request", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 51 r.ParseForm() 52 postData, _ := io.ReadAll(r.Body) 53 json.NewEncoder(w).Encode(struct { 54 Method string `json:"method"` 55 Auth string `json:"auth,omitempty"` 56 ContentType string `json:"contentType,omitempty"` 57 ContentLength int64 `json:"contentLength,omitempty"` 58 Form url.Values `json:"form,omitempty"` 59 PostForm url.Values `json:"postForm,omitempty"` 60 PostData string `json:"postData,omitempty"` 61 }{ 62 Method: r.Method, 63 Auth: r.Header.Get("Authorization"), 64 ContentType: r.Header.Get("Content-Type"), 65 ContentLength: r.ContentLength, 66 Form: r.Form, 67 PostForm: r.PostForm, 68 PostData: string(postData), 69 }) 70 })) 71 m.Handle("/socket", websocket.Handler(func(conn *websocket.Conn) { 72 conn.SetDeadline(time.Now().Add(time.Second * 60)) 73 io.Copy(conn, conn) 74 })) 75 m.Handle("/socket-close", websocket.Handler(func(conn *websocket.Conn) { conn.Close() })) 76 m.Handle("/rpc", websocket.Handler(func(conn *websocket.Conn) { 77 var jrpc *jsonrpc.Server 78 conn.SetDeadline(time.Now().Add(time.Second * 60)) 79 jrpc = jsonrpc.New(conn, jsonrpc.HandlerFunc(func(method string, data json.RawMessage) (interface{}, error) { 80 switch method { 81 case "static": 82 return "123", nil 83 case "echo": 84 return data, nil 85 case "broadcast": 86 jrpc.Send(jsonrpc.Response{ 87 ID: -1, 88 Result: data, 89 }) 90 return true, nil 91 case "close": 92 conn.Close() 93 return nil, nil 94 } 95 return nil, jsonrpc.Error{ 96 Code: 1, 97 Message: "unknown endpoint", 98 Data: method, 99 } 100 })) 101 jrpc.Handle() 102 })) 103 audio, _ := base64.StdEncoding.DecodeString("UklGRiwAAABXQVZFZm10IBAAAAABAAIARKwAABCxAgAEABAAZGF0YQgAAAAAAAAAAAD//w==") 104 m.Handle("/AUDIO", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 105 w.Header().Add("Content-Type", "audio/wav") 106 w.Header().Add("Content-Length", strconv.FormatUint(uint64(len(audio)), 10)) 107 w.Write(audio) 108 })) 109 image, _ := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNoAAAAggCBTBfX3wAAAABJRU5ErkJggg==") 110 m.Handle("/IMAGE", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 111 w.Header().Add("Content-Type", "image/png") 112 w.Header().Add("Content-Length", strconv.FormatUint(uint64(len(image)), 10)) 113 w.Write(image) 114 })) 115 return http.ListenAndServe(":8080", m) 116 } 117