pianod2
multisource multiuser scriptable networked music player
response.h
Go to the documentation of this file.
1 
9 #pragma once
10 
11 #include <config.h>
12 
13 #include <ctime>
14 
15 #include <string>
16 #include <vector>
17 #include <ostream>
18 #include <exception>
19 #include <memory>
20 
21 #include "fundamentals.h"
22 #include "musictypes.h"
23 #include "retainer.h"
24 
25 namespace Football {
26  class Thingie;
27 }
28 namespace Parsnip {
29  class Data;
30 }
31 
32 extern const char *ResponseText (RESPONSE_CODE code);
33 extern const char *JSONFieldName (RESPONSE_CODE code);
34 
35 namespace JSON {
36  namespace Key {
37  extern const char *PlayDuration;
38  extern const char *PlayPoint;
39  extern const char *PlayRemaining;
40  } // namespace Key
41 } // namespace JSON
42 
43 std::string format_duration (time_t duration, int minute_places = 1);
44 
49 class Response {
50  friend class ResponseCollector;
51  friend class ResponseGroup;
52  friend class CommandReply;
53 
54 public:
55  using List = std::vector<std::string>;
56  static constexpr int TransmitUnaltered = 0;
57  static constexpr int TransmitAsDiagnostic = -100;
58 
60 private:
61 
62  enum class Type { EMPTY, STRING, LONG, DOUBLE, WORDLIST }; // Additional data types.
65  std::string value;
66  long long_value;
67  double double_value;
70  std::shared_ptr<Parsnip::Data> json_data;
71  std::string regarding;
73  mutable const class User *user = nullptr;
74 
75 public:
76  inline bool isStatusChange() const {
78  }
79  inline bool isDataField() const {
81  }
82  inline bool isSuccess() const {
84  }
85  inline bool isCommandError() const {
87  }
88  inline bool isServerFailure() const {
90  }
91  inline bool isUserAction() const {
93  }
95  inline void bindUser (const class User *u) const {
96  user = u;
97  };
98 
99  void transmitLine (Football::Thingie &there, int offset = TransmitUnaltered) const;
100  Parsnip::Data serialize() const;
101 
102  Response() = default;
103  Response (const Response &) = default;
104  Response (Response &&) = default;
105  Response &operator= (const Response &) = default;
106  Response &operator= (Response &&) = default;
107 
108  Response (RESPONSE_CODE msg);
109  Response (RESPONSE_CODE msg, const std::string &details);
110  Response (RESPONSE_CODE msg, long details);
111  Response (RESPONSE_CODE msg, double details, int precision);
112  Response (RESPONSE_CODE msg, List &&details, Parsnip::Data &&json_details);
113 
114  Response (const std::string &regard, RESPONSE_CODE msg);
115  Response (const std::string &regard, RESPONSE_CODE msg, const std::string &details);
116  Response (const std::string &regard, RESPONSE_CODE msg, long details);
117  Response (const std::string &regard, RESPONSE_CODE msg, double details, int precision);
118  Response (const std::string &regard, RESPONSE_CODE msg, List &&details, Parsnip::Data &&json_details);
119 
121  Response (Retainer<MusicThingie *> rel, RESPONSE_CODE msg, const std::string &details);
122  Response (Retainer<MusicThingie *> rel, RESPONSE_CODE msg, long details);
123  Response (Retainer<MusicThingie *> rel, RESPONSE_CODE msg, double details, int precision);
124  Response (Retainer<MusicThingie *> rel, RESPONSE_CODE msg, List &&details, Parsnip::Data &&json_details);
125 
126  Response (const CommandError &err);
127  Response (const std::string &regard, const CommandError &err);
129 };
130 
132 inline Football::Thingie &operator<< (Football::Thingie &there, const Response &response) {
133  response.transmitLine (there);
134  return there;
135 }
136 
138 inline Football::Thingie &operator<< (Football::Thingie *there, const Response &response) {
139  response.transmitLine (*there);
140  return *there;
141 }
142 
143 extern PianodConnection &operator<< (PianodConnection &there, const Response &response);
144 
146 inline PianodConnection &operator<< (PianodConnection *there, const Response &response) {
147  return (*there << response);
148 }
149 
155 class ResponseGroup : public std::vector<Response> {
156  friend class ResponseCollector;
157 
158 private:
160  Parsnip::Data serializeData (const User *) const;
162  Parsnip::Data serializeEvents (bool, const User *) const;
163 
164  void transmitLine (class PianodService &) const;
165  void transmitJSON (class PianodService &) const;
166 
167 public:
168  ResponseGroup() = default;
169  ResponseGroup (ResponseGroup &&) = default;
171 
174  push_back (std::move (r));
175  }
177  template <typename... Parameters>
178  inline void operator() (Parameters &&...params) {
179  push_back (Response (std::forward<Parameters> (params)...));
180  }
181 
182  void operator() (ResponseGroup &&);
183 
184  void transmit (class PianodService &) const;
185 
186  void transmitLine (PianodConnection &, int offset = Response::TransmitUnaltered) const;
187  void transmit (class PianodConnection &) const;
188 };
189 
198  friend class PianodConnection &operator<< (class PianodConnection &there, const ResponseCollector &response);
199 
200 private:
201  bool close_after_response = false;
202 
203  Parsnip::Data serialize (const User *user) const;
204  void transmitJSON (PianodConnection &) const;
205  void transmitLine (PianodConnection &) const;
206 
207 protected:
209 
212 
213  std::vector<ResponseGroup> data_groups;
215 
216  // These are not publicly accessible through ResponseCollector; use DataResponse instead.
217  void data (ResponseGroup &&group);
218  void data (const ThingieList &item_list);
219  void data (const SongList &songs);
220  void data (const PlaylistList &playlists);
221 
225 public:
227 
228  inline void setNoResponse() {
229  assert (noop() && reason != S_DATA);
230  reason = NO_REPLY;
231  }
232 
234  inline bool allSuccess() const {
235  assert (data_reply.empty());
236  return diagnostics.empty() && !successes.empty();
237  };
239  inline bool allFailure() const {
240  assert (data_reply.empty());
241  return !diagnostics.empty() && successes.empty();
242  }
244  inline bool anySuccess() const {
245  assert (data_reply.empty());
246  return !successes.empty();
247  };
249  inline bool anyFailure() const {
250  assert (data_reply.empty());
251  return !diagnostics.empty();
252  }
254  inline bool partial() const {
255  assert (data_reply.empty());
256  return !diagnostics.empty() && !successes.empty();
257  }
259  inline bool noop() const {
260  return diagnostics.empty() && successes.empty();
261  }
263  inline bool dataResponse() const {
264  return (reason == S_DATA);
265  }
267  inline bool isNoResponse() const {
268  return (reason == NO_REPLY);
269  }
271  inline void close() {
272  close_after_response = true;
273  }
274 
275  void transmit (PianodConnection &, const bool json);
276 
277  ResponseCollector() = default;
280 
281  ResponseCollector (Response &&initial);
282  inline ResponseCollector (const RESPONSE_CODE response) : ResponseCollector (Response{ response }){};
284  ResponseCollector (const ThingieList &things);
285  ResponseCollector (const SongList &songs);
287 };
288 
295 public:
297 
298 private:
300  void mergeReason (RESPONSE_CODE why);
301 
302 public:
307 
308  void fail (Response &&failure);
310  template <typename ParamOne, typename ParamTwo, typename... Additional>
311  inline void fail (ParamOne &&first, ParamTwo &&second, Additional &&...more) {
312  fail (Response (std::forward<ParamOne> (first),
313  std::forward<ParamTwo> (second),
314  std::forward<Additional> (more)...));
315  }
316 
317  void succeed (Response &&success);
319  inline void succeed() {
320  succeed (S_OK);
321  }
323  template <typename ParamOne, typename ParamTwo, typename... Additional>
324  inline void succeed (ParamOne &&first, ParamTwo &&second, Additional &&...more) {
325  succeed (Response (std::forward<ParamOne> (first),
326  std::forward<ParamTwo> (second),
327  std::forward<Additional> (more)...));
328  }
329 
330  void operator() (Response &&r);
332  template <typename ParamOne, typename... Parameters>
333  inline void operator() (ParamOne &&first, Parameters &&...more) {
334  operator() (Response (std::forward<ParamOne> (first), std::forward<Parameters> (more)...));
335  }
336 
338  inline CommandReply (Response &&initial) : ResponseCollector (std::move (initial)){};
339  CommandReply (const std::exception_ptr except, const char *triggering_command = nullptr);
340 };
341 
348 public:
351 
352  void data (Response &&r);
353 
355  template <typename ParamOne, typename ParamTwo, typename... Additional>
356  inline void data (ParamOne &&first, ParamTwo &&second, Additional &&...more) {
357  data (Response (std::forward<ParamOne> (first),
358  std::forward<ParamTwo> (second),
359  std::forward<Additional> (more)...));
360  }
361 
363  template <typename T>
364  inline void data (const Retainer<T> &from) {
365  ResponseGroup group;
366  group (from, I_ATTACHED_THING);
367  data_groups.push_back (std::move (group));
368  }
369 
373  }
374 };
375 
376 extern class PianodConnection &operator<< (class PianodConnection &there, const ResponseCollector &response);
377 
379 inline class PianodConnection &operator<< (class PianodConnection *there, const ResponseCollector &response) {
380  *there << response;
381  return *there;
382 }
383 
384 // Helper for sending updated ratings.
385 void sendUpdatedRatings (PianodConnection &conn, const PianodSong *song, CommandReply *reply);
Exception for command execution problems.
Definition: fundamentals.h:293
This class is derived from ResponseCollector and adds success/failure adder functions and a few varia...
Definition: response.h:294
void mergeReason(RESPONSE_CODE why)
Update the collection's final status.
Definition: response.cpp:466
void succeed(ParamOne &&first, ParamTwo &&second, Additional &&...more)
Add a succeess to the successes list, after constructing it.
Definition: response.h:324
RESPONSE_CODE mixed_reason
The final response if there are both successes and failures.
Definition: response.h:299
CommandReply(Aggregation kind=Aggregation::OPTIMISTIC)
Construct a response collector for status collection.
Definition: response.cpp:509
Aggregation
Definition: response.h:296
CommandReply(Response &&initial)
Definition: response.h:338
void fail(ParamOne &&first, ParamTwo &&second, Additional &&...more)
Add a failure to the failures list, after constructing it.
Definition: response.h:311
void fail(Response &&failure)
Add a failure response to the collection.
Definition: response.cpp:481
void succeed()
Add a simple success to the list.
Definition: response.h:319
void operator()(Response &&r)
Add a success or failure response to the collection.
Definition: response.cpp:497
This class is derived from ResponseCollector, and adds no member variables but adds data adder functi...
Definition: response.h:347
void data(ParamOne &&first, ParamTwo &&second, Additional &&...more)
Add data to the data response list, after constructing it.
Definition: response.h:356
void data(const Retainer< T > &from)
Add a music item to the data response list.
Definition: response.h:364
DataResponse()
Construct a new DataResponse (i.e., a ResponseCollector that's been earmarked for returning data.
Definition: response.h:372
void data(ResponseGroup &&group)
Add a record for transmission as response data.
Definition: response.cpp:421
Base class for services, events, and connections.
Definition: football.h:37
Base class for songs, albums, artists, playlists, genres, etc.
Definition: musictypes.h:77
Generic data type.
Definition: parsnip.h:81
Connection to a pianod client, along with context and state of that connection.
Definition: connection.h:54
User * user
Definition: connection.h:76
Pianod service, a customized FootballService for Pianod connections.
Definition: connection.h:115
Base class for songs, these are also MusicThingies, artists and albums.
Definition: musictypes.h:339
A container for lists of playlists.
Definition: retainedlist.h:324
A response collector/aggregator.
Definition: response.h:197
ResponseGroup room_events
Broadcast to all same-room sessions.
Definition: response.h:223
bool allSuccess() const
ResponseCollector contains successes but no failures.
Definition: response.h:234
RESPONSE_CODE reason
The final response that will be sent.
Definition: response.h:208
ResponseGroup broadcast_events
Broadcast to all users, all rooms.
Definition: response.h:224
bool dataResponse() const
ResponseCollector is transporting data for transmission.
Definition: response.h:263
bool allFailure() const
ResponseCollector contains failures but no successes.
Definition: response.h:239
ResponseGroup successes
Success messages.
Definition: response.h:210
friend class PianodConnection & operator<<(class PianodConnection &there, const ResponseCollector &response)
ResponseCollector()=default
ResponseGroup diagnostics
Details of errors encountered.
Definition: response.h:211
bool anyFailure() const
ResponseCollector contains at least one failure, regardless of successes.
Definition: response.h:249
bool close_after_response
If true, the connection is closed after response is sent.
Definition: response.h:201
ResponseCollector(ResponseCollector &&from)=default
ResponseCollector(const RESPONSE_CODE response)
Definition: response.h:282
Parsnip::Data serialize(const User *user) const
Assemble a response collection into either a data response or a reply (i.e., successes/failures).
Definition: responsejson.cpp:359
bool isNoResponse() const
ResponseCollector should not send a reply to a command.
Definition: response.h:267
bool noop() const
ResponseCollector contains neither successes nor failures.
Definition: response.h:259
void transmitJSON(PianodConnection &) const
Format and transmit a response collection to JSON client.
Definition: responsejson.cpp:399
ResponseGroup data_reply
Discrete data responses destined for the client.
Definition: response.h:214
ResponseGroup user_events
Broadcast to other same-user sessions.
Definition: response.h:222
bool partial() const
ResponseCollector contains a mix of successes and failures.
Definition: response.h:254
void close()
Causes the connection to be closed after the response is sent.
Definition: response.h:271
void transmit(PianodConnection &, const bool json)
Transmit a reply.
Definition: response.cpp:443
void data(ResponseGroup &&group)
Add a record for transmission as response data.
Definition: response.cpp:421
std::vector< ResponseGroup > data_groups
Complete data records destined for the client.
Definition: response.h:213
void setNoResponse()
Definition: response.h:228
void transmitLine(PianodConnection &) const
Transmit a data response OR command reply to a specific node, followed by any client-specific add-on ...
Definition: responseline.cpp:144
ResponseCollector & operator=(ResponseCollector &&from)=default
bool anySuccess() const
ResponseCollector contains at least one success, regardless of failures.
Definition: response.h:244
ResponseGroup information
Session notices going back to user.
Definition: response.h:226
Container for multiple Responses.
Definition: response.h:155
void transmitJSON(class PianodService &) const
Transmit a group of responses JSON connection on a service.
Definition: responsejson.cpp:332
Parsnip::Data serializeEvents(bool, const User *) const
Re-sort messages to be broadcast into categories:
Definition: responsejson.cpp:251
Parsnip::Data serializeData(const User *) const
Format a record's worth of reponses for JSON protocol.
Definition: responsejson.cpp:213
ResponseGroup & operator=(ResponseGroup &&)=default
void transmitLine(class PianodService &) const
Broadcast a group of responses to an entire service.
Definition: responseline.cpp:124
ResponseGroup(Response &&r)
Construct from a single response.
Definition: response.h:173
Parsnip::Data serializeHomogenousData(const User *) const
Format a homogenous list of responses as a series JSON records.
Definition: responsejson.cpp:233
void transmit(class PianodService &) const
Transmit a group of response messages to all nodes on a service, using the appropriate protocol for e...
Definition: response.cpp:333
void operator()(Parameters &&...params)
Add a new response to the list, after constructing it.
Definition: response.h:178
ResponseGroup()=default
Parsnip::Data serializeReply() const
Format successes or diagnostics for JSON transmission.
Definition: responsejson.cpp:202
ResponseGroup(ResponseGroup &&)=default
Type combining RESPONSE_CODE with a value or explanation:
Definition: response.h:49
static constexpr int TransmitAsDiagnostic
Transform command errors to diagnostic codes.
Definition: response.h:57
std::vector< std::string > List
Definition: response.h:55
Parsnip::Data serialize() const
Format a response for JSON protocol.
Definition: responsejson.cpp:131
Retainer< MusicThingie * > related
Music item to send, or in regards to.
Definition: response.h:72
static Parsnip::Data NoJsonData
Definition: response.h:59
std::shared_ptr< Parsnip::Data > json_data
Parsnip data to be used for JSON replies.
Definition: response.h:70
bool isSuccess() const
Definition: response.h:82
bool isDataField() const
Definition: response.h:79
List list
Definition: response.h:69
Type
Definition: response.h:62
Response & operator=(const Response &)=default
void bindUser(const class User *u) const
Associate a user triggering the response (for user actions & yells).
Definition: response.h:95
void transmitLine(Football::Thingie &there, int offset=TransmitUnaltered) const
Transmit a response using line protocol.
Definition: responseline.cpp:37
Response(Response &&)=default
double double_value
Definition: response.h:67
bool isStatusChange() const
Definition: response.h:76
static constexpr int TransmitUnaltered
Transmit data as stored.
Definition: response.h:56
const class User * user
User triggering the response.
Definition: response.h:73
RESPONSE_CODE message
Message code, initialized to "empty" value.
Definition: response.h:63
bool isUserAction() const
Definition: response.h:91
bool isServerFailure() const
Definition: response.h:88
std::string value
Definition: response.h:65
int double_precision
Definition: response.h:68
long long_value
Definition: response.h:66
Type type
Type of additional data stored herein.
Definition: response.h:64
bool isCommandError() const
Definition: response.h:85
Response()=default
Response(const Response &)=default
std::string regarding
ID or name of item response is in regards to.
Definition: response.h:71
A container for holding songs.
Definition: retainedlist.h:328
Base class for storing lists of thingies, which need to be reference counted accurately.
Definition: retainedlist.h:20
Data about each user.
Definition: user.h:53
Essential data structures and support.
bool isServerFailure(RESPONSE_CODE code)
Definition: fundamentals.h:283
bool isDataField(RESPONSE_CODE code)
Definition: fundamentals.h:271
bool isSuccess(RESPONSE_CODE code)
Definition: fundamentals.h:275
enum server_status_t RESPONSE_CODE
bool isUserAction(RESPONSE_CODE code)
Definition: fundamentals.h:287
@ I_ATTACHED_THING
Transmit the attached thing instead of a response message.
Definition: fundamentals.h:159
@ S_DATA
Definition: fundamentals.h:167
@ S_NOOP
Nothing to do; default success.
Definition: fundamentals.h:173
@ NO_REPLY
Do not transmit any reply.
Definition: fundamentals.h:78
@ S_OK
Definition: fundamentals.h:164
@ E_PARTIAL
Partial failure, but a portion succeeded.
Definition: fundamentals.h:206
bool isCommandError(RESPONSE_CODE code)
Definition: fundamentals.h:279
bool isStatusChange(RESPONSE_CODE code)
Definition: fundamentals.h:267
Playlist / Artist / Album / Song data types.
Football C++ connections, services and parsers.
Definition: fb_arena.cpp:23
const char * PlayDuration
Definition: responsejson.cpp:48
static const char * Data
Definition: responsejson.cpp:42
const char * PlayRemaining
Definition: responsejson.cpp:50
const char * PlayPoint
Definition: responsejson.cpp:49
Definition: response.h:35
Definition: musiccache.cpp:18
Serialization and parsing library.
Definition: mediaunit.h:26
std::string format_duration(time_t duration, int minute_places=1)
Format a duration as minutes and seconds.
Definition: response.cpp:47
Football::Thingie & operator<<(Football::Thingie &there, const Response &response)
Use << as output operator for Response.
Definition: response.h:132
const char * ResponseText(RESPONSE_CODE code)
Retrieve the text for a success, failure, event or data message.
Definition: response.cpp:56
void sendUpdatedRatings(PianodConnection &conn, const PianodSong *song, CommandReply *reply)
Send updated ratings.
Definition: response.cpp:527
const char * JSONFieldName(RESPONSE_CODE code)
Retrieve the JSON text for a response.
Definition: responsejson.cpp:58
Smart pointers for music thingie types.