Skip to content

Commit

Permalink
[feature] support canceling scheduled tasks, some federation API perf…
Browse files Browse the repository at this point in the history
…ormance improvements (#2329)
  • Loading branch information
NyaaaWhatsUpDoc authored Nov 4, 2023
1 parent 314dda1 commit 41435a6
Show file tree
Hide file tree
Showing 23 changed files with 993 additions and 487 deletions.
14 changes: 9 additions & 5 deletions cmd/gotosocial/action/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"syscall"
"time"

"codeberg.org/gruf/go-sched"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/cmd/gotosocial/action"
"github.com/superseriousbusiness/gotosocial/internal/api"
Expand Down Expand Up @@ -123,16 +122,21 @@ var Start action.GTSAction = func(ctx context.Context) error {
// Add a task to the scheduler to sweep caches.
// Frequency = 1 * minute
// Threshold = 80% capacity
sweep := func(time.Time) { state.Caches.Sweep(80) }
job := sched.NewJob(sweep).Every(time.Minute)
_ = state.Workers.Scheduler.Schedule(job)
_ = state.Workers.Scheduler.AddRecurring(
"@cachesweep", // id
time.Time{}, // start
time.Minute, // freq
func(context.Context, time.Time) {
state.Caches.Sweep(80)
},
)

// Build handlers used in later initializations.
mediaManager := media.NewManager(&state)
oauthServer := oauth.New(ctx, dbService)
typeConverter := typeutils.NewConverter(&state)
filter := visibility.NewFilter(&state)
federatingDB := federatingdb.New(&state, typeConverter)
federatingDB := federatingdb.New(&state, typeConverter, filter)
transportController := transport.NewController(&state, federatingDB, &federation.Clock{}, client)
federator := federation.NewFederator(&state, federatingDB, transportController, typeConverter, mediaManager)

Expand Down
101 changes: 100 additions & 1 deletion internal/ap/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,105 @@ func ExtractActivityData(activity pub.Activity, rawJSON map[string]any) ([]TypeO
}
}

// ExtractAccountables extracts Accountable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
func ExtractAccountables(arr []TypeOrIRI) ([]Accountable, []TypeOrIRI) {
var accounts []Accountable

for i := 0; i < len(arr); i++ {
elem := arr[i]

if elem.IsIRI() {
// skip IRIs
continue
}

// Extract AS vocab type
// associated with elem.
t := elem.GetType()

// Try cast AS type as Accountable.
account, ok := ToAccountable(t)
if !ok {
continue
}

// Add casted accountable type.
accounts = append(accounts, account)

// Drop elem from slice.
copy(arr[:i], arr[i+1:])
arr = arr[:len(arr)-1]
}

return accounts, arr
}

// ExtractStatusables extracts Statusable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
func ExtractStatusables(arr []TypeOrIRI) ([]Statusable, []TypeOrIRI) {
var statuses []Statusable

for i := 0; i < len(arr); i++ {
elem := arr[i]

if elem.IsIRI() {
// skip IRIs
continue
}

// Extract AS vocab type
// associated with elem.
t := elem.GetType()

// Try cast AS type as Statusable.
status, ok := ToStatusable(t)
if !ok {
continue
}

// Add casted Statusable type.
statuses = append(statuses, status)

// Drop elem from slice.
copy(arr[:i], arr[i+1:])
arr = arr[:len(arr)-1]
}

return statuses, arr
}

// ExtractPollOptionables extracts PollOptionable objects from a slice TypeOrIRI, returning extracted and remaining TypeOrIRIs.
func ExtractPollOptionables(arr []TypeOrIRI) ([]PollOptionable, []TypeOrIRI) {
var options []PollOptionable

for i := 0; i < len(arr); i++ {
elem := arr[i]

if elem.IsIRI() {
// skip IRIs
continue
}

// Extract AS vocab type
// associated with elem.
t := elem.GetType()

// Try cast as PollOptionable.
option, ok := ToPollOptionable(t)
if !ok {
continue
}

// Add casted PollOptionable type.
options = append(options, option)

// Drop elem from slice.
copy(arr[:i], arr[i+1:])
arr = arr[:len(arr)-1]
}

return options, arr
}

// ExtractPreferredUsername returns a string representation of
// an interface's preferredUsername property. Will return an
// error if preferredUsername is nil, not a string, or empty.
Expand Down Expand Up @@ -192,7 +291,7 @@ func ExtractToURIs(i WithTo) []*url.URL {

// ExtractCcURIs returns a slice of URIs
// that the given WithCC addresses as Cc.
func ExtractCcURIs(i WithCC) []*url.URL {
func ExtractCcURIs(i WithCc) []*url.URL {
ccProp := i.GetActivityStreamsCc()
if ccProp == nil {
return nil
Expand Down
98 changes: 85 additions & 13 deletions internal/ap/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ import (
"github.com/superseriousbusiness/activity/streams/vocab"
)

// IsActivityable returns whether AS vocab type name is acceptable as Activityable.
func IsActivityable(typeName string) bool {
return isActivity(typeName) ||
isIntransitiveActivity(typeName)
}

// ToActivityable safely tries to cast vocab.Type as Activityable, also checking for expected AS type names.
func ToActivityable(t vocab.Type) (Activityable, bool) {
activityable, ok := t.(Activityable)
if !ok || !IsActivityable(t.GetTypeName()) {
return nil, false
}
return activityable, true
}

// IsAccountable returns whether AS vocab type name is acceptable as Accountable.
func IsAccountable(typeName string) bool {
switch typeName {
Expand Down Expand Up @@ -88,6 +103,43 @@ func ToPollable(t vocab.Type) (Pollable, bool) {
return pollable, true
}

// IsPollOptionable returns whether AS vocab type name is acceptable as PollOptionable.
func IsPollOptionable(typeName string) bool {
return typeName == ObjectNote
}

// ToPollOptionable safely tries to cast vocab.Type as PollOptionable, also checking for expected AS type names.
func ToPollOptionable(t vocab.Type) (PollOptionable, bool) {
note, ok := t.(vocab.ActivityStreamsNote)
if !ok || !IsPollOptionable(t.GetTypeName()) {
return nil, false
}
if note.GetActivityStreamsContent() != nil ||
note.GetActivityStreamsName() == nil {
// A PollOption is an ActivityStreamsNote
// WITHOUT a content property, instead only
// a name property.
return nil, false
}
return note, true
}

// Activityable represents the minimum activitypub interface for representing an 'activity'.
// (see: IsActivityable() for types implementing this, though you MUST make sure to check
// the typeName as this bare interface may be implementable by non-Activityable types).
type Activityable interface {
// Activity is also a vocab.Type
vocab.Type

WithTo
WithCc
WithBcc
WithAttributedTo
WithActor
WithObject
WithPublished
}

// Accountable represents the minimum activitypub interface for representing an 'account'.
// (see: IsAccountable() for types implementing this, though you MUST make sure to check
// the typeName as this bare interface may be implementable by non-Accountable types).
Expand Down Expand Up @@ -126,7 +178,7 @@ type Statusable interface {
WithURL
WithAttributedTo
WithTo
WithCC
WithCc
WithSensitive
WithConversation
WithContent
Expand All @@ -145,16 +197,21 @@ type Pollable interface {
WithClosed
WithVotersCount

// base-interface
// base-interfaces
Statusable
}

// PollOptionable represents the minimum activitypub interface for representing a poll 'option'.
// (see: IsPollOptionable() for types implementing this).
// PollOptionable represents the minimum activitypub interface for representing a poll 'vote'.
// (see: IsPollOptionable() for types implementing this, though you MUST make sure to check
// the typeName as this bare interface may be implementable by non-Pollable types).
type PollOptionable interface {
WithTypeName
vocab.Type

WithName
WithTo
WithInReplyTo
WithReplies
WithAttributedTo
}

// Attachmentable represents the minimum activitypub interface for representing a 'mediaAttachment'. (see: IsAttachmentable).
Expand Down Expand Up @@ -226,13 +283,13 @@ type Announceable interface {
WithObject
WithPublished
WithTo
WithCC
WithCc
}

// Addressable represents the minimum interface for an addressed activity.
type Addressable interface {
WithTo
WithCC
WithCc
}

// ReplyToable represents the minimum interface for an Activity that can be InReplyTo another activity.
Expand Down Expand Up @@ -268,6 +325,15 @@ type TypeOrIRI interface {
WithType
}

// Property represents the minimum interface for an ActivityStreams property with IRIs.
type Property[T TypeOrIRI] interface {
Len() int
At(int) T

AppendIRI(*url.URL)
SetIRI(int, *url.URL)
}

// WithJSONLDId represents an activity with JSONLDIdProperty.
type WithJSONLDId interface {
GetJSONLDId() vocab.JSONLDIdProperty
Expand Down Expand Up @@ -386,18 +452,24 @@ type WithTo interface {
SetActivityStreamsTo(vocab.ActivityStreamsToProperty)
}

// WithCC represents an activity with ActivityStreamsCcProperty
type WithCc interface {
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
SetActivityStreamsCc(vocab.ActivityStreamsCcProperty)
}

// WithCC represents an activity with ActivityStreamsBccProperty
type WithBcc interface {
GetActivityStreamsBcc() vocab.ActivityStreamsBccProperty
SetActivityStreamsBcc(vocab.ActivityStreamsBccProperty)
}

// WithInReplyTo represents an activity with ActivityStreamsInReplyToProperty
type WithInReplyTo interface {
GetActivityStreamsInReplyTo() vocab.ActivityStreamsInReplyToProperty
SetActivityStreamsInReplyTo(vocab.ActivityStreamsInReplyToProperty)
}

// WithCC represents an activity with ActivityStreamsCcProperty
type WithCC interface {
GetActivityStreamsCc() vocab.ActivityStreamsCcProperty
SetActivityStreamsCc(vocab.ActivityStreamsCcProperty)
}

// WithSensitive represents an activity with ActivityStreamsSensitiveProperty
type WithSensitive interface {
GetActivityStreamsSensitive() vocab.ActivityStreamsSensitiveProperty
Expand Down
Loading

0 comments on commit 41435a6

Please sign in to comment.