Antonio Mika
·
2025-03-12
web.go
1package tunkit
2
3import (
4 "fmt"
5 "log/slog"
6 "net"
7 "net/http"
8
9 "github.com/picosh/pico/pkg/pssh"
10)
11
12type HttpHandlerFn = func(ctx *pssh.SSHServerConnSession) http.Handler
13
14type WebTunnel interface {
15 GetHttpHandler() HttpHandlerFn
16 CreateListener(ctx *pssh.SSHServerConnSession) (net.Listener, error)
17 CreateConn(ctx *pssh.SSHServerConnSession) (net.Conn, error)
18 GetLogger() *slog.Logger
19 Close(ctx *pssh.SSHServerConnSession) error
20}
21
22type ctxListenerKey struct{}
23
24func getListenerCtx(ctx *pssh.SSHServerConnSession) (net.Listener, error) {
25 listener, ok := ctx.Value(ctxListenerKey{}).(net.Listener)
26 if listener == nil || !ok {
27 return nil, fmt.Errorf("listener not set on `*pssh.SSHServerConnSession()` for connection")
28 }
29 return listener, nil
30}
31
32func setListenerCtx(ctx *pssh.SSHServerConnSession, listener net.Listener) {
33 ctx.SetValue(ctxListenerKey{}, listener)
34}
35
36func httpServe(handler WebTunnel, ctx *pssh.SSHServerConnSession, log *slog.Logger) (net.Listener, error) {
37 cached, _ := getListenerCtx(ctx)
38 if cached != nil {
39 return cached, nil
40 }
41
42 listener, err := handler.CreateListener(ctx)
43 if err != nil {
44 return nil, err
45 }
46 setListenerCtx(ctx, listener)
47
48 go func() {
49 httpHandler := handler.GetHttpHandler()
50 err := http.Serve(listener, httpHandler(ctx))
51 if err != nil {
52 log.Error("serving http content", "err", err)
53 }
54 }()
55
56 return listener, nil
57}