Eric Bower
·
2025-03-17
config.go
1package shared
2
3import (
4 "context"
5 "fmt"
6 "html/template"
7 "log/slog"
8 "net/http"
9 "net/url"
10 "os"
11 "path"
12 "strings"
13 "time"
14
15 "github.com/picosh/pico/pkg/db"
16 "github.com/picosh/utils"
17
18 pipeLogger "github.com/picosh/utils/pipe/log"
19)
20
21var DefaultEmail = "hello@pico.sh"
22
23type SitePageData struct {
24 Domain template.URL
25 HomeURL template.URL
26}
27
28type PageData struct {
29 Site SitePageData
30}
31
32type ConfigSite struct {
33 Debug bool
34 SendgridKey string
35 Domain string
36 Port string
37 PortOverride string
38 Protocol string
39 DbURL string
40 StorageDir string
41 MinioURL string
42 MinioUser string
43 MinioPass string
44 Space string
45 Issuer string
46 Secret string
47 SecretWebhook string
48 AllowedExt []string
49 HiddenPosts []string
50 MaxSize uint64
51 MaxAssetSize int64
52 MaxSpecialFileSize int64
53 Logger *slog.Logger
54 TunsSecret string
55}
56
57func NewConfigSite() *ConfigSite {
58 return &ConfigSite{}
59}
60
61type CreateURL struct {
62 Subdomain bool
63 UsernameInRoute bool
64 HostDomain string
65 AppDomain string
66 Username string
67 Cfg *ConfigSite
68}
69
70func NewCreateURL(cfg *ConfigSite) *CreateURL {
71 return &CreateURL{
72 Cfg: cfg,
73 Subdomain: cfg.IsSubdomains(),
74 }
75}
76
77func CreateURLFromRequest(cfg *ConfigSite, r *http.Request) *CreateURL {
78 hostDomain := strings.Split(r.Host, ":")[0]
79 appDomain := strings.Split(cfg.Domain, ":")[0]
80
81 onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
82 withUserName := !cfg.IsCustomdomains() || (!onSubdomain && hostDomain == appDomain)
83
84 return &CreateURL{
85 Cfg: cfg,
86 AppDomain: appDomain,
87 HostDomain: hostDomain,
88 Subdomain: onSubdomain,
89 UsernameInRoute: withUserName,
90 }
91}
92
93func (c *ConfigSite) GetSiteData() *SitePageData {
94 return &SitePageData{
95 Domain: template.URL(c.Domain),
96 HomeURL: template.URL(c.HomeURL()),
97 }
98}
99
100func (c *ConfigSite) IsSubdomains() bool {
101 return true
102}
103
104func (c *ConfigSite) IsCustomdomains() bool {
105 return true
106}
107
108func (c *ConfigSite) HomeURL() string {
109 if c.IsSubdomains() || c.IsCustomdomains() {
110 return fmt.Sprintf("//%s", c.Domain)
111 }
112
113 return "/"
114}
115
116func (c *ConfigSite) ReadURL() string {
117 if c.IsSubdomains() || c.IsCustomdomains() {
118 return fmt.Sprintf("%s://%s", c.Protocol, c.Domain)
119 }
120
121 return "/"
122}
123
124func (c *ConfigSite) StaticPath(fname string) string {
125 return path.Join(c.Space, fname)
126}
127
128func (c *ConfigSite) BlogURL(username string) string {
129 if c.IsSubdomains() {
130 return fmt.Sprintf("%s://%s.%s", c.Protocol, username, c.Domain)
131 }
132
133 return fmt.Sprintf("/%s", username)
134}
135
136func (c *ConfigSite) CssURL(username string) string {
137 if c.IsSubdomains() || c.IsCustomdomains() {
138 return "/_styles.css"
139 }
140
141 return fmt.Sprintf("/%s/styles.css", username)
142}
143
144func (c *ConfigSite) PostURL(username, slug string) string {
145 fname := url.PathEscape(slug)
146 if c.IsSubdomains() {
147 return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
148 }
149
150 return fmt.Sprintf("/%s/%s", username, fname)
151
152}
153
154func (c *ConfigSite) RawPostURL(username, slug string) string {
155 fname := url.PathEscape(slug)
156 if c.IsSubdomains() {
157 return fmt.Sprintf("%s://%s.%s/raw/%s", c.Protocol, username, c.Domain, fname)
158 }
159
160 return fmt.Sprintf("/raw/%s/%s", username, fname)
161}
162
163func (c *ConfigSite) ImgFullURL(username, slug string) string {
164 fname := url.PathEscape(strings.TrimLeft(slug, "/"))
165 return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
166}
167
168func (c *ConfigSite) FullBlogURL(curl *CreateURL, username string) string {
169 if c.IsSubdomains() && curl.Subdomain {
170 return fmt.Sprintf("%s://%s.%s", c.Protocol, username, c.Domain)
171 }
172
173 if curl.UsernameInRoute {
174 return fmt.Sprintf("/%s", username)
175 }
176
177 return fmt.Sprintf("%s://%s", c.Protocol, curl.HostDomain)
178}
179
180func (c *ConfigSite) FullPostURL(curl *CreateURL, username, slug string) string {
181 fname := url.PathEscape(strings.TrimLeft(slug, "/"))
182
183 if curl.Subdomain && c.IsSubdomains() {
184 return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
185 }
186
187 if curl.UsernameInRoute {
188 return fmt.Sprintf("%s://%s/%s/%s", c.Protocol, c.Domain, username, fname)
189 }
190
191 return fmt.Sprintf("%s://%s/%s", c.Protocol, curl.HostDomain, fname)
192}
193
194func (c *ConfigSite) RssBlogURL(curl *CreateURL, username, tag string) string {
195 url := ""
196 if c.IsSubdomains() && curl.Subdomain {
197 url = fmt.Sprintf("%s://%s.%s/rss", c.Protocol, username, c.Domain)
198 } else if curl.UsernameInRoute {
199 url = fmt.Sprintf("/%s/rss", username)
200 } else {
201 url = "/rss"
202 }
203
204 if tag != "" {
205 return fmt.Sprintf("%s?tag=%s", url, tag)
206 }
207
208 return url
209}
210
211func (c *ConfigSite) ImgURL(curl *CreateURL, username string, slug string) string {
212 fname := url.PathEscape(strings.TrimLeft(slug, "/"))
213 if c.IsSubdomains() && curl.Subdomain {
214 return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
215 }
216
217 if curl.UsernameInRoute {
218 return fmt.Sprintf("/%s/%s", username, fname)
219 }
220
221 return fmt.Sprintf("/%s", fname)
222}
223
224func (c *ConfigSite) ImgPostURL(curl *CreateURL, username string, slug string) string {
225 fname := url.PathEscape(strings.TrimLeft(slug, "/"))
226 if c.IsSubdomains() && curl.Subdomain {
227 return fmt.Sprintf("%s://%s.%s/p/%s", c.Protocol, username, c.Domain, fname)
228 }
229
230 if curl.UsernameInRoute {
231 return fmt.Sprintf("/%s/p/%s", username, fname)
232 }
233
234 return fmt.Sprintf("/p/%s", fname)
235}
236
237func (c *ConfigSite) ImgOrigURL(curl *CreateURL, username string, slug string) string {
238 fname := url.PathEscape(strings.TrimLeft(slug, "/"))
239 if c.IsSubdomains() && curl.Subdomain {
240 return fmt.Sprintf("%s://%s.%s/o/%s", c.Protocol, username, c.Domain, fname)
241 }
242
243 if curl.UsernameInRoute {
244 return fmt.Sprintf("/%s/o/%s", username, fname)
245 }
246
247 return fmt.Sprintf("/o/%s", fname)
248}
249
250func (c *ConfigSite) TagURL(curl *CreateURL, username, tag string) string {
251 tg := url.PathEscape(tag)
252 return fmt.Sprintf("%s?tag=%s", c.FullBlogURL(curl, username), tg)
253}
254
255func (c *ConfigSite) AssetURL(username, projectName, fpath string) string {
256 if username == projectName {
257 return fmt.Sprintf(
258 "%s://%s.%s/%s",
259 c.Protocol,
260 username,
261 c.Domain,
262 fpath,
263 )
264 }
265
266 return fmt.Sprintf(
267 "%s://%s-%s.%s/%s",
268 c.Protocol,
269 username,
270 projectName,
271 c.Domain,
272 fpath,
273 )
274}
275
276func CreateLogger(space string) *slog.Logger {
277 logger := slog.New(
278 slog.NewTextHandler(
279 os.Stdout,
280 &slog.HandlerOptions{
281 AddSource: true,
282 Level: slog.LevelInfo,
283 },
284 ),
285 )
286
287 if strings.ToLower(utils.GetEnv("PICO_PIPE_ENABLED", "true")) == "true" {
288 conn := NewPicoPipeClient()
289 logger = pipeLogger.RegisterReconnectLogger(context.Background(), logger, conn, 100, 10*time.Millisecond)
290 }
291
292 logger = logger.With("service", space)
293
294 hostname, err := os.Hostname()
295 if err == nil && hostname != "" {
296 logger = logger.With("hostname", hostname)
297 }
298
299 nodename := os.Getenv("NODENAME")
300 if nodename != "" {
301 logger = logger.With("nodename", nodename)
302 }
303
304 slog.SetDefault(logger)
305
306 return logger
307}
308
309func LoggerWithUser(logger *slog.Logger, user *db.User) *slog.Logger {
310 return logger.With("user", user.Name, "userId", user.ID)
311}