package goap import "time" type Tag interface { Marshal() map[string]any sealed() } type TagEmoji struct { Id string Icon Media Name string LastUpdated time.Time } func (t TagEmoji) sealed() {} func (t TagEmoji) Marshal() map[string]any { m := map[string]any{ KEY_ID: t.Id, KEY_TYPE: []string{KEY_MASTO_EMOJI}, KEY_ACTIVITYSTREAMS_ICON: []map[string]any{t.Icon.Marshal()}, KEY_ACTIVITYSTREAMS_NAME: []map[string]any{{KEY_VALUE: t.Name}}, } return m } type TagMention struct { TargetId string TargetName string } func (t TagMention) sealed() {} func (t TagMention) Marshal() map[string]any { return map[string]any{ KEY_TYPE: []string{KEY_ACTIVITYSTREAMS_MENTION}, KEY_ACTIVITYSTREAMS_HREF: []map[string]any{{KEY_ID: t.TargetId}}, KEY_ACTIVITYSTREAMS_NAME: []map[string]any{{KEY_VALUE: t.TargetName}}, } } type TagHashtag struct { Url string Name string } func (t TagHashtag) sealed() {} func (t TagHashtag) Marshal() map[string]any { return map[string]any{ KEY_TYPE: []string{KEY_ACTIVITYSTREAMS_HASHTAG}, KEY_ACTIVITYSTREAMS_HREF: []map[string]any{{KEY_ID: t.Url}}, KEY_ACTIVITYSTREAMS_NAME: []map[string]any{{KEY_VALUE: t.Name}}, } } func ParseTag(raw map[string]any) (Tag, error) { rawTypeArr, ok := raw[KEY_TYPE] if !ok { return nil, NoRequiredFieldError{KEY_TYPE} } typeArr, ok := rawTypeArr.([]string) if !ok { return nil, BadFieldValueError[[]string]{KEY_TYPE, rawTypeArr, typeArr} } if len(typeArr) != 1 { return nil, BadFieldArrayLengthError{KEY_TYPE, 1, len(typeArr)} } tagType := typeArr[0] switch tagType { case KEY_MASTO_EMOJI: return parseEmojiTag(raw) case KEY_ACTIVITYSTREAMS_MENTION: return parseMentionTag(raw) case KEY_ACTIVITYSTREAMS_HASHTAG: return parseHashtagTag(raw) default: return nil, UnknownTagType{TagType: tagType} } } func parseEmojiTag(raw map[string]any) (*TagEmoji, error) { rawId, ok := raw[KEY_ID] if !ok { return nil, NoRequiredFieldError{KEY_ID} } id, ok := rawId.(string) if !ok { return nil, BadFieldValueError[string]{KEY_ID, rawId, id} } media, err := ParseASIconData(raw, nil) if err != nil { return nil, err } rawName1, ok := raw[KEY_ACTIVITYSTREAMS_NAME] if !ok { return nil, NoRequiredFieldError{KEY_ACTIVITYSTREAMS_NAME} } name1, ok := rawName1.([]map[string]any) if !ok { return nil, BadFieldValueError[[]map[string]any]{KEY_ACTIVITYSTREAMS_NAME, rawName1, name1} } if len(name1) != 1 { return nil, BadFieldArrayLengthError{KEY_ACTIVITYSTREAMS_NAME, 1, len(name1)} } rawName2, ok := name1[0][KEY_VALUE] if !ok { return nil, NoRequiredSubFieldError{KEY_ACTIVITYSTREAMS_NAME, KEY_VALUE} } name2, ok := rawName2.(string) if !ok { return nil, BadFieldValueError[string]{KEY_VALUE, rawName2, name2} } // Casting media to ASIconData without check is ok here // Reason: ParseASIconData returns an BaseAPChain, an interface. // However, the function guarantees that, if it doesn't error out, you get an ASIconData struct back return &TagEmoji{Id: id, Icon: media.(*ASIconData).Media, Name: name2}, nil } func parseMentionTag(raw map[string]any) (*TagMention, error) { rawHref, err := ParseASHrefData(raw, nil) if err != nil { return nil, err } href := rawHref.(*ASHrefData) rawName, err := ParseASNameData(raw, nil) if err != nil { return nil, err } name := rawName.(*ASNameData) return &TagMention{ TargetId: href.Id, TargetName: name.Value.Value, }, nil } func parseHashtagTag(raw map[string]any) (*TagHashtag, error) { rawHref, err := ParseASHrefData(raw, nil) if err != nil { return nil, err } href := rawHref.(*ASHrefData) rawName, err := ParseASNameData(raw, nil) if err != nil { return nil, err } name := rawName.(*ASNameData) return &TagHashtag{ Url: href.Id, Name: name.Value.Value, }, nil }