Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

change gomedigap/laravel-echo-server PR with hooks for version larave… #544

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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