├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── public ├── .gitkeep └── js │ └── WebSocketClient.js └── src └── Freestream └── WebSocket ├── WebSocketServiceProvider.php ├── command └── WebSocketCommand.php ├── helper ├── .gitkeep └── Evaluate.php └── model ├── .gitkeep ├── WebSocketConnectionWrapper.php ├── WebSocketEventListener.php ├── WebSocketResponse.php └── WebSocketServer.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Anton Samuelsson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Laravel WebSocket server 2 | 3 | > WebSocket server based on Ratchet. Built to be completely event driven so it can used in several different project without having to manipulate the base code. 4 | 5 | ## Installation 6 | 7 | Add `require` and `repositories` information in the projects `composer.json` file: 8 | 9 | ```json 10 | "require": { 11 | ... 12 | "freestream/websocket": "1.*" 13 | ... 14 | }, 15 | "repositories": [ 16 | ... 17 | { 18 | "type": "vcs", 19 | "url": "git@github.com:freestream/laravel-websocket.git" 20 | } 21 | ... 22 | ], 23 | ``` 24 | 25 | Now it's time to run `composer update` in your terminal. 26 | 27 | After the update is complete the service provider needs to be registered in `app/config/app.php` inside the `providers` array: 28 | 29 | ```php 30 | 'Freestream\WebSocket\WebSocketServiceProvider', 31 | ``` 32 | 33 | ## Server side configuration 34 | Run the following command in the project root folder to startup the WebSocket server. By default the server will be run on port 8080 but by adding `--port=[number]` at the end of the command it is possible to change to any desired port. 35 | 36 | ```php 37 | php artisan websocket:start 38 | ``` 39 | 40 | This will startup a daemon service that will estsblish the WebSocket server. To make sure that command is constantly running it is recommended to use [Supervisord](http://supervisord.org/) to run the process. 41 | 42 | ## Client side listener 43 | 44 | This service comes included with the necsesary JavaScript. To include these into the project assets folder run the following command. 45 | 46 | ```php 47 | php artisan asset:publish freestream/web-socket 48 | ``` 49 | 50 | After that add this line into the template file. 51 | 52 | ```php 53 | 54 | ``` 55 | 56 | To estalish a WebSocket client add the following code. 57 | 58 | ```JavaScript 59 | 66 | ``` 67 | 68 | The availible configurations are: 69 | 70 | ```JavaScript 71 | debug boolean Enabled debug messages in browser console. Default is false. 72 | prefix string Event firing prefix. Default 'Laravel.Freestream.WebSocket' 73 | server string WebSocket server address. Default 'localhost' 74 | port integer WebSocket server port. Default 8080 75 | sessionId string Session ID for the opened WebSocket. Default random integer. 76 | reconnect boolean Should reconnect automatically if losing connection. Default true. 77 | ``` 78 | 79 | Messages can be sent through the socket as soon as the connection is established. The first parameter is an event name that will be sent to the backend as a tracing event for easier filtering. The second parameter is the message and can contain a string or JSON. 80 | 81 | ```JavaScript 82 | 85 | ``` 86 | 87 | Messages that are sent back from the server to the client contains JSON with two elements, `origData` and `data`. OrigData contains any data that was sent as a message and the server has responded to, and data contains the reponse data from the server. 88 | 89 | ```JSON 90 | { 91 | origData: { 92 | ... 93 | }, 94 | data: { 95 | ... 96 | }, 97 | } 98 | ``` 99 | 100 | Add Event Listensers to respond/listen to anything that happens in the WebSocket. 101 | 102 | ```JavaScript 103 | document.addEventListener('Laravel.Freestream.WebSocket.Message.Received', function(event) {}); 104 | ``` 105 | 106 | Events that will be fired is: 107 | 108 | ```JavaScript 109 | [PREFIX].Error 110 | [PREFIX].Message.Received 111 | [PREFIX].Connection.Established 112 | [PREFIX].Connection.Closed 113 | ``` 114 | 115 | ## Server side listener 116 | 117 | The server needs to be able to respond to any new connections or messages that are sent by the client. This is done by Laravel's event listener. This can be setup in different ways. The recommended way is to use `events.php`. 118 | 119 | If `events.php` is not already in the 'app/' folder create the file and after that open up 'app/start/global.php' and make sure the follwoing line is in the end of the file. 120 | 121 | ```php 122 | require app_path().'/events.php'; 123 | ``` 124 | 125 | All events that will be handled by the server should now be placed inside `events.php`: 126 | 127 | ```php 128 | =5.4.0", 13 | "cboden/Ratchet": "0.3.*" 14 | }, 15 | "autoload": { 16 | "classmap": [ 17 | "src/Freestream/WebSocket/helper", 18 | "src/Freestream/WebSocket/model", 19 | "src/Freestream/WebSocket/command" 20 | ], 21 | "psr-0": { 22 | "Freestream\\WebSocket\\": "src/" 23 | } 24 | }, 25 | "minimum-stability": "stable" 26 | } 27 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freestream/laravel-websocket/b8755a993e56e4a27dbe9b578d26fab8f0d39134/public/.gitkeep -------------------------------------------------------------------------------- /public/js/WebSocketClient.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014 Anton Samuelsson 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * Custom Event constructor pollyfill 27 | */ 28 | (function () { 29 | function CustomEvent (event, params) { 30 | params = params || { bubbles: false, cancelable: false, detail: undefined }; 31 | var evt = document.createEvent( 'CustomEvent' ); 32 | evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); 33 | return evt; 34 | }; 35 | 36 | CustomEvent.prototype = window.Event.prototype; 37 | 38 | window.CustomEvent = CustomEvent; 39 | })(); 40 | 41 | 42 | /** 43 | * Establishes a WebSocket connection and broadcasts the events. 44 | * 45 | * @param {Object} options 46 | */ 47 | var WebSocketClient = function(options) { 48 | this.options = { 49 | debug: options.debug || 0, 50 | prefix: options.prefix ||'Laravel.Freestream.WebSocket', 51 | server: options.server || 'localhost', 52 | port: options.port || '8080', 53 | sessionId: options.sessionId || Math.floor((Math.random()*1000)+1), 54 | reconnect: options.reconnect || true, 55 | }; 56 | 57 | this.queue = []; 58 | this.isOpen = false; 59 | this.tryReconnect = options.reconnect; 60 | 61 | this.init(); 62 | }; 63 | 64 | /** 65 | * Initial configuration. 66 | */ 67 | WebSocketClient.prototype.init = function() { 68 | this.connection = this.setConnection(new WebSocket('ws://' + this.options.server + ':' + this.options.port)); 69 | 70 | this.connection.WebSocketClient = this; 71 | }; 72 | 73 | /** 74 | * Modifies the established WebSocket connection. 75 | * 76 | * @param {WebSocket} connection 77 | */ 78 | WebSocketClient.prototype.setConnection = function(connection) { 79 | var that = this; 80 | var prefix = this.options.prefix; 81 | 82 | /** 83 | * React to any connection error. 84 | * 85 | * @param {String} error 86 | */ 87 | connection.onerror = function(error) { 88 | if (that.options.debug) { 89 | console.log('Caused error'); 90 | console.log(error); 91 | } 92 | 93 | document.dispatchEvent(new CustomEvent(prefix + '.Error', { 94 | detail: { 95 | error: error, 96 | webSocketClient: that, 97 | connection: this, 98 | }, 99 | bubbles: true, 100 | cancelable: false 101 | })); 102 | }; 103 | 104 | /** 105 | * React on any message. 106 | * 107 | * @param {[Object]} message 108 | */ 109 | connection.onmessage = function(message) { 110 | if (that.options.debug) { 111 | console.log('Received message'); 112 | console.log(message); 113 | } 114 | 115 | document.dispatchEvent(new CustomEvent(prefix + '.Message.Received', { 116 | detail: { 117 | message: message, 118 | webSocketClient: that, 119 | connection: this, 120 | }, 121 | bubbles: true, 122 | cancelable: false 123 | })); 124 | }; 125 | 126 | /** 127 | * React when the connection is established. 128 | */ 129 | connection.onopen = function() { 130 | if (that.options.debug) { 131 | console.log('Connection open!'); 132 | } 133 | 134 | that.isOpen = true; 135 | 136 | document.dispatchEvent(new CustomEvent(prefix + '.Connection.Established', { 137 | detail: { 138 | webSocketClient: that, 139 | connection: this, 140 | }, 141 | bubbles: true, 142 | cancelable: false 143 | })); 144 | 145 | that.sendQueue(); 146 | }; 147 | 148 | /** 149 | * React when the connection is closed. 150 | */ 151 | connection.onclose = function() { 152 | if (that.options.debug) { 153 | console.log('Connection closed!'); 154 | } 155 | 156 | that.isOpen = false; 157 | that.tryReconnect = true; 158 | 159 | document.dispatchEvent(new CustomEvent(prefix + '.Connection.Closed', { 160 | detail: { 161 | webSocketClient: that, 162 | connection: this, 163 | }, 164 | bubbles: true, 165 | cancelable: false 166 | })); 167 | 168 | if (that.tryReconnect === true) { 169 | setTimeout(function() { 170 | that.init(); 171 | }, 5000); 172 | } 173 | }; 174 | 175 | return connection; 176 | }; 177 | 178 | /** 179 | * Checks if the current object is from the server. 180 | * 181 | * @param {Object} object 182 | * 183 | * @return {Boolean} 184 | */ 185 | WebSocketClient.prototype.isServerResponse = function(object) { 186 | return (object.server && object.server.event); 187 | }; 188 | 189 | /** 190 | * After connection is established any stored queue data can be processed. 191 | */ 192 | WebSocketClient.prototype.sendQueue = function() { 193 | if (!this.isOpen) { 194 | return false; 195 | } 196 | 197 | var that = this; 198 | 199 | this.queue.forEach(function(queue){ 200 | that.message(queue.event, queue.data); 201 | }); 202 | } 203 | 204 | /** 205 | * Sends a message through the WebSocket connection. 206 | * 207 | * @param {String} event 208 | * @param {Object} data 209 | */ 210 | WebSocketClient.prototype.message = function(event, data) { 211 | if (!this.isOpen) { 212 | this.queue.push({event: event, data: data}); 213 | } else { 214 | var json = { 215 | event: event, 216 | sessionID: this.options.sessionId, 217 | message: data || [], 218 | }; 219 | 220 | console.log(json); 221 | 222 | this.connection.send(JSON.stringify(json)); 223 | } 224 | }; 225 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/WebSocketServiceProvider.php: -------------------------------------------------------------------------------- 1 | 26 | 35 | */ 36 | class WebSocketServiceProvider 37 | extends ServiceProvider { 38 | 39 | /** 40 | * Internal service prefix. 41 | * 42 | * @var string 43 | */ 44 | const SERVICE_PREFIX = 'Laravel.Freestream.WebSocket'; 45 | 46 | /** 47 | * Indicates if loading of the provider is deferred. 48 | * 49 | * @var boolean 50 | */ 51 | protected $defer = false; 52 | 53 | /** 54 | * Bootstrap the application events. 55 | */ 56 | public function boot() 57 | { 58 | $this->package('freestream/websocket'); 59 | } 60 | 61 | /** 62 | * Register the service provider. 63 | */ 64 | public function register() 65 | { 66 | $this->app['command.websocket:start'] = $this->app->share(function($app) 67 | { 68 | return new WebSocketCommand(); 69 | }); 70 | 71 | $this->commands('command.websocket:start'); 72 | } 73 | 74 | /** 75 | * Get the services provided by the provider. 76 | * 77 | * @return array 78 | */ 79 | public function provides() 80 | { 81 | return array('freestream_websocket','command.websocket:start'); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/command/WebSocketCommand.php: -------------------------------------------------------------------------------- 1 | 26 | 38 | */ 39 | class WebSocketCommand 40 | extends Command 41 | { 42 | /** 43 | * Default WebSocket port. 44 | * 45 | * @var integer 46 | */ 47 | const DEFAULT_WEBSOCKET_PORT = 8080; 48 | 49 | /** 50 | * The console command name. 51 | * 52 | * @var string 53 | */ 54 | protected $name = 'websocket:start'; 55 | 56 | /** 57 | * The console command description. 58 | * 59 | * @var string 60 | */ 61 | protected $description = 'Starts WebSocket server and runs event-driven applications with Laravel.'; 62 | 63 | /** 64 | * Create a new command instance. 65 | */ 66 | public function __construct() 67 | { 68 | parent::__construct(); 69 | } 70 | 71 | /** 72 | * Execute the console command. 73 | */ 74 | public function fire() 75 | { 76 | $port = $this->option('port'); 77 | 78 | try { 79 | $server = new WebSocketServer(); 80 | $server->start($port); 81 | $this->info("WebSocket server started on port: {$port}"); 82 | $server->run(); 83 | } catch (Exception $e) { 84 | Log::error('Something went wrong:', $e); 85 | $this->error('Unable to establish a WebSocket server. Review the log for more information.'); 86 | } 87 | } 88 | 89 | /** 90 | * Get the console command options. 91 | * 92 | * @return array 93 | */ 94 | protected function getOptions() 95 | { 96 | return array( 97 | array( 98 | 'port', null, InputOption::VALUE_OPTIONAL, 99 | "The port that the WebSocket server will run on (default: {self::DEFAULT_WEBSOCKET_PORT})", 100 | self::DEFAULT_WEBSOCKET_PORT 101 | ), 102 | ); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/helper/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freestream/laravel-websocket/b8755a993e56e4a27dbe9b578d26fab8f0d39134/src/Freestream/WebSocket/helper/.gitkeep -------------------------------------------------------------------------------- /src/Freestream/WebSocket/helper/Evaluate.php: -------------------------------------------------------------------------------- 1 | 26 | 33 | */ 34 | class Evaluate 35 | { 36 | /** 37 | * Checks if the input string is a JSON. 38 | * 39 | * @param string $string 40 | * 41 | * @return boolean 42 | */ 43 | public static function isJson($string) 44 | { 45 | json_decode($string); 46 | return (json_last_error() == JSON_ERROR_NONE); 47 | } 48 | 49 | /** 50 | * Returns a PHP standard object from a JSON string. 51 | * 52 | * @return stdClass 53 | */ 54 | public static function jsonDecodeString($string) 55 | { 56 | return ((Evaluate::isJson($string))) ? (array) json_decode($string, true): []; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/model/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freestream/laravel-websocket/b8755a993e56e4a27dbe9b578d26fab8f0d39134/src/Freestream/WebSocket/model/.gitkeep -------------------------------------------------------------------------------- /src/Freestream/WebSocket/model/WebSocketConnectionWrapper.php: -------------------------------------------------------------------------------- 1 | 26 | 36 | */ 37 | class WebSocketConnectionWrapper 38 | { 39 | /** 40 | * Connection interface for the established connection. 41 | * 42 | * @var Ratchet\ConnectionInterface 43 | */ 44 | protected $_connection; 45 | 46 | /** 47 | * Response container. 48 | * 49 | * @var Freestream\WebSocket\WebSocketResponse 50 | */ 51 | protected $_response; 52 | 53 | /** 54 | * Initial configuration. 55 | * 56 | * @param ConnectionInterface $connection 57 | * @param string $message 58 | */ 59 | public function __construct(ConnectionInterface $connection, $message = '') 60 | { 61 | $this->_connection = $connection; 62 | $this->_response = $this->_getMessageObject($message); 63 | } 64 | 65 | /** 66 | * Extension of class function to make sure data is correctly formatted. 67 | * 68 | * @param string $string 69 | */ 70 | public function send($string = '') 71 | { 72 | $this->_response->setMessage($string); 73 | 74 | $this->_connection->send( 75 | $this->_response->composeMessage() 76 | ); 77 | } 78 | 79 | /** 80 | * Sets the response session ID. 81 | * 82 | * @param string $string 83 | * 84 | * @return Freestream\WebSocket\WebSocketConnectionWrapper 85 | */ 86 | public function setSessionId($string = '') 87 | { 88 | $this->_response->setSessionId($string); 89 | 90 | return $this; 91 | } 92 | 93 | /** 94 | * Sets the response event name. 95 | * 96 | * @param string $string 97 | * 98 | * @return Freestream\WebSocket\WebSocketConnectionWrapper 99 | */ 100 | public function setEvent($string = '') 101 | { 102 | $this->_response->setEvent($string); 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Apprehend every method call that is not present and send it directly to 109 | * the origin connection. 110 | * 111 | * @param string $method 112 | * @param array $args 113 | * 114 | * @return mixed 115 | */ 116 | public function __call($method, $args) 117 | { 118 | return call_user_func_array(array($this->_connection, $method), $args); 119 | } 120 | 121 | /** 122 | * Validates and converts JSON object into a array and generates and returns 123 | * a response container. 124 | * 125 | * @param string $message 126 | * 127 | * @return Freestream\WebSocket\WebSocketResponse 128 | */ 129 | protected function _getMessageObject($message = '') 130 | { 131 | $message = Evaluate::jsonDecodeString($message); 132 | return new WebSocketResponse($message); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/model/WebSocketEventListener.php: -------------------------------------------------------------------------------- 1 | 26 | 37 | */ 38 | class WebSocketEventListener 39 | implements MessageComponentInterface 40 | { 41 | /** 42 | * Used event prefix. 43 | * 44 | * @var string 45 | */ 46 | protected $_prefix; 47 | 48 | /** 49 | * Map from objects. 50 | * 51 | * @var \SplObjectStorage 52 | */ 53 | protected $_clients; 54 | 55 | /** 56 | * Initial configuration. 57 | */ 58 | public function __construct() 59 | { 60 | $this->_prefix = WebSocketServiceProvider::SERVICE_PREFIX; 61 | $this->_clients = new \SplObjectStorage; 62 | } 63 | 64 | /** 65 | * Fire a event when a new connection has been opened. 66 | * 67 | * @param ConnectionInterface $conn 68 | */ 69 | public function onOpen(ConnectionInterface $conn) 70 | { 71 | $connection = new WebSocketConnectionWrapper($conn); 72 | 73 | $event = Event::fire( 74 | "{$this->_prefix}.Listener.Open", 75 | array( 76 | 'connection' => $connection, 77 | 'clients' => $this->_clients, 78 | 'listener' => $this, 79 | ) 80 | ); 81 | 82 | if ($event) { 83 | echo "Connection Established! \n"; 84 | $this->_clients->attach($conn); 85 | 86 | Event::fire( 87 | "{$this->_prefix}.Listener.Open.After", 88 | array( 89 | 'connection' => $connection, 90 | 'clients' => $this->_clients, 91 | 'listener' => $this, 92 | ) 93 | ); 94 | } 95 | } 96 | 97 | /** 98 | * Fire a event when a message has been received through the tunnel. 99 | * 100 | * @param ConnectionInterface $from 101 | * @param string $msg 102 | */ 103 | public function onMessage(ConnectionInterface $from, $msg) 104 | { 105 | $connection = new WebSocketConnectionWrapper($from, $msg); 106 | 107 | Event::fire( 108 | "{$this->_prefix}.Listener.Message", 109 | [ 110 | 'from' => $connection, 111 | 'raw' => $msg, 112 | 'clients' => $this->_clients, 113 | 'listener' => $this, 114 | ] 115 | ); 116 | } 117 | 118 | /** 119 | * Fire a event when a connection has been closed. 120 | * 121 | * @param ConnectionInterface $conn 122 | */ 123 | public function onClose(ConnectionInterface $conn) 124 | { 125 | $connection = new WebSocketConnectionWrapper($conn); 126 | 127 | $event = Event::fire( 128 | "{$this->_prefix}.Listener.Close", 129 | [ 130 | 'connection' => $connection, 131 | 'clients' => $this->_clients, 132 | 'listener' => $this, 133 | ] 134 | ); 135 | 136 | if ($event) { 137 | $this->clients->detach($conn); 138 | echo "Connection {$conn->resourceId} has disconnected\n"; 139 | } 140 | } 141 | 142 | /** 143 | * Fire a event when a error has occurred. 144 | * 145 | * @param ConnectionInterface $conn 146 | * @param \Exception $exception 147 | */ 148 | public function onError(ConnectionInterface $conn, \Exception $exception) 149 | { 150 | $connection = new WebSocketConnectionWrapper($conn); 151 | 152 | Event::fire( 153 | "{$this->_prefix}.Listener.Error", 154 | [ 155 | 'connection' => $connection, 156 | 'clients' => $this->_clients, 157 | 'listener' => $this, 158 | 'exception' => $exception, 159 | ] 160 | ); 161 | 162 | echo "An error has occurred: {$exception->getMessage()}\n"; 163 | $conn->close(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/model/WebSocketResponse.php: -------------------------------------------------------------------------------- 1 | 26 | 33 | */ 34 | class WebSocketResponse 35 | { 36 | /** 37 | * Data values. 38 | * 39 | * @var array 40 | */ 41 | protected $_data = []; 42 | 43 | /** 44 | * Original data values. 45 | * 46 | * @var array 47 | */ 48 | protected $_origData = []; 49 | 50 | /** 51 | * Initial configuration. 52 | * 53 | * @param array $values 54 | */ 55 | public function __construct(array $values) 56 | { 57 | $this->_setData($values); 58 | } 59 | 60 | /** 61 | * Magic data setter based on array of data. 62 | * Will only set data witch are compatible with a existing function. 63 | * 64 | * @param array $values 65 | * 66 | * @return Freestream\WebSocket\WebSocketResponse 67 | */ 68 | protected function _setData(array $values) 69 | { 70 | foreach ((array) $values as $key => $value) { 71 | $method = 'set' . ucfirst($key); 72 | if (method_exists($this, $method)) { 73 | call_user_func_array([$this, $method], [$value]); 74 | } 75 | } 76 | 77 | $this->_origData = $this->_data; 78 | $this->_data = []; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Sets value to message data. 85 | * 86 | * @param string $value 87 | * 88 | * @return Freestream\WebSocket\WebSocketResponse 89 | */ 90 | public function setMessage($value) 91 | { 92 | if (!is_object($value)) { 93 | $this->_setValue($value, 'message'); 94 | } 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Sets value to sessionId data. 101 | * 102 | * @param string $value 103 | * 104 | * @return Freestream\WebSocket\WebSocketResponse 105 | */ 106 | public function setSessionId($value) 107 | { 108 | if (!is_object($value)) { 109 | $this->_setValue($value, 'sessionId'); 110 | } 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Sets value to event data. 117 | * 118 | * @param string $value 119 | * 120 | * @return Freestream\WebSocket\WebSocketResponse 121 | */ 122 | public function setEvent($value) 123 | { 124 | if (!is_object($value)) { 125 | $this->_setValue($value, 'event'); 126 | } 127 | 128 | return $this; 129 | } 130 | 131 | /** 132 | * Sets value to data array. 133 | * 134 | * @param string $value 135 | * 136 | * @return Freestream\WebSocket\WebSocketResponse 137 | */ 138 | protected function _setValue($value, $key) 139 | { 140 | $this->_data[$key] = $value; 141 | 142 | return $this; 143 | } 144 | 145 | /** 146 | * Returns message value. 147 | * 148 | * @return string 149 | */ 150 | public function getMessage($orignData = false) 151 | { 152 | return $this->_getValue('message', $orignData); 153 | } 154 | 155 | /** 156 | * Returns sessionId value. 157 | * 158 | * @return string 159 | */ 160 | public function getSessionId($orignData = false) 161 | { 162 | return $this->_getValue('sessionId', $orignData); 163 | } 164 | 165 | /** 166 | * Returns event value. 167 | * 168 | * @return string 169 | */ 170 | public function getEvent($orignData = false) 171 | { 172 | return $this->_getValue('event', $orignData); 173 | } 174 | 175 | /** 176 | * Retrieves message from data or origin array. 177 | * 178 | * @param string $value 179 | */ 180 | protected function _getValue($key, $fromOrigin = false) 181 | { 182 | $data = ($fromOrigin) ? $this->_origData : $this->_data; 183 | 184 | if (array_key_exists($key, $data)) { 185 | return $data[$key]; 186 | } 187 | 188 | return ''; 189 | } 190 | 191 | /** 192 | * Composes the JSON formated message. 193 | * 194 | * @return string 195 | */ 196 | public function composeMessage() 197 | { 198 | return json_encode([ 199 | 'origData' => [ 200 | 'event' => $this->getEvent(true), 201 | 'sessionId' => $this->getSessionId(true), 202 | 'message' => $this->getMessage(true), 203 | ], 204 | 'data' => [ 205 | 'event' => $this->getEvent(), 206 | 'sessionId' => $this->getSessionId(), 207 | 'message' => $this->getMessage(), 208 | ], 209 | ]); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/Freestream/WebSocket/model/WebSocketServer.php: -------------------------------------------------------------------------------- 1 | 26 | 37 | */ 38 | class WebSocketServer 39 | { 40 | /** 41 | * Ratchet WebSocket server. 42 | * 43 | * @var Ratchet\Server\IoServer 44 | */ 45 | protected $server; 46 | 47 | /** 48 | * Prepares a new WebSocket server on a specified port. 49 | * 50 | * @param integer $port 51 | * 52 | * @return Freestream\WebSocket\WebSocketServer 53 | */ 54 | public function start($port) 55 | { 56 | $this->server = IoServer::factory(new HttpServer(new WsServer( 57 | new WebSocketEventListener() 58 | )), $port); 59 | 60 | return $this; 61 | } 62 | 63 | /** 64 | * Starts the prepared server. 65 | * 66 | * @return Freestream\WebSocket\WebSocketServer 67 | */ 68 | public function run() 69 | { 70 | $this->server->run(); 71 | 72 | return $this; 73 | } 74 | } 75 | --------------------------------------------------------------------------------