From b5d853b1ee5649faf70d6505af57673b85974760 Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Tue, 17 Jan 2017 17:45:54 +0100 Subject: [PATCH] [AMCP] #475 Added special command REQ that can be prepended before any command to identify the response with a client specified request id, allowing a client to know exactly what asynchronous response matched a specific request. --- CHANGELOG | 3 +++ protocol/amcp/AMCPCommand.h | 11 +++++++++- protocol/amcp/AMCPCommandsImpl.cpp | 17 +++++++++++++++ protocol/amcp/AMCPProtocolStrategy.cpp | 25 ++++++++++++++++++++--- protocol/amcp/amcp_command_repository.cpp | 5 +++++ protocol/amcp/amcp_command_repository.h | 1 + 6 files changed, 58 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1d9deb884..fc3e1a53b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,6 +56,9 @@ AMCP values. o MIXER CHROMA syntax deprecated (still supported) in favour of the more advanced syntax required by the rewritten chroma key code. + o Added special command REQ that can be prepended before any command to + identify the response with a client specified request id, allowing a client + to know exactly what asynchronous response matched a specific request. diff --git a/protocol/amcp/AMCPCommand.h b/protocol/amcp/AMCPCommand.h index 0eb9a2855..7c6d56af7 100644 --- a/protocol/amcp/AMCPCommand.h +++ b/protocol/amcp/AMCPCommand.h @@ -95,6 +95,7 @@ namespace amcp { int min_num_params_; std::wstring name_; std::wstring replyString_; + std::wstring request_id_; public: AMCPCommand(const command_context& ctx, const amcp_command_func& command, int min_num_params, const std::wstring& name) : ctx_(ctx) @@ -134,9 +135,17 @@ namespace amcp { return name_; } + void set_request_id(std::wstring request_id) + { + request_id_ = std::move(request_id); + } + void SetReplyString(const std::wstring& str) { - replyString_ = str; + if (request_id_.empty()) + replyString_ = str; + else + replyString_ = L"RES " + request_id_ + L" " + str; } }; }}} diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index b1e6536c7..a46120cc6 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -2948,6 +2948,21 @@ std::wstring lock_command(command_context& ctx) CASPAR_THROW_EXCEPTION(file_not_found() << msg_info(L"Unknown LOCK command " + command)); } +void req_describer(core::help_sink& sink, const core::help_repository& repo) +{ + sink.short_description(L"Perform any command with an additional request id identifying the response."); + sink.syntax(L"REQ [request_id:string] COMMAND..."); + sink.para() + ->text(L"This special command modifies the AMCP protocol a little bit to prepend ") + ->code(L"RES request_id")->text(L" to the response, in order to see what asynchronous response matches what request."); + sink.para()->text(L"Examples:"); + sink.example(L"REQ unique PLAY 1-0 AMB\n"); + sink.example( + L">> REQ unique PLAY 1-0 AMB\n" + L"<< RES unique 202 PLAY OK"); +} + + void register_commands(amcp_command_repository& repo) { repo.register_channel_command( L"Basic Commands", L"LOADBG", loadbg_describer, loadbg_command, 1); @@ -3034,6 +3049,8 @@ void register_commands(amcp_command_repository& repo) repo.register_command( L"Query Commands", L"HELP", help_describer, help_command, 0); repo.register_command( L"Query Commands", L"HELP PRODUCER", help_producer_describer, help_producer_command, 0); repo.register_command( L"Query Commands", L"HELP CONSUMER", help_consumer_describer, help_consumer_command, 0); + + repo.help_repo()->register_item({ L"AMCP", L"Protocol Commands" }, L"REQ", req_describer); } } //namespace amcp diff --git a/protocol/amcp/AMCPProtocolStrategy.cpp b/protocol/amcp/AMCPProtocolStrategy.cpp index 871f25c91..39529a709 100644 --- a/protocol/amcp/AMCPProtocolStrategy.cpp +++ b/protocol/amcp/AMCPProtocolStrategy.cpp @@ -19,7 +19,7 @@ * Author: Nicklas P Andersson */ - + #include "../StdAfx.h" #include "AMCPProtocolStrategy.h" @@ -106,7 +106,7 @@ public: void Parse(const std::wstring& message, ClientInfoPtr client) { CASPAR_LOG_COMMUNICATION(info) << L"Received message from " << client->address() << ": " << message << L"\\r\\n"; - + command_interpreter_result result; if(interpret_command_string(message, result, client)) { @@ -115,7 +115,7 @@ public: else result.queue->AddCommand(result.command); } - + if (result.error != error_state::no_error) { std::wstringstream answer; @@ -157,6 +157,22 @@ private: if (!tokens.empty() && tokens.front().at(0) == L'/') tokens.pop_front(); + std::wstring request_id; + + if (boost::iequals(tokens.front(), L"REQ")) + { + tokens.pop_front(); + + if (tokens.empty()) + { + result.error = error_state::parameters_error; + return false; + } + + request_id = tokens.front(); + tokens.pop_front(); + } + // Fail if no more tokens. if (tokens.empty()) { @@ -234,6 +250,9 @@ private: if (result.command->parameters().size() < result.command->minimum_parameters()) result.error = error_state::parameters_error; } + + if (result.command) + result.command->set_request_id(std::move(request_id)); } catch (std::out_of_range&) { diff --git a/protocol/amcp/amcp_command_repository.cpp b/protocol/amcp/amcp_command_repository.cpp index 06249814d..2457ec72d 100644 --- a/protocol/amcp/amcp_command_repository.cpp +++ b/protocol/amcp/amcp_command_repository.cpp @@ -225,4 +225,9 @@ void amcp_command_repository::register_channel_command( self.channel_commands.insert(std::make_pair(std::move(name), std::make_pair(std::move(command), min_num_params))); } +spl::shared_ptr amcp_command_repository::help_repo() const +{ + return impl_->help_repo; +} + }}} diff --git a/protocol/amcp/amcp_command_repository.h b/protocol/amcp/amcp_command_repository.h index 778c99845..2cd065fbb 100644 --- a/protocol/amcp/amcp_command_repository.h +++ b/protocol/amcp/amcp_command_repository.h @@ -60,6 +60,7 @@ public: void register_command(std::wstring category, std::wstring name, core::help_item_describer describer, amcp_command_func command, int min_num_params); void register_channel_command(std::wstring category, std::wstring name, core::help_item_describer describer, amcp_command_func command, int min_num_params); + spl::shared_ptr help_repo() const; private: struct impl; spl::shared_ptr impl_; -- 2.39.2