This repository has been archived on 2022-11-27. You can view files and clone it, but cannot push or open issues or pull requests.
activitypub/encoding_json.go

362 lines
9.7 KiB
Go

package activitypub
import (
"encoding/json"
"fmt"
"time"
"git.sr.ht/~mariusor/go-xsd-duration"
"github.com/go-ap/jsonld"
)
func JSONWriteComma(b *[]byte) {
if len(*b) > 1 && (*b)[len(*b)-1] != ',' {
*b = append(*b, ',')
}
}
func JSONWriteJSONProp(b *[]byte, name string, val []byte) (notEmpty bool) {
if len(val) == 0 {
return false
}
JSONWriteComma(b)
success := JSONWritePropJSONName(b, name) && JSONWriteJSONValue(b, val)
if !success {
*b = (*b)[:len(*b)-1]
}
return success
}
func JSONWrite(b *[]byte, c ...byte) {
*b = append(*b, c...)
}
func JSONWriteS(b *[]byte, s string) {
*b = append(*b, s...)
}
func JSONWritePropJSONName(b *[]byte, s string) (notEmpty bool) {
if len(s) == 0 {
return false
}
JSONWrite(b, '"')
JSONWriteS(b, s)
JSONWrite(b, '"', ':')
return true
}
func JSONWriteJSONValue(b *[]byte, s []byte) (notEmpty bool) {
if len(s) == 0 {
return false
}
JSONWrite(b, s...)
return true
}
func JSONWriteNaturalLanguageJSONProp(b *[]byte, n string, nl NaturalLanguageValues) (notEmpty bool) {
l := nl.Count()
if l > 1 {
n += "Map"
}
if v, err := nl.MarshalJSON(); err == nil && len(v) > 0 {
return JSONWriteJSONProp(b, n, v)
}
return false
}
func JSONWriteStringJSONProp(b *[]byte, n string, s string) (notEmpty bool) {
return JSONWriteJSONProp(b, n, []byte(fmt.Sprintf(`"%s"`, s)))
}
func JSONWriteBoolJSONProp(b *[]byte, n string, t bool) (notEmpty bool) {
return JSONWriteJSONProp(b, n, []byte(fmt.Sprintf(`"%t"`, t)))
}
func JSONWriteIntJSONProp(b *[]byte, n string, d int64) (notEmpty bool) {
return JSONWriteJSONProp(b, n, []byte(fmt.Sprintf("%d", d)))
}
func JSONWriteFloatJSONProp(b *[]byte, n string, f float64) (notEmpty bool) {
return JSONWriteJSONProp(b, n, []byte(fmt.Sprintf("%f", f)))
}
func JSONWriteTimeJSONProp(b *[]byte, n string, t time.Time) (notEmpty bool) {
var tb []byte
JSONWrite(&tb, '"')
JSONWriteS(&tb, t.UTC().Format(time.RFC3339))
JSONWrite(&tb, '"')
return JSONWriteJSONProp(b, n, tb)
}
func JSONWriteDurationJSONProp(b *[]byte, n string, d time.Duration) (notEmpty bool) {
if v, err := xsd.Marshal(d); err == nil {
return JSONWriteJSONProp(b, n, v)
}
return false
}
func JSONWriteIRIJSONProp(b *[]byte, n string, i LinkOrIRI) (notEmpty bool) {
url := i.GetLink().String()
if len(url) == 0 {
return false
}
JSONWriteStringJSONProp(b, n, url)
return true
}
func JSONWriteItemJSONProp(b *[]byte, n string, i Item) (notEmpty bool) {
if i == nil {
return notEmpty
}
if im, ok := i.(json.Marshaler); ok {
v, err := im.MarshalJSON()
if err != nil {
return false
}
return JSONWriteJSONProp(b, n, v)
}
return notEmpty
}
func JSONWriteStringJSONValue(b *[]byte, s string) (notEmpty bool) {
if len(s) == 0 {
return false
}
JSONWrite(b, '"')
JSONWriteS(b, s)
JSONWrite(b, '"')
return true
}
func JSONWriteItemCollectionJSONValue(b *[]byte, col ItemCollection) (notEmpty bool) {
if len(col) == 0 {
return notEmpty
}
JSONWriteCommaIfNotEmpty := func(notEmpty bool) {
if notEmpty {
JSONWrite(b, ',')
}
}
JSONWrite(b, '[')
for i, it := range col {
if im, ok := it.(json.Marshaler); ok {
v, err := im.MarshalJSON()
if err != nil {
return false
}
JSONWriteCommaIfNotEmpty(i > 0)
JSONWrite(b, v...)
}
}
JSONWrite(b, ']')
return true
}
func JSONWriteItemCollectionJSONProp(b *[]byte, n string, col ItemCollection) (notEmpty bool) {
if len(col) == 0 {
return notEmpty
}
JSONWriteComma(b)
success := JSONWritePropJSONName(b, n) && JSONWriteItemCollectionJSONValue(b, col)
if !success {
*b = (*b)[:len(*b)-1]
}
return success
}
func JSONWriteObjectJSONValue(b *[]byte, o Object) (notEmpty bool) {
if v, err := o.ID.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "id", v) || notEmpty
}
if v, err := o.Type.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "type", v) || notEmpty
}
if v, err := o.MediaType.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "mediaType", v) || notEmpty
}
if len(o.Name) > 0 {
notEmpty = JSONWriteNaturalLanguageJSONProp(b, "name", o.Name) || notEmpty
}
if len(o.Summary) > 0 {
notEmpty = JSONWriteNaturalLanguageJSONProp(b, "summary", o.Summary) || notEmpty
}
if len(o.Content) > 0 {
notEmpty = JSONWriteNaturalLanguageJSONProp(b, "content", o.Content) || notEmpty
}
if o.Attachment != nil {
notEmpty = JSONWriteItemJSONProp(b, "attachment", o.Attachment) || notEmpty
}
if o.AttributedTo != nil {
notEmpty = JSONWriteItemJSONProp(b, "attributedTo", o.AttributedTo) || notEmpty
}
if o.Audience != nil {
notEmpty = JSONWriteItemJSONProp(b, "audience", o.Audience) || notEmpty
}
if o.Context != nil {
notEmpty = JSONWriteItemJSONProp(b, "context", o.Context) || notEmpty
}
if o.Generator != nil {
notEmpty = JSONWriteItemJSONProp(b, "generator", o.Generator) || notEmpty
}
if o.Icon != nil {
notEmpty = JSONWriteItemJSONProp(b, "icon", o.Icon) || notEmpty
}
if o.Image != nil {
notEmpty = JSONWriteItemJSONProp(b, "image", o.Image) || notEmpty
}
if o.InReplyTo != nil {
notEmpty = JSONWriteItemJSONProp(b, "inReplyTo", o.InReplyTo) || notEmpty
}
if o.Location != nil {
notEmpty = JSONWriteItemJSONProp(b, "location", o.Location) || notEmpty
}
if o.Preview != nil {
notEmpty = JSONWriteItemJSONProp(b, "preview", o.Preview) || notEmpty
}
if o.Replies != nil {
notEmpty = JSONWriteItemJSONProp(b, "replies", o.Replies) || notEmpty
}
if o.Tag != nil {
notEmpty = JSONWriteItemJSONProp(b, "tag", o.Tag) || notEmpty
}
if o.URL != nil {
notEmpty = JSONWriteItemJSONProp(b, "url", o.URL) || notEmpty
}
if o.To != nil {
notEmpty = JSONWriteItemJSONProp(b, "to", o.To) || notEmpty
}
if o.Bto != nil {
notEmpty = JSONWriteItemJSONProp(b, "bto", o.Bto) || notEmpty
}
if o.CC != nil {
notEmpty = JSONWriteItemJSONProp(b, "cc", o.CC) || notEmpty
}
if o.BCC != nil {
notEmpty = JSONWriteItemJSONProp(b, "bcc", o.BCC) || notEmpty
}
if !o.Published.IsZero() {
notEmpty = JSONWriteTimeJSONProp(b, "published", o.Published) || notEmpty
}
if !o.Updated.IsZero() {
notEmpty = JSONWriteTimeJSONProp(b, "updated", o.Updated) || notEmpty
}
if !o.StartTime.IsZero() {
notEmpty = JSONWriteTimeJSONProp(b, "startTime", o.StartTime) || notEmpty
}
if !o.EndTime.IsZero() {
notEmpty = JSONWriteTimeJSONProp(b, "endTime", o.EndTime) || notEmpty
}
if o.Duration != 0 {
// TODO(marius): maybe don't use 0 as a nil value for Object types
// which can have a valid duration of 0 - (Video, Audio, etc)
notEmpty = JSONWriteDurationJSONProp(b, "duration", o.Duration) || notEmpty
}
if o.Likes != nil {
notEmpty = JSONWriteItemJSONProp(b, "likes", o.Likes) || notEmpty
}
if o.Shares != nil {
notEmpty = JSONWriteItemJSONProp(b, "shares", o.Shares) || notEmpty
}
if v, err := o.Source.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "source", v) || notEmpty
}
return notEmpty
}
func JSONWriteActivityJSONValue(b *[]byte, a Activity) (notEmpty bool) {
OnIntransitiveActivity(a, func(i *IntransitiveActivity) error {
if i == nil {
return nil
}
notEmpty = JSONWriteIntransitiveActivityJSONValue(b, *i) || notEmpty
return nil
})
if a.Object != nil {
notEmpty = JSONWriteItemJSONProp(b, "object", a.Object) || notEmpty
}
return notEmpty
}
func JSONWriteIntransitiveActivityJSONValue(b *[]byte, i IntransitiveActivity) (notEmpty bool) {
OnObject(i, func(o *Object) error {
if o == nil {
return nil
}
notEmpty = JSONWriteObjectJSONValue(b, *o) || notEmpty
return nil
})
if i.Actor != nil {
notEmpty = JSONWriteItemJSONProp(b, "actor", i.Actor) || notEmpty
}
if i.Target != nil {
notEmpty = JSONWriteItemJSONProp(b, "target", i.Target) || notEmpty
}
if i.Result != nil {
notEmpty = JSONWriteItemJSONProp(b, "result", i.Result) || notEmpty
}
if i.Origin != nil {
notEmpty = JSONWriteItemJSONProp(b, "origin", i.Origin) || notEmpty
}
if i.Instrument != nil {
notEmpty = JSONWriteItemJSONProp(b, "instrument", i.Instrument) || notEmpty
}
return notEmpty
}
func JSONWriteQuestionJSONValue(b *[]byte, q Question) (notEmpty bool) {
OnIntransitiveActivity(q, func(i *IntransitiveActivity) error {
if i == nil {
return nil
}
notEmpty = JSONWriteIntransitiveActivityJSONValue(b, *i) || notEmpty
return nil
})
if q.OneOf != nil {
notEmpty = JSONWriteItemJSONProp(b, "oneOf", q.OneOf) || notEmpty
}
if q.AnyOf != nil {
notEmpty = JSONWriteItemJSONProp(b, "anyOf", q.AnyOf) || notEmpty
}
notEmpty = JSONWriteBoolJSONProp(b, "closed", q.Closed) || notEmpty
return notEmpty
}
func JSONWriteLinkJSONValue(b *[]byte, l Link) (notEmpty bool) {
if v, err := l.ID.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "id", v) || notEmpty
}
if v, err := l.Type.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "type", v) || notEmpty
}
if v, err := l.MediaType.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "mediaType", v) || notEmpty
}
if len(l.Name) > 0 {
notEmpty = JSONWriteNaturalLanguageJSONProp(b, "name", l.Name) || notEmpty
}
if v, err := l.Rel.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "rel", v) || notEmpty
}
if l.Height > 0 {
notEmpty = JSONWriteIntJSONProp(b, "height", int64(l.Height))
}
if l.Width > 0 {
notEmpty = JSONWriteIntJSONProp(b, "width", int64(l.Width))
}
if l.Preview != nil {
notEmpty = JSONWriteItemJSONProp(b, "rel", l.Preview) || notEmpty
}
if v, err := l.Href.MarshalJSON(); err == nil && len(v) > 0 {
notEmpty = JSONWriteJSONProp(b, "href", v) || notEmpty
}
if len(l.HrefLang) > 0 {
notEmpty = JSONWriteStringJSONProp(b, "hrefLang", string(l.HrefLang)) || notEmpty
}
return notEmpty
}
// MarshalJSON represents just a wrapper for the jsonld.Marshal function
func MarshalJSON(it Item) ([]byte, error) {
return jsonld.Marshal(it)
}