And finally, is there some recommended way to perform a partial deserialisation? Let's say that I have a json object with one value determining the nature of the rest of its contents, so first I need to extract that one value only, based on that value select the correct DTO, and only after that deserialise the whole object with the correct DTO.
You can use Polymorphic DTO fields for that - https://github.com/oatpp/oatpp/blob/master/changelog/1.3.0.md#polymorphic-dto_field
class MyDto : public oatpp::DTO {
DTO_INIT(MyDto, DTO)
DTO_FIELD(String, dataType); //<-- value determining the nature of the rest of its contents
DTO_FIELD(Any, data); //<-- polymorphic data
DTO_FIELD_TYPE_SELECTOR(data) {
if(dataType == "animal") return Object<AnimalDto>::Class::getType();
if(dataType == "car") return Object<CarDto>::Class::getType();
if(dataType == "int") return Int32::Class::getType();
return Void::Class::getType();
}
};
@mmn:matrix.org
@junyama
auto connectionPool = oatpp::network::ClientConnectionPool::createShared(
connectionProvider, // connection provider
10, //max connections
std::chrono::seconds(5) // max lifetime of idle connection
);
use ClientConnectionPool::createShared
instead
dataType
, I would need to select a whole DTO rather than a type for one field.
dataType
and in the second round for all fields with the correct DTO, but of course I'd prefer something that would at least parse the json object only once (and map twice).
Hi, I am creating async listeners with the following code:
OATPP_COMPONENT(std::shared_ptr<std::list<std::shared_ptr<oatpp::network::ServerConnectionProvider>>>, connectionProviders);
std::list<std::thread> threads;
for(auto& provider : *connectionProviders) {
threads.push_back(std::thread([provider]{
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, handler);
oatpp::network::Server server(provider, handler);
server.run();
}));
}
std::thread statThread([]{
printStats();
});
My question is: How do I properly shut the listeners down?
@mmn:matrix.org
So based on the value ofdataType
, I would need to select a whole DTO rather than a type for one field.
The obvious dirty solution is to deserialise the received json object twice, in the first round only fordataType
and in the second round for all fields with the correct DTO, but of course I'd prefer something that would at least parse the json object only once (and map twice).
Yes, in this case, you just have to parse and map it twice.
1.3.0
but API is almost the same
I have set RetryPolicy as follows:
std::unordered_set<v_int32> m_httpCodes{500};
auto retryPolicy = std::make_shared<oatpp::web::client::SimpleRetryPolicy>(10, std::chrono::seconds(1), m_httpCodes);
Looking at the log of my client code, I saw some strange HTTP response status code, such as 3 and 4. My ENDPOINT is based on CRUD example:
ENDPOINT("POST", "images", createImage, BODY_DTO(Object<ImageDto>, imageDto)) {
auto userDto = UserDto::createShared();
serializeImageDto(imageDto, userDto);
return createDtoResponse(Status::CODE_200, m_imageServices.createUser(userDto));
}
I do not change UserService.cpp. What was wrong? Thank you for your help in advance.
@oatpp_io_twitter
Hello, question: when the server takes the initiative to send data, F5 refreshes the browser page. The server suddenly reports an error. What's the better way?
Thank you. Here is an example:
class WSInstanceListener : public oatpp::websocket::ConnectionHandler::SocketInstanceListener {
public:
static bool m_bState;
...
};
bool WSInstanceListener::m_bState = true;
void WSInstanceListener::onAfterCreate(const oatpp::websocket::WebSocket& socket, const std::shared_ptr<const ParameterMap>& params) {
SOCKETS ++;
OATPP_LOGD(TAG, "New Incoming Connection. Connection count=%d", SOCKETS.load());
/* In this particular case we create one WSListener per each connection */
/* Which may be redundant in many cases */
socket.setListener(std::make_shared<WSListener>());
m_bState = true;
std::thread t([&socket]{
while (m_bState) {
socket.sendOneFrameText("Hello");
}
});
t.detach();
}
void WSInstanceListener::onBeforeDestroy(const oatpp::websocket::WebSocket& socket) {
SOCKETS --;
OATPP_LOGD(TAG, "Connection closed. Connection count=%d", SOCKETS.load());
m_bState = false;
}
I |2021-12-09 18:45:59 1639043159419263| MyApp:Server running on port 8000
D |2021-12-09 18:46:06 1639043166551007| Server_WSListener:onClose code=1001
D |2021-12-09 18:46:06 1639043166551045| Server_WSInstanceListener:Connection closed. Connection count=0
terminate called after throwing an instance of 'std::runtime_error'
what(): [oatpp::web::protocol::websocket::WebSocket::sendOneFrameText()]: Unknown error while writing to socket.
Hello, question: when the server takes the initiative to send data, F5 refreshes the browser page. The server suddenly reports an error. What's the better way?
Hey @shijiantouzouyiqie , if you refresh the page in web-browser then the client is disconnected from the server, and the server reports that it can't use that already invalid connection.
Hi I was wondering how to deserialize the following using oatpp::DTO:
"changes": [
[
"buy",
"9122.04",
"0.00121425"
],
...,
[
"sell",
"9122.07",
"0.98942292"
]
...
],
I had hoped I'd be able to do something like this:Vector<Object<Change>>
as opposed to Vector<Vector<String>>>
. Ideas?
Also wondering how to do something similar for this:
"trades": [
{
"type": "trade",
"symbol": "BTCUSD",
"eventid": 169841458,
"timestamp": 1560976400428,
"price": "9122.04",
"quantity": "0.0073173",
"side": "sell"
},
...
],
Thanks.
Hey @shijiantouzouyiqie ,
Hello,after refreshing the browser, the program crashes. How to optimize the error point whenwsinstancelistener::onaftercreate uses std::threadto actively send data?
Or doesstd::threadnot cause the program to crash!
You can see the error, right? Try to use try - catch
terminate called after throwing an instance of 'std::runtime_error'
what(): [oatpp::web::protocol::websocket::WebSocket::sendOneFrameText()]: Unknown error while writing to socket.
Hey @Maboulmagd ,
Hi I was wondering how to deserialize the following using oatpp::DTO:
"changes": [
[
"buy",
"9122.04",
"0.00121425"
],
...,
[
"sell",
"9122.07",
"0.98942292"
]
...
],
Vector<Vector<String>>>
"trades": [
{
"type": "trade",
"symbol": "BTCUSD",
"eventid": 169841458,
"timestamp": 1560976400428,
"price": "9122.04",
"quantity": "0.0073173",
"side": "sell"
},
...
],
Vector<Object<MyObj>>
@nikoladsp ,
You can do that.
server
address in swagger-ui and that all your services are accessible at that host-name void* StartThread(void* arg);
class WSInstanceListener : public oatpp::websocket::ConnectionHandler::SocketInstanceListener {
public:
.....
public:
pthread_t m_pid;
bool m_bQuitThread;
oatpp::websocket::WebSocket* m_Socket;
};
WSInstanceListener::WSInstanceListener() {
m_pid = -1;
m_bQuitThread = true;
m_Socket = NULL;
}
void WSInstanceListener::onAfterCreate(
const oatpp::websocket::WebSocket &socket,
const std::shared_ptr<const ParameterMap> ¶ms) {
SOCKETS++;
OATPP_LOGD(TAG, "New Incoming Connection. Connection count=%d",
SOCKETS.load());
socket.setListener(std::make_shared<WSListener>());
m_Socket = (oatpp::websocket::WebSocket*) &socket;
pthread_create(&m_pid, NULL, StartThread, (void*) this);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_detach(m_pid);
}
void WSInstanceListener::onBeforeDestroy(
const oatpp::websocket::WebSocket &socket) {
SOCKETS--;
OATPP_LOGD(TAG, "Connection closed. Connection count=%d", SOCKETS.load());
m_bQuitThread = false;
pthread_cancel(m_pid);
pthread_join(m_pid,NULL);
this->m_Socket->stopListening();
}
void* StartThread(void *arg) {
WSInstanceListener *lis = (WSInstanceListener*) arg;
lis->m_bQuitThread = true;
while (lis->m_bQuitThread) {
pthread_testcancel();
lis->m_Socket->sendOneFrameText("hello");
}
return (void*) 0;
}
I |2021-12-15 19:46:53 1639568813189617| MyApp:Server running on port 8000
D |2021-12-15 19:47:00 1639568820630942| Server_WSInstanceListener:New Incoming Connection. Connection count=1
D |2021-12-15 19:47:06 1639568826556318| Server_WSListener:onClose code=1001
D |2021-12-15 19:47:06 1639568826556353| Server_WSInstanceListener:Connection closed. Connection count=0
D |2021-12-15 19:47:16 1639568836406451| Server_WSInstanceListener:New Incoming Connection. Connection count=1
D |2021-12-15 19:47:21 1639568841210745| Server_WSListener:onClose code=1001
terminate called after throwing an instance of 'std::runtime_error'
D |2021-12-15 19:47:21 1639568841210782| Server_WSInstanceListener:Connection closed. Connection count=0
terminate called recursively
Hello.
I've got an annoying issue I'm trying to fix on my oat++ client application : if my server shuts down before it gets the time to send a response to my client after a client request, it causes my client to crash. This is probably a common problem. Any way to fix this client side ?
Hey @nikoladsp ,
In an ideal world you would have to decouple the DB model and REST DTOs. The way you present data to service users and the way you store data may differ (and they do differ in most cases). Also, it's not recommended to expose DB ids - since they do not describe the actual resource in most cases.
Treat CRUD service as an adaptor of REST interface to DB model.
So the answer is - create two sets of DTOs - one for REST, second for DB.
Read from DB - do whatever transformations/compositions you need - join data in memory if needed - form response DTO and return it on the endpoint.
Hey @mmn:matrix.org ,
if the WebSocket connection was closed gracefully - you'll receive the onClose
method call in WS listener first, then the listen method will return.
If there was any kind of network issue - listen method will just return - no onClose
event triggered.
Here is the implementation of listen - https://github.com/oatpp/oatpp-websocket/blob/master/src/oatpp-websocket/WebSocket.cpp#L279