How to call a Julia function from an application running in a web browser
I believe you want:
(or one of the alternatives mentioned there, OR this latest package):
[EDIT: It used to be called Websocket.jl when I originally wrote this post, was renamed, see link at the bottom.]
I noticed the latter package registered a few days ago, but now when looking into it, it seemed to have years of development, and I was confusingly looking at the former package…
I do not know too much about these packages, or the standardized API, but I believe it’s exactly what you’re looking for. You would runs some JavaScript code in the web browser to access the Julia websocket. In general you can compile Julia code to JavaScript too, with JSExpr.jl, but I’m not sure if it helps with this, at least that would be optional.
An alternative approach is to host your page using Genie.jl. Depending on what you want, this can be highly advantageous. I’ve been doing this for a web app at work, and I can ring down to shell via run()
send emails with postmail, use LibPQ to crunch some numbers, log activity, upload files via genie+html forms, and spit out some pretty css/html to say what is happening, open JIRA issues via the REST API. All with Julia at the middle. Julia is almost made for the web - except it’s not yet…
Please consider SimpleWebsockets and not Websocket
. I was asked to rename the package to be more distinct from JuliaWeb/WebSockets
.
Sorry about the confusion.
Thank you for your reply,
could you please share more detail ?
What I am looking for is an application / process that would allow me to run Julia, without having to manually trigger it every time.
Ideally through VBA or hosting it on a server
As a generic technology solution for this, you could consider Remote Procedure Call solutions such as GRPC. There is no official Julia support for GRPC, but I have spotted some work on Github towards this.
Another approach would be to implement a messaging BUS architecture with any of the many solutions such as Kafka, ZeroMQ, RabbitMQ, MQTT, etc, etc…
And as mentioned before, you can achieve the same using messaging over websockets.
Or http request / response with a http server on your Julia instance.
I did a similar proof of concept a while back that you can check out here:
Backend API:
https://github.com/mthelm85/JuliaAPI
Client side (built with Vue.js):
https://github.com/mthelm85/JuliaAPIClient
I have the Julia API running on a free Heroku dyno and the client running on another free Heroku dyno:
Client: https://julia-api-client.herokuapp.com/
API: https://julia-api-example.herokuapp.com/addxy
It’s not set up properly so if you test the client app in your browser it throws a network error and you have to wait and keep clicking “Compute” but it will eventually return something ; )
You can also just play with the API endpoint by doing something like this:
https://julia-api-example.herokuapp.com/addxy?x=4&y=4
which will return the sum of x and y (8).
It’s strange, I just played with it now for the first time in a long time and when everything starts up it’s really slow and clunky but once you compute a few sums it seems to speed up a bit. I know those free Heroku dynos go into some sort of hibernate mode and have to wake up once someone makes a request to the URLs but I’m not sure why it seems to need to “warm up” to get going.
For a more high level example see also this post that uses Interact + Mux.
EDIT: I saw now your other post on this thread, maybe this is not what you want… if your only need is to not “manually” run the application you could maybe just use the cron system of your server ?
Please share with us what the Julia code is doing - what sort of task? Also the enviironment where you want the code to run.
This is the shortest, most ridiculously unsecure, bare metal way to remote control a Julia process from a html page I could think of using a websocket connection:
Julia
using Pkg
Pkg.add(name = "SimpleWebsockets", version = "0.1.4")
using SimpleWebsockets
server = WebsocketServer()
listen(server, :client) do ws
listen(ws, :message) do message
try
comm = Meta.parse(message)
result = Base.eval(@__MODULE__, comm)
send(ws, string(result))
catch err
@error err
send(ws, "Could not run command")
end
end
end
function echo(val)
return val
end
serve(server, 8081)
HTML (tested on Firefox)
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<title>Websockets are awesome</title>
<style>
body {
font-family: sans-serif;
height: 100vh;
padding: 0;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
input {
margin: 4px 0;
}
</style>
</head>
<body>
<form onsubmit='event.preventDefault(); sendcommand();'>
<label>Enter a Julia command:</label><br>
<input
type='text'
placeholder='eg. 1+1 or echo("hellooooo..")'
id='command'
/>
<span id='result'></span><br>
<input type='submit' value = 'Send command'>
</form>
<script>
input = document.getElementById('command');
result = document.getElementById('result');
const ws = new WebSocket('ws://localhost:8081')
ws.addEventListener('message', message => {
result.innerHTML = ` = ${message.data}`
})
function sendcommand(){
ws.send(input.value)
}
</script>
</body>
</html>
Uses port 8081, but that can be adjusted as you like.
Start the Julia code locally, save the HTML to index.html
and open it locally in your browser.
“It’s Slow to start” - Isn’t that because Julia is a compiled language ?
In this case I don’t believe that has anything to do with it as it’s just a simple sum function - I’m almost certain it’s a Heroku dyno thing. I don’t know that the Julia session ever actually shuts down - I think it’s just the dyno that goes to sleep (so it shouldn’t be recompiling anyting). I’ve hosted other applications on their free tier dynos and sometimes they seem to need to be jolted back to life by a few requests
In this case, the client is on one dyno and the API is on a second dyno so the client has to wake up, call the API, the API dyno has to wake up, then do the calculation and send the answer back to the client. I’m sure if these were on the paid-tier dynos they would run smoothly and without issue.
Please be very careful when following this advice since it will allow anyone who can access the web page to do whatever they want to the server.
To make it infinitely safer don’t read code that someone sends over the internet. Instead just trigger a prewritten script.
Don’t overcomplicate, to connect Browser JS to Julia all you need is half a page of code. Don’t use message busses, RPC frameworks, WebSockets and all sorts of other complicated things unless you are good paid to waste your time overengineering it.
Use any julia web server implemeting single /server/rpc
route, and this code in the browser:
async function call_server_function(fn: string, args: any[]): Promise<any> {
const res = await fetch(
`/server/rpc`,
{ method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([{ fn, args }])
})
return await res.json()
}
And if you need to initiate some task from the server, server push etc, this:
setInterval(async () => {
const result = await call_server_function('server_push', [])
if (result) do_something_with(result)
}, 200)
And when you make your app work, and for some reason need to scale it to millions of users (modern servers would easily handle hundreds and thousands requests/sec with this setup), then you may invest more time and build more complicated and performant solution.