Skip to content
This repository was archived by the owner on May 3, 2019. It is now read-only.

Commit 4fe80f8

Browse files
committed
Initial commit.
0 parents  commit 4fe80f8

19 files changed

+1258
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2016 Codemash
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.

README.md

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# Laravel Socket
2+
3+
This package allows you to use sockets easily and elegantly in your Laravel 5 application. Based on the awesome PHP socket library, [Ratchet](https://github.com/ratchetphp/Ratchet). Read the instructions below to get setup.
4+
5+
## Requirements
6+
7+
Laravel 5.x.
8+
9+
## Installation
10+
11+
12+
You can install the package using the [Composer](https://getcomposer.org/) package manager. You can install it by running this command in your project root:
13+
14+
```sh
15+
composer require codemash/socket
16+
```
17+
18+
Add the `Codemash\Socket\SocketServiceProvider` provider to the `providers` array in `config/app.php`':
19+
20+
```php
21+
'providers' => [
22+
...
23+
Codemash\Socket\SocketServiceProvider::class,
24+
],
25+
```
26+
27+
Then, add the facade to your `aliases` array. The default facade provides an easy-to-use interface to integrate the socket files in your view.
28+
29+
```php
30+
'aliases' => [
31+
...
32+
'Socket' => Codemash\Socket\Facades\Socket::class,
33+
]
34+
```
35+
36+
Finally, the config and the javascript files need to be published, which can be done by running the following command:
37+
38+
```sh
39+
php artisan vendor:publish --provider="Codemash\Socket\SocketServiceProvider"
40+
```
41+
42+
The published assets can be found at `config/socket.php` and the default javascript at `public/vendor/socket/socket.js`. It is important to know that the `Socket::javascript()` facade function will include both a default socket located at `window.appSocket` and the `socket.js` source file located in the vendor folder. These are merely a start, and provide a quick way to work with the sockets but you are always free to write a custom implementation.
43+
44+
## Getting started
45+
46+
Let's create a simple application that sends a message to all other connected clients. When a socket action occurs, it will be wrapped around a Laravel event and triggered. This is a great way for us to catch these events and act upon them. Let's register our listener in the `app/Providers/EventServiceProvider.php` file like this:
47+
48+
```php
49+
<?php
50+
51+
namespace App\Providers;
52+
53+
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
54+
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
55+
56+
class EventServiceProvider extends ServiceProvider
57+
{
58+
...
59+
60+
/**
61+
* The subscriber classes to register.
62+
*
63+
* @var array
64+
*/
65+
protected $subscribe = [
66+
'App\Listeners\MessageEventListener'
67+
];
68+
}
69+
```
70+
71+
And create the listener at the following path: `app/Listeners/MessageEventListener.php`. Listeners provide 3 basic events. For our example here, we'll only be using the `onMessageReceived` event.
72+
73+
```php
74+
<?php
75+
76+
namespace App\Listeners;
77+
78+
use Codemash\Socket\Events\MessageReceived;
79+
use Codemash\Socket\Events\ClientConnected;
80+
use Codemash\Socket\Events\ClientDisconnected;
81+
82+
class MessageEventListener {
83+
84+
public function onMessageReceived(MessageReceived $event)
85+
{
86+
$message = $event->message;
87+
88+
// If the incomming command is 'sendMessageToOthers', forward the message to the others.
89+
if ($message->command === 'sendMessageToOthers') {
90+
// To get the client sending this message, use the $event->from property.
91+
// To get a list of all connected clients, use the $event->clients pointer.
92+
$others = $event->allOtherClients();
93+
foreach ($others as $client) {
94+
// The $message->data property holds the actual message
95+
$client->send('newMessage', $message->data);
96+
}
97+
}
98+
}
99+
100+
public function onConnected(ClientConnected $event)
101+
{
102+
// Not used in this example.
103+
}
104+
105+
public function onDisconnected(ClientDisconnected $event)
106+
{
107+
// Not used in this example.
108+
}
109+
110+
/**
111+
* Register the listeners for the subscriber.
112+
*
113+
* @param Illuminate\Events\Dispatcher $events
114+
*/
115+
public function subscribe($events)
116+
{
117+
$events->listen(
118+
'Codemash\Socket\Events\ClientConnected',
119+
'App\Listeners\MessageEventListener@onConnected'
120+
);
121+
122+
$events->listen(
123+
'Codemash\Socket\Events\MessageReceived',
124+
'App\Listeners\MessageEventListener@onMessageReceived'
125+
);
126+
127+
$events->listen(
128+
'Codemash\Socket\Events\ClientDisconnected',
129+
'App\Listeners\MessageEventListener@onDisconnected'
130+
);
131+
132+
}
133+
}
134+
```
135+
136+
What the application above does, is the following: a connected client sends a message with the `sendMessageToOthers` command, which basically forwards the message to the rest of the connected clients on your application. It is **important** to note that a client is not the same as a `User` model. A client is simply a connection from someones browser to your Laravel application, no matter if that user is authed or not. There is a possibility to fetch the connected authentication model, more on that later.
137+
138+
Now it's time to write the client side, luckily the `Socket` facade takes care of that in no time. Create a blade template with the following content:
139+
140+
```html
141+
<!doctype html>
142+
<html lang="en">
143+
<head>
144+
<meta charset="utf-8">
145+
</head>
146+
<body>
147+
<button onclick="sendMessage()">Send message</button>
148+
{!! Socket::javascript() !!}
149+
<script>
150+
var socket = window.appSocket;
151+
152+
function sendMessage() {
153+
var text = window.prompt('Which message would you like to send?');
154+
socket.send('sendMessageToOthers', text);
155+
}
156+
157+
socket.on('newMessage', function (newMessage) {
158+
alert('New message: ' + newMessage);
159+
});
160+
161+
socket.connect(function () {
162+
// The socket is connected.
163+
});
164+
</script>
165+
</body>
166+
</html>
167+
```
168+
169+
Finally, let's run the socket listener. You can do this by running the following artisan command in the project root:
170+
171+
```sh
172+
php artisan socket:listen
173+
```
174+
175+
## Using Eloquent models
176+
177+
Laravel Socket reads the session when available and maps the `User` eloquent model to your client. You can then retrieve the Eloquent model by using the following code:
178+
179+
```php
180+
foreach ($clients as $client) {
181+
if ($client->authed()) {
182+
$user = $client->getUser();
183+
// $user now holds the App\User model,
184+
// or the model set in the 'config.auth.providers.users.model' config variable.
185+
}
186+
}
187+
```
188+
189+
Whenever you're using the clients list, like `$event->clients`, this is a Laravel Collection object. Methods such as filter, map, and so on, work very well on it.
190+
191+
## Production
192+
193+
Ubuntu provides the neat `nohup` tool, which runs processes on the background. In case you'd like to run your socket on a production server and you're on Ubuntu, you may always use the nohup tool to run the socket listener.
194+
195+
```sh
196+
nohup php artisan socket:listen &
197+
```
198+
199+
When using the `jobs` command, you'll see the socket running. It's easy to kill the process using the `kill <pid>` command. The process ID is listed in the jobs list.
200+
201+
## Contributing
202+
203+
If you're having problems, spot a bug, or have a feature suggestion, please log and issue on Github. If you'd like to have a crack yourself, fork the package and make a pull request. Any improvements are more than welcome.
204+

assets/Socket.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
var Socket = function (url) {
2+
this.url = url;
3+
4+
this.events = [];
5+
6+
this.connected = false;
7+
8+
this.triggerEvent = function (name, data, event) {
9+
var i = 0, len = this.events.length;
10+
for (; i < len; i++) {
11+
if (this.events[i].name === name) {
12+
this.events[i].callback(data, event);
13+
}
14+
}
15+
};
16+
17+
this.addEvent = function (name, callback) {
18+
this.events.push({
19+
name: name,
20+
callback: callback
21+
});
22+
};
23+
24+
this.removeEvent = function (callback) {
25+
var i = 0, len = this.events.length;
26+
for (; i < len; i++) {
27+
if (!this.events[i])
28+
continue;
29+
if (this.events[i].callback === callback) {
30+
this.events.splice(i, 1);
31+
}
32+
}
33+
};
34+
35+
this.bindConnection = function () {
36+
var _this = this;
37+
38+
this.connection.onopen = function (event) {
39+
_this.connected = true;
40+
41+
_this.triggerEvent('connected', null, event);
42+
};
43+
44+
this.connection.onmessage = function (event) {
45+
_this.triggerEvent('message', null, event);
46+
47+
var incoming = JSON.parse(event.data);
48+
_this.triggerEvent(incoming.command, incoming.data, event);
49+
};
50+
51+
this.connection.onclose = function (event) {
52+
_this.triggerEvent('disconnected', null, event);
53+
};
54+
};
55+
};
56+
57+
Socket.prototype.connect = function (callback) {
58+
if (callback) {
59+
this.bind('connected', callback);
60+
}
61+
62+
this.connection = new WebSocket(this.url);
63+
this.bindConnection();
64+
};
65+
66+
Socket.prototype.isConnected = function () {
67+
return this.connected;
68+
};
69+
70+
Socket.prototype.disconnect = function () {
71+
this.connection.close();
72+
};
73+
74+
Socket.prototype.bind = function (name, callback) {
75+
this.addEvent(name, callback);
76+
return callback;
77+
};
78+
79+
Socket.prototype.on = Socket.prototype.bind;
80+
81+
Socket.prototype.unbind = function (callback) {
82+
this.removeEvent(callback);
83+
};
84+
85+
Socket.prototype.send = function (command, data) {
86+
var json = JSON.stringify({
87+
command: command,
88+
data: data
89+
});
90+
this.connection.send(json);
91+
};

composer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "codemash/laravel-socket",
3+
"description": "A socket implementation for Laravel 5",
4+
"version": "1.0.0",
5+
"require": {
6+
"cboden/ratchet": "^0.3.5"
7+
},
8+
"license": "MIT",
9+
"authors": [
10+
{
11+
"name": "Matthias Van Parijs",
12+
"email": "matvp91@gmail.com"
13+
}
14+
],
15+
"autoload": {
16+
"psr-4": {
17+
"Codemash\\Socket\\": "src/"
18+
}
19+
},
20+
"post-update-cmd": [
21+
"php artisan vendor:publish"
22+
]
23+
}

config/socket.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
return [
4+
5+
'default_port' => 8043
6+
7+
];

0 commit comments

Comments
 (0)