Skip to content

Commit

Permalink
#585: update docs for client-to-server websockets
Browse files Browse the repository at this point in the history
  • Loading branch information
Badgerati committed Sep 17, 2020
1 parent 7b652aa commit e0369b1
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 36 deletions.
57 changes: 30 additions & 27 deletions docs/Tutorials/WebSockets.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
# Web Sockets

Pode has support for server-to-client communications using WebSockets, including secure WebSockets.

!!! note
Currently only broadcasting messages to connected clients/browsers from the server is supported. Client-to-server communications is in the works!
Pode has support for using WebSockets, including secure WebSockets, for either server-to-client or vice-versa.

WebSockets allow you to send messages directly from your server to connected clients. This allows you to get real-time continuous updates for the frontend without having to constantly refresh the page, or by using async javascript!

## Server Side

### Listening

On the server side, the only real work required is to register a new endpoint to listen on. To do this you can use the normal [`Add-PodeEndpoint`](../../Functions/Core/Add-PodeEndpoint) function, but with a protocol of either `Ws` or `Wss`:
On the server side, the only real work required is to register a new endpoint to listen on. To do this you can use the normal [`Add-PodeEndpoint`](../../Functions/Core/Add-PodeEndpoint), but with a protocol of either `Ws` or `Wss`:

```powershell
Add-PodeEndpoint -Address * -Port 8091 -Protocol Ws
Expand All @@ -22,7 +19,7 @@ Add-PodeEndpoint -Address * -Port 8091 -Certificate './path/cert.pfx' -Certifica

### Broadcasting

To broadcast a message from the server to all connected clients you can use the [`Send-PodeSignal`](../../Functions/Responses/Send-PodeSignal) function. You can either send raw JSON data, or you can pass a HashTable/PSObject and it will be converted to JSON for you.
To broadcast a message from the server to all connected clients you can use [`Send-PodeSignal`](../../Functions/Responses/Send-PodeSignal). You can either send raw JSON data, or you can pass a HashTable/PSObject and it will be converted to JSON for you.

To broadcast some data to all clients from a POST route, you could use the following. This will get some message from one of the clients, and then broadcast it to every other client:

Expand All @@ -45,6 +42,8 @@ You can also broadcast messages from Timers, or from Schedules.

## Client Side

### Receiving

On the client side, you need to use javascript to register a WebSocket and then bind the `onmessage` event to do something when a broadcasted message is received.

To create a WebSocket, you can do something like the following which will bind a WebSocket onto the root path '/':
Expand All @@ -62,6 +61,22 @@ $(document).ready(() => {
})
```

### Sending

To send a message using the WebSocket, you can use the `.send` function. When you send a message from client-to-server, the data must be a JSON value containing the `message`, `path`, and `clientId`. Only the `message` is mandatory.

For example, if you have a form with input, you can send the message as follows:

```javascript
$('#form').submit(function(e) {
e.preventDefault();
ws.send(JSON.stringify({ message: $('#input').val() }));
$('#input').val('');
})
```

This will send the message to the server, which will in-turn broadcast to all other clients.

## Full Example

> This full example is a cut-down version of the one found in `/examples/web-signal.ps1` of the main repository.
Expand All @@ -78,10 +93,7 @@ server.ps1
script.js
```

The following is the Pode server code, that will create two routes.

* The first route will be for some home page, with a button/input for broadcasting messages.
* The second route will be invoked when the button above is clicked. It will then broadcast some message to all clients.
The following is the Pode server code, that will create one route, which will be for some home page, with a button/input for broadcasting messages.

```powershell
Start-PodeServer {
Expand All @@ -94,12 +106,6 @@ Start-PodeServer {
Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
Write-PodeViewResponse -Path 'index'
}
# broadcast a received message back out to ever connected client via websockets
Add-PodeRoute -Method Post -Path '/broadcast' -ScriptBlock {
param($e)
Send-PodeSignal -Value @{ Message = $e.Data['message'] }
}
}
```

Expand All @@ -124,30 +130,27 @@ Next we have the HTML web page with a basic button/input for broadcasting messag
</html>
```

Finally, the following is the client-side javascript to register a WebSocket for the client. It will also invoke the `/broadcast` endpoint when the button is clicked:
Finally, the following is the client-side javascript to register a WebSocket for the client. It will also invoke the `.send` function of the WebSocket when the button is clicked:

```javascript
$(document).ready(() => {
// bind submit on the form to send message to the server
$('#bc-form').submit(function(e) {
e.preventDefault();

$.ajax({
url: '/broadcast',
type: 'post',
data: $('#bc-form').serialize()
})
ws.send(JSON.stringify({
message: $('input[name=message]').val()
}));

$('input[name=message]').val('')
})
$('input[name=message]').val('');
});

// create the websocket
var ws = new WebSocket("ws://localhost:8091/");

// event for inbound messages to append them
ws.onmessage = function(evt) {
var data = JSON.parse(evt.data)
$('#messages').append(`<p>${data.Message}</p>`);
$('#messages').append(`<p>${evt.data}</p>`);
}
})
});
```
4 changes: 2 additions & 2 deletions examples/public/scripts/websockets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ $(document).ready(() => {
$('#messages').append(`<p>${evt.data}</p>`);
}

// send message on the socket
// send message on the socket, to all clients
$('#bc-form').submit(function(e) {
e.preventDefault();
ws.send(JSON.stringify({ message: $('#bc-message').val() }));
$('input[name=message]').val('')
$('input[name=message]').val('');
})
})
6 changes: 0 additions & 6 deletions examples/web-signal.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,4 @@ Start-PodeServer -Threads 5 {
Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
Write-PodeViewResponse -Path 'websockets'
}

# POST broadcast a received message back out to ever connected client via websockets
Add-PodeRoute -Method Post -Path '/broadcast' -ScriptBlock {
param($e)
Send-PodeSignal -Value @{ Message = $e.Data['message'] }
}
}
2 changes: 1 addition & 1 deletion src/Private/SignalServer.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function Start-PodeSignalServer
{
$context = (Wait-PodeTask -Task $Listener.GetClientSignalAsync($PodeContext.Tokens.Cancellation.Token))
$context = ($context.Message | ConvertFrom-Json)
Send-PodeSignal -Value $context.message
Send-PodeSignal -Value $context.message -Path $context.path -ClientId $context.clientId
}
}
catch [System.OperationCanceledException] {}
Expand Down

0 comments on commit e0369b1

Please sign in to comment.