Skip to content

Commit 9195e49

Browse files
committed
feat: add frontend
1 parent 69b0fbb commit 9195e49

File tree

6 files changed

+182
-4
lines changed

6 files changed

+182
-4
lines changed

Makefile

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ endif
1414
# PROTO_SOURCES = $(wildcard **/*.proto)
1515
GO_SOURCES = $(call rwildcard,,*.go)
1616
PROTO_SOURCES = $(call rwildcard,,*.proto)
17-
18-
17+
TARGET_DIR = headscale-ui
1918
build:
2019
nix build
2120

@@ -62,3 +61,12 @@ compress: build
6261
generate:
6362
rm -rf gen
6463
buf generate proto
64+
65+
frontend:
66+
@if not [ -d "$(TARGET_DIR)" ]; then \
67+
git clone https://github.com/gurucomputing/headscale-ui.git "$(TARGET_DIR)"; \
68+
fi
69+
-rm -r hscontrol/build
70+
bun install --cwd headscale-ui
71+
bun run --cwd headscale-ui build
72+
mv headscale-ui/build hscontrol

devbox.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"platforms": ["x86_64-darwin", "aarch64-darwin"]
99
},
1010
"buf": "1.48.0",
11-
"protoc-gen-go": "1.35.2"
11+
"protoc-gen-go": "1.35.2",
12+
"bun": "1.1.42",
13+
"nodejs": "18.8.0"
1214
},
1315
"shell": {
1416
"init_hook": [

devbox.lock

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,54 @@
4949
}
5050
}
5151
},
52+
53+
"last_modified": "2024-12-26T01:25:00Z",
54+
"resolved": "github:NixOS/nixpkgs/16e046229f3b4f53257973a5532bcbb72457d2f2#bun",
55+
"source": "devbox-search",
56+
"version": "1.1.42",
57+
"systems": {
58+
"aarch64-darwin": {
59+
"outputs": [
60+
{
61+
"name": "out",
62+
"path": "/nix/store/5c73vw31nbji92hggrgjnfi33wzhbxk3-bun-1.1.42",
63+
"default": true
64+
}
65+
],
66+
"store_path": "/nix/store/5c73vw31nbji92hggrgjnfi33wzhbxk3-bun-1.1.42"
67+
},
68+
"aarch64-linux": {
69+
"outputs": [
70+
{
71+
"name": "out",
72+
"path": "/nix/store/shm69afh0zrm5r0gkpkj9l0z8l6vkpmr-bun-1.1.42",
73+
"default": true
74+
}
75+
],
76+
"store_path": "/nix/store/shm69afh0zrm5r0gkpkj9l0z8l6vkpmr-bun-1.1.42"
77+
},
78+
"x86_64-darwin": {
79+
"outputs": [
80+
{
81+
"name": "out",
82+
"path": "/nix/store/70nzsdr814rka1b3qaxz8b4hfk8r6wi9-bun-1.1.42",
83+
"default": true
84+
}
85+
],
86+
"store_path": "/nix/store/70nzsdr814rka1b3qaxz8b4hfk8r6wi9-bun-1.1.42"
87+
},
88+
"x86_64-linux": {
89+
"outputs": [
90+
{
91+
"name": "out",
92+
"path": "/nix/store/ws04zldxbkg26d4qkwyr4km1zd26mach-bun-1.1.42",
93+
"default": true
94+
}
95+
],
96+
"store_path": "/nix/store/ws04zldxbkg26d4qkwyr4km1zd26mach-bun-1.1.42"
97+
}
98+
}
99+
},
52100
"darwin.apple_sdk.frameworks.IOKit": {
53101
"resolved": "github:NixOS/nixpkgs/75a52265bda7fd25e06e3a67dee3f0354e73243c#darwin.apple_sdk.frameworks.IOKit",
54102
"source": "nixpkg"
@@ -153,6 +201,71 @@
153201
}
154202
}
155203
},
204+
205+
"last_modified": "2022-08-27T08:52:24Z",
206+
"plugin_version": "0.0.2",
207+
"resolved": "github:NixOS/nixpkgs/ed0fab06cc1ca9799e6dda30529c963b95c4dc2a#nodejs",
208+
"source": "devbox-search",
209+
"version": "18.8.0",
210+
"systems": {
211+
"aarch64-darwin": {
212+
"outputs": [
213+
{
214+
"name": "out",
215+
"path": "/nix/store/amvfx98dwsqjiclz570fkmc7pd9h27nj-nodejs-18.8.0",
216+
"default": true
217+
},
218+
{
219+
"name": "libv8",
220+
"path": "/nix/store/xg73kcbyknfnz3wh9iz7pb8mcvmahyli-nodejs-18.8.0-libv8"
221+
}
222+
],
223+
"store_path": "/nix/store/amvfx98dwsqjiclz570fkmc7pd9h27nj-nodejs-18.8.0"
224+
},
225+
"aarch64-linux": {
226+
"outputs": [
227+
{
228+
"name": "out",
229+
"path": "/nix/store/771xwnjhlhyxq5nfh825b239q552fxnk-nodejs-18.8.0",
230+
"default": true
231+
},
232+
{
233+
"name": "libv8",
234+
"path": "/nix/store/b6mwrm6y94pw4mkm8jn4q5p4fwkk69pa-nodejs-18.8.0-libv8"
235+
}
236+
],
237+
"store_path": "/nix/store/771xwnjhlhyxq5nfh825b239q552fxnk-nodejs-18.8.0"
238+
},
239+
"x86_64-darwin": {
240+
"outputs": [
241+
{
242+
"name": "out",
243+
"path": "/nix/store/0ws9319m3qpsafm0grigpmh60d2qkby9-nodejs-18.8.0",
244+
"default": true
245+
},
246+
{
247+
"name": "libv8",
248+
"path": "/nix/store/02ddlysk5c29sg23gafzcmj62yjsiiq8-nodejs-18.8.0-libv8"
249+
}
250+
],
251+
"store_path": "/nix/store/0ws9319m3qpsafm0grigpmh60d2qkby9-nodejs-18.8.0"
252+
},
253+
"x86_64-linux": {
254+
"outputs": [
255+
{
256+
"name": "out",
257+
"path": "/nix/store/sndm8q6yhr6a8yy9zdd1sxni3lc8pcmw-nodejs-18.8.0",
258+
"default": true
259+
},
260+
{
261+
"name": "libv8",
262+
"path": "/nix/store/fc199pzbq6l7bcgxadfljdy6addrrwv1-nodejs-18.8.0-libv8"
263+
}
264+
],
265+
"store_path": "/nix/store/sndm8q6yhr6a8yy9zdd1sxni3lc8pcmw-nodejs-18.8.0"
266+
}
267+
}
268+
},
156269
157270
"last_modified": "2024-12-03T12:40:06Z",
158271
"resolved": "github:NixOS/nixpkgs/566e53c2ad750c84f6d31f9ccb9d00f823165550#protoc-gen-go",

