Skip to content

Commit

Permalink
rendering support for custom status codes and headers, WebChannels fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Adrian Salceanu committed Jul 14, 2019
1 parent e89d33a commit 303838c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 38 deletions.
4 changes: 2 additions & 2 deletions src/Genie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ end


"""
newapp(path = "."; autostart = true, fullstack = true, dbsupport = true) :: Nothing
newapp(path = "."; autostart = true, fullstack = false, dbsupport = true) :: Nothing
Scaffolds a new Genie app.
"""
function newapp(path = "."; autostart = true, fullstack = true, dbsupport = true) :: Nothing
function newapp(path = "."; autostart = true, fullstack = false, dbsupport = true) :: Nothing
REPL.newapp(path, autostart = autostart, fullstack = fullstack, dbsupport = dbsupport)
end
const new_app = newapp
Expand Down
5 changes: 3 additions & 2 deletions src/Plugins.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ const APP_FOLDER = Genie.APP_PATH
const path_prefix = joinpath(@__DIR__, "..", FILES_FOLDER, "new_app") |> normpath |> relpath
const FOLDERS = [ joinpath(path_prefix, APP_FOLDER),
joinpath(path_prefix, "db"),
joinpath(path_prefix, "lib"),
joinpath(path_prefix, Genie.LIB_PATH),
joinpath(path_prefix, PLUGINS_FOLDER),
joinpath(path_prefix, TASKS_FOLDER) ]
joinpath(path_prefix, TASKS_FOLDER),
joinpath(path_prefix, Genie.DOC_ROOT_PATH) ]


function recursive_copy(path::String, dest::String; only_hidden = true, force = false)
Expand Down
47 changes: 29 additions & 18 deletions src/Renderer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,28 @@ const DEFAULT_CONTENT_TYPE = :html

"""
"""
function html(resource::Union{Symbol,String}, action::Union{Symbol,String}; layout::Union{Symbol,String} = Genie.config.renderer_default_layout_file, context::Module = @__MODULE__, vars...) :: Dict{Symbol,HTMLString}
function html(resource::Union{Symbol,String}, action::Union{Symbol,String}; layout::Union{Symbol,String} = Genie.config.renderer_default_layout_file,
context::Module = @__MODULE__, vars...) :: Dict{Symbol,HTMLString}
Dict(:html => (Flax.html_renderer(resource, action; layout = layout, mod = context, vars...) |> Base.invokelatest))
end
function html(data::String; context::Module = @__MODULE__, vars...) :: Dict{Symbol,HTMLString}
Dict(:html => (Flax.html_renderer(data; mod = context, vars...) |> Base.invokelatest))
end
function html!(resource::Union{Symbol,String}, action::Union{Symbol,String}; layout::Union{Symbol,String} = Genie.config.renderer_default_layout_file, context::Module = @__MODULE__, vars...) :: HTTP.Response
html(resource, action; layout = layout, context = context, vars...) |> respond


"""
"""
function html!( resource::Union{Symbol,String}, action::Union{Symbol,String}; layout::Union{Symbol,String} = Genie.config.renderer_default_layout_file,
context::Module = @__MODULE__, status::Int = 200, headers::Dict{String,String} = Dict{String,String}(), vars...) :: HTTP.Response
respond(html(resource, action; layout = layout, context = context, vars...), status, headers)
end
function html!(data::String; context::Module = @__MODULE__, vars...) :: HTTP.Response
html(data; context = context, vars...) |> respond
function html!(data::String; context::Module = @__MODULE__, status::Int = 200, headers::Dict{String,String} = Dict{String,String}(), vars...) :: HTTP.Response
respond(html(data; context = context, vars...), status, headers)
end

### JSON RENDERING ###

"""
json(resource::Symbol, action::Symbol, check_nulls::Vector{Pair{Symbol,Nullable}} = Vector{Pair{Symbol,Nullable}}(); vars...) :: Dict{Symbol,String}
Invokes the JSON renderer of the underlying configured templating library.
"""
function json(resource::Union{Symbol,String}, action::Union{Symbol,String}; context::Module = @__MODULE__, vars...) :: Dict{Symbol,JSONString}
Expand All @@ -50,11 +54,15 @@ end
function json(data) :: Dict{Symbol,JSONString}
Dict(:json => JSON.json(data))
end
function json!(resource::Union{Symbol,String}, action::Union{Symbol,String}; context::Module = @__MODULE__, vars...) :: HTTP.Response
json(resource, action; mod = context, vars...) |> respond


