package ap import ( "encoding/json" "fmt" "net/url" "github.com/piprate/json-gold/ld" ) type ApThing map[string]any type RemoteDocumentLoader struct{} // Try and parse a remote ActivityPub object into a more usable form // Result is a map[string]any where the keys defined in /ap/constants.go should be usable, // depending on the type of object // The general approach for fetching an object will be to fetch the main object // and only store the ID for sub-objects to fetch them later func ParseFromUrl(u *url.URL) (ApThing, error) { opts := ld.NewJsonLdOptions("") processor := ld.NewJsonLdProcessor() // TODO: Add custom document parser (copy default implementation) that includes verification // Explanation: // Expansion removes the context from a document (json-ld activitypub data) // and turns every field into something along the lines of // "https://example.com/ns#ObjectType": // This makes it easier to deal with things as they now have a very consistent naming scheme // See /ap/constants.go for those parsed, err := processor.Expand(u.String(), opts) if err != nil { return nil, fmt.Errorf("failed to process remote document: %w", err) } if len(parsed) == 0 { return nil, fmt.Errorf("document has a length of 0") } typed, ok := parsed[0].(ApThing) if !ok { return nil, fmt.Errorf("couldn't cast data to ApThing") } return typed, nil } // Compact an AP object down into a compressed json-ld form // That compacted form should be accepted by all AP servers // It also handles context for any fields // Content should only use keys defined in /ap/constants.go though // Other things might get lost in translation func Compact(content map[string]any) ([]byte, error) { opts := ld.NewJsonLdOptions("") processor := ld.NewJsonLdProcessor() res, err := processor.Compact(content, allContext, opts) if err != nil { return nil, fmt.Errorf("failed to compact data: %w", err) } return json.Marshal(res) }