-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
137 lines (118 loc) · 3.25 KB
/
main.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
125
126
127
128
129
130
131
132
133
134
135
136
137
//go:generate go-winres make
package main
import (
"context"
"embed"
"errors"
"io/fs"
"log"
"net"
"net/http"
"os"
"os/signal"
"path"
"steamview-go/appinfo"
"steamview-go/steam"
"steamview-go/trayicon"
"steamview-go/worker"
"steamview-go/wsserver"
"strings"
"syscall"
"time"
)
// assets folder packed into binary
//
//go:embed assets
var assets embed.FS
// sumsRaw contains precalculated md5 sums in raw format
//
//go:embed md5sums.txt
var sumsRaw string
// sumsMap contains mapping filename -> md5
var sumsMap map[string]string
func main() {
ctx, cancel := context.WithCancel(context.Background())
parseSums()
setupHandles()
//start async parser of Steam DB
go appinfo.ParseAsync(path.Join(steam.CacheRoot, "appinfo.vdf"))
//start worker watching changes in current working appID
go worker.Serve()
httpServer := &http.Server{
Addr: ":3000",
Handler: nil,
BaseContext: func(_ net.Listener) context.Context { return ctx },
}
//stop worker on server shutdown, sending "Server is dead" to all clients
httpServer.RegisterOnShutdown(func() {
worker.Panic()
})
//start http server
go func() {
if err := httpServer.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("HTTP server ListenAndServe: %v", err)
}
}()
//setup channel for kill command
signalChan := make(chan os.Signal, 1)
signal.Notify(
signalChan,
syscall.SIGHUP, // kill -SIGHUP processID
syscall.SIGINT, // kill -SIGINT processID or Ctrl+c
syscall.SIGQUIT, // kill -SIGQUIT processID
)
//run tray icon in separate goroutine
quitChan := make(chan struct{})
trayicon.Run(quitChan)
defer trayicon.Quit()
//wait for shutdown signal from tray icon or terminal
select {
case <-signalChan:
case <-quitChan:
}
//now shutdown server gracefully
gracefulCtx, cancelShutdown := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelShutdown()
err := httpServer.Shutdown(gracefulCtx)
if err != nil {
log.Fatalln("shutdown error: ", err)
}
cancel()
}
// parseSums parses sumsRaw into sumsMap
func parseSums() {
sumsSlice := strings.Fields(sumsRaw)
sumsMap = map[string]string{}
for i := 0; i < len(sumsSlice); i += 2 {
//serving "/" is equal to serving embed.FS/index.html
if sumsSlice[i+1] == "index.html" {
sumsMap["/"] = sumsSlice[i]
}
//works both in linux and windows
sumsMap["/"+strings.ReplaceAll(sumsSlice[i+1], "\\", "/")] = sumsSlice[i]
}
}
// serveFSCached is middleware for sending embedded resources with their md5sum as e-tag
func serveFSCached(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "public, max-age=2592000")
md5Sum := sumsMap[r.URL.Path]
w.Header().Set("ETag", md5Sum)
next.ServeHTTP(w, r)
})
}
// setupHandles sets up server handles
func setupHandles() {
var staticFS = fs.FS(assets)
htmlContent, err := fs.Sub(staticFS, "assets")
if err != nil {
log.Fatal(err)
}
ServeFs := http.FileServer(http.FS(htmlContent))
//handle for socketserver
http.HandleFunc("/socket", wsserver.ServeWs)
//handle for steam cache, app will get pictures from real steam cache
http.HandleFunc("/cache/", steam.ServeCache)
//any other files would come from assets folder
http.Handle("/", serveFSCached(ServeFs))
}