hscontrol/app.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,14 @@ func (h *Headscale) createRouter(grpcMux *grpcRuntime.ServeMux) *mux.Router {
490490
apiRouter.Use(h.httpAuthenticationMiddleware)
491491
apiRouter.PathPrefix("/v1/").HandlerFunc(grpcMux.ServeHTTP)
492492

493-
router.PathPrefix("/").HandlerFunc(notFoundHandler)
493+
if h.cfg.Frontend.Enabled {
494+
if path := h.cfg.Frontend.Path; path != "" {
495+
router.PathPrefix("/").Handler(SvelteKitHandler("/"))
496+
}
497+
498+
} else {
499+
router.PathPrefix("/").HandlerFunc(notFoundHandler)
500+
}
494501

495502
return router
496503
}

hscontrol/svelte.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package hscontrol
2+
3+
import (
4+
"embed"
5+
"errors"
6+
"fmt"
7+
"io/fs"
8+
"net/http"
9+
"os"
10+
"strings"
11+
)
12+
13+
//go:embed all:build
14+
var files embed.FS
15+
16+
func SvelteKitHandler(path string) http.Handler {
17+
fsys, err := fs.Sub(files, "build")
18+
if err != nil {
19+
20+
}
21+
filesystem := http.FS(fsys)
22+
23+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
24+
path := strings.TrimPrefix(r.URL.Path, path)
25+
_, err := filesystem.Open(path)
26+
if errors.Is(err, os.ErrNotExist) {
27+
path = fmt.Sprintf("%s.html", path)
28+
}
29+
r.URL.Path = path
30+
http.FileServer(filesystem).ServeHTTP(w, r)
31+
})
32+
}

hscontrol/types/config.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ type Config struct {
9797
Policy PolicyConfig
9898

9999
Tuning Tuning
100+
101+
Frontend FrontendConfig
100102
}
101103

102104
type DNSConfig struct {
@@ -220,6 +222,12 @@ type PolicyConfig struct {
220222
Mode PolicyMode
221223
}
222224

225+
type FrontendConfig struct {
226+
Enabled bool
227+
URL string
228+
Path string
229+
}
230+
223231
func (p *PolicyConfig) IsEmpty() bool {
224232
return p.Mode == PolicyModeFile && p.Path == ""
225233
}
@@ -323,6 +331,8 @@ func LoadConfig(path string, isFile bool) error {
323331

324332
viper.SetDefault("prefixes.allocation", string(IPAllocationStrategySequential))
325333

334+
viper.SetDefault("frontend.enabled", false)
335+
326336
if err := viper.ReadInConfig(); err != nil {
327337
return fmt.Errorf("fatal error reading config file: %w", err)
328338
}
@@ -980,6 +990,12 @@ func LoadServerConfig() (*Config, error) {
980990
"tuning.node_mapsession_buffered_chan_size",
981991
),
982992
},
993+
994+
Frontend: FrontendConfig{
995+
Enabled: viper.GetBool("frontend.enabled"),
996+
URL: viper.GetString("frontend.url"),
997+
Path: viper.GetString("frontend.path"),
998+
},
983999
}, nil
9841000
}
9851001

0 commit comments

Comments
 (0)