Needs to be used with a Client, example: https://gist.github.com/xprilion/aec07a8878882b7b06c596c174fd8b5b
-
-
Save xprilion/ceab48ec77a70be1d403e396170991e6 to your computer and use it in GitHub Desktop.
| <html> | |
| <head> | |
| <title>WebSocket demo</title> | |
| <style type="text/css"> | |
| body { | |
| font-family: "Courier New", sans-serif; | |
| text-align: center; | |
| } | |
| .buttons { | |
| font-size: 4em; | |
| display: flex; | |
| justify-content: center; | |
| } | |
| .button, .value { | |
| line-height: 1; | |
| padding: 2rem; | |
| margin: 2rem; | |
| border: medium solid; | |
| min-height: 1em; | |
| min-width: 1em; | |
| } | |
| .button { | |
| cursor: pointer; | |
| user-select: none; | |
| } | |
| .minus { | |
| color: red; | |
| } | |
| .plus { | |
| color: green; | |
| } | |
| .value { | |
| min-width: 2em; | |
| } | |
| .state { | |
| font-size: 2em; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="buttons"> | |
| <div class="minus button">-</div> | |
| <div class="value">?</div> | |
| <div class="plus button">+</div> | |
| </div> | |
| <div class="state"> | |
| <span class="users">?</span> online | |
| </div> | |
| <script> | |
| var minus = document.querySelector('.minus'), | |
| plus = document.querySelector('.plus'), | |
| value = document.querySelector('.value'), | |
| users = document.querySelector('.users'), | |
| websocket = new WebSocket("wss://gpu.dpi.one:6789/"); | |
| minus.onclick = function (event) { | |
| websocket.send(JSON.stringify({action: 'minus'})); | |
| } | |
| plus.onclick = function (event) { | |
| websocket.send(JSON.stringify({action: 'plus'})); | |
| } | |
| websocket.onmessage = function (event) { | |
| data = JSON.parse(event.data); | |
| switch (data.type) { | |
| case 'state': | |
| value.textContent = data.value; | |
| break; | |
| case 'users': | |
| users.textContent = ( | |
| data.count.toString() + " user" + | |
| (data.count == 1 ? "" : "s")); | |
| break; | |
| default: | |
| console.error( | |
| "unsupported event", data); | |
| } | |
| }; | |
| </script> | |
| </body> | |
| </html |
| #!/usr/bin/env python | |
| # WS server example that synchronizes state across clients | |
| import asyncio | |
| import json | |
| import logging | |
| import websockets | |
| import ssl | |
| logging.basicConfig() | |
| ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) | |
| # Generate with Lets Encrypt, copied to this location, chown to current user and 400 permissions | |
| ssl_cert = "/home/username/fullchain.pem" | |
| ssl_key = "/home/username/privkey.pem" | |
| ssl_context.load_cert_chain(ssl_cert, keyfile=ssl_key) | |
| STATE = {"value": 0} | |
| USERS = set() | |
| def state_event(): | |
| return json.dumps({"type": "state", **STATE}) | |
| def users_event(): | |
| return json.dumps({"type": "users", "count": len(USERS)}) | |
| async def notify_state(): | |
| if USERS: # asyncio.wait doesn't accept an empty list | |
| message = state_event() | |
| await asyncio.wait([user.send(message) for user in USERS]) | |
| async def notify_users(): | |
| if USERS: # asyncio.wait doesn't accept an empty list | |
| message = users_event() | |
| await asyncio.wait([user.send(message) for user in USERS]) | |
| async def register(websocket): | |
| USERS.add(websocket) | |
| await notify_users() | |
| async def unregister(websocket): | |
| USERS.remove(websocket) | |
| await notify_users() | |
| async def counter(websocket, path): | |
| # register(websocket) sends user_event() to websocket | |
| await register(websocket) | |
| try: | |
| await websocket.send(state_event()) | |
| async for message in websocket: | |
| data = json.loads(message) | |
| if data["action"] == "minus": | |
| STATE["value"] -= 1 | |
| await notify_state() | |
| elif data["action"] == "plus": | |
| STATE["value"] += 1 | |
| await notify_state() | |
| else: | |
| logging.error("unsupported event: {}", data) | |
| finally: | |
| await unregister(websocket) | |
| start_server = websockets.serve(counter, "0.0.0.0", 6789, ssl=ssl_context) | |
| asyncio.get_event_loop().run_until_complete(start_server) | |
| asyncio.get_event_loop().run_forever() |
Thanks! 😃
Published a blog that discusses this gist in more detail here - https://xprilion.com/python-websockets-ssl-with-lets-encrypt/
Published a blog that discusses this gist in more detail here - https://xprilion.com/python-websockets-ssl-with-lets-encrypt/
Dude. Great blog. Thanks a ton, super useful stuff especially with the chmod examples
Thanks for the feedback @vuolo, your comment earlier today encouraged me to work on the blog! 😃 I figured the way I had written it initially was slightly tough to follow for folks who were doing socket SSL setup for the first time.
hi @xprilion ,
i launched the example on my local machine on port 12088 (... start_server = websockets.serve(counter, "0.0.0.0", 12088, ssl=ssl_context) ...)
i tested it from chrome browser from Developer tools->console :
try {
let s = new WebSocket('wss://127.0.0.1:12088');
s.onerror = e =>{console.error('onerror!!!', e)}
s.onopen = r => {
console.debug('onopen', r)
}
} catch (e) {
console.error('EEERRR', e)
}
console result:
VM132:2 WebSocket connection to 'wss://127.0.0.1:12088/' failed:
(anonymous) @ VM132:2
VM132:3 onerror!!! Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
as you can see it doesn't work. but if i launch the server script without ssl parameter (... start_server = websockets.serve(counter, "0.0.0.0", 12088...) it works:
try {
let s = new WebSocket('ws://127.0.0.1:12088');
s.onerror = e =>{console.error('onerror!!!', e)}
s.onopen = r => {
console.debug('onopen', r)
}
} catch (e) {
console.error('EEERRR', e)
}
result:
onopen Event {isTrusted: true, type: 'open', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
also, no any external web server is launched on my machine.
any suggestions?
thanks in advance
Awesome example of a secure websocket!
Thank you so much @xprilion!
how about if python is the client?
I wonder if any special configuration is needed to use python as a client for a websocket, maybe you can generate one easily using any GPT tools? Do let me know if that doesn't work for you.
This was extremely helpful, thank you!