From 0e4a87c523593389543d94742068654d9e5b2390 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sun, 13 Aug 2023 23:54:24 -0400 Subject: [PATCH 01/50] turns out the buildsetting stuff was added in go 1.18 --- README | 2 +- docs/honk.8 | 2 +- go.mod | 7 ++++++- preflight.sh | 6 +++--- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README b/README index 12da7d2..3287cc7 100644 --- a/README +++ b/README @@ -20,7 +20,7 @@ This does not imply the goal is to be what you want. ## build It should be sufficient to type make after unpacking a release. -You'll need a go compiler version 1.16 or later. And libsqlite3. +You'll need a go compiler version 1.18 or later. And libsqlite3. Even on a fast machine, building from source can take several seconds. diff --git a/docs/honk.8 b/docs/honk.8 index 966a939..861c86a 100644 --- a/docs/honk.8 +++ b/docs/honk.8 @@ -41,7 +41,7 @@ proxy_set_header Host $http_host; .Ss Build Building .Nm -requires a go compiler 1.16 and libsqlite. +requires a go compiler 1.18 and libsqlite. On .Ox this is the go and sqlite3 packages. diff --git a/go.mod b/go.mod index a19ad41..58f97d6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module humungus.tedunangst.com/r/honk -go 1.16 +go 1.18 require ( github.com/andybalholm/cascadia v1.3.1 @@ -11,3 +11,8 @@ require ( humungus.tedunangst.com/r/go-sqlite3 v1.1.3 humungus.tedunangst.com/r/webs v0.6.68 ) + +require ( + github.com/rivo/uniseg v0.2.0 // indirect + golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect +) diff --git a/preflight.sh b/preflight.sh index 5ebc0ab..7aeb972 100644 --- a/preflight.sh +++ b/preflight.sh @@ -1,11 +1,11 @@ set -e -go version > /dev/null 2>&1 || (echo go 1.16+ is required && false) +go version > /dev/null 2>&1 || (echo go 1.18+ is required && false) v=`go version | egrep -o "go1\.[^.]+"` || echo failed to identify go version -if [ "$v" \< "go1.16" ] ; then +if [ "$v" \< "go1.18" ] ; then echo go version is too old: $v - echo go 1.16+ is required + echo go 1.18+ is required false fi From 1910279c6becf97a8630c152717cb0d00ef6331e Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 18 Aug 2023 11:51:28 -0400 Subject: [PATCH 02/50] start working on an export command --- import.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 5 +++++ 2 files changed, 66 insertions(+) diff --git a/import.go b/import.go index 7dfbe6e..627f98f 100644 --- a/import.go +++ b/import.go @@ -16,6 +16,7 @@ package main import ( + "archive/zip" "encoding/csv" "encoding/json" "fmt" @@ -27,6 +28,8 @@ import ( "sort" "strings" "time" + + "humungus.tedunangst.com/r/webs/junk" ) func importMain(username, flavor, source string) { @@ -513,3 +516,61 @@ func importInstagram(username, source string) { log.Printf("honk saved %v -> %v", xid, err) } } + +func export(username, file string) { + user, err := butwhatabout(username) + if err != nil { + elog.Fatal(err) + } + fd, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + elog.Fatal(err) + } + zd := zip.NewWriter(fd) + donks := make(map[string]bool) + { + w, err := zd.Create("outbox.json") + if err != nil { + elog.Fatal(err) + } + var jonks []junk.Junk + rows, err := stmtUserHonks.Query(0, 3, user.Name, "0", 1234567) + honks := getsomehonks(rows, err) + for _, honk := range honks { + noise := honk.Noise + j, jo := jonkjonk(user, honk) + if honk.Format == "markdown" { + jo["source"] = noise + } + for _, donk := range honk.Donks { + donks[donk.XID] = true + } + jonks = append(jonks, j) + } + j := junk.New() + j["@context"] = itiswhatitis + j["id"] = user.URL + "/outbox" + j["attributedTo"] = user.URL + j["type"] = "OrderedCollection" + j["totalItems"] = len(jonks) + j["orderedItems"] = jonks + j.Write(w) + } + zd.Create("media/") + for donk := range donks { + var media string + var data []byte + w, err := zd.Create("media/" + donk) + if err != nil { + elog.Fatal(err) + } + row := stmtGetFileData.QueryRow(donk) + err = row.Scan(&media, &data) + if err != nil { + elog.Fatal(err) + } + w.Write(data) + } + zd.Close() + fd.Close() +} diff --git a/main.go b/main.go index 5e944d1..d40ca8b 100644 --- a/main.go +++ b/main.go @@ -122,6 +122,11 @@ func main() { elog.Fatal("import username mastodon|twitter srcdir") } importMain(args[1], args[2], args[3]) + case "export": + if len(args) != 3 { + elog.Fatal("export username destdir") + } + export(args[1], args[2]) case "devel": if len(args) != 2 { elog.Fatal("need an argument: devel (on|off)") From 842816f1bfae7b0bced75ec549b985b7ac88ccf8 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 18 Aug 2023 14:32:27 -0400 Subject: [PATCH 03/50] also export the inbox --- database.go | 4 ++-- import.go | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/database.go b/database.go index 8c9696b..1647a6e 100644 --- a/database.go +++ b/database.go @@ -245,7 +245,7 @@ func gethonksforuserfirstclass(userid int64, wanted int64) []*Honk { func gethonksforme(userid int64, wanted int64) []*Honk { dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) - rows, err := stmtHonksForMe.Query(wanted, userid, dt, userid) + rows, err := stmtHonksForMe.Query(wanted, userid, dt, userid, 250) return getsomehonks(rows, err) } func gethonksfromlongago(userid int64, wanted int64) []*Honk { @@ -1184,7 +1184,7 @@ func prepareStatements(db *sql.DB) { myhonkers := " and honker in (select xid from honkers where userid = ? and (flavor = 'sub' or flavor = 'peep' or flavor = 'presub') and combos not like '% - %')" stmtHonksForUser = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and dt > ?"+myhonkers+butnotthose+limit) stmtHonksForUserFirstClass = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and dt > ? and (rid = '' or what = 'bonk')"+myhonkers+butnotthose+limit) - stmtHonksForMe = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and dt > ? and whofore = 1"+butnotthose+limit) + stmtHonksForMe = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and dt > ? and whofore = 1"+butnotthose+smalllimit) stmtHonksFromLongAgo = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and dt > ? and dt < ? and whofore = 2"+butnotthose+limit) stmtHonksISaved = preparetodie(db, selecthonks+"where honks.honkid > ? and honks.userid = ? and flags & 4 order by honks.honkid desc") stmtHonksByHonker = preparetodie(db, selecthonks+"join honkers on (honkers.xid = honks.honker or honkers.xid = honks.oonker) where honks.honkid > ? and honks.userid = ? and honkers.name = ?"+butnotthose+limit) diff --git a/import.go b/import.go index 627f98f..01c9156 100644 --- a/import.go +++ b/import.go @@ -556,6 +556,30 @@ func export(username, file string) { j["orderedItems"] = jonks j.Write(w) } + { + w, err := zd.Create("inbox.json") + if err != nil { + elog.Fatal(err) + } + var jonks []junk.Junk + rows, err := stmtHonksForMe.Query(0, user.ID, "0", user.ID, 1234567) + honks := getsomehonks(rows, err) + for _, honk := range honks { + j, _ := jonkjonk(user, honk) + for _, donk := range honk.Donks { + donks[donk.XID] = true + } + jonks = append(jonks, j) + } + j := junk.New() + j["@context"] = itiswhatitis + j["id"] = user.URL + "/inbox" + j["attributedTo"] = user.URL + j["type"] = "OrderedCollection" + j["totalItems"] = len(jonks) + j["orderedItems"] = jonks + j.Write(w) + } zd.Create("media/") for donk := range donks { var media string From 20699112a0ca5e9edaac1cb7d9f443990ea79d4a Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 18 Aug 2023 20:53:42 -0400 Subject: [PATCH 04/50] matching import for the honk export. roughly roundtrips now. --- docs/honk.8 | 12 ++++++++- import.go | 78 ++++++++++++++++++++++++++++++++++++++++------------- main.go | 2 +- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/docs/honk.8 b/docs/honk.8 index 861c86a..af6942a 100644 --- a/docs/honk.8 +++ b/docs/honk.8 @@ -194,10 +194,13 @@ and templates are reloaded every request. Data may be imported and converted from other services using the .Ic import command. -Currently supports Mastodon, Twitter, and Instagram exported data. +Currently supports Honk, Mastodon, Twitter, and Instagram exported data. Posts are imported and backdated to appear as old honks. The Mastodon following list is imported, but must be refollowed. .Pp +To prepare a Honk data archive, extract the export.zip file. +.Dl ./honk import username honk source-directory +.Pp To prepare a Mastodon data archive, extract the archive-longhash.tar.gz file. .Dl ./honk import username mastodon source-directory .Pp @@ -208,6 +211,13 @@ and unzip any zip files contained within. .Pp To prepare an Instagram data archive, extract the igusername.zip file. .Dl ./honk import username instagram source-directory +.Ss Export +User data may be exported to a zip archive using the +.Ic export +command. +This will export the user's outbox and inbox in ActvityPub json format, +along with associated media. +.Dl ./honk export username zipname .Ss Advanced Options Advanced configuration values may be set by running the .Ic setconfig Ar key value diff --git a/import.go b/import.go index 01c9156..fc35ffe 100644 --- a/import.go +++ b/import.go @@ -36,6 +36,8 @@ func importMain(username, flavor, source string) { switch flavor { case "mastodon": importMastodon(username, source) + case "honk": + importHonk(username, source) case "twitter": importTwitter(username, source) case "instagram": @@ -45,11 +47,13 @@ func importMain(username, flavor, source string) { } } -type TootObject struct { +type ActivityObject struct { + AttributedTo string Summary string Content string InReplyTo string Conversation string + Context string Published time.Time Tag []struct { Type string @@ -63,10 +67,10 @@ type TootObject struct { } } -type PlainTootObject TootObject +type PlainActivityObject ActivityObject -func (obj *TootObject) UnmarshalJSON(b []byte) error { - p := (*PlainTootObject)(obj) +func (obj *ActivityObject) UnmarshalJSON(b []byte) error { + p := (*PlainActivityObject)(obj) json.Unmarshal(b, p) return nil } @@ -77,8 +81,9 @@ func importMastodon(username, source string) { elog.Fatal(err) } - if _, err := os.Stat(source + "/outbox.json"); err == nil { - importMastotoots(user, source) + outbox := source + "/outbox.json" + if _, err := os.Stat(outbox); err == nil { + importActivities(user, outbox, source) } else { ilog.Printf("skipping outbox.json!") } @@ -89,19 +94,33 @@ func importMastodon(username, source string) { } } -func importMastotoots(user *WhatAbout, source string) { - type Toot struct { +func importHonk(username, source string) { + user, err := butwhatabout(username) + if err != nil { + elog.Fatal(err) + } + + outbox := source + "/outbox.json" + if _, err := os.Stat(outbox); err == nil { + importActivities(user, outbox, source) + } else { + ilog.Printf("skipping outbox.json!") + } +} + +func importActivities(user *WhatAbout, filename, source string) { + type Activity struct { Id string Type string - To []string + To interface{} Cc []string - Object TootObject + Object ActivityObject } var outbox struct { - OrderedItems []Toot + OrderedItems []Activity } ilog.Println("Importing honks...") - fd, err := os.Open(source + "/outbox.json") + fd, err := os.Open(filename) if err != nil { elog.Fatal(err) } @@ -123,7 +142,11 @@ func importMastotoots(user *WhatAbout, source string) { } re_tootid := regexp.MustCompile("[^/]+$") - for _, item := range outbox.OrderedItems { + items := outbox.OrderedItems + for i, j := 0, len(items)-1; i < j; i, j = i+1, j-1 { + items[i], items[j] = items[j], items[i] + } + for _, item := range items { toot := item if toot.Type != "Create" { continue @@ -136,6 +159,21 @@ func importMastotoots(user *WhatAbout, source string) { if havetoot(xid) { continue } + + convoy := toot.Object.Context + if convoy == "" { + convoy = toot.Object.Conversation + } + var audience []string + to, ok := toot.To.(string) + if ok { + audience = append(audience, to) + } else { + for _, t := range toot.To.([]interface{}) { + audience = append(audience, t.(string)) + } + } + audience = append(audience, toot.Cc...) honk := Honk{ UserID: user.ID, What: "honk", @@ -144,9 +182,9 @@ func importMastotoots(user *WhatAbout, source string) { RID: toot.Object.InReplyTo, Date: toot.Object.Published, URL: xid, - Audience: append(toot.To, toot.Cc...), + Audience: audience, Noise: toot.Object.Content, - Convoy: toot.Object.Conversation, + Convoy: convoy, Whofore: 2, Format: "html", Precis: toot.Object.Summary, @@ -537,14 +575,15 @@ func export(username, file string) { rows, err := stmtUserHonks.Query(0, 3, user.Name, "0", 1234567) honks := getsomehonks(rows, err) for _, honk := range honks { + for _, donk := range honk.Donks { + donk.URL = "media/" + donk.XID + donks[donk.XID] = true + } noise := honk.Noise j, jo := jonkjonk(user, honk) if honk.Format == "markdown" { jo["source"] = noise } - for _, donk := range honk.Donks { - donks[donk.XID] = true - } jonks = append(jonks, j) } j := junk.New() @@ -565,10 +604,11 @@ func export(username, file string) { rows, err := stmtHonksForMe.Query(0, user.ID, "0", user.ID, 1234567) honks := getsomehonks(rows, err) for _, honk := range honks { - j, _ := jonkjonk(user, honk) for _, donk := range honk.Donks { + donk.URL = "media/" + donk.XID donks[donk.XID] = true } + j, _ := jonkjonk(user, honk) jonks = append(jonks, j) } j := junk.New() diff --git a/main.go b/main.go index d40ca8b..d5839ec 100644 --- a/main.go +++ b/main.go @@ -119,7 +119,7 @@ func main() { adminscreen() case "import": if len(args) != 4 { - elog.Fatal("import username mastodon|twitter srcdir") + elog.Fatal("import username honk|mastodon|twitter srcdir") } importMain(args[1], args[2], args[3]) case "export": From 9658fb8605e698db37e20fecffea1e1c9b2e8630 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 19 Aug 2023 01:12:50 -0400 Subject: [PATCH 05/50] misc.js is a view dir file --- web.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web.go b/web.go index 905327c..918634a 100644 --- a/web.go +++ b/web.go @@ -81,8 +81,8 @@ func getInfo(r *http.Request) map[string]interface{} { templinfo["StyleParam"] = getassetparam(viewDir + "/views/style.css") templinfo["LocalStyleParam"] = getassetparam(dataDir + "/views/local.css") templinfo["JSParam"] = getassetparam(viewDir + "/views/honkpage.js") + templinfo["MiscJSParam"] = getassetparam(viewDir + "/views/misc.js") templinfo["LocalJSParam"] = getassetparam(dataDir + "/views/local.js") - templinfo["MiscJSParam"] = getassetparam(dataDir + "/views/misc.js") templinfo["ServerName"] = serverName templinfo["IconName"] = iconName templinfo["UserSep"] = userSep @@ -2685,6 +2685,7 @@ func serve() { viewDir + "/views/style.css", dataDir + "/views/local.css", viewDir + "/views/honkpage.js", + viewDir + "/views/misc.js", dataDir + "/views/local.js", } for _, s := range assets { From 773eb649a1e6f587bb95116d3cce2b69a0f0a6d4 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 19 Aug 2023 21:16:05 -0400 Subject: [PATCH 06/50] solve the problem of slow requests running in parallel --- deliverator.go | 6 +++--- go.mod | 8 ++++---- go.sum | 43 +++++++++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/deliverator.go b/deliverator.go index 6f55964..e1c8377 100644 --- a/deliverator.go +++ b/deliverator.go @@ -118,8 +118,9 @@ func deliverate(userid int64, rcpt string, msg []byte) { var garage = gate.NewLimiter(40) func deliveration(doover Doover) { - garage.Start() - defer garage.Finish() + rcpt := doover.Rcpt + garage.StartKey(rcpt) + defer garage.FinishKey(rcpt) var ki *KeyInfo ok := ziggies.Get(doover.Userid, &ki) @@ -128,7 +129,6 @@ func deliveration(doover Doover) { return } var inbox string - rcpt := doover.Rcpt // already did the box indirection if rcpt[0] == '%' { inbox = rcpt[1:] diff --git a/go.mod b/go.mod index 58f97d6..b7d44e5 100644 --- a/go.mod +++ b/go.mod @@ -6,13 +6,13 @@ require ( github.com/andybalholm/cascadia v1.3.1 github.com/gorilla/mux v1.8.0 github.com/mattn/go-runewidth v0.0.13 - golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 - golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 + golang.org/x/crypto v0.12.0 + golang.org/x/net v0.14.0 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 - humungus.tedunangst.com/r/webs v0.6.68 + humungus.tedunangst.com/r/webs v0.7.2 ) require ( github.com/rivo/uniseg v0.2.0 // indirect - golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect + golang.org/x/image v0.11.0 // indirect ) diff --git a/go.sum b/go.sum index 5fef797..2a48f61 100644 --- a/go.sum +++ b/go.sum @@ -6,24 +6,47 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE= -golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= +golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= -humungus.tedunangst.com/r/webs v0.6.68 h1:veKjASf1krPf4o3O7hMRsNvE4+Z6LzXVso/qMccZntk= -humungus.tedunangst.com/r/webs v0.6.68/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc= +humungus.tedunangst.com/r/webs v0.7.2 h1:WTBrDhoHXt0lKpvERn7TzcLB0KVRy0wYwscxjB4aD+E= +humungus.tedunangst.com/r/webs v0.7.2/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= From 57e34c344dfbace87c2f32da46b83687e4c8873d Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Wed, 23 Aug 2023 23:34:14 -0400 Subject: [PATCH 07/50] run analyze as final upgrade step --- upgradedb.go | 1 + 1 file changed, 1 insertion(+) diff --git a/upgradedb.go b/upgradedb.go index de6cb61..c15bb84 100644 --- a/upgradedb.go +++ b/upgradedb.go @@ -172,6 +172,7 @@ func upgradedb() { tx = nil fallthrough case 45: + try("analyze") default: elog.Fatalf("can't upgrade unknown version %d", dbversion) From f7cd268fe29dc6a37bee06bdcbb56f3aad5fc532 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 24 Aug 2023 11:54:10 -0400 Subject: [PATCH 08/50] add some logging for unexpected activities --- web.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/web.go b/web.go index 918634a..e88e35f 100644 --- a/web.go +++ b/web.go @@ -449,7 +449,20 @@ func inbox(w http.ResponseWriter, r *http.Request) { addreaction(user, obj, who, content) } default: - go xonksaver(user, j, origin) + go saveandcheck(user, j, origin) + } +} + +func saveandcheck(user *WhatAbout, j junk.Junk, origin string) { + xonk := xonksaver(user, j, origin) + if xonk == nil { + return + } + if sname := shortname(user.ID, xonk.Honker); sname == "" { + dlog.Printf("received unexpected activity from %s", xonk.Honker) + if xonk.Whofore == 0 { + dlog.Printf("it's not even for me!") + } } } From 93a79455d2cba2e75d2666dd97713d9d1fdf11da Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 24 Aug 2023 13:09:41 -0400 Subject: [PATCH 09/50] don't reset audience for updates --- web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web.go b/web.go index e88e35f..de6ee08 100644 --- a/web.go +++ b/web.go @@ -1783,7 +1783,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk { honk.Precis = "re: " + honk.Precis } } - } else { + } else if updatexid == "" { honk.Audience = []string{thewholeworld} } if honk.Noise != "" && honk.Noise[0] == '@' { From 634d74d139b7079b8ecfc81d5f04c25fb9aa0638 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 00:30:19 -0400 Subject: [PATCH 10/50] a very plain text accessor that's helpful for debugging --- database.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/database.go b/database.go index 1647a6e..afbf133 100644 --- a/database.go +++ b/database.go @@ -790,9 +790,19 @@ func loadchatter(userid int64) []*Chatter { } func (honk *Honk) Plain() string { + return honktoplain(honk, false) +} + +func (honk *Honk) VeryPlain() string { + return honktoplain(honk, true) +} + +func honktoplain(honk *Honk, very bool) string { var plain []string var filt htfilter.Filter - filt.WithLinks = true + if !very { + filt.WithLinks = true + } if honk.Precis != "" { t, _ := filt.TextOnly(honk.Precis) plain = append(plain, t) From 4f0d15ebb548fa42d1efca280740b1b1d216b9e2 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 00:33:16 -0400 Subject: [PATCH 11/50] i think maybe we want the thread sorted the other way actually? --- web.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/web.go b/web.go index de6ee08..0ec9ccf 100644 --- a/web.go +++ b/web.go @@ -1078,9 +1078,16 @@ func threadsort(honks []*Honk) []*Honk { } p.Style += fmt.Sprintf(" level%d", level) childs := kids[p.XID] - sort.SliceStable(childs, func(i, j int) bool { - return sameperson(childs[i], p) && !sameperson(childs[j], p) - }) + if false { + sort.SliceStable(childs, func(i, j int) bool { + return sameperson(childs[i], p) && !sameperson(childs[j], p) + }) + } + if true { + sort.SliceStable(childs, func(i, j int) bool { + return !sameperson(childs[i], p) && sameperson(childs[j], p) + }) + } for _, h := range childs { if !done[h] { done[h] = true From dbff9a6151649fe2105716ee4cc8387391963e61 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 00:45:41 -0400 Subject: [PATCH 12/50] at least use servername for title, until we fill in better --- views/header.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/header.html b/views/header.html index bd10995..c40314a 100644 --- a/views/header.html +++ b/views/header.html @@ -1,7 +1,7 @@ -honk +{{ or .Title .ServerName }} {{ if .LocalStyleParam }} From bddd8554a2fde7503ae5897cd5a7ba6c2be0dbf2 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 01:12:26 -0400 Subject: [PATCH 13/50] rely less on id for form updates --- views/honkpage.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/views/honkpage.js b/views/honkpage.js index ec9d8db..3e22cd2 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -384,13 +384,13 @@ function hideelement(el) { if (!el) return el.style.display = "none" } -function updatedonker() { - var el = document.getElementById("donker") +function updatedonker(ev) { + var el = ev.target.parentElement el.children[1].textContent = el.children[0].value.slice(-20) - el = document.getElementById("donkdescriptor") - el.style.display = "" - el = document.getElementById("saveddonkxid") + el = el.nextSibling el.value = "" + el = el.parentElement.nextSibling + el.style.display = "" } var checkinprec = 100.0 var gpsoptions = { From 6f5bf49fca0ad139358b85b322bf6a76c42fba91 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 01:34:48 -0400 Subject: [PATCH 14/50] allow uploading multiple files (but beware, it gets weird fast) --- views/honkform.html | 2 +- web.go | 35 +++++++++++++++++++++++++---------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/views/honkform.html b/views/honkform.html index b5eb4a3..ae6cac2 100644 --- a/views/honkform.html +++ b/views/honkform.html @@ -9,7 +9,7 @@
more options

