Merge pull request #58 from nextcloud-gmbh/network-request-queue

Priority, Queue and Async
alpha1
Maxence Lange 2018-11-27 17:31:22 -01:00 zatwierdzone przez GitHub
commit ce6edf240c
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
33 zmienionych plików z 1486 dodań i 111 usunięć

Wyświetl plik

@ -268,6 +268,13 @@
<primary>true</primary>
</field>
<field>
<name>type</name>
<type>text</type>
<length>31</length>
<notnull>true</notnull>
</field>
<field>
<name>account</name>
<type>text</type>
@ -461,5 +468,79 @@
</declaration>
</table>
<table>
<name>*dbprefix*social_request_queue</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<length>11</length>
<unsigned>true</unsigned>
<notnull>true</notnull>
<autoincrement>true</autoincrement>
<primary>true</primary>
</field>
<field>
<name>token</name>
<type>text</type>
<length>63</length>
<notnull>true</notnull>
</field>
<field>
<name>author</name>
<type>text</type>
<length>1270</length>
<notnull>true</notnull>
</field>
<field>
<name>activity</name>
<type>text</type>
<length>6000</length>
<notnull>true</notnull>
</field>
<field>
<name>instance</name>
<type>text</type>
<length>500</length>
<notnull>false</notnull>
</field>
<field>
<name>priority</name>
<type>integer</type>
<length>1</length>
<default>0</default>
<notnull>false</notnull>
</field>
<field>
<name>status</name>
<type>integer</type>
<length>1</length>
<default>0</default>
<notnull>false</notnull>
</field>
<field>
<name>tries</name>
<type>integer</type>
<length>2</length>
<default>0</default>
<notnull>false</notnull>
</field>
<field>
<name>last</name>
<type>timestamp</type>
</field>
</declaration>
</table>
</database>

Wyświetl plik

@ -5,7 +5,7 @@
<name>Social</name>
<summary>🎉 Nextcloud becomes part of the federated social networks!</summary>
<description><![CDATA[test]]></description>
<version>0.0.43</version>
<version>0.0.50</version>
<licence>agpl</licence>
<author mail="maxence@artificial-owl.com">Maxence Lange</author>
<author mail="jus@bitgrid.net">Julius Härtl</author>
@ -32,6 +32,7 @@
<commands>
<command>OCA\Social\Command\CacheRefresh</command>
<command>OCA\Social\Command\QueueStatus</command>
<command>OCA\Social\Command\NoteCreate</command>
</commands>

Wyświetl plik

