REDACProtocol
Documentation for REDACProtocol. A packge which defines a the protocl to communicate with REDAC computers.
Types of messages
There are 4 types of messages.
- Request sent from the client running library to a REDAC
- Responeses from the server to the client answering a request
- Errors from the server to the client communcation about problem to a request
- Notifications send out by the server to the client
Each request has one and only one response or error.
Enveloping messages
Messages exchanged between the server and the client are always wrapped in an envelope which carries metadata about the messages. See:
REDACProtocol.RequestEnvelope — Typestruct RequestEnvelope{MType<:AbstractREDACMachine, MsgType<:AbstractREDACRequest} <: REDACProtocol.AbstractREDACEnvelopeid::Base.UUID: Unique identifier under which the reply is extectedmsg::AbstractREDACRequest: A message which contains the data to process the request. An instance of a subtype of AbstractREDACRequesttype::Symbol: Type of the message. Reply usually has the same type.
REDACProtocol.ResponseEnvelope — Typestruct ResponseEnvelope{MType<:AbstractREDACMachine, MsgType<:AbstractREDACResponse} <: REDACProtocol.AbstractREDACEnvelopeid::Base.UUID: Unique identifier noting which previous message this repliesmsg::AbstractREDACResponse: A message which contains the results of the processed request. An instance of a subtype of AbstractREDACResponsetype::Symbol: Type of the message. Usually the same type as the request.success::Bool: Correctly processed request always havesuccess == true
REDACProtocol.NotificationEnvelope — Typestruct NotificationEnvelope{MType<:AbstractREDACMachine, MsgType<:AbstractREDACNotification} <: REDACProtocol.AbstractREDACEnvelopemsg::AbstractREDACNotification: Contains server send information not associated with any particular request. An instance of a subtype of AbstractREDACNotificationtype::Symbol: Type of the notification.
REDACProtocol.ErrorEnvelope — Typestruct ErrorEnvelope{MType<:AbstractREDACMachine, MsgType<:AbstractREDACResponse} <: REDACProtocol.AbstractREDACEnvelopeid::Base.UUID: An error raised in response the request with the same id.type::Symbol: Matches type of the message it is responding tosuccess::Bool: Always falseerror::String: Human readable error which should be shown to the user.
This format is unambigious if one knows one is a client or is a server.
Parsing messages
The protocol uses JSON for transport. This is accomplished by representing the format as StructTypes.jl and using JSON3 for serialisation and deserialisation. As this library can be used both for clients and for end points presenting as REDACs the library has provides means to parse a message as a client or a REDAC by using these two exported constants which are parametrized on the type of machine.
REDACProtocol.MatchTypeHcAbstract — TypeMatchTypeHCAbstract{AbstractREDACMachine} handles machine specific stuff as a dict.
REDACProtocol.MatchTypeClientAbstract — TypeMatchTypeClientAbstract{AbstractREDACMachine} handles machine specific stuff as a dict.
For machine independ functionality
We observe that a client has no problem parsing this Error message sent while a server complains bitterly.
julia> using JSON3, REDACProtocol;julia> amsg = "{\"id\":\"1538250c-a380-4596-a766-5b794e6dee63\",\"type\":\"start_session\",\"success\":false,\"error\":\"The service is being rebooted\"}";julia> JSON3.read(amsg, MatchTypeClient)ERROR: MethodError: no method matching AbstractRecievedEnvelope()julia> JSON3.read(amsg, MatchTypeREDAC)ERROR: UndefVarError: `MatchTypeREDAC` not defined
Creating readable error messages for this was not a priority, as only a developer can encounter these by accident. It is the developers responsibility to throw a more human readable error.
The internal parsing machinery
If you are not interested in understanding what happens when you add new messages then you can skip to the protocol specification. For parsing this in an extendable manner we rely on both Julias type hierarchy and on a different hierarchcy maintained by StructTypes.jl. The Julia type hierachy start with:
REDACProtocol.AbstractREDACEnvelope — Typeabstract type AbstractREDACEnvelope <: REDACProtocol.AbstractComparableAs per protocol definition messages send via the REDAC protocol need to be wrapped in such an envelope. We distinguish between Requests, Responses, Notifications and Errors.
Introduction and REDAC side parsing
Let's explore how the server side parsing works:
julia> MatchTypeREDACERROR: UndefVarError: `MatchTypeREDAC` not defined
JSON3.jl relying on StructTypes.jl tries to interpret the content of a message as a RequestEnvelope. To do it creates a new hierachy of subtyping independt of Julias own type hierarchy. For that it checks the subtypekey of the associated type. Reads that field in the JSON object then looks the value in the of Indexable thing stored in type associated subtypes. Once the subtype is looked an attempt is made to construct that subtype given the message. The associated source code for RequestEnvelope is:
StructTypes.StructType(::Type{RequestEnvelope}) = StructTypes.AbstractType()
StructTypes.subtypekey(::Type{RequestEnvelope}) = :type
@generated StructTypes.subtypes(::Type{RequestEnvelope}) = :(return $(Dict{
Symbol,
DataType,
}()))This returns the same dictionary which maps symbols to datatypes every time. Through macros we append to these Dicts to add new message types to handle.
REDACProtocol.@register_request — MacroSetups message mod{msg} with name for AbstractType mod
This diagram notes this pattern as
Client side parsing
The client can't know whether the next message is (in) a ResponseEnvelope, a NotificationEnvelope or a ErrorEnvelope. Thus we use the same AbstractType mechanism again. Our entry point is:
julia> MatchTypeClientAbstractRecievedEnvelope
Depending if the type of the message is associated with a notification we can build notification object right away depending on the type noted in the type field of the envelope which a NotificationEnvelope is guaranteed to have. Otherwise it is possible that the message could be either a ResponseEnvelope or an REDACProtocol.ErrorEnvelope. So we check the success field to determine this. We make heavy use of parametric types here.
StructTypes.StructType(::Type{AbstractRecievedEnvelope{T}}) where
{T <: AbstractREDACResponse} = StructTypes.AbstractType()Every AbstractRecievedEnvelope{T} where T can be any subtype of AbstractREDACResponse is treated as an AbstractType by StructTypes.jl. Every AbstractRecievedEnvelope{T} checks the success field to decide whether a ResponseEnvelope{T} or a ErrorEnvelope{T} should be created.
function StructTypes.subtypekey(::Type{
AbstractRecievedEnvelope{T},
}) where {T <: AbstractREDACResponse}
:success
end
function StructTypes.subtypes(::Type{
AbstractRecievedEnvelope{T},
}) where {T <: AbstractREDACResponse}
(; Symbol("true") => ResponseEnvelope{T}, Symbol("false") => ErrorEnvelope{T})
endAs notfications are subtypes of AbstractREDACNotification they don't go through this check, this check wouldn't even make sense as notifications don't have a success field. Instead they directly said to be structs in which case JSON3.jl relying on StructTypes.jl tries to interpret the content inside the msg field of the JSON as the matching notification object.
function StructTypes.StructType(::Type{T}) where {T <: AbstractREDACNotification}
StructTypes.Struct()
endSee
StructTypes.StructType(::Type{REDACProtocol.AbstractRecievedEnvelope{M}})All this machinery is maintained by using the macros to register your function.
REDACProtocol.@register_notification — MacroSetups message mod{msg} with name for AbstractType mod
REDACProtocol.@register_response — MacroSetups message msg with name
REDACProtocol.@register_antiphon — MacroSetups message req and rep with shared name for RequestEnvelope and ResponseEnvelope each.
@register_antiphon sets up a request-response pair and also convinently maintains the look up structure to get the expected response type from a request type.
Understanding the last two sections should enable developers to add new messages to the client and server.
Messages
This is an alphabetically sorted list of all stuff where there are docs strings for but not yet further described. Consult the python documentation for now.
REDACProtocol.GetConfigRequest — Typestruct GetConfigRequest <: AbstractREDACRequestentity::REDACProtocol.Path
REDACProtocol.GetConfigResponse — Typestruct GetConfigResponse{T} <: AbstractREDACResponseconfig::Anyentity::REDACProtocol.Path
REDACProtocol.GetMetadataRequest — Typestruct GetMetadataRequest <: AbstractREDACRequestentity::REDACProtocol.Path: Entity to request metadata from
REDACProtocol.GetMetadataResponse — Typestruct GetMetadataResponse{T} <: AbstractREDACResponseentity::REDACProtocol.Path: Path of the entityconfig::Any: Configuation of the entity
REDACProtocol.SetConfigRequest — Typestruct SetConfigRequest{T} <: AbstractREDACRequestconfig::Anyentity::REDACProtocol.Path
REDACProtocol.SetConfigResponse — Typestruct SetConfigResponse <: AbstractREDACResponseREDACProtocol.SetDAQRequest — Typestruct SetDAQRequest <: AbstractREDACRequestdaq::REDACProtocol.DAQConfiguration
REDACProtocol.SetDAQResponse — Typestruct SetDAQResponse <: AbstractREDACResponseREDACProtocol.GetEntitiesRequest — Typestruct GetEntitiesRequest <: AbstractREDACRequestREDACProtocol.GetEntitiesResponse — Typestruct GetEntitiesResponse <: AbstractREDACResponseentities::Dict{REDACProtocol.Path, Dict}
REDACProtocol.@register_antiphon — MacroSetups message req and rep with shared name for RequestEnvelope and ResponseEnvelope each.
REDACProtocol.@register_notification — MacroSetups message mod{msg} with name for AbstractType mod
REDACProtocol.@register_request — MacroSetups message mod{msg} with name for AbstractType mod
REDACProtocol.@register_response — MacroSetups message msg with name
REDACProtocol.MatchTypeClient — TypeUsing this constant as MatchTypeClientAbstract{MachineType} enables to parse the JSON arriving at the client to the correct Julia types.
REDACProtocol.MatchTypeHc — TypeUsing this constant as MatchTypeHCAbstract{MachineType} enables to parse the JSON arriving at the Hybridcontroller to the correct Julia types.
StructTypes.StructType — MethodAn AbstractRecievedEnvelope could either be a notification or a AbstractExpectedEnvelope. Both errors and responses are AbstractExpectedEnvelope.
StructTypes.StructType — MethodStructType(
_::Type{REDACProtocol.AbstractExpectedEnvelope{M<:AbstractREDACMachine, T<:AbstractREDACResponse}}
) -> StructTypes.AbstractType
Handles success dependent interpretation as a ResponseEnvelope or ErrorEnvelope. The success field must be set otherwise we crash.
REDACProtocol.getname — Methodgetname(D::DataType)A helper function. Looks up type string for a message using StructTypes dispatch data.
REDACProtocol.Ping — Typestruct Ping <: AbstractREDACRequestnow::Dates.DateTime
REDACProtocol.Pong — Typestruct Pong <: AbstractREDACResponsenow::Dates.DateTime
REDACProtocol.CancelRunRequest — Typestruct CancelRunRequest <: AbstractREDACRequestid::Base.UUID: Requests a canceling of this run
REDACProtocol.CancelRunResponse — Typestruct CancelRunResponse <: AbstractREDACResponseid::Base.UUID: Confirms which run was canceled.
REDACProtocol.RunDataMessage — Typestruct RunDataMessage <: AbstractREDACNotificationentity::REDACProtocol.Path: from which entityid::Base.UUID: Which run this data is for.data::Vector{Vector{Float64}}: Data from the run.
REDACProtocol.RunStateChangeMessage — Typestruct RunStateChangeMessage <: AbstractREDACNotificationid::Base.UUID: Which run changed statenew::RunState: Current stateold::RunState: Previous staterunflags::Union{Nothing, REDACProtocol.RunFlags}t::Int64
REDACProtocol.StartRunRequest — Typestruct StartRunRequest <: AbstractREDACRequestid::Base.UUID: Starts a run under this UUID.config::REDACProtocol.RunConfig: Configuation of the run.daq_config::Union{Nothing, REDACProtocol.DAQConfiguration}
REDACProtocol.StartRunResponse — Typestruct StartRunResponse <: AbstractREDACResponseREDACProtocol.EndSessionRequest — Typestruct EndSessionRequest <: AbstractREDACRequestid::Base.UUID: Cooie of the session to end
REDACProtocol.EndSessionResponse — Typestruct EndSessionResponse <: AbstractREDACResponseREDACProtocol.EntityReservationRequest — Typestruct EntityReservationRequest <: AbstractREDACRequestentities::Vector{REDACProtocol.Path}: Entities to try to reserveid::Base.UUID: Cookie for the session
REDACProtocol.EntityReservationResponse — Typestruct EntityReservationResponse <: AbstractREDACResponseREDACProtocol.StartSessionRequest — Typestruct StartSessionRequest <: AbstractREDACRequestentities::Vector{REDACProtocol.Path}: Entities to reserve with the beginning of the session
REDACProtocol.StartSessionResponse — Typestruct StartSessionResponse <: AbstractREDACResponseid::Base.UUID: Cookie for the session
REDACProtocol.DAQConfiguration — Typestruct DAQConfiguration <: REDACProtocol.AbstractComparablenum_channels::Int64sample_op::Boolsample_op_end::Boolsample_rate::Int64
REDACProtocol.Path — Typestruct Path <: REDACProtocol.AbstractComparableboard::String: MAC Address which identifies the carrier boardcluster::Union{Nothing, String}block::Union{Nothing, String}funct::Union{Nothing, Int64}
REDACProtocol.RunConfig — Typestruct RunConfig <: REDACProtocol.AbstractComparablehalt_on_external_trigger::Boolhalt_on_overload::Boolic_time::Int64op_time::Int64
REDACProtocol.RunFlags — Typestruct RunFlags <: REDACProtocol.AbstractComparableexternally_halted::Booloverloaded::Union{Nothing, Vector{REDACProtocol.Path}}
REDACProtocol.RunState — Typeprimitive type RunState <: Enum{Int32} 32Useful stuff for developers
Here are some utilities helpful for developers.
REDACProtocol.getname — Functiongetname(D::DataType)A helper function. Looks up type string for a message using StructTypes dispatch data.
Index
REDACProtocol.AbstractREDACEnvelopeREDACProtocol.CancelRunRequestREDACProtocol.CancelRunResponseREDACProtocol.DAQConfigurationREDACProtocol.EndSessionRequestREDACProtocol.EndSessionResponseREDACProtocol.EntityReservationRequestREDACProtocol.EntityReservationResponseREDACProtocol.ErrorEnvelopeREDACProtocol.GetConfigRequestREDACProtocol.GetConfigResponseREDACProtocol.GetEntitiesRequestREDACProtocol.GetEntitiesResponseREDACProtocol.GetMetadataRequestREDACProtocol.GetMetadataResponseREDACProtocol.MatchTypeClientREDACProtocol.MatchTypeClientAbstractREDACProtocol.MatchTypeHcREDACProtocol.MatchTypeHcAbstractREDACProtocol.NotificationEnvelopeREDACProtocol.PathREDACProtocol.PingREDACProtocol.PongREDACProtocol.RequestEnvelopeREDACProtocol.ResponseEnvelopeREDACProtocol.RunConfigREDACProtocol.RunDataMessageREDACProtocol.RunFlagsREDACProtocol.RunStateREDACProtocol.RunStateChangeMessageREDACProtocol.SetConfigRequestREDACProtocol.SetConfigResponseREDACProtocol.SetDAQRequestREDACProtocol.SetDAQResponseREDACProtocol.StartRunRequestREDACProtocol.StartRunResponseREDACProtocol.StartSessionRequestREDACProtocol.StartSessionResponseStructTypes.StructTypeStructTypes.StructTypeREDACProtocol.getnameREDACProtocol.getnameREDACProtocol.@register_antiphonREDACProtocol.@register_antiphonREDACProtocol.@register_notificationREDACProtocol.@register_notificationREDACProtocol.@register_requestREDACProtocol.@register_requestREDACProtocol.@register_responseREDACProtocol.@register_response