Skip to content

Commit

Permalink
Adding code for the module
Browse files Browse the repository at this point in the history
  • Loading branch information
Gagandeep authored and Gagandeep committed Aug 17, 2022
1 parent 21d9ccb commit 6f8a2cc
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ ret = conn.getLocalStorageVal(key='k1')
st.write('ret: ' + ret)
```

You can use the ```linode.liquidco.in``` websocket relay server for testing. Alternately run your websocket relay server from the code in ```ws_server.py```
You can use the ```linode.liquidco.in``` websocket relay server for testing. Alternately run your websocket relay server from the code in ```websocket-server/ws_server.py```
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
simple-websocket-server===0.4.2
websockets===10.3
streamlit
98 changes: 98 additions & 0 deletions streamlit_ws_localstorage/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import asyncio
import json
import ssl
import time
import uuid

import certifi
import streamlit as st
import streamlit.components.v1 as components
import websockets


def getOrCreateUID():
if 'uid' not in st.session_state:
st.session_state['uid'] = ''
st.session_state['uid'] = st.session_state['uid'] or str(uuid.uuid1())
print ('getOrCreateUID: ', st.session_state['uid'])
return st.session_state['uid']


# Generate a unique uid that gets embedded in components.html for frontend
# Both frontend and server connect to ws using the same uid
# server sends commands like localStorage_get_key, localStorage_set_key, localStorage_clear_key etc. to the WS server,
# which relays the commands to the other connected endpoint (the frontend), and back
def injectWebsocketCode(hostPort, uid):
code = '<script>function connect() { console.log("in connect uid: ", "' + uid + '"); var ws = new WebSocket("wss://' + hostPort + '/?uid=' + uid + '");' + """
ws.onopen = function() {
// subscribe to some channels
// ws.send(JSON.stringify({ status: 'connected' }));
console.log("onopen");
};
ws.onmessage = function(e) {
console.log('Message:', e.data);
var obj = JSON.parse(e.data);
if (obj.cmd == 'localStorage_get_key') {
var val = localStorage[obj.key] || '';
ws.send(JSON.stringify({ status: 'success', val }));
console.log('returning: ', val);
} else if (obj.cmd == 'localStorage_set_key') {
localStorage[obj.key] = obj.val;
ws.send(JSON.stringify({ status: 'success' }));
console.log('set: ', obj.key, obj.val);
}
};
ws.onclose = function(e) {
console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
setTimeout(function() {
connect();
}, 1000);
};
ws.onerror = function(err) {
console.error('Socket encountered error: ', err.message, 'Closing socket');
ws.close();
};
}
connect();
</script>
"""
components.html(code, height=0)
time.sleep(1) # Without sleep there are problems
return WebsocketClient(hostPort, uid)


class WebsocketClient:
def __init__(self, hostPort, uid):
self.hostPort = hostPort
self.uid = uid
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)

def sendCommand(self, value):
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())

async def query(future):
async with websockets.connect("wss://" + self.hostPort + "/?uid=" + self.uid, ssl=ssl_context) as ws:
await ws.send(value)
response = await ws.recv()
print('response: ', response)
future.set_result(response)

future1 = asyncio.Future()
self.loop.run_until_complete(query(future1))
print('future1.result: ', future1.result())
return future1.result()

def getLocalStorageVal(self, key):
result = self.sendCommand(json.dumps({ 'cmd': 'localStorage_get_key', 'key': key }))
return json.loads(result)['val']

def setLocalStorageVal(self, key, val):
result = self.sendCommand(json.dumps({ 'cmd': 'localStorage_set_key', 'key': key, 'val': val }))
return result

Empty file added websocket-server/__init__.py
Empty file.
108 changes: 108 additions & 0 deletions websocket-server/websocket-chat-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<!DOCTYPE html>

<meta charset="utf-8" />

<title>WebSocket Test</title>

<script language="javascript" type="text/javascript">


function init()
{
document.myform.url.value = "ws://localhost:8000/"
document.myform.inputtext.value = "Hello World!"
document.myform.disconnectButton.disabled = true;
}

function doConnect()
{
websocket = new WebSocket(document.myform.url.value);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}

function onOpen(evt)
{
writeToScreen("connected\n");
document.myform.connectButton.disabled = true;
document.myform.disconnectButton.disabled = false;
}

function onClose(evt)
{
writeToScreen("disconnected\n");
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}

function onMessage(evt)
{
writeToScreen("response: " + evt.data + '\n');
}

function onError(evt)
{
writeToScreen('error: ' + evt.data + '\n');

websocket.close();

document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;

}

function doSend(message)
{
writeToScreen("sent: " + message + '\n');
websocket.send(message);
}

function writeToScreen(message)
{
document.myform.outputtext.value += message
document.myform.outputtext.scrollTop = document.myform.outputtext.scrollHeight;

}

window.addEventListener("load", init, false);


function sendText() {
doSend( document.myform.inputtext.value );
}

function clearText() {
document.myform.outputtext.value = "";
}

function doDisconnect() {
websocket.close();
}


</script>

<div id="output"></div>

<form name="myform">
<p>
<textarea name="outputtext" rows="20" cols="50"></textarea>
</p>
<p>
<textarea name="inputtext" cols="50"></textarea>
</p>
<p>
<textarea name="url" cols="50"></textarea>
</p>
<p>
<input type="button" name=sendButton value="Send" onClick="sendText();">
<input type="button" name=clearButton value="Clear" onClick="clearText();">
<input type="button" name=disconnectButton value="Disconnect" onClick="doDisconnect();">
<input type="button" name=connectButton value="Connect" onClick="doConnect();">
</p>


</form>
</html>
24 changes: 24 additions & 0 deletions websocket-server/websocket-echo-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import asyncio
import ssl

import certifi
import websockets


def main():
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())

async def query(future):
async with websockets.connect("wss://linode.liquidco.in/?uid=21", ssl=ssl_context) as ws:
await ws.send('{"cmd":"echo","msg":"hi4"}')
response = await ws.recv()
print ('response: ', response)
future.set_result(response)

future1 = asyncio.Future()
asyncio.run(query(future1))
print ('future1.result: ', future1.result())


main()
58 changes: 58 additions & 0 deletions websocket-server/ws_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import json
from urllib.parse import urlparse, parse_qs

from simple_websocket_server import WebSocketServer, WebSocket


# Generate a unique uid that gets embedded in components.html for frontend
# Both frontend and server connect to ws using the same uid
# server sends commands like localStorage_get_key, localStorage_set_key, localStorage_clear_key etc.
class SimpleChat(WebSocket):
uid: str = None

def handle(self):
print ('handle: ', self.uid, self.data, self.address)

# Echo back
try:
obj = json.loads(self.data)
if 'cmd' in obj and obj['cmd'] == 'echo':
self.send_message(self.data)
except:
print ('exception in handle, ignoring')

for client in clients[self.uid]:
if client != self:
client.send_message(self.data)

def connected(self):
print('connected: ', self.address, self.request.path)
self.uid = self.request.path
try:
parsed_url = urlparse(self.request.path)
d = parse_qs(parsed_url.query)
if 'uid' in d and len(d['uid']) > 0:
self.uid = d['uid'][0]
else:
self.send_message('No uid found')
self.close(1, 'No uid found')
return
except:
self.send_message('Exception')
self.close(2, 'Exception')
return

if self.uid not in clients:
clients[self.uid] = []
clients[self.uid].append(self)

def handle_close(self):
print ('handle_close: ', self.uid, self.address)
clients[self.uid].remove(self)
print(self.address, 'closed')


clients = dict()

server = WebSocketServer('0.0.0.0', 8001, SimpleChat)
server.serve_forever()

0 comments on commit 6f8a2cc

Please sign in to comment.