123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- package pub
- import (
- "errors"
- "fmt"
- "golang.org/x/exp/slices"
- "servitor/ansi"
- "servitor/client"
- "servitor/mime"
- "servitor/object"
- "servitor/style"
- "net/url"
- "sync"
- "time"
- )
- type Activity struct {
- kind string
- id *url.URL
- actor *Actor
- actorErr error
- created time.Time
- createdErr error
- target Tangible
- }
- func NewActivity(input any, source *url.URL) (*Activity, error) {
- o, id, err := client.FetchUnknown(input, source)
- if err != nil {
- return nil, err
- }
- return NewActivityFromObject(o, id)
- }
- func NewActivityFromObject(o object.Object, id *url.URL) (*Activity, error) {
- a := &Activity{}
- a.id = id
- var err error
- if a.kind, err = o.GetString("type"); err != nil {
- return nil, err
- }
- if !slices.Contains([]string{
- "Create", "Announce", "Dislike", "Like",
- }, a.kind) {
- return nil, fmt.Errorf("%w: %s is not an Activity", ErrWrongType, a.kind)
- }
- a.created, a.createdErr = o.GetTime("published")
- var wg sync.WaitGroup
- wg.Add(2)
- go func() { a.actor, a.actorErr = getActor(o, "actor", a.id); wg.Done() }()
- go func() { a.target = getPostOrActor(o, "object", a.id); wg.Done() }()
- wg.Wait()
- return a, nil
- }
- func (a *Activity) Kind() string {
- return a.kind
- }
- func (a *Activity) header(width int) string {
- if a.kind == "Create" {
- return ""
- }
- var output string
- if a.actorErr != nil {
- output += style.Problem(a.actorErr)
- } else {
- output += a.actor.Name()
- }
- output += " "
- switch a.kind {
- case "Announce":
- output += "retweeted"
- case "Like":
- output += "upvoted"
- case "Dislike":
- output += "downvoted"
- default:
- panic("encountered unrecognized Activity type: " + a.kind)
- }
- output += ":\n"
- return ansi.Wrap(output, width)
- }
- func (a *Activity) String(width int) string {
- output := a.header(width)
- output += a.target.String(width)
- return output
- }
- func (a *Activity) Preview(width int) string {
- output := a.header(width)
- output += a.target.Preview(width)
- return output
- }
- func (a *Activity) Children() Container {
- return a.target.Children()
- }
- func (a *Activity) Parents(quantity uint) ([]Tangible, Tangible) {
- return a.target.Parents(quantity)
- }
- func (a *Activity) Timestamp() time.Time {
- if errors.Is(a.createdErr, object.ErrKeyNotPresent) {
- return a.target.Timestamp()
- } else if a.createdErr != nil {
- return time.Time{}
- }
- return a.created
- }
- func (a *Activity) Name() string {
- return a.target.Name()
- }
- func (a *Activity) Actor() Tangible {
- if a.actorErr != nil {
- return NewFailure(a.actorErr)
- }
- return a.actor
- }
- func (a *Activity) Target() Tangible {
- return a.target
- }
- func (a *Activity) SelectLink(input int) (string, *mime.MediaType, bool) {
- return a.target.SelectLink(input)
- }
|