basically finish anonAp adapter, it can fetch a user's profile, their outbox, or an individual note

This commit is contained in:
Iris Lightshard 2024-12-01 09:02:12 -07:00
parent 194a5aed48
commit a2017e3de8
Signed by: Iris Lightshard
GPG key ID: 688407174966CAF3

View file

@ -13,9 +13,9 @@ import (
) )
type anonAPAdapter struct { type anonAPAdapter struct {
data *chan models.SocketData data *chan models.SocketData
server string server string
client http.Client client http.Client
protocol string protocol string
nickname string nickname string
} }
@ -27,17 +27,17 @@ type apLink struct {
} }
type apAttachment struct { type apAttachment struct {
MediaType string MediaType string
Type string Type string
Name string Name string
Summary string Summary string
Url string Url string
} }
type apTag struct { type apTag struct {
Href string Href string
Name string Name string
Type string Type string
} }
type apIcon struct { type apIcon struct {
@ -55,20 +55,70 @@ type apActor struct {
Url string Url string
} }
type apOutbox struct {
OrderedItems []interface{} `json:"-"`
RawOrderedItems []json.RawMessage `json:"OrderedItems"`
}
func (self *apOutbox) UnmarshalJSON(b []byte) error {
type obInternal apOutbox
err := json.Unmarshal(b, (*obInternal)(self))
if err != nil {
return err
}
for _, raw := range self.RawOrderedItems {
var i apOutboxItem
err := json.Unmarshal(raw, &i)
var x interface{}
switch i.Type {
case "Create":
fallthrough
case "Update":
x = &apOutboxItemCreateUpdate{}
case "Announce":
x = &apOutboxItemAnnounce{}
}
err = json.Unmarshal(raw, &x)
if err != nil {
return err
}
self.OrderedItems = append(self.OrderedItems, x)
}
return nil
}
type apOutboxItem struct {
Actor string
Id string
Type string
To string
Published string
}
type apOutboxItemCreateUpdate struct {
Object apActivity
apOutboxItem
}
type apOutboxItemAnnounce struct {
Object string
apOutboxItem
}
type apActivity struct { type apActivity struct {
Id string Id string
Content string Content string
AttributedTo string AttributedTo string
Context string Context string
Conversation string Conversation string
Published string Published string
Tag []apTag Tag []apTag
Attachment []apAttachment Attachment []apAttachment
To string To string
Url string Url string
Actor *string InReplyTo *string
Object *string
InReplyTo *string
} }
type webFinger struct { type webFinger struct {
@ -85,6 +135,10 @@ func (self *anonAPAdapter) Init(data *chan models.SocketData, server, protocol,
func getBodyJson(res *http.Response) []byte { func getBodyJson(res *http.Response) []byte {
l := res.ContentLength l := res.ContentLength
// 4k is a reasonable max size if we get unknown length right?
if l < 0 {
l = 4096
}
jsonData := make([]byte, l) jsonData := make([]byte, l)
res.Body.Read(jsonData) res.Body.Read(jsonData)
return jsonData return jsonData
@ -101,36 +155,36 @@ func (self *anonAPAdapter) makeApRequest(method, url string, data io.Reader) (*h
} }
func (self *anonAPAdapter) toMsg(activity apActivity) *models.Message { func (self *anonAPAdapter) toMsg(activity apActivity) *models.Message {
t, err := time.Parse(time.RFC3339, activity.Published) t, err := time.Parse(time.RFC3339, activity.Published)
if err != nil { if err != nil {
t = time.Now() t = time.Now()
} }
vis := strings.Split(activity.To, "#") vis := strings.Split(activity.To, "#")
if len(vis) > 1 { if len(vis) > 1 {
activity.To = vis[1] activity.To = vis[1]
} }
m := &models.Message{ m := &models.Message{
Datagram: models.Datagram{ Datagram: models.Datagram{
Id: activity.Id, Id: activity.Id,
Uri: activity.Url, Uri: activity.Url,
Type: "message", Type: "message",
Created: t.UnixMilli(), Created: t.UnixMilli(),
Updated: nil, Updated: nil,
Protocol: self.protocol, Protocol: self.protocol,
Adapter: self.nickname, Adapter: self.nickname,
}, },
Author: activity.AttributedTo, Author: activity.AttributedTo,
Content: activity.Content, Content: activity.Content,
ReplyTo: activity.InReplyTo, ReplyTo: activity.InReplyTo,
Visibility: activity.To, Visibility: activity.To,
} }
for _, a := range activity.Attachment { for _, a := range activity.Attachment {
m.Attachments = append(m.Attachments, models.Attachment{ m.Attachments = append(m.Attachments, models.Attachment{
Src: a.Url, Src: a.Url,
Desc: a.Summary, Desc: a.Summary,
}) })
} }
return m return m
} }
@ -147,13 +201,13 @@ func (self *anonAPAdapter) toAuthor(actor apActor) *models.Author {
curtime := time.Now().UnixMilli() curtime := time.Now().UnixMilli()
a := &models.Author{ a := &models.Author{
Datagram: models.Datagram{ Datagram: models.Datagram{
Id: actor.Id, Id: actor.Id,
Uri: actor.Url, Uri: actor.Url,
Type: "author", Type: "author",
Created: curtime, Created: curtime,
Updated: &curtime, Updated: &curtime,
Protocol: self.protocol, Protocol: self.protocol,
Adapter: self.nickname, Adapter: self.nickname,
}, },
Name: actor.PreferredUsername, Name: actor.PreferredUsername,
ProfileData: actor.Summary, ProfileData: actor.Summary,
@ -195,22 +249,90 @@ func (self *anonAPAdapter) Fetch(etype string, ids []string) error {
self.send(author) self.send(author)
} }
case "byAuthor": case "byAuthor":
// get outbox // get outbox
// for each item in outbox, check if it's a Create/Update or an Announce if string([]byte{id[0]}) == "@" {
// Create/Update you can directly deserialize the object id = id[1:]
// if it's an Announce, try to get the object and deserialize it, build a boost out of it }
res, err := http.Get(self.server + "/.well-known/webfinger?resource=acct:" + id)
if err != nil {
return err
}
data := getBodyJson(res)
wf := webFinger{}
json.Unmarshal(data, &wf)
var profile string
for _, l := range wf.Links {
if l.Rel == "self" {
profile = l.Href
break
}
}
res, err = self.makeApRequest("GET", profile+"/outbox", nil)
if err != nil {
return err
}
obData := getBodyJson(res)
ob := apOutbox{}
ob.UnmarshalJSON(obData)
for _, i := range ob.OrderedItems {
switch a := i.(type) {
case *apOutboxItemCreateUpdate:
msg := self.toMsg(a.Object)
if msg != nil {
self.send(msg)
}
case *apOutboxItemAnnounce:
res, err = self.makeApRequest("GET", a.Object, nil)
if err != nil {
return err
}
fmt.Println(a.Object)
activityData := getBodyJson(res)
activity := apActivity{}
json.Unmarshal(activityData, &activity)
ogMsg := self.toMsg(activity)
if ogMsg != nil {
self.send(ogMsg)
}
t, err := time.Parse(time.RFC3339, a.Published)
if err != nil {
t = time.Now()
}
vis := strings.Split(a.To, "#")
if len(vis) > 1 {
a.To = vis[1]
}
boostMsg := models.Message{
Datagram: models.Datagram{
Id: a.Id,
Uri: a.Id,
Protocol: self.protocol,
Adapter: self.nickname,
Type: "message",
Created: t.UnixMilli(),
},
Author: a.Actor,
RenoteId: &ogMsg.Id,
Visibility: a.To,
}
self.send(boostMsg)
}
}
// for each item in outbox, check if it's a Create/Update or an Announce
// Create/Update you can directly deserialize the object
// if it's an Announce, try to get the object and deserialize it, build a boost out of it
case "message": case "message":
res, err := self.makeApRequest("GET", id, nil) res, err := self.makeApRequest("GET", id, nil)
if err != nil { if err != nil {
return err return err
} }
activityData := getBodyJson(res) activityData := getBodyJson(res)
activity := apActivity{} activity := apActivity{}
json.Unmarshal(activityData, &activity) json.Unmarshal(activityData, &activity)
message := self.toMsg(activity) message := self.toMsg(activity)
if message != nil { if message != nil {
self.send(message) self.send(message)
} }
case "children": case "children":
case "convoy": case "convoy":
default: default: