repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / tunkit
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}