Use WebSocket wrapper for all iframe, ws requests - javascript

I'm trying to experiment if I can force all elements within an iframe (of dask-labextension to be precise) to use a custom web socket wrapper following answers to this question with the following snippet:
const iframe = document.getElementsByTagName("iframe")[0];
const originalSocket = iframe.contentWindow.WebSocket;
iframe.contentWindow.WebSocket = function(...args) {
const socket = originalSocket(...args);
console.log("Creating new socket: ", socket);
return socket;
};
iframe.contentWindow.WebSocket.prototype = originalSocket.prototype;
iframe.contentWindow.WebSocket.prototype.constructor = iframe.contentWindow.WebSocket;
JupyterLab's Dask Extension loads a bunch of dashboards as iframes, each of which includes the following bokeh js files:
<head>
<meta charset="utf-8">
<title>Bokeh Application</title>
<script type="text/javascript" src="static/js/bokeh.min.js?v=3c61e952b808bb7e346ce828a565a5f23aaf7708d034fa9d0906403813355d45bb4e8d8b0b23a93f032c76831d4f0221846f28699c7f5147caa62e0d31668314"></script>
<script type="text/javascript" src="static/js/bokeh-gl.min.js?v=e5df31fd9010eacff0aa72d315264604b5e34972ba445acea6fce98080eecf33acf2d2986126360faaa5852813cffa16f6f6f4889923318300f062497c02da4e"></script>
<script type="text/javascript" src="static/js/bokeh-widgets.min.js?v=8a1ff6f5aa0d967f4998d275803bbb111d928fd9f605ef9e1f30cfd021df0e77224ee3d13f83edb3a942f6e4ccc569ee5dd8951a8aa6cb600602463b90c65a87"></script>
<script type="text/javascript" src="static/js/bokeh-tables.min.js?v=ae2903e57cf57f52819fdf4d938c648982b51c34f73b6e653a0f3bb3c8ab44f338505931ace43eafc1636e215492e2314acf54c54baffb47813b86b4923a7fe0"></script>
<script type="text/javascript" src="static/js/bokeh-mathjax.min.js?v=176c36fdbcd8fc1019fc828101a2804081a35baf4018d7f2633cd263156b593aa73112f400112b662daa0590138b74851bc91f1f2a5fbf5416ee8c876c3e0d0c"></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
</head>
But it looks like all of Bokeh's websocket requests goes through a separate WebSocket object, instead of my custom wrapper. The following are console logs coming from Bokeh:
[bokeh] setting log level to: 'info'
bokeh.min.js?v=3c61e952b808bb7e346ce828a565a5f23aaf7708d034fa9d0906403813355d45bb4e8d8b0b23a93f032c76831d4f0221846f28699c7f5147caa62e0d31668314:587 [bokeh] Websocket connection 0 is now open
bokeh.min.js?v=3c61e952b808bb7e346ce828a565a5f23aaf7708d034fa9d0906403813355d45bb4e8d8b0b23a93f032c76831d4f0221846f28699c7f5147caa62e0d31668314:165 [bokeh] document idle at 94 ms
bokeh.min.js?v=3c61e952b808bb7e346ce828a565a5f23aaf7708d034fa9d0906403813355d45bb4e8d8b0b23a93f032c76831d4f0221846f28699c7f5147caa62e0d31668314:163 Bokeh items were rendered successfully
The console output seems to be missing the console log I have around my custom wrapper, which makes me think it uses a different WebSocket function.
Is there a way to force Bokeh (or any other included script's) websockets to use my custom wrapper?

Related

How to implement only client to graphql subscriptions in a website with only front code?

I am coding a only front end site using Django. to query data to a DataBase I use AJAX to my Django and Django requests a third party GraphQL. so far all works perfect. But now I need to alert the users on updates to a table. the third party has setup subscriptions. I know is working because I made a view with the play ground, execute the subscription and on updates, the playground shows the update.
So how can I implemente those subscriptions to my site so on updates I can do console.log(subscriptionUpdateMsg) ?
I have been looking for about 3 days and I have found many docs whith info, but they require node.js or other servers, the problem is that I already have all on Django server as I was required. and some other sites works with but I get error failed: Error during WebSocket handshake: Unexpected response code: 500
This is what the code creates, and is working:
screenshot here
Here is the working code with the playgroun in my site:
<html>
<head>
<style>
html,
body {
height: 100%;
margin: 0;
overflow: hidden;
width: 100%;
}
</style>
<link
href="//cdn.jsdelivr.net/npm/graphiql#0.11.11/graphiql.css"
rel="stylesheet"
/>
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
<script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/graphiql#0.11.11/graphiql.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/graphql-transport-ws#0.8.3/browser/client.js"></script>
</head>
<body>
<script>
// Setup subscription client.
const GRAPHQL_ENDPOINT =
(location.protocol === "https" ? "wss" : "ws") +
"://" +
//location.host +
"apiclients.develop.ThirdPartyWebSite.com:8009/graphql/"
let subClient = new window.SubscriptionsTransportWs.SubscriptionClient(
GRAPHQL_ENDPOINT,
{reconnect: true},
)
subFetcher = subClient.request.bind(subClient)
// Render <GraphiQL /> into the body.
ReactDOM.render(
React.createElement(GraphiQL, {
fetcher: subFetcher, //graphQLFetcher
}),
document.body,
)
</script>
</body>
</html>
Since I could not find any tutorials or full examples I made hours of test on the browser console and now I see that is easy:
1: add the javascript src="//cdn.jsdelivr.net/npm/graphql-transport-ws#0.8.3/browser/client.js
2: with only this javascript we are ready to subscribe
const GRAPHQL_ENDPOINT =
(location.protocol === "https" ? "wss" : "ws") +
"://apiclients.develop.ThirdPartyWebSite.com:8009/graphql/"
let subClient = new window.SubscriptionsTransportWs.SubscriptionClient(
GRAPHQL_ENDPOINT,
{reconnect: true},
)
with the next line:
subClient.subscribe({query:'subscription{onNewReservation(group:"clients"){reservationId}}'}, function(error,data){console.log(data); })
☺

Accessing scala.js output in resources

I'm trying to build a application server using scala.js, scalatags, akka-http, and mill as my build tool. All goes well until the browser tries to find scripts with generated scala.js code. This is the scalatags code which successfully gets built and references the compiled scala.js code (HiPage.js - built as a ScalaJSModule in mill). When it is run the println below prints out:
file:/Users/nnovod/projects/lims/LIMS/resources/HiPage.js
which is indeed where I've placed the javascript output from scala.js
object HiPage {
val boot =
"Hi().main(document.getElementById('contents'))"
println(getClass.getResource("/HiPage.js").toString)
val skeleton =
html(
head(
script(`type`:="text/javascript", src:="/HiPage.js"),
link(
rel:="stylesheet",
href:="https://cdnjs.cloudflare.com/ajax/libs/pure/0.5.0/pure-min.css"
)
),
body(
onload:=boot,
div(id:="contents")
)
)
}
This eventually shows up in the browser as follows:
<html>
<head>
<script type="text/javascript" src="/HiPage.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pure/0.5.0/pure-min.css"/>
</head>
<body onload="Hi().main(document.getElementById('contents'))">
<div id="contents"></div>
</body>
</html>
This is my akka-http route...
val route =
path("hello") {
get {
complete(
HttpEntity(
ContentTypes.`text/html(UTF-8)`,
HiPage.skeleton.render
)
)
}
}
The browser can never find the HiPage.js ("Failed to load resource: the server responded with a status of 404 (Not Found)"). HiPage.js is in a top level resources directory and is found by the println(getClass.getResource("/HiPage.js").toString) in the code. What do I have to do to get it seen when the browser requests it from the server?
Not sure if this is the best way but I finally was able to solve the problem by having all src references in script start with /resource and then editing my akka-http route to include the following:
pathPrefix("resource") {
extractUnmatchedPath { unmatched =>
val resource = unmatched.toString()
if (!resource.startsWith("/"))
reject()
else
getFromResource(resource.substring(1))
}
}

JavaScript - order of execution of <script> tags

As stated in this SO question and many other similar, the order of execution of <script>s on the page should be the same as the order in which these tags are defined in the html document.
I created a simple Java (server side) test app that allows to execute a request and wait specified period of time before returning a response (relevant code snippet at the bottom of this question). It has a simple API:
http://localhost:8080/latency?time=XXX&response=YYY
Example request that will return console.log('done') after one second (1000ms):
http://localhost:8080/latency?time=1000&response=console.log(%27done%27)
Next I created a simple index.html page (served by nginx):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test order</title>
</head>
<body>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=1000&response=console.log(%27done1%27)"></script>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=100&response=console.log(%27done2%27)"></script>
<script type="text/javascript" async=false src="http://localhost:8080/latency?time=10&response=console.log(%27done3%27)"></script>
<script>console.log('static script without "src" attr');</script>
</body>
</html>
According to everything I read so far I expected the order of console output to be:
done1
done2
done3
static script without "src" attr
This is what I got (Firefox 51 dev console):
This is just the opposite order of what I expected to get. Am I missing something? Is there a way to execute these scripts in the desired order (i.e. in the order they are defined in HTML)?
As a reference, the Java part on a server side:
private String latency(HttpServletRequest request) {
long millis = Long.parseLong(request.getParameter("time"));
String response = request.getParameter("response");
try {
Thread.sleep(millis);
return (response != null) ? response : "";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
async is a boolean attribute. Its value does not matter. Remove the attribute.

include the JS source in the existing *.js file

I have MqttConnect.js file and mqttws31.js lib . I have to mqttws31.js all source code include my MqttConnect.js file, How it possible?.
when I copy everything from mqttws31.js and past mqttconnect.js file .that time this error occur:
ReferenceError: Messaging is not defined
if I try this way it is working fine :
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
<script src="http://www.hivemq.com/demos/websocket-client/js/mqttws31.js" type="text/javascript"></script>
<script src="MqttJS/MqttConnect.js"></script>
</head>
MqttConnect.js file code :
// Using the HiveMQ public Broker, with a random client Id
var client = new Messaging.Client("broker.mqttdashboard.com",8000, "myclientid_" + parseInt(Math.random() * 100, 10));
//Connect Options
var options = {
timeout: 60,
keepAliveInterval:450,
cleanSession:false,
//Gets Called if the connection has sucessfully been established
onSuccess: function () {
alert("Connected:");
},
//Gets Called if the connection could not be established
onFailure: function (message) {
alert("Connection failed -: " + message.errorMessage);
}
};
function Connect(){
try {
client.connect(options)
}
catch(err){
alert(err.message);
}
}
mqttws31.js code:
http://www.hivemq.com/demos/websocket-client/js/mqttws31.js
UPDATE
where I want use this , there have no html page
This may be due to a quirk of how JavaScript loads. You can find a good example of how it should be done in this answer.
The quick answer is to place the loading of both JavaScript files into the body of the HTML document hosting them, with the MQTT library above your script.
Do NOT just copy the library into your own file, that's very poor form and a copyright violation if you don't credit the library's source properly.
Copy content of mqttws31.js into MqttConnect.js at the top (not at the bottom) and then load MqttConnect.js file:
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
<script src="MqttJS/MqttConnect.js"></script>
</head>
I tried this myself, I am not getting any error. (window is undefined)
There is a dependency between the two files, that is, there is code in MqttConnect.js which needs the code in mqttws31.js in order to work properly. So I'm assuming you pasted the contents of mqttws31.js at the end of MqttConnect.js. Pasting the contents of mqttws31.js at the beginning of MqttConnect.js should fix this. Your MqttConnect.js should look like
// Contents of mqttws31.js ...
// Contents of MqttConnect.js ...

javascript Thrift client hangs

I have the following Thrift client code in javascript:
<script language="javascript" type="text/javascript" src="thrift.js" />
<script language="javascript" type="text/javascript" src="QuantSvc_types.js" />
<script language="javascript" type="text/javascript" src="QuantSvc.js" />
<script language="javascript" type="text/javascript">
function calc() {
var transport = new Thrift.Transport("http://localhost:9997/QuantSvc/");
var protocol = new Thrift.Protocol(transport);
var client = new QuantSvcClient(protocol);
try {
result = client.ListAllVariables()
} catch(ouch) {
alert("An exception occurred!")
}
}
</script>
Which is triggered when I push a button on my HTML page. Then, I have the following server-side Scala code, running on localhost:9997:
object Application extends App {
val handler = new QuantSvcHandler()
val processor = new QuantSvc.Processor(handler)
val serverTransport = new TServerSocket(9997)
val server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor))
}
Where the QuantSvcHandler's ListAllVariables function is (basically a skeleton function, just trying to get things to work):
override def ListAllVariables(): util.List[Attributes] =
{
var input = scala.collection.mutable.Buffer[Attributes]()
input
}
I put a breakpoint at the first line of ListAllVariables, and also a few places in the QuantSvcHandler processor. I run the server in debug in intellij IDEA, open my HTML page in Chrome, and push the button (the one that calls the javascript calc() function). The button stays stuck and I see no kind of response on the server, the breakpoints aren't being hit.
Any ideas about what I'm doing wrong?
You mix a HTTP client with a socket server.
Although HTTP uses sockets, the Thrift HTTP transport is not compatible with the Thrift Sockets transport. You need to set up the exact same protocol/transport stack on both ends. The only exception to that rule is that some server transports implicitly require an additional framed transport layer on the client side.
So the solution is to use a HTTP server. Depending on the version you use, you may also have to switch to the JSON protocol.

Categories