Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BufferInfo and Message to represent complex data types #41

Merged
merged 3 commits into from
Jun 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,10 @@ anything about it.

There are only few noticable exceptions to this rule:

* Incoming chat messages use a plain Unix timestamp integers, while all other
`data` events usually use `DateTime` objects.
This library always converts this to `DateTime` for consistency reasons.
* Incoming buffers/channels and chat messages use complex data models, so they
are represented by `BufferInfo` and `Message` respectively. All other data
types use plain structured data, so you can access it's array-based
structure very similar to a JSON-like data structure.
* The legacy protocol uses plain times for heartbeat messages while the newer
datastream protocol uses `DateTime` objects.
This library always converts this to `DateTime` for consistency reasons.
Expand Down
10 changes: 6 additions & 4 deletions examples/02-chatbot.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Clue\React\Quassel\Factory;
use Clue\React\Quassel\Client;
use Clue\React\Quassel\Io\Protocol;
use Clue\React\Quassel\Models\Message;

require __DIR__ . '/../vendor/autoload.php';

Expand Down Expand Up @@ -42,12 +43,13 @@

// chat message received
if (isset($message[0]) && $message[0] === Protocol::REQUEST_RPCCALL && $message[1] === '2displayMsg(Message)') {
$data = $message[2];
$in = $message[2];
assert($in instanceof Message);

if (strpos($data['content'], $keyword) !== false) {
$client->writeBufferInput($data['bufferInfo'], 'Hello from clue/quassel-react :-)');
if (strpos($in->getContents(), $keyword) !== false) {
$client->writeBufferInput($in->getBufferInfo(), 'Hello from clue/quassel-react :-)');

echo date('Y-m-d H:i:s') . ' Replied to ' . $data['bufferInfo']['name'] . '/' . explode('!', $data['sender'], 2)[0] . ': "' . $data['content'] . '"' . PHP_EOL;
echo date('Y-m-d H:i:s') . ' Replied to ' . $in->getBufferInfo()->getName() . '/' . explode('!', $in->getSender())[0] . ': "' . $in->getContents() . '"' . PHP_EOL;
}
}
});
Expand Down
17 changes: 10 additions & 7 deletions examples/03-pingbot.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use Clue\React\Quassel\Factory;
use Clue\React\Quassel\Client;
use Clue\React\Quassel\Io\Protocol;
use Clue\React\Quassel\Models\BufferInfo;
use Clue\React\Quassel\Models\Message;

require __DIR__ . '/../vendor/autoload.php';

Expand Down Expand Up @@ -64,27 +66,28 @@

// chat message received
if (isset($message[0]) && $message[0] === Protocol::REQUEST_RPCCALL && $message[1] === '2displayMsg(Message)') {
$data = $message[2];
$in = $message[2];
assert($in instanceof Message);
$reply = null;

// we may be connected to multiple networks with different nicks
// find correct nick for current network
$nick = isset($nicks[$data['bufferInfo']['network']]) ? $nicks[$data['bufferInfo']['network']] : null;
$nick = isset($nicks[$in->getBufferInfo()->getNetworkId()]) ? $nicks[$in->getBufferInfo()->getNetworkId()] : null;

// received "nick: ping" in any buffer/channel
if ($nick !== null && strtolower($data['content']) === ($nick . ': ping')) {
$reply = explode('!', $data['sender'], 2)[0] . ': pong :-)';
if ($nick !== null && strtolower($in->getContents()) === ($nick . ': ping')) {
$reply = explode('!', $in->getSender())[0] . ': pong :-)';
}

// received "ping" in direct query buffer (user to user)
if (strtolower($data['content']) === 'ping' && $data['bufferInfo']['type'] === 0x04) {
if (strtolower($in->getContents()) === 'ping' && $in->getBufferInfo()->getType() === BufferInfo::TYPE_QUERY) {
$reply = 'pong :-)';
}

if ($reply !== null) {
$client->writeBufferInput($data['bufferInfo'], $reply);
$client->writeBufferInput($in->getBufferInfo(), $reply);

echo date('Y-m-d H:i:s') . ' Replied to ' . $data['bufferInfo']['name'] . '/' . explode('!', $data['sender'], 2)[0] . ': "' . $data['content'] . '"' . PHP_EOL;
echo date('Y-m-d H:i:s') . ' Replied to ' . $in->getBufferInfo()->getName() . '/' . explode('!', $in->getSender())[0] . ': "' . $in->getContents() . '"' . PHP_EOL;
}
}
});
Expand Down
14 changes: 9 additions & 5 deletions examples/04-connect.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use Clue\React\Quassel\Factory;
use Clue\React\Quassel\Client;
use Clue\React\Quassel\Io\Protocol;
use Clue\React\Quassel\Models\Message;
use Clue\React\Quassel\Models\BufferInfo;

require __DIR__ . '/../vendor/autoload.php';

Expand Down Expand Up @@ -36,9 +38,10 @@
}

foreach ($message['SessionState']['BufferInfos'] as $buffer) {
if ($buffer['type'] === 2) { // type == 4 for user
var_dump('requesting IrcChannel for ' . $buffer['name']);
$client->writeInitRequest('IrcChannel', $buffer['network'] . '/' . $buffer['id']);
assert($buffer instanceof BufferInfo);
if ($buffer->getType() === BufferInfo::TYPE_CHANNEL) {
var_dump('requesting IrcChannel for ' . $buffer->getName());
$client->writeInitRequest('IrcChannel', $buffer->getNetworkId() . '/' . $buffer->getId());
}
}

Expand All @@ -58,8 +61,9 @@
}