"""
"""
function json!(resource::Union{Symbol,String}, action::Union{Symbol,String}; context::Module = @__MODULE__, status::Int = 200, headers::Dict{String,String} = Dict{String,String}(), vars...) :: HTTP.Response
respond(json(resource, action; mod = context, vars...), status, headers)
end
function json!(data) :: HTTP.Response
json(data) |> respond
function json!(data; status::Int = 200, headers::Dict{String,String} = Dict{String,String}()) :: HTTP.Response
respond(json(data), status, headers)
end

### REDIRECT RESPONSES ###
Expand All @@ -64,11 +72,11 @@ end
Sets redirect headers and prepares the `Response`.
"""
function redirect_to(location::String, code = 302, headers = Dict{String,String}()) :: HTTP.Response
function redirect_to(location::String, code::Int = 302, headers::Dict{String,String} = Dict{String,String}()) :: HTTP.Response
headers["Location"] = location
respond(Dict{Symbol,String}(:plain => "Redirecting you to $location"), code, headers)
end
function redirect_to(named_route::Symbol, code = 302, headers = Dict{String,String}()) :: HTTP.Response
function redirect_to(named_route::Symbol, code::Int = 302, headers::Dict{String,String} = Dict{String,String}()) :: HTTP.Response
redirect_to(Genie.Router.link_to(named_route), code, headers)
end

Expand All @@ -89,7 +97,7 @@ end
Constructs a `Response` corresponding to the content-type of the request.
"""
function respond(body::Dict{Symbol,T}, code::Int = 200, headers = Dict{String,String}())::HTTP.Response where {T}
function respond(body::Dict{Symbol,T}, code::Int = 200, headers::Dict{String,String} = Dict{String,String}())::HTTP.Response where {T}
sbody::String = if haskey(body, :json)
headers["Content-Type"] = CONTENT_TYPES[:json]
body[:json]
Expand Down Expand Up @@ -123,19 +131,22 @@ end
function respond(err::T, content_type::Union{Symbol,String} = Genie.Router.response_type(), code::Int = 500)::HTTP.Response where {T<:Exception}
HTTP.Response(code, (isa(content_type, Symbol) ? ["Content-Type" => CONTENT_TYPES[content_type]] : ["Content-Type" => content_type]), body = string(err))
end

function respond(body::String, content_type::Union{Symbol,String} = Genie.Router.response_type(), code::Int = 200) :: HTTP.Response
HTTP.Response(code, (isa(content_type, Symbol) ? ["Content-Type" => CONTENT_TYPES[content_type]] : ["Content-Type" => content_type]), body = body)
end
function respond(body, code::Int = 200, headers = Dict{String,String}())
HTTP.Response(code, [h for h in headers], body = string(body))
end
function respond(f::Function, code::Int = 200, headers = Dict{String,String}())
respond(f(), code, headers)
end

### ASSETS ###

"""
http_error(status_code; id = "resource_not_found", code = "404-0001", title = "Not found", detail = "The requested resource was not found")
Constructs an error `Response`.
"""
function http_error(status_code; id = "", code = "", title = "", msg = "") :: HTTP.Response
function http_error(status_code; id = "", code = "", title = "", msg = "") :: HTTP.Response # TODO: check this!
respond(Dict(Genie.Router.response_type() => msg), status_code, Dict{String,String}())
end
const error! = http_error
Expand Down
6 changes: 3 additions & 3 deletions src/Router.jl
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ end
"""
"""
function extract_request_params(req::HTTP.Request, params::Params) :: Nothing
req.method != POST && return nothing
req.method in [POST, PUT, PATCH] || return nothing

params.collection[Genie.PARAMS_RAW_PAYLOAD] = String(req.body)

