}\r
else\r
{\r
- CASPAR_LOG(debug) << L"CLK: Executed valid command: " \r << currentCommandString_.str();\r }\r
+ CASPAR_LOG(debug) << L"CLK: Executed valid command: " \r
+ << currentCommandString_.str();\r
+ }\r
} \r
catch (...)\r
{\r
namespace caspar { namespace protocol { namespace CLK {\r
\r
/**\r
- * TODO:\r
- * Can only handle one connection at a time safely. Works with multiple if\r
- * every Parse call contains a complete command, but this will not happen if\r
- * the client sends one command in multiple chunks, then partial commands can\r
- * be interlieved with each other from different clients, causing the parser\r
- * to be confused.\r
+ * Can only handle one connection at a time safely, therefore it should be\r
+ * wrapped in a stateful_protocol_strategy_wrapper.\r
*/\r
class CLKProtocolStrategy : public IO::IProtocolStrategy\r
{\r
<ClInclude Include="util\ClientInfo.h" />\r
<ClInclude Include="util\ProtocolStrategy.h" />\r
<ClInclude Include="util\SocketInfo.h" />\r
+ <ClInclude Include="util\stateful_protocol_strategy_wrapper.h" />\r
<ClInclude Include="util\Thread.h" />\r
</ItemGroup>\r
<ItemGroup>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
+ <ClCompile Include="util\stateful_protocol_strategy_wrapper.cpp">\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
+ </ClCompile>\r
<ClCompile Include="util\Thread.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<ClInclude Include="clk\clk_commands.h">\r
<Filter>source\clk</Filter>\r
</ClInclude>\r
+ <ClInclude Include="util\stateful_protocol_strategy_wrapper.h">\r
+ <Filter>source\util</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="amcp\AMCPCommandQueue.cpp">\r
<ClCompile Include="clk\clk_commands.cpp">\r
<Filter>source\clk</Filter>\r
</ClCompile>\r
+ <ClCompile Include="util\stateful_protocol_strategy_wrapper.cpp">\r
+ <Filter>source\util</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
--- /dev/null
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#include "../StdAfx.h"\r
+\r
+#include "stateful_protocol_strategy_wrapper.h"\r
+\r
+namespace caspar { namespace IO {\r
+\r
+stateful_protocol_strategy_wrapper::stateful_protocol_strategy_wrapper(\r
+ const std::function<ProtocolStrategyPtr ()>& factory)\r
+ : factory_(factory)\r
+ , codepage_(factory()->GetCodepage())\r
+{\r
+}\r
+\r
+void stateful_protocol_strategy_wrapper::purge_dead_clients()\r
+{\r
+ for (auto it = strategies_.begin(); it != strategies_.end();)\r
+ {\r
+ auto strong = it->first.lock();\r
+\r
+ if (strong)\r
+ ++it;\r
+ else\r
+ it = strategies_.erase(it);\r
+ }\r
+}\r
+\r
+void stateful_protocol_strategy_wrapper::Parse(\r
+ const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo)\r
+{\r
+ purge_dead_clients();\r
+\r
+ std::weak_ptr<ClientInfo> weak(pClientInfo);\r
+ ProtocolStrategyPtr strategy;\r
+ auto strategy_iter = strategies_.find(weak);\r
+\r
+ if (strategy_iter == strategies_.end())\r
+ {\r
+ strategy = factory_();\r
+ strategies_.insert(std::make_pair(weak, strategy));\r
+ }\r
+ else\r
+ {\r
+ strategy = strategy_iter->second;\r
+ }\r
+\r
+ strategy->Parse(pData, charCount, pClientInfo);\r
+}\r
+\r
+unsigned int stateful_protocol_strategy_wrapper::GetCodepage()\r
+{\r
+ return codepage_;\r
+}\r
+\r
+}}\r
--- /dev/null
+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#pragma once\r
+\r
+#include "ProtocolStrategy.h"\r
+\r
+#include <functional>\r
+#include <map>\r
+#include <memory>\r
+\r
+namespace caspar { namespace IO {\r
+\r
+/**\r
+ * A protocol strategy which creates unique protocol strategy instances per\r
+ * client connection, using a supplied factory.\r
+ *\r
+ * This allows for the strategy implementation to only concern about one\r
+ * client.\r
+ */\r
+class stateful_protocol_strategy_wrapper : public IProtocolStrategy\r
+{\r
+ std::function<ProtocolStrategyPtr ()> factory_;\r
+ std::map<\r
+ std::weak_ptr<ClientInfo>, \r
+ ProtocolStrategyPtr, \r
+ std::owner_less<std::weak_ptr<ClientInfo>>> strategies_;\r
+ unsigned int codepage_;\r
+public:\r
+ stateful_protocol_strategy_wrapper(\r
+ const std::function<ProtocolStrategyPtr ()>& factory);\r
+\r
+ virtual void Parse(\r
+ const wchar_t* pData, int charCount, ClientInfoPtr pClientInfo);\r
+\r
+ virtual unsigned int GetCodepage();\r
+private:\r
+ void purge_dead_clients();\r
+};\r
+\r
+}}\r
#include <protocol/cii/CIIProtocolStrategy.h>\r
#include <protocol/CLK/CLKProtocolStrategy.h>\r
#include <protocol/util/AsyncEventServer.h>\r
-\r
+#include <protocol/util/stateful_protocol_strategy_wrapper.h>\r\r
#include <boost/algorithm/string.hpp>\r
#include <boost/lexical_cast.hpp>\r
#include <boost/foreach.hpp>\r
else if(boost::iequals(name, L"CII"))\r
return make_safe<cii::CIIProtocolStrategy>(channels_);\r
else if(boost::iequals(name, L"CLOCK"))\r
- return make_safe<CLK::CLKProtocolStrategy>(channels_);\r
+ //return make_safe<CLK::CLKProtocolStrategy>(channels_);\r
+ return make_safe<IO::stateful_protocol_strategy_wrapper>([=]\r
+ {\r
+ return std::make_shared<CLK::CLKProtocolStrategy>(channels_);\r
+ });\r
\r
BOOST_THROW_EXCEPTION(caspar_exception() << arg_name_info("name") << arg_value_info(narrow(name)) << msg_info("Invalid protocol"));\r
}\r