repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

pico / shared
Mac Chaffee · 17 Dec 24

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/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	CacheTTL           time.Duration
 42	CacheControl       string
 43	MinioURL           string
 44	MinioUser          string
 45	MinioPass          string
 46	Space              string
 47	Issuer             string
 48	Secret             string
 49	SecretWebhook      string
 50	AllowedExt         []string
 51	HiddenPosts        []string
 52	MaxSize            uint64
 53	MaxAssetSize       int64
 54	MaxSpecialFileSize int64
 55	Logger             *slog.Logger
 56}
 57
 58func NewConfigSite() *ConfigSite {
 59	return &ConfigSite{}
 60}
 61
 62type CreateURL struct {
 63	Subdomain       bool
 64	UsernameInRoute bool
 65	HostDomain      string
 66	AppDomain       string
 67	Username        string
 68	Cfg             *ConfigSite
 69}
 70
 71func NewCreateURL(cfg *ConfigSite) *CreateURL {
 72	return &CreateURL{
 73		Cfg:       cfg,
 74		Subdomain: cfg.IsSubdomains(),
 75	}
 76}
 77
 78func CreateURLFromRequest(cfg *ConfigSite, r *http.Request) *CreateURL {
 79	hostDomain := strings.Split(r.Host, ":")[0]
 80	appDomain := strings.Split(cfg.Domain, ":")[0]
 81
 82	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
 83	withUserName := !cfg.IsCustomdomains() || (!onSubdomain && hostDomain == appDomain)
 84
 85	return &CreateURL{
 86		Cfg:             cfg,
 87		AppDomain:       appDomain,
 88		HostDomain:      hostDomain,
 89		Subdomain:       onSubdomain,
 90		UsernameInRoute: withUserName,
 91	}
 92}
 93
 94func (c *ConfigSite) GetSiteData() *SitePageData {
 95	return &SitePageData{
 96		Domain:  template.URL(c.Domain),
 97		HomeURL: template.URL(c.HomeURL()),
 98	}
 99}
