├── .gitignore ├── .travis.yml ├── AUTHORS ├── LICENSE ├── README.rst ├── composer.json ├── phpunit.xml.dist ├── tests ├── ApiTest.php ├── ThunderTest.php └── bootstrap.php └── thunderclient └── Thunder.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sublime-project 3 | *.sublime-workspace 4 | 5 | composer.lock 6 | /vendor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.4 4 | - 5.5 5 | 6 | before_script: 7 | # Install dev requirements 8 | - composer install 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | - Krzysztof Jagiello -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 by the Krzysztof Jagiello, see AUTHORS for more details. 2 | 3 | Some rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * The names of the contributors may not be used to endorse or 18 | promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | -------------------------- 2 | Thunderpush client for PHP 3 | -------------------------- 4 | 5 | .. image:: https://travis-ci.org/thunderpush/php-thunderclient.png?branch=master 6 | :target: https://travis-ci.org/thunderpush/php-thunderclient 7 | 8 | A PHP library for sending messages to the `Thunderpush `_ server. 9 | 10 | Example 11 | ======= 12 | 13 | :: 14 | 15 | get_user_count(); 23 | 24 | // Get users in channel "test" 25 | print $thunder->get_users_in_channel("test"); 26 | 27 | // Send message to user "test" 28 | print $thunder->send_message_to_user("test", array("msg" => "hello!")); 29 | 30 | // Send message to a channel 31 | print $thunder->send_message_to_channel("test", array("msg" => "hello!")); 32 | 33 | // Check if user "test" is online 34 | print $thunder->is_user_online("test"); 35 | 36 | // Disconnect user "test" 37 | print $thunder->disconnect_user("test"); 38 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thunderpush/php-thunderclient", 3 | "description": "A PHP library for sending messages to Thunderpush server.", 4 | "version": "1.1.0", 5 | "keywords": ["thunderpush", "push", "beacon", "pubsub"], 6 | "license": "BSD-3-Clause", 7 | "homepage": "https://github.com/thunderpush/php-thunderclient", 8 | "authors": [ 9 | { 10 | "name": "Krzysztof Jagiełło", 11 | "homepage": "https://github.com/kjagiello" 12 | } 13 | ], 14 | "require": { 15 | "guzzlehttp/guzzle": "~5.0" 16 | }, 17 | "autoload": { 18 | "psr-0": { 19 | "Thunder": "./thunderclient" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | ./tests/ 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/ApiTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use GuzzleHttp\Client; 13 | use GuzzleHttp\Subscriber\Mock; 14 | use GuzzleHttp\Message\Response; 15 | use GuzzleHttp\Stream\Stream; 16 | 17 | class ApiTest extends \PHPUnit_Framework_TestCase 18 | { 19 | 20 | public function setup() { 21 | $this->mock = new Mock(); 22 | $this->key = 'key'; 23 | $this->secret = 'secret'; 24 | $this->host = 'localhost'; 25 | $this->port = 80; 26 | $this->https = false; 27 | $this->thunder = new Thunder( 28 | $this->key, $this->secret, $this->host, $this->port, $this->https 29 | ); 30 | 31 | $property = new \ReflectionProperty('Thunder', 'client'); 32 | $property->setAccessible(true); 33 | $this->client = $property->getValue($this->thunder); 34 | $this->client->getEmitter()->attach($this->mock); 35 | } 36 | 37 | /** 38 | * @covers Thunder::get_user_count 39 | */ 40 | public function testGetUserCount() 41 | { 42 | $method = new \ReflectionMethod('Thunder', 'get_user_count'); 43 | $method->setAccessible(true); 44 | 45 | $this->mock->addResponse( 46 | new Response(200, array(), Stream::factory('{"count": 1}')) 47 | ); 48 | $actual = $method->invokeArgs($this->thunder, array()); 49 | $this->assertEquals(1, $actual); 50 | } 51 | 52 | /** 53 | * @covers Thunder::get_users_in_channel 54 | */ 55 | public function testGetUsersInChannel() 56 | { 57 | $method = new \ReflectionMethod('Thunder', 'get_users_in_channel'); 58 | $method->setAccessible(true); 59 | 60 | $this->mock->addResponse( 61 | new Response(200, array(), Stream::factory('{"users": 1}')) 62 | ); 63 | $actual = $method->invokeArgs($this->thunder, array('foo')); 64 | $this->assertEquals(1, $actual); 65 | } 66 | 67 | /** 68 | * @covers Thunder::send_message_to_user 69 | */ 70 | public function testSendMessageToUser() 71 | { 72 | $method = new \ReflectionMethod('Thunder', 'send_message_to_user'); 73 | $method->setAccessible(true); 74 | 75 | $this->mock->addResponse( 76 | new Response(200, array(), Stream::factory('{"count": 1}')) 77 | ); 78 | $actual = $method->invokeArgs($this->thunder, array('foo', 'bar')); 79 | $this->assertEquals(1, $actual); 80 | } 81 | 82 | /** 83 | * @covers Thunder::send_message_to_channel 84 | */ 85 | public function testSendMessageToChannel() 86 | { 87 | $method = new \ReflectionMethod('Thunder', 'send_message_to_channel'); 88 | $method->setAccessible(true); 89 | 90 | $this->mock->addResponse( 91 | new Response(200, array(), Stream::factory('{"count": 1}')) 92 | ); 93 | $actual = $method->invokeArgs($this->thunder, array('foo', 'bar')); 94 | $this->assertEquals(1, $actual); 95 | } 96 | 97 | /** 98 | * @covers Thunder::is_user_online 99 | */ 100 | public function testIsUserOnline() 101 | { 102 | $method = new \ReflectionMethod('Thunder', 'is_user_online'); 103 | $method->setAccessible(true); 104 | 105 | $this->mock->addResponse( 106 | new Response(200, array(), Stream::factory('{"online": 1}')) 107 | ); 108 | $actual = $method->invokeArgs($this->thunder, array('foo', 'bar')); 109 | $this->assertEquals(1, $actual); 110 | } 111 | 112 | /** 113 | * @covers Thunder::disconnect_user 114 | */ 115 | public function testDisconnectUser() 116 | { 117 | $method = new \ReflectionMethod('Thunder', 'disconnect_user'); 118 | $method->setAccessible(true); 119 | 120 | $this->mock->addResponse( 121 | new Response(204, array(), Stream::factory('')) 122 | ); 123 | $actual = $method->invokeArgs($this->thunder, array('foo', null)); 124 | $this->assertEquals(1, $actual); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tests/ThunderTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use GuzzleHttp\Client; 13 | use GuzzleHttp\Subscriber\Mock; 14 | use GuzzleHttp\Message\Response; 15 | 16 | class ThunderTest extends \PHPUnit_Framework_TestCase 17 | { 18 | 19 | public function setup() { 20 | $this->mock = new Mock(); 21 | $this->key = 'key'; 22 | $this->secret = 'secret'; 23 | $this->host = 'localhost'; 24 | $this->port = 80; 25 | $this->https = false; 26 | $this->thunder = new Thunder( 27 | $this->key, $this->secret, $this->host, $this->port, $this->https 28 | ); 29 | 30 | $property = new \ReflectionProperty('Thunder', 'client'); 31 | $property->setAccessible(true); 32 | $this->client = $property->getValue($this->thunder); 33 | $this->client->getEmitter()->attach($this->mock); 34 | } 35 | 36 | /** 37 | * @covers Thunder::make_url 38 | */ 39 | public function testMakeUrl() 40 | { 41 | $expected = sprintf(Thunder::API_URL, Thunder::API_VERSION, $this->key, 'foo'); 42 | 43 | $method = new \ReflectionMethod('Thunder', 'make_url'); 44 | $method->setAccessible(true); 45 | 46 | $actual = $method->invokeArgs($this->thunder, array('foo')); 47 | $this->assertEquals($expected, $actual); 48 | 49 | $actual = $method->invokeArgs($this->thunder, array('foo', 'bar')); 50 | $this->assertEquals($expected . 'bar/', $actual); 51 | } 52 | 53 | /** 54 | * @covers Thunder::make_request 55 | */ 56 | public function testMakeRequest() 57 | { 58 | $method = new \ReflectionMethod('Thunder', 'make_request'); 59 | $method->setAccessible(true); 60 | 61 | $this->mock->addResponse(new Response(200)); 62 | $actual = $method->invokeArgs($this->thunder, array('GET', array('foo', 'bar'))); 63 | $this->assertEquals(array( 64 | 'status' => 200, 65 | 'data' => array() 66 | ), $actual); 67 | 68 | $this->mock->addResponse(new Response(200)); 69 | $actual = $method->invokeArgs($this->thunder, array('POST', array('foo', 'bar'), array('foo' => 'bar'))); 70 | $this->assertEquals(array( 71 | 'status' => 200, 72 | 'data' => array() 73 | ), $actual); 74 | 75 | $this->mock->addResponse(new Response(200)); 76 | $actual = $method->invokeArgs($this->thunder, array('DELETE', array('foo', 'bar'))); 77 | $this->assertEquals(array( 78 | 'status' => 200, 79 | 'data' => array() 80 | ), $actual); 81 | 82 | $this->setExpectedException('UnsupportedMethodException'); 83 | $this->mock->addResponse(new Response(200)); 84 | $actual = $method->invokeArgs($this->thunder, array('UNSUPPORTED_METHOD', array('foo', 'bar'))); 85 | } 86 | 87 | /** 88 | * @covers Thunder::build_response 89 | */ 90 | public function testBuildResponse() 91 | { 92 | $method = new \ReflectionMethod('Thunder', 'build_response'); 93 | $method->setAccessible(true); 94 | 95 | $response = array( 96 | 'data' => array('foo' => 'bar'), 97 | 'status' => 200 98 | ); 99 | $actual = $method->invokeArgs($this->thunder, array($response, 'foo')); 100 | $this->assertEquals('bar', $actual); 101 | 102 | $response = array( 103 | 'status' => 204 104 | ); 105 | $actual = $method->invokeArgs($this->thunder, array($response, NULL)); 106 | $this->assertTrue($actual); 107 | 108 | $response = array( 109 | 'status' => 204 110 | ); 111 | $actual = $method->invokeArgs($this->thunder, array($response, 'foo')); 112 | $this->assertNull($actual); 113 | 114 | $response = array( 115 | 'status' => 555 116 | ); 117 | $actual = $method->invokeArgs($this->thunder, array($response, 'foo')); 118 | $this->assertNull($actual); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | use GuzzleHttp\Client; 13 | use GuzzleHttp\Psr7\Request; 14 | 15 | class Thunder 16 | { 17 | const API_VERSION = '1.0.0'; 18 | const API_URL = '/api/%s/%s/%s/'; 19 | 20 | protected $apikey; 21 | protected $apisecret; 22 | protected $host; 23 | 24 | /** 25 | * @var $client Guzzle\Http\Client Guzzle client 26 | */ 27 | protected $client; 28 | 29 | public function __construct($apikey, $apisecret, $host, $port = 80, $https = false) 30 | { 31 | $this->apikey = $apikey; 32 | $this->apisecret = $apisecret; 33 | 34 | $proto = $https === true ? 'https' : 'http'; 35 | $this->client = new Client(array( 36 | 'base_uri' => $proto . '://' . $host . ':' . $port . '/', 37 | 'headers' => array( 38 | 'Content-Type' => 'application/json', 39 | 'X-Thunder-Secret-Key' => $this->apisecret 40 | ) 41 | )); 42 | } 43 | 44 | protected function make_url($command) 45 | { 46 | $arguments = array_slice(func_get_args(), 1); 47 | 48 | $url = sprintf(self::API_URL, self::API_VERSION, $this->apikey, 49 | $command); 50 | 51 | if ($arguments) { 52 | $url .= implode('/', $arguments) . '/'; 53 | } 54 | 55 | return $url; 56 | } 57 | 58 | protected function make_request($method, $url, $data = NULL) 59 | { 60 | $url = call_user_func_array(array($this, 'make_url'), $url); 61 | 62 | $return = array( 63 | 'data' => array(), 64 | 'status' => 500 65 | ); 66 | 67 | // set the request method 68 | switch ($method) { 69 | case 'GET': 70 | // do nothing, GET is the default request method 71 | $request = $this->client->createRequest('GET', $url); 72 | break; 73 | case 'POST': 74 | $request = $this->client->createRequest('POST', $url, array( 75 | 'body' => json_encode($data) 76 | )); 77 | break; 78 | case 'DELETE': 79 | $request = $this->client->createRequest('DELETE', $url); 80 | break; 81 | default: 82 | throw new \UnsupportedMethodException( 83 | 'Unsupported request method: ' . $method 84 | ); 85 | return; 86 | } 87 | 88 | try { 89 | $response = $this->client->send($request); 90 | $return['data'] = json_decode($response->getBody(), true); 91 | $return['data'] = empty($return['data']) ? array() : $return['data']; 92 | $return['status'] = $response->getStatusCode(); 93 | } 94 | catch(\RequestException $e) { 95 | $return['status'] = $e->getStatusCode(); 96 | $return['exception'] = $e; 97 | } 98 | catch(\Exception $e) { 99 | $return['exception'] = $e; 100 | } 101 | 102 | return $return; 103 | } 104 | 105 | // builds function response based on the API response 106 | protected function build_response($response, $field = NULL) { 107 | if ($response['status'] == 200) { 108 | return $response['data'][$field]; 109 | } 110 | else if (is_null($field) && $response['status'] == 204) { 111 | return true; 112 | } 113 | else { 114 | return NULL; 115 | } 116 | } 117 | 118 | public function get_user_count() 119 | { 120 | $response = $this->make_request('GET', array('users')); 121 | return $this->build_response($response, 'count'); 122 | } 123 | 124 | public function get_users_in_channel($channel) 125 | { 126 | $response = $this->make_request('GET', array('channels', $channel)); 127 | return $this->build_response($response, 'users'); 128 | } 129 | 130 | public function send_message_to_user($userid, $message) 131 | { 132 | $response = $this->make_request('POST', array('users', $userid), $message); 133 | return $this->build_response($response, 'count'); 134 | } 135 | 136 | public function send_message_to_channel($channel, $message) 137 | { 138 | $response = $this->make_request('POST', array('channels', $channel), $message); 139 | return $this->build_response($response, 'count'); 140 | } 141 | 142 | public function is_user_online($userid) 143 | { 144 | $response = $this->make_request('GET', array('users', $userid)); 145 | return $this->build_response($response, 'online'); 146 | } 147 | 148 | public function disconnect_user($userid) 149 | { 150 | $response = $this->make_request('DELETE', array('users', $userid)); 151 | return $this->build_response($response); 152 | } 153 | } 154 | 155 | /** Exceptions **/ 156 | 157 | class UnsupportedMethodException extends \Exception {} 158 | --------------------------------------------------------------------------------