kopia lustrzana https://github.com/nextcloud/social
avoid race condition on stream action
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>pull/1780/head
rodzic
18790fb914
commit
0f2c5816e0
|
@ -1002,7 +1002,9 @@ class CoreRequestBuilder {
|
|||
$qb->selectAlias('sa.id', 'streamaction_id')
|
||||
->selectAlias('sa.actor_id', 'streamaction_actor_id')
|
||||
->selectAlias('sa.stream_id', 'streamaction_stream_id')
|
||||
->selectAlias('sa.values', 'streamaction_values');
|
||||
->selectAlias('sa.liked', 'streamaction_liked')
|
||||
->selectAlias('sa.boosted', 'streamaction_boosted')
|
||||
->selectAlias('sa.replied', 'streamaction_replied');
|
||||
|
||||
$orX = $expr->orX();
|
||||
$orX->add($expr->eq('sa.stream_id_prim', $pf . '.id_prim'));
|
||||
|
|
|
@ -374,7 +374,9 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
|
|||
$this->selectAlias('sa.id', 'streamaction_id')
|
||||
->selectAlias('sa.actor_id', 'streamaction_actor_id')
|
||||
->selectAlias('sa.stream_id', 'streamaction_stream_id')
|
||||
->selectAlias('sa.values', 'streamaction_values');
|
||||
->selectAlias('sa.liked', 'streamaction_liked')
|
||||
->selectAlias('sa.boosted', 'streamaction_boosted')
|
||||
->selectAlias('sa.replied', 'streamaction_replied');
|
||||
}
|
||||
|
||||
|
||||
|
@ -392,7 +394,9 @@ class SocialCrossQueryBuilder extends SocialCoreQueryBuilder {
|
|||
$this->selectAlias($alias . '.id', 'streamaction_id')
|
||||
->selectAlias($alias . '.actor_id', 'streamaction_actor_id')
|
||||
->selectAlias($alias . '.stream_id', 'streamaction_stream_id')
|
||||
->selectAlias($alias . '.values', 'streamaction_values');
|
||||
->selectAlias($alias . '.liked', 'streamaction_liked')
|
||||
->selectAlias($alias . '.boosted', 'streamaction_boosted')
|
||||
->selectAlias($alias . '.replied', 'streamaction_replied');
|
||||
|
||||
$orX = $expr->orX();
|
||||
$orX->add($expr->eq($alias . '.stream_id_prim', $pf . '.id_prim'));
|
||||
|
|
|
@ -186,6 +186,16 @@ class SocialLimitsQueryBuilder extends SocialCrossQueryBuilder {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $streamId
|
||||
* @param string $alias
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function limitToStreamIdPrim(string $streamId, string $alias = '') {
|
||||
$this->limitToDBField('stream_id_prim', $streamId, false, $alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the request to the FollowId
|
||||
*
|
||||
|
|
|
@ -55,11 +55,6 @@ class StreamActionsRequest extends StreamActionsRequestBuilder {
|
|||
->setValue('actor_id_prim', $qb->createNamedParameter($qb->prim($action->getActorId())))
|
||||
->setValue('stream_id', $qb->createNamedParameter($action->getStreamId()))
|
||||
->setValue('stream_id_prim', $qb->createNamedParameter($qb->prim($action->getStreamId())))
|
||||
->setValue(
|
||||
'values', $qb->createNamedParameter(
|
||||
json_encode($values, JSON_UNESCAPED_SLASHES)
|
||||
)
|
||||
)
|
||||
->setValue('liked', $qb->createNamedParameter(($liked) ? 1 : 0))
|
||||
->setValue('boosted', $qb->createNamedParameter(($boosted) ? 1 : 0))
|
||||
->setValue('replied', $qb->createNamedParameter(($replied) ? 1 : 0));
|
||||
|
@ -68,24 +63,26 @@ class StreamActionsRequest extends StreamActionsRequestBuilder {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Queue in the database.
|
||||
*/
|
||||
public function update(StreamAction $action): int {
|
||||
$qb = $this->getStreamActionUpdateSql();
|
||||
|
||||
$values = $action->getValues();
|
||||
$liked = $this->getBool(StreamAction::LIKED, $values, false);
|
||||
$boosted = $this->getBool(StreamAction::BOOSTED, $values, false);
|
||||
$replied = $this->getBool(StreamAction::REPLIED, $values, false);
|
||||
// update entry/field in database, based only on affected action
|
||||
// to avoid race condition on 2 different actions
|
||||
foreach($action->getAffected() as $entry) {
|
||||
$field = match ($entry) {
|
||||
StreamAction::LIKED => 'liked',
|
||||
StreamAction::BOOSTED => 'boosted',
|
||||
StreamAction::REPLIED => 'replied',
|
||||
default => ''
|
||||
};
|
||||
|
||||
$qb->set('values', $qb->createNamedParameter(json_encode($values, JSON_UNESCAPED_SLASHES)))
|
||||
->set('liked', $qb->createNamedParameter(($liked) ? 1 : 0))
|
||||
->set('boosted', $qb->createNamedParameter(($boosted) ? 1 : 0))
|
||||
->set('replied', $qb->createNamedParameter(($replied) ? 1 : 0));
|
||||
if ($field !== '') {
|
||||
$qb->set($field, $qb->createNamedParameter(($action->getValueBool($entry)) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
$this->limitToActorId($qb, $action->getActorId());
|
||||
$this->limitToStreamId($qb, $action->getStreamId());
|
||||
$qb->limitToActorIdPrim($qb->prim($action->getActorId()));
|
||||
$qb->limitToStreamIdPrim($qb->prim($action->getStreamId()));
|
||||
|
||||
return $qb->executeStatement();
|
||||
}
|
||||
|
|
|
@ -77,7 +77,10 @@ class StreamActionsRequestBuilder extends CoreRequestBuilder {
|
|||
$qb = $this->getQueryBuilder();
|
||||
|
||||
/** @noinspection PhpMethodParametersCountMismatchInspection */
|
||||
$qb->select('sa.id', 'sa.actor_id', 'sa.stream_id', 'sa.values')
|
||||
$qb->select(
|
||||
'sa.id', 'sa.actor_id', 'sa.stream_id',
|
||||
'sa.boosted', 'sa.liked', 'sa.replied'
|
||||
)
|
||||
->from(self::TABLE_STREAM_ACTIONS, 'sa');
|
||||
|
||||
$this->defaultSelectAlias = 'sa';
|
||||
|
|
|
@ -231,6 +231,8 @@ class StreamRequestBuilder extends CoreRequestBuilder {
|
|||
}
|
||||
|
||||
$action = $this->parseStreamActionsLeftJoin($data);
|
||||
$item->setAction($action);
|
||||
|
||||
if ($item->hasCache()) {
|
||||
$cache = $item->getCache();
|
||||
try {
|
||||
|
@ -243,7 +245,7 @@ class StreamRequestBuilder extends CoreRequestBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
$item->setAction($action);
|
||||
|
||||
if ($item->getType() === Announce::TYPE) {
|
||||
$item->setAttributedTo($this->get('following_actor_id', $data, ''));
|
||||
}
|
||||
|
|
|
@ -529,12 +529,8 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
|
|||
$this->setLanguage($this->get('language', $data));
|
||||
|
||||
$action = new StreamAction();
|
||||
$action->setValues(
|
||||
[
|
||||
StreamAction::LIKED => $this->getBool('favourited', $data),
|
||||
StreamAction::BOOSTED => $this->getBool('reblogged', $data)
|
||||
]
|
||||
);
|
||||
$action->updateValueBool(StreamAction::LIKED, $this->getBool('favourited', $data));
|
||||
$action->updateValueBool(StreamAction::BOOSTED, $this->getBool('reblogged', $data));
|
||||
$this->setAction($action);
|
||||
|
||||
try {
|
||||
|
|
|
@ -44,7 +44,6 @@ class StreamAction implements JsonSerializable {
|
|||
use TArrayTools;
|
||||
use TStringTools;
|
||||
|
||||
|
||||
public const LIKED = 'liked';
|
||||
public const BOOSTED = 'boosted';
|
||||
public const REPLIED = 'replied';
|
||||
|
@ -53,7 +52,12 @@ class StreamAction implements JsonSerializable {
|
|||
private string $actorId = '';
|
||||
private string $streamId = '';
|
||||
private array $values = [];
|
||||
|
||||
private array $affected = [];
|
||||
private array $accepted = [
|
||||
self::LIKED,
|
||||
self::BOOSTED,
|
||||
self::REPLIED
|
||||
];
|
||||
|
||||
/**
|
||||
* StreamAction constructor.
|
||||
|
@ -95,14 +99,23 @@ class StreamAction implements JsonSerializable {
|
|||
|
||||
public function updateValue(string $key, string $value): void {
|
||||
$this->values[$key] = $value;
|
||||
if (in_array($key, $this->accepted) && !in_array($key, $this->affected)) {
|
||||
$this->affected[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateValueInt(string $key, int $value): void {
|
||||
$this->values[$key] = $value;
|
||||
if (in_array($key, $this->accepted) && !in_array($key, $this->affected)) {
|
||||
$this->affected[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateValueBool(string $key, bool $value): void {
|
||||
$this->values[$key] = $value;
|
||||
if (in_array($key, $this->accepted) && !in_array($key, $this->affected)) {
|
||||
$this->affected[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasValue(string $key): bool {
|
||||
|
@ -125,10 +138,8 @@ class StreamAction implements JsonSerializable {
|
|||
return $this->values;
|
||||
}
|
||||
|
||||
public function setValues(array $values): StreamAction {
|
||||
$this->values = $values;
|
||||
|
||||
return $this;
|
||||
public function getAffected(): array {
|
||||
return $this->affected;
|
||||
}
|
||||
|
||||
public function setDefaultValues(array $default): StreamAction {
|
||||
|
@ -146,7 +157,11 @@ class StreamAction implements JsonSerializable {
|
|||
$this->setId($this->getInt('id', $data, 0));
|
||||
$this->setActorId($this->get('actor_id', $data, ''));
|
||||
$this->setStreamId($this->get('stream_id', $data, ''));
|
||||
$this->setValues($this->getArray('values', $data, []));
|
||||
$this->values = [
|
||||
self::LIKED => $this->getBool('liked', $data),
|
||||
self::BOOSTED => $this->getBool('boosted', $data),
|
||||
self::REPLIED => $this->getBool('replied', $data)
|
||||
];
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array {
|
||||
|
|
Ładowanie…
Reference in New Issue