More stuff
This commit is contained in:
parent
28bb8e9442
commit
7e0952d398
6 changed files with 149 additions and 13 deletions
21
README.md
Normal file
21
README.md
Normal 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
|
|
@ -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
52
commonTypes.go
Normal 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
48
errors.go
Normal 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)
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package goap
|
|
12
utils.go
12
utils.go
|
@ -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]{
|
||||||
|
|
Loading…
Reference in a new issue