-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwebappServer.go
More file actions
122 lines (110 loc) · 3.25 KB
/
webappServer.go
File metadata and controls
122 lines (110 loc) · 3.25 KB
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
package main
import (
"database/sql"
"embed"
"fmt"
"io/fs"
"net/http"
"strings"
"github.com/PiotrTopa/js8web/model"
)
//go:embed webapp/*
var WEBAPP_FS embed.FS
var WEBAPP_SUBDIR = "webapp"
func startWebappServer(db *sql.DB, wsEventsSessionContainer *websocketSessionContainer, outgoingEvents chan<- model.Js8callEvent) {
serverRoot, err := fs.Sub(WEBAPP_FS, WEBAPP_SUBDIR)
if err != nil {
logger.Sugar().Fatalw(
"Cannot access WebApp subdirectory",
"subdir", WEBAPP_SUBDIR,
"error", err,
)
}
webappFs := http.FileServer(http.FS(serverRoot))
mux := http.NewServeMux()
mux.HandleFunc("/api/rx-packets", methodHandler(methodRouter{
get: apiRxPacketsGet,
}, db))
mux.HandleFunc("/api/chat-messages", methodHandler(methodRouter{
get: apiChatMessagesGet,
}, db))
mux.HandleFunc("/api/station-info", methodHandler(methodRouter{
get: apiStationInfoGet,
}, db))
mux.HandleFunc("/api/rig-status", methodHandler(methodRouter{
get: apiRigStatusGet,
}, db))
mux.HandleFunc("/api/tx-message", roleRequired(
[]string{model.ROLE_ADMIN, model.ROLE_OPERATOR},
methodHandler(methodRouter{
post: apiTxMessagePost(outgoingEvents),
}, db),
))
mux.HandleFunc("/api/auth/login", methodHandler(methodRouter{
post: apiAuthLoginPost,
}, db))
mux.HandleFunc("/api/auth/logout", methodHandler(methodRouter{
post: apiAuthLogoutPost,
}, db))
mux.HandleFunc("/api/auth/check", methodHandler(methodRouter{
get: apiAuthCheckGet,
}, db))
// User management (admin only)
adminOnly := []string{model.ROLE_ADMIN}
mux.HandleFunc("/api/users", roleRequired(adminOnly, methodHandler(methodRouter{
get: apiUsersGet,
post: apiUsersPost,
}, db)))
// Sub-routes: /api/users/{id} and /api/users/{id}/password
mux.HandleFunc("/api/users/", roleRequired(adminOnly, func(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if strings.HasSuffix(path, "/password") {
methodHandler(methodRouter{put: apiUserPasswordPut}, db)(w, r)
} else {
methodHandler(methodRouter{get: apiUserGet, put: apiUserPut, delete: apiUserDelete}, db)(w, r)
}
}))
mux.HandleFunc("/ws/events", websocketHandler(wsEventsSessionContainer))
mux.Handle("/", webappFs)
err = http.ListenAndServe(fmt.Sprintf(":%d", WEBAPP_PORT), mux)
if err != nil {
logger.Sugar().Fatalw(
"Cannot start WebApp HTTP server",
"port", WEBAPP_PORT,
"error", err,
)
}
}
type methodRouter struct {
get func(http.ResponseWriter, *http.Request, *sql.DB)
post func(http.ResponseWriter, *http.Request, *sql.DB)
put func(http.ResponseWriter, *http.Request, *sql.DB)
delete func(http.ResponseWriter, *http.Request, *sql.DB)
}
func methodNotSupported(w http.ResponseWriter, req *http.Request, db *sql.DB) {
logger.Sugar().Errorw(
"Method is not supported by the API",
"method", req.Method,
"url", req.URL,
)
http.Error(w, "method not supported", http.StatusNotImplemented)
}
func methodHandler(r methodRouter, db *sql.DB) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
f := methodNotSupported
switch req.Method {
case http.MethodGet:
f = r.get
case http.MethodPost:
f = r.post
case http.MethodPut:
f = r.put
case http.MethodDelete:
f = r.delete
}
if f == nil {
f = methodNotSupported
}
f(w, req, db)
}
}