Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch from WebSockets.jl to HTTP.jl #500

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ AssetRegistry = "bf4720bc-e11a-5d0c-854e-bdca1663c893"
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
FunctionalCollections = "de31a74c-ac4f-5751-b3fd-e18cd04993ca"
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
Observables = "510215fc-4207-5dde-b226-833fc4488ee2"
Expand All @@ -16,17 +17,16 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"
UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
WebSockets = "104b5d7c-a370-577a-8038-80a2059c5097"
Widgets = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62"

[compat]
AssetRegistry = "0.1.0"
FunctionalCollections = "0.5.0"
HTTP = "1"
JSExpr = "0.5"
JSON = "0.18, 0.19, 0.20, 0.21"
Observables = "0.5"
Requires = "0.4.4, 0.5, 1.0.0"
WebSockets = "1.5.0"
Widgets = "0.6.2"
julia = "0.7, 1"

Expand Down
2 changes: 1 addition & 1 deletion src/WebIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function __init__()
@require IJulia="7073ff75-c697-5162-941a-fcdaad2a7d2a" begin
include_string(@__MODULE__, provider_ijulia.code, provider_ijulia.file)
end
@require WebSockets="104b5d7c-a370-577a-8038-80a2059c5097" begin
@require HTTP="cd3eb016-35fb-5094-929b-558a96fad6f3" begin
include_string(@__MODULE__, provider_generic_http.code, provider_generic_http.file)
end

Expand Down
68 changes: 46 additions & 22 deletions src/providers/generic_http.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using .Sockets
import .AssetRegistry, .JSON
using .WebIO
using .WebSockets: is_upgrade, upgrade, writeguarded
using .WebSockets: HTTP
import .HTTP
import .HTTP.WebSockets


struct WSConnection{T} <: WebIO.AbstractConnection
sock::T
struct WSConnection <: WebIO.AbstractConnection
stream::HTTP.WebSocket
end

Sockets.send(p::WSConnection, data) = writeguarded(p.sock, JSON.json(data))
Base.isopen(p::WSConnection) = isopen(p.sock)
Sockets.send(p::WSConnection, data) = HTTP.send(p.stream, JSON.json(data))
Base.isopen(p::WSConnection) = !HTTP.WebSockets.isclosed(p.stream)

if !isfile(GENERIC_HTTP_BUNDLE_PATH)
error(
Expand All @@ -25,7 +25,7 @@ include(joinpath(@__DIR__, "..", "..", "deps", "mimetypes.jl"))
"""
Serve an asset from the asset registry.
"""
function serve_assets(req)
function serve_assets(req::HTTP.Request)
if haskey(AssetRegistry.registry, req.target)
filepath = AssetRegistry.registry[req.target]
if isfile(filepath)
Expand All @@ -42,22 +42,23 @@ function serve_assets(req)
return HTTP.Response(404)
end

function websocket_handler(ws)
function websocket_handler(ws::HTTP.WebSocket)
conn = WSConnection(ws)
while isopen(ws)
data, success = WebSockets.readguarded(ws)
!success && break
for data in ws
msg = JSON.parse(String(data))
WebIO.dispatch(conn, msg)
end
end

struct WebIOServer{S}
server::S
serve_task::Task
struct WebIOServer
server::HTTP.Server
end

kill!(server::WebIOServer) = put!(server.server.in, HTTP.Servers.KILL)

function kill!(s::WebIOServer)
close(s.server)
wait(s.server)
end

const singleton_instance = Ref{WebIOServer}()

Expand Down Expand Up @@ -93,17 +94,40 @@ function WebIOServer(
)
# TODO test if actually still running, otherwise restart even if singleton
if !singleton || !isassigned(singleton_instance)
function handler(req)

function handler(req::HTTP.Request)
response = default_response(req)
response !== missing && return response
return serve_assets(req)
end
function wshandler(req, sock)
req.target == websocket_route && websocket_handler(sock)

function wshandler(req::HTTP.Request)
if req.target == websocket_route
HTTP.WebSockets.upgrade(http) do clientstream
if !HTTP.WebSockets.isclosed(clientstream)
websocket_handler(clientstream)
end
end
end
end

server = HTTP.listen!(baseurl, http_port; stream = true, server_kw_args...) do http::HTTP.Stream
if HTTP.WebSockets.isupgrade(http.message)
wshandler(request)
else
request::HTTP.Request = http.message
request.body = read(http)

response = handler(request)
response.request = request

HTTP.startwrite(http)
write(http, response.body)
HTTP.closewrite(http)
end
end
server = WebSockets.ServerWS(handler, wshandler; server_kw_args...)
server_task = @async WebSockets.serve(server, baseurl, http_port, verbose)
singleton_instance[] = WebIOServer(server, server_task)

singleton_instance[] = WebIOServer(server)
bundle_url = get(ENV, "WEBIO_BUNDLE_URL") do
webio_base = WebIO.baseurl[]
base = if startswith(webio_base, "http") # absolute url
Expand All @@ -117,7 +141,7 @@ function WebIOServer(
while time() - start < wait_time
# Block as long as our server doesn't actually serve the bundle
try
resp = WebSockets.HTTP.get(bundle_url)
resp = HTTP.get(bundle_url)
resp.status == 200 && break
sleep(0.1)
catch e
Expand Down
2 changes: 1 addition & 1 deletion test/http-tests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using WebIO
using WebSockets
using HTTP
using Test

@testset "HTTP provider" begin
Expand Down