pico
created pr with
32.1
added 32.2
1: 7ec3569 = 1: 7ec3569 feat(auth): subscribe to pico's metric-drain pipe
2: 8a197f0 = 2: 8a197f0 chore: update pubsub
3: d4bda15 = 3: d4bda15 refactor: use pipe for analytics
-: ------- > 4: 2b7c358 chore: prep for release
cmds
checkout latest patchset:
ssh pr.pico.sh print 32 | git am -3checkout any patchset in a patch request:
ssh pr.pico.sh print 32.[rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pr add 32
Patchset
32.2
chore: prep for release
Eric Bower
2024-11-14T15:10:28ZSemantic diff summary
4 added,
10 modified,
3 signature changed,
2 removed
across 9 analyzed files
(4 files skipped: unsupported file type)
shared/analytics.go
-
function_declarationtrackableUserAgentadded -
function_declarationtrackableRequestremoved -
function_declarationcleanUrlFromRequestadded -
function_declarationcleanUrlsignature changed -
function_declarationAnalyticsVisitFromVisitadded -
function_declarationipFromRequestadded -
function_declarationAnalyticsVisitFromRequestremoved
+2
-1
Makefile
#
| ... | ... | @@ -130,10 +130,11 @@ migrate: | |
| 130 | 130 | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20240324_add_analytics_table.sql | |
| 131 | 131 | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20240819_add_projects_blocked.sql | |
| 132 | 132 | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20241028_add_analytics_indexes.sql | |
| 133 | + | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20241114_add_namespace_to_analytics.sql | |
| 133 | 134 | .PHONY: migrate | |
| 134 | 135 | ||
| 135 | 136 | latest: | |
| 136 | - | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20241028_add_analytics_indexes.sql | |
| 137 | + | $(DOCKER_CMD) exec -i $(DB_CONTAINER) psql -U $(PGUSER) -d $(PGDATABASE) < ./sql/migrations/20241114_add_namespace_to_analytics.sql | |
| 137 | 138 | .PHONY: latest | |
| 138 | 139 | ||
| 139 | 140 | psql: |
+16
-2
auth/api.go
#
| ... | ... | @@ -641,7 +642,7 @@ func handler(routes []shared.Route, client *Client) http.HandlerFunc { | |
| 641 | 642 | } | |
| 642 | 643 | } | |
| 643 | 644 | ||
| 644 | - | func metricDrainSub(ctx context.Context, dbpool db.DB, logger *slog.Logger) { | |
| 645 | + | func metricDrainSub(ctx context.Context, dbpool db.DB, logger *slog.Logger, secret string) { | |
| 645 | 646 | conn := shared.NewPicoPipeClient() | |
| 646 | 647 | stdoutPipe, err := pubsub.RemoteSub("sub metric-drain -k", ctx, conn) | |
| 647 | 648 |
| ... | ... | @@ -659,6 +660,14 @@ func metricDrainSub(ctx context.Context, dbpool db.DB, logger *slog.Logger) { | |
| 659 | 660 | logger.Error("json unmarshal", "err", err) | |
| 660 | 661 | continue | |
| 661 | 662 | } | |
| 663 | + | ||
| 664 | + | err = shared.AnalyticsVisitFromVisit(&view, dbpool, secret) | |
| 665 | + | if err != nil { | |
| 666 | + | if !errors.Is(err, shared.ErrAnalyticsDisabled) { | |
| 667 | + | logger.Info("could not record analytics view", "reason", err) | |
| 668 | + | } | |
| 669 | + | } | |
| 670 | + | ||
| 662 | 671 | err = dbpool.InsertVisit(&view) | |
| 663 | 672 | if err != nil { | |
| 664 | 673 | logger.Error("could not insert view record", "err", err) |
| ... | ... | @@ -682,6 +692,10 @@ func StartApiServer() { | |
| 682 | 692 | Issuer: utils.GetEnv("AUTH_ISSUER", "pico.sh"), | |
| 683 | 693 | Domain: utils.GetEnv("AUTH_DOMAIN", "http://0.0.0.0:3000"), | |
| 684 | 694 | Port: utils.GetEnv("AUTH_WEB_PORT", "3000"), | |
| 695 | + | Secret: utils.GetEnv("PICO_SECRET", ""), | |
| 696 | + | } | |
| 697 | + | if cfg.Secret == "" { | |
| 698 | + | panic("must provide PICO_SECRET environment variable") | |
| 685 | 699 | } | |
| 686 | 700 | ||
| 687 | 701 | logger := shared.CreateLogger("auth") |
+1
-0
db/db.go
#
| ... | ... | @@ -165,6 +165,7 @@ type AnalyticsVisits struct { | |
| 165 | 165 | UserID string `json:"user_id"` | |
| 166 | 166 | ProjectID string `json:"project_id"` | |
| 167 | 167 | PostID string `json:"post_id"` | |
| 168 | + | Namespace string `json:"namespace"` | |
| 168 | 169 | Host string `json:"host"` | |
| 169 | 170 | Path string `json:"path"` | |
| 170 | 171 | IpAddress string `json:"ip_adress"` |
+12
-11
db/postgres/storage.go
#
| ... | ... | @@ -984,18 +984,19 @@ func newNullString(s string) sql.NullString { | |
| 984 | 984 | } | |
| 985 | 985 | } | |
| 986 | 986 | ||
| 987 | - | func (me *PsqlDB) InsertVisit(view *db.AnalyticsVisits) error { | |
| 987 | + | func (me *PsqlDB) InsertVisit(visit *db.AnalyticsVisits) error { | |
| 988 | 988 | _, err := me.Db.Exec( | |
| 989 | - | `INSERT INTO analytics_visits (user_id, project_id, post_id, host, path, ip_address, user_agent, referer, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);`, | |
| 990 | - | view.UserID, | |
| 991 | - | newNullString(view.ProjectID), | |
| 992 | - | newNullString(view.PostID), | |
| 993 | - | view.Host, | |
| 994 | - | view.Path, | |
| 995 | - | view.IpAddress, | |
| 996 | - | view.UserAgent, | |
| 997 | - | view.Referer, | |
| 998 | - | view.Status, | |
| 989 | + | `INSERT INTO analytics_visits (user_id, project_id, post_id, namespace, host, path, ip_address, user_agent, referer, status) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);`, | |
| 990 | + | visit.UserID, | |
| 991 | + | newNullString(visit.ProjectID), | |
| 992 | + | newNullString(visit.PostID), | |
| 993 | + | newNullString(visit.Namespace), | |
| 994 | + | visit.Host, | |
| 995 | + | visit.Path, | |
| 996 | + | visit.IpAddress, | |
| 997 | + | visit.UserAgent, | |
| 998 | + | visit.Referer, | |
| 999 | + | visit.Status, | |
| 999 | 1000 | ) | |
| 1000 | 1001 | return err | |
| 1001 | 1002 | } |
+1
-1
go.mod
#
| ... | ... | @@ -36,7 +36,7 @@ require ( | |
| 36 | 36 | github.com/muesli/termenv v0.15.3-0.20240912151726-82936c5ea257 | |
| 37 | 37 | github.com/neurosnap/go-exif-remove v0.0.0-20221010134343-50d1e3c35577 | |
| 38 | 38 | github.com/picosh/pobj v0.0.0-20241016194248-c39198b2ff23 | |
| 39 | - | github.com/picosh/pubsub v0.0.0-20241112151357-866d44c53659 | |
| 39 | + | github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4 | |
| 40 | 40 | github.com/picosh/send v0.0.0-20241107150437-0febb0049b4f | |
| 41 | 41 | github.com/picosh/tunkit v0.0.0-20240905223921-532404cef9d9 | |
| 42 | 42 | github.com/picosh/utils v0.0.0-20241018143404-b351d5d765f3 |
+2
-2
go.sum
#
| ... | ... | @@ -269,8 +269,8 @@ github.com/picosh/go-rsync-receiver v0.0.0-20240709135253-1daf4b12a9fc h1:bvcsoO | |
| 269 | 269 | github.com/picosh/go-rsync-receiver v0.0.0-20240709135253-1daf4b12a9fc/go.mod h1:i0iR3W4GSm1PuvVxB9OH32E5jP+CYkVb2NQSe0JCtlo= | |
| 270 | 270 | github.com/picosh/pobj v0.0.0-20241016194248-c39198b2ff23 h1:NEJ5a4UXeF0/X7xmYNzXcwLQID9DwgazlqkMMC5zZ3M= | |
| 271 | 271 | github.com/picosh/pobj v0.0.0-20241016194248-c39198b2ff23/go.mod h1:cF+eAl4G1vU+WOD8cYCKaxokHo6MWmbR8J4/SJnvESg= | |
| 272 | - | github.com/picosh/pubsub v0.0.0-20241112151357-866d44c53659 h1:HmRi+QkAcKkOcLD90xbf7qZy95muQEd/DqttK9xtpHk= | |
| 273 | - | github.com/picosh/pubsub v0.0.0-20241112151357-866d44c53659/go.mod h1:m6ZZpg+lZB3XTIKlbSqQgi4NrBPtARv23b8vGYDoCo4= | |
| 272 | + | github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4 h1:pITSRXb9NDGdC6AmuS3JE+8Ek4/pUG7tXJPP3cOaqf4= | |
| 273 | + | github.com/picosh/pubsub v0.0.0-20241114025640-35db438302b4/go.mod h1:m6ZZpg+lZB3XTIKlbSqQgi4NrBPtARv23b8vGYDoCo4= | |
| 274 | 274 | github.com/picosh/send v0.0.0-20241107150437-0febb0049b4f h1:pdEh1Z7zH5Og9nS7jRuqwup3bcPsC6faDNQ6mgrV9ws= | |
| 275 | 275 | github.com/picosh/send v0.0.0-20241107150437-0febb0049b4f/go.mod h1:RAgLDK3LrDK6pNeXtU9tjo28obl5DxShcTUk2nm/KCM= | |
| 276 | 276 | github.com/picosh/senpai v0.0.0-20240503200611-af89e73973b0 h1:pBRIbiCj7K6rGELijb//dYhyCo8A3fvxW5dijrJVtjs= |
+0
-5
pgs/config.go
#
| ... | ... | @@ -20,13 +20,8 @@ func NewConfigSite() *shared.ConfigSite { | |
| 20 | 20 | minioUser := utils.GetEnv("MINIO_ROOT_USER", "") | |
| 21 | 21 | minioPass := utils.GetEnv("MINIO_ROOT_PASSWORD", "") | |
| 22 | 22 | dbURL := utils.GetEnv("DATABASE_URL", "") | |
| 23 | - | secret := utils.GetEnv("PICO_SECRET", "") | |
| 24 | - | if secret == "" { | |
| 25 | - | panic("must provide PICO_SECRET environment variable") | |
| 26 | - | } | |
| 27 | 23 | ||
| 28 | 24 | cfg := shared.ConfigSite{ | |
| 29 | - | Secret: secret, | |
| 30 | 25 | Domain: domain, | |
| 31 | 26 | Port: port, | |
| 32 | 27 | Protocol: protocol, |
+2
-2
pgs/web_asset_handler.go
#
| ... | ... | @@ -157,7 +157,7 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 157 | 157 | ) | |
| 158 | 158 | // track 404s | |
| 159 | 159 | ch := h.AnalyticsQueue | |
| 160 | - | view, err := shared.AnalyticsVisitFromRequest(r, h.Dbpool, h.UserID, h.Cfg.Secret) | |
| 160 | + | view, err := shared.AnalyticsVisitFromRequest(r, h.Dbpool, h.UserID) | |
| 161 | 161 | if err == nil { | |
| 162 | 162 | view.ProjectID = h.ProjectID | |
| 163 | 163 | view.Status = http.StatusNotFound |
| ... | ... | @@ -236,7 +236,7 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 236 | 236 | if finContentType == "text/html" { | |
| 237 | 237 | // track visit | |
| 238 | 238 | ch := h.AnalyticsQueue | |
| 239 | - | view, err := shared.AnalyticsVisitFromRequest(r, h.Dbpool, h.UserID, h.Cfg.Secret) | |
| 239 | + | view, err := shared.AnalyticsVisitFromRequest(r, h.Dbpool, h.UserID) | |
| 240 | 240 | if err == nil { | |
| 241 | 241 | view.ProjectID = h.ProjectID | |
| 242 | 242 | ch <- view |
+2
-2
prose/api.go
#
| ... | ... | @@ -272,7 +272,7 @@ func blogHandler(w http.ResponseWriter, r *http.Request) { | |
| 272 | 272 | ||
| 273 | 273 | // track visit | |
| 274 | 274 | ch := shared.GetAnalyticsQueue(r) | |
| 275 | - | view, err := shared.AnalyticsVisitFromRequest(r, dbpool, user.ID, cfg.Secret) | |
| 275 | + | view, err := shared.AnalyticsVisitFromRequest(r, dbpool, user.ID) | |
| 276 | 276 | if err == nil { | |
| 277 | 277 | ch <- view | |
| 278 | 278 | } else { |
| ... | ... | @@ -426,7 +426,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) { | |
| 426 | 426 | } | |
| 427 | 427 | ||
| 428 | 428 | // track visit | |
| 429 | - | view, err := shared.AnalyticsVisitFromRequest(r, dbpool, user.ID, cfg.Secret) | |
| 429 | + | view, err := shared.AnalyticsVisitFromRequest(r, dbpool, user.ID) | |
| 430 | 430 | if err == nil { | |
| 431 | 431 | view.PostID = post.ID | |
| 432 | 432 | ch <- view |
+0
-5
prose/config.go
#
| ... | ... | @@ -17,14 +17,9 @@ func NewConfigSite() *shared.ConfigSite { | |
| 17 | 17 | dbURL := utils.GetEnv("DATABASE_URL", "") | |
| 18 | 18 | maxSize := uint64(500 * utils.MB) | |
| 19 | 19 | maxImgSize := int64(10 * utils.MB) | |
| 20 | - | secret := utils.GetEnv("PICO_SECRET", "") | |
| 21 | - | if secret == "" { | |
| 22 | - | panic("must provide PICO_SECRET environment variable") | |
| 23 | - | } | |
| 24 | 20 | ||
| 25 | 21 | return &shared.ConfigSite{ | |
| 26 | 22 | Debug: debug == "1", | |
| 27 | - | Secret: secret, | |
| 28 | 23 | Domain: domain, | |
| 29 | 24 | Port: port, | |
| 30 | 25 | Protocol: protocol, |