2018-01-24 08:31:50 +09:00
|
|
|
# streams
|
|
|
|
|
2018-05-31 06:48:34 +09:00
|
|
|
Please read the `README.md` in the `go-fed/activity/vocab` package first. This
|
|
|
|
library is a convenience layer on top of the `go-fed/activity/vocab` library, so
|
|
|
|
this README builds off of that one.
|
2018-01-24 08:31:50 +09:00
|
|
|
|
2018-05-31 06:48:34 +09:00
|
|
|
This library is entirely code-generated by the
|
|
|
|
`go-fed/activity/tools/streams/gen` library and `go-fed/activity/tools/streams`
|
|
|
|
tool. Run `go generate` to refresh the library, which requires `$GOPATH/bin` to
|
|
|
|
be on your `$PATH`.
|
2018-01-24 08:31:50 +09:00
|
|
|
|
2018-08-20 01:39:54 +09:00
|
|
|
The [go-fed.org](https://go-fed.org) website has a tutorial. It also hosts godoc
|
|
|
|
documentation for every version of this library.
|
|
|
|
|
2018-01-24 08:31:50 +09:00
|
|
|
## What it does
|
|
|
|
|
|
|
|
This library provides a `Resolver`, which is simply a collection of callbacks
|
|
|
|
that clients can specify to handle specific ActivtyStream data types. The
|
|
|
|
`Resolver.Deserialize` method turns a JSON-decoded `map[string]interface{}`
|
|
|
|
into its proper type, passed to the corresponding callback.
|
|
|
|
|
|
|
|
For example, given the data:
|
|
|
|
|
2018-06-25 16:44:24 +09:00
|
|
|
```golang
|
2018-01-24 08:31:50 +09:00
|
|
|
{
|
|
|
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
|
|
"type": "Note",
|
|
|
|
"name": "Equivalent Exchange",
|
|
|
|
"content": "I'll give half of my life to you and you give half of yours to me!",
|
|
|
|
"attachment": "https://example.com/attachment"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
in `b []byte` one can do the following:
|
|
|
|
|
2018-06-25 16:44:24 +09:00
|
|
|
```golang
|
2018-01-24 08:31:50 +09:00
|
|
|
var m map[string]interface{}
|
|
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r := &Resolver {
|
|
|
|
NoteCallback: func(n *Note) error {
|
|
|
|
// 1) Use the Note concrete type here
|
|
|
|
// 2) Errors are propagated transparently
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if handled, err := r.Deserialize(m); err != nil {
|
|
|
|
// 3) Any errors from #2 can be handled, or the payload is an unknown type.
|
|
|
|
return err
|
|
|
|
} else if !handled {
|
|
|
|
// 4) The callback to handle the concrete type was not set.
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Only set the callbacks that are interesting. There is no need to set every
|
|
|
|
callback, unless your application requires it.
|
|
|
|
|
|
|
|
## Using concrete types
|
|
|
|
|
|
|
|
The convenience layer provides easy access to properties with specific types.
|
|
|
|
However, because ActivityStreams is fundamentally built off of JSON-LD and
|
|
|
|
still permits large degree of freedom when it comes to obtaining a concrete type
|
|
|
|
for a property, the convenience API is built to give clients the freedom to
|
|
|
|
choose how best to federate.
|
|
|
|
|
|
|
|
For every type in this package (except `Resolver`), there is an equivalent type
|
|
|
|
in the `activity/vocab` package. It takes only a call to `Raw` to go from this
|
|
|
|
convenience API to the full API:
|
|
|
|
|
2018-06-25 16:44:24 +09:00
|
|
|
```golang
|
2018-01-24 08:31:50 +09:00
|
|
|
r := &Resolver {
|
|
|
|
NoteCallback: func(n *Note) error {
|
|
|
|
// Raw is available for all ActivityStream types
|
|
|
|
vocabNote := n.Raw()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
To determine whether the call to `Raw` is needed, the "get" and "has" methods
|
|
|
|
use `Resolution` and `Presence` types to inform client code. The client is free
|
|
|
|
to support as many types as is feasible within the specific application.
|
|
|
|
|
|
|
|
Reusing the `Note` example above that has an `attachment`, the following is
|
|
|
|
client code that tries to handle every possible type that `attachment` can
|
|
|
|
take. **The W3C does not require client applications to support all of these
|
|
|
|
use cases.**
|
|
|
|
|
2018-06-25 16:44:24 +09:00
|
|
|
```golang
|
2018-01-24 08:31:50 +09:00
|
|
|
r := &Resolver {}
|
|
|
|
r.NoteCallback = func(n *Note) error {
|
|
|
|
if n.LenAttachment() == 1 {
|
|
|
|
if presence := n.HasAttachment(0); p == ConvenientPresence {
|
|
|
|
// A new or existing Resolver can be used. This is the convenient getter.
|
|
|
|
if resolution, err := n.ResolveAttachment(r, 0); err != nil {
|
|
|
|
return err
|
|
|
|
} else if resolution == RawResolutionNeeded {
|
|
|
|
vocabNote := n.Raw()
|
|
|
|
// Use the full API
|
|
|
|
if vocabNote.IsAttachmentIRI(0) {
|
|
|
|
...
|
|
|
|
} else ...
|
|
|
|
}
|
|
|
|
} else if p == RawPresence {
|
|
|
|
vocabNote := n.Raw()
|
|
|
|
// Use the full API
|
|
|
|
if vocabNote.IsAttachmentIRI(0) {
|
|
|
|
...
|
|
|
|
} else ...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Serializing data
|
|
|
|
|
|
|
|
Creating a raw type and serializing it is straightforward:
|
|
|
|
|
2018-06-25 16:44:24 +09:00
|
|
|
```golang
|
2018-01-24 08:31:50 +09:00
|
|
|
n := &Note{}
|
|
|
|
n.AddName("I'll see you again")
|
|
|
|
n.AddContent("You don't have to be alone when I leave")
|
|
|
|
// The "type" property is automatically handled...
|
|
|
|
m, err := n.Serialize()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// ...but "@context" is not.
|
|
|
|
m["@context"] = "https://www.w3.org/ns/activitystreams"
|
|
|
|
b, err := json.Marshal(m)
|
|
|
|
```
|
|
|
|
|
|
|
|
The only caveat is that clients must set `"@context"` manually at this time.
|
|
|
|
|
|
|
|
## What it doesn't do
|
|
|
|
|
2018-05-31 06:48:34 +09:00
|
|
|
Please see the same section in the `go-fed/activity/vocab` package.
|
2018-01-24 08:31:50 +09:00
|
|
|
|
|
|
|
## Other considerations
|
|
|
|
|
2018-05-31 06:48:34 +09:00
|
|
|
This library is entirely code-generated. Please see the same section in the
|
|
|
|
`go-fed/activity/vocab` package for more details.
|