1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
package main
import (
"encoding/json"
"errors"
"flag"
"fmt"
"go/build"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)
// Examples represents the examples loaded from examples.json.
type Examples []*Example
var (
errListExamples = errors.New("failed to list examples (please run in the examples folder)")
errParseExamples = errors.New("failed to parse examples")
)
// Example represents an example loaded from examples.json.
type Example struct {
Title string `json:"title"`
Link string `json:"link"`
Description string `json:"description"`
Type string `json:"type"`
IsJS bool
IsWASM bool
}
func main() {
addr := flag.String("address", ":80", "Address to host the HTTP server on.")
flag.Parse()
log.Println("Listening on", *addr)
err := serve(*addr)
if err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
func serve(addr string) error {
// Load the examples
examples, err := getExamples()
if err != nil {
return err
}
// Load the templates
homeTemplate := template.Must(template.ParseFiles("index.html"))
// Serve the required pages
// DIY 'mux' to avoid additional dependencies
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
url := r.URL.Path
if url == "/wasm_exec.js" {
http.FileServer(http.Dir(filepath.Join(build.Default.GOROOT, "misc/wasm/"))).ServeHTTP(w, r)
return
}
// Split up the URL. Expected parts:
// 1: Base url
// 2: "example"
// 3: Example type: js or wasm
// 4: Example folder, e.g.: data-channels
// 5: Static file as part of the example
parts := strings.Split(url, "/")
if len(parts) > 4 &&
parts[1] == "example" {
exampleType := parts[2]
exampleLink := parts[3]
for _, example := range *examples {
if example.Link != exampleLink {
continue
}
fiddle := filepath.Join(exampleLink, "jsfiddle")
if len(parts[4]) != 0 {
http.StripPrefix("/example/"+exampleType+"/"+exampleLink+"/", http.FileServer(http.Dir(fiddle))).ServeHTTP(w, r)
return
}
temp := template.Must(template.ParseFiles("example.html"))
_, err = temp.ParseFiles(filepath.Join(fiddle, "demo.html"))
if err != nil {
panic(err)
}
data := struct {
*Example
JS bool
}{
example,
exampleType == "js",
}
err = temp.Execute(w, data)
if err != nil {
panic(err)
}
return
}
}
// Serve the main page
err = homeTemplate.Execute(w, examples)
if err != nil {
panic(err)
}
})
// Start the server
return http.ListenAndServe(addr, nil)
}
// getExamples loads the examples from the examples.json file.
func getExamples() (*Examples, error) {
file, err := os.Open("./examples.json")
if err != nil {
return nil, fmt.Errorf("%w: %v", errListExamples, err)
}
defer func() {
closeErr := file.Close()
if closeErr != nil {
panic(closeErr)
}
}()
var examples Examples
err = json.NewDecoder(file).Decode(&examples)
if err != nil {
return nil, fmt.Errorf("%w: %v", errParseExamples, err)
}
for _, example := range examples {
fiddle := filepath.Join(example.Link, "jsfiddle")
js := filepath.Join(fiddle, "demo.js")
if _, err := os.Stat(js); !os.IsNotExist(err) {
example.IsJS = true
}
wasm := filepath.Join(fiddle, "demo.wasm")
if _, err := os.Stat(wasm); !os.IsNotExist(err) {
example.IsWASM = true
}
}
return &examples, nil
}
|