Delete old stuff, added full parser
This commit is contained in:
parent
926e328986
commit
b6071c50ec
12 changed files with 98 additions and 505 deletions
6
go.mod
6
go.mod
|
@ -2,11 +2,9 @@ module gitlab.com/mstarongitlab/goap
|
|||
|
||||
go 1.22.5
|
||||
|
||||
require github.com/piprate/json-gold v0.5.0
|
||||
|
||||
require (
|
||||
github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38 // indirect
|
||||
github.com/samber/go-type-to-string v1.7.0 // indirect
|
||||
github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38
|
||||
github.com/piprate/json-gold v0.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
2
go.sum
2
go.sum
|
@ -8,8 +8,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/samber/go-type-to-string v1.7.0 h1:FiSstaAikHMUSLt5bhVlsvCnD7bbQzC8L0UkkGS3Bj8=
|
||||
github.com/samber/go-type-to-string v1.7.0/go.mod h1:jpU77vIDoIxkahknKDoEx9C8bQ1ADnh2sotZ8I4QqBU=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
gitlab.com/mstarongitlab/goutils v1.3.0 h1:uuxPHjIU36lyJ8/z4T2xI32zOyh53Xj0Au8K12qkaJ4=
|
||||
|
|
34
old/actor.go
34
old/actor.go
|
@ -1,34 +0,0 @@
|
|||
package ap
|
||||
|
||||
type MinimalActor struct {
|
||||
Id string
|
||||
Username string
|
||||
Inbox string
|
||||
}
|
||||
|
||||
type MastoActor struct {
|
||||
Id string
|
||||
Devices MastoDevices
|
||||
Discoverable MastoDiscoverable
|
||||
Featured MastoFeatured
|
||||
FeaturedTags MastoFeaturedTags
|
||||
Indexable MastoIndexable
|
||||
Memorial MastoMemorial
|
||||
Inbox W3Inbox
|
||||
PublicKey W3SecurityPublicKey
|
||||
AlsoKnownAs ActivityStreamsAlsoKnownAs
|
||||
Attachments []ActivityStreamsAttachment
|
||||
Endpoints []map[string]IdType
|
||||
Followers ActivityStreamsFollowers
|
||||
Following ActivityStreamsFollowing
|
||||
Icon ActivityStreamsIcon
|
||||
Image ActivityStreamsImage
|
||||
RestrictedFollow ActivityStreamsRestrictedFollow
|
||||
Name ActivityStreamsName
|
||||
Outbox ActivityStreamsOutbox
|
||||
PrefferedUsername ActivityStreamsPrefferedUsername
|
||||
Published ActivityStreamsPublished
|
||||
Summary ActivityStreamsSummary
|
||||
Tags []ActivityStreamsTag
|
||||
Url ActivityStreamsUrl
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package ap
|
||||
|
||||
import "strings"
|
||||
|
||||
// Header used for making requests for AP resources
|
||||
// Not used yet
|
||||
const OUTBOUND_REQUEST_HEADER = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1"
|
||||
|
||||
var contentHeadersToCheck = []string{
|
||||
"application/json",
|
||||
"application/ld+json",
|
||||
}
|
||||
|
||||
// Check a given string if it contains any of the content types specified in
|
||||
// the contentHeadersToCheck slice
|
||||
// Used for differentiating requests for the ActivityPub version of some data vs frontend version
|
||||
func ContainsApContentHeader(toCheck string) bool {
|
||||
for _, h := range contentHeadersToCheck {
|
||||
if strings.Contains(toCheck, h) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package ap
|
||||
|
||||
import "net/url"
|
||||
|
||||
type IdType struct {
|
||||
Id *url.URL
|
||||
}
|
||||
|
||||
type ValueType[T any] struct {
|
||||
Value T
|
||||
}
|
||||
|
||||
type Media struct {
|
||||
Type url.URL
|
||||
MediaType *ValueType[string]
|
||||
Url IdType
|
||||
Sensitive *ValueType[bool]
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package ap
|
||||
|
||||
const (
|
||||
KEY_ID = "@id" // Value of type string
|
||||
KEY_TYPE = "@type" // Value of type string slice / activitystreams object url slice
|
||||
KEY_VALUE = "@value" // Could be any type really
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_MASTO_DEVICES = "http://joinmastodon.org/ns#devices" // No idea what this is, but Masto includes it
|
||||
KEY_MASTO_DISCOVERABLE = "http://joinmastodon.org/ns#discoverable" // iirc this is whether the object can be found by crawlers
|
||||
KEY_MASTO_FEATURED = "http://joinmastodon.org/ns#featured" // Users tagged? I think
|
||||
KEY_MASTO_FEATURED_TAGS = "http://joinmastodon.org/ns#featuredTags" // Hashtags included, I think
|
||||
KEY_MASTO_INDEXABLE = "http://joinmastodon.org/ns#indexable" // Is the object crawlable round 2
|
||||
KEY_MASTO_MEMORIAL = "http://joinmastodon.org/ns#memorial" // Account dead and disabled?
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_W3_INBOX = "http://www.w3.org/ns/ldp#inbox" // Where to send activities to
|
||||
KEY_W3_SECURITY_PUBLICKEY = "https://w3id.org/security#publicKey" // Public key of the account
|
||||
KEY_W3_SECURITY_OWNER = "https://w3id.org/security#owner" // Owner of the public key
|
||||
KEY_W3_SECURITY_PUBLICKEYPEM = "https://w3id.org/security#publicKeyPem" // Pem content of the key
|
||||
KEY_W3_VCARD_ADRESS = "http://www.w3.org/2006/vcard/ns#Address" // Vcard address of an account
|
||||
KEY_W3_VCARD_BIRTHDAY = "http://www.w3.org/2006/vcard/ns#bday" // Vcard birthday of an account
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_ACTIVITYSTREAMS_ALSOKNOWNAS = "https://www.w3.org/ns/activitystreams#alsoKnownAs" // Lists of usernames?
|
||||
KEY_ACTIVITYSTREAMS_ATTACHMENTS = "https://www.w3.org/ns/activitystreams#attachment" // Attached elements like emotes and hashtags
|
||||
KEY_ACTIVITYSTREAMS_NAME = "https://www.w3.org/ns/activitystreams#name" // AP name
|
||||
KEY_ACTIVITYSTREAMS_ENDPOINTS = "https://www.w3.org/ns/activitystreams#endpoints" // list of assocciated endpoints
|
||||
KEY_ACTIVITYSTREAMS_SHAREDINBOX = "https://www.w3.org/ns/activitystreams#sharedInbox" // Link to the shared inbox of the server
|
||||
KEY_ACTIVITYSTREAMS_FOLLOWERS = "https://www.w3.org/ns/activitystreams#followers" // Who is following the account
|
||||
KEY_ACTIVITYSTREAMS_FOLLOWING = "https://www.w3.org/ns/activitystreams#following" // Who is this account following
|
||||
KEY_ACTIVITYSTREAMS_ICON = "https://www.w3.org/ns/activitystreams#icon" // User icon
|
||||
KEY_ACTIVITYSTREAMS_MEDIATYPE = "https://www.w3.org/ns/activitystreams#mediaType" // What type of media is this? Example image/jpeg
|
||||
KEY_ACTIVITYSTREAMS_URL = "https://www.w3.org/ns/activitystreams#url" // Some url
|
||||
KEY_ACTIVITYSTREAMS_IMAGE = "https://www.w3.org/ns/activitystreams#image" // Account banner
|
||||
KEY_ACTIVITYSTREAMS_RESTRICTED_FOLLOW = "https://www.w3.org/ns/activitystreams#manuallyApprovesFollowers" // Does the account manually approve follow requests
|
||||
KEY_ACTIVITYSTREAMS_OUTBOX = "https://www.w3.org/ns/activitystreams#outbox" // Link to the account's outbox
|
||||
KEY_ACTIVITYSTREAMS_PREFFEREDUSERNAME = "https://www.w3.org/ns/activitystreams#preferredUsername" // What the shown username is
|
||||
KEY_ACTIVITYSTREAMS_PUBLISHED = "https://www.w3.org/ns/activitystreams#published" // When an object was created
|
||||
KEY_ACTIVITYSTREAMS_SUMMARY = "https://www.w3.org/ns/activitystreams#summary" // Summary of an account
|
||||
KEY_ACTIVITYSTREAMS_TAG = "https://www.w3.org/ns/activitystreams#tag" // A tag, no idea what those are
|
||||
KEY_ACTIVITYSTREAMS_CC = "https://www.w3.org/ns/activitystreams#cc" // Urls also included in the object
|
||||
KEY_ACTIVITYSTREAMS_TO = "https://www.w3.org/ns/activitystreams#to" // Urls to send an activity to
|
||||
KEY_ACTIVITYSTREAMS_OBJECT = "https://www.w3.org/ns/activitystreams#object" // Object url and sometimes value
|
||||
|
||||
// Object types (I think)
|
||||
// Those are values the object type can have
|
||||
|
||||
KEY_ACTIVITYSTREAMS_ACTOR = "https://www.w3.org/ns/activitystreams#actor"
|
||||
KEY_ACTIVITYSTREAMS_FOLLOW = "https://www.w3.org/ns/activitystreams#Follow" // Object is an activity of type follow
|
||||
KEY_ACTIVITYSTREAMS_PERSON = "https://www.w3.org/ns/activitystreams#Person" // Object is of type Person
|
||||
KEY_ACTIVITYSTREAMS_CREATE = "https://www.w3.org/ns/activitystreams#Create" // Object is an activity of type Create
|
||||
|
||||
KEY_ACTIVITYSTREAMS_OAUTHAUTHORIZATION = "https://www.w3.org/ns/activitystreams#oauthAuthorizationEndpoint" // Endpoint url for oauth login?
|
||||
KEY_ACTIVITYSTREAMS_OAUTHTOKEN = "https://www.w3.org/ns/activitystreams#oauthTokenEndpoint" // Endpoint url for oauth token verification?
|
||||
KEY_ACTIVITYSTREAMS_UPLOADMEDIA = "https://www.w3.org/ns/activitystreams#uploadMedia" // Endpoint url to upload media to?
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_SCHEMA_VALUE = "http://schema.org#value" // The value for some field
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_MISSKEY_MKSUMMARY = "https://misskey-hub.net/ns#_misskey_summary" // Misskey specific formatted summary
|
||||
KEY_MISSKEY_ISCAT = "https://misskey-hub.net/ns#isCat" // Does the account identify as cat?
|
||||
KEY_FIREFISH_SPEAKASCAT = "https://joinfirefish.org/ns#speakAsCat" // Does the account speak like a cat?
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_LITEPUB_CAPABILITIES = "http://litepub.social/ns#capabilities"
|
||||
KEY_LITEPUB_OAUTHREGISTRATION = "http://litepub.social/ns#oauthRegistrationEndpoint"
|
||||
)
|
||||
|
||||
const (
|
||||
KEY_MYSTERIOUS_NOINDEX = "_:noindex"
|
||||
KEY_MYSTERIOUS_BACKGROUNDURL = "_:backgroundUrl"
|
||||
KEY_MYSTERIOUS_FEATURED = "_:featured"
|
||||
)
|
|
@ -1,49 +0,0 @@
|
|||
package ap
|
||||
|
||||
// Just steal this one from sharkey
|
||||
// Also use this one for all AP objects for now
|
||||
// Can make a function to extract context from an expanded object later
|
||||
// TODO: Consider if such a function is worth it or if it would hinder learning
|
||||
var allContext = map[string]any{
|
||||
"@context": []any{
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
map[string]any{
|
||||
"fedibird": "http://fedibird.com/ns#",
|
||||
"toot": "http://joinmastodon.org/ns#",
|
||||
"schema": "http://schema.org#",
|
||||
"misskey": "https://misskey-hub.net/ns#",
|
||||
"firefish": "https://joinfirefish.org/ns#",
|
||||
"sharkey": "https://joinsharkey.org/ns#",
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#",
|
||||
|
||||
"Key": "sec:Key",
|
||||
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"sensitive": "as:sensitive",
|
||||
"Hashtag": "as:Hashtag",
|
||||
"quoteUrl": "as:quoteUrl",
|
||||
|
||||
"quoteUri": "fedibird:quoteUri",
|
||||
|
||||
"Emoji": "toot:Emoji",
|
||||
"featured": "toot:featured",
|
||||
"discoverable": "toot:discoverable",
|
||||
|
||||
"PropertyValue": "schema:PropertyValue",
|
||||
"value": "schema:value",
|
||||
|
||||
"_misskey_content": "misskey:_misskey_content",
|
||||
"_misskey_quote": "misskey:_misskey_quote",
|
||||
"_misskey_reaction": "misskey:_misskey_reaction",
|
||||
"_misskey_votes": "misskey:_misskey_votes",
|
||||
"_misskey_summary": "misskey:_misskey_summary",
|
||||
"isCat": "misskey:isCat",
|
||||
|
||||
"speakAsCat": "firefish:speakAsCat",
|
||||
|
||||
"backgroundUrl": "sharkey:backgroundUrl",
|
||||
"listenbrainz": "sharkey:listenbrainz",
|
||||
},
|
||||
},
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package ap
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
ActivityStreamsAlsoKnownAs IdType
|
||||
ActivityStreamsAttachment struct {
|
||||
Type *url.URL
|
||||
Value ValueType[string]
|
||||
Name ValueType[string]
|
||||
}
|
||||
ActivityStreamsSharedInbox IdType
|
||||
ActivityStreamsFollowers IdType
|
||||
ActivityStreamsFollowing IdType
|
||||
ActivityStreamsImage Media
|
||||
ActivityStreamsIcon Media
|
||||
ActivityStreamsRestrictedFollow ValueType[bool]
|
||||
ActivityStreamsName ValueType[string]
|
||||
ActivityStreamsOutbox IdType
|
||||
ActivityStreamsPrefferedUsername ValueType[string]
|
||||
ActivityStreamsPublished struct {
|
||||
Type string
|
||||
Value time.Time
|
||||
}
|
||||
ActivityStreamsSummary ValueType[string]
|
||||
ActivityStreamsUrl IdType
|
||||
// NOTE: Technically can contain a lot more values, but tags are not consistent in what those are. Only consistent one is the type
|
||||
|
||||
ActivityStreamsTag struct {
|
||||
Type string
|
||||
}
|
||||
ActivityStreamsTo IdType
|
||||
ActivityStreamsCC IdType
|
||||
|
||||
ActivityStreamsActor IdType
|
||||
// NOTE: Technically, objects can have a LOT of data. I don't care. Treat them as ID type
|
||||
// Just fetch whatever the ID is later on separately and throw away anything else but the ID
|
||||
ActivityStreamsObject IdType
|
||||
ActivityStreamsFollow IdType
|
||||
)
|
||||
|
||||
type (
|
||||
MastoDevices IdType
|
||||
MastoDiscoverable ValueType[bool]
|
||||
MastoFeatured IdType
|
||||
MastoFeaturedTags IdType
|
||||
MastoIndexable ValueType[bool]
|
||||
MastoMemorial ValueType[bool]
|
||||
)
|
||||
|
||||
type (
|
||||
W3Inbox IdType
|
||||
W3SecurityPublicKey struct {
|
||||
Id *url.URL
|
||||
Owner *url.URL
|
||||
KeyPem string
|
||||
}
|
||||
)
|
|
@ -1,58 +0,0 @@
|
|||
package ap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/piprate/json-gold/ld"
|
||||
)
|
||||
|
||||
type ApThing map[string]any
|
||||
|
||||
type RemoteDocumentLoader struct{}
|
||||
|
||||
var ldOpts = ld.NewJsonLdOptions("")
|
||||
var ldProcessor = ld.NewJsonLdProcessor()
|
||||
|
||||
// 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) {
|
||||
// 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": <Insert data for that object here>
|
||||
// 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 := ldProcessor.Expand(u.String(), ldOpts)
|
||||
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) {
|
||||
res, err := ldProcessor.Compact(content, allContext, ldOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compact data: %w", err)
|
||||
}
|
||||
return json.Marshal(res)
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
package ap
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Try and parse a value into an IdType
|
||||
// Returns nil if failed
|
||||
func TryParseIdType(rawIn any) *IdType {
|
||||
switch in := rawIn.(type) {
|
||||
case []any:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
m, ok := in[0].(map[string]any)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return TryParseIdType(m)
|
||||
case map[string]any:
|
||||
vRaw, ok := in[KEY_ID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
v, ok := vRaw.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
u, err := url.Parse(v)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &IdType{
|
||||
Id: u,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TryParseValueType[T any](rawIn any) *ValueType[T] {
|
||||
switch in := rawIn.(type) {
|
||||
case map[string]any:
|
||||
vRaw, ok := in[KEY_ID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
v, ok := vRaw.(T)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &ValueType[T]{
|
||||
Value: v,
|
||||
}
|
||||
case []any:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
v, ok := in[0].(map[string]any)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return TryParseValueType[T](v)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TryParseActivityStreamsPublicKey(rawIn any) *W3SecurityPublicKey {
|
||||
switch in := rawIn.(type) {
|
||||
case map[string]any:
|
||||
asIdType := TryParseIdType(in)
|
||||
if asIdType == nil {
|
||||
return nil
|
||||
}
|
||||
ownerType := TryParseIdType(in[KEY_W3_SECURITY_OWNER])
|
||||
if ownerType == nil {
|
||||
return nil
|
||||
}
|
||||
keyValue := TryParseValueType[string](in[KEY_W3_SECURITY_PUBLICKEYPEM])
|
||||
if keyValue == nil {
|
||||
return nil
|
||||
}
|
||||
return &W3SecurityPublicKey{
|
||||
Id: asIdType.Id,
|
||||
Owner: ownerType.Id,
|
||||
KeyPem: keyValue.Value,
|
||||
}
|
||||
case []any:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
return TryParseActivityStreamsPublicKey(in[0])
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TryParseActivityStreamsAttachment(rawIn any) *ActivityStreamsAttachment {
|
||||
switch in := rawIn.(type) {
|
||||
case []any:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
return TryParseActivityStreamsAttachment(in[0])
|
||||
case map[string]any:
|
||||
rawType, ok := in[KEY_TYPE]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
strType, ok := rawType.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
urlType, err := url.Parse(strType)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
value := TryParseValueType[string](in[KEY_SCHEMA_VALUE])
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
name := TryParseValueType[string](in[KEY_ACTIVITYSTREAMS_NAME])
|
||||
if name == nil {
|
||||
return nil
|
||||
}
|
||||
return &ActivityStreamsAttachment{
|
||||
Type: urlType,
|
||||
Name: *name,
|
||||
Value: *value,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TryParseActivityStreamsPublished(rawIn any) *ActivityStreamsPublished {
|
||||
switch in := rawIn.(type) {
|
||||
case []any:
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
return TryParseActivityStreamsPublished(in[0])
|
||||
case map[string]any:
|
||||
rawType, ok := in[KEY_TYPE]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
strType, ok := rawType.(string)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
value := TryParseValueType[string](in)
|
||||
tv, err := time.Parse("2006-01-02T04:05:06Z", value.Value)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &ActivityStreamsPublished{
|
||||
Type: strType,
|
||||
Value: tv,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Since I do not know if tags are consistent with the struct yet,
|
||||
// This funtion does not do anything yet and should not be used
|
||||
func TryParseActivityStreamsTag(rawIn any) *ActivityStreamsTag {
|
||||
return nil
|
||||
}
|
94
parser.go
Normal file
94
parser.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package goap
|
||||
|
||||
import "slices"
|
||||
|
||||
var allInternalParsersExceptBase []UnmarshalFunc = []UnmarshalFunc{
|
||||
ParseASActorData,
|
||||
ParseASAlsoKnownAsData,
|
||||
ParseASAttachmentsData,
|
||||
ParseASAttributedToData,
|
||||
ParseASCCData,
|
||||
ParseASContentData,
|
||||
ParseASEndpointsData,
|
||||
ParseASFollowersData,
|
||||
ParseASFollowingData,
|
||||
ParseASHrefData,
|
||||
ParseASIconData,
|
||||
ParseASImageData,
|
||||
ParseASMediaTypeData,
|
||||
ParseASNameData,
|
||||
ParseASOutboxData,
|
||||
ParseASObjectData,
|
||||
ParseASPreferredNameData,
|
||||
ParseASPublishedData,
|
||||
ParseASRestrictedData,
|
||||
ParseASRepliesData,
|
||||
ParseASSharedInboxData,
|
||||
ParseASSummaryData,
|
||||
ParseASSensitiveData,
|
||||
ParseASTagData,
|
||||
ParseASToData,
|
||||
ParseASUrlData,
|
||||
ParseASUpdatedData,
|
||||
|
||||
ParseOstatusAtomUriData,
|
||||
ParseOstatusConversationData,
|
||||
|
||||
ParseW3InboxData,
|
||||
|
||||
ParseW3VcardAddressData,
|
||||
ParseW3VcardBirthdayData,
|
||||
|
||||
ParseW3SecurityOwnerData,
|
||||
ParseW3SecurityPublicKeyPemData,
|
||||
ParseW3SecurityPublicKeyData,
|
||||
|
||||
ParseMastoDevicesData,
|
||||
ParseMastoDiscoverableData,
|
||||
ParseMastoFeaturedData,
|
||||
ParseMastoDiscoverableData,
|
||||
ParseMastoIndexableData,
|
||||
ParseMastoMemorialData,
|
||||
|
||||
ParseSchemaValueData,
|
||||
|
||||
ParseMKIsCatData,
|
||||
ParseMKSummaryData,
|
||||
|
||||
ParseFFSpeakAsCatData,
|
||||
}
|
||||
|
||||
func chainParse(
|
||||
raw map[string]any,
|
||||
start BaseApChain,
|
||||
parsers ...UnmarshalFunc,
|
||||
) (BaseApChain, []error) {
|
||||
var current BaseApChain = start
|
||||
errors := []error{}
|
||||
|
||||
for _, p := range parsers {
|
||||
next, err := p(raw, current)
|
||||
current = next
|
||||
errors = append(errors, err)
|
||||
}
|
||||
|
||||
return current, errors
|
||||
}
|
||||
|
||||
func ParseEmptyBase(raw map[string]any, extraParsers ...UnmarshalFunc) (BaseApChain, []error) {
|
||||
base := EmptyBaseObject{}
|
||||
|
||||
allParsers := slices.Clone(allInternalParsersExceptBase)
|
||||
allParsers = append(allParsers, extraParsers...)
|
||||
return chainParse(raw, &base, allParsers...)
|
||||
}
|
||||
|
||||
func ParseDefaultBase(raw map[string]any, extraParsers ...UnmarshalFunc) (BaseApChain, []error) {
|
||||
base, err := UnmarshalBaseObject(raw, nil)
|
||||
if err != nil {
|
||||
return base, []error{err}
|
||||
}
|
||||
allParsers := slices.Concat(allInternalParsersExceptBase, extraParsers)
|
||||
res, errs := chainParse(raw, base, allParsers...)
|
||||
return res, slices.Insert(errs, 0, err)
|
||||
}
|
4
tags.go
4
tags.go
|
@ -134,7 +134,7 @@ func parseMentionTag(raw map[string]any) (*TagMention, error) {
|
|||
name := rawName.(*ASNameData)
|
||||
return &TagMention{
|
||||
TargetId: href.Id,
|
||||
TargetName: name.Name.Value,
|
||||
TargetName: name.Value.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -151,6 +151,6 @@ func parseHashtagTag(raw map[string]any) (*TagHashtag, error) {
|
|||
name := rawName.(*ASNameData)
|
||||
return &TagHashtag{
|
||||
Url: href.Id,
|
||||
Name: name.Name.Value,
|
||||
Name: name.Value.Value,
|
||||
}, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue