1<?php
2
3declare(strict_types=1);
4/**
5 * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com>
6 *
7 * @license GNU AGPL version 3 or any later version
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24namespace OCA\Talk\Service;
25
26use OCA\Talk\Model\Attendee;
27use OCA\Talk\Model\Session;
28use OCA\Talk\Model\SessionMapper;
29use OCP\DB\Exception;
30use OCP\DB\QueryBuilder\IQueryBuilder;
31use OCP\IDBConnection;
32use OCP\Security\ISecureRandom;
33
34class SessionService {
35	/** @var SessionMapper */
36	protected $sessionMapper;
37	/** @var IDBConnection */
38	protected $connection;
39	/** @var ISecureRandom */
40	protected $secureRandom;
41
42	public function __construct(SessionMapper $sessionMapper,
43								IDBConnection $connection,
44								ISecureRandom $secureRandom) {
45		$this->sessionMapper = $sessionMapper;
46		$this->connection = $connection;
47		$this->secureRandom = $secureRandom;
48	}
49
50	/**
51	 * Update last ping for multiple sessions
52	 *
53	 * Since this function is called by the HPB with potentially hundreds of
54	 * sessions, we do not use the SessionMapper to get the entities first, as
55	 * that would just not scale good enough.
56	 *
57	 * @param string[] $sessionIds
58	 * @param int $lastPing
59	 */
60	public function updateMultipleLastPings(array $sessionIds, int $lastPing): void {
61		$update = $this->connection->getQueryBuilder();
62		$update->update('talk_sessions')
63			->set('last_ping', $update->createNamedParameter($lastPing, IQueryBuilder::PARAM_INT))
64			->where($update->expr()->in('session_id', $update->createNamedParameter($sessionIds, IQueryBuilder::PARAM_STR_ARRAY)));
65
66		$update->executeStatement();
67	}
68
69	public function updateLastPing(Session $session, int $lastPing): void {
70		$session->setLastPing($lastPing);
71		$this->sessionMapper->update($session);
72	}
73
74	/**
75	 * @param int[] $ids
76	 */
77	public function deleteSessionsById(array $ids): void {
78		$this->sessionMapper->deleteByIds($ids);
79	}
80
81	/**
82	 * @param Attendee $attendee
83	 * @return Session[]
84	 */
85	public function getAllSessionsForAttendee(Attendee $attendee): array {
86		return $this->sessionMapper->findByAttendeeId($attendee->getId());
87	}
88
89	/**
90	 * @param Attendee $attendee
91	 * @param string $forceSessionId
92	 * @return Session
93	 * @throws Exception
94	 */
95	public function createSessionForAttendee(Attendee $attendee, string $forceSessionId = ''): Session {
96		$session = new Session();
97		$session->setAttendeeId($attendee->getId());
98
99		if ($forceSessionId !== '') {
100			$session->setSessionId($forceSessionId);
101			$this->sessionMapper->insert($session);
102		} else {
103			while (true) {
104				$sessionId = $this->secureRandom->generate(255);
105				$session->setSessionId($sessionId);
106				try {
107					$this->sessionMapper->insert($session);
108					break;
109				} catch (Exception $e) {
110					// 255 chars are not unique? Try again...
111					if ($e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
112						throw $e;
113					}
114				}
115			}
116		}
117
118		return $session;
119	}
120}
121