events processing changed: treat events chronologically (except for the first time, to avoid looping throug all history), phpdoc, custom update period
This commit is contained in:
parent
5e86865841
commit
f4efe4aefc
@ -25,6 +25,7 @@ $cb = function($event)
|
||||
$m = new MatrixClient("https://domain.tld");
|
||||
//$m->login_with_password("@bot:domain.tld", "password");
|
||||
//echo $m->get_access_token() . "\n";
|
||||
$m->set_update_period(0.5);
|
||||
$m->login_with_token("@bot:domain.tld", "token");
|
||||
$room = $m->join_room("!roomname:domain.tld");
|
||||
//$room->send_text("pouet");
|
||||
|
145
phpmatrix.php
145
phpmatrix.php
@ -2,12 +2,24 @@
|
||||
|
||||
class MatrixClient
|
||||
{
|
||||
/** @var string Matrix server (https://domain.tld) */
|
||||
private $matrix_server;
|
||||
private $rooms;
|
||||
private $transaction_id;
|
||||
/** @var string MXID (@login:domain.tld) */
|
||||
private $mxid;
|
||||
private $access_token;
|
||||
|
||||
/** @var MatrixRoom[] List of subscribed rooms */
|
||||
private $rooms;
|
||||
|
||||
/** @var int API transaction ID */
|
||||
private $transaction_id;
|
||||
/** @var string API Access token */
|
||||
private $access_token;
|
||||
/** @var int Update period in microseconds */
|
||||
private $update_period = 1000000;
|
||||
|
||||
/**
|
||||
* @param string $matrix_server Matrix server (https://domain.tld)
|
||||
*/
|
||||
function __construct($matrix_server)
|
||||
{
|
||||
$this->matrix_server = $matrix_server;
|
||||
@ -17,23 +29,47 @@ class MatrixClient
|
||||
$this->transaction_id = microtime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
private function get_new_transaction_id()
|
||||
{
|
||||
$this->transaction_id = microtime();
|
||||
return $this->transaction_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_access_token()
|
||||
{
|
||||
return $this->access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_mxid()
|
||||
{
|
||||
return $this->mxid;
|
||||
}
|
||||
|
||||
function login_with_password($mxid, $password)
|
||||
/**
|
||||
* Change update period (for events update)
|
||||
* @param float $seconds Period in seconds
|
||||
*/
|
||||
public function set_update_period($seconds)
|
||||
{
|
||||
$this->update_period = intval($seconds * 1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to login to Matrix API and get an access token.
|
||||
* Will throw a MatrixRequestException if it fails
|
||||
* @param string $mxid client's login (@login:domain.tld)
|
||||
* @param string $password client's password
|
||||
*/
|
||||
public function login_with_password($mxid, $password)
|
||||
{
|
||||
$this->mxid = $mxid;
|
||||
|
||||
@ -54,13 +90,17 @@ class MatrixClient
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string $url_path: path after the TLD
|
||||
* @var string $method: GET, PUT, POST
|
||||
* @var string[] $body: array of key/values for POST/PUT
|
||||
* @var string[] $params: URL params
|
||||
* @var bool $require_token: if true, access_token needed
|
||||
* Query to the Matrix API
|
||||
* Will throw a MatrixRequestException if it fails
|
||||
* TODO: change default timeouts?
|
||||
* @param string $url_path: path after the Matrix server
|
||||
* @param string $method: GET, PUT, POST
|
||||
* @param string[] $body: array of key/values for POST/PUT
|
||||
* @param string[] $params: URL params
|
||||
* @param bool $require_token: if true, access_token needed
|
||||
* @return string[] json decoded response
|
||||
*/
|
||||
function query($url_path, $method="GET", $body=null, $params=null, $require_token=true)
|
||||
public function query($url_path, $method="GET", $body=null, $params=null, $require_token=true)
|
||||
{
|
||||
if (!$this->access_token && $require_token) {
|
||||
throw new MatrixRequestException("Missing access token", 0);
|
||||
@ -111,7 +151,14 @@ class MatrixClient
|
||||
return $res;
|
||||
}
|
||||
|
||||
function send_room_event($room_id, $event_type, $body)
|
||||
/**
|
||||
* Send a room event
|
||||
* @param string $room_id Room ID (!xxxxxx:domain.tld. #alias:domain.tld seems to fail)
|
||||
* @param string $event_type Event type (e.g. m.room.message)
|
||||
* @param string[] $body key-value array
|
||||
* @return string[] json decoded response
|
||||
*/
|
||||
public function send_room_event($room_id, $event_type, $body)
|
||||
{
|
||||
$txn_id = $this->get_new_transaction_id();
|
||||
$room_id = curl_escape($this->ch, $room_id);
|
||||
@ -120,20 +167,24 @@ class MatrixClient
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string $mxid: mxid (@xxxx:yyyy.zz) to identify the user
|
||||
* @var string $access_token: the access token returned by a login
|
||||
* Will just store the mxid/access token
|
||||
* TODO: check if token valid?
|
||||
* @param string $mxid: mxid (@xxxx:yyyy.zz) to identify the user
|
||||
* @param string $access_token: the access token returned by a login
|
||||
*/
|
||||
function login_with_token($mxid, $access_token)
|
||||
public function login_with_token($mxid, $access_token)
|
||||
{
|
||||
$this->mxid = $mxid;
|
||||
$this->access_token = $access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var string $room_id room id or alias (#xxxx:yyy.zz)
|
||||
* Subscribe to a room: will allow to receive/send events from/to this room
|
||||
* NB: the user has to have already join the room
|
||||
* @param string $room_id room id or alias (#xxxx:yyy.zz)
|
||||
* @return MatrixRoom
|
||||
*/
|
||||
function join_room($room_id)
|
||||
public function join_room($room_id)
|
||||
{
|
||||
$room = new MatrixRoom($this, $room_id);
|
||||
$this->rooms[$room_id] = $room;
|
||||
@ -141,13 +192,16 @@ class MatrixClient
|
||||
return $room;
|
||||
}
|
||||
|
||||
function run()
|
||||
/**
|
||||
* Blocking loop to get rooms' events
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while (true) {
|
||||
foreach ($this->rooms as $room) {
|
||||
$room->get_events();
|
||||
}
|
||||
usleep(500000);
|
||||
usleep($this->update_period);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -171,6 +225,10 @@ class MatrixEvent
|
||||
public $user_id;
|
||||
public $age;
|
||||
|
||||
/**
|
||||
* @param MatrixRoom $room the room that received the event
|
||||
* @param string[] $contents the event's contents
|
||||
*/
|
||||
function __construct($room, $contents)
|
||||
{
|
||||
$this->room = $room;
|
||||
@ -178,6 +236,7 @@ class MatrixEvent
|
||||
$this->sender = $contents["sender"];
|
||||
$this->content = $contents["content"];
|
||||
$this->event_id = $contents["event_id"];
|
||||
// TODO: convert to datetime?
|
||||
$this->origin_server_ts = $contents["origin_server_ts"];
|
||||
$this->user_id = $contents["user_id"];
|
||||
$this->age = isset($contents["age"]) ? $contents["age"] : null;
|
||||
@ -191,6 +250,10 @@ class MatrixRoom
|
||||
private $listeners = [];
|
||||
private $last_end_token = null;
|
||||
|
||||
/**
|
||||
* @param MatrixClient $client
|
||||
* @param string $room_id
|
||||
*/
|
||||
function __construct($client, $room_id)
|
||||
{
|
||||
$this->client = $client;
|
||||
@ -198,14 +261,23 @@ class MatrixRoom
|
||||
}
|
||||
|
||||
/**
|
||||
* @var $callback function(room, event)
|
||||
* Add an event listener: will be called each time we received a room's event
|
||||
* NB: logged-in user's events are ignored
|
||||
* TODO: param to allow them?
|
||||
* @param $callback function(room, event)
|
||||
*/
|
||||
function add_listener($callback)
|
||||
public function add_listener($callback)
|
||||
{
|
||||
$this->listeners[] = $callback;
|
||||
}
|
||||
|
||||
function send_text($text)
|
||||
/**
|
||||
* Helper to send a simple text message (m.room.message with a text body)
|
||||
* Will throw a MatrixRequest Exception if it fails
|
||||
* @param string $text the raw text
|
||||
* @return string[] json decoded response
|
||||
*/
|
||||
public function send_text($text)
|
||||
{
|
||||
$body = [
|
||||
"body" => $text,
|
||||
@ -214,7 +286,14 @@ class MatrixRoom
|
||||
return $this->client->send_room_event($this->room_id, "m.room.message", $body);
|
||||
}
|
||||
|
||||
function send_html($html)
|
||||
/**
|
||||
* Helper to send a simple html message (m.room.message with html body)
|
||||
* TODO: text body too? (RTFM)
|
||||
* Will throw a MatrixRequest Exception if it fails
|
||||
* @param string $html the HTML
|
||||
* @return string[] json decoded response
|
||||
*/
|
||||
public function send_html($html)
|
||||
{
|
||||
$body = [
|
||||
"body" => $text,
|
||||
@ -223,15 +302,23 @@ class MatrixRoom
|
||||
return $this->client->send_room_event($this->room_id, "m.room.message", $body);
|
||||
}
|
||||
|
||||
function get_events()
|
||||
/**
|
||||
* Read the room's last X events
|
||||
* TODO: param to change the limit
|
||||
*/
|
||||
public function get_events()
|
||||
{
|
||||
$params = [
|
||||
"limit" => 10,
|
||||
"dir" => "b",
|
||||
"dir" => $this->last_end_token ? "f" : "b",
|
||||
];
|
||||
|
||||
// (a bit dirty) trick:
|
||||
// First time: get events in reverse order (most recent first) to get the last token (start)
|
||||
// After that: get events chronologically (oldest first) with the end token
|
||||
|
||||
if ($this->last_end_token) {
|
||||
$params["to"] = $this->last_end_token;
|
||||
$params["from"] = $this->last_end_token;
|
||||
}
|
||||
|
||||
$room_id = curl_escape($this->client->ch, $this->room_id);
|
||||
@ -240,9 +327,13 @@ class MatrixRoom
|
||||
"GET", null, $params);
|
||||
|
||||
$dispatch_events = $this->last_end_token !== null;
|
||||
$this->last_end_token = $res["start"];
|
||||
if (!$this->last_end_token) {
|
||||
$this->last_end_token = $res["start"];
|
||||
} elseif (isset($res["end"])) {
|
||||
$this->last_end_token = $res["end"];
|
||||
}
|
||||
|
||||
// First time we get events: do nothing
|
||||
// First time we get events : do nothing (it's history)
|
||||
if ($dispatch_events) {
|
||||
foreach ($res["chunk"] as $event) {
|
||||
foreach ($this->listeners as $listener) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user