100
101func (c *ConfigSite) IsSubdomains() bool {
102	return true
103}
104
105func (c *ConfigSite) IsCustomdomains() bool {
106	return true
107}
108
109func (c *ConfigSite) HomeURL() string {
110	if c.IsSubdomains() || c.IsCustomdomains() {
111		return fmt.Sprintf("//%s", c.Domain)
112	}
113
114	return "/"
115}
116
117func (c *ConfigSite) ReadURL() string {
118	if c.IsSubdomains() || c.IsCustomdomains() {
119		return fmt.Sprintf("%s://%s", c.Protocol, c.Domain)
120	}
121
122	return "/"
123}
124
125func (c *ConfigSite) StaticPath(fname string) string {
126	return path.Join(c.Space, fname)
127}
128
129func (c *ConfigSite) BlogURL(username string) string {
130	if c.IsSubdomains() {
131		return fmt.Sprintf("%s://%s.%s", c.Protocol, username, c.Domain)
132	}
133
134	return fmt.Sprintf("/%s", username)
135}
136
137func (c *ConfigSite) CssURL(username string) string {
138	if c.IsSubdomains() || c.IsCustomdomains() {
139		return "/_styles.css"
140	}
141
142	return fmt.Sprintf("/%s/styles.css", username)
143}
144
145func (c *ConfigSite) PostURL(username, slug string) string {
146	fname := url.PathEscape(slug)
147	if c.IsSubdomains() {
148		return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
149	}
150
151	return fmt.Sprintf("/%s/%s", username, fname)
152
153}
154
155func (c *ConfigSite) RawPostURL(username, slug string) string {
156	fname := url.PathEscape(slug)
157	if c.IsSubdomains() {
158		return fmt.Sprintf("%s://%s.%s/raw/%s", c.Protocol, username, c.Domain, fname)
159	}
160
161	return fmt.Sprintf("/raw/%s/%s", username, fname)
162}
163
164func (c *ConfigSite) ImgFullURL(username, slug string) string {
165	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
166	return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
167}
168
169func (c *ConfigSite) FullBlogURL(curl *CreateURL, username string) string {
170	if c.IsSubdomains() && curl.Subdomain {
171		return fmt.Sprintf("%s://%s.%s", c.Protocol, username, c.Domain)
172	}
173
174	if curl.UsernameInRoute {
175		return fmt.Sprintf("/%s", username)
176	}
177
178	return fmt.Sprintf("%s://%s", c.Protocol, curl.HostDomain)
179}
180
181func (c *ConfigSite) FullPostURL(curl *CreateURL, username, slug string) string {
182	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
183
184	if curl.Subdomain && c.IsSubdomains() {
185		return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
186	}
187
188	if curl.UsernameInRoute {
189		return fmt.Sprintf("%s://%s/%s/%s", c.Protocol, c.Domain, username, fname)
190	}
191
192	return fmt.Sprintf("%s://%s/%s", c.Protocol, curl.HostDomain, fname)
193}
194
195func (c *ConfigSite) RssBlogURL(curl *CreateURL, username, tag string) string {
196	url := ""
197	if c.IsSubdomains() && curl.Subdomain {
198		url = fmt.Sprintf("%s://%s.%s/rss", c.Protocol, username, c.Domain)
199	} else if curl.UsernameInRoute {
200		url = fmt.Sprintf("/%s/rss", username)
201	} else {
202		url = "/rss"
203	}
204
205	if tag != "" {
206		return fmt.Sprintf("%s?tag=%s", url, tag)
207	}
208
209	return url
210}
211
212func (c *ConfigSite) ImgURL(curl *CreateURL, username string, slug string) string {
213	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
214	if c.IsSubdomains() && curl.Subdomain {
215		return fmt.Sprintf("%s://%s.%s/%s", c.Protocol, username, c.Domain, fname)
216	}
217
218	if curl.UsernameInRoute {
219		return fmt.Sprintf("/%s/%s", username, fname)
220	}
221
222	return fmt.Sprintf("/%s", fname)
223}
224
225func (c *ConfigSite) ImgPostURL(curl *CreateURL, username string, slug string) string {
226	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
227	if c.IsSubdomains() && curl.Subdomain {
228		return fmt.Sprintf("%s://%s.%s/p/%s", c.Protocol, username, c.Domain, fname)
229	}
230
231	if curl.UsernameInRoute {
232		return fmt.Sprintf("/%s/p/%s", username, fname)
233	}
234
235	return fmt.Sprintf("/p/%s", fname)
236}
237
238func (c *ConfigSite) ImgOrigURL(curl *CreateURL, username string, slug string) string {
239	fname := url.PathEscape(strings.TrimLeft(slug, "/"))
240	if c.IsSubdomains() && curl.Subdomain {
241		return fmt.Sprintf("%s://%s.%s/o/%s", c.Protocol, username, c.Domain, fname)
242	}
243
244	if curl.UsernameInRoute {
245		return fmt.Sprintf("/%s/o/%s", username, fname)
246	}
247
248	return fmt.Sprintf("/o/%s", fname)
249}
250
251func (c *ConfigSite) TagURL(curl *CreateURL, username, tag string) string {
252	tg := url.PathEscape(tag)
253	return fmt.Sprintf("%s?tag=%s", c.FullBlogURL(curl, username), tg)
254}
255
256func (c *ConfigSite) AssetURL(username, projectName, fpath string) string {
257	if username == projectName {
258		return fmt.Sprintf(
259			"%s://%s.%s/%s",
260			c.Protocol,
261			username,
262			c.Domain,
263			fpath,
264		)
265	}
266
267	return fmt.Sprintf(
268		"%s://%s-%s.%s/%s",
269		c.Protocol,
270		username,
271		projectName,
272		c.Domain,
273		fpath,
274	)
275}
276
277func CreateLogger(space string) *slog.Logger {
278	opts := &slog.HandlerOptions{
279		AddSource: true,
280	}
281	log := slog.New(
282		slog.NewTextHandler(os.Stdout, opts),
283	)
284
285	newLogger := log
286
287	if strings.ToLower(utils.GetEnv("PICO_PIPE_ENABLED", "true")) == "true" {
288		conn := NewPicoPipeClient()
289		newLogger = pipeLogger.RegisterReconnectLogger(context.Background(), log, conn, 100, 10*time.Millisecond)
290	}
291
292	return newLogger.With("service", space)
293}
294
295func LoggerWithUser(logger *slog.Logger, user *db.User) *slog.Logger {
296	return logger.With("user", user.Name, "userId", user.ID)
297}