- +


diff --git a/web.go b/web.go index 0ec9ccf..dc5d1b2 100644 --- a/web.go +++ b/web.go @@ -22,6 +22,7 @@ import ( "html/template" "io" notrand "math/rand" + "mime/multipart" "net/http" "net/url" "os" @@ -1612,11 +1613,23 @@ func canedithonk(user *WhatAbout, honk *Honk) bool { return true } -func submitdonk(w http.ResponseWriter, r *http.Request) (*Donk, error) { +func submitdonk(w http.ResponseWriter, r *http.Request) ([]*Donk, error) { if !strings.HasPrefix(strings.ToLower(r.Header.Get("Content-Type")), "multipart/form-data") { return nil, nil } - file, filehdr, err := r.FormFile("donk") + var donks []*Donk + for _, hdr := range r.MultipartForm.File["donk"] { + donk, err := formtodonk(w, r, hdr) + if err != nil { + return nil, err + } + donks = append(donks, donk) + } + return donks, nil +} + +func formtodonk(w http.ResponseWriter, r *http.Request, filehdr *multipart.FileHeader) (*Donk, error) { + file, err := filehdr.Open() if err != nil { if err == http.ErrMissingFile { return nil, nil @@ -1814,12 +1827,13 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk { donkxid := r.FormValue("donkxid") if donkxid == "" { - d, err := submitdonk(w, r) + donks, err := submitdonk(w, r) if err != nil && err != http.ErrMissingFile { return nil } - if d != nil { - honk.Donks = append(honk.Donks, d) + if len(donks) > 0 { + honk.Donks = append(honk.Donks, donks...) + d := donks[0] donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID) } } else { @@ -1992,12 +2006,12 @@ func submitchonk(w http.ResponseWriter, r *http.Request) { Noise: noise, Format: format, } - d, err := submitdonk(w, r) + donks, err := submitdonk(w, r) if err != nil && err != http.ErrMissingFile { return } - if d != nil { - ch.Donks = append(ch.Donks, d) + if len(donks) > 0 { + ch.Donks = append(ch.Donks, donks...) } translatechonk(&ch) @@ -2505,15 +2519,16 @@ func apihandler(w http.ResponseWriter, r *http.Request) { } fmt.Fprintf(w, "%s", h.XID) case "donk": - d, err := submitdonk(w, r) + donks, err := submitdonk(w, r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } - if d == nil { + if len(donks) == 0 { http.Error(w, "missing donk", http.StatusBadRequest) return } + d := donks[0] donkxid := fmt.Sprintf("%s:%d", d.XID, d.FileID) w.Write([]byte(donkxid)) case "zonkit": From 17f2f729eee91fa172fd9ca63d5c877493cefb85 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Fri, 25 Aug 2023 01:47:20 -0400 Subject: [PATCH 15/50] start the changelog --- docs/changelog.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5e7adbd..c308f4d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,5 +1,23 @@ changelog +### next + ++ Upload multiple files (but beware). + ++ Better page titles. + ++ Refine thread sort. + ++ Send updates to correct audience. + ++ Run analyze to improve database performance. + ++ Delivery performance improvements. + ++ Export command to ActivityPub data. (And import.) + ++ Note that we require go 1.18 now. + ### 1.0.0 Happy Honker + A great big honk composition text box. From 2c5a05137615a2fe3e0c573aaad85ccbff6f422d Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 14:39:09 -0400 Subject: [PATCH 16/50] some hotkeys from zev --- views/honkpage.html | 4 ++-- views/honkpage.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/views/honkpage.html b/views/honkpage.html index cbb1565..15d4b96 100644 --- a/views/honkpage.html +++ b/views/honkpage.html @@ -18,8 +18,8 @@ {{ if and .HonkCSRF (not .IsPreview) }}

-

- +

+

{{ end }}
diff --git a/views/honkpage.js b/views/honkpage.js index 3e22cd2..f94cd21 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -416,6 +416,50 @@ function fillcheckin() { }, gpsoptions) } } + +function scrollnexthonk() { + var honks = document.getElementsByClassName("honk"); + for (var i = 0; i < honks.length; i++) { + var h = honks[i]; + var b = h.getBoundingClientRect(); + if (b.top > 1.0) { + h.scrollIntoView(); + break; + } + } +} + +function scrollprevioushonk() { + var honks = document.getElementsByClassName("honk"); + for (var i = 1; i < honks.length; i++) { + var b = honks[i].getBoundingClientRect(); + if (b.top > -1.0) { + honks[i-1].scrollIntoView(); + break; + } + } +} + +document.addEventListener("keydown", function(e) { + if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) + return; + + switch (e.code) { + case "KeyR": + refreshhonks(document.getElementById("honkrefresher")); + break; + case "KeyS": + oldestnewest(document.getElementById("newerscroller")); + break; + case "KeyJ": + scrollnexthonk(); + break; + case "KeyK": + scrollprevioushonk(); + break; + } +}) + function addemu(elem) { const data = elem.alt const box = document.getElementById("honknoise"); From 0ba146c00cb69ed21c5d528f88f737714ecabde5 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 14:56:28 -0400 Subject: [PATCH 17/50] hotkey / to focus search --- views/header.html | 2 +- views/honkpage.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/views/header.html b/views/header.html index c40314a..ef927f2 100644 --- a/views/header.html +++ b/views/header.html @@ -52,7 +52,7 @@
  • help
  • - +
  • diff --git a/views/honkpage.js b/views/honkpage.js index f94cd21..9f198a3 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -457,6 +457,11 @@ document.addEventListener("keydown", function(e) { case "KeyK": scrollprevioushonk(); break; + case "Slash": + document.getElementById("topmenu").open = true + document.getElementById("searchbox").focus() + e.preventDefault() + break } }) From 86738e30b832edb93fe506599921581f752aebbc Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 17:42:14 -0400 Subject: [PATCH 18/50] if develmode, relative links for emoji --- fun.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fun.go b/fun.go index d013ac9..17fc380 100644 --- a/fun.go +++ b/fun.go @@ -432,6 +432,9 @@ var emucache = cache.New(cache.Options{Filler: func(ename string) (Emu, bool) { continue } url := fmt.Sprintf("https://%s/emu/%s%s", serverName, fname, ext) + if develMode { + url = fmt.Sprintf("/emu/%s%s", fname, ext) + } return Emu{ID: url, Name: ename, Type: "image/" + ext[1:]}, true } return Emu{Name: ename, ID: "", Type: "image/png"}, true From db63bd3fc393627cdc7447b3404f3a4bf0337c77 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 18:09:21 -0400 Subject: [PATCH 19/50] some fixes for attachments and edits and previews --- views/honkform.html | 3 +-- web.go | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/views/honkform.html b/views/honkform.html index ae6cac2..b519529 100644 --- a/views/honkform.html +++ b/views/honkform.html @@ -9,8 +9,7 @@
    more options

    - - +


    {{ with .SavedPlace }} diff --git a/web.go b/web.go index dc5d1b2..16c6a1d 100644 --- a/web.go +++ b/web.go @@ -1569,11 +1569,15 @@ func edithonkpage(w http.ResponseWriter, r *http.Request) { templinfo["Duration"] = tm.Duration } } - templinfo["ServerMessage"] = "honk edit 2" + templinfo["ServerMessage"] = "honk edit" templinfo["IsPreview"] = true templinfo["UpdateXID"] = honk.XID if len(honk.Donks) > 0 { - templinfo["SavedFile"] = honk.Donks[0].XID + var savedfiles []string + for _, d := range honk.Donks { + savedfiles = append(savedfiles, fmt.Sprintf("%s:%d", d.XID, d.FileID)) + } + templinfo["SavedFile"] = strings.Join(savedfiles, ",") } err := readviews.Execute(w, "honkpage.html", templinfo) if err != nil { @@ -1618,7 +1622,10 @@ func submitdonk(w http.ResponseWriter, r *http.Request) ([]*Donk, error) { return nil, nil } var donks []*Donk - for _, hdr := range r.MultipartForm.File["donk"] { + for i, hdr := range r.MultipartForm.File["donk"] { + if i > 16 { + break + } donk, err := formtodonk(w, r, hdr) if err != nil { return nil, err @@ -1825,7 +1832,7 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk { honk.Public = loudandproud(honk.Audience) honk.Convoy = convoy - donkxid := r.FormValue("donkxid") + donkxid := strings.Join(r.Form["donkxid"], ",") if donkxid == "" { donks, err := submitdonk(w, r) if err != nil && err != http.ErrMissingFile { @@ -1833,11 +1840,18 @@ func submithonk(w http.ResponseWriter, r *http.Request) *Honk { } if len(donks) > 0 { honk.Donks = append(honk.Donks, donks...) - d := donks[0] - donkxid = fmt.Sprintf("%s:%d", d.XID, d.FileID) + var xids []string + for _, d := range honk.Donks { + xids = append(xids, fmt.Sprintf("%s:%d", d.XID, d.FileID)) + } + donkxid = strings.Join(xids, ",") } } else { - for _, xid := range r.Form["donkxid"] { + xids := strings.Split(donkxid, ",") + for i, xid := range xids { + if i > 16 { + break + } p := strings.Split(xid, ":") xid = p[0] url := fmt.Sprintf("https://%s/d/%s", serverName, xid) From 314949d045b4f6fbe86ec0fe53807c577f518388 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 19:03:11 -0400 Subject: [PATCH 20/50] the zalgo filter was accidentally eating newlines too --- skulduggery.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/skulduggery.go b/skulduggery.go index c8f669c..1f90cef 100644 --- a/skulduggery.go +++ b/skulduggery.go @@ -29,6 +29,9 @@ func demoji(s string) string { zw := false for _, c := range s { + if c == '\n' { + continue + } if runewidth.RuneWidth(c) == 0 { zw = true break From 1b36e72cc1b6e3e9425915be69f870934edbf258 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sat, 26 Aug 2023 19:47:45 -0400 Subject: [PATCH 21/50] need to allow images in markdown --- fun.go | 1 + 1 file changed, 1 insertion(+) diff --git a/fun.go b/fun.go index 17fc380..a71cf54 100644 --- a/fun.go +++ b/fun.go @@ -344,6 +344,7 @@ func translate(honk *Honk) { var marker mz.Marker marker.HashLinker = ontoreplacer marker.AtLinker = attoreplacer + marker.AllowImages = true noise = strings.TrimSpace(noise) noise = marker.Mark(noise) honk.Noise = noise From 0dd17d00386e1666c51f4761c1d6706b73d6b231 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sun, 27 Aug 2023 15:25:58 -0400 Subject: [PATCH 22/50] a bigger shrinker for uploads --- backend.go | 25 +++++++++++++++++++++++++ web.go | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/backend.go b/backend.go index 19b260f..2d20874 100644 --- a/backend.go +++ b/backend.go @@ -83,6 +83,31 @@ func imageFromSVG(data []byte) (*image.Image, error) { return svg, nil } +func bigshrink(data []byte) (*image.Image, error) { + if isSVG(data) { + return imageFromSVG(data) + } + cl, err := rpc.Dial("unix", backendSockname()) + if err != nil { + return nil, err + } + defer cl.Close() + var res ShrinkerResult + err = cl.Call("Shrinker.Shrink", &ShrinkerArgs{ + Buf: data, + Params: image.Params{ + LimitSize: 14200 * 4200, + MaxWidth: 2600, + MaxHeight: 2048, + MaxSize: 768 * 1024, + }, + }, &res) + if err != nil { + return nil, err + } + return res.Image, nil +} + func shrinkit(data []byte) (*image.Image, error) { if isSVG(data) { return imageFromSVG(data) diff --git a/web.go b/web.go index 16c6a1d..398cbde 100644 --- a/web.go +++ b/web.go @@ -1650,7 +1650,7 @@ func formtodonk(w http.ResponseWriter, r *http.Request, filehdr *multipart.FileH file.Close() data := buf.Bytes() var media, name string - img, err := shrinkit(data) + img, err := bigshrink(data) if err == nil { data = img.Data format := img.Format From a4be8b9e02fb8ea7de956d95f4725c352832c61f Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Sun, 27 Aug 2023 17:06:11 -0400 Subject: [PATCH 23/50] note the hotkeys --- docs/changelog.txt | 4 ++++ docs/honk.1 | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c308f4d..eb634f9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -2,6 +2,10 @@ changelog ### next ++ Allow bigger image uploads. + ++ Some hotkeys for the web UI. + + Upload multiple files (but beware). + Better page titles. diff --git a/docs/honk.1 b/docs/honk.1 index 4b4582a..a98fa07 100644 --- a/docs/honk.1 +++ b/docs/honk.1 @@ -130,11 +130,24 @@ Replies higher in the tree are still received. Please no. .It Ic edit Change it up. -Alas, Update activities do not federate reliably. .Ss Refresh Clicking the refresh button will load new honks, if any. New honks will be subtly highlighted. .El +.Ss Hotkeys +The following keyboard shortcuts may also be used to navigate. +.Bl -tag -width short +.It j +Scroll to next honk. +.It k +Scroll to previous honk. +.It r +Refresh. +.It s +Scroll down to oldest newest. +.It / +Search. +.El .Ss Honking Refer to the .Xr honk 5 From 3bbd1ad2b3cd04e58bb10f4f90d3378976b4dea4 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 01:06:39 -0400 Subject: [PATCH 24/50] make target for help --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 8b87efd..70756e5 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,11 @@ honk: .preflightcheck schema.sql *.go go.mod .preflightcheck: preflight.sh @sh ./preflight.sh +help: + for m in docs/*.[13578] ; do \ + mandoc -T html -O fragment,man=%N.%S.html $$m | sed -E 's//
    /g' > $$m.html ; \ + done + clean: rm -f honk From b360a01719e379f859034a5ac25bc03ac26bb2c2 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 01:10:27 -0400 Subject: [PATCH 25/50] factor out 7 day honkwindow, from zev --- database.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/database.go b/database.go index afbf133..dacca18 100644 --- a/database.go +++ b/database.go @@ -36,6 +36,8 @@ import ( "humungus.tedunangst.com/r/webs/mz" ) +var honkwindow time.Duration = 7 * 24 * time.Hour + //go:embed schema.sql var sqlSchema string @@ -187,7 +189,7 @@ func getbonk(userid int64, xid string) *Honk { } func getpublichonks() []*Honk { - dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) + dt := time.Now().Add(-honkwindow).UTC().Format(dbtimeformat) rows, err := stmtPublicHonks.Query(dt, 100) return getsomehonks(rows, err) } @@ -223,7 +225,7 @@ func geteventhonks(userid int64) []*Honk { return honks } func gethonksbyuser(name string, includeprivate bool, wanted int64) []*Honk { - dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) + dt := time.Now().Add(-honkwindow).UTC().Format(dbtimeformat) limit := 50 whofore := 2 if includeprivate { @@ -233,18 +235,18 @@ func gethonksbyuser(name string, includeprivate bool, wanted int64) []*Honk { return getsomehonks(rows, err) } func gethonksforuser(userid int64, wanted int64) []*Honk { - dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) + dt := time.Now().Add(-honkwindow).UTC().Format(dbtimeformat) rows, err := stmtHonksForUser.Query(wanted, userid, dt, userid, userid) return getsomehonks(rows, err) } func gethonksforuserfirstclass(userid int64, wanted int64) []*Honk { - dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) + dt := time.Now().Add(-honkwindow).UTC().Format(dbtimeformat) rows, err := stmtHonksForUserFirstClass.Query(wanted, userid, dt, userid, userid) return getsomehonks(rows, err) } func gethonksforme(userid int64, wanted int64) []*Honk { - dt := time.Now().Add(-7 * 24 * time.Hour).UTC().Format(dbtimeformat) + dt := time.Now().Add(-honkwindow).UTC().Format(dbtimeformat) rows, err := stmtHonksForMe.Query(wanted, userid, dt, userid, 250) return getsomehonks(rows, err) } From d69156f96ece1f7ee7ce4b177193b1e8e3dcaaee Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 01:12:53 -0400 Subject: [PATCH 26/50] configurable honkwindow --- database.go | 2 +- main.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/database.go b/database.go index dacca18..6d7b5f6 100644 --- a/database.go +++ b/database.go @@ -36,7 +36,7 @@ import ( "humungus.tedunangst.com/r/webs/mz" ) -var honkwindow time.Duration = 7 * 24 * time.Hour +var honkwindow time.Duration = 7 //go:embed schema.sql var sqlSchema string diff --git a/main.go b/main.go index d5839ec..e2d42ef 100644 --- a/main.go +++ b/main.go @@ -112,6 +112,8 @@ func main() { getconfig("devel", &develMode) getconfig("fasttimeout", &fastTimeout) getconfig("slowtimeout", &slowTimeout) + getconfig("honkwindow", &honkwindow) + honkwindow *= 24 * time.Hour getconfig("signgets", &signGets) prepareStatements(db) switch cmd { From cc3976daa63612814494de37030ceb68a1c232f5 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 01:21:44 -0400 Subject: [PATCH 27/50] command line errors to stderr and exit(1), like zev --- main.go | 62 ++++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/main.go b/main.go index e2d42ef..2295159 100644 --- a/main.go +++ b/main.go @@ -64,6 +64,11 @@ func reexecArgs(cmd string) []string { var elog, ilog, dlog *golog.Logger +func errx(msg string, args ...interface{}) { + fmt.Fprintf(os.Stderr, msg, args...) + os.Exit(1) +} + func main() { flag.StringVar(&dataDir, "datadir", dataDir, "data directory") flag.StringVar(&viewDir, "viewdir", viewDir, "view directory") @@ -121,17 +126,17 @@ func main() { adminscreen() case "import": if len(args) != 4 { - elog.Fatal("import username honk|mastodon|twitter srcdir") + errx("import username honk|mastodon|twitter srcdir") } importMain(args[1], args[2], args[3]) case "export": if len(args) != 3 { - elog.Fatal("export username destdir") + errx("export username destdir") } export(args[1], args[2]) case "devel": if len(args) != 2 { - elog.Fatal("need an argument: devel (on|off)") + errx("need an argument: devel (on|off)") } switch args[1] { case "on": @@ -139,11 +144,11 @@ func main() { case "off": setconfig("devel", 0) default: - elog.Fatal("argument must be on or off") + errx("argument must be on or off") } case "setconfig": if len(args) != 3 { - elog.Fatal("need an argument: setconfig key val") + errx("need an argument: setconfig key val") } var val interface{} var err error @@ -155,66 +160,55 @@ func main() { adduser() case "deluser": if len(args) < 2 { - fmt.Printf("usage: honk deluser username\n") - return + errx("usage: honk deluser username\n") } deluser(args[1]) case "chpass": if len(args) < 2 { - fmt.Printf("usage: honk chpass username\n") - return + errx("usage: honk chpass username\n") } chpass(args[1]) case "follow": if len(args) < 3 { - fmt.Printf("usage: honk follow username url\n") - return + errx("usage: honk follow username url\n") } user, err := butwhatabout(args[1]) if err != nil { - fmt.Printf("user not found\n") - return + errx("user %s not found\n", args[1]) } var meta HonkerMeta mj, _ := jsonify(&meta) honkerid, err := savehonker(user, args[2], "", "presub", "", mj) if err != nil { - fmt.Printf("had some trouble with that: %s\n", err) - return + errx("had some trouble with that: %s\n", err) } followyou(user, honkerid, true) case "unfollow": if len(args) < 3 { - fmt.Printf("usage: honk unfollow username url\n") - return + errx("usage: honk unfollow username url\n") } user, err := butwhatabout(args[1]) if err != nil { - fmt.Printf("user not found\n") - return + errx("user not found\n") } row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID) var honkerid int64 err = row.Scan(&honkerid) if err != nil { - fmt.Printf("sorry couldn't find them\n") - return + errx("sorry couldn't find them\n") } unfollowyou(user, honkerid, true) case "sendmsg": if len(args) < 4 { - fmt.Printf("usage: honk send username filename rcpt\n") - return + errx("usage: honk send username filename rcpt\n") } user, err := butwhatabout(args[1]) if err != nil { - fmt.Printf("user not found\n") - return + errx("user %s not found\n", args[1]) } data, err := os.ReadFile(args[2]) if err != nil { - fmt.Printf("can't read file\n") - return + errx("can't read file: %s\n", err) } deliverate(user.ID, args[3], data) case "cleanup": @@ -225,29 +219,25 @@ func main() { cleanupdb(arg) case "unplug": if len(args) < 2 { - fmt.Printf("usage: honk unplug servername\n") - return + errx("usage: honk unplug servername\n") } name := args[1] unplugserver(name) case "backup": if len(args) < 2 { - fmt.Printf("usage: honk backup dirname\n") - return + errx("usage: honk backup dirname\n") } name := args[1] svalbard(name) case "ping": if len(args) < 3 { - fmt.Printf("usage: honk ping (from username) (to username or url)\n") - return + errx("usage: honk ping (from username) (to username or url)\n") } name := args[1] targ := args[2] user, err := butwhatabout(name) if err != nil { - elog.Printf("unknown user") - return + errx("unknown user %s", name) } ping(user, targ) case "run": @@ -257,6 +247,6 @@ func main() { case "test": ElaborateUnitTests() default: - elog.Fatal("unknown command") + errx("unknown command") } } From b539f292a68f6c2a98b014df5f4152eadc8ae9fb Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 02:10:23 -0400 Subject: [PATCH 28/50] ignore help files --- .hgignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.hgignore b/.hgignore index a00a9cf..5596488 100644 --- a/.hgignore +++ b/.hgignore @@ -7,3 +7,11 @@ memes emus honk violations.json +docs/activitypub.7.html +docs/hfcs.1.html +docs/honk.1.html +docs/honk.3.html +docs/honk.5.html +docs/honk.8.html +docs/intro.1.html +docs/vim.3.html From aad5243bb13f4aabdf5cf956d601bdfac8196cdd Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 15:00:18 -0400 Subject: [PATCH 29/50] ignore alt and ctrl in hotkey --- views/honkpage.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/views/honkpage.js b/views/honkpage.js index 9f198a3..c3e3e63 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -440,9 +440,11 @@ function scrollprevioushonk() { } } -document.addEventListener("keydown", function(e) { +function hotkey(e) { if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) - return; + return + if (e.ctrlKey || e.altKey) + return switch (e.code) { case "KeyR": @@ -463,7 +465,9 @@ document.addEventListener("keydown", function(e) { e.preventDefault() break } -}) +} + +document.addEventListener("keydown", hotkey) function addemu(elem) { const data = elem.alt From a4817e149bd52db25a3d0e7eb9a6e5288022877e Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 16:08:29 -0400 Subject: [PATCH 30/50] consistent newlines in errx --- main.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/main.go b/main.go index 2295159..620467f 100644 --- a/main.go +++ b/main.go @@ -65,7 +65,7 @@ func reexecArgs(cmd string) []string { var elog, ilog, dlog *golog.Logger func errx(msg string, args ...interface{}) { - fmt.Fprintf(os.Stderr, msg, args...) + fmt.Fprintf(os.Stderr, msg+"\n", args...) os.Exit(1) } @@ -160,55 +160,55 @@ func main() { adduser() case "deluser": if len(args) < 2 { - errx("usage: honk deluser username\n") + errx("usage: honk deluser username") } deluser(args[1]) case "chpass": if len(args) < 2 { - errx("usage: honk chpass username\n") + errx("usage: honk chpass username") } chpass(args[1]) case "follow": if len(args) < 3 { - errx("usage: honk follow username url\n") + errx("usage: honk follow username url") } user, err := butwhatabout(args[1]) if err != nil { - errx("user %s not found\n", args[1]) + errx("user %s not found", args[1]) } var meta HonkerMeta mj, _ := jsonify(&meta) honkerid, err := savehonker(user, args[2], "", "presub", "", mj) if err != nil { - errx("had some trouble with that: %s\n", err) + errx("had some trouble with that: %s", err) } followyou(user, honkerid, true) case "unfollow": if len(args) < 3 { - errx("usage: honk unfollow username url\n") + errx("usage: honk unfollow username url") } user, err := butwhatabout(args[1]) if err != nil { - errx("user not found\n") + errx("user not found") } row := db.QueryRow("select honkerid from honkers where xid = ? and userid = ? and flavor in ('sub')", args[2], user.ID) var honkerid int64 err = row.Scan(&honkerid) if err != nil { - errx("sorry couldn't find them\n") + errx("sorry couldn't find them") } unfollowyou(user, honkerid, true) case "sendmsg": if len(args) < 4 { - errx("usage: honk send username filename rcpt\n") + errx("usage: honk send username filename rcpt") } user, err := butwhatabout(args[1]) if err != nil { - errx("user %s not found\n", args[1]) + errx("user %s not found", args[1]) } data, err := os.ReadFile(args[2]) if err != nil { - errx("can't read file: %s\n", err) + errx("can't read file: %s", err) } deliverate(user.ID, args[3], data) case "cleanup": @@ -219,19 +219,19 @@ func main() { cleanupdb(arg) case "unplug": if len(args) < 2 { - errx("usage: honk unplug servername\n") + errx("usage: honk unplug servername") } name := args[1] unplugserver(name) case "backup": if len(args) < 2 { - errx("usage: honk backup dirname\n") + errx("usage: honk backup dirname") } name := args[1] svalbard(name) case "ping": if len(args) < 3 { - errx("usage: honk ping (from username) (to username or url)\n") + errx("usage: honk ping (from username) (to username or url)") } name := args[1] targ := args[2] From 15572f2e218e0a411ee3bee487be05ef68e8ba00 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 16:26:33 -0400 Subject: [PATCH 31/50] better export/import. support markdown source now. --- import.go | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/import.go b/import.go index fc35ffe..dd0d3a3 100644 --- a/import.go +++ b/import.go @@ -51,6 +51,10 @@ type ActivityObject struct { AttributedTo string Summary string Content string + Source struct { + MediaType string + Content string + } InReplyTo string Conversation string Context string @@ -173,6 +177,12 @@ func importActivities(user *WhatAbout, filename, source string) { audience = append(audience, t.(string)) } } + content := toot.Object.Content + format := "html" + if toot.Object.Source.MediaType == "text/markdown" { + content = toot.Object.Source.Content + format = "markdown" + } audience = append(audience, toot.Cc...) honk := Honk{ UserID: user.ID, @@ -183,10 +193,10 @@ func importActivities(user *WhatAbout, filename, source string) { Date: toot.Object.Published, URL: xid, Audience: audience, - Noise: toot.Object.Content, + Noise: content, Convoy: convoy, Whofore: 2, - Format: "html", + Format: format, Precis: toot.Object.Summary, } if !loudandproud(honk.Audience) { @@ -198,7 +208,7 @@ func importActivities(user *WhatAbout, filename, source string) { fname := fmt.Sprintf("%s/%s", source, att.Url) data, err := ioutil.ReadFile(fname) if err != nil { - elog.Printf("error reading media: %s", fname) + elog.Printf("error reading media for %s: %s", honk.XID, fname) continue } u := xfiltrate() @@ -569,7 +579,7 @@ func export(username, file string) { { w, err := zd.Create("outbox.json") if err != nil { - elog.Fatal(err) + elog.Fatal("error creating outbox.json", err) } var jonks []junk.Junk rows, err := stmtUserHonks.Query(0, 3, user.Name, "0", 1234567) @@ -582,7 +592,10 @@ func export(username, file string) { noise := honk.Noise j, jo := jonkjonk(user, honk) if honk.Format == "markdown" { - jo["source"] = noise + source := junk.New() + source["mediaType"] = "text/markdown" + source["content"] = noise + jo["source"] = source } jonks = append(jonks, j) } @@ -598,7 +611,7 @@ func export(username, file string) { { w, err := zd.Create("inbox.json") if err != nil { - elog.Fatal(err) + elog.Fatal("error creating inbox.json", err) } var jonks []junk.Junk rows, err := stmtHonksForMe.Query(0, user.ID, "0", user.ID, 1234567) @@ -622,16 +635,21 @@ func export(username, file string) { } zd.Create("media/") for donk := range donks { + if donk == "" { + continue + } var media string var data []byte w, err := zd.Create("media/" + donk) if err != nil { - elog.Fatal(err) + elog.Printf("error creating %s: %s", donk, err) + continue } row := stmtGetFileData.QueryRow(donk) err = row.Scan(&media, &data) if err != nil { - elog.Fatal(err) + elog.Printf("error scanning file %s: %s", donk, err) + continue } w.Write(data) } From a6bc763507a2c6da9357329f26c6e647fc2609cf Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 17:41:56 -0400 Subject: [PATCH 32/50] negate operator for more queries --- database.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/database.go b/database.go index 6d7b5f6..e9cb3cb 100644 --- a/database.go +++ b/database.go @@ -307,11 +307,11 @@ func gethonksbysearch(userid int64, q string, wanted int64) []*Honk { continue } if t == "@me" { - queries = append(queries, "whofore = 1") + queries = append(queries, negate+"whofore = 1") continue } if t == "@self" { - queries = append(queries, "(whofore = 2 or whofore = 3)") + queries = append(queries, negate+"(whofore = 2 or whofore = 3)") continue } if strings.HasPrefix(t, "before:") { From 76da4515bc8fb93e2b1850f981d3ec9553783a6a Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 17:42:21 -0400 Subject: [PATCH 33/50] update webs --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b7d44e5..90cdf93 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( golang.org/x/crypto v0.12.0 golang.org/x/net v0.14.0 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 - humungus.tedunangst.com/r/webs v0.7.2 + humungus.tedunangst.com/r/webs v0.7.6 ) require ( diff --git a/go.sum b/go.sum index 2a48f61..e3ca8d3 100644 --- a/go.sum +++ b/go.sum @@ -48,5 +48,5 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= -humungus.tedunangst.com/r/webs v0.7.2 h1:WTBrDhoHXt0lKpvERn7TzcLB0KVRy0wYwscxjB4aD+E= -humungus.tedunangst.com/r/webs v0.7.2/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= +humungus.tedunangst.com/r/webs v0.7.6 h1:P+lve8d0zRp7Xlj4wN4LbVZ9umk5tQgej1su5856tr4= +humungus.tedunangst.com/r/webs v0.7.6/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= From 1a1c56200ca54a73b837ba7336c5193470c159a4 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 22:01:50 -0400 Subject: [PATCH 34/50] m and escape to open close menu. and set focus on actions after scroll. --- docs/honk.1 | 4 ++++ views/honkpage.js | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/docs/honk.1 b/docs/honk.1 index a98fa07..bd8a583 100644 --- a/docs/honk.1 +++ b/docs/honk.1 @@ -145,6 +145,10 @@ Scroll to previous honk. Refresh. .It s Scroll down to oldest newest. +.It m +Open menu. +.It esc +Close menu. .It / Search. .El diff --git a/views/honkpage.js b/views/honkpage.js index c3e3e63..99ce903 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -423,8 +423,10 @@ function scrollnexthonk() { var h = honks[i]; var b = h.getBoundingClientRect(); if (b.top > 1.0) { - h.scrollIntoView(); - break; + h.scrollIntoView() + var a = h.querySelector(".actions summary") + if (a) a.focus({ preventScroll: true }) + break } } } @@ -434,8 +436,10 @@ function scrollprevioushonk() { for (var i = 1; i < honks.length; i++) { var b = honks[i].getBoundingClientRect(); if (b.top > -1.0) { - honks[i-1].scrollIntoView(); - break; + honks[i-1].scrollIntoView() + var a = honks[i-1].querySelector(".actions summary") + if (a) a.focus({ preventScroll: true }) + break } } } @@ -459,6 +463,15 @@ function hotkey(e) { case "KeyK": scrollprevioushonk(); break; + case "KeyM": + var menu = document.getElementById("topmenu") + menu.open = true + menu.querySelector("a").focus() + break + case "Escape": + var menu = document.getElementById("topmenu") + menu.open = false + break case "Slash": document.getElementById("topmenu").open = true document.getElementById("searchbox").focus() From 7dc99cec9b70845a5b932fd90e2cdb33bb877a6b Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 28 Aug 2023 22:56:19 -0400 Subject: [PATCH 35/50] csp requires classes not styles --- go.mod | 2 +- go.sum | 4 ++-- views/about.html | 8 ++++---- views/style.css | 8 +++++++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 90cdf93..077f8c8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( golang.org/x/crypto v0.12.0 golang.org/x/net v0.14.0 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 - humungus.tedunangst.com/r/webs v0.7.6 + humungus.tedunangst.com/r/webs v0.7.7 ) require ( diff --git a/go.sum b/go.sum index e3ca8d3..9fba220 100644 --- a/go.sum +++ b/go.sum @@ -48,5 +48,5 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= -humungus.tedunangst.com/r/webs v0.7.6 h1:P+lve8d0zRp7Xlj4wN4LbVZ9umk5tQgej1su5856tr4= -humungus.tedunangst.com/r/webs v0.7.6/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= +humungus.tedunangst.com/r/webs v0.7.7 h1:1IITkwf5T3Zv2mG0rzmORPVcXuP/YGoTPeh6uBpUkCo= +humungus.tedunangst.com/r/webs v0.7.7/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= diff --git a/views/about.html b/views/about.html index 65bae2e..9c48090 100644 --- a/views/about.html +++ b/views/about.html @@ -5,10 +5,10 @@

    -
    version:{{ .HonkVersion }} -
    memory:{{ printf "%.02f" .Sensors.Memory }}MB -
    uptime:{{ printf "%.02f" .Sensors.Uptime }}s -
    cputime:{{ printf "%.02f" .Sensors.CPU }}s +
    version:{{ .HonkVersion }} +
    memory:{{ printf "%.02f" .Sensors.Memory }}MB +
    uptime:{{ printf "%.02f" .Sensors.Uptime }}s +
    cputime:{{ printf "%.02f" .Sensors.CPU }}s

    diff --git a/views/style.css b/views/style.css index cb2dae2..7c52719 100644 --- a/views/style.css +++ b/views/style.css @@ -389,9 +389,15 @@ li.details { display: none; } -.textright { +.text-left { + text-align: left; +} +.text-right { text-align: right; } +.text-center { + text-align: center; +} .font08em { font-size: 0.8em; From 8380a32139e2610b7495ff689dafa741615fb9f0 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Tue, 29 Aug 2023 00:18:14 -0400 Subject: [PATCH 36/50] big resigh. need to resign after redirect. --- activity.go | 36 ++++++++++++++++++------------------ main.go | 6 +++++- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/activity.go b/activity.go index c91b32c..2e8b997 100644 --- a/activity.go +++ b/activity.go @@ -59,12 +59,14 @@ func friendorfoe(ct string) bool { return false } -var develClient = &http.Client{ - Transport: &http.Transport{ +var honkClient = http.Client{} + +func gogglesDoNothing() { + honkClient.Transport = &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, - }, + } } func PostJunk(keyname string, key httpsig.PrivateKey, url string, j junk.Junk) error { @@ -72,10 +74,6 @@ func PostJunk(keyname string, key httpsig.PrivateKey, url string, j junk.Junk) e } func PostMsg(keyname string, key httpsig.PrivateKey, url string, msg []byte) error { - client := http.DefaultClient - if develMode { - client = develClient - } req, err := http.NewRequest("POST", url, bytes.NewReader(msg)) if err != nil { return err @@ -86,7 +84,7 @@ func PostMsg(keyname string, key httpsig.PrivateKey, url string, msg []byte) err ctx, cancel := context.WithTimeout(context.Background(), 2*slowTimeout*time.Second) defer cancel() req = req.WithContext(ctx) - resp, err := client.Do(req) + resp, err := honkClient.Do(req) if err != nil { return err } @@ -130,13 +128,10 @@ func GetJunkHardMode(userid int64, url string) (junk.Junk, error) { var flightdeck = gate.NewSerializer() -var signGets = true - func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, error) { if rejectorigin(userid, url, false) { return nil, fmt.Errorf("rejected origin: %s", url) } - client := http.DefaultClient sign := func(req *http.Request) error { var ki *KeyInfo ok := ziggies.Get(userid, &ki) @@ -146,9 +141,18 @@ func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, return nil } if develMode { - client = develClient sign = nil } + client := honkClient + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 5 { + return fmt.Errorf("stopped after 5 redirects") + } + if sign != nil { + sign(req) + } + return nil + } fn := func() (interface{}, error) { at := theonetruename if strings.Contains(url, ".well-known/webfinger?resource") { @@ -158,7 +162,7 @@ func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, Accept: at, Agent: "honksnonk/5.0; " + serverName, Timeout: timeout, - Client: client, + Client: &client, Fixup: sign, }) return j, err @@ -173,10 +177,6 @@ func GetJunkTimeout(userid int64, url string, timeout time.Duration) (junk.Junk, } func fetchsome(url string) ([]byte, error) { - client := http.DefaultClient - if develMode { - client = develClient - } req, err := http.NewRequest("GET", url, nil) if err != nil { ilog.Printf("error fetching %s: %s", url, err) @@ -186,7 +186,7 @@ func fetchsome(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() req = req.WithContext(ctx) - resp, err := client.Do(req) + resp, err := honkClient.Do(req) if err != nil { ilog.Printf("error fetching %s: %s", url, err) return nil, err diff --git a/main.go b/main.go index 620467f..b35e6bf 100644 --- a/main.go +++ b/main.go @@ -115,12 +115,16 @@ func main() { getconfig("usersep", &userSep) getconfig("honksep", &honkSep) getconfig("devel", &develMode) + if develMode { + gogglesDoNothing() + } getconfig("fasttimeout", &fastTimeout) getconfig("slowtimeout", &slowTimeout) getconfig("honkwindow", &honkwindow) honkwindow *= 24 * time.Hour - getconfig("signgets", &signGets) + prepareStatements(db) + switch cmd { case "admin": adminscreen() From 99aed03a36e3dd8ec6389ef84efe4b35bdaeefdf Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Wed, 30 Aug 2023 03:03:10 -0400 Subject: [PATCH 37/50] smooth scroll --- views/honkpage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/honkpage.js b/views/honkpage.js index 99ce903..3f29067 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -82,7 +82,7 @@ var lehonkbutton = document.getElementById("honkingtime") function oldestnewest(btn) { var els = document.getElementsByClassName("glow") if (els.length) { - els[els.length-1].scrollIntoView() + els[els.length-1].scrollIntoView({ behavior: "smooth" }) } } function removeglow() { From b60e2e61565839af034b1a0f5a0eb1b5b652098a Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Wed, 30 Aug 2023 19:12:12 -0400 Subject: [PATCH 38/50] don't leak

    into summary, seen by eta --- fun.go | 1 + go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fun.go b/fun.go index a71cf54..202c25e 100644 --- a/fun.go +++ b/fun.go @@ -330,6 +330,7 @@ func precipitate(honk *Honk) { noise = noise[idx+1:] } var marker mz.Marker + marker.Short = true honk.Precis = marker.Mark(strings.TrimSpace(honk.Precis)) honk.Noise = noise } diff --git a/go.mod b/go.mod index 077f8c8..96c2c56 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( golang.org/x/crypto v0.12.0 golang.org/x/net v0.14.0 humungus.tedunangst.com/r/go-sqlite3 v1.1.3 - humungus.tedunangst.com/r/webs v0.7.7 + humungus.tedunangst.com/r/webs v0.7.9 ) require ( diff --git a/go.sum b/go.sum index 9fba220..9625746 100644 --- a/go.sum +++ b/go.sum @@ -48,5 +48,5 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= humungus.tedunangst.com/r/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M= -humungus.tedunangst.com/r/webs v0.7.7 h1:1IITkwf5T3Zv2mG0rzmORPVcXuP/YGoTPeh6uBpUkCo= -humungus.tedunangst.com/r/webs v0.7.7/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= +humungus.tedunangst.com/r/webs v0.7.9 h1:LC9o2F9joAcf4SxWaRFs5ZqXHSbzdfre9/9BY0gcM0w= +humungus.tedunangst.com/r/webs v0.7.9/go.mod h1:ylhqHSPI0Oi7b4nsnx5mSO7AjLXN7wFpEHayLfN/ugk= From 0a66a0e13a5f1fa2c56e545a45f9429dd0b9528f Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 00:09:38 -0400 Subject: [PATCH 39/50] go fix --- unveil.go | 1 - 1 file changed, 1 deletion(-) diff --git a/unveil.go b/unveil.go index cbce333..6ede087 100644 --- a/unveil.go +++ b/unveil.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd // // Copyright (c) 2019 Ted Unangst From ae3843690fc64c66be5e675368ad935c96a6cc3e Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 02:48:07 -0400 Subject: [PATCH 40/50] this is web code --- util.go | 18 ------------------ web.go | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/util.go b/util.go index f709513..13508fd 100644 --- a/util.go +++ b/util.go @@ -36,10 +36,8 @@ import ( "bufio" "crypto/rand" "crypto/rsa" - "crypto/sha512" "database/sql" "fmt" - "io/ioutil" "net" "os" "os/signal" @@ -52,24 +50,8 @@ import ( "humungus.tedunangst.com/r/webs/login" ) -var savedassetparams = make(map[string]string) - var re_plainname = regexp.MustCompile("^[[:alnum:]_-]+$") -func getassetparam(file string) string { - if p, ok := savedassetparams[file]; ok { - return p - } - data, err := ioutil.ReadFile(file) - if err != nil { - return "" - } - hasher := sha512.New() - hasher.Write(data) - - return fmt.Sprintf("?v=%.8x", hasher.Sum(nil)) -} - var dbtimeformat = "2006-01-02 15:04:05" var alreadyopendb *sql.DB diff --git a/web.go b/web.go index 398cbde..4eec440 100644 --- a/web.go +++ b/web.go @@ -17,6 +17,7 @@ package main import ( "bytes" + "crypto/sha512" "database/sql" "fmt" "html/template" @@ -2692,6 +2693,22 @@ func emuinit() { }) } +var savedassetparams = make(map[string]string) + +func getassetparam(file string) string { + if p, ok := savedassetparams[file]; ok { + return p + } + data, err := os.ReadFile(file) + if err != nil { + return "" + } + hasher := sha512.New() + hasher.Write(data) + + return fmt.Sprintf("?v=%.8x", hasher.Sum(nil)) +} + func serve() { db := opendatabase() login.Init(login.InitArgs{Db: db, Logger: ilog, Insecure: develMode, SameSiteStrict: !develMode}) From 281570fe6b6d4f227c71827a9d01d9aea05792f9 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 02:57:49 -0400 Subject: [PATCH 41/50] backup code hasn't been well maintained --- backupdb.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backupdb.go b/backupdb.go index 10d1853..d95539e 100644 --- a/backupdb.go +++ b/backupdb.go @@ -35,6 +35,7 @@ func svalbard(dirname string) { if err != nil { elog.Fatalf("can't open backup database") } + _, err = backup.Exec("PRAGMA journal_mode=WAL") for _, line := range strings.Split(sqlSchema, ";") { _, err = backup.Exec(line) if err != nil { @@ -76,16 +77,16 @@ func svalbard(dirname string) { honkids := make(map[int64]bool) for c := range convoys { - rows = qordie(orig, "select honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags from honks where convoy = ?", c) + rows = qordie(orig, "select honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain from honks where convoy = ?", c) for rows.Next() { var honkid, userid int64 - var what, honker, xid, rid, dt, url, audience, noise, convoy string + var what, honker, xid, rid, dt, url, audience, noise, convoy, plain string var whofore int64 var format, precis, oonker string var flags int64 - scanordie(rows, &honkid, &userid, &what, &honker, &xid, &rid, &dt, &url, &audience, &noise, &convoy, &whofore, &format, &precis, &oonker, &flags) + scanordie(rows, &honkid, &userid, &what, &honker, &xid, &rid, &dt, &url, &audience, &noise, &convoy, &whofore, &format, &precis, &oonker, &flags, &plain) honkids[honkid] = true - doordie(tx, "insert into honks (honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags) + doordie(tx, "insert into honks (honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", honkid, userid, what, honker, xid, rid, dt, url, audience, noise, convoy, whofore, format, precis, oonker, flags, plain) } rows.Close() } @@ -169,6 +170,7 @@ func svalbard(dirname string) { if err != nil { elog.Fatalf("can't open backup blob database") } + _, err = blob.Exec("PRAGMA journal_mode=WAL") doordie(blob, "create table filedata (xid text, media text, hash text, content blob)") doordie(blob, "create index idx_filexid on filedata(xid)") doordie(blob, "create index idx_filehash on filedata(hash)") From 1a00ca5b43a81c9798f62a0e0115e0f2c2e56f9e Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 03:05:55 -0400 Subject: [PATCH 42/50] 1.1 notes --- docs/changelog.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index eb634f9..39c2b56 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,6 +1,10 @@ changelog -### next +### 1.1.0 Eventual Enshittification + ++ Fix backup command. + ++ Fixes for markdown. + Allow bigger image uploads. From 81bb8099aef709af88e700d469fbe1eb030664f1 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 03:09:59 -0400 Subject: [PATCH 43/50] fix help makefile target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 70756e5..56e2fa9 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ honk: .preflightcheck schema.sql *.go go.mod help: for m in docs/*.[13578] ; do \ - mandoc -T html -O fragment,man=%N.%S.html $$m | sed -E 's//
    /g' > $$m.html ; \ + mandoc -T html -O style=mandocs.css,man=%N.%S.html $$m | sed -E 's/
    /
    /g' > $$m.html ; \ done clean: From 90bef0b0b955dacbe9e7c41383c8e76784bef8a2 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 03:10:45 -0400 Subject: [PATCH 44/50] Added tag v1.1.0 for changeset 36c2a2746133 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 963d5f9..2801e8e 100644 --- a/.hgtags +++ b/.hgtags @@ -39,3 +39,4 @@ bc1bcfb9c0cc86b3c63325b07e13a36b9d4500f0 v0.9.7 4b8cf31560b7d1e1696af109b158766c4ce823ab v0.9.9 d7c3a01e7aaef67c40920bbc4e8507350fc33e31 v0.9.91 b1e7ac92a58a7183310b1a5cca8222d65f242d81 v1.0.0 +36c2a2746133f4b5b31103c0b4232554d2b15a5d v1.1.0 From 850ec873a83bd0531fa5b95c8da65697150bb891 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 16:40:14 -0400 Subject: [PATCH 45/50] fix the help stylesheet, from horia --- Makefile | 2 +- docs/changelog.txt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 56e2fa9..f382c8a 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ honk: .preflightcheck schema.sql *.go go.mod help: for m in docs/*.[13578] ; do \ - mandoc -T html -O style=mandocs.css,man=%N.%S.html $$m | sed -E 's/
    /
    /g' > $$m.html ; \ + mandoc -T html -O style=mandoc.css,man=%N.%S.html $$m | sed -E 's/
    /
    /g' > $$m.html ; \ done clean: diff --git a/docs/changelog.txt b/docs/changelog.txt index 39c2b56..d7d745a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,5 +1,9 @@ changelog +### 1.1.1 Required Refinement + ++ Fix help file stylesheet link. + ### 1.1.0 Eventual Enshittification + Fix backup command. From 82c7e22193d407850f641c9ee78fa40cf890f412 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Thu, 31 Aug 2023 16:40:18 -0400 Subject: [PATCH 46/50] Added tag v1.1.1 for changeset 135cdbfa6d7d --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 2801e8e..3f4055d 100644 --- a/.hgtags +++ b/.hgtags @@ -40,3 +40,4 @@ bc1bcfb9c0cc86b3c63325b07e13a36b9d4500f0 v0.9.7 d7c3a01e7aaef67c40920bbc4e8507350fc33e31 v0.9.91 b1e7ac92a58a7183310b1a5cca8222d65f242d81 v1.0.0 36c2a2746133f4b5b31103c0b4232554d2b15a5d v1.1.0 +135cdbfa6d7d1a9b1b436cb57d9837a943d83227 v1.1.1 From c750122b7fee8cabb94e8f0b18a896dd7f62fc21 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 11 Sep 2023 18:52:21 -0400 Subject: [PATCH 47/50] need to cache front page internally to avoid herding --- web.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/web.go b/web.go index 4eec440..c83a001 100644 --- a/web.go +++ b/web.go @@ -38,6 +38,7 @@ import ( "github.com/gorilla/mux" "humungus.tedunangst.com/r/webs/cache" + "humungus.tedunangst.com/r/webs/gencache" "humungus.tedunangst.com/r/webs/httpsig" "humungus.tedunangst.com/r/webs/junk" "humungus.tedunangst.com/r/webs/login" @@ -88,6 +89,9 @@ func getInfo(r *http.Request) map[string]interface{} { templinfo["ServerName"] = serverName templinfo["IconName"] = iconName templinfo["UserSep"] = userSep + if r == nil { + return templinfo + } if u := login.GetUserInfo(r); u != nil { templinfo["UserInfo"], _ = butwhatabout(u.Username) templinfo["UserStyle"] = getuserstyle(u) @@ -98,9 +102,50 @@ func getInfo(r *http.Request) map[string]interface{} { return templinfo } +var oldnews = gencache.New(gencache.Options[string, []byte]{ + Fill: func(url string) ([]byte, bool) { + templinfo := getInfo(nil) + var honks []*Honk + var userid int64 = -1 + + templinfo["ServerMessage"] = serverMsg + switch url { + case "/events": + honks = geteventhonks(userid) + templinfo["ServerMessage"] = "some recent and upcoming events" + default: + templinfo["ShowRSS"] = true + honks = getpublichonks() + } + reverbolate(userid, honks) + templinfo["Honks"] = honks + templinfo["MapLink"] = getmaplink(nil) + var buf bytes.Buffer + err := readviews.Execute(&buf, "honkpage.html", templinfo) + if err != nil { + elog.Print(err) + } + return buf.Bytes(), true + + }, + Duration: 1 * time.Minute, +}) + +func lonelypage(w http.ResponseWriter, r *http.Request) { + page, _ := oldnews.Get(r.URL.Path) + if !develMode { + w.Header().Set("Cache-Control", "max-age=60") + } + w.Write(page) +} + func homepage(w http.ResponseWriter, r *http.Request) { - templinfo := getInfo(r) u := login.GetUserInfo(r) + if u == nil { + lonelypage(w, r) + return + } + templinfo := getInfo(r) var honks []*Honk var userid int64 = -1 @@ -1199,10 +1244,13 @@ func showonehonk(w http.ResponseWriter, r *http.Request) { //reversehonks(rawhonks) rawhonks = threadsort(rawhonks) var honks []*Honk - for _, h := range rawhonks { + for i, h := range rawhonks { if h.XID == xid { templinfo["Honkology"] = honkology(h) - if len(honks) != 0 { + if i > 0 { + top := new(Honk) + *top = *h + honks = append([]*Honk{top}, honks...) h.Style += " glow" } } From dbbd4468fae665dcd819df489d13c8480a539038 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 11 Sep 2023 18:54:05 -0400 Subject: [PATCH 48/50] don't think i want to duplicate honks in threads yet --- web.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/web.go b/web.go index c83a001..2f40d26 100644 --- a/web.go +++ b/web.go @@ -1248,9 +1248,6 @@ func showonehonk(w http.ResponseWriter, r *http.Request) { if h.XID == xid { templinfo["Honkology"] = honkology(h) if i > 0 { - top := new(Honk) - *top = *h - honks = append([]*Honk{top}, honks...) h.Style += " glow" } } From 386dc6f79869c72813ea75235c42ba7ff22376e8 Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Mon, 11 Sep 2023 21:34:05 -0400 Subject: [PATCH 49/50] fix slow public queries with a special index just for you --- docs/changelog.txt | 4 ++++ schema.sql | 1 + upgradedb.go | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index d7d745a..987b4b2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,5 +1,9 @@ changelog +### next + ++ Finally fix slow public queries. + ### 1.1.1 Required Refinement + Fix help file stylesheet link. diff --git a/schema.sql b/schema.sql index 1ce0071..6816987 100644 --- a/schema.sql +++ b/schema.sql @@ -15,6 +15,7 @@ create index idx_honksxid on honks(xid); create index idx_honksconvoy on honks(convoy); create index idx_honkshonker on honks(honker); create index idx_honksoonker on honks(oonker); +create index idx_honkswhotwo on honks(whofore) where whofore = 2; create index idx_donkshonk on donks(honkid); create index idx_donkschonk on donks(chonkid); create index idx_honkerxid on honkers(xid); diff --git a/upgradedb.go b/upgradedb.go index c15bb84..62f9d08 100644 --- a/upgradedb.go +++ b/upgradedb.go @@ -23,7 +23,7 @@ import ( "humungus.tedunangst.com/r/webs/htfilter" ) -var myVersion = 45 +var myVersion = 46 // idx whotwo type dbexecer interface { Exec(query string, args ...interface{}) (sql.Result, error) @@ -172,6 +172,10 @@ func upgradedb() { tx = nil fallthrough case 45: + try("create index idx_honkswhotwo on honks(whofore) where whofore = 2") + setV(46) + fallthrough + case 46: try("analyze") default: From 58ecc76b901fa879b107cbb2b0b82d1bf0a8b7af Mon Sep 17 00:00:00 2001 From: Ted Unangst Date: Wed, 13 Sep 2023 21:00:53 -0400 Subject: [PATCH 50/50] toggle menu --- views/honkpage.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/views/honkpage.js b/views/honkpage.js index 3f29067..8270149 100644 --- a/views/honkpage.js +++ b/views/honkpage.js @@ -465,8 +465,12 @@ function hotkey(e) { break; case "KeyM": var menu = document.getElementById("topmenu") - menu.open = true - menu.querySelector("a").focus() + if (!menu.open) { + menu.open = true + menu.querySelector("a").focus() + } else { + menu.open = false + } break case "Escape": var menu = document.getElementById("topmenu")