main pico / pkg / shared / config.go
Antonio Mika  ·  2026-10-10
  1package shared
  2
  3import (
  4	"context"
  5	"fmt"
  6	"html/template"
  7	"log/slog"
  8	"net/http"
  9	"net/url"
 10	"os"
 11	"strings"
 12	"time"
 13
 14	"github.com/picosh/pico/pkg/db"
 15
 16	pipeLogger "github.com/picosh/utils/pipe/log"
 17)
 18
 19var DefaultEmail = "hello@pico.sh"
 20
 21type SitePageData struct {
 22	Domain  template.URL
 23	HomeURL template.URL
 24}
 25
 26type PageData struct {
 27	Site SitePageData
 28}
 29
 30// CreateURL builds links to users' sites on Domain, as seen from the host a
 31// request came in on.
 32type CreateURL struct {
 33	Protocol        string
 34	Domain          string
 35	Subdomain       bool
 36	UsernameInRoute bool
 37	HostDomain      string
 38}
 39
 40// NewCreateURL builds links that point at users' subdomains.
 41func NewCreateURL(protocol, domain string) *CreateURL {
 42	return &CreateURL{
 43		Protocol:  protocol,
 44		Domain:    domain,
 45		Subdomain: true,
 46	}
 47}
 48
 49func CreateURLFromRequest(protocol, domain string, r *http.Request) *CreateURL {
 50	hostDomain := strings.Split(r.Host, ":")[0]
 51	appDomain := strings.Split(domain, ":")[0]
 52
 53	onSubdomain := strings.Contains(hostDomain, appDomain)
 54	withUserName := !onSubdomain && hostDomain == appDomain
 55
 56	return &CreateURL{
 57		Protocol:        protocol,
 58		Domain:          domain,
 59		HostDomain:      hostDomain,
 60		Subdomain:       onSubdomain,
 61		UsernameInRoute: withUserName,
 62	}
 63}
 64
 65func (c *CreateURL) FullBlogURL(username string) string {
 66	if c.Subdomain {
 67		return fmt.Sprintf("%s://%s.%s", c.Protocol, username, c.Domain)
 68	}
 69
 70	if c.UsernameInRoute {
 71		return fmt.Sprintf("/%s", username)
 72	}
 73
 74	return fmt.Sprintf("%s://%s", c.Protocol, c.HostDomain)
 75}
 76
 77func (c *CreateURL) FullPostURL(username, slug string) string {
 78	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
 79
 80	if c.Subdomain {
 81		return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
 82	}
 83
 84	if c.UsernameInRoute {
 85		return fmt.Sprintf("%s://%s/%s/%s", c.Protocol, c.Domain, username, fname)
 86	}
 87
 88	return fmt.Sprintf("%s://%s/%s", c.Protocol, c.HostDomain, fname)
 89}
 90
 91func (c *CreateURL) RssBlogURL(username, tag string) string {
 92	url := ""
 93	if c.Subdomain {
 94		url = fmt.Sprintf("%s://%s.%s/rss", c.Protocol, username, c.Domain)
 95	} else if c.UsernameInRoute {
 96		url = fmt.Sprintf("/%s/rss", username)
 97	} else {
 98		url = "/rss"
 99	}
100
101	if tag != "" {
102		return fmt.Sprintf("%s?tag=%s", url, tag)
103	}
104
105	return url
106}
107
108func CreateLogger(space string, withPipe bool) *slog.Logger {
109	logger := slog.New(
110		slog.NewTextHandler(
111			os.Stdout,
112			&slog.HandlerOptions{
113				AddSource: true,
114				Level:     slog.LevelInfo,
115			},
116		),
117	)
118
119	if withPipe {
120		conn := NewPicoPipeClient()
121		logger = pipeLogger.RegisterReconnectLogger(context.Background(), logger, conn, 100, 10*time.Millisecond)
122	}
123
124	logger = logger.With("service", space)
125
126	hostname, err := os.Hostname()
127	if err == nil && hostname != "" {
128		logger = logger.With("hostname", hostname)
129	}
130
131	nodename := os.Getenv("NODENAME")
132	if nodename != "" {
133		logger = logger.With("nodename", nodename)
134	}
135
136	slog.SetDefault(logger)
137
138	return logger
139}
140
141func LoggerWithUser(logger *slog.Logger, user *db.User) *slog.Logger {
142	return logger.With("user", user.Name, "userId", user.ID)
143}