diff --git a/src/Server.jl b/src/Server.jl index 51c44700d..4de4d45d8 100644 --- a/src/Server.jl +++ b/src/Server.jl @@ -7,6 +7,7 @@ using HTTP, Sockets, HTTP.WebSockets import Millboard, Distributed, Logging import Genie import Distributed +import HTTP.Servers: Listener, forceclose """ @@ -15,8 +16,8 @@ import Distributed Represents a object containing references to Genie's web and websockets servers. """ Base.@kwdef mutable struct ServersCollection - webserver::Union{Task,Nothing} = nothing - websockets::Union{Task,Nothing} = nothing + webserver::Union{T,Nothing} where T <: HTTP.Server = nothing + websockets::Union{T,Nothing} where T <: HTTP.Server = nothing end """ @@ -101,7 +102,7 @@ function up(port::Int, if Genie.config.websockets_server !== nothing && port !== ws_port print_server_status("Web Sockets server starting at $host:$ws_port") - new_server.websockets = @async HTTP.listen(host, ws_port; verbose = verbose, rate_limit = ratelimit, server = wsserver, + new_server.websockets = HTTP.listen!(host, ws_port; verbose = verbose, rate_limit = ratelimit, server = wsserver, reuseaddr = reuseaddr, http_kwargs...) do http::HTTP.Stream if HTTP.WebSockets.isupgrade(http.message) HTTP.WebSockets.upgrade(http) do ws @@ -112,7 +113,7 @@ function up(port::Int, end command = () -> begin - HTTP.listen(parse(Sockets.IPAddr, host), port; verbose = verbose, rate_limit = ratelimit, server = server, + HTTP.listen!(parse(Sockets.IPAddr, host), port; verbose = verbose, rate_limit = ratelimit, server = server, reuseaddr = reuseaddr, http_kwargs...) do stream::HTTP.Stream try if Genie.config.websockets_server !== nothing && port === ws_port && HTTP.WebSockets.isupgrade(stream.message) @@ -134,16 +135,31 @@ function up(port::Int, server_url *= ("?" * join(["$(k)=$(v)" for (k, v) in query], "&")) end - status = if async + if async print_server_status("Web Server starting at $server_url") - @async command() else print_server_status("Web Server starting at $server_url - press Ctrl/Cmd+C to stop the server.") + end + + listener = try command() + catch + nothing + end + if !async && !isnothing(listener) + try + wait(listener) + catch + nothing + finally + close(listener) + # close the corresponding websocket server + new_server.websockets !== nothing && isopen(new_server.websockets) && close(new_server.websockets) + end end - if status !== nothing && status.state === :runnable - new_server.webserver = status + if listener !== nothing && isopen(listener) + new_server.webserver = listener try open_browser && openbrowser(server_url) @@ -237,18 +253,19 @@ end Shuts down the servers optionally indicating which of the `webserver` and `websockets` servers to be stopped. It does not remove the servers from the `SERVERS` collection. Returns the collection. """ -function down(; webserver::Bool = true, websockets::Bool = true) :: Vector{ServersCollection} +function down(; webserver::Bool = true, websockets::Bool = true, force::Bool = true) :: Vector{ServersCollection} for i in 1:length(SERVERS) - down(SERVERS[i]; webserver, websockets) + down(SERVERS[i]; webserver, websockets, force) end SERVERS end -function down(server::ServersCollection; webserver::Bool = true, websockets::Bool = true) :: ServersCollection - webserver && (@async Base.throwto(server.webserver, InterruptException())) - isnothing(websockets) || (websockets && (@async Base.throwto(server.websockets, InterruptException()))) +function down(server::ServersCollection; webserver::Bool = true, websockets::Bool = true, force::Bool = true) :: ServersCollection + close_cmd = force ? forceclose : close + webserver && !isnothing(server.webserver) && isopen(server.webserver) && close_cmd(server.webserver) + websockets && !isnothing(server.websockets) && isopen(server.websockets) && close_cmd(server.websockets) server end diff --git a/test/tests_AppServer.jl b/test/tests_AppServer.jl index 9785a541d..c7a4a7403 100644 --- a/test/tests_AppServer.jl +++ b/test/tests_AppServer.jl @@ -8,24 +8,24 @@ empty!(Genie.Server.SERVERS) servers = Genie.Server.up() - @test servers.webserver.state == :runnable + @test isopen(servers.webserver) servers = Genie.Server.down(servers) sleep(1) - @test servers.webserver.state == :failed - @test Genie.Server.SERVERS[1].webserver.state == :failed + @test !isopen(servers.webserver) + @test !isopen(Genie.Server.SERVERS[1].webserver) servers = Genie.Server.down!() empty!(Genie.Server.SERVERS) servers = Genie.Server.up(; open_browser = false) Genie.Server.down(servers; webserver = false) - @test servers.webserver.state == :runnable + @test isopen(servers.webserver) servers = Genie.Server.down(servers; webserver = true) sleep(1) - @test servers.webserver.state == :failed - @test Genie.Server.SERVERS[1].webserver.state == :failed + @test !isopen(servers.webserver) + @test !isopen(Genie.Server.SERVERS[1].webserver) servers = nothing end;