sendMessage("!roomid:matrix.org", "Hello!"); * * @package Aryess\PhpMatrixSdk */ class MatrixHttpApi { const MATRIX_V2_API_PATH = "/_matrix/client/r0"; /** * @var string */ private $baseUrl; /** * @var string|null */ private $token; /** * @var string|null */ private $identity; /** * @var int */ private $default429WaitMs; /** * @var bool */ private $useAuthorizationHeader; /** * @var int */ private $txnId; /** * @var bool */ private $vallidateCert; /** * @var Client */ private $client; /** * MatrixHttpApi constructor. * * @param string $baseUrl The home server URL e.g. 'http://localhost:8008' * @param string|null $token Optional. The client's access token. * @param string|null $identity Optional. The mxid to act as (For application services only). * @param int $default429WaitMs Optional. Time in milliseconds to wait before retrying a request * when server returns a HTTP 429 response without a 'retry_after_ms' key. * @param bool $useAuthorizationHeader Optional. Use Authorization header instead of access_token query parameter. * @throws MatrixException */ public function __construct(string $baseUrl, ?string $token = null, ?string $identity = null, int $default429WaitMs = 5000, bool $useAuthorizationHeader = true) { if (!filter_var($baseUrl, FILTER_VALIDATE_URL)) { throw new MatrixException("Invalid homeserver url $baseUrl"); } if (!array_get(parse_url($baseUrl), 'scheme')) { throw new MatrixException("No scheme in homeserver url $baseUrl"); } $this->baseUrl = $baseUrl; $this->token = $token; $this->identity = $identity; $this->txnId = 0; $this->vallidateCert = true;//FIXME: use config $this->client = new Client(); $this->default429WaitMs = $default429WaitMs; $this->useAuthorizationHeader = $useAuthorizationHeader; } public function setClient(Client $client) { $this->client = $client; } /** * @param string|null $since Optional. A token which specifies where to continue a sync from. * @param int $timeoutMs * @param null $filter * @param bool $fullState * @param string|null $setPresence * @return array|string * @throws MatrixException * @throws \GuzzleHttp\Exception\GuzzleException */ public function sync(?string $since = null, int $timeoutMs = 30000, $filter = null, bool $fullState = false, ?string $setPresence = null) { $request = [ 'timeout' => (int)$timeoutMs, ]; if ($since) { $request['since'] = $since; } if ($filter) { $request['filter'] = $filter; } if ($fullState) { $request['full_state'] = json_encode($fullState); } if ($setPresence) { $request['set_presence'] = $setPresence; } return $this->send('GET', "/sync", null, $request); } public function validateCertificate(bool $validity) { $this->vallidateCert = $validity; } /** * Performs /register. * * @param array $authBody Authentication Params. * @param string $kind Specify kind of account to register. Can be 'guest' or 'user'. * @param bool $bindEmail Whether to use email in registration and authentication. * @param string|null $username The localpart of a Matrix ID. * @param string|null $password The desired password of the account. * @param string|null $deviceId ID of the client device. * @param string|null $initialDeviceDisplayName Display name to be assigned. * @param bool $inhibitLogin Whether to login after registration. Defaults to false. */ public function register(array $authBody = [], string $kind = "user", bool $bindEmail = false, ?string $username = null, ?string $password = null, ?string $deviceId = null, ?string $initialDeviceDisplayName = null, bool $inhibitLogin = false) { $content = [ 'kind' => $kind ]; if ($authBody) { $content['auth'] = $authBody; } if ($username) { $content['username'] = $username; } if ($password) { $content['password'] = $password; } if ($deviceId) { $content['device_id'] = $deviceId; } if ($initialDeviceDisplayName) { $content['initial_device_display_name'] = $initialDeviceDisplayName; } if ($bindEmail) { $content['bind_email'] = $bindEmail; } if ($inhibitLogin) { $content['inhibit_login'] = $inhibitLogin; } return $this->send('POST', '/register', $content, ['kind' => $kind]); } public function getDisplayName(string $userId): ?string { $content = $this->send("GET", "/profile/$userId/displayname"); return array_get($content, 'displayname', json_encode($content)); } /** * @param string $method * @param string $path * @param mixed $content * @param array $queryParams * @param array $headers * @param string $apiPath * @param bool $returnJson * @return array|string * @throws MatrixException * @throws \GuzzleHttp\Exception\GuzzleException */ private function send(string $method, string $path, $content = null, array $queryParams = [], array $headers = [], $apiPath = self::MATRIX_V2_API_PATH, $returnJson = true) { $options = []; if (!in_array('User-Agent', $headers)) { $headers['User-Agent'] = 'php-matrix-sdk/0.0.1-dev'; //TODO: add version } $method = strtoupper($method); if (!in_array($method, ['GET', 'POST', 'PUT', 'DELETE'])) { throw new MatrixException("Unsupported HTTP method: $method"); } if (!in_array('Content-Type', $headers)) { $headers['Content-Type'] = 'application/json'; } if ($this->useAuthorizationHeader) { $headers['Authorization'] = sprintf('Bearer %s', $this->token); } else { $queryParams['access_token'] = $this->token; } if ($this->identity) { $queryParams['user_id'] = $this->identity; } $endpoint = $this->baseUrl . $apiPath . $path; if ($headers['Content-Type'] == "application/json" && $content != null) { $content = json_encode($content); } $options = array_merge($options, [ 'headers' => $headers, 'query' => $queryParams, 'body' => $content, 'verify' => $this->vallidateCert, ]); $responseBody = ''; while (true) { try { $response = $this->client->request($method, $endpoint, $options); } catch (RequestException $e) { throw new MatrixHttpLibException($e, $method, $endpoint); } if ($response->getStatusCode() != 429) { $responseBody = $response->getBody()->getContents(); break; } $jsonResponse = json_decode($responseBody, true); $waitTime = array_get($jsonResponse, 'retry_after_ms'); $waitTime = $waitTime ?: array_get($jsonResponse, 'error.retry_after_ms', $this->default429WaitMs); $waitTime /= 1000; sleep($waitTime); } if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { throw new MatrixRequestException($response->getStatusCode(), $responseBody); } return $returnJson ? json_decode($responseBody, true) : $responseBody; } }