I'm writing a basic socket programming code in python which takes any kind of URL and returns the content of the body in bytes. I need to only use socket library and nothing else. When I pass different URLs, I get full response of the body for some URLs and only a partial response for some URLs. I'm not sure why it is so.
This is my code:
import socket
def retrieve_url(url):
url1 = url.split("http://", 1)
empty = url1[1].find("/")
if empty > 0:
url2 = url1[1].split("/", 1)
else:
url2 = url1[1].split("/", 1)
url2.append('')
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
soc.connect((url2[0], 80))
soc.sendall(b"GET /" + bytes(url2[1], 'utf8') + b" HTTP/1.1\r\nHost: " + bytes(url2[0],'utf8') + b"\r\nConnection: close\r\n\r\n")
spl = soc.recv(8192)
soc.close()
a = spl.split(b"\r\n\r\n", 1)
b = spl.split(None, 2)
if b[1] == b'200':
return a[1]
else:
return None
except:
return None
if __name__ == "__main__":
print(retrieve_url("http://bombus.myspecies.info/node/24"))
This is the output I'm getting:
b'007a84\r\n<!DOCTYPE html PUBLIC "-//W3C//DTD HTML+RDFa 1.1//EN">\n<html lang="en" dir="ltr" version="HTML+RDFa 1.1"\n xmlns:content="http://purl.org/rss/1.0/modules/content/"\n xmlns:dc="http://purl.org/dc/terms/"\n xmlns:foaf="http://xmlns.com/foaf/0.1/"\n xmlns:og="http://ogp.me/ns#"\n xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"\n xmlns:sioc="http://rdfs.org/sioc/ns#"\n xmlns:sioct="http://rdfs.org/sioc/types#"\n xmlns:skos="http://www.w3.org/2004/02/skos/core#"\n xmlns:xsd="http://www.w3.org/2001/XMLSchema#">\n<head profile="http://www.w3.org/1999/xhtml/vocab">\n <!--[if IE]><![endif]-->\n<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />\n<![endif]--><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n<meta name="Generator" content="Drupal 7 (http://drupal.org)" />\n<link rel="canonical" href="/node/24" />\n<link rel="shortlink" href="/node/24" />\n<link rel="shortcut icon" href="http://bombus.myspecies.info/sites/all/themes/scratchpads/favicon.ico" type="image/vnd.microsoft.icon" />\n<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />\n <title>Bumblebee links | Genus Bombus</title>\n <link type="text/css" rel="stylesheet" href="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_css/css__-thr5kmN-aeH-BTlyCidKsE4D9T2geiRzcvwxBTJ3sU__VQtLPGzb9rjfNLJ2SaVDJUKhxtssNArRk3nO7wMUGoA__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.css" media="all" />\n\n<!--[if (lt IE 9)]>\n<link type="text/css" rel="stylesheet" href="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_css/css__GuBcvhFB_-fswxhbycYya2JRgqrqDq5y-pWYcuQbqp4__5h6_elrgEAXONSci50a6ewD4zUldIVoOgFFSjk7rVzg__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.css" media="all" />\n<![endif]-->\n<link type="text/css" rel="stylesheet" href="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_css/css__wxRBHPf0PIq6kCJXm57TkZCESl8zp_O0VduSG6wH0S0__ov4XZtBPHqH1F5cpK65jxEp1K5zF3dLEO4ihA2xTbE8__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.css" media="all" />\n\n<!--[if (lt IE 9)&(!IEMobile)]>\n<link type="text/css" rel="stylesheet" href="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_css/css__ISa-1zfLkp-52D_pPloP6gBpDvJwKu9Kitwbfnm33JY__PDj463LZhTo68R-x__a4AOf-EyYxSMW6sZpiNjtiKlQ__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.css" media="all" />\n<![endif]-->\n\n<!--[if gte IE 9]><!-->\n<link type="text/css" rel="stylesheet" href="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_css/css__Sisgbo-UreLp3cHBWfv37bIck8X5olI1W5xaYzDaATc__9XoSDv750KzHbfRkMww8VsZREmLh-SRR3SnhCYOEF2Q__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.css" media="all" />\n<!--<![endif]-->\n <script type="text/javascript" src="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_js/js__jQBI8pfG-VfYV1aN0gSeRXUYps9-4-M-XVb2H2ZbWuw__SyNVdbb0UiBMvI1oo0AzTY4CH83E7BmTR7ZP1Wwz_VE__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.js"></script>\n<script type="text/javascript" src="//bombus.myspecies.info/sites/all/libraries/mediaelement/build/mediaelement-and-player.min.js?v=2.1.6"></script>\n<script type="text/javascript" src="//bombus.myspecies.info/sites/bombus.myspecies.info/files/advagg_js/js__O2-Mfrpb6mHF0S5LAfIan_d38-kqXvv66sN_ZsHG9Qo__caMiUBuMxDF7rNYJXFf8geEVfuxGw22B96ouV1h3-1Q__CirpVkWrddCrpKWbZfWXvbwVN8pmqviBo8YZAKaYUQg.js"></script>\n<script type="text/javascript">\n<!--//--><![CDATA[//><!--\njQuery.extend(Drupal.settings,{"basePath":"\\/","pathPrefix":"","ajaxPageState":{"theme":"scratchpads","theme_token":"u7Gd7GPT7EPAVsIznB6HVhd9aHAwVUfjG4LrulLh3ak","jquery_version":"1.8","css":{"modules\\/system\\/system.base.css":1,"modules\\/system\\/system.menus.css":1,"modules\\/system\\/system.messages.css":1,"modules\\/system\\/system.theme.css":1,"sites\\/all\\/libraries\\/mediaelement\\/build\\/mediaelementplayer.min.css":1,"misc\\/ui\\/jquery.ui.core.css":1,"misc\\/ui\\/jquery.ui.theme.css":1,"modules\\/overlay\\/overlay-parent.css":1,"sites\\/all\\/modules\\/contrib\\/comment_notify\\/comment_notify.css":1,"modules\\/aggregator\\/aggregator.css":1,"modules\\/comment\\/comment.css":1,"sites\\/all\\/modules\\/contrib\\/date\\/date_api\\/date.css":1,"sites\\/all\\/modules\\/custom\\/entityfilter\\/ckeditor\\/entityfilter.css":1,"sites\\/all\\/modules\\/custom\\/field_quick_delete\\/theme\\/field.css":1,"modules\\/node\\/node.css":1,"sites\\/all\\/modules\\/custom\\/remote_issue_tab\\/css\\/remote_issue_tab.css":1,"sites\\/all\\/modules\\/custom\\/scratchpads\\/scratchpads_biography\\/css\\/scratchpads_biography.css":1,"sites\\/all\\/modules\\/custom\\/scratchpads\\/scratchpads_show_taxa_revisions\\/css\\/scratchpads_show_taxa_revisions.css":1,"modules\\/search\\/search.css":1,"sites\\/all\\/modules\\/custom\\/spm\\/css\\/spm.css":1,"sites\\/all\\/modules\\/custom\\/twitter_filter\\/css\\/twitter_filter.css":1,"sites\\/all\\/modules\\/custom\\/twitterscript\\/css\\/twitterscript.css":1,"modules\\/user\\/user.css":1,"sites\\/all\\/modules\\/contrib\\/views\\/css\\/views.css":1,"sites\\/all\\/modules\\/contrib\\/ckeditor\\/ckeditor.css":1,"sites\\/all\\/modules\\/contrib\\/colorbox\\/styles\\/default\\/colorbox_default_style.css":1,"sites\\/all\\/modules\\/contrib\\/ctools\\/css\\/ctools.css":1,"sites\\/all\\/modules\\/contrib\\/ctools\\/css\\/modal.css":1,"sites\\/all\\/modules\\/contrib\\/modal_forms\\/css\\/modal_forms_popup.css":1,"sites\\/all\\/modules\\/contrib\\/biblio\\/biblio.css":1,"modules\\/openid\\/openid.css":1,"public:\\/\\/spamicide\\/feed_me.css":1,"sites\\/all\\/modules\\/custom\\/scratchpads\\/scratchpads_search_block\\/css\\/scratchpads_search_block.css":1,"sites\\/all\\/modules\\/custom\\/creative_commons\\/css\\/creative_commons.css":1,"sites\\/all\\/themes\\/scratchpads\\/css\\/ie8.css":1,"public:\\/\\/css\\/css_tcVOMdlRmJTsBkm7ZJABjZ3Oct1H-tB7QsRkmUkgNco.css":1,"sites\\/all\\/themes\\/scratchpads\\/css\\/tabs.css":1,"sites\\/all\\/themes\\/scratchpads\\/css\\/sites.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/alpha-reset.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/alpha-mobile.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/alpha-alpha.css":1,"sites\\/all\\/themes\\/omega\\/omega\\/css\\/formalize.css":1,"sites\\/all\\/themes\\/omega\\/omega\\/css\\/omega-text.css":1,"sites\\/all\\/themes\\/omega\\/omega\\/css\\/omega-branding.css":1,"sites\\/all\\/themes\\/omega\\/omega\\/css\\/omega-menu.css":1,"sites\\/all\\/themes\\/omega\\/omega\\/css\\/omega-forms.css":1,"sites\\/all\\/themes\\/scratchpads\\/css\\/global.css":1,"ie::normal::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default.css":1,"ie::normal::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default-normal.css":1,"ie::normal::sites\\/all\\/themes\\/omega\\/alpha\\/css\\/grid\\/alpha_default\\/normal\\/alpha-default-normal-12.css":1,"narrow::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default.css":1,"narrow::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default-narrow.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/grid\\/alpha_default\\/narrow\\/alpha-default-narrow-12.css":1,"normal::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default.css":1,"normal::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default-normal.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/grid\\/alpha_default\\/normal\\/alpha-default-normal-12.css":1,"wide::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default.css":1,"wide::sites\\/all\\/themes\\/scratchpads\\/css\\/scratchpads-alpha-default-wide.css":1,"sites\\/all\\/themes\\/omega\\/alpha\\/css\\/grid\\/alpha_default\\/wide\\/alpha-default-wide-12.css":1},"js":{"modules\\/statistics\\/statistics.js":1,"sites\\/all\\/modules\\/contrib\\/jquer'
I only get partial response for this, but what I need is the full response.
Any help is appreciated. Thanks in advance.
soc.sendall(b"GET /" + bytes(url2[1], 'utf8') + b" HTTP/1.1\r\nHost: " + bytes(url2[0],'utf8') + b"\r\nConnection: close\r\n\r\n")
spl = soc.recv(8192)
soc.close()
You assume that all data will be retrieved with a single recv. This assumption is wrong. Given that you use an explicit Connection: close you can rely on the server closing the connection after the response is done, i.e. you should call recv as long as it returns more data and concatenate all these date for the full response.
You also assume that the answer is contained in plain in the response body. While this might be true in your specific case your use of HTTP/1.1 makes it possible for the server to send a chunked response too - which you need to handle differently. In order to avoid this better use HTTP/1.0 only (which also has an implicit Connection: close).
Related
I 've searched here for similar problems but couldn't find an exact answer. I'm definately no socketio specialist, so please forgive me in advance...
To put it simple and in short: when I perform send() from my server (py script) preceded by a '#socket.on('message')' all is received fine on the client side. However when I use emit() on a manually triggered def, nothing is shown on client side.
Here is my simplified code:
server - app.py
app=Flask(__name__) app.config["SECRET_KEY"]="secretkey"
socket = SocketIO(app, logger=True)
somelist = ["el1", "el2", "el3", "el4"]
i=0
#app.route("/") def main():
return render_template("main.html")
#app.route("/test2")
def test2():
print("called test2")
manual_callback("note 1")
#socket.on('message')
def handlemsg(msg):
global i
if i < len(somelist):
socket.send(somelist[i] + " - " + msg)
i+=1
def manual_callback(note):
print("manual_callback triggered")
socket.emit('updateData', {"data": "this the data to show - " + note}, namespace="/test2")
print("trigger done")
if __name__ == "__main__":
socket.run(app)
Client - main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.1/socket.io.js"></script>
<script>
socket = io();
socket.connect('http://' + document.domain + ':' + location.port);
socket.on('updateData',function(data){
console.log('called updateData');
console.log(data);
console.log('ended call');
})
socket.on('connect',function(){
console.log('CONNECT');
socket.send('a');
})
socket.on('message',function(msg){
console.log(msg);
socket.send('b');
})
</script>
</head>
<body>
<h1>test</h1>
</body>
</html>
What works fine:
After connecting, 'socket.on('connect',...) is triggered in main.html and 'CONNECT' is printed in the browser log followed by the 4 elements in somelist.
What doesn't work like I would expect:
After navigating to localhost/test2, def manual_callback() is called. So I would expect that on client side, 'socket.on('updateData'...)' gets triggered and messages 'called UpdateData', 'this the data to show - note 1' and 'ended call' appear in the browser's log. But the latter does not seem to happen.
What am I doing wrong here?
Thank you in advance.
I wanted to know how WebSocket servers are written so I tried making my own.
I used this as my reference and wrote a simple ThreadedTCPServer from the socket server module
this is my code for it
import base64
import hashlib
import re
import socketserver
def make_headers(headers: dict):
result = ""
result += "HTTP/1.1 101 Switching Protocols\r\n"
for header, value in headers.items():
result += f"{header}: {value}\r\n"
return result
def get_key(handshake_string):
key = re.findall(r"Sec-WebSocket-Key: .*", handshake_string)[0]
key = key.split(":")[1].strip()
return key
class Handler(socketserver.BaseRequestHandler):
MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def setup(self) -> None:
handshake_text = self.request.recv(1024).decode('utf-8')
print(handshake_text)
key = get_key(handshake_text)
key = key + self.MAGIC
print(key)
key = hashlib.sha1(key.encode()).digest()
key = base64.b64encode(key).decode()
print(key)
headers = {"Upgrade": "websocket", "Connection": "Upgrade",
"Sec-WebSocket-Accept": key}
headers = make_headers(headers)
self.request.send(headers.encode())
def handle(self) -> None:
self.request.send(b"Connection Finally works ^_^")
print("conn sent?")
def finish(self) -> None:
print("Connection Over :(")
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(("127.0.0.1", 2449), Handler)
server.serve_forever()
As mentioned in the referenced site, I have implemented the handshake in the setup method of my handler class however when I open my simple HTML document for testing the server I don't get my desired result in the browser console (blank)
this is my html code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Socket test</title>
</head>
<body>
<h1>Sample text1</h1>
<script>
var ws = new WebSocket("ws://127.0.0.1:2449/")
ws.onopen = function() {
console.log("Connection Established!")
}
ws.onmessage = function(msg)
{
console.log("message received!")
console.log(msg)
}
ws.onerror = function(err){
console.log(err)
}
</script>
</body>
</html>
The html page sends a socket request which triggers the server handler and upon the handshake the request closes. is there any reason as to why this happens?
So I'm trying to make a problem for a ctf, and for a problem, I need to send data from a python script to the javascript. Can anyone tell me how?
My html code is:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1 class="text">text</h1>
<script>
$.get("[website]/cgi-bin/challenge.py",
function(data) {
$(".text").html(data);
});
</script>
</body>
</html>
I replaced the website with [website].
The python code is like this:
#!/usr/bin/python
import json
print "Content-type: text/html\n\n"
json.dumps("It works!")
#!/usr/bin/python
import json
text = json.dumps("It works!")
print "Content-Type: application/json\n"
print text
you can try: https://www.zerorpc.io/ , zerorpc is a communication between server-side processes that lets you transfer data from a server to a client.
in your situation, if you want to transfer data from python to node.js you cand do it like this:
in your python file as a server do:
import zerorpc
class HelloRPC(object):
def hello(self, name):
return "Hello, %s" % name
s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()
and in your node.js code as a client:
var zerorpc = require("zerorpc");
var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
client.invoke("hello", "RPC", function(error, res, more) {
console.log(res);
});
this will print "hello RPC" on the console.
I'm getting:
Error 413 (Request Entity Too Large)
Using the new Google Cloud Translation API, via Python client. I need to cut my text limit, but not able to find the limit. My request contained 15185 characters.
Looks like my error is not related to Quota limits:
https://cloud.google.com/translate/limits
google.cloud.exceptions.GoogleCloudError: 413 <!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 413 (Request Entity Too Large)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}#media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}#media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>413.</b> <ins>That’s an error.</ins>
<p>Your client issued a request that was too large.
<script>
(function() { var c=function(a,d,b){a=a+"=deleted"+("; path="+d);null!=b&&(a+="; domain="+b);document.cookie=a+"; expires=Thu, 01 Jan 1970 00:00:00 GMT"};var g=function(a){var d=e,b=location.hostname;c(d,a,null);c(d,a,b);for(var f=0;;){f=b.indexOf(".",f+1);if(0>f)break;c(d,a,b.substring(f+1))}};var h;if(4E3<unescape(encodeURI(document.cookie)).length){for(var k=document.cookie.split(";"),l=[],m=0;m<k.length;m++){var n=k[m].match(/^\s*([^=]+)/);n&&l.push(n[1])}for(var p=0;p<l.length;p++){var e=l[p];g("/");for(var q=location.pathname,r=0;;){r=q.indexOf("/",r+1);if(0>r)break;var t=q.substring(0,r);g(t);g(t+"/")}"/"!=q.charAt(q.length-1)&&(g(q),g(q+"/"))}h=!0}else h=!1;
h&&setTimeout(function(){if(history.replaceState){var a=location.href;history.replaceState(null,"","/");location.replace(a)}},1E3); })();
Same situation here although I found the following in the docs:
https://cloud.google.com/translate/quotas
https://cloud.google.com/translate/faq
In the second link there is a specific question about chars per request and it says it shouldn't be more than 5000
Im pretty new to Autobahn and WAMP (Web Apps Messaging Protocol).
Im just creating a simple Application Component based on http://autobahn.ws/python/wamp/programming.html and https://github.com/crossbario/crossbarexamples/blob/master/votes/python/votes.py
Below is my Server side Python
from autobahn.asyncio.wamp import (
ApplicationSession,
ApplicationRunner
)
from autobahn import wamp
from asyncio import coroutine
class MyComponent(ApplicationSession):
#wamp.register("com.myapp.add2")
def add2(self, x, y):
print("added 2")
return x + y
#wamp.register("com.myapp.add3")
def add3(self, x, y, z):
print("added 3")
return x + y + z
#coroutine
def onJoin(self, details):
res = yield from self.register(self)
print("{} procedures registered.".format(len(res)))
if __name__ == '__main__':
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(MyComponent)
and the Client side
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>AUTOBAHN_DEBUG = false;</script>
<script src="http://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz"></script>
<script>
var connection = new autobahn.Connection({
url: "ws://localhost:8080/ws",
realm: "realm1"
});
connection.onopen = function (session, details) {
session.call("com.myapp.add2", [2,3]).then(session.log);
session.call("com.myapp.add3", [2,3,4]).then(session.log);
};
connection.onclose = function (reason, details) {
console.log("Connection lost: " + reason);
};
connection.open();
</script>
</body>
</html>
Error
Looks like this is similar to https://github.com/hwmrocker/hextest/issues/2 but I can't get my head around. I can't even find a sample that works. This one (https://github.com/tavendo/AutobahnPython/tree/master/examples/asyncio/wamp/wamplet/wamplet1) is similar but it has the same issue as well.
Surprisingly, when I run an external Crossbar sample on the same Port and run the above example, it works like a magic and I can see the results on the console.
I found this one (https://github.com/tavendo/AutobahnPython/blob/master/examples/asyncio/wamp/basic/server.py) but it looks quite complicated.
Please help me out.
Thank you in Advanced.
Your code works for me without modification:
Your app consists of 2 WAMP application components: a browser side (using AutobahnJS), and a server side (using AutobahnPython/Python3/asyncio).
For these 2 components to talk to each other, both components need to connect to a WAMP router. I used Crossbar.io.
Note that your Python component is logically a server-side component, but it is not technically a server: it does not open a listening port or what, but it connects to a WAMP router.