mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-01 06:50:00 +00:00
[bugfix] in fedi API CreateStatus(), handle case of data-race and return early (#2403)
This commit is contained in:
parent
eb170003b8
commit
d1cac53cbb
1 changed files with 52 additions and 72 deletions
|
@ -152,20 +152,61 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg messages.FromFe
|
||||||
func (p *fediAPI) CreateStatus(ctx context.Context, fMsg messages.FromFediAPI) error {
|
func (p *fediAPI) CreateStatus(ctx context.Context, fMsg messages.FromFediAPI) error {
|
||||||
var (
|
var (
|
||||||
status *gtsmodel.Status
|
status *gtsmodel.Status
|
||||||
|
statusable ap.Statusable
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if fMsg.APObjectModel == nil /* i.e. forwarded */ {
|
var ok bool
|
||||||
// Model was not set, deref with IRI (this is a forward).
|
|
||||||
// This will also cause the status to be inserted into the db.
|
switch {
|
||||||
status, err = p.statusFromAPIRI(ctx, fMsg)
|
case fMsg.APObjectModel != nil:
|
||||||
} else {
|
// A model was provided, extract this from message.
|
||||||
// Model is set, ensure we have the most up-to-date model.
|
statusable, ok = fMsg.APObjectModel.(ap.Statusable)
|
||||||
status, err = p.statusFromAPModel(ctx, fMsg)
|
if !ok {
|
||||||
|
return gtserror.Newf("cannot cast %T -> ap.Statusable", fMsg.APObjectModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create bare-bones model to pass
|
||||||
|
// into RefreshStatus(), which it will
|
||||||
|
// further populate and insert as new.
|
||||||
|
bareStatus := new(gtsmodel.Status)
|
||||||
|
bareStatus.Local = util.Ptr(false)
|
||||||
|
bareStatus.URI = ap.GetJSONLDId(statusable).String()
|
||||||
|
|
||||||
|
// Call RefreshStatus() to parse and process the provided
|
||||||
|
// statusable model, which it will use to further flesh out
|
||||||
|
// the bare bones model and insert it into the database.
|
||||||
|
status, statusable, err = p.federate.RefreshStatus(ctx,
|
||||||
|
fMsg.ReceivingAccount.Username,
|
||||||
|
bareStatus,
|
||||||
|
statusable,
|
||||||
|
true,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gtserror.Newf("error extracting status from federatorMsg: %w", err)
|
return gtserror.Newf("error processing new status %s: %w", bareStatus.URI, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case fMsg.APIri != nil:
|
||||||
|
// Model was not set, deref with IRI (this is a forward).
|
||||||
|
// This will also cause the status to be inserted into the db.
|
||||||
|
status, statusable, err = p.federate.GetStatusByURI(ctx,
|
||||||
|
fMsg.ReceivingAccount.Username,
|
||||||
|
fMsg.APIri,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return gtserror.Newf("error dereferencing forwarded status %s: %w", fMsg.APIri, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return gtserror.New("neither APObjectModel nor APIri set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusable == nil {
|
||||||
|
// Another thread beat us to
|
||||||
|
// creating this status! Return
|
||||||
|
// here and let the other thread
|
||||||
|
// handle timelining + notifying.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.InReplyToID != "" {
|
if status.InReplyToID != "" {
|
||||||
|
@ -227,66 +268,6 @@ func (p *fediAPI) CreatePollVote(ctx context.Context, fMsg messages.FromFediAPI)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *fediAPI) statusFromAPModel(ctx context.Context, fMsg messages.FromFediAPI) (*gtsmodel.Status, error) {
|
|
||||||
// AP statusable representation MUST have been set.
|
|
||||||
statusable, ok := fMsg.APObjectModel.(ap.Statusable)
|
|
||||||
if !ok {
|
|
||||||
return nil, gtserror.Newf("cannot cast %T -> ap.Statusable", fMsg.APObjectModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status may have been set (no problem if not).
|
|
||||||
status, _ := fMsg.GTSModel.(*gtsmodel.Status)
|
|
||||||
|
|
||||||
if status == nil {
|
|
||||||
// No status was set, create a bare-bones
|
|
||||||
// model for the deferencer to flesh-out,
|
|
||||||
// this indicates it is a new (to us) status.
|
|
||||||
status = >smodel.Status{
|
|
||||||
|
|
||||||
// if coming in here status will ALWAYS be remote.
|
|
||||||
Local: util.Ptr(false),
|
|
||||||
URI: ap.GetJSONLDId(statusable).String(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call refresh on status to either update existing
|
|
||||||
// model, or parse + insert status from statusable data.
|
|
||||||
status, _, err := p.federate.RefreshStatus(
|
|
||||||
ctx,
|
|
||||||
fMsg.ReceivingAccount.Username,
|
|
||||||
status,
|
|
||||||
statusable,
|
|
||||||
false, // Don't force refresh.
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.Newf("error refreshing status: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *fediAPI) statusFromAPIRI(ctx context.Context, fMsg messages.FromFediAPI) (*gtsmodel.Status, error) {
|
|
||||||
// There should be a status IRI pinned to
|
|
||||||
// the federatorMsg for us to dereference.
|
|
||||||
if fMsg.APIri == nil {
|
|
||||||
const text = "neither APObjectModel nor APIri set"
|
|
||||||
return nil, gtserror.New(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the status + ensure we have
|
|
||||||
// the most up-to-date version.
|
|
||||||
status, _, err := p.federate.GetStatusByURI(
|
|
||||||
ctx,
|
|
||||||
fMsg.ReceivingAccount.Username,
|
|
||||||
fMsg.APIri,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, gtserror.Newf("error getting status by uri %s: %w", fMsg.APIri, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *fediAPI) CreateFollowReq(ctx context.Context, fMsg messages.FromFediAPI) error {
|
func (p *fediAPI) CreateFollowReq(ctx context.Context, fMsg messages.FromFediAPI) error {
|
||||||
followRequest, ok := fMsg.GTSModel.(*gtsmodel.FollowRequest)
|
followRequest, ok := fMsg.GTSModel.(*gtsmodel.FollowRequest)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -359,8 +340,7 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg messages.FromFediAPI)
|
||||||
// Dereference status that this boosts, note
|
// Dereference status that this boosts, note
|
||||||
// that this will handle dereferencing the status
|
// that this will handle dereferencing the status
|
||||||
// ancestors / descendants where appropriate.
|
// ancestors / descendants where appropriate.
|
||||||
if err := p.federate.DereferenceAnnounce(
|
if err := p.federate.DereferenceAnnounce(ctx,
|
||||||
ctx,
|
|
||||||
status,
|
status,
|
||||||
fMsg.ReceivingAccount.Username,
|
fMsg.ReceivingAccount.Username,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
@ -388,7 +368,7 @@ func (p *fediAPI) CreateAnnounce(ctx context.Context, fMsg messages.FromFediAPI)
|
||||||
log.Errorf(ctx, "error notifying announce: %v", err)
|
log.Errorf(ctx, "error notifying announce: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interaction counts changed on the boosted status;
|
// Interaction counts changed on the original status;
|
||||||
// uncache the prepared version from all timelines.
|
// uncache the prepared version from all timelines.
|
||||||
p.surface.invalidateStatusFromTimelines(ctx, status.ID)
|
p.surface.invalidateStatusFromTimelines(ctx, status.ID)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue