FETPAPI 0.3.0.0
This project provides C++ classes which facilitate the developement of ETP1.2 clients and servers.
Loading...
Searching...
No Matches
AbstractClientSessionCRTP.h
1/*-----------------------------------------------------------------------
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements. See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership. The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"; you may not use this file except in compliance
8with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied. See the License for the
16specific language governing permissions and limitations
17under the License.
18-----------------------------------------------------------------------*/
19#pragma once
20
21#include "ClientSession.h"
22
23namespace ETP_NS
24{
25 // This uses the Curiously Recurring Template Pattern so that the same code works with both SSL streams and regular sockets.
26 template<class Derived>
28 {
29 public:
30
31 virtual ~AbstractClientSessionCRTP() = default;
32
33 void on_connect(boost::system::error_code ec) {
34 if (ec) {
35 std::cerr << "on_connect : " << ec.message() << std::endl;
36 }
37
38#if BOOST_VERSION < 107000
39 // Perform the websocket handshake
40 derived().ws().async_handshake_ex(responseType,
41 etpServerHost + ":" + etpServerPort, etpServerTarget,
42 [&](websocket::request_type& m)
43 {
44 m.insert(boost::beast::http::field::sec_websocket_protocol, "etp12.energistics.org");
45 m.insert(boost::beast::http::field::authorization, etpServerAuthorization);
46 if (!proxyHost.empty() && !isTls()) {
47 m.insert(boost::beast::http::field::proxy_authorization, proxyAuthorization);
48 }
49 m.insert("etp-encoding", "binary");
50 for (const auto& mapEntry : additionalHandshakeHeaderFields_) {
51 m.insert(mapEntry.first, mapEntry.second);
52 }
53 },
54 std::bind(
55 &AbstractClientSessionCRTP::on_handshake,
56 std::static_pointer_cast<AbstractClientSessionCRTP>(shared_from_this()),
57 std::placeholders::_1));
58#else
59 derived().ws().set_option(websocket::stream_base::decorator(
60 [&](websocket::request_type& m)
61 {
62 m.insert(boost::beast::http::field::sec_websocket_protocol, "etp12.energistics.org");
63 m.insert(boost::beast::http::field::authorization, etpServerAuthorization);
64 if (!proxyHost.empty() && !isTls()) {
65 m.insert(boost::beast::http::field::proxy_authorization, proxyAuthorization);
66 }
67 m.insert("etp-encoding", "binary");
68 for (const auto& mapEntry : additionalHandshakeHeaderFields_) {
69 m.insert(mapEntry.first, mapEntry.second);
70 }
71 })
72 );
73 // Perform the websocket handshake
74 derived().ws().async_handshake(responseType,
75 etpServerHost + ":" + etpServerPort, etpServerTarget,
76 std::bind(
77 &AbstractClientSessionCRTP::on_handshake,
78 std::static_pointer_cast<AbstractClientSessionCRTP>(shared_from_this()),
79 std::placeholders::_1));
80#endif
81 }
82
87 FETPAPI_DLL_IMPORT_OR_EXPORT void do_close() {
88 derived().ws().async_close(websocket::close_code::normal,
89 std::bind(
90 &AbstractSession::on_close,
91 shared_from_this(),
92 std::placeholders::_1));
93 }
94
95 FETPAPI_DLL_IMPORT_OR_EXPORT void do_read()
96 {
97 if (webSocketSessionClosed) {
98 fesapi_log("CLOSED : NOTHING MORE TO DO");
99 return;
100 }
101
102 // Read a message into our buffer
103 derived().ws().async_read(
104 receivedBuffer,
105 std::bind(
106 &AbstractSession::on_read,
107 shared_from_this(),
108 std::placeholders::_1,
109 std::placeholders::_2));
110 }
111
112 void on_handshake(boost::system::error_code ec)
113 {
114 if (ec) {
115 std::cerr << "on_handshake : " << ec.message() << std::endl;
116 std::cerr << "Sometimes some ETP server require a trailing slash at the end of their URL. Did you also check your optional \"data-partition-id\" additional Header Field?" << std::endl;
117 return;
118 }
119
120 if (!responseType.count(boost::beast::http::field::sec_websocket_protocol) ||
121 responseType[boost::beast::http::field::sec_websocket_protocol] != "etp12.energistics.org")
122 std::cerr << "The client MUST specify the Sec-Websocket-Protocol header value of etp12.energistics.org, and the server MUST reply with the same" << std::endl;
123
124 successfulConnection = true;
125 webSocketSessionClosed = false;
126
127 send(requestSession, 0, 0x02);
128 do_read();
129 }
130
131 void setMaxWebSocketMessagePayloadSize(int64_t value) final {
132 maxWebSocketMessagePayloadSize = value;
133 derived().ws().read_message_max(value);
134 }
135
136 protected:
137 using ClientSession::ClientSession;
138
139 // Access the derived class, this is part of the Curiously Recurring Template Pattern idiom.
140 Derived& derived() { return static_cast<Derived&>(*this); }
141
142 void do_write() {
143 const std::lock_guard<std::mutex> specificProtocolHandlersLock(specificProtocolHandlersMutex);
144 if (sendingQueue.empty()) {
145 fesapi_log("The sending queue is empty.");
146 return;
147 }
148
149 bool previousSentMessageCompleted = specificProtocolHandlers.find(std::get<0>(sendingQueue.front())) == specificProtocolHandlers.end();
150
151 if (!previousSentMessageCompleted) {
152 fesapi_log("Cannot send Message id :", std::to_string(std::get<0>(sendingQueue.front())), "because the previous message has not finished to be sent.");
153 }
154 else {
155 fesapi_log("Sending Message id :", std::to_string(std::get<0>(sendingQueue.front())));
156
157 derived().ws().async_write(
158 boost::asio::buffer(std::get<1>(sendingQueue.front())),
159 std::bind(
160 &AbstractSession::on_write,
161 shared_from_this(),
162 std::placeholders::_1,
163 std::placeholders::_2));
164
165 // Register the handler to respond to the sent message
166 specificProtocolHandlers[std::get<0>(sendingQueue.front())] = std::get<2>(sendingQueue.front());
167 }
168 }
169 };
170}
Definition AbstractClientSessionCRTP.h:28
FETPAPI_DLL_IMPORT_OR_EXPORT void do_close()
Definition AbstractClientSessionCRTP.h:87
FETPAPI_DLL_IMPORT_OR_EXPORT void do_read()
Definition AbstractClientSessionCRTP.h:95
Definition ClientSession.h:28