@ -1,12 +1,39 @@
<?php
declare(strict_types=1);
/**
* Create your routes in here. The name is the lowercase name of the controller
* without the controller part, the stuff after the hash is the method.
* e.g. page#index -> OCA\MailTest\Controller\PageController->index()
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The controller class has to be registered in the application.php file since
* it's instantiated in there
*/
namespace OCA\Social\AppInfo;
use OCA\Social\Service\CurlService;
return [
'routes' => [
['name' => 'Navigation#navigate', 'url' => '/', 'verb' => 'GET'],
@ -52,6 +79,8 @@ return [
['name' => 'Local#actorInfo', 'url' => '/api/v1/actor/info', 'verb' => 'GET'],
['name' => 'Local#documentsCache', 'url' => '/api/v1/documents/cache', 'verb' => 'POST'],
['name' => 'Queue#asyncWithToken', 'url' => CurlService::ASYNC_TOKEN, 'verb' => 'POST'],
[
'name' => 'Config#setCloudAddress', 'url' => '/api/v1/config/cloudAddress',
'verb' => 'POST'

8
composer.lock wygenerowano
Wyświetl plik

@ -12,12 +12,12 @@
"source": {
"type": "git",
"url": "https://github.com/daita/my-small-php-tools.git",
"reference": "fc822e4c08072844ad9d58846d407e83a62b3d38"
"reference": "ba839f3253672defc4bbb181493c78e2c96e272a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/fc822e4c08072844ad9d58846d407e83a62b3d38",
"reference": "fc822e4c08072844ad9d58846d407e83a62b3d38",
"url": "https://api.github.com/repos/daita/my-small-php-tools/zipball/ba839f3253672defc4bbb181493c78e2c96e272a",
"reference": "ba839f3253672defc4bbb181493c78e2c96e272a",
"shasum": ""
},
"require": {
@ -40,7 +40,7 @@
}
],
"description": "My small PHP Tools",
"time": "2018-11-20T22:42:57+00:00"
"time": "2018-11-27T14:31:43+00:00"
}
],
"packages-dev": [],

Wyświetl plik

@ -135,10 +135,10 @@ class NoteCreate extends Base {
$post->setReplyTo(($replyTo === null) ? '' : $replyTo);
$post->addTo(($to === null) ? '' : $to);
$result = $this->postService->createPost($post, $activity);
$token = $this->postService->createPost($post, $activity);
echo 'object: ' . json_encode($activity, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
echo 'result: ' . json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
echo 'token: ' . $token . "\n";
}
}

Wyświetl plik

@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Command;
use Exception;
use OC\Core\Command\Base;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\QueueService;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class QueueStatus extends Base {
/** @var ConfigService */
private $configService;
/** @var QueueService */
private $queueService;
/** @var MiscService */
private $miscService;
/**
* NoteCreate constructor.
*
* @param QueueService $queueService
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
QueueService $queueService, ConfigService $configService, MiscService $miscService
) {
parent::__construct();
$this->queueService = $queueService;
$this->configService = $configService;
$this->miscService = $miscService;
}
/**
*
*/
protected function configure() {
parent::configure();
$this->setName('social:queue:status')
->addOption(
'token', 't', InputOption::VALUE_OPTIONAL, 'token of a request'
)
->setDescription('Return status on the request queue');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws Exception
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$token = $input->getOption('token');
if ($token === null) {
throw new Exception('As of today, --token is mandatory');
}
$requests = $this->queueService->getRequestFromToken($token);
foreach ($requests as $request) {
$output->writeLn(json_encode($request));
}
}
}

Wyświetl plik

@ -87,7 +87,7 @@ class LocalController extends Controller {
/**
* NavigationController constructor.
* LocalController constructor.
*
* @param IRequest $request
* @param string $userId

Wyświetl plik

@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Controller;
use daita\MySmallPhpTools\Traits\TAsync;
use OCA\Social\AppInfo\Application;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\RequestException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\RequestQueue;
use OCA\Social\Service\ActivityService;
use OCA\Social\Service\CurlService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\QueueService;
use OCP\AppFramework\Controller;
use OCP\IRequest;
/**
* Class QueueController
*
* @package OCA\Social\Controller
*/
class QueueController extends Controller {
use TAsync;
/** @var QueueService */
private $queueService;
/** @var ActivityService */
private $activityService;
/** @var MiscService */
private $miscService;
/**
* QueueController constructor.
*
* @param IRequest $request
* @param QueueService $queueService
* @param ActivityService $activityService
* @param MiscService $miscService
*/
public function __construct(
IRequest $request, QueueService $queueService, ActivityService $activityService,
MiscService $miscService
) {
parent::__construct(Application::APP_NAME, $request);
$this->queueService = $queueService;
$this->activityService = $activityService;
$this->miscService = $miscService;
}
/**
* // TODO: Delete the NoCSRF check
*
* @PublicPage
* @NoCSRFRequired
* @NoAdminRequired
* @NoSubAdminRequired
*
* @param string $token
*/
public function asyncWithToken(string $token) {
$this->async();
$requests = $this->queueService->getRequestFromToken($token, RequestQueue::STATUS_STANDBY);
foreach ($requests as $request) {
try {
$this->activityService->manageRequest($request);
} catch (ActorDoesNotExistException $e) {
} catch (RequestException $e) {
} catch (SocialAppConfigException $e) {
}
}
// or it will feed the logs.
exit();
}
}

Wyświetl plik

@ -113,6 +113,7 @@ class ActorsRequestBuilder extends CoreRequestBuilder {
$actor = new Person();
$actor->importFromDatabase($data);
$actor->setType('Person');
$actor->setInbox($actor->getId() . '/inbox')
->setOutbox($actor->getId() . '/outbox')
->setFollowers($actor->getId() . '/followers')

Wyświetl plik

@ -69,6 +69,7 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
$qb = $this->getCacheActorsInsertSql();
$qb->setValue('id', $qb->createNamedParameter($actor->getId()))
->setValue('account', $qb->createNamedParameter($actor->getAccount()))
->setValue('type', $qb->createNamedParameter($actor->getType()))
->setValue('local', $qb->createNamedParameter(($actor->isLocal()) ? '1' : '0'))
->setValue('following', $qb->createNamedParameter($actor->getFollowing()))
->setValue('followers', $qb->createNamedParameter($actor->getFollowers()))

Wyświetl plik

@ -78,7 +78,7 @@ class CacheActorsRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select(
'ca.id', 'ca.account', 'ca.following', 'ca.followers', 'ca.inbox',
'ca.shared_inbox', 'ca.outbox', 'ca.featured', 'ca.url',
'ca.shared_inbox', 'ca.outbox', 'ca.featured', 'ca.url', 'ca.type',
'ca.preferred_username', 'ca.name', 'ca.summary',
'ca.public_key', 'ca.local', 'ca.source', 'ca.creation'
)

Wyświetl plik

@ -53,6 +53,8 @@ use OCP\IDBConnection;
class CoreRequestBuilder {
const TABLE_REQUEST_QUEUE = 'social_request_queue';
const TABLE_SERVER_ACTORS = 'social_server_actors';
const TABLE_SERVER_NOTES = 'social_server_notes';
const TABLE_SERVER_FOLLOWS = 'social_server_follows';
@ -158,6 +160,17 @@ class CoreRequestBuilder {
}
/**
* Limit the request to the token
*
* @param IQueryBuilder $qb
* @param string $token
*/
protected function limitToToken(IQueryBuilder &$qb, string $token) {
$this->limitToDBField($qb, 'token', $token);
}
/**
* Limit the request to the ActorId
*
@ -262,10 +275,10 @@ class CoreRequestBuilder {
* Limit the request to the status
*
* @param IQueryBuilder $qb
* @param string $status
* @param int $status
*/
protected function limitToStatus(IQueryBuilder &$qb, $status) {
$this->limitToDBField($qb, 'status', $status);
protected function limitToStatus(IQueryBuilder &$qb, int $status) {
$this->limitToDBFieldInt($qb, 'status', $status);
}
@ -348,6 +361,14 @@ class CoreRequestBuilder {
}
/**
* @param IQueryBuilder $qb
*/
protected function orderByPriority(IQueryBuilder &$qb) {
$qb->orderBy('priority', 'desc');
}
/**
* @param IQueryBuilder $qb
* @param string $field
@ -474,6 +495,7 @@ class CoreRequestBuilder {
// /** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->selectAlias('ca.id', 'cacheactor_id')
->selectAlias('ca.type', 'cacheactor_type')
->selectAlias('ca.account', 'cacheactor_account')
->selectAlias('ca.following', 'cacheactor_following')
->selectAlias('ca.followers', 'cacheactor_followers')

Wyświetl plik

@ -177,7 +177,9 @@ class NotesRequestBuilder extends CoreRequestBuilder {
$instances = json_decode($data['instances'], true);
if (is_array($instances)) {
foreach ($instances as $instance) {
$note->addInstancePath(new InstancePath($instance['uri'], $instance['type']));
$instancePath = new InstancePath();
$instancePath->import($instance);
$note->addInstancePath($instancePath);
}
}

Wyświetl plik

@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use DateTime;
use Exception;
use OCA\Social\Exceptions\QueueStatusException;
use OCA\Social\Model\RequestQueue;
use OCA\Social\Service\QueueService;
use OCP\DB\QueryBuilder\IQueryBuilder;
/**
* Class RequestQueueRequest
*
* @package OCA\Social\Db
*/
class RequestQueueRequest extends RequestQueueRequestBuilder {
/**
* create a new Queue in the database.
*
* @param RequestQueue[] $queues
*
* @throws Exception
*/
public function multiple(array $queues) {
foreach ($queues as $queue) {
$this->create($queue);
// $qb->values(
// [
// 'source' => $qb->createNamedParameter($queue->getSource()),
// 'activity' => $qb->createNamedParameter($queue->getActivity()),
// 'instance' => $qb->createNamedParameter(
// json_encode($queue->getInstance(), JSON_UNESCAPED_SLASHES)
// ),
// 'status' => $qb->createNamedParameter($queue->getStatus()),
// 'tries' => $qb->createNamedParameter($queue->getTries()),
// 'last' => $qb->createNamedParameter($queue->getLast())
// ]
// );
}
}
/**
* create a new Queue in the database.
*
* @param RequestQueue $queue
*
* @throws Exception
*/
public function create(RequestQueue $queue) {
$qb = $this->getQueueInsertSql();
$qb->setValue('token', $qb->createNamedParameter($queue->getToken()))
->setValue('author', $qb->createNamedParameter($queue->getAuthor()))
->setValue('activity', $qb->createNamedParameter($queue->getActivity()))
->setValue(
'instance', $qb->createNamedParameter(
json_encode($queue->getInstance(), JSON_UNESCAPED_SLASHES)
)
)
->setValue('priority', $qb->createNamedParameter($queue->getPriority()))
->setValue('status', $qb->createNamedParameter($queue->getStatus()))
->setValue('tries', $qb->createNamedParameter($queue->getTries()))
->setValue('last', $qb->createNamedParameter($queue->getLast()));
$qb->execute();
}
/**
* return Actor from database based on the username
*
* @param string $token
* @param int $status
*
* @return RequestQueue[]
*/
public function getFromToken(string $token, int $status = -1): array {
$qb = $this->getQueueSelectSql();
$this->limitToToken($qb, $token);
if ($status > -1) {
$this->limitToStatus($qb, $status);
}
$this->orderByPriority($qb);
$requests = [];
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
$requests[] = $this->parseQueueSelectSql($data);
}
$cursor->closeCursor();
return $requests;
}
/**
* @param RequestQueue $queue
*
* @throws QueueStatusException
*/
public function setAsRunning(RequestQueue &$queue) {
$qb = $this->getQueueUpdateSql();
$qb->set('status', $qb->createNamedParameter(RequestQueue::STATUS_RUNNING))
->set(
'last',
$qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE)
);
$this->limitToId($qb, $queue->getId());
$this->limitToStatus($qb, RequestQueue::STATUS_STANDBY);
$count = $qb->execute();
if ($count === 0) {
throw new QueueStatusException();
}
$queue->setStatus(RequestQueue::STATUS_RUNNING);
}
/**
* @param RequestQueue $queue
*
* @throws QueueStatusException
*/
public function setAsSuccess(RequestQueue &$queue) {
$qb = $this->getQueueUpdateSql();
$qb->set('status', $qb->createNamedParameter(RequestQueue::STATUS_SUCCESS));
$this->limitToId($qb, $queue->getId());
$this->limitToStatus($qb, RequestQueue::STATUS_RUNNING);
$count = $qb->execute();
if ($count === 0) {
throw new QueueStatusException();
}
$queue->setStatus(RequestQueue::STATUS_SUCCESS);
}
/**
* @param RequestQueue $queue >ll
*
* @throws QueueStatusException
*/
public function setAsFailure(RequestQueue &$queue) {
$qb = $this->getQueueUpdateSql();
$qb->set('status', $qb->createNamedParameter(RequestQueue::STATUS_STANDBY));
// TODO - increment tries++
// ->set('tries', 'tries+1');
$this->limitToId($qb, $queue->getId());
$this->limitToStatus($qb, RequestQueue::STATUS_RUNNING);
$count = $qb->execute();
if ($count === 0) {
throw new QueueStatusException();
}
$queue->setStatus(RequestQueue::STATUS_SUCCESS);
}
}

Wyświetl plik

@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Db;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\Model\RequestQueue;
use OCP\DB\QueryBuilder\IQueryBuilder;
class RequestQueueRequestBuilder extends CoreRequestBuilder {
use TArrayTools;
/**
* Base of the Sql Insert request
*
* @return IQueryBuilder
*/
protected function getQueueInsertSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->insert(self::TABLE_REQUEST_QUEUE);
return $qb;
}
/**
* Base of the Sql Update request
*
* @return IQueryBuilder
*/
protected function getQueueUpdateSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->update(self::TABLE_REQUEST_QUEUE);
return $qb;
}
/**
* Base of the Sql Select request for Shares
*
* @return IQueryBuilder
*/
protected function getQueueSelectSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select(
'rq.id', 'rq.token', 'rq.author', 'rq.activity', 'rq.instance', 'rq.priority',
'rq.status', 'rq.tries', 'rq.last'
)
->from(self::TABLE_REQUEST_QUEUE, 'rq');
$this->defaultSelectAlias = 'rq';
return $qb;
}
/**
* Base of the Sql Delete request
*
* @return IQueryBuilder
*/
protected function getQueueDeleteSql(): IQueryBuilder {
$qb = $this->dbConnection->getQueryBuilder();
$qb->delete(self::TABLE_REQUEST_QUEUE);
return $qb;
}
/**
* @param array $data
*
* @return RequestQueue
*/
protected function parseQueueSelectSql($data): RequestQueue {
$queue = new RequestQueue();
$queue->importFromDatabase($data);
return $queue;
}
}

