Last active
May 30, 2024 09:26
-
-
Save sesgoe/81aad6dd4b587d6bcc4d8937407ef601 to your computer and use it in GitHub Desktop.
Retool Realtime WebSocket
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const webSocket = new WebSocket('wss://echo.websocket.org'); | |
//Event listeners are the pillars upon which WebSockets are built. This event fires when the WebSocket is considered 'OPEN', | |
//which means that it has connected successfully. | |
webSocket.addEventListener('open', function(event) { | |
console.log('websocket connected successfully') //log this into the browser console so we can check if the websocket connected | |
}); | |
//This is a global reference to the websocket that we created. We need this because otherwise multiple JS | |
//queries can't access the same WebSocket object. If each query had its own `new WebSocket()`, the interactivity of this | |
//example wouldn't work, because they'd all be referring to different WebSocket connections. | |
//This is what I was referring to when I mentioned that the two-way WebSocket example was "messier". | |
//This global stuff isn't needed to simply listen on a WebSocket, as we'll see later with the Pusher-based 2nd example app. | |
window.WEB_SOCKET = () => { | |
return webSocket | |
}; | |
//This is our response message queue. I tried building this initially with a Temporary State object, but | |
//I ran into some weird issues arouund live-updating that I suspect have something to do with React's internal visual cycles. | |
let messages = []; | |
//`window` properties in Retool must be functions to be able to access them as globals from within any query. | |
//For example, when you see a line that looks like: | |
//MESSAGES().push(...) it's really referring to our global response messages queue | |
window.MESSAGES = () => { | |
return messages; | |
}; | |
//I originally set this up as a simple `clear` parameter for the above function, but the global properties don't support function | |
//arguments. I suspect this is some weird Javascript sandbox behavior, but either way, I can confirm that this works. | |
window.CLEAR_MESSAGES = () => { | |
messages = [] | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const webSocket = WEB_SOCKET() //grab a reference to the global WebSocket object mentioned earlier | |
//This allows us to run a function every time the WebSocket receives a message. | |
//In this example, this happens any time we send a message because the echo WebSocket sends our message back to us. | |
webSocket.addEventListener('message', function(event) { | |
//This gets a reference to the global response messages list (array) and appends the response that comes back from the echo WebSocket | |
MESSAGES().push(event.data) | |
//This is a retool hacky thing to ensure the text actually visually updates its contents. | |
text1.setValue(MESSAGES().join('\n')) | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const webSocket = WEB_SOCKET() | |
//This line specifically is what would fail if we didn't have a reference to the same `WebSocket` object. | |
//If we created a new `WebSocket` object in this query, we would be sending messages to THAT `WebSocket` instead of the global one | |
//we created earlier. Then, the echo service would be echoing to THAT `WebSocket` instead of the one we are actually listening to. | |
//Basically we do the global stuff just to be able to do this `webSocket.send(...)` call. | |
webSocket.send(textInput1.value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//The part that actually clears the messages queue by just re-assigning an empty array | |
CLEAR_MESSAGES() | |
//The part that updates the textbox visually because Retool | |
text1.setValue(MESSAGES().join('\n')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const pusher = new Pusher('app-key-goes-here', { | |
cluster: 'us2' | |
}); | |
//This is where Pusher sets up the WebSocket in the background and subscribes to the Pusher channel called `event-channel-goes-here` | |
//By itself, this doesn't listen to any events on this channel. You need the `channel.bind(...)` line below. | |
const channel = pusher.subscribe('event-channel-goes-here'); | |
//This is the exact same thing as an EventListener. The syntax is even similar by design so that it looks familiar. | |
//Inside the `function(data) { ... }`, you can do any Retool things that you would like to do in response to Pusher events. | |
//In this example, I am triggering a simple query, which will refresh the data inside a table. | |
channel.bind('event-type-goes-here', function(data) { | |
get_table_data.trigger() | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment