Skip to content

Commit

Permalink
Add options and is_busy functionality to server
Browse files Browse the repository at this point in the history
 - Re-factor server code structure
 - Rename arguments request and repository
 - Add options to handler functions
 - Add minimal is_busy logic
  • Loading branch information
FrameConsult authored and sschlenkrich committed Apr 12, 2024
1 parent ea7b430 commit 9e0a209
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 364 deletions.
10 changes: 9 additions & 1 deletion src/DiffFusionServer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@ using Sockets

include("client/Requests.jl")

# server configurations
include("server/Config.jl")
include("server/Errors.jl")
include("server/Info.jl")
include("server/Options.jl")
include("server/Repository.jl")
include("server/Router.jl")
include("server/Utils.jl")

# server handlers and router
include("server/Infos.jl")
include("server/Gets.jl")
include("server/Posts.jl")
include("server/Deletes.jl")
include("server/Router.jl")

end
33 changes: 33 additions & 0 deletions src/server/Deletes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

"""
api_delete(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
Delete an object from repository.
Request header must contain field 'alias'. The value of field
'alias' is the object alias of requested object in the server
repository.
"""
function api_delete(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
res = _check_for_header_field(request, "alias")
if isa(res, HTTP.Message)
return res
end
res = _check_for_alias_in_repository(res, repository)
if isa(res, HTTP.Message)
return res
end
alias = res
obj_type = string(typeof(repository[alias]))
delete!(repository, alias)
msg = "Deleted object with alias " * alias * " and object type " * obj_type * "."
return HTTP.Response(_NO_HTTP_ERROR, JSON3.write(msg))
end
25 changes: 24 additions & 1 deletion src/server/Errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ end
Create error response for unknown server operation in http header.
Allowed operations are COPY and BUILD.
Allowed operations are COPY and BUILD and BUILD_ASYNC.
"""
function _error_operation_not_implemented(op::AbstractString)
HTTP.Response(213, JSON3.write("Operation " * op * " is not implemented."))
Expand Down Expand Up @@ -122,3 +122,26 @@ function _error_build_async_fail(alias::AbstractString, e::Exception)
msg = "Cannot create Future object for alias " * alias * ".\n" * string(e)
return HTTP.Response(221, JSON3.write(msg))
end

"""
_error_option_not_implemented(option_field::AbstractString, option_value::AbstractString)
Create error response for unknown server option/value combination in http header.
"""
function _error_option_not_implemented(option_field::AbstractString, option_value::AbstractString)
HTTP.Response(222, JSON3.write("Option " * option_field * " with value " * option_value * " is not implemented."))
end


## Use standard error codes in below error functions

"""
_error_server_is_busy()
Create an error response for a rejected (POST) operation due to *is_busy* flag.
"""
function _error_server_is_busy()
msg = "Cannot process POST request because server is flagged as busy."
return HTTP.Response(429, JSON3.write(msg))
end

147 changes: 147 additions & 0 deletions src/server/Gets.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@

"""
api_get(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
Return the object with requested alias header field in body of response.
This operation does not modify the server repository.
Request header must contain fields 'alias' and 'op'. The value of field
'alias' is the object alias of requested object in the server
repository. Value of field 'op' is 'COPY' or 'BUILD'.
For COPY operation, the requested data is directly written to JSON format.
For BUILD operation, the requested data is first serialised using DiffFusion
serialise operation. Then the serialised object is written to JSON format.
The resulting JSON object is returned via the response body.
"""
function api_get(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
#
res = _check_for_header_field(request, "alias")
if isa(res, HTTP.Message)
return res
end
res = _check_for_alias_in_repository(res, repository)
if isa(res, HTTP.Message)
return res
end
alias = res
res = _check_for_header_field(request, "op")
if isa(res, HTTP.Message)
return res
end
op = uppercase(res)
if !(op in _OPERATIONS)
return _error_operation_not_implemented(op)
end
obj = repository[alias]
local out_obj
if op==_BUILD_OP
try
out_obj = DiffFusion.serialise(obj)
catch e
return _error_object_serialisation_fail(alias, e)
end
else
out_obj = obj
end
local json3_string
try
json3_string = JSON3.write(out_obj)
catch e
return _error_create_json_string_fail(alias, e)
end
# finally return object...
return HTTP.Response(_NO_HTTP_ERROR, json3_string)
end


"""
api_bulk_get(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
Return a list of objects for a list of aliases.
This operation does not modify the server repository.
Request header must contain field 'op'. Value of field 'op' is
'COPY' or 'BUILD'.
Request body must contain a list of 'alias'. The list of 'alias'
is iterated. For each 'alias' the corresponding object is retrieved
from the server repository.
Handling of each individual object follows method `api_get`.
The result is a `Vector` of objects. This result is written to
JSON and returned via the response body.
"""
function api_bulk_get(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
# we need to retrieve the list of alias from the request body
local json3_obj
try
json3_obj = JSON3.read(request.body)
catch e
return _error_create_json_fail(alias, e)
end
if !isa(json3_obj, AbstractVector)
return _error_bulk_list_not_found(json3_obj)
end
for alias in json3_obj
res = _check_for_alias_in_repository(alias, repository)
if isa(res, HTTP.Message)
return res
end
end
#
res = _check_for_header_field(request, "op")
if isa(res, HTTP.Message)
return res
end
op = uppercase(res)
if !(op in _OPERATIONS)
return _error_operation_not_implemented(op)
end
res_list = []
for alias in json3_obj
obj = repository[alias]
local out_obj
if op==_BUILD_OP
try
out_obj = DiffFusion.serialise(obj)
catch e
return _error_object_serialisation_fail(alias, e)
end
else
out_obj = obj
end
res_list = vcat(res_list, [out_obj])
end
#
local json3_string
try
json3_string = JSON3.write(res_list)
catch e
return _error_create_json_string_fail("[]", e)
end
# finally return objects...
return HTTP.Response(_NO_HTTP_ERROR, json3_string)
end

27 changes: 27 additions & 0 deletions src/server/Infos.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

"""
api_get_info(request::HTTP.Request)
Return an info string about the API as response.
"""
function api_get_info(request::HTTP.Request)
return HTTP.Response(_NO_HTTP_ERROR, _INFO_STRING)
end


"""
api_get_aliases(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
Return all aliases from the repository in body of response.
"""
function api_get_aliases(
request::HTTP.Request,
repository::AbstractDict,
options::Options,
)
return HTTP.Response(_NO_HTTP_ERROR, JSON3.write(keys(repository)))
end
33 changes: 33 additions & 0 deletions src/server/Options.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

"""
mutable struct Options
is_busy::Bool
end
A container that holds flags and data which control the behaviour of the router.
The options object is created at inception of the router and passed to the
various handler functions.
`Options` element `is_busy` specifies that the server currently does not accept
POST requests. The flag may be set via the *is_busy* header field in a POST
request. The flag may be de-activated via the *is_busy* header field in
(subsequent) GET request.
"""
mutable struct Options
is_busy::Bool
end


"""
initial_options(
is_busy::Bool = false,
)
Create an `Options` object and initialise with default settings.
"""
function initial_options(
is_busy::Bool = false,
)
return Options(is_busy)
end
Loading

0 comments on commit 9e0a209

Please sign in to comment.