Compare commits

..

2 commits

Author SHA1 Message Date
3b3ebe2dae
Update dockerfiles 2023-05-04 12:08:38 +02:00
eb2766370a
Add docker files
Build: docker build
2023-05-04 12:08:38 +02:00
19 changed files with 182 additions and 554 deletions

View file

@ -25,6 +25,7 @@ import (
"io" "io"
notrand "math/rand" notrand "math/rand"
"net/http" "net/http"
"net/url"
"os" "os"
"regexp" "regexp"
"strings" "strings"
@ -165,11 +166,7 @@ func junkGet(userid int64, url string, args junk.GetArgs) (junk.Junk, error) {
} }
defer resp.Body.Close() defer resp.Body.Close()
switch resp.StatusCode { if resp.StatusCode != 200 {
case 200:
case 201:
case 202:
default:
return nil, fmt.Errorf("http get status: %d", resp.StatusCode) return nil, fmt.Errorf("http get status: %d", resp.StatusCode)
} }
return junk.Read(resp.Body) return junk.Read(resp.Body)
@ -511,13 +508,36 @@ func firstofmany(obj junk.Junk, key string) string {
} }
var re_mast0link = regexp.MustCompile(`https://[[:alnum:].]+/users/[[:alnum:]]+/statuses/[[:digit:]]+`) var re_mast0link = regexp.MustCompile(`https://[[:alnum:].]+/users/[[:alnum:]]+/statuses/[[:digit:]]+`)
var re_masto1ink = regexp.MustCompile(`https://([[:alnum:].]+)/@([[:alnum:]]+)/([[:digit:]]+)`) var re_masto1ink = regexp.MustCompile(`https://[[:alnum:].]+/@[[:alnum:]]+/[[:digit:]]+`)
var re_misslink = regexp.MustCompile(`https://[[:alnum:].]+/notes/[[:alnum:]]+`) var re_misslink = regexp.MustCompile(`https://[[:alnum:].]+/notes/[[:alnum:]]+`)
var re_honklink = regexp.MustCompile(`https://[[:alnum:].]+/u/[[:alnum:]]+/h/[[:alnum:]]+`) var re_honklink = regexp.MustCompile(`https://[[:alnum:].]+/u/[[:alnum:]]+/h/[[:alnum:]]+`)
var re_r0malink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`) var re_r0malink = regexp.MustCompile(`https://[[:alnum:].]+/objects/[[:alnum:]-]+`)
var re_roma1ink = regexp.MustCompile(`https://[[:alnum:].]+/notice/[[:alnum:]]+`) var re_roma1ink = regexp.MustCompile(`https://[[:alnum:].]+/notice/[[:alnum:]]+`)
var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`) var re_qtlinks = regexp.MustCompile(`>https://[^\s<]+<`)
func qutify(user *WhatAbout, content string) string {
// well this is gross
malcontent := strings.ReplaceAll(content, `</span><span class="ellipsis">`, "")
malcontent = strings.ReplaceAll(malcontent, `</span><span class="invisible">`, "")
mlinks := re_qtlinks.FindAllString(malcontent, -1)
for _, m := range mlinks {
m = m[1 : len(m)-1]
if re_mast0link.MatchString(m) || re_masto1ink.MatchString(m) ||
re_misslink.MatchString(m) ||
re_honklink.MatchString(m) ||
re_r0malink.MatchString(m) || re_roma1ink.MatchString(m) {
j, err := GetJunk(user.ID, m)
if err == nil {
q, ok := j.GetString("content")
if ok {
content = fmt.Sprintf("%s<blockquote>%s</blockquote>", content, q)
}
}
}
}
return content
}
func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk { func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
depth := 0 depth := 0
maxdepth := 10 maxdepth := 10
@ -525,44 +545,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
goingup := 0 goingup := 0
var xonkxonkfn func(item junk.Junk, origin string, isUpdate bool) *Honk var xonkxonkfn func(item junk.Junk, origin string, isUpdate bool) *Honk
qutify := func(user *WhatAbout, content string) string {
if depth >= maxdepth {
ilog.Printf("in too deep")
return content
}
// well this is gross
malcontent := strings.ReplaceAll(content, `</span><span class="ellipsis">`, "")
malcontent = strings.ReplaceAll(malcontent, `</span><span class="invisible">`, "")
mlinks := re_qtlinks.FindAllString(malcontent, -1)
for _, m := range mlinks {
tryit := false
m = m[1 : len(m)-1]
if re_mast0link.MatchString(m) || re_misslink.MatchString(m) ||
re_honklink.MatchString(m) || re_r0malink.MatchString(m) ||
re_roma1ink.MatchString(m) {
tryit = true
} else if re_masto1ink.MatchString(m) {
m = re_masto1ink.ReplaceAllString(m, "https://$1/users/$2/statuses/$3")
tryit = true
}
if tryit {
if x := getxonk(user.ID, m); x != nil {
content = fmt.Sprintf("%s<blockquote>%s</blockquote>", content, x.Noise)
} else if j, err := GetJunk(user.ID, m); err == nil {
q, ok := j.GetString("content")
if ok {
content = fmt.Sprintf("%s<blockquote>%s</blockquote>", content, q)
}
prevdepth := depth
depth = maxdepth
xonkxonkfn(j, originate(m), false)
depth = prevdepth
}
}
}
return content
}
saveonemore := func(xid string) { saveonemore := func(xid string) {
dlog.Printf("getting onemore: %s", xid) dlog.Printf("getting onemore: %s", xid)
if depth >= maxdepth { if depth >= maxdepth {
@ -631,14 +613,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Announce": case "Announce":
obj, ok = item.GetMap("object") obj, ok = item.GetMap("object")
if ok { if ok {
what, ok := obj.GetString("type")
if ok && what == "Create" {
obj, ok = obj.GetMap("object")
if !ok {
ilog.Printf("lost object inside create %s", id)
return nil
}
}
xid, _ = obj.GetString("id") xid, _ = obj.GetString("id")
} else { } else {
xid, _ = item.GetString("object") xid, _ = item.GetString("object")
@ -646,16 +620,12 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
if !needbonkid(user, xid) { if !needbonkid(user, xid) {
return nil return nil
} }
origin = originate(xid) dlog.Printf("getting bonk: %s", xid)
if ok && originate(id) == origin { obj, err = GetJunkHardMode(user.ID, xid)
dlog.Printf("using object in announce for %s", xid) if err != nil {
} else { ilog.Printf("error getting bonk: %s: %s", xid, err)
dlog.Printf("getting bonk: %s", xid)
obj, err = GetJunkHardMode(user.ID, xid)
if err != nil {
ilog.Printf("error getting bonk: %s: %s", xid, err)
}
} }
origin = originate(xid)
what = "bonk" what = "bonk"
case "Update": case "Update":
isUpdate = true isUpdate = true
@ -719,9 +689,7 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
case "Audio": case "Audio":
fallthrough fallthrough
case "Image": case "Image":
if what == "Image" { preferorig = true
preferorig = true
}
fallthrough fallthrough
case "Video": case "Video":
fallthrough fallthrough
@ -869,9 +837,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
procatt := func(att junk.Junk) { procatt := func(att junk.Junk) {
at, _ := att.GetString("type") at, _ := att.GetString("type")
mt, _ := att.GetString("mediaType") mt, _ := att.GetString("mediaType")
if mt == "" {
mt = "image"
}
u, ok := att.GetString("url") u, ok := att.GetString("url")
if !ok { if !ok {
u, ok = att.GetString("href") u, ok = att.GetString("href")
@ -901,24 +866,14 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
desc = name desc = name
} }
localize := false localize := false
if at == "Document" || at == "Image" { if numatts > 4 {
ilog.Printf("excessive attachment: %s", at)
} else if at == "Document" || at == "Image" || (preferorig && at == "Link") {
mt = strings.ToLower(mt) mt = strings.ToLower(mt)
dlog.Printf("attachment: %s %s", mt, u) dlog.Printf("attachment: %s %s", mt, u)
if mt == "text/plain" || mt == "application/pdf" || if mt == "text/plain" || mt == "application/pdf" ||
strings.HasPrefix(mt, "image") { strings.HasPrefix(mt, "image") {
if numatts > 4 { localize = true
ilog.Printf("excessive attachment: %s", at)
} else {
localize = true
}
}
} else if at == "Link" {
if waspage {
xonk.Noise += fmt.Sprintf(`<p><a href="%s">%s</a>`, u, u)
return
}
if name == "" {
name = u
} }
} else { } else {
ilog.Printf("unknown attachment: %s", at) ilog.Printf("unknown attachment: %s", at)
@ -935,9 +890,6 @@ func xonksaver(user *WhatAbout, item junk.Junk, origin string) *Honk {
} }
numatts++ numatts++
} }
if img, ok := obj.GetMap("image"); ok {
procatt(img)
}
if preferorig { if preferorig {
atts, _ := obj.GetArray("url") atts, _ := obj.GetArray("url")
for _, atti := range atts { for _, atti := range atts {
@ -1167,7 +1119,7 @@ func rubadubdub(user *WhatAbout, req junk.Junk) {
j["published"] = time.Now().UTC().Format(time.RFC3339) j["published"] = time.Now().UTC().Format(time.RFC3339)
j["object"] = req j["object"] = req
deliverate(user.ID, actor, j.ToBytes()) deliverate(0, user.ID, actor, j.ToBytes(), true)
} }
func itakeitallback(user *WhatAbout, xid string, owner string, folxid string) { func itakeitallback(user *WhatAbout, xid string, owner string, folxid string) {
@ -1186,7 +1138,7 @@ func itakeitallback(user *WhatAbout, xid string, owner string, folxid string) {
j["object"] = f j["object"] = f
j["published"] = time.Now().UTC().Format(time.RFC3339) j["published"] = time.Now().UTC().Format(time.RFC3339)
deliverate(user.ID, owner, j.ToBytes()) deliverate(0, user.ID, owner, j.ToBytes(), true)
} }
func subsub(user *WhatAbout, xid string, owner string, folxid string) { func subsub(user *WhatAbout, xid string, owner string, folxid string) {
@ -1203,7 +1155,7 @@ func subsub(user *WhatAbout, xid string, owner string, folxid string) {
j["object"] = xid j["object"] = xid
j["published"] = time.Now().UTC().Format(time.RFC3339) j["published"] = time.Now().UTC().Format(time.RFC3339)
deliverate(user.ID, owner, j.ToBytes()) deliverate(0, user.ID, owner, j.ToBytes(), true)
} }
func activatedonks(donks []*Donk) []junk.Junk { func activatedonks(donks []*Donk) []junk.Junk {
@ -1513,7 +1465,7 @@ func sendchonk(user *WhatAbout, ch *Chonk) {
rcpts := make(map[string]bool) rcpts := make(map[string]bool)
rcpts[ch.Target] = true rcpts[ch.Target] = true
for a := range rcpts { for a := range rcpts {
go deliverate(user.ID, a, msg) go deliverate(0, user.ID, a, msg, true)
} }
} }
@ -1552,13 +1504,25 @@ func honkworldwide(user *WhatAbout, honk *Honk) {
} }
} }
for a := range rcpts { for a := range rcpts {
go deliverate(user.ID, a, msg) go deliverate(0, user.ID, a, msg, doesitmatter(honk.What))
} }
if honk.Public && len(honk.Onts) > 0 { if honk.Public && len(honk.Onts) > 0 {
collectiveaction(honk) collectiveaction(honk)
} }
} }
func doesitmatter(what string) bool {
switch what {
case "ack":
return false
case "react":
return false
case "deack":
return false
}
return true
}
func collectiveaction(honk *Honk) { func collectiveaction(honk *Honk) {
user := getserveruser() user := getserveruser()
for _, ont := range honk.Onts { for _, ont := range honk.Onts {
@ -1585,7 +1549,7 @@ func collectiveaction(honk *Honk) {
} }
msg := j.ToBytes() msg := j.ToBytes()
for a := range rcpts { for a := range rcpts {
go deliverate(user.ID, a, msg) go deliverate(0, user.ID, a, msg, false)
} }
} }
} }
@ -1620,7 +1584,12 @@ func junkuser(user *WhatAbout) junk.Junk {
a := junk.New() a := junk.New()
a["type"] = "Image" a["type"] = "Image"
a["mediaType"] = "image/png" a["mediaType"] = "image/png"
a["url"] = avatarURL(user) if ava := user.Options.Avatar; ava != "" {
a["url"] = ava
} else {
u := fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL))
a["url"] = u
}
j["icon"] = a j["icon"] = a
if ban := user.Options.Banner; ban != "" { if ban := user.Options.Banner; ban != "" {
a := junk.New() a := junk.New()
@ -1646,8 +1615,10 @@ var oldjonkers = cache.New(cache.Options{Filler: func(name string) ([]byte, bool
if err != nil { if err != nil {
return nil, false return nil, false
} }
var buf bytes.Buffer
j := junkuser(user) j := junkuser(user)
return j.ToBytes(), true j.Write(&buf)
return buf.Bytes(), true
}, Duration: 1 * time.Minute}) }, Duration: 1 * time.Minute})
func asjonker(name string) ([]byte, bool) { func asjonker(name string) ([]byte, bool) {
@ -1725,12 +1696,9 @@ func investigate(name string) (*SomeThing, error) {
func somethingabout(obj junk.Junk) (*SomeThing, error) { func somethingabout(obj junk.Junk) (*SomeThing, error) {
info := new(SomeThing) info := new(SomeThing)
t, _ := obj.GetString("type") t, _ := obj.GetString("type")
isowned := false
switch t { switch t {
case "Person": case "Person":
fallthrough fallthrough
case "Group":
fallthrough
case "Organization": case "Organization":
fallthrough fallthrough
case "Application": case "Application":
@ -1738,7 +1706,6 @@ func somethingabout(obj junk.Junk) (*SomeThing, error) {
case "Service": case "Service":
info.What = SomeActor info.What = SomeActor
case "OrderedCollection": case "OrderedCollection":
isowned = true
fallthrough fallthrough
case "Collection": case "Collection":
info.What = SomeCollection info.What = SomeCollection
@ -1750,9 +1717,7 @@ func somethingabout(obj junk.Junk) (*SomeThing, error) {
if info.Name == "" { if info.Name == "" {
info.Name, _ = obj.GetString("name") info.Name, _ = obj.GetString("name")
} }
if isowned { info.Owner, _ = obj.GetString("attributedTo")
info.Owner, _ = obj.GetString("attributedTo")
}
if info.Owner == "" { if info.Owner == "" {
info.Owner = info.XID info.Owner = info.XID
} }
@ -1892,7 +1857,7 @@ func updateMe(username string) {
} }
} }
for a := range rcpts { for a := range rcpts {
go deliverate(user.ID, a, msg) go deliverate(0, user.ID, a, msg, false)
} }
} }

View file

@ -125,7 +125,7 @@ func adminscreen() {
} }
defer restore() defer restore()
go func() { go func() {
sig := make(chan os.Signal, 1) sig := make(chan os.Signal)
signal.Notify(sig, os.Interrupt) signal.Notify(sig, os.Interrupt)
<-sig <-sig
restore() restore()

View file

@ -23,7 +23,6 @@ import (
"image" "image"
"image/png" "image/png"
"net/http" "net/http"
"net/url"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -104,13 +103,6 @@ func genAvatar(name string) []byte {
return buf.Bytes() return buf.Bytes()
} }
func avatarURL(user *WhatAbout) string {
if ava := user.Options.Avatar; ava != "" {
return ava
}
return fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL))
}
func showflag(writer http.ResponseWriter, req *http.Request) { func showflag(writer http.ResponseWriter, req *http.Request) {
code := mux.Vars(req)["code"] code := mux.Vars(req)["code"]
colors := strings.Split(code, ",") colors := strings.Split(code, ",")

View file

@ -23,10 +23,7 @@ import (
"net/rpc" "net/rpc"
"os" "os"
"os/exec" "os/exec"
"os/signal"
"strings" "strings"
"sync"
"syscall"
"humungus.tedunangst.com/r/webs/gate" "humungus.tedunangst.com/r/webs/gate"
"humungus.tedunangst.com/r/webs/image" "humungus.tedunangst.com/r/webs/image"
@ -115,7 +112,6 @@ func orphancheck() {
func backendServer() { func backendServer() {
dlog.Printf("backend server running") dlog.Printf("backend server running")
go orphancheck() go orphancheck()
signal.Ignore(syscall.SIGINT)
shrinker := new(Shrinker) shrinker := new(Shrinker)
srv := rpc.NewServer() srv := rpc.NewServer()
err := srv.Register(shrinker) err := srv.Register(shrinker)
@ -156,23 +152,9 @@ func runBackendServer() {
if err != nil { if err != nil {
elog.Panicf("can't exec backend: %s", err) elog.Panicf("can't exec backend: %s", err)
} }
workinprogress++
var mtx sync.Mutex
go func() {
<-endoftheworld
mtx.Lock()
defer mtx.Unlock()
w.Close()
w = nil
readyalready <- true
}()
go func() { go func() {
proc.Wait() proc.Wait()
mtx.Lock() elog.Printf("lost the backend: %s", err)
defer mtx.Unlock() w.Close()
if w != nil {
elog.Printf("lost the backend: %s", err)
w.Close()
}
}() }()
} }

View file

@ -303,26 +303,6 @@ func gethonksbysearch(userid int64, q string, wanted int64) []*Honk {
if t == "" { if t == "" {
continue continue
} }
if t == "@me" {
queries = append(queries, "whofore = 1")
continue
}
if t == "@self" {
queries = append(queries, "(whofore = 2 or whofore = 3)")
continue
}
if strings.HasPrefix(t, "before:") {
before := t[7:]
queries = append(queries, "dt < ?")
params = append(params, before)
continue
}
if strings.HasPrefix(t, "after:") {
after := t[6:]
queries = append(queries, "dt > ?")
params = append(params, after)
continue
}
if strings.HasPrefix(t, "site:") { if strings.HasPrefix(t, "site:") {
site := t[5:] site := t[5:]
site = "%" + site + "%" site = "%" + site + "%"
@ -1126,7 +1106,6 @@ var stmtSaveMeta, stmtDeleteAllMeta, stmtDeleteOneMeta, stmtDeleteSomeMeta, stmt
var stmtHonksISaved, stmtGetFilters, stmtSaveFilter, stmtDeleteFilter *sql.Stmt var stmtHonksISaved, stmtGetFilters, stmtSaveFilter, stmtDeleteFilter *sql.Stmt
var stmtGetTracks *sql.Stmt var stmtGetTracks *sql.Stmt
var stmtSaveChonk, stmtLoadChonks, stmtGetChatters *sql.Stmt var stmtSaveChonk, stmtLoadChonks, stmtGetChatters *sql.Stmt
var stmtDeliquentCheck, stmtDeliquentUpdate *sql.Stmt
func preparetodie(db *sql.DB, s string) *sql.Stmt { func preparetodie(db *sql.DB, s string) *sql.Stmt {
stmt, err := db.Prepare(s) stmt, err := db.Prepare(s)
@ -1213,6 +1192,4 @@ func prepareStatements(db *sql.DB) {
stmtSaveChonk = preparetodie(db, "insert into chonks (userid, xid, who, target, dt, noise, format) values (?, ?, ?, ?, ?, ?, ?)") stmtSaveChonk = preparetodie(db, "insert into chonks (userid, xid, who, target, dt, noise, format) values (?, ?, ?, ?, ?, ?, ?)")
stmtLoadChonks = preparetodie(db, "select chonkid, userid, xid, who, target, dt, noise, format from chonks where userid = ? and dt > ? order by chonkid asc") stmtLoadChonks = preparetodie(db, "select chonkid, userid, xid, who, target, dt, noise, format from chonks where userid = ? and dt > ? order by chonkid asc")
stmtGetChatters = preparetodie(db, "select distinct(target) from chonks where userid = ?") stmtGetChatters = preparetodie(db, "select distinct(target) from chonks where userid = ?")
stmtDeliquentCheck = preparetodie(db, "select dooverid, msg from doovers where userid = ? and rcpt = ?")
stmtDeliquentUpdate = preparetodie(db, "update doovers set msg = ? where dooverid = ?")
} }

View file

@ -16,42 +16,39 @@
package main package main
import ( import (
"bytes" "fmt"
"database/sql"
notrand "math/rand" notrand "math/rand"
"strings"
"sync"
"time" "time"
"humungus.tedunangst.com/r/webs/gate" "humungus.tedunangst.com/r/webs/gate"
) )
type Doover struct { type Doover struct {
ID int64 ID int64
When time.Time When time.Time
Userid int64
Tries int64
Rcpt string
Msgs [][]byte
} }
func sayitagain(doover Doover) { func sayitagain(goarounds int64, userid int64, rcpt string, msg []byte) {
doover.Tries += 1
var drift time.Duration var drift time.Duration
if doover.Tries <= 3 { // 5, 10, 15 minutes switch goarounds {
drift = time.Duration(doover.Tries*5) * time.Minute case 1:
} else if doover.Tries <= 6 { // 1, 2, 3 hours drift = 5 * time.Minute
drift = time.Duration(doover.Tries-3) * time.Hour case 2:
} else if doover.Tries <= 9 { // 12, 12, 12 hours drift = 1 * time.Hour
drift = time.Duration(12) * time.Hour case 3:
} else { drift = 4 * time.Hour
ilog.Printf("he's dead jim: %s", doover.Rcpt) case 4:
drift = 12 * time.Hour
case 5:
drift = 24 * time.Hour
default:
ilog.Printf("he's dead jim: %s", rcpt)
clearoutbound(rcpt)
return return
} }
drift += time.Duration(notrand.Int63n(int64(drift / 10))) drift += time.Duration(notrand.Int63n(int64(drift / 10)))
when := time.Now().Add(drift) when := time.Now().Add(drift)
data := bytes.Join(doover.Msgs, []byte{0}) _, err := stmtAddDoover.Exec(when.UTC().Format(dbtimeformat), goarounds, userid, rcpt, msg)
_, err := stmtAddDoover.Exec(when.UTC().Format(dbtimeformat), doover.Tries, doover.Userid, doover.Rcpt, data)
if err != nil { if err != nil {
elog.Printf("error saving doover: %s", err) elog.Printf("error saving doover: %s", err)
} }
@ -61,66 +58,30 @@ func sayitagain(doover Doover) {
} }
} }
func lethaldose(err error) int64 { func clearoutbound(rcpt string) {
str := err.Error() hostname := originate(rcpt)
if strings.Contains(str, "no such host") { if hostname == "" {
return 8
}
return 0
}
var dqmtx sync.Mutex
func delinquent(userid int64, rcpt string, msg []byte) bool {
dqmtx.Lock()
defer dqmtx.Unlock()
row := stmtDeliquentCheck.QueryRow(userid, rcpt)
var dooverid int64
var data []byte
err := row.Scan(&dooverid, &data)
if err == sql.ErrNoRows {
return false
}
if err != nil {
elog.Printf("error scanning deliquent check: %s", err)
return true
}
data = append(data, 0)
data = append(data, msg...)
_, err = stmtDeliquentUpdate.Exec(data, dooverid)
if err != nil {
elog.Printf("error updating deliquent: %s", err)
return true
}
return true
}
func deliverate(userid int64, rcpt string, msg []byte) {
if delinquent(userid, rcpt, msg) {
return return
} }
var d Doover xid := fmt.Sprintf("%%https://%s/%%", hostname)
d.Userid = userid ilog.Printf("clearing outbound for %s", xid)
d.Tries = 0 db := opendatabase()
d.Rcpt = rcpt db.Exec("delete from doovers where rcpt like ?", xid)
d.Msgs = append(d.Msgs, msg)
deliveration(d)
} }
var garage = gate.NewLimiter(40) var garage = gate.NewLimiter(40)
func deliveration(doover Doover) { func deliverate(goarounds int64, userid int64, rcpt string, msg []byte, prio bool) {
garage.Start() garage.Start()
defer garage.Finish() defer garage.Finish()
var ki *KeyInfo var ki *KeyInfo
ok := ziggies.Get(doover.Userid, &ki) ok := ziggies.Get(userid, &ki)
if !ok { if !ok {
elog.Printf("lost key for delivery") elog.Printf("lost key for delivery")
return return
} }
var inbox string var inbox string
rcpt := doover.Rcpt
// already did the box indirection // already did the box indirection
if rcpt[0] == '%' { if rcpt[0] == '%' {
inbox = rcpt[1:] inbox = rcpt[1:]
@ -129,25 +90,18 @@ func deliveration(doover Doover) {
ok := boxofboxes.Get(rcpt, &box) ok := boxofboxes.Get(rcpt, &box)
if !ok { if !ok {
ilog.Printf("failed getting inbox for %s", rcpt) ilog.Printf("failed getting inbox for %s", rcpt)
sayitagain(doover) sayitagain(goarounds+1, userid, rcpt, msg)
return return
} }
inbox = box.In inbox = box.In
} }
for i, msg := range doover.Msgs { err := PostMsg(ki.keyname, ki.seckey, inbox, msg)
if i > 0 { if err != nil {
time.Sleep(2 * time.Second) ilog.Printf("failed to post json to %s: %s", inbox, err)
} if prio {
err := PostMsg(ki.keyname, ki.seckey, inbox, msg) sayitagain(goarounds+1, userid, rcpt, msg)
if err != nil {
ilog.Printf("failed to post json to %s: %s", inbox, err)
if t := lethaldose(err); t > doover.Tries {
doover.Tries = t
}
doover.Msgs = doover.Msgs[i:]
sayitagain(doover)
return
} }
return
} }
} }
@ -176,23 +130,6 @@ func getdoovers() []Doover {
return doovers return doovers
} }
func extractdoover(d *Doover) error {
dqmtx.Lock()
defer dqmtx.Unlock()
row := stmtLoadDoover.QueryRow(d.ID)
var data []byte
err := row.Scan(&d.Tries, &d.Userid, &d.Rcpt, &data)
if err != nil {
return err
}
_, err = stmtZapDoover.Exec(d.ID)
if err != nil {
return err
}
d.Msgs = bytes.Split(data, []byte{0})
return nil
}
func redeliverator() { func redeliverator() {
sleeper := time.NewTimer(5 * time.Second) sleeper := time.NewTimer(5 * time.Second)
for { for {
@ -211,13 +148,22 @@ func redeliverator() {
nexttime := now.Add(24 * time.Hour) nexttime := now.Add(24 * time.Hour)
for _, d := range doovers { for _, d := range doovers {
if d.When.Before(now) { if d.When.Before(now) {
err := extractdoover(&d) var goarounds, userid int64
var rcpt string
var msg []byte
row := stmtLoadDoover.QueryRow(d.ID)
err := row.Scan(&goarounds, &userid, &rcpt, &msg)
if err != nil { if err != nil {
elog.Printf("error extracting doover: %s", err) elog.Printf("error scanning doover: %s", err)
continue continue
} }
ilog.Printf("redeliverating %s try %d", d.Rcpt, d.Tries) _, err = stmtZapDoover.Exec(d.ID)
deliveration(d) if err != nil {
elog.Printf("error deleting doover: %s", err)
continue
}
ilog.Printf("redeliverating %s try %d", rcpt, goarounds)
deliverate(goarounds, userid, rcpt, msg, true)
} else if d.When.Before(nexttime) { } else if d.When.Before(nexttime) {
nexttime = d.When nexttime = d.When
} }

View file

@ -2,16 +2,6 @@ changelog
=== next === next
+ New threaded display order.
+ Improved search.
+ Tuned up superdeliverator.
+ Import from instagram.
+ improve handling of some Page and Link objects
+ search can now load external posts + search can now load external posts
=== 0.9.91 One More Time === 0.9.91 One More Time

View file

@ -143,18 +143,10 @@ section of the manual for details of honk composition.
Find old honks. Find old honks.
It's basic substring match with a few extensions. It's basic substring match with a few extensions.
The following keywords are supported: The following keywords are supported:
.Bl -tag -width honker: .Bl -tag -width honker
.It @me .It site
Honks mentioning the user.
.It @self
Honks by the user.
.It before:
Honks posted before YYYY-MM-DD.
.It after:
As above.
.It site:
Substring match on the post domain name. Substring match on the post domain name.
.It honker: .It honker
Exact match, either AP actor or honker nickname. Exact match, either AP actor or honker nickname.
.It - .It -
Negate term. Negate term.

View file

@ -154,10 +154,6 @@ The
command exists to purge old external data, by default 30 days. command exists to purge old external data, by default 30 days.
This removes unreferenced, unsaved posts and attachments. This removes unreferenced, unsaved posts and attachments.
It does not remove any original content. It does not remove any original content.
This will not immediately reduce the size of the database, but frees space
for future use.
A vacuum may be performed manually if necessary, but will require more time
and additional disk space.
.Pp .Pp
Backups may be performed by running Backups may be performed by running
.Ic backup dirname . .Ic backup dirname .
@ -194,7 +190,7 @@ and templates are reloaded every request.
Data may be imported and converted from other services using the Data may be imported and converted from other services using the
.Ic import .Ic import
command. command.
Currently supports Mastodon, Twitter, and Instagram exported data. Currently supports Mastodon and Twitter exported data.
Posts are imported and backdated to appear as old honks. Posts are imported and backdated to appear as old honks.
The Mastodon following list is imported, but must be refollowed. The Mastodon following list is imported, but must be refollowed.
.Pp .Pp
@ -205,9 +201,6 @@ To prepare a Twitter data archive, extract the twitter-longhash.zip file.
After unzipping the data archive, navigate to the tweet_media directory After unzipping the data archive, navigate to the tweet_media directory
and unzip any zip files contained within. and unzip any zip files contained within.
.Dl ./honk import username twitter source-directory .Dl ./honk import username twitter source-directory
.Pp
To prepare an Instagram data archive, extract the igusername.zip file.
.Dl ./honk import username instagram source-directory
.Ss Advanced Options .Ss Advanced Options
Advanced configuration values may be set by running the Advanced configuration values may be set by running the
.Ic setconfig Ar key value .Ic setconfig Ar key value

8
fun.go
View file

@ -211,8 +211,7 @@ func replaceimgsand(zap map[string]bool, absolute bool) func(node *html.Node) st
func translatechonk(ch *Chonk) { func translatechonk(ch *Chonk) {
noise := ch.Noise noise := ch.Noise
if ch.Format == "markdown" { if ch.Format == "markdown" {
var marker mz.Marker noise = markitzero(noise)
noise = marker.Mark(noise)
} }
var htf htfilter.Filter var htf htfilter.Filter
htf.SpanClasses = allowedclasses htf.SpanClasses = allowedclasses
@ -301,8 +300,7 @@ func precipitate(honk *Honk) {
honk.Precis = noise[:idx] honk.Precis = noise[:idx]
noise = noise[idx+1:] noise = noise[idx+1:]
} }
var marker mz.Marker honk.Precis = markitzero(strings.TrimSpace(honk.Precis))
honk.Precis = marker.Mark(strings.TrimSpace(honk.Precis))
honk.Noise = noise honk.Noise = noise
} }
} }
@ -549,7 +547,7 @@ func attoreplacer(m string) string {
} }
func ontoreplacer(h string) string { func ontoreplacer(h string) string {
return fmt.Sprintf(`<a class="mention hashtag" href="https://%s/o/%s">%s</a>`, serverName, return fmt.Sprintf(`<a href="https://%s/o/%s">%s</a>`, serverName,
strings.ToLower(h[1:]), h) strings.ToLower(h[1:]), h)
} }

2
go.mod
View file

@ -9,5 +9,5 @@ require (
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
humungus.tedunangst.com/r/go-sqlite3 v1.1.3 humungus.tedunangst.com/r/go-sqlite3 v1.1.3
humungus.tedunangst.com/r/webs v0.6.62 humungus.tedunangst.com/r/webs v0.6.61
) )

4
go.sum
View file

@ -25,5 +25,5 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
humungus.tedunangst.com/r/go-sqlite3 v1.1.3 h1:G2N4wzDS0NbuvrZtQJhh4F+3X+s7BF8b9ga8k38geUI= 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/go-sqlite3 v1.1.3/go.mod h1:FtEEmQM7U2Ey1TuEEOyY1BmphTZnmiEjPsNLEAkpf/M=
humungus.tedunangst.com/r/webs v0.6.62 h1:T/T0a2xWw1cYKTMqKXwP4GStRPUfOWYytN9zCMMlqpA= humungus.tedunangst.com/r/webs v0.6.61 h1:Sgy0Htb8Y0jmmLPp73nYDuD4NebeUsgXftP+wB86wSg=
humungus.tedunangst.com/r/webs v0.6.62/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc= humungus.tedunangst.com/r/webs v0.6.61/go.mod h1:03R0N9BcT49HB4TDd1YmarpbiPvPzVDm74Mk4h1hYPc=

View file

@ -20,7 +20,6 @@ import (
"regexp" "regexp"
"sort" "sort"
"time" "time"
"unicode"
"humungus.tedunangst.com/r/webs/cache" "humungus.tedunangst.com/r/webs/cache"
) )
@ -110,8 +109,8 @@ func filtcachefiller(userid int64) (afiltermap, bool) {
} }
} }
if t := filt.Text; t != "" && t != "." { if t := filt.Text; t != "" && t != "." {
wordfront := unicode.IsLetter(rune(t[0])) wordfront := t[0] != '#'
wordtail := unicode.IsLetter(rune(t[len(t)-1])) wordtail := true
t = "(?i:" + t + ")" t = "(?i:" + t + ")"
if wordfront { if wordfront {
t = "\\b" + t t = "\\b" + t
@ -126,8 +125,8 @@ func filtcachefiller(userid int64) (afiltermap, bool) {
} }
} }
if t := filt.Rewrite; t != "" { if t := filt.Rewrite; t != "" {
wordfront := unicode.IsLetter(rune(t[0])) wordfront := t[0] != '#'
wordtail := unicode.IsLetter(rune(t[len(t)-1])) wordtail := true
t = "(?i:" + t + ")" t = "(?i:" + t + ")"
if wordfront { if wordfront {
t = "\\b" + t t = "\\b" + t

View file

@ -35,8 +35,6 @@ func importMain(username, flavor, source string) {
importMastodon(username, source) importMastodon(username, source)
case "twitter": case "twitter":
importTwitter(username, source) importTwitter(username, source)
case "instagram":
importInstagram(username, source)
default: default:
elog.Fatal("unknown source flavor") elog.Fatal("unknown source flavor")
} }
@ -447,79 +445,3 @@ func importTwitter(username, source string) {
log.Printf("honk saved %v -> %v", xid, err) log.Printf("honk saved %v -> %v", xid, err)
} }
} }
func importInstagram(username, source string) {
user, err := butwhatabout(username)
if err != nil {
elog.Fatal(err)
}
type Gram struct {
Media []struct {
URI string
Creation int64 `json:"creation_timestamp"`
Title string
}
}
var grams []*Gram
fd, err := os.Open(source + "/content/posts_1.json")
if err != nil {
elog.Fatal(err)
}
dec := json.NewDecoder(fd)
err = dec.Decode(&grams)
if err != nil {
elog.Fatalf("error parsing json: %s", err)
}
fd.Close()
log.Printf("importing %d grams", len(grams))
sort.Slice(grams, func(i, j int) bool {
return grams[i].Media[0].Creation < grams[j].Media[0].Creation
})
for _, g0 := range grams {
g := g0.Media[0]
xid := fmt.Sprintf("%s/%s/%s", user.URL, honkSep, xfiltrate())
what := "honk"
noise := g.Title
convoy := "data:,acoustichonkytonk-" + xfiltrate()
date := time.Unix(g.Creation, 0)
audience := []string{thewholeworld}
honk := Honk{
UserID: user.ID,
Username: user.Name,
What: what,
Honker: user.URL,
XID: xid,
Date: date,
Format: "markdown",
Audience: audience,
Convoy: convoy,
Public: true,
Whofore: 2,
}
{
u := xfiltrate()
fname := fmt.Sprintf("%s/%s", source, g.URI)
data, err := ioutil.ReadFile(fname)
if err != nil {
elog.Printf("error reading media: %s", fname)
continue
}
newurl := fmt.Sprintf("https://%s/d/%s", serverName, u)
fileid, err := savefile(u, u, newurl, "image/jpg", true, data)
if err != nil {
elog.Printf("error saving media: %s", fname)
continue
}
donk := &Donk{
FileID: fileid,
}
honk.Donks = append(honk.Donks, donk)
}
honk.Noise = noise
err := savehonk(&honk)
log.Printf("honk saved %v -> %v", xid, err)
}
}

25
markitzero.go Normal file
View file

@ -0,0 +1,25 @@
//
// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package main
import (
"humungus.tedunangst.com/r/webs/mz"
)
func markitzero(s string) string {
var marker mz.Marker
return marker.Mark(s)
}

View file

@ -90,7 +90,7 @@ func initdb() {
os.Remove(dbname) os.Remove(dbname)
os.Exit(1) os.Exit(1)
}() }()
c := make(chan os.Signal, 1) c := make(chan os.Signal)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
go func() { go func() {
<-c <-c
@ -209,7 +209,7 @@ func adduser() {
defer func() { defer func() {
os.Exit(1) os.Exit(1)
}() }()
c := make(chan os.Signal, 1) c := make(chan os.Signal)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
go func() { go func() {
<-c <-c
@ -263,7 +263,7 @@ func chpass(username string) {
defer func() { defer func() {
os.Exit(1) os.Exit(1)
}() }()
c := make(chan os.Signal, 1) c := make(chan os.Signal)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)
go func() { go func() {
<-c <-c

View file

@ -7,7 +7,6 @@
<link href="/local.css{{ .LocalStyleParam }}" rel="stylesheet"> <link href="/local.css{{ .LocalStyleParam }}" rel="stylesheet">
{{ end }} {{ end }}
{{ .APAltLink }} {{ .APAltLink }}
{{ .Honkology }}
<link href="/icon.png" rel="icon"> <link href="/icon.png" rel="icon">
<meta name="theme-color" content="#305"> <meta name="theme-color" content="#305">
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">

View file

@ -175,6 +175,7 @@ input[type=file] {
.glow { .glow {
box-shadow: 0px 0px 16px var(--hl); box-shadow: 0px 0px 16px var(--hl);
} }
.honk { .honk {
margin: auto; margin: auto;
background: var(--bg-dark); background: var(--bg-dark);
@ -187,35 +188,6 @@ input[type=file] {
overflow: hidden; overflow: hidden;
} }
.level1 {
margin-left: 0.5em;
}
.level1::before {
position: absolute;
content: ">";
}
.level2 {
margin-left: 1.0em;
}
.level2::before {
position: absolute;
content: ">>";
}
.level3 {
margin-left: 1.5em;
}
.level3::before {
position: absolute;
content: ">>>";
}
.level4 {
margin-left: 2.0em;
}
.level4::before {
position: absolute;
content: ">>>>";
}
.chat { .chat {
border-bottom: 0.5px solid var(--fg-subtle); border-bottom: 0.5px solid var(--fg-subtle);
padding-left: 1em; padding-left: 1em;

170
web.go
View file

@ -364,7 +364,7 @@ func inbox(w http.ResponseWriter, r *http.Request) {
} }
what, _ := j.GetString("type") what, _ := j.GetString("type")
obj, _ := j.GetString("object") obj, _ := j.GetString("object")
if what == "Like" || what == "Dislike" || (what == "EmojiReact" && originate(obj) != serverName) { if what == "Like" || (what == "EmojiReact" && originate(obj) != serverName) {
return return
} }
who, _ := j.GetString("actor") who, _ := j.GetString("actor")
@ -779,8 +779,7 @@ func showconvoy(w http.ResponseWriter, r *http.Request) {
templinfo["TopHID"] = honks[0].ID templinfo["TopHID"] = honks[0].ID
} }
honks = osmosis(honks, u.UserID, false) honks = osmosis(honks, u.UserID, false)
//reversehonks(honks) reversehonks(honks)
honks = threadsort(honks)
templinfo["PageName"] = "convoy" templinfo["PageName"] = "convoy"
templinfo["PageArg"] = c templinfo["PageArg"] = c
templinfo["ServerMessage"] = "honks in convoy: " + c templinfo["ServerMessage"] = "honks in convoy: " + c
@ -1018,106 +1017,6 @@ func trackback(xid string, r *http.Request) {
} }
} }
func sameperson(h1, h2 *Honk) bool {
n1, n2 := h1.Honker, h2.Honker
if h1.Oonker != "" {
n1 = h1.Oonker
}
if h2.Oonker != "" {
n2 = h2.Oonker
}
return n1 == n2
}
func threadsort(honks []*Honk) []*Honk {
sort.Slice(honks, func(i, j int) bool {
return honks[i].Date.Before(honks[j].Date)
})
honkx := make(map[string]*Honk)
kids := make(map[string][]*Honk)
for _, h := range honks {
honkx[h.XID] = h
rid := h.RID
kids[rid] = append(kids[rid], h)
}
done := make(map[*Honk]bool)
var thread []*Honk
var nextlevel func(p *Honk)
level := 0
nextlevel = func(p *Honk) {
levelup := level < 4
if pp := honkx[p.RID]; p.RID == "" || (pp != nil && sameperson(p, pp)) {
levelup = false
}
if level > 0 && len(kids[p.RID]) == 1 {
if pp := honkx[p.RID]; pp != nil && len(kids[pp.RID]) == 1 {
levelup = false
}
}
if levelup {
level++
}
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)
})
for _, h := range childs {
if !done[h] {
done[h] = true
thread = append(thread, h)
nextlevel(h)
}
}
if levelup {
level--
}
}
for _, h := range honks {
if !done[h] && h.RID == "" {
done[h] = true
thread = append(thread, h)
nextlevel(h)
}
}
for _, h := range honks {
if !done[h] {
done[h] = true
thread = append(thread, h)
nextlevel(h)
}
}
return thread
}
func honkology(honk *Honk) template.HTML {
var user *WhatAbout
ok := somenumberedusers.Get(honk.UserID, &user)
if !ok {
return ""
}
title := fmt.Sprintf("%s: %s", user.Display, honk.Precis)
imgurl := avatarURL(user)
for _, d := range honk.Donks {
if d.Local && strings.HasPrefix(d.Media, "image") {
imgurl = d.URL
break
}
}
short := honk.Noise
if len(short) > 160 {
short = short[0:160] + "..."
}
return templates.Sprintf(
`<meta property="og:title" content="%s" />
<meta property="og:type" content="article" />
<meta property="article:author" content="%s" />
<meta property="og:url" content="%s" />
<meta property="og:image" content="%s" />
<meta property="og:description" content="%s" />`,
title, user.URL, honk.XID, imgurl, short)
}
func showonehonk(w http.ResponseWriter, r *http.Request) { func showonehonk(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"] name := mux.Vars(r)["name"]
user, err := butwhatabout(name) user, err := butwhatabout(name)
@ -1165,24 +1064,19 @@ func showonehonk(w http.ResponseWriter, r *http.Request) {
honkpage(w, u, honks, templinfo) honkpage(w, u, honks, templinfo)
return return
} }
templinfo := getInfo(r)
rawhonks := gethonksbyconvoy(honk.UserID, honk.Convoy, 0) rawhonks := gethonksbyconvoy(honk.UserID, honk.Convoy, 0)
//reversehonks(rawhonks) reversehonks(rawhonks)
rawhonks = threadsort(rawhonks)
var honks []*Honk var honks []*Honk
for _, h := range rawhonks { for _, h := range rawhonks {
if h.XID == xid { if h.XID == xid && len(honks) != 0 {
templinfo["Honkology"] = honkology(h) h.Style += " glow"
if len(honks) != 0 {
h.Style += " glow"
}
} }
if h.Public && (h.Whofore == 2 || h.IsAcked()) { if h.Public && (h.Whofore == 2 || h.IsAcked()) {
honks = append(honks, h) honks = append(honks, h)
} }
} }
templinfo := getInfo(r)
templinfo["ServerMessage"] = "one honk maybe more" templinfo["ServerMessage"] = "one honk maybe more"
templinfo["HonkCSRF"] = login.GetCSRF("honkhonk", r) templinfo["HonkCSRF"] = login.GetCSRF("honkhonk", r)
templinfo["APAltLink"] = templates.Sprintf("<link href='%s' rel='alternate' type='application/activity+json'>", xid) templinfo["APAltLink"] = templates.Sprintf("<link href='%s' rel='alternate' type='application/activity+json'>", xid)
@ -2182,10 +2076,15 @@ func dochpass(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/account", http.StatusSeeOther) http.Redirect(w, r, "/account", http.StatusSeeOther)
} }
var oldfingers = cache.New(cache.Options{Filler: func(orig string) ([]byte, bool) { func fingerlicker(w http.ResponseWriter, r *http.Request) {
orig := r.FormValue("resource")
dlog.Printf("finger lick: %s", orig)
if strings.HasPrefix(orig, "acct:") { if strings.HasPrefix(orig, "acct:") {
orig = orig[5:] orig = orig[5:]
} }
name := orig name := orig
idx := strings.LastIndexByte(name, '/') idx := strings.LastIndexByte(name, '/')
if idx != -1 { if idx != -1 {
@ -2206,7 +2105,12 @@ var oldfingers = cache.New(cache.Options{Filler: func(orig string) ([]byte, bool
} }
user, err := butwhatabout(name) user, err := butwhatabout(name)
if err != nil { if err != nil {
return nil, false http.NotFound(w, r)
return
}
if stealthmode(user.ID, r) {
http.NotFound(w, r)
return
} }
j := junk.New() j := junk.New()
@ -2217,22 +2121,9 @@ var oldfingers = cache.New(cache.Options{Filler: func(orig string) ([]byte, bool
l["type"] = `application/activity+json` l["type"] = `application/activity+json`
l["href"] = user.URL l["href"] = user.URL
j["links"] = []junk.Junk{l} j["links"] = []junk.Junk{l}
return j.ToBytes(), true
}})
func fingerlicker(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/jrd+json")
orig := r.FormValue("resource") j.Write(w)
dlog.Printf("finger lick: %s", orig)
var j []byte
ok := oldfingers.Get(orig, &j)
if ok {
w.Header().Set("Content-Type", "application/jrd+json")
w.Write(j)
} else {
http.NotFound(w, r)
}
} }
func somedays() string { func somedays() string {
@ -2404,8 +2295,6 @@ func webhydra(w http.ResponseWriter, r *http.Request) {
c := r.FormValue("c") c := r.FormValue("c")
honks = gethonksbyconvoy(userid, c, wanted) honks = gethonksbyconvoy(userid, c, wanted)
honks = osmosis(honks, userid, false) honks = osmosis(honks, userid, false)
honks = threadsort(honks)
reversehonks(honks)
hydra.Srvmsg = templates.Sprintf("honks in convoy: %s", c) hydra.Srvmsg = templates.Sprintf("honks in convoy: %s", c)
case "honker": case "honker":
xid := r.FormValue("xid") xid := r.FormValue("xid")
@ -2533,7 +2422,7 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
rcpts := boxuprcpts(user, r.Form["rcpt"], public) rcpts := boxuprcpts(user, r.Form["rcpt"], public)
msg := []byte(r.FormValue("msg")) msg := []byte(r.FormValue("msg"))
for rcpt := range rcpts { for rcpt := range rcpts {
go deliverate(userid, rcpt, msg) go deliverate(0, userid, rcpt, msg, true)
} }
case "gethonkers": case "gethonkers":
j := junk.New() j := junk.New()
@ -2551,24 +2440,13 @@ func apihandler(w http.ResponseWriter, r *http.Request) {
} }
} }
func fiveoh(w http.ResponseWriter, r *http.Request) {
fd, err := os.OpenFile("violations.json", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
elog.Printf("error opening violations! %s", err)
return
}
defer fd.Close()
io.Copy(fd, r.Body)
fd.WriteString("\n")
}
var endoftheworld = make(chan bool) var endoftheworld = make(chan bool)
var readyalready = make(chan bool) var readyalready = make(chan bool)
var workinprogress = 0 var workinprogress = 0
func enditall() { func enditall() {
sig := make(chan os.Signal, 1) sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
<-sig <-sig
ilog.Printf("stopping...") ilog.Printf("stopping...")
for i := 0; i < workinprogress; i++ { for i := 0; i < workinprogress; i++ {
@ -2716,8 +2594,6 @@ func serve() {
posters.HandleFunc("/server/inbox", serverinbox) posters.HandleFunc("/server/inbox", serverinbox)
posters.HandleFunc("/inbox", serverinbox) posters.HandleFunc("/inbox", serverinbox)
posters.HandleFunc("/csp-violation", fiveoh)
getters.HandleFunc("/style.css", serveviewasset) getters.HandleFunc("/style.css", serveviewasset)
getters.HandleFunc("/honkpage.js", serveviewasset) getters.HandleFunc("/honkpage.js", serveviewasset)
getters.HandleFunc("/misc.js", serveviewasset) getters.HandleFunc("/misc.js", serveviewasset)