Wyświetl plik

@ -0,0 +1,8 @@
<?php
namespace OCA\Social\Exceptions;
class EmptyQueueException extends \Exception {
}

Wyświetl plik

@ -0,0 +1,8 @@
<?php
namespace OCA\Social\Exceptions;
class NoHighPriorityRequestException extends \Exception {
}

Wyświetl plik

@ -0,0 +1,8 @@
<?php
namespace OCA\Social\Exceptions;
class QueueStatusException extends \Exception {
}

Wyświetl plik

@ -36,7 +36,7 @@ use JsonSerializable;
use OCA\Social\Exceptions\ActivityCantBeVerifiedException;
use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\InstancePath;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\ActivityPub\ICoreService;
abstract class ACore implements JsonSerializable {

Wyświetl plik

@ -44,11 +44,17 @@ class InstancePath implements JsonSerializable {
use TArrayTools;
const TYPE_PUBLIC = 0;
const TYPE_INBOX = 1;
const TYPE_GLOBAL = 2;
const TYPE_FOLLOWERS = 3;
const PRIORITY_NONE = 0;
const PRIORITY_LOW = 1;
const PRIORITY_MEDIUM = 2;
const PRIORITY_HIGH = 3;
const PRIORITY_TOP = 4;
/** @var string */
private $uri = '';
@ -56,19 +62,35 @@ class InstancePath implements JsonSerializable {
/** @var int */
private $type = 0;
/** @var int */
private $priority = 0;
/**
* InstancePath constructor.
*
* @param string $uri
* @param int $type
* @param int $priority
*/
public function __construct(string $uri = '', int $type = 0) {
public function __construct(string $uri = '', int $type = 0, int $priority = 0) {
$this->uri = $uri;
$this->type = $type;
$this->priority = $priority;
}
/**
* @param string $uri
*
* @return InstancePath
*/
public function setUri(string $uri): InstancePath {
$this->uri = $uri;
return $this;
}
/**
* @return string
*/
@ -77,6 +99,17 @@ class InstancePath implements JsonSerializable {
}
/**
* @param int $type
*
* @return InstancePath
*/
public function setType(int $type): InstancePath {
$this->type = $type;
return $this;
}
/**
* @return int
*/
@ -85,11 +118,30 @@ class InstancePath implements JsonSerializable {
}
/**
* @return int
*/
public function getPriority(): int {
return $this->priority;
}
/**
* @param int $priority
*
* @return InstancePath
*/
public function setPriority(int $priority): InstancePath {
$this->priority = $priority;
return $this;
}
/**
* @return string
*/
public function getAddress(): string {
$info = parse_url($this->uri);
$info = parse_url($this->getUri());
return $this->get('host', $info, '');
}
@ -99,15 +151,19 @@ class InstancePath implements JsonSerializable {
* @return string
*/
public function getPath(): string {
$info = parse_url($this->uri);
$info = parse_url($this->getUri());
return $this->get('path', $info, '');
}
/**
* @param array $data
*/
public function import(array $data) {
$this->setUri($this->get('uri', $data, ''));
$this->setType($this->getInt('type', $data, 0));
$this->setPriority($this->getInt('priority', $data, 0));
}
@ -116,8 +172,9 @@ class InstancePath implements JsonSerializable {
*/
public function jsonSerialize(): array {
return [
'uri' => $this->getUri(),
'type' => $this->getType()
'uri' => $this->getUri(),
'type' => $this->getType(),
'priority' => $this->getPriority()
];
}

Wyświetl plik

@ -0,0 +1,323 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Model;
use daita\MySmallPhpTools\Traits\TArrayTools;
use JsonSerializable;
/**
* Class RequestQueue
*
* @package OCA\Social\Model
*/
class RequestQueue implements JsonSerializable {
use TArrayTools;
const STATUS_STANDBY = 0;
const STATUS_RUNNING = 1;
const STATUS_SUCCESS = 9;
/** @var integer */
private $id = 0;
/** @var string */
private $token = '';
/** @var string */
private $author = '';
/** @var string */
private $activity = '';
/** @var InstancePath */
private $instance;
/** @var int */
private $priority = 0;
/** @var int */
private $status = 0;
/** @var int */
private $tries = 0;
/** @var int */
private $last = 0;
/**
* RequestQueue constructor.
*
* @param string $activity
* @param InstancePath $instance
* @param string $author
*/
public function __construct(string $activity = '', $instance = null, string $author = '') {
$this->setActivity($activity);
if ($instance instanceof InstancePath) {
$this->setInstance($instance);
}
$this->setAuthor($author);
$this->resetToken();
}
/**
* @return int
*/
public function getId(): int {
return $this->id;
}
/**
* @param int $id
*
* @return RequestQueue
*/
public function setId(int $id): RequestQueue {
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getToken(): string {
return $this->token;
}
/**
* @param string $token
*
* @return RequestQueue
*/
public function setToken(string $token): RequestQueue {
$this->token = $token;
return $this;
}
/**
* @return string
*/
public function getAuthor(): string {
return $this->author;
}
/**
* @param string $author
*
* @return RequestQueue
*/
public function setAuthor(string $author): RequestQueue {
$this->author = $author;
return $this;
}
/**
* @return RequestQueue
*/
public function resetToken(): RequestQueue {
$uuid = sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff), mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
$this->setToken($uuid);
return $this;
}
/**
* @return string
*/
public function getActivity(): string {
return $this->activity;
}
/**
* @param string $activity
*
* @return RequestQueue
*/
public function setActivity(string $activity): RequestQueue {
$this->activity = $activity;
return $this;
}
/**
* @return InstancePath
*/
public function getInstance(): InstancePath {
return $this->instance;
}
/**
* @param InstancePath $instance
*
* @return RequestQueue
*/
public function setInstance(InstancePath $instance): RequestQueue {
$this->setPriority($instance->getPriority());
$this->instance = $instance;
return $this;
}
/**
* @return int
*/
public function getPriority(): int {
return $this->priority;
}
/**
* @param int $priority
*
* @return RequestQueue
*/
public function setPriority(int $priority): RequestQueue {
$this->priority = $priority;
return $this;
}
/**
* @return int
*/
public function getStatus(): int {
return $this->status;
}
/**
* @param int $status
*
* @return RequestQueue
*/
public function setStatus(int $status): RequestQueue {
$this->status = $status;
return $this;
}
/**
* @return int
*/
public function getTries(): int {
return $this->tries;
}
/**
* @param int $tries
*
* @return RequestQueue
*/
public function setTries(int $tries): RequestQueue {
$this->tries = $tries;
return $this;
}
/**
* @return int
*/
public function getLast(): int {
return $this->last;
}
/**
* @param int $last
*
* @return RequestQueue
*/
public function setLast(int $last): RequestQueue {
$this->last = $last;
return $this;
}
/**
* @param array $data
*/
public function importFromDatabase(array $data) {
$instance = new InstancePath();
$instance->import(json_decode($this->get('instance', $data, '{}'), true));
$this->setId($this->getInt('id', $data, 0));
$this->setToken($this->get('token', $data, ''));
$this->setAuthor($this->get('author', $data, ''));
$this->setInstance($instance);
$this->setPriority($this->getInt('priority', $data, 0));
$this->setActivity($this->get('activity', $data, ''));
$this->setStatus($this->getInt('status', $data, 0));
$this->setTries($this->getInt('tries', $data, 0));
$this->setLast($this->getInt('last', $data, 0));
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'id' => $this->getId(),
'token' => $this->getToken(),
'author' => $this->getAuthor(),
'instance' => $this->getInstance(),
'priority' => $this->getPriority(),
'status' => $this->getStatus(),
'tries' => $this->getTries(),
'last' => $this->getLast()
];
}
}

Wyświetl plik

@ -38,7 +38,6 @@ use OCA\Social\Exceptions\UnknownItemException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Activity\Delete;
use OCA\Social\Service\ActivityService;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\MiscService;

Wyświetl plik

@ -39,6 +39,7 @@ use OCA\Social\Exceptions\FollowDoesNotExistException;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\RequestException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Activity\Accept;
use OCA\Social\Model\ActivityPub\Activity\Reject;
@ -49,7 +50,6 @@ use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Model\InstancePath;
use OCA\Social\Service\ActivityService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\MiscService;
@ -103,6 +103,7 @@ class FollowService implements ICoreService {
* @throws SocialAppConfigException
* @throws CacheActorDoesNotExistException
* @throws InvalidResourceException
* @throws UrlCloudException
*/
public function followAccount(Person $actor, string $account) {
$remoteActor = $this->personService->getFromAccount($account);
@ -118,9 +119,11 @@ class FollowService implements ICoreService {
$this->followsRequest->save($follow);
$follow->addInstancePath(
new InstancePath($remoteActor->getInbox(), InstancePath::TYPE_INBOX)
new InstancePath(
$remoteActor->getInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_TOP
)
);
$this->activityService->manageRequest($follow);
$this->activityService->request($follow);
}
}
@ -132,6 +135,8 @@ class FollowService implements ICoreService {
* @throws CacheActorDoesNotExistException
* @throws InvalidResourceException
* @throws RequestException
* @throws SocialAppConfigException
* @throws UrlCloudException
*/
public function unfollowAccount(Person $actor, string $account) {
$remoteActor = $this->personService->getFromAccount($account);
@ -173,12 +178,14 @@ class FollowService implements ICoreService {
$accept->setObject($follow);
$accept->addInstancePath(
new InstancePath($remoteActor->getInbox(), InstancePath::TYPE_INBOX)
new InstancePath(
$remoteActor->getInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_TOP
)
);
$follow->setParent($accept);
$this->activityService->manageRequest($accept);
$this->activityService->request($accept);
$this->followsRequest->accepted($follow);
} catch (Exception $e) {
}

Wyświetl plik

@ -28,7 +28,7 @@ declare(strict_types=1);
*/
namespace OCA\Social\Service;
namespace OCA\Social\Service\ActivityPub;
use OCA\Social\Model\ActivityPub\ACore;

Wyświetl plik

@ -47,7 +47,6 @@ use OCA\Social\Service\ActivityService;
use OCA\Social\Service\ActorService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\CurlService;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\MiscService;
class NoteService implements ICoreService {
@ -150,7 +149,7 @@ class NoteService implements ICoreService {
case self::TYPE_UNLISTED:
$note->setTo($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW)
);
$note->addCc(ActivityService::TO_PUBLIC);
break;
@ -158,7 +157,7 @@ class NoteService implements ICoreService {
case self::TYPE_FOLLOWERS:
$note->setTo($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW)
);
break;
@ -169,7 +168,7 @@ class NoteService implements ICoreService {
$note->setTo(ActivityService::TO_PUBLIC);
$note->addCc($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, InstancePath::PRIORITY_LOW)
);
break;
}
@ -192,7 +191,9 @@ class NoteService implements ICoreService {
return;
}
$instancePath = new InstancePath($actor->getInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_MEDIUM);
if ($type === self::TYPE_DIRECT) {
$instancePath->setPriority(InstancePath::PRIORITY_HIGH);
$note->addToArray($actor->getId());
} else {
$note->addCc($actor->getId());
@ -205,7 +206,7 @@ class NoteService implements ICoreService {
]
);
$note->addInstancePath(new InstancePath($actor->getInbox(), InstancePath::TYPE_INBOX));
$note->addInstancePath($instancePath);
}
@ -213,8 +214,6 @@ class NoteService implements ICoreService {
* @param Note $note
* @param string $type
* @param array $accounts
*
* @throws RequestException
*/
public function addRecipients(Note $note, string $type, array $accounts) {
if ($accounts === []) {
@ -237,7 +236,8 @@ class NoteService implements ICoreService {
}
$note->setInReplyTo($replyTo);
$note->addInstancePath(new InstancePath($replyTo));
// TODO - type can be NOT public !
$note->addInstancePath(new InstancePath($replyTo, InstancePath::TYPE_PUBLIC, InstancePath::PRIORITY_HIGH));
}

Wyświetl plik

@ -44,7 +44,6 @@ use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\InstanceService;
use OCA\Social\Service\MiscService;

Wyświetl plik

@ -33,7 +33,6 @@ namespace OCA\Social\Service\ActivityPub;
use Exception;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Service\ICoreService;
use OCA\Social\Service\MiscService;

Wyświetl plik

@ -39,16 +39,21 @@ use OCA\Social\Db\ActorsRequest;
use OCA\Social\Db\FollowsRequest;
use OCA\Social\Db\NotesRequest;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\EmptyQueueException;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\NoHighPriorityRequestException;
use OCA\Social\Exceptions\QueueStatusException;
use OCA\Social\Exceptions\RequestException;
use OCA\Social\Exceptions\SignatureException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Activity\Create;
use OCA\Social\Model\ActivityPub\Activity\Delete;
use OCA\Social\Model\ActivityPub\Activity\Tombstone;
use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Model\InstancePath;
use OCA\Social\Model\RequestQueue;
use OCA\Social\Service\ActivityPub\PersonService;
use OCP\IRequest;
@ -68,6 +73,7 @@ class ActivityService {
const DATE_FORMAT = 'D, d M Y H:i:s T';
const DATE_DELAY = 30;
/** @var ActorsRequest */
private $actorsRequest;
@ -77,6 +83,9 @@ class ActivityService {
/** @var FollowsRequest */
private $followsRequest;
/** @var QueueService */
private $queueService;
/** @var ActorService */
private $actorService;
@ -99,6 +108,7 @@ class ActivityService {
/**
* ActivityService constructor.
*
* @param QueueService $queueService
* @param ActorsRequest $actorsRequest
* @param NotesRequest $notesRequest
* @param FollowsRequest $followsRequest
@ -111,15 +121,15 @@ class ActivityService {
*/
public function __construct(
ActorsRequest $actorsRequest, NotesRequest $notesRequest, FollowsRequest $followsRequest,
CurlService $curlService, ActorService $actorService,
QueueService $queueService, CurlService $curlService, ActorService $actorService,
PersonService $personService, InstanceService $instanceService,
ConfigService $configService,
MiscService $miscService
ConfigService $configService, MiscService $miscService
) {
$this->curlService = $curlService;
$this->actorsRequest = $actorsRequest;
$this->notesRequest = $notesRequest;
$this->followsRequest = $followsRequest;
$this->queueService = $queueService;
$this->curlService = $curlService;
$this->actorService = $actorService;
$this->personService = $personService;
$this->instanceService = $instanceService;
@ -133,13 +143,11 @@ class ActivityService {
* @param ACore $item
* @param ACore $activity
*
* @return array
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
* @return string
* @throws Exception
*/
public function createActivity(Person $actor, ACore $item, ACore &$activity = null
): array {
): string {
$activity = new Create();
$item->setParent($activity);
@ -158,20 +166,17 @@ class ActivityService {
$activity->setActor($actor);
$result = $this->request($activity);
return $result;
return $this->request($activity);
}
/**
* @param ACore $item
*
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
* @return string
* @throws Exception
*/
public function deleteActivity(ACore $item) {
public function deleteActivity(ACore $item): string {
$delete = new Delete();
$delete->setId($item->getId() . '#delete');
$delete->setActorId($item->getActorId());
@ -182,7 +187,7 @@ class ActivityService {
$delete->setObject($tombstone);
$delete->addInstancePaths($item->getInstancePaths());
$this->request($delete);
return $this->request($delete);
}
@ -217,61 +222,91 @@ class ActivityService {
/**
* @param ACore $activity
*
* @return string
* @throws Exception
*/
public function request(ACore $activity): string {
$this->setupCore($activity);
$author = $this->getAuthorFromItem($activity);
$instancePaths = $this->generateInstancePaths($activity);
$token = $this->queueService->generateRequestQueue($instancePaths, $activity, $author);
try {
$directRequest = $this->queueService->getPriorityRequest($token);
$this->manageRequest($directRequest);
} catch (NoHighPriorityRequestException $e) {
} catch (EmptyQueueException $e) {
return '';
}
$this->curlService->asyncWithToken($token);
return $token;
}
/**
* @param RequestQueue $queue
*
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
*/
public function manageRequest(ACore $activity) {
$result = $this->request($activity);
$this->miscService->log('Activity: ' . json_encode($activity));
$this->miscService->log('Result: ' . json_encode($result));
public function manageRequest(RequestQueue $queue) {
try {
$this->queueService->initRequest($queue);
} catch (QueueStatusException $e) {
return;
}
$result = $this->generateRequest(
$queue->getInstance(), $queue->getActivity(), $queue->getAuthor()
);
try {
if ($this->getint('_code', $result, 500) === 202) {
$this->queueService->endRequest($queue, true);
} else {
$this->queueService->endRequest($queue, false);
}
} catch (QueueStatusException $e) {
}
}
/**
* @param ACore $activity
*
*
* @return array
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
* @return InstancePath[]
*/
public function request(ACore &$activity) {
$this->setupCore($activity);
// $hosts = $this->instanceService->getInstancesFromActivity($activity);
$result = [];
// foreach ($hosts as $host) {
// foreach ($host->getInstancePaths() as $path) {
private function generateInstancePaths(ACore $activity): array {
$instancePaths = [];
foreach ($activity->getInstancePaths() as $instancePath) {
if ($instancePath->getType() === InstancePath::TYPE_FOLLOWERS) {
$result = array_merge($result, $this->requestToFollowers($activity, $instancePath));
$instancePaths = array_merge(
$instancePaths, $this->generateInstancePathsFollowers($instancePath)
);
} else {
$result[] = $this->generateRequest($instancePath, $activity);
$instancePaths[] = $instancePath;
}
}
// }
return $result;
return $instancePaths;
}
/**
* @param ACore $activity
* @param InstancePath $instancePath
*
* @return array
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
* @return InstancePath[]
*/
private function requestToFollowers(ACore &$activity, InstancePath $instancePath): array {
$result = [];
private function generateInstancePathsFollowers(InstancePath $instancePath): array {
$follows = $this->followsRequest->getByFollowId($instancePath->getUri());
$sharedInboxes = [];
$follows = $this->followsRequest->getByFollowId($instancePath->getUri());
$instancePaths = [];
foreach ($follows as $follow) {
if (!$follow->gotActor()) {
// TODO - check if cache can be empty at this point ?
@ -285,28 +320,32 @@ class ActivityService {
}
$sharedInboxes[] = $sharedInbox;
$result[] = $this->generateRequest(
new InstancePath($sharedInbox, InstancePath::TYPE_GLOBAL), $activity
$instancePaths[] = new InstancePath(
$sharedInbox, InstancePath::TYPE_GLOBAL, $instancePath->getPriority()
);
// $result[] = $this->generateRequest(
// new InstancePath($sharedInbox, InstancePath::TYPE_GLOBAL), $activity
// );
}
return $result;
return $instancePaths;
}
/**
* @param InstancePath $path
* @param ACore $activity
* @param string $activity
* @param string $author
*
* @return Request[]
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
*/
public function generateRequest(InstancePath $path, ACore $activity): array {
$document = json_encode($activity);
public function generateRequest(InstancePath $path, string $activity, string $author): array {
// $document = json_encode($activity);
$date = gmdate(self::DATE_FORMAT);
$localActor = $this->getActorFromItem($activity);
$localActor = $this->getActorFromAuthor($author);
$localActorLink =
$this->configService->getUrlSocial() . '@' . $localActor->getPreferredUsername();
@ -332,7 +371,7 @@ class ActivityService {
$request->addHeader('Date: ' . $date);
$request->addHeader('Signature: ' . $header);
$request->setDataJson($document);
$request->setDataJson($activity);
$request->setAddress($path->getAddress());
return $this->curlService->request($request);
@ -362,18 +401,27 @@ class ActivityService {
/**
* @param ACore $activity
*
* @return Person
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
* @return string
*/
private function getActorFromItem(Acore $activity): Person {
private function getAuthorFromItem(Acore $activity): string {
if ($activity->gotActor()) {
return $activity->getActor();
return $activity->getActor()
->getId();
}
$actorId = $activity->getActorId();
return $activity->getActorId();
}
return $this->actorService->getActorById($actorId);
/**
* @param string $author
*
* @return Person
* @throws ActorDoesNotExistException
* @throws SocialAppConfigException
*/
private function getActorFromAuthor(string $author): Person {
return $this->actorService->getActorById($author);
}
@ -456,8 +504,10 @@ class ActivityService {
* @param $keyId
*
* @return string
* @throws RequestException
* @throws InvalidResourceException
* @throws RequestException
* @throws SocialAppConfigException
* @throws UrlCloudException
*/
private function retrieveKey($keyId): string {
$actor = $this->personService->getFromId($keyId);
@ -467,6 +517,8 @@ class ActivityService {
/**
* @deprecated !??? - do we need this !?
*
* @param ACore $activity
*/
private function setupCore(ACore $activity) {

Wyświetl plik

@ -52,11 +52,18 @@ class ConfigService {
const SOCIAL_ADDRESS = 'address';
const SOCIAL_SERVICE = 'service';
const SOCIAL_MAX_SIZE = 'max_size';
const BACKGROUND_CRON = 1;
const BACKGROUND_ASYNC = 2;
const BACKGROUND_SERVICE = 3;
const BACKGROUND_FULL_SERVICE = 4;
/** @var array */
public $defaults = [
self::SOCIAL_ADDRESS => '',
self::SOCIAL_SERVICE => 1,
self::SOCIAL_MAX_SIZE => 25
];

Wyświetl plik

@ -31,11 +31,24 @@ namespace OCA\Social\Service;
use daita\MySmallPhpTools\Model\Request;
use daita\MySmallPhpTools\Traits\TArrayTools;
use daita\MySmallPhpTools\Traits\TPathTools;
use OCA\Social\Exceptions\RequestException;
use OCA\Social\Exceptions\SocialAppConfigException;
class CurlService {
use TArrayTools;
use TPathTools;
const ASYNC_TOKEN = '/async/token/{token}';
/** @var ConfigService */
private $configService;
/** @var MiscService */
private $miscService;
@ -43,9 +56,11 @@ class CurlService {
/**
* CurlService constructor.
*
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(MiscService $miscService) {
public function __construct(ConfigService $configService, MiscService $miscService) {
$this->configService = $configService;
$this->miscService = $miscService;
}
@ -89,6 +104,29 @@ class CurlService {
}
/**
* @param string $token
*
* @throws SocialAppConfigException
*/
public function asyncWithToken(string $token) {
$address = $this->configService->getUrlSocial();
$parse = parse_url($address);
$host = $this->get('host', $parse, '');
$path = $this->withEndSlash($this->get('path', $parse, '')) . $this->withoutBeginSlash(
self::ASYNC_TOKEN
);
$path = str_replace('{token}', $token, $path);
$request = new Request($path, Request::TYPE_POST);
$request->setAddress($host);
try {
$this->request($request);
} catch (RequestException $e) {
}
}
/**
* @param Request $request
*

Wyświetl plik

@ -71,6 +71,7 @@ class ImportService {
/** @var DeleteService */
private $deleteService;
/** @var ConfigService */
private $configService;
/** @var MiscService */

Wyświetl plik

@ -30,6 +30,7 @@ declare(strict_types=1);
namespace OCA\Social\Service;
use Exception;
use OC\User\NoUserException;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\RequestException;
@ -77,20 +78,20 @@ class PostService {
* @param Post $post
* @param ACore $activity
*
* @return array
* @return string
* @throws ActorDoesNotExistException
* @throws NoUserException
* @throws RequestException
* @throws SocialAppConfigException
* @throws Exception
*/
public function createPost(Post $post, ACore &$activity = null) {
public function createPost(Post $post, ACore &$activity = null): string {
$note =
$this->noteService->generateNote(
$post->getUserId(), $post->getContent(), $post->getType()
);
$this->noteService->addRecipients($note, $post->getType(), $post->getTo());
$this->noteService->replyTo($note, $post->getReplyTo());
$this->noteService->addRecipients($note, $post->getType(), $post->getTo());
$actor = $this->actorService->getActorFromUserId($post->getUserId());

Wyświetl plik

@ -0,0 +1,191 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Social Support
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Social\Service;
use daita\MySmallPhpTools\Traits\TArrayTools;
use Exception;
use OCA\Social\Db\RequestQueueRequest;
use OCA\Social\Exceptions\EmptyQueueException;
use OCA\Social\Exceptions\NoHighPriorityRequestException;
use OCA\Social\Exceptions\QueueStatusException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\InstancePath;
use OCA\Social\Model\RequestQueue;
class QueueService {
use TArrayTools;
/** @var RequestQueueRequest */
private $requestQueueRequest;
/** @var ConfigService */
private $configService;
/** @var MiscService */
private $miscService;
/**
* QueueService constructor.
*
* @param RequestQueueRequest $requestQueueRequest
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
RequestQueueRequest $requestQueueRequest, ConfigService $configService,
MiscService $miscService
) {
$this->requestQueueRequest = $requestQueueRequest;
$this->configService = $configService;
$this->miscService = $miscService;
}
/**
* @param array $instancePaths
* @param ACore $item
*
* @return string
* @throws Exception
*/
public function generateRequestQueue(array $instancePaths, ACore $item, string $author
): string {
$activity = json_encode($item, JSON_UNESCAPED_SLASHES);
$token = '';
$requests = [];
foreach ($instancePaths as $instancePath) {
$request = new RequestQueue($activity, $instancePath, $author);
if ($token === '') {
$token = $request->getToken();
} else {
$request->setToken($token);
}
$requests[] = $request;
}
$this->requestQueueRequest->multiple($requests);
return $token;
}
/**
* @param string $token
*
* @return RequestQueue
* @throws EmptyQueueException
* @throws NoHighPriorityRequestException
*/
public function getPriorityRequest(string $token): RequestQueue {
$requests = $this->requestQueueRequest->getFromToken($token);
if (sizeof($requests) === 0) {
throw new EmptyQueueException();
}
$request = $requests[0];
switch ($request->getPriority()) {
case InstancePath::PRIORITY_TOP:
return $request;
case InstancePath::PRIORITY_HIGH:
if (sizeof($requests) === 1) {
return $request;
}
$next = $requests[1];
if ($next->getStatus() < InstancePath::PRIORITY_HIGH) {
return $request;
}
break;
case InstancePath::PRIORITY_MEDIUM:
if (sizeof($requests) === 1) {
return $request;
}
break;
}
throw new NoHighPriorityRequestException();
}
/**
* @param string $token
* @param int $status
*
* @return array
*/
public function getRequestFromToken(string $token, int $status = -1): array {
if ($token === '') {
return [];
}
return $this->requestQueueRequest->getFromToken($token, $status);
}
/**
* @param RequestQueue $queue
*
* @throws QueueStatusException
*/
public function initRequest(RequestQueue $queue) {
$this->requestQueueRequest->setAsRunning($queue);
}
/**
* @param RequestQueue $queue
* @param bool $success
*
* @throws QueueStatusException
*/
public function endRequest(RequestQueue $queue, bool $success) {
if ($success === true) {
$this->requestQueueRequest->setAsSuccess($queue);
} else {
$this->requestQueueRequest->setAsFailure($queue);
}
}
}