Expand All @@ -771,7 +771,7 @@ end
"""
"""
function content_type(req::HTTP.Request) :: String
get(HTTPUtils.req_headers_to_dict(req), "content-type", "")
get(Genie.HTTPUtils.req_headers_to_dict(req), "content-type", "")
end
function content_type() :: String
content_type(_params_(Genie.PARAMS_REQUEST_KEY))
Expand All @@ -781,7 +781,7 @@ end
"""
"""
function content_length(req::HTTP.Request) :: Int
parse(Int, get(HTTPUtils.req_headers_to_dict(req), "content-length", "0"))
parse(Int, get(Genie.HTTPUtils.req_headers_to_dict(req), "content-length", "0"))
end
function content_length() :: Int
content_length(_params_(Genie.PARAMS_REQUEST_KEY))
Expand Down
40 changes: 27 additions & 13 deletions src/WebChannels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ using Genie.Loggers


const ClientId = UInt # web socket hash
const ChannelName = Union{String,Symbol}
const ChannelName = String

mutable struct ChannelClient
client::HTTP.WebSockets.WebSocket
Expand Down Expand Up @@ -100,7 +100,7 @@ end
Unsubscribes a web socket client `ws` from `channel`.
"""
function unsubscribe(ws::HTTP.WebSockets.WebSocket, channel::ChannelName) :: ChannelClientsCollection
haskey(CLIENTS, id(ws)) && delete!(CLIENTS[id(ws)].channels, channel)
haskey(CLIENTS, id(ws)) && deleteat!(CLIENTS[id(ws)].channels, CLIENTS[id(ws)].channels .== channel)
pop_subscription(id(ws), channel)

CLIENTS
Expand All @@ -126,21 +126,29 @@ function unsubscribe_client(ws::HTTP.WebSockets.WebSocket) :: ChannelClientsColl
end
function unsubscribe_client(client_id::ClientId) :: ChannelClientsCollection
unsubscribe_client(CLIENTS[client_id].client)

CLIENTS
end
function unsubscribe_client(channel_client::ChannelClient) :: ChannelClientsCollection
unsubscribe_client(channel_client.client)

CLIENTS
end


function unsubscribe_disconnected_clients() :: ChannelClientsCollection
for channel_client in disconnected_clients()
unsubscribe_client(channel_client)
end

CLIENTS
end
function unsubscribe_disconnected_clients(channel::ChannelName) :: ChannelClientsCollection
for channel_client in disconnected_clients(channel)
unsubscribe(channel_client, channel)
end

CLIENTS
end


Expand Down Expand Up @@ -197,23 +205,29 @@ Pushes `msg` (and `payload`) to all the clients subscribed to the channels in `c
function broadcast(channels::Union{ChannelName,Vector{ChannelName}}, msg::String) :: Bool
isa(channels, Array) || (channels = ChannelName[channels])

@sync @distributed for channel in channels
for client in SUBSCRIPTIONS[channel]
message(client, msg)
try
for channel in channels
for client in SUBSCRIPTIONS[channel]
message(client, msg)
end
end
catch
end

true
end
function broadcast(channels::Union{ChannelName,Vector{ChannelName}}, msg::String, payload::Dict) :: Bool
isa(channels, Array) || (channels = ChannelName[channels])
isa(channels, Array) || (channels = [channels])

@sync @distributed for channel in channels
in(channel, keys(SUBSCRIPTIONS)) || continue
try
for channel in channels
in(channel, keys(SUBSCRIPTIONS)) || continue

for client in SUBSCRIPTIONS[channel]
message(client, ChannelMessage(channel, client, msg, payload) |> JSON.json)
for client in SUBSCRIPTIONS[channel]
message(client, ChannelMessage(channel, client, msg, payload) |> JSON.json)
end
end
catch
end

true
Expand All @@ -233,10 +247,10 @@ end
"""
Pushes `msg` (and `payload`) to `channel`.
"""
function message(channel::ChannelName, msg::String, payload::Union{Dict,Nothing} = nothing) :: Nothing
function message(channel::ChannelName, msg::String, payload::Union{Dict,Nothing} = nothing) :: Bool
payload == nothing ?
broadcast(ChannelName[channel], msg) :
broadcast(ChannelName[channel], msg, payload)
broadcast(channel, msg) :
broadcast(channel, msg, payload)
end


Expand Down

0 comments on commit 303838c

Please sign in to comment.