Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Action.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_UPnP_SOAP_Action_h_
5#define _Stroika_Frameworks_UPnP_SOAP_Action_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9#include <functional>
10#include <stdexcept>
11
13#include "Stroika/Foundation/Common/KeyValuePair.h"
14#include "Stroika/Foundation/Containers/Mapping.h"
15#include "Stroika/Foundation/Containers/Sequence.h"
16#include "Stroika/Foundation/Execution/Exceptions.h"
19
22#include "Stroika/Frameworks/WebServer/Message.h"
24
25/**
26 * \file
27 *
28 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
29 */
30
31/**
32 * UPnP's control (UPnP Device Architecture 1.1, section 3): a control point asks a service to do one of its actions - an
33 * ActionRequest, POSTed to the service's controlURL (Invoke) - and the service answers (HandleAction) with the action's out
34 * arguments, an ActionResponse, or says why it could not, an ActionError.
35 *
36 * It is SOAP 1.1's RPC (WebService::SOAP) with UPnP's conventions on top: a method's namespace is its service's type, the
37 * SOAPACTION header is that type, # and the action, and an error is a UPnPError in a fault's detail.
38 *
39 * So each function here that reads or writes a control message takes WebService::SOAP::Options, defaulted: how SOAP reads
40 * and writes one - with which XML provider, and whether an envelope read is checked against SOAP's schema - is all there
41 * is to say. But for one thing: whatever its fEncodingStyleAttribute, what is written carries encodingStyle on the
42 * Envelope. UPnP Device Architecture 1.1 (Table 3-1) prohibits it on the Body, and requires it on the Envelope of a
43 * message to or from a UPnP 1.0 device or control point. So a control message holds to WebService::SOAP::EnvelopeSchema
44 * as it is by default, corrected - not to SOAP's schema as published, which refuses encodingStyle on the Envelope.
45 *
46 * \par Example Usage
47 * \code
48 * // a control point: switch a light on, then ask it its status (service: one of dd.fServices, where
49 * // dd = UPnP::DeSerialize (fetched).Resolve (location) - its URLs absolute)
50 * const URI& controlURL = service.fControlURL;
51 * SOAP::Invoke (controlURL, {.fServiceType = kSwitchPower, .fAction = "SetTarget"sv, .fArguments = {{"newTargetValue"sv, true}}});
52 * optional<bool> on = SOAP::Invoke (controlURL, {.fServiceType = kSwitchPower, .fAction = "GetStatus"sv}).LookupArgument<bool> ("ResultStatus"sv);
53 *
54 * // the light: its actions, each by name - and its controlURL's route, where each request is checked against its service's
55 * // description (a ServiceDescription), then done by its action's handler
56 * const SOAP::ActionHandlers actions{
57 * {"SetTarget"sv, [&] (const SOAP::ActionRequest& request) -> SOAP::Arguments {
58 * on = *request.LookupArgument<bool> ("newTargetValue"sv); // checked: there, and a boolean
59 * return {};
60 * }},
61 * {"GetStatus"sv, [&] (const SOAP::ActionRequest&) -> SOAP::Arguments { return {{"ResultStatus"sv, on}}; }}};
62 * Route{HTTP::MethodsRegEx::kPost, "SwitchPower/control"_RegEx, [&] (Message& m) {
63 * SOAP::HandleAction (m, kSwitchPower, kSwitchPowerDescription, actions);
64 * }}
65 * \endcode
66 */
68
71
72 /**
73 * \brief One of an action's arguments: its name, and its value as text, as UPnP writes it (DataTypes::ToText) - made from a
74 * value of any of UPnP's data types, as its C++ type: {"ResultStatus"sv, true}
75 */
76 struct Argument : Foundation::Common::KeyValuePair<String, String> {
77 /**
78 * A value of any of UPnP's data types - written as UPnP writes it: as dataType, if given (a BLOB as bin.hex, say), else as
79 * its C++ type's default; or, given text, that text: a string's value, say
80 *
81 * \pre dataType, if given, is a data type whose C++ type is value's (DataTypes::IsTypeOf)
82 */
83 template <DataTypes::IValue T>
84 Argument (const String& name, const T& value);
85 Argument (const String& name, const DataTypes::Value& value, DataTypes::DataType dataType); ///< \brief A value of any of UPnP's data types - written as UPnP writes it
86 Argument (const String& name, const String& text); ///< \brief A value of any of UPnP's data types - written as UPnP writes it; or, given text, that text
87 Argument (const Foundation::Common::KeyValuePair<String, String>& nameAndText); ///< \brief As SOAP has it: its name, and its text
88 };
89
90 /**
91 * An action's arguments - in order: the order its service's description lists them in, which is the order they are sent in
92 * (UPnP Device Architecture 1.1, section 3.2.1).
93 */
95
96 /**
97 * \brief A control point's request that a service do one of its actions.
98 */
100 /**
101 * The service's type: urn:schemas-upnp-org:service:SwitchPower:1, say
102 */
104 /**
105 * The action's name: SetTarget, say
106 */
108 /**
109 * Its in arguments
110 */
112
113 /**
114 * The SOAPACTION header it is sent with: its service type, # and action, in quotes (UPnP Device Architecture 1.1,
115 * section 3.2.1)
116 */
117 nonvirtual String GetSOAPAction () const;
118
119 /**
120 * The value of the argument called name, read as a T (DataTypes::FromText) - as dataType, if given (bin.hex, say), else as
121 * T's default data type; its text, by default - nullopt if no argument has that name, or its text is not a T's
122 *
123 * \pre dataType, if given, is a data type whose C++ type is T (DataTypes::IsTypeOf)
124 */
125 template <DataTypes::IValue T = String>
126 nonvirtual optional<T> LookupArgument (const String& name) const;
127 template <DataTypes::IValue T>
128 nonvirtual optional<T> LookupArgument (const String& name, DataTypes::DataType dataType) const; ///< \brief The value of the argument called name, read as a T
129
130 bool operator== (const ActionRequest&) const = default;
131
132 /**
133 * @see Characters::ToString ();
134 */
135 nonvirtual String ToString () const;
136 };
137
138 /**
139 * \brief A service's answer to an ActionRequest, it having done the action: the action's out arguments.
140 */
142 /**
143 * The service's type, as in the request
144 */
146 /**
147 * The action's name, as in the request
148 */
150 /**
151 * Its out arguments
152 */
154
155 /**
156 * The value of the argument called name, read as a T (DataTypes::FromText) - as dataType, if given (bin.hex, say), else as
157 * T's default data type; its text, by default - nullopt if no argument has that name, or its text is not a T's
158 *
159 * \pre dataType, if given, is a data type whose C++ type is T (DataTypes::IsTypeOf)
160 */
161 template <DataTypes::IValue T = String>
162 nonvirtual optional<T> LookupArgument (const String& name) const;
163 template <DataTypes::IValue T>
164 nonvirtual optional<T> LookupArgument (const String& name, DataTypes::DataType dataType) const; ///< \brief The value of the argument called name, read as a T
165
166 bool operator== (const ActionResponse&) const = default;
167
168 /**
169 * @see Characters::ToString ();
170 */
171 nonvirtual String ToString () const;
172 };
173
174 /**
175 * \brief A service's answer to an ActionRequest, it having not done the action: why not (UPnP Device Architecture 1.1,
176 * section 3.2.2) - a UPnPError, in a SOAP fault's detail.
177 */
178 struct ActionError {
179 /**
180 * The error codes UPnP Device Architecture 1.1, section 3.2.2, gives - each with its errorDescription there: 401 Invalid
181 * Action (none of that name), 402 Invalid Args (too few or too many, misnamed, or a value of the wrong type), 501 Action
182 * Failed (could not, as things are), ...
183 */
184 static constexpr unsigned int kInvalidAction = 401;
185 static constexpr unsigned int kInvalidArgs = 402;
186 static constexpr unsigned int kActionFailed = 501;
187 static constexpr unsigned int kArgumentValueInvalid = 600;
188 static constexpr unsigned int kArgumentValueOutOfRange = 601;
189 static constexpr unsigned int kOptionalActionNotImplemented = 602;
190 static constexpr unsigned int kOutOfMemory = 603;
191 static constexpr unsigned int kHumanInterventionRequired = 604;
192 static constexpr unsigned int kStringArgumentTooLong = 605;
193
194 /**
195 * One of those, or one the service's standard gives (606-799), or its vendor's (800-899)
196 */
197 unsigned int fErrorCode{kActionFailed};
198 String fErrorDescription;
199
200 /**
201 * \brief As SOAP sends it: a Client fault, UPnPError, its detail a UPnPError element
202 */
203 nonvirtual WebService::SOAP::Fault AsFault () const;
204
205 /**
206 * \brief The UPnPError a SOAP fault's detail holds; nullopt if it holds none - the detail read with options' XML
207 * provider (and checked against no schema: SOAP's is an envelope's)
208 */
209 static optional<ActionError> FromFault (const WebService::SOAP::Fault& fault, const WebService::SOAP::Options& options = {});
210
211 bool operator== (const ActionError&) const = default;
212
213 /**
214 * @see Characters::ToString ();
215 */
216 nonvirtual String ToString () const;
217 };
218
219 /**
220 * \brief An ActionError, thrown: Invoke throws the one a service answers with, and a HandleAction doAction throws one to
221 * answer with it.
222 */
223 class ActionException : public Foundation::Execution::Exception<runtime_error> {
224 public:
225 /**
226 * The error; or, given just one of ActionError's codes, the errorDescription UPnP gives it
227 */
228 ActionException (const ActionError& error);
229 ActionException (unsigned int errorCode); ///< \brief The error; or, given just one of ActionError's codes, the errorDescription UPnP gives it
230
231 public:
232 /**
233 */
234 nonvirtual ActionError GetError () const;
235
236 private:
237 ActionError fError_;
238 };
239
240 /**
241 * \brief The SOAP message - its XML, UTF-8 - which sends it: a request, a response, or an error (a SOAP fault)
242 */
244 Foundation::Memory::BLOB Serialize (const ActionResponse& response, const WebService::SOAP::Options& options = {}); ///< \brief The SOAP message - its XML, UTF-8 - which sends it
245 Foundation::Memory::BLOB Serialize (const ActionError& error, const WebService::SOAP::Options& options = {}); ///< \brief The SOAP message - its XML, UTF-8 - which sends it
246
247 /**
248 * \brief The SOAP message read: what Serialize writes, and any other's. Throws DataExchange::BadFormatException if it is not one
249 * - an ActionResponse read from a fault, say, or with options.fValidateReadAgainst, one that schema refuses; and
250 * throws in a build with no XML parser.
251 */
252 void DeSerialize (const Foundation::Memory::BLOB& b, ActionRequest* request, const WebService::SOAP::Options& options = {});
253 void DeSerialize (const Foundation::Memory::BLOB& b, ActionResponse* response, const WebService::SOAP::Options& options = {}); ///< \brief The SOAP message read
254 void DeSerialize (const Foundation::Memory::BLOB& b, ActionError* error, const WebService::SOAP::Options& options = {}); ///< \brief The SOAP message read
255
256 /**
257 * \brief Ask the service at controlURL to do request's action - and return its answer. Throws ActionException if the service
258 * answers with a UPnPError; otherwise as WebService::SOAP::Invoke.
259 *
260 * Sent over connection, where one is given - the caller's, as WebService::SOAP::Invoke's: a control point asking one
261 * device many things can keep one, or lease them from a Transfer::ConnectionPool. Else over a new connection, with the
262 * defaults.
263 */
264 ActionResponse Invoke (const URI& controlURL, const ActionRequest& request, const WebService::SOAP::Options& options = {});
265 ActionResponse Invoke (Foundation::IO::Network::Transfer::Connection::Ptr connection, const URI& controlURL, const ActionRequest& request,
266 const WebService::SOAP::Options& options = {}); ///< \brief Ask the service at controlURL to do request's action, over the caller's connection
267
268 /**
269 * \brief Throws the ActionException a service answers request with if its description - its actions, their arguments, and
270 * the state variables whose types they have - rules it out (UPnP Device Architecture 1.1, section 3.2.2):
271 *
272 * o 401 (Invalid Action): it has no action of that name
273 * o 402 (Invalid Args): the in arguments are not the action's, in its order - too few or too many, misnamed, out of
274 * order - or a value is not of its argument's data type (its related state variable's)
275 * o 601 (Argument Value Out of Range): a value is not one its state variable allows - in its allowedValueList, or its
276 * allowedValueRange
277 *
278 * A data type the description names that is not UPnP's (DataTypes::DataType) - a vendor's - is not checked.
279 */
280 void CheckRequest (const ActionRequest& request, const ServiceDescription& description);
281
282 /**
283 * \brief What a service does for a request for one of its actions: the action's out arguments - or, thrown (ActionException),
284 * why it was not done
285 */
286 using ActionHandler = function<Arguments (const ActionRequest&)>;
287
288 /**
289 * \brief A service's actions' handlers, each by its action's name - as its description names it
290 */
292
293 /**
294 * \brief Answer a control request, at the controlURL's route of the service of type serviceType: doAction's out arguments,
295 * or the ActionError it throws (as ActionException) - and 401 (Invalid Action) for another service type's request.
296 * Otherwise as WebService::SOAP::HandleRequest: 415 if not text/xml, and a Client fault if not a SOAP call (nor, with
297 * options.fValidateReadAgainst, a valid one).
298 *
299 * Given the service's description, a request it rules out (CheckRequest) is answered with that error, and doAction never
300 * sees it - so doAction may count on each in argument being there, and of its type.
301 *
302 * Given its actions' handlers too, a request is done by its action's - and one for an action described, but with no handler,
303 * is answered with 602 (Optional Action Not Implemented). So a service that does only its required actions hands over
304 * just theirs.
305 *
306 * \pre each of actions is an action description has
307 */
308 void HandleAction (WebServer::Message& m, const String& serviceType, const ActionHandler& doAction, const WebService::SOAP::Options& options = {});
309 void HandleAction (WebServer::Message& m, const String& serviceType, const ServiceDescription& description, const ActionHandler& doAction,
310 const WebService::SOAP::Options& options = {}); ///< \brief Answer a control request - having checked it against the service's description
311 void HandleAction (WebServer::Message& m, const String& serviceType, const ServiceDescription& description, const ActionHandlers& actions,
312 const WebService::SOAP::Options& options = {}); ///< \brief Answer a control request - checked against the service's description, and done by its action's handler
313
314}
315
316/*
317 ********************************************************************************
318 ***************************** Implementation Details ***************************
319 ********************************************************************************
320 */
321#include "Action.inl"
322
323#endif /*_Stroika_Frameworks_UPnP_SOAP_Action_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:219
An ActionError, thrown: Invoke throws the one a service answers with, and a HandleAction doAction thr...
Definition Action.h:223
variant< bool, uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t, float, double, Foundation::Characters::Character, String, Foundation::Time::Date, Foundation::Time::DateTime, Foundation::Time::TimeOfDay, Foundation::Memory::BLOB, Foundation::IO::Network::URI, Foundation::Common::GUID > Value
A value of any of UPnP's data types, as its C++ type (the table above) - for code that learns a value...
Definition DataTypes.h:111
DataType
UPnP's data types - each named, as a service's description names it (Common::DefaultNames): ui2,...
Definition DataTypes.h:69
Foundation::Memory::BLOB Serialize(const ActionRequest &request, const WebService::SOAP::Options &options={})
The SOAP message - its XML, UTF-8 - which sends it: a request, a response, or an error (a SOAP fault)
Definition Action.cpp:215
ActionResponse Invoke(const URI &controlURL, const ActionRequest &request, const WebService::SOAP::Options &options={})
Ask the service at controlURL to do request's action - and return its answer. Throws ActionException ...
Definition Action.cpp:272
Foundation::Containers::Sequence< Argument > Arguments
Definition Action.h:94
void DeSerialize(const Foundation::Memory::BLOB &b, ActionRequest *request, const WebService::SOAP::Options &options={})
The SOAP message read: what Serialize writes, and any other's. Throws DataExchange::BadFormatExceptio...
Definition Action.cpp:239
Foundation::Containers::Mapping< String, ActionHandler > ActionHandlers
A service's actions' handlers, each by its action's name - as its description names it.
Definition Action.h:291
void CheckRequest(const ActionRequest &request, const ServiceDescription &description)
Throws the ActionException a service answers request with if its description - its actions,...
Definition Action.cpp:377
void HandleAction(WebServer::Message &m, const String &serviceType, const ActionHandler &doAction, const WebService::SOAP::Options &options={})
Answer a control request, at the controlURL's route of the service of type serviceType: doAction's ou...
Definition Action.cpp:300
function< Arguments(const ActionRequest &)> ActionHandler
What a service does for a request for one of its actions: the action's out arguments - or,...
Definition Action.h:286
A service's answer to an ActionRequest, it having not done the action: why not (UPnP Device Architect...
Definition Action.h:178
nonvirtual WebService::SOAP::Fault AsFault() const
As SOAP sends it: a Client fault, UPnPError, its detail a UPnPError element.
Definition Action.cpp:140
static constexpr unsigned int kInvalidAction
Definition Action.h:184
static optional< ActionError > FromFault(const WebService::SOAP::Fault &fault, const WebService::SOAP::Options &options={})
The UPnPError a SOAP fault's detail holds; nullopt if it holds none - the detail read with options' X...
Definition Action.cpp:148
A control point's request that a service do one of its actions.
Definition Action.h:99
nonvirtual String GetSOAPAction() const
Definition Action.cpp:95
nonvirtual optional< T > LookupArgument(const String &name) const
nonvirtual optional< T > LookupArgument(const String &name, DataTypes::DataType dataType) const
The value of the argument called name, read as a T.
A service's answer to an ActionRequest, it having done the action: the action's out arguments.
Definition Action.h:141
nonvirtual optional< T > LookupArgument(const String &name, DataTypes::DataType dataType) const
The value of the argument called name, read as a T.
nonvirtual optional< T > LookupArgument(const String &name) const
One of an action's arguments: its name, and its value as text, as UPnP writes it (DataTypes::ToText) ...
Definition Action.h:76
A service's description - its SCPD (UPnP Device Architecture 1.1, section 2.5): its actions,...
A call's answer, the method having not been done: why not (section 4.4) - sent in an HTTP response wh...
Definition SOAP.h:143
What SOAP must be told that has a sensible default - taken by Serialize and DeSerialize,...
Definition SOAP.h:252