Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Open
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
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM node:14.16.1-alpine

WORKDIR /app

RUN apk add --update --no-cache curl

COPY . /app

RUN npm ci && npm run prepublish

RUN ln -s /app/bin/server.js /usr/bin/laravel-echo-server

COPY bin/docker-entrypoint bin/health-check /usr/local/bin/

ENTRYPOINT ["docker-entrypoint"]

VOLUME /app

EXPOSE 6001

HEALTHCHECK --interval=30s --timeout=5s \
CMD /usr/local/bin/health-check

CMD ["start"]
118 changes: 118 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Edit the default configuration of the server by adding options to your **laravel
| `database` | `redis` | Database used to store data that should persist, like presence channel members. Options are currently `redis` and `sqlite` |
| `databaseConfig` | `{}` | Configurations for the different database drivers [Example](#database) |
| `devMode` | `false` | Adds additional logging for development purposes |
| `hookEndpoint` | `null` | The route that receives to the client-side event [Example](#hook-client-side-event) |
| `host` | `null` | The host of the socket.io server ex.`app.dev`. `null` will accept connections on any IP-address |
| `port` | `6001` | The port that the socket.io server should run on |
| `protocol` | `http` | Must be either `http` or `https` |
Expand All @@ -110,6 +111,7 @@ file, the following options can be overridden:
- `sslCertPath`: `LARAVEL_ECHO_SERVER_SSL_CERT`
- `sslPassphrase`: `LARAVEL_ECHO_SERVER_SSL_PASS`
- `sslCertChainPath`: `LARAVEL_ECHO_SERVER_SSL_CHAIN`
- `rejectUnautorized`: `NODE_TLS_REJECT_UNAUTHORIZED`


### Running with SSL
Expand Down Expand Up @@ -371,3 +373,119 @@ _Note: When using the socket.io client library from your running server, remembe
#### µWebSockets deprecation

µWebSockets has been [officially deprecated](https://www.npmjs.com/package/uws). Currently there is no support for µWebSockets in Socket.IO, but it may have the new [ClusterWS](https://www.npmjs.com/package/@clusterws/cws) support incoming. Meanwhile Laravel Echo Server will use [`ws` engine](https://www.npmjs.com/package/ws) by default until there is another option.

## Hook client side event
There are 3 types of client-side event can be listen to. Here is the event names:
- join
- leave
- client_event

### Hooks configuration
First, you need to configurate your `hookEndpoint`. Here is an example:

```ini
"hookHost": "/api/hook",
```

You don't need to configure hook host. hook host value is getting from `authHost`

`laravel-echo-server` will send a post request to hook endpoint when there is a client-side event coming.
You can get event information from `cookie` and `form`.

#### Get data from cookie
`laravel-echo-server` directly use `cookie` from page. So you can add some cookie values like `user_id` to identify user.

#### Get data from post form
There is always an attribute in post form called `channel`. You can get event payload of [Client Event](https://laravel.com/docs/5.7/broadcasting#client-events) of there is an client event, such as `whisper`.

**Post form format**

| Attribute | Description | Example | Default |
| :-------------------| :---------------------- | :-------------------| :---------------------|
| `event` | The event name. Options: `join`, `leave`, `client_event` | `join` | |
| `channel` | The channel name | `meeting` | |
| `payload` | Payload of client event. `joinChannel` or `leaveChannel` hook doesn't have payload | `{from: 'Alex', to: 'Bill'}` | `null` |

### join channel hook
When users join in a channel `event` should be `join`.

The request form example:
```ini
event = join
channel = helloworld
```

Route configuration example:
```php
Route::post('/hook', function(Request $request) {
if ($request->input('event') === 'join') {
$channel = $request->input('channel');
$x_csrf_token = $request->header('X-CSRF-TOKEN');
$cookie = $request->header('Cookie');
// ...
}
});
```

### leave channel hook
When users leave a channel `event` should be `leave`.

> Notes that there is no X-CSRF-TOKEN in header when sending a post request for leave channel event, so you'd better not to use the route in `/routes/web.php`.

The request form example:
```ini
event = leave
channel = helloworld
```

Route configuration example:
```php
use Illuminate\Http\Request;

Route::post('/hook', function(Request $request) {
if ($request->input('event') === 'leave') {
$channel = $request->input('channel');
$cookie = $request->header('Cookie');
// ...
}
});
```

### client event hook
When users use `whisper` to broadcast an event in a channel `event` should be `client_event`.

> Notes that there is no X-CSRF-TOKEN in header when sending a post request for client-event event, so you'd better not to use the route in `/routes/web.php`.

It will fire the client-event after using `whisper` to broadcast an event like this:
```javascript
Echo.private('chat')
.whisper('whisperEvent', {
from: this.username,
to: this.whisperTo
});
```

The request form example
```ini
event = client_event
channel = helloworld
payload = {from:'Alex', to:'Bill'}
```

Route configuration example
```php
use Illuminate\Http\Request;

Route::post('/hoot', function(Request $request) {
if ($request->input('event') === 'client_event') {
$channel = $request->input('channel');
$user_id = $request->header('Cookie');
$payload = $request->input('payload');
$from = $payload['from'];
$to = $payload['to'];
// ...
}
});
```

> Notes that even though we use an `Object` as payload of client event, the payload will be transformed to an `Array` in PHP. So remember to get your attribute from payload by using an `Array` method like `$payload['xxxx']`
40 changes: 40 additions & 0 deletions bin/docker-entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/sh
set -e

/usr/sbin/update-ca-certificates

# laravel-echo-server init
if [[ "$1" == 'init' ]]; then
set -- laravel-echo-server "$@"
fi

# laravel-echo-server <sub-command>
if [[ "$1" == 'start' ]] || [[ "$1" == 'client:add' ]] || [[ "$1" == 'client:remove' ]]; then
if [[ "${GENERATE_CONFIG:-true}" == "false" ]]; then
# wait for another process to inject the config
echo -n "Waiting for /app/laravel-echo-server.json"
while [[ ! -f /app/laravel-echo-server.json ]]; do
sleep 2
echo -n "."
done
elif [[ ! -f /app/laravel-echo-server.json ]]; then
cp /usr/local/src/laravel-echo-server.json /app/laravel-echo-server.json
# Replace with environment variables
sed -i "s|LARAVEL_ECHO_SERVER_DB|${LARAVEL_ECHO_SERVER_DB:-redis}|i" /app/laravel-echo-server.json
sed -i "s|REDIS_HOST|${REDIS_HOST:-redis}|i" /app/laravel-echo-server.json
sed -i "s|REDIS_PORT|${REDIS_PORT:-6379}|i" /app/laravel-echo-server.json
sed -i "s|REDIS_PASSWORD|${REDIS_PASSWORD}|i" /app/laravel-echo-server.json
sed -i "s|REDIS_PREFIX|${REDIS_PREFIX:-laravel_database_}|i" /app/laravel-echo-server.json
sed -i "s|REDIS_DB|${REDIS_DB:-0}|i" /app/laravel-echo-server.json
# Remove password config if it is empty
sed -i "s|\"password\": \"\",||i" /app/laravel-echo-server.json
fi
set -- laravel-echo-server "$@"
fi

# first arg is `-f` or `--some-option`
if [[ "${1#-}" != "$1" ]]; then
set -- laravel-echo-server "$@"
fi

exec "$@"
39 changes: 39 additions & 0 deletions bin/health-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/bin/sh
set -x

_init () {
scheme="http://"
address="$(netstat -nplt 2>/dev/null | awk ' /(.*\/laravel-echo-serv)/ { gsub(":::","127.0.0.1:",$4); print $4}')"
resource="/socket.io/socket.io.js"
start=$(stat -c "%Y" /proc/1)
}

fn_health_check () {
# In distributed environment like Swarm, traffic is routed
# to a container only when it reports a `healthy` status. So, we exit
# with 0 to ensure healthy status till distributed service starts (120s).
#
# Refer: https://github.com/moby/moby/pull/28938#issuecomment-301753272
if [[ $(( $(date +%s) - start )) -lt 120 ]]; then
exit 0
else
# Get the http response code
http_response=$(curl -s -k -o /dev/null -w "%{http_code}" ${scheme}${address}${resource})

# Get the http response body
http_response_body=$(curl -k -s ${scheme}${address}${resource})

# server returns response 403 and body "SSL required" if non-TLS
# connection is attempted on a TLS-configured server. Change
# the scheme and try again
if [[ "$http_response" = "403" ]] && [[ "$http_response_body" = "SSL required" ]]; then
scheme="https://"
http_response=$(curl -s -k -o /dev/null -w "%{http_code}" ${scheme}${address}${resource})
fi

# If http_response is 200 - server is up.
[[ "$http_response" = "200" ]]
fi
}

_init && fn_health_check
Loading