This repository has been archived by the owner on Dec 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http_server.go
124 lines (103 loc) · 3.2 KB
/
http_server.go
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
package main
import (
"context"
"embed"
"fmt"
"html"
"html/template"
"log"
"net/http"
"os"
"os/exec"
"os/signal"
"strings"
"time"
)
var (
//go:embed templates/index.html
templatesFS embed.FS
//go:embed static/[email protected] static/[email protected]
staticFS embed.FS
)
func startHTTPServer(address string, zsvVersions []string, zsvCLIsJson string) {
templates, err := template.ParseFS(templatesFS, "templates/index.html")
if err != nil {
log.Fatalf("failed to parse templates, %v", err)
}
data := struct {
PlaygroundVersion string
ZsvVersions []string
ZsvCLIsJson string
}{
PlaygroundVersion: version,
ZsvVersions: zsvVersions,
ZsvCLIsJson: zsvCLIsJson,
}
http.Handle("/static/", http.FileServer(http.FS(staticFS)))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
err := templates.ExecuteTemplate(w, "index.html", data)
if err != nil {
log.Print(err)
http.NotFound(w, r)
}
})
http.HandleFunc("/run", func(w http.ResponseWriter, r *http.Request) {
peer := r.RemoteAddr
log.Printf("[%v] %v", peer, *r)
if err := r.ParseForm(); err != nil {
log.Printf("[%v] failed to parse form, error: %v", peer, err)
if _, err := w.Write([]byte(err.Error())); err != nil {
log.Printf("[%v] failed to send 'parsing failed' response", peer)
}
return
}
version := r.FormValue("version")
cli := r.FormValue("cli")
csv := r.FormValue("csv")
// log.Printf("[%v] version: [%v]", peer, version)
// log.Printf("[%v] cli: [%v]", peer, cli)
// log.Printf("[%v] csv: [%v]", peer, csv)
zsv := getExePath(version)
cli = strings.Replace(cli, "zsv", zsv, 1)
log.Printf("[%v] executing: [%v]", peer, cli)
start := time.Now()
cmd := exec.Command("sh", "-c", cli)
cmd.Stdin = strings.NewReader(csv)
output, err := cmd.CombinedOutput()
elapsedTimeMsg := fmt.Sprintf("\n\n(elapsed time: %v)", time.Since(start))
escapedOutput := html.EscapeString(string(output))
if err != nil {
log.Printf("[%v] failed to execute command, error: %v", peer, err)
if !strings.HasSuffix(escapedOutput, "\n") {
escapedOutput += "\n"
}
if _, err := w.Write([]byte(escapedOutput + err.Error() + elapsedTimeMsg)); err != nil {
log.Printf("[%v] failed to send 'execution failed' response", peer)
}
return
}
// log.Printf("[%v] output: [%v]", peer, string(output))
log.Printf("[%v] sending response [size: %v bytes]", peer, len(escapedOutput))
if n, err := w.Write([]byte(escapedOutput + elapsedTimeMsg)); err != nil {
log.Printf("[%v] failed to send response", peer)
} else {
log.Printf("[%v] sent response successfully [%v]", peer, n)
}
})
// start http server and wait for SIGINT
server := &http.Server{Addr: address}
go func() {
log.Printf("starting http server on %v [press CTRL+C for graceful shutdown]", address)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("failed to start HTTP server, error: %v", err)
}
}()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("failed to shutdown, error: %v", err)
}
}