the spice must flow. redeliverate with extreme prejudice.

This commit is contained in:
Ted Unangst 2019-04-14 21:35:42 -04:00
parent 4e223b7922
commit bf323bd0e5
6 changed files with 90 additions and 8 deletions

6
README
View File

@ -54,3 +54,9 @@ Then run honk.
Refer also to the docs directory, in particular manual.txt. Refer also to the docs directory, in particular manual.txt.
Busy honk instances may use megabytes of memory. Busy honk instances may use megabytes of memory.
-- upgrade
./honk upgrade
./honk

View File

@ -21,6 +21,11 @@ import (
"time" "time"
) )
type Doover struct {
ID int64
When time.Time
}
func sayitagain(goarounds int, username string, rcpt string, msg []byte) { func sayitagain(goarounds int, username string, rcpt string, msg []byte) {
var drift time.Duration var drift time.Duration
switch goarounds { switch goarounds {
@ -36,9 +41,13 @@ func sayitagain(goarounds int, username string, rcpt string, msg []byte) {
log.Printf("he's dead jim: %s", rcpt) log.Printf("he's dead jim: %s", rcpt)
return return
} }
drift += time.Duration(rand.Int63n(int64(drift / 16))) drift += time.Duration(rand.Int63n(int64(drift / 10)))
when := time.Now().UTC().Add(drift) when := time.Now().UTC().Add(drift)
log.Print(when.Format(dbtimeformat), goarounds, username, rcpt, msg) stmtAddDoover.Exec(when.Format(dbtimeformat), goarounds, username, rcpt, msg)
select {
case pokechan <- 0:
default:
}
} }
func deliverate(goarounds int, username string, rcpt string, msg []byte) { func deliverate(goarounds int, username string, rcpt string, msg []byte) {
@ -53,5 +62,56 @@ func deliverate(goarounds int, username string, rcpt string, msg []byte) {
if err != nil { if err != nil {
log.Printf("failed to post json to %s: %s", inbox, err) log.Printf("failed to post json to %s: %s", inbox, err)
sayitagain(goarounds+1, username, rcpt, msg) sayitagain(goarounds+1, username, rcpt, msg)
return
}
}
var pokechan = make(chan int)
func redeliverator() {
sleeper := time.NewTimer(0)
for {
select {
case <-pokechan:
if !sleeper.Stop() {
<-sleeper.C
}
time.Sleep(1 * time.Minute)
case <-sleeper.C:
}
rows, err := stmtGetDoovers.Query()
if err != nil {
log.Printf("wat?")
time.Sleep(1 * time.Minute)
continue
}
var doovers []Doover
for rows.Next() {
var d Doover
var dt string
rows.Scan(&d.ID, &dt)
d.When, _ = time.Parse(dbtimeformat, dt)
doovers = append(doovers, d)
}
rows.Close()
now := time.Now().UTC()
nexttime := now.Add(24 * time.Hour)
for _, d := range doovers {
if d.When.Before(now) {
var goarounds int
var username, rcpt string
var msg []byte
row := stmtLoadDoover.QueryRow(d.ID)
row.Scan(&goarounds, &username, &rcpt, &msg)
stmtZapDoover.Exec(d.ID)
log.Printf("redeliverating %s try %d", rcpt, goarounds)
deliverate(goarounds, username, rcpt, msg)
} else if d.When.Before(nexttime) {
nexttime = d.When
}
}
dur := nexttime.Sub(now).Round(time.Second) + 1*time.Minute
sleeper.Reset(dur)
} }
} }

View File

@ -914,6 +914,8 @@ func serve() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
go redeliverator()
debug := false debug := false
getconfig("debug", &debug) getconfig("debug", &debug)
readviews = ParseTemplates(debug, readviews = ParseTemplates(debug,
@ -975,6 +977,7 @@ var stmtHonkers, stmtDubbers, stmtOneXonk, stmtHonks, stmtUserHonks *sql.Stmt
var stmtHonksForUser, stmtDeleteHonk, stmtSaveDub *sql.Stmt var stmtHonksForUser, stmtDeleteHonk, stmtSaveDub *sql.Stmt
var stmtHonksByHonker, stmtSaveHonk, stmtFileData, stmtWhatAbout *sql.Stmt var stmtHonksByHonker, stmtSaveHonk, stmtFileData, stmtWhatAbout *sql.Stmt
var stmtFindXonk, stmtSaveDonk, stmtFindFile, stmtSaveFile *sql.Stmt var stmtFindXonk, stmtSaveDonk, stmtFindFile, stmtSaveFile *sql.Stmt
var stmtAddDoover, stmtGetDoovers, stmtLoadDoover, stmtZapDoover *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)
@ -1001,6 +1004,10 @@ func prepareStatements(db *sql.DB) {
stmtSaveFile = preparetodie(db, "insert into files (xid, name, url, media, content) values (?, ?, ?, ?, ?)") stmtSaveFile = preparetodie(db, "insert into files (xid, name, url, media, content) values (?, ?, ?, ?, ?)")
stmtWhatAbout = preparetodie(db, "select userid, username, displayname, about, pubkey from users where username = ?") stmtWhatAbout = preparetodie(db, "select userid, username, displayname, about, pubkey from users where username = ?")
stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor) values (?, ?, ?, ?)") stmtSaveDub = preparetodie(db, "insert into honkers (userid, name, xid, flavor) values (?, ?, ?, ?)")
stmtAddDoover = preparetodie(db, "insert into doovers (dt, tries, username, rcpt, msg) values (?, ?, ?, ?, ?)")
stmtGetDoovers = preparetodie(db, "select dooverid, dt from doovers")
stmtLoadDoover = preparetodie(db, "select tries, username, rcpt, msg from doovers where dooverid = ?")
stmtZapDoover = preparetodie(db, "delete from doovers where dooverid = ?")
} }
func ElaborateUnitTests() { func ElaborateUnitTests() {

View File

@ -3,6 +3,7 @@ CREATE TABLE honks (honkid integer primary key, userid integer, what text, honke
CREATE TABLE donks (honkid integer, fileid integer); CREATE TABLE donks (honkid integer, fileid integer);
CREATE TABLE files(fileid integer primary key, xid text, name text, url text, media text, content blob); CREATE TABLE files(fileid integer primary key, xid text, name text, url text, media text, content blob);
CREATE TABLE honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, pubkey text); CREATE TABLE honkers (honkerid integer primary key, userid integer, name text, xid text, flavor text, pubkey text);
create table doovers(dooverid integer primary key, dt text, tries integer, username text, rcpt text, msg blob);
create index idx_honksxid on honks(xid); create index idx_honksxid on honks(xid);
create index idx_honkshonker on honks(honker); create index idx_honkshonker on honks(honker);

View File

@ -16,24 +16,32 @@
package main package main
import ( import (
"database/sql"
"log" "log"
"os" "os"
) )
func doordie(db *sql.DB, s string) {
_, err := db.Exec(s)
if err != nil {
log.Fatal(err)
}
}
func upgradedb() { func upgradedb() {
db := opendatabase() db := opendatabase()
dbversion := 0 dbversion := 0
getconfig("dbversion", &dbversion) getconfig("dbversion", &dbversion)
var err error
switch dbversion { switch dbversion {
case 0: case 0:
_, err = db.Exec("insert into config (key, value) values ('dbversion', 1)") doordie(db, "insert into config (key, value) values ('dbversion', 1)")
if err != nil {
log.Fatal(err)
}
fallthrough fallthrough
case 1: case 1:
doordie(db, "create table doovers(dooverid integer primary key, dt text, tries integer, username text, rcpt text, msg blob)")
doordie(db, "update config set value = 2 where key = 'dbversion'")
fallthrough
case 2:
default: default:
log.Fatalf("can't upgrade unknown version %d", dbversion) log.Fatalf("can't upgrade unknown version %d", dbversion)
} }

View File

@ -70,7 +70,7 @@ var dbtimeformat = "2006-01-02 15:04:05"
var alreadyopendb *sql.DB var alreadyopendb *sql.DB
var dbname = "honk.db" var dbname = "honk.db"
var stmtConfig *sql.Stmt var stmtConfig *sql.Stmt
var myVersion = 1 var myVersion = 2
func initdb() { func initdb() {
schema, err := ioutil.ReadFile("schema.sql") schema, err := ioutil.ReadFile("schema.sql")