if ($type === Protocol::REQUEST_RPCCALL && $message[1] === '2displayMsg(Message)') {
$data = $message[2];
echo $data['timestamp']->format(\DateTime::ISO8601) . ' in ' . $data['bufferInfo']['name'] . ' by ' . explode('!', $data['sender'], 2)[0] . ': ' . $data['content'] . PHP_EOL;
$in = $message[2];
assert($in instanceof Message);
echo date(DATE_ISO8601, $in->getTimestamp()) . ' in ' . $in->getBufferInfo()->getName() . ' by ' . explode('!', $in->getSender())[0] . ': ' . $in->getContents() . PHP_EOL;

return;
}
Expand Down
12 changes: 10 additions & 2 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Clue\QDataStream\Types;
use Clue\React\Quassel\Io\PacketSplitter;
use Clue\React\Quassel\Io\Protocol;
use Clue\React\Quassel\Models\BufferInfo;
use Evenement\EventEmitter;
use React\Stream\DuplexStreamInterface;
use React\Stream\Util;
Expand Down Expand Up @@ -191,13 +192,20 @@ public function writeHeartBeatReply(\DateTime $dt)
));
}

public function writeBufferInput($bufferInfo, $input)
/**
* Sends a chat message to the given buffer/channel
*
* @param BufferInfo $bufferInfo buffer/channel to send to (from previous Message object or SessionInit message)
* @param string $contents buffer input (chat message) to send
* @return bool
*/
public function writeBufferInput(BufferInfo $bufferInfo, $contents)
{
return $this->write(array(
Protocol::REQUEST_RPCCALL,
"2sendInput(BufferInfo,QString)",
new QVariant($bufferInfo, 'BufferInfo'),
(string)$input
(string)$contents
));
}

Expand Down
36 changes: 16 additions & 20 deletions src/Io/Protocol.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Clue\QDataStream\Writer;
use Clue\QDataStream\Reader;
use Clue\React\Quassel\Models\BufferInfo;
use Clue\React\Quassel\Models\Message;

/** @internal */
abstract class Protocol
Expand Down Expand Up @@ -55,12 +57,12 @@ public function __construct()
return $reader->readUInt();
},
'BufferInfo' => function (Reader $reader) {
return array(
'id' => $reader->readUInt(),
'network' => $reader->readUInt(),
'type' => $reader->readUShort(),
'group' => $reader->readUInt(),
'name' => $reader->readQByteArray(),
return new BufferInfo(
$reader->readUInt(),
$reader->readUInt(),
$reader->readUShort(),
$reader->readUInt(),
$reader->readQByteArray()
);
},
// all required by "Network" InitRequest
Expand All @@ -72,20 +74,14 @@ public function __construct()
return $reader->readUInt();
},
'Message' => function (Reader $reader) {
// create DateTime object with local time zone from given unix timestamp
$datetime = function ($timestamp) {
$d = new \DateTime('@' . $timestamp);
$d->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
return $d;
};
return array(
'id' => $reader->readUInt(),
'timestamp' => $datetime($reader->readUInt()),
'type' => $reader->readUInt(),
'flags' => $reader->readUChar(),
'bufferInfo' => $reader->readQUserTypeByName('BufferInfo'),
'sender' => $reader->readQByteArray(),
'content' => $reader->readQByteArray()
return new Message(
$reader->readUInt(),
$reader->readUInt(),
$reader->readUInt(),
$reader->readUChar(),
$reader->readQUserTypeByName('BufferInfo'),
$reader->readQByteArray(),
$reader->readQByteArray()
);
},
'MsgId' => function (Reader $reader) {
Expand Down
78 changes: 78 additions & 0 deletions src/Models/BufferInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Clue\React\Quassel\Models;

class BufferInfo
{
// @link https://github.com/quassel/quassel/blob/e17fca767d60c06ca02bc5898ced04f06d3670bd/src/common/bufferinfo.h#L32
const TYPE_INVALID = 0x00;
const TYPE_STATUS = 0x01;
const TYPE_CHANNEL = 0x02;
const TYPE_QUERY = 0x04;
const TYPE_GROUP = 0x08;

private $id;
private $networkId;
private $type;
private $groupId;
private $name;

/**
* [Internal] Instantiation is handled internally and should not be called manually.
*
* @param int $id
* @param int $networkId
* @param int $type single type constant, see self::TYPE_*
* @param int $groupId
* @param string $name buffer/channel name `#channel`, `user` or empty string
* @internal
*/
public function __construct($id, $networkId, $type, $groupId, $name)
{
$this->id = $id;
$this->networkId = $networkId;
$this->type = $type;
$this->groupId = $groupId;
$this->name = $name;
}

/**
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* @return int
*/
public function getNetworkId()
{
return $this->networkId;
}

/**
* @return int single type constant, see self::TYPE_*
*/
public function getType()
{
return $this->type;
}

/**
* @return int
*/
public function getGroupId()
{
return $this->groupId;
}

/**
* @return string buffer/channel name `#channel` or `user` or empty string
*/
public function getName()
{
return $this->name;
}
}
Loading