2019-12-19 12:39:42 +00:00
|
|
|
package toot
|
|
|
|
|
2020-03-28 02:57:58 +00:00
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2019-12-19 13:20:23 +00:00
|
|
|
|
2020-03-28 02:57:58 +00:00
|
|
|
"git.eeqj.de/sneak/feta/jsonapis"
|
|
|
|
"github.com/rs/zerolog/log"
|
2019-12-19 12:39:42 +00:00
|
|
|
|
2020-03-28 02:57:58 +00:00
|
|
|
//import "github.com/davecgh/go-spew/spew"
|
|
|
|
|
|
|
|
//import "encoding/hex"
|
|
|
|
mh "github.com/multiformats/go-multihash"
|
|
|
|
|
|
|
|
mhopts "github.com/multiformats/go-multihash/opts"
|
|
|
|
)
|
2019-12-19 12:39:42 +00:00
|
|
|
|
2019-12-19 13:20:23 +00:00
|
|
|
// Hash is a type for storing a string-based base58 multihash of a
|
|
|
|
// toot's identity
|
2019-12-19 12:39:42 +00:00
|
|
|
|
2019-12-19 13:20:23 +00:00
|
|
|
// Toot is an object we use internally for storing a discovered toot
|
2019-12-19 12:39:42 +00:00
|
|
|
type Toot struct {
|
|
|
|
Original []byte
|
|
|
|
Parsed *jsonapis.APISerializedToot
|
2020-03-28 02:57:58 +00:00
|
|
|
Hash string
|
2019-12-19 12:39:42 +00:00
|
|
|
FromHost string
|
|
|
|
}
|
|
|
|
|
2019-12-19 13:20:23 +00:00
|
|
|
// NewTootCollectionFromMastodonAPIResponse takes a byte array from a masto
|
|
|
|
// api response and provides you with a nice array of pointers to parsed
|
|
|
|
// toots
|
|
|
|
func NewTootCollectionFromMastodonAPIResponse(in []byte, hostname string) ([]*Toot, error) {
|
2019-12-19 12:39:42 +00:00
|
|
|
var rt []json.RawMessage
|
|
|
|
err := json.Unmarshal(in, &rt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.New("unable to parse api response")
|
|
|
|
}
|
|
|
|
|
2019-12-19 13:20:23 +00:00
|
|
|
var tc []*Toot
|
2019-12-19 12:39:42 +00:00
|
|
|
|
|
|
|
// iterate over rawtoots from api
|
|
|
|
for _, item := range rt {
|
|
|
|
parsed := new(jsonapis.APISerializedToot)
|
|
|
|
err := json.Unmarshal(item, parsed)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Msg("unable to parse toot, skipping")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
t := new(Toot)
|
|
|
|
t.Parsed = parsed
|
|
|
|
o, err := item.MarshalJSON()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
t.Original = o
|
|
|
|
t.FromHost = hostname
|
|
|
|
t.calcHash()
|
2019-12-19 13:20:23 +00:00
|
|
|
tc = append(tc, t)
|
2019-12-19 12:39:42 +00:00
|
|
|
}
|
2019-12-19 13:20:23 +00:00
|
|
|
return tc, nil
|
2019-12-19 12:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Toot) String() string {
|
|
|
|
return fmt.Sprintf("%#v", t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Toot) multiHash(in []byte) string {
|
|
|
|
opts := new(mhopts.Options)
|
|
|
|
opts.Algorithm = "sha2-256"
|
|
|
|
opts.Encoding = "base58"
|
|
|
|
var found bool
|
|
|
|
opts.AlgorithmCode, found = mh.Names[opts.Algorithm]
|
|
|
|
if !found {
|
|
|
|
panic("oops")
|
|
|
|
}
|
|
|
|
opts.Length = mh.DefaultLengths[opts.AlgorithmCode]
|
|
|
|
r := strings.NewReader(string(in))
|
|
|
|
h, err := opts.Multihash(r)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return h.B58String()
|
|
|
|
}
|
|
|
|
|
2019-12-19 13:20:23 +00:00
|
|
|
// DiskStoragePath is a helper function on a Toot that allows it to provide
|
|
|
|
// a storage path on disk. This should probably be moved into the FSStorage
|
|
|
|
// backend instead. FIXME
|
|
|
|
// It's here because it's a pure function that just formats its own toot attributes
|
|
|
|
// into a string.
|
2019-12-19 12:39:42 +00:00
|
|
|
func (t *Toot) DiskStoragePath() string {
|
|
|
|
// FIXME make this error if fields are missing
|
|
|
|
// '/YYYYMMDD/example.com/username/YYYY-MM-DD.HHMMSS.username@fromHost.multihash.json'
|
|
|
|
return fmt.Sprintf("%s/%s/%s/%s.%s@%s.%s.json",
|
|
|
|
t.Parsed.CreatedAt.Format("20060102"),
|
|
|
|
strings.ToLower(t.FromHost),
|
|
|
|
t.Parsed.Account.Acct,
|
|
|
|
t.Parsed.CreatedAt.Format("2006-01-02.150405"),
|
|
|
|
t.Parsed.Account.Acct,
|
|
|
|
strings.ToLower(t.FromHost),
|
|
|
|
t.Hash,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Toot) identityHashInput() string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
"%s.%s.%s.%s.%s",
|
|
|
|
t.Parsed.Account.URL,
|
|
|
|
t.Parsed.CreatedAt,
|
|
|
|
t.Parsed.ID,
|
|
|
|
t.Parsed.Content,
|
|
|
|
strings.ToLower(t.FromHost),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-03-28 02:57:58 +00:00
|
|
|
func (t *Toot) GetHash() string {
|
|
|
|
if t.Hash == "" {
|
|
|
|
t.calcHash()
|
|
|
|
}
|
|
|
|
return t.Hash
|
|
|
|
}
|
|
|
|
|
2019-12-19 12:39:42 +00:00
|
|
|
func (t *Toot) calcHash() {
|
|
|
|
hi := t.identityHashInput()
|
2020-03-28 02:57:58 +00:00
|
|
|
t.Hash = string(t.multiHash([]byte(hi)))
|
2019-12-19 12:39:42 +00:00
|
|
|
}
|