More stuff

This commit is contained in:
Melody Becker 2024-07-29 13:26:31 +02:00
parent 28bb8e9442
commit 7e0952d398
6 changed files with 149 additions and 13 deletions

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# GoAp
A Go library to more easily work with ActivityPub
## Design goal
Provide an extendable and easy to use system for working with ActivityPub activities
## Why?
Because the other existing solutions (used by fedbox and gotosocial) are both narrow in scope,
only providing a subset of what AP is capable of, while simultaniously locking you into using them in a very specific way.
This library attempts to provide a more flexible interface to ActivityPub (and indirectly and technically jsonld too) by splitting
it up into lots of small structs, one per attribute and extendable by implementing a parser func and an interface on the struct,
then giving the parser func to the main parser of the library
Additionally the library provides structs that contain information that common ActivityPub servers send, such as Mastodon's Persons
## Examples
TODO: Add examples here

View file

@ -12,6 +12,9 @@ type BaseApChain interface {
MarshalToMap() map[string]any MarshalToMap() map[string]any
} }
// Func used to add parsers for other attributes not yet included in the library
type UnmarshalFunc func(map[string]any, BaseApChain) (BaseApChain, error)
// The minimum data every AP object has // The minimum data every AP object has
type BaseObject struct { type BaseObject struct {
Id string Id string
@ -28,3 +31,28 @@ func (b *BaseObject) MarshalToMap() map[string]any {
KEY_TYPE: b.Type, KEY_TYPE: b.Type,
} }
} }
func UnmarshalBaseObject(raw map[string]any, _ BaseApChain) (BaseApChain, error) {
rawId, ok := raw[KEY_ID]
if !ok {
return nil, NoRequiredFieldError{KEY_ID}
}
id, ok := rawId.(string)
if !ok {
return nil, BadFieldValueError{KEY_ID, rawId, ""}
}
rawObjType, ok := raw[KEY_TYPE]
if !ok {
return nil, NoRequiredFieldError{KEY_TYPE}
}
objType, ok := rawObjType.([]string)
if !ok {
return nil, BadFieldValueError{KEY_TYPE, rawObjType, []string{}}
}
return &BaseObject{
Id: id,
Type: objType[0],
}, nil
}

52
commonTypes.go Normal file
View file

@ -0,0 +1,52 @@
package goap
// Helper type for parsing attributes where the value (after expansion) is of the following form
// ```json
// [
//
// {
// "@id": "some url here"
// }
//
// ]
// ```
type IdType struct {
Next BaseApChain
Id string
}
func (idtype *IdType) GetSelfOrBase() (BaseApChain, bool) {
return idtype.Next, true
}
func (idtype *IdType) MarshalToMapWithName(name string) map[string]any {
m := idtype.Next.MarshalToMap()
m[name] = []map[string]any{{KEY_ID: idtype.Id}}
return m
}
func ParseIdTypeWithName(m map[string]any, b BaseApChain, name string) (*IdType, error) {
rawData1, ok := m[name]
if !ok {
return nil, NoRequiredFieldError{name}
}
data1, ok := rawData1.([]map[string]any)
if !ok {
return nil, BadFieldValueError{name, rawData1, []map[string]any{{}}}
}
if len(data1) != 1 {
return nil, BadFieldArrayLengthError{name, 1, len(data1)}
}
rawData2, ok := data1[0][KEY_ID]
if !ok {
return nil, NoRequiredSubFieldError{name, KEY_ID}
}
data2, ok := rawData1.(string)
if !ok {
return nil, BadFieldValueError{name, rawData2, ""}
}
return &IdType{
Next: b,
Id: data2,
}, nil
}

48
errors.go Normal file
View file

@ -0,0 +1,48 @@
package goap
import "fmt"
type NoRequiredFieldError struct {
FieldName string
}
func (n NoRequiredFieldError) Error() string {
return fmt.Sprintf("no attribute named %s", n.FieldName)
}
type BadFieldValueError struct {
FieldName string
RawValue any
Expected any
}
func (b BadFieldValueError) Error() string {
return fmt.Sprintf(
"attribute %s has a bad raw value, inspect error struct for raw and expected value",
b.FieldName,
)
}
type BadFieldArrayLengthError struct {
FieldName string
ExpectedLen int
ActualLen int
}
func (b BadFieldArrayLengthError) Error() string {
return fmt.Sprintf(
"attribute %s expects an array of length %d but got an array with %d elements",
b.FieldName,
b.ExpectedLen,
b.ActualLen,
)
}
type NoRequiredSubFieldError struct {
FieldName string
Subfield string
}
func (n NoRequiredSubFieldError) Error() string {
return fmt.Sprintf("missing subfield %s for attribute %s", n.Subfield, n.FieldName)
}

View file

@ -1 +0,0 @@
package goap

View file

@ -4,7 +4,6 @@ import (
"time" "time"
"gitlab.com/mstarongitlab/goutils/other" "gitlab.com/mstarongitlab/goutils/other"
"gitlab.com/mstarongitlab/goutils/sliceutils"
) )
func appendWithKey(toAppend map[string]any, key string, val any) map[string]any { func appendWithKey(toAppend map[string]any, key string, val any) map[string]any {
@ -12,17 +11,6 @@ func appendWithKey(toAppend map[string]any, key string, val any) map[string]any
return toAppend return toAppend
} }
// Returns an array of IdValues since that's what is expected for compression of the map later on
func strToId(str string) []IdValue {
return []IdValue{{Id: str}}
}
func strsToIds(strs []string) []IdValue {
return sliceutils.Map(strs, func(s string) IdValue {
return IdValue{Id: s}
})
}
// Returns an array of values since that's what expected for compression later on // Returns an array of values since that's what expected for compression later on
func timeToXmlTime(t time.Time) []ValueValue[string] { func timeToXmlTime(t time.Time) []ValueValue[string] {
return []ValueValue[string]{ return []ValueValue[string]{