pvxslibs 1.5.0__cp310-cp310-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvxslibs/__init__.py +0 -0
- pvxslibs/dbd/pvxsIoc.dbd +8 -0
- pvxslibs/include/pvxs/client.h +1094 -0
- pvxslibs/include/pvxs/data.h +948 -0
- pvxslibs/include/pvxs/iochooks.h +170 -0
- pvxslibs/include/pvxs/log.h +148 -0
- pvxslibs/include/pvxs/netcommon.h +82 -0
- pvxslibs/include/pvxs/nt.h +208 -0
- pvxslibs/include/pvxs/server.h +238 -0
- pvxslibs/include/pvxs/sharedArray.h +748 -0
- pvxslibs/include/pvxs/sharedpv.h +121 -0
- pvxslibs/include/pvxs/source.h +290 -0
- pvxslibs/include/pvxs/srvcommon.h +148 -0
- pvxslibs/include/pvxs/unittest.h +327 -0
- pvxslibs/include/pvxs/util.h +354 -0
- pvxslibs/include/pvxs/version.h +97 -0
- pvxslibs/include/pvxs/versionNum.h +6 -0
- pvxslibs/ioc.py +10 -0
- pvxslibs/lib/__init__.py +0 -0
- pvxslibs/lib/event_core_dsoinfo.py +14 -0
- pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
- pvxslibs/lib/libevent_core.so +0 -0
- pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
- pvxslibs/lib/libevent_pthread.so +0 -0
- pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
- pvxslibs/lib/libpvxs.so +0 -0
- pvxslibs/lib/libpvxs.so.1.5 +0 -0
- pvxslibs/lib/libpvxsIoc.so +0 -0
- pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
- pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
- pvxslibs/lib/pvxs_dsoinfo.py +14 -0
- pvxslibs/path.py +12 -0
- pvxslibs/test/__init__.py +0 -0
- pvxslibs/test/test_load.py +30 -0
- pvxslibs/version.py +32 -0
- pvxslibs-1.5.0.dist-info/METADATA +44 -0
- pvxslibs-1.5.0.dist-info/RECORD +40 -0
- pvxslibs-1.5.0.dist-info/WHEEL +5 -0
- pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
- pvxslibs-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1094 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
3
|
+
* pvxs is distributed subject to a Software License Agreement found
|
|
4
|
+
* in file LICENSE that is included with this distribution.
|
|
5
|
+
*/
|
|
6
|
+
#ifndef PVXS_CLIENT_H
|
|
7
|
+
#define PVXS_CLIENT_H
|
|
8
|
+
|
|
9
|
+
#include <stdexcept>
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <map>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <functional>
|
|
15
|
+
#include <iosfwd>
|
|
16
|
+
#include <typeinfo>
|
|
17
|
+
|
|
18
|
+
#include <epicsTime.h>
|
|
19
|
+
#include <epicsEndian.h>
|
|
20
|
+
|
|
21
|
+
#include <pvxs/version.h>
|
|
22
|
+
#include <pvxs/data.h>
|
|
23
|
+
#include <pvxs/netcommon.h>
|
|
24
|
+
#include <pvxs/util.h>
|
|
25
|
+
|
|
26
|
+
namespace pvxs {
|
|
27
|
+
namespace client {
|
|
28
|
+
|
|
29
|
+
class Context;
|
|
30
|
+
struct Config;
|
|
31
|
+
|
|
32
|
+
//! Operation failed because of connection to server was lost
|
|
33
|
+
struct PVXS_API Disconnect : public std::runtime_error
|
|
34
|
+
{
|
|
35
|
+
Disconnect();
|
|
36
|
+
virtual ~Disconnect();
|
|
37
|
+
|
|
38
|
+
//! When loss of connection was noticed (when timeout expires).
|
|
39
|
+
const epicsTime time;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
//! Error condition signaled by server
|
|
43
|
+
struct PVXS_API RemoteError : public std::runtime_error
|
|
44
|
+
{
|
|
45
|
+
RemoteError(const std::string& msg);
|
|
46
|
+
virtual ~RemoteError();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//! For monitor only. Subscription has completed normally
|
|
50
|
+
//! and no more events will ever be received.
|
|
51
|
+
struct PVXS_API Finished : public Disconnect
|
|
52
|
+
{
|
|
53
|
+
Finished() = default;
|
|
54
|
+
virtual ~Finished();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//! For monitor only. Subscription has (re)connected.
|
|
58
|
+
struct PVXS_API Connected : public std::runtime_error
|
|
59
|
+
{
|
|
60
|
+
Connected(const std::string& peerName);
|
|
61
|
+
virtual ~Connected();
|
|
62
|
+
|
|
63
|
+
const std::string peerName;
|
|
64
|
+
const epicsTime time;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
struct PVXS_API Interrupted : public std::runtime_error
|
|
68
|
+
{
|
|
69
|
+
Interrupted();
|
|
70
|
+
virtual ~Interrupted();
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
struct PVXS_API Timeout : public std::runtime_error
|
|
74
|
+
{
|
|
75
|
+
Timeout();
|
|
76
|
+
virtual ~Timeout();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//! Holder for a Value or an exception
|
|
80
|
+
class Result {
|
|
81
|
+
Value _result;
|
|
82
|
+
std::exception_ptr _error;
|
|
83
|
+
std::string _peerName;
|
|
84
|
+
public:
|
|
85
|
+
Result() = default;
|
|
86
|
+
Result(Value&& val, const std::string& peerName) :_result(std::move(val)), _peerName(peerName) {}
|
|
87
|
+
explicit Result(const std::exception_ptr& err) :_error(err) {}
|
|
88
|
+
|
|
89
|
+
//! Access to the Value, or rethrow the exception
|
|
90
|
+
Value& operator()() {
|
|
91
|
+
if(_error)
|
|
92
|
+
std::rethrow_exception(_error);
|
|
93
|
+
return _result;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const std::string peerName() const { return _peerName; }
|
|
97
|
+
|
|
98
|
+
bool error() const { return !!_error; }
|
|
99
|
+
explicit operator bool() const { return _result || _error; }
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
//! Handle for in-progress operation
|
|
103
|
+
struct PVXS_API Operation {
|
|
104
|
+
//! Operation type
|
|
105
|
+
const enum operation_t {
|
|
106
|
+
Info = 17, // CMD_GET_FIELD
|
|
107
|
+
Get = 10, // CMD_GET
|
|
108
|
+
Put = 11, // CMD_PUT
|
|
109
|
+
RPC = 20, // CMD_RPC
|
|
110
|
+
Monitor = 13, // CMD_MONITOR
|
|
111
|
+
Discover = 3, // CMD_SEARCH
|
|
112
|
+
} op;
|
|
113
|
+
|
|
114
|
+
explicit constexpr Operation(operation_t op) :op(op) {}
|
|
115
|
+
Operation(const Operation&) = delete;
|
|
116
|
+
Operation& operator=(const Operation&) = delete;
|
|
117
|
+
virtual ~Operation() =0;
|
|
118
|
+
|
|
119
|
+
/** PV name
|
|
120
|
+
*
|
|
121
|
+
* Returned reference is valid for the lifetime of the Operation
|
|
122
|
+
*/
|
|
123
|
+
virtual const std::string& name() =0;
|
|
124
|
+
|
|
125
|
+
//! Explicitly cancel a pending operation.
|
|
126
|
+
//! Blocks until an in-progress callback has completed.
|
|
127
|
+
//! @returns true if the operation was canceled, or false if already complete.
|
|
128
|
+
virtual bool cancel() =0;
|
|
129
|
+
|
|
130
|
+
/** @brief Block until Operation completion
|
|
131
|
+
*
|
|
132
|
+
* As an alternative to a .result() callback, wait for operation completion,
|
|
133
|
+
* timeout, or interruption (via. interrupt() ).
|
|
134
|
+
*
|
|
135
|
+
* @param timeout Time to wait prior to throwing TimeoutError. cf. epicsEvent::wait(double)
|
|
136
|
+
* @return result Value. Always empty/invalid for put()
|
|
137
|
+
* @throws Timeout Timeout exceeded
|
|
138
|
+
* @throws Interrupted interrupt() called
|
|
139
|
+
*/
|
|
140
|
+
virtual Value wait(double timeout) =0;
|
|
141
|
+
|
|
142
|
+
//! wait(double) without a timeout
|
|
143
|
+
Value wait() {
|
|
144
|
+
return wait(99999999.0);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//! Queue an interruption of a wait() or wait(double) call.
|
|
148
|
+
virtual void interrupt() =0;
|
|
149
|
+
|
|
150
|
+
protected:
|
|
151
|
+
virtual void _reExecGet(std::function<void(client::Result&&)>&& resultcb) =0;
|
|
152
|
+
virtual void _reExecPut(const Value& arg, std::function<void(client::Result&&)>&& resultcb) =0;
|
|
153
|
+
public:
|
|
154
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
155
|
+
// usable when Builder::autoExec(false)
|
|
156
|
+
// For GET/PUT, (re)issue request for current value
|
|
157
|
+
inline void reExecGet(std::function<void(client::Result&&)>&& resultcb) { this->_reExecGet(std::move(resultcb)); }
|
|
158
|
+
// For PUT (re)issue request to set current value
|
|
159
|
+
inline void reExecPut(const Value& arg, std::function<void(client::Result&&)>&& resultcb) { this->_reExecPut(arg, std::move(resultcb)); }
|
|
160
|
+
#endif
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
//! Information about the state of a Subscription
|
|
164
|
+
struct SubscriptionStat {
|
|
165
|
+
//! Number of events in the queue
|
|
166
|
+
size_t nQueue=0;
|
|
167
|
+
//! Number of Value updates where the server reported at least
|
|
168
|
+
//! one update dropped/squashed.
|
|
169
|
+
size_t nSrvSquash=0;
|
|
170
|
+
//! Number of Value updates dropped/squashed due to client queue overflow
|
|
171
|
+
size_t nCliSquash=0;
|
|
172
|
+
//! Max queue size so far
|
|
173
|
+
size_t maxQueue=0;
|
|
174
|
+
//! Limit on queue size
|
|
175
|
+
size_t limitQueue=0;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
//! Handle for monitor subscription
|
|
179
|
+
struct PVXS_API Subscription {
|
|
180
|
+
Subscription() = default;
|
|
181
|
+
Subscription(const Subscription&) = delete;
|
|
182
|
+
Subscription& operator=(const Subscription&) = delete;
|
|
183
|
+
virtual ~Subscription() =0;
|
|
184
|
+
|
|
185
|
+
protected:
|
|
186
|
+
virtual const std::string& _name() =0;
|
|
187
|
+
public:
|
|
188
|
+
//! PV name
|
|
189
|
+
inline const std::string& name() { return _name(); }
|
|
190
|
+
|
|
191
|
+
//! Explicitly cancel a active subscription.
|
|
192
|
+
//! Blocks until any in-progress callback has completed.
|
|
193
|
+
virtual bool cancel() =0;
|
|
194
|
+
|
|
195
|
+
//! Ask a server to stop (true) or re-start (false), sending updates to this Subscription
|
|
196
|
+
virtual void pause(bool p=true) =0;
|
|
197
|
+
//! Shorthand for @code pause(false) @endcode
|
|
198
|
+
inline void resume() { pause(false); }
|
|
199
|
+
|
|
200
|
+
/** De-queue update from subscription event queue.
|
|
201
|
+
*
|
|
202
|
+
* If the queue is empty, return an empty/invalid Value (Value::valid()==false).
|
|
203
|
+
* A data update is returned as a Value.
|
|
204
|
+
* An error or special event is thrown.
|
|
205
|
+
*
|
|
206
|
+
* @returns A valid Value until the queue is empty
|
|
207
|
+
* @throws Connected (depending on MonitorBuilder::maskConnected())
|
|
208
|
+
* @throws Disconnect (depending on MonitorBuilder::maskDisconnect())
|
|
209
|
+
* @throws Finished (depending on MonitorBuilder::maskDisconnect())
|
|
210
|
+
* @throws RemoteError For server signaled errors
|
|
211
|
+
* @throws std::exception For client side failures.
|
|
212
|
+
*
|
|
213
|
+
* @code
|
|
214
|
+
* std::shared_ptr<Subscription> sub(...);
|
|
215
|
+
* try {
|
|
216
|
+
* while(auto update = sub.pop()) {
|
|
217
|
+
* // have data update
|
|
218
|
+
* ...
|
|
219
|
+
* }
|
|
220
|
+
* // queue empty
|
|
221
|
+
* } catch(Connected& con) { // if MonitorBuilder::maskConnected(false)
|
|
222
|
+
* } catch(Finished& con) { // if MonitorBuilder::maskDisconnected(false)
|
|
223
|
+
* } catch(Disconnect& con) { // if MonitorBuilder::maskDisconnected(false)
|
|
224
|
+
* } catch(RemoteError& con) { // error message from server
|
|
225
|
+
* } catch(std::exception& con) { // client side error
|
|
226
|
+
* }
|
|
227
|
+
* @endcode
|
|
228
|
+
*/
|
|
229
|
+
virtual Value pop() =0;
|
|
230
|
+
|
|
231
|
+
protected:
|
|
232
|
+
virtual bool doPop(std::vector<Value>& out, size_t limit=0u) =0;
|
|
233
|
+
public:
|
|
234
|
+
|
|
235
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
236
|
+
/** De-queue a batch of updates from subscription event queue.
|
|
237
|
+
*
|
|
238
|
+
* @param out Updated with any Values dequeued. Will always be clear()d
|
|
239
|
+
* @param limit When non-zero, an upper limit on the number of Values which will be dequeued.
|
|
240
|
+
* @return true if the queue was not emptied, and pop() should be called again.
|
|
241
|
+
* false if the queue was emptied, and a further onEvent() callback may be awaited.
|
|
242
|
+
* @throws the same exceptions as non-batch pop()
|
|
243
|
+
*
|
|
244
|
+
* @since 1.1.0 Added
|
|
245
|
+
*/
|
|
246
|
+
inline bool pop(std::vector<Value>& out, size_t limit=0u)
|
|
247
|
+
{ return doPop(out, limit); }
|
|
248
|
+
#endif
|
|
249
|
+
|
|
250
|
+
//! Poll statistics
|
|
251
|
+
//! @since 1.1.0
|
|
252
|
+
virtual void stats(SubscriptionStat&, bool reset = false) =0;
|
|
253
|
+
|
|
254
|
+
protected:
|
|
255
|
+
virtual void _onEvent(std::function<void(Subscription&)>&&) =0;
|
|
256
|
+
public:
|
|
257
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
258
|
+
// replace handler stored with MonitorBuilder::event()
|
|
259
|
+
inline void onEvent(std::function<void(Subscription&)>&& fn) { this->_onEvent(std::move(fn)); }
|
|
260
|
+
#endif
|
|
261
|
+
|
|
262
|
+
//! Return strong internal reference which will not prevent
|
|
263
|
+
//! implicit cancellation when the last reference returned
|
|
264
|
+
//! by exec() is released.
|
|
265
|
+
//! @since 0.2.0
|
|
266
|
+
virtual std::shared_ptr<Subscription> shared_from_this() const =0;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
//! Handle for entry in Channel cache
|
|
270
|
+
struct PVXS_API Connect {
|
|
271
|
+
virtual ~Connect() =0;
|
|
272
|
+
|
|
273
|
+
//! Name passed to Context::connect()
|
|
274
|
+
virtual const std::string& name() const =0;
|
|
275
|
+
//! Poll (momentary) connection status
|
|
276
|
+
virtual bool connected() const =0;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
class GetBuilder;
|
|
280
|
+
class PutBuilder;
|
|
281
|
+
class RPCBuilder;
|
|
282
|
+
class MonitorBuilder;
|
|
283
|
+
class RequestBuilder;
|
|
284
|
+
class ConnectBuilder;
|
|
285
|
+
struct Discovered;
|
|
286
|
+
class DiscoverBuilder;
|
|
287
|
+
|
|
288
|
+
/** An independent PVA protocol client instance
|
|
289
|
+
*
|
|
290
|
+
* Typically created with Config::build()
|
|
291
|
+
*
|
|
292
|
+
* @code
|
|
293
|
+
* Context ctxt(Config::from_env().build());
|
|
294
|
+
* @endcode
|
|
295
|
+
*/
|
|
296
|
+
class PVXS_API Context {
|
|
297
|
+
public:
|
|
298
|
+
struct Pvt;
|
|
299
|
+
|
|
300
|
+
//! An empty/dummy Context
|
|
301
|
+
constexpr Context() = default;
|
|
302
|
+
//! Create/allocate a new client with the provided config.
|
|
303
|
+
//! Config::build() is a convenient shorthand.
|
|
304
|
+
explicit Context(const Config &);
|
|
305
|
+
~Context();
|
|
306
|
+
|
|
307
|
+
/** Create new client context based on configuration from $EPICS_PVA* environment variables.
|
|
308
|
+
*
|
|
309
|
+
* Shorthand for @code Config::fromEnv().build() @endcode.
|
|
310
|
+
* @since 0.2.1
|
|
311
|
+
*/
|
|
312
|
+
static
|
|
313
|
+
Context fromEnv();
|
|
314
|
+
|
|
315
|
+
//! effective config of running client
|
|
316
|
+
const Config& config() const;
|
|
317
|
+
|
|
318
|
+
/** Force close the client.
|
|
319
|
+
*
|
|
320
|
+
* ~Context() will close() automatically. So an explicit call is optional.
|
|
321
|
+
*
|
|
322
|
+
* Aborts/interrupts all in progress network operations.
|
|
323
|
+
* Blocks until any in-progress callbacks have completed.
|
|
324
|
+
*
|
|
325
|
+
* @since 1.1.0
|
|
326
|
+
*/
|
|
327
|
+
void close();
|
|
328
|
+
|
|
329
|
+
/** Request the present value of a PV
|
|
330
|
+
*
|
|
331
|
+
* Simple blocking
|
|
332
|
+
*
|
|
333
|
+
* @code
|
|
334
|
+
* Context ctxt(...);
|
|
335
|
+
* auto result = ctxt.get("pv:name")
|
|
336
|
+
* .exec()
|
|
337
|
+
* ->wait();
|
|
338
|
+
* @endcode
|
|
339
|
+
*
|
|
340
|
+
* With completion callback
|
|
341
|
+
*
|
|
342
|
+
* @code
|
|
343
|
+
* Context ctxt(...);
|
|
344
|
+
* auto op = ctxt.get("pv:name")
|
|
345
|
+
* .result([](Result&& prototype){
|
|
346
|
+
* std::cout<<prototype();
|
|
347
|
+
* })
|
|
348
|
+
* .exec();
|
|
349
|
+
* // store op until completion
|
|
350
|
+
* @endcode
|
|
351
|
+
* See GetBuilder and <a href="#get-info">Get/Info</a> for details.
|
|
352
|
+
*/
|
|
353
|
+
inline
|
|
354
|
+
GetBuilder get(const std::string& pvname);
|
|
355
|
+
|
|
356
|
+
/** Request type information from PV.
|
|
357
|
+
* Results in a Value with no marked fields.
|
|
358
|
+
*
|
|
359
|
+
* Simple blocking
|
|
360
|
+
*
|
|
361
|
+
* @code
|
|
362
|
+
* Context ctxt(...);
|
|
363
|
+
* auto result = ctxt.info("pv:name")
|
|
364
|
+
* .exec()
|
|
365
|
+
* ->wait();
|
|
366
|
+
* @endcode
|
|
367
|
+
*
|
|
368
|
+
* With completion callback
|
|
369
|
+
*
|
|
370
|
+
* @code
|
|
371
|
+
* Context ctxt(...);
|
|
372
|
+
* auto op = ctxt.info("pv:name")
|
|
373
|
+
* .result([](Result&& prototype){
|
|
374
|
+
* std::cout<<prototype();
|
|
375
|
+
* })
|
|
376
|
+
* .exec();
|
|
377
|
+
* // store op until completion
|
|
378
|
+
* @endcode
|
|
379
|
+
*
|
|
380
|
+
* See GetBuilder and <a href="#get-info">Get/Info</a> for details.
|
|
381
|
+
*/
|
|
382
|
+
inline
|
|
383
|
+
GetBuilder info(const std::string& pvname);
|
|
384
|
+
|
|
385
|
+
/** Request change/update of PV.
|
|
386
|
+
*
|
|
387
|
+
* Assign certain values to certain fields and block for completion.
|
|
388
|
+
*
|
|
389
|
+
* @code
|
|
390
|
+
* Context ctxt(...);
|
|
391
|
+
* auto result = ctxt.put("pv:name")
|
|
392
|
+
* .set("value", 42)
|
|
393
|
+
* .exec()
|
|
394
|
+
* ->wait();
|
|
395
|
+
* @endcode
|
|
396
|
+
*
|
|
397
|
+
* Alternately, and more generally, using a .build() callback
|
|
398
|
+
* and use .result() callback for completion notification.
|
|
399
|
+
*
|
|
400
|
+
* @code
|
|
401
|
+
* Context ctxt(...);
|
|
402
|
+
* auto op = ctxt.put("pv:name")
|
|
403
|
+
* .build([](Value&& prototype) -> Value {
|
|
404
|
+
* auto putval = prototype.cloneEmpty();
|
|
405
|
+
* putval["value"] = 42;
|
|
406
|
+
* return putval;
|
|
407
|
+
* })
|
|
408
|
+
* .result([](Result&& prototype){
|
|
409
|
+
* try {
|
|
410
|
+
* // always returns empty Value on success
|
|
411
|
+
* prototype();
|
|
412
|
+
* std::cout<<"Success";
|
|
413
|
+
* }catch(std::exception& e){
|
|
414
|
+
* std::cout<<"Error: "<<e.what();
|
|
415
|
+
* }
|
|
416
|
+
* })
|
|
417
|
+
* .exec();
|
|
418
|
+
* // store op until completion
|
|
419
|
+
* @endcode
|
|
420
|
+
*
|
|
421
|
+
* See PutBuilder and <a href="#put">Put</a> for details.
|
|
422
|
+
*/
|
|
423
|
+
inline
|
|
424
|
+
PutBuilder put(const std::string& pvname);
|
|
425
|
+
|
|
426
|
+
inline
|
|
427
|
+
RPCBuilder rpc(const std::string& pvname);
|
|
428
|
+
|
|
429
|
+
/** Execute "stateless" remote procedure call operation.
|
|
430
|
+
*
|
|
431
|
+
* Simple blocking
|
|
432
|
+
*
|
|
433
|
+
* @code
|
|
434
|
+
* Value arg = ...;
|
|
435
|
+
* Context ctxt(...);
|
|
436
|
+
* auto result = ctxt.rpc("pv:name", arg)
|
|
437
|
+
* .arg("blah", 5)
|
|
438
|
+
* .arg("other", "example")
|
|
439
|
+
* .exec()
|
|
440
|
+
* ->wait();
|
|
441
|
+
* @endcode
|
|
442
|
+
*
|
|
443
|
+
* With completion callback
|
|
444
|
+
*
|
|
445
|
+
* @code
|
|
446
|
+
* Value arg = ...;
|
|
447
|
+
* Context ctxt(...);
|
|
448
|
+
* auto op = ctxt.rpc("pv:name", arg)
|
|
449
|
+
* .result([](Result&& prototype){
|
|
450
|
+
* std::cout<<prototype();
|
|
451
|
+
* })
|
|
452
|
+
* .exec();
|
|
453
|
+
* // store op until completion
|
|
454
|
+
* @endcode
|
|
455
|
+
*
|
|
456
|
+
* See RPCBuilder and <a href="#rpc">RPC</a> for details.
|
|
457
|
+
*/
|
|
458
|
+
inline
|
|
459
|
+
RPCBuilder rpc(const std::string& pvname, const Value& arg);
|
|
460
|
+
|
|
461
|
+
/** Create a new subscription for changes to a PV.
|
|
462
|
+
*
|
|
463
|
+
* @code
|
|
464
|
+
* MPMCFIFO<std::shared_ptr<Subscription>> workqueue(42u);
|
|
465
|
+
*
|
|
466
|
+
* auto sub = ctxt.monitor("pv:name")
|
|
467
|
+
* .event([&workqueue](Subscription& sub) {
|
|
468
|
+
* // Subscription queue becomes not empty.
|
|
469
|
+
* // Avoid I/O on PVXS worker thread,
|
|
470
|
+
* // delegate to application thread
|
|
471
|
+
* workqueue.push(sub.shared_from_this());
|
|
472
|
+
* })
|
|
473
|
+
* .exec();
|
|
474
|
+
*
|
|
475
|
+
* while(auto sub = workqueue.pop()) { // could workqueue.push(nullptr) to break
|
|
476
|
+
* try {
|
|
477
|
+
* Value update = sub.pop();
|
|
478
|
+
* if(!update)
|
|
479
|
+
* continue; // Subscription queue empty, wait for another event callback
|
|
480
|
+
* std::cout<<update<<"\n";
|
|
481
|
+
* } catch(std::exception& e) {
|
|
482
|
+
* // may be Connected(), Disconnect(), Finished(), or RemoteError()
|
|
483
|
+
* std::cerr<<"Error "<<e.what()<<"\n";
|
|
484
|
+
* }
|
|
485
|
+
* // queue not empty, reschedule
|
|
486
|
+
* workqueue.push(sub);
|
|
487
|
+
* }
|
|
488
|
+
* // store op until completion
|
|
489
|
+
* @endcode
|
|
490
|
+
*
|
|
491
|
+
* See MonitorBuilder and <a href="#monitor">Monitor</a> for details.
|
|
492
|
+
*/
|
|
493
|
+
inline
|
|
494
|
+
MonitorBuilder monitor(const std::string& pvname);
|
|
495
|
+
|
|
496
|
+
/** Manually add, and maintain, an entry in the Channel cache.
|
|
497
|
+
*
|
|
498
|
+
* This optional method may be used when it is known that a given PV
|
|
499
|
+
* will be needed in future.
|
|
500
|
+
* ConnectBuilder::onConnect() and ConnectBuilder::onDisconnect()
|
|
501
|
+
* may be used to get asynchronous notification, or
|
|
502
|
+
* the returned Connect object may be used to poll Channel (dis)connect state.
|
|
503
|
+
*
|
|
504
|
+
* @since 0.2.0
|
|
505
|
+
*/
|
|
506
|
+
inline
|
|
507
|
+
ConnectBuilder connect(const std::string& pvname);
|
|
508
|
+
|
|
509
|
+
/** Compose a pvRequest independently of a network operation.
|
|
510
|
+
*
|
|
511
|
+
* This is not a network operation.
|
|
512
|
+
*
|
|
513
|
+
* Use of request() is optional. pvRequests can be composed
|
|
514
|
+
* with individual network operation Builders.
|
|
515
|
+
*
|
|
516
|
+
* @code
|
|
517
|
+
* Value pvReq = Context::request()
|
|
518
|
+
* .pvRequest("field(value)field(blah)")
|
|
519
|
+
* .record("pipeline", true)
|
|
520
|
+
* .build();
|
|
521
|
+
* @endcode
|
|
522
|
+
*/
|
|
523
|
+
static inline
|
|
524
|
+
RequestBuilder request();
|
|
525
|
+
|
|
526
|
+
/** Discover the presence or absence of Servers.
|
|
527
|
+
*
|
|
528
|
+
* Combines information from periodic Server Beacon messages, and optionally
|
|
529
|
+
* Discover pings, to provide notice when PVA servers appear or disappear
|
|
530
|
+
* from attached networks.
|
|
531
|
+
*
|
|
532
|
+
* Note that a discover() Operation will never complete with a Value,
|
|
533
|
+
* and so can only end with a timeout or cancellation.
|
|
534
|
+
*
|
|
535
|
+
* @code
|
|
536
|
+
* Context ctxt(...);
|
|
537
|
+
* auto op = ctxt.discover([](const Discovered& evt) {
|
|
538
|
+
* std::cout<<evt<<std::endl;
|
|
539
|
+
* })
|
|
540
|
+
* .pingAll(false) // implied default
|
|
541
|
+
* .exec();
|
|
542
|
+
* op->wait(10.0); // wait 10 seconds, will always timeout.
|
|
543
|
+
* @endcode
|
|
544
|
+
*
|
|
545
|
+
* @since 0.3.0
|
|
546
|
+
*/
|
|
547
|
+
inline
|
|
548
|
+
DiscoverBuilder discover(std::function<void(const Discovered &)> && fn);
|
|
549
|
+
|
|
550
|
+
/** Request prompt search of any disconnected channels.
|
|
551
|
+
*
|
|
552
|
+
* This method is recommended for use when executing a batch of operations.
|
|
553
|
+
*
|
|
554
|
+
* @code
|
|
555
|
+
* Context ctxt = ...;
|
|
556
|
+
* std::vector<std::string> pvnames = ...;
|
|
557
|
+
* std::vector<Operation> ops(pvnames.size());
|
|
558
|
+
*
|
|
559
|
+
* // Initiate all operations
|
|
560
|
+
* for(size_t i=0; i<pvname.size(); i++)
|
|
561
|
+
* ops[i] = ctxt.get(pvnames[i]).exec();
|
|
562
|
+
*
|
|
563
|
+
* ctxt.hurryUp(); // indicate end of batch
|
|
564
|
+
*
|
|
565
|
+
* for(size_t i=0; i<pvname.size(); i++)
|
|
566
|
+
* ... = ops[i].wait(); // wait for results
|
|
567
|
+
* @endcode
|
|
568
|
+
*
|
|
569
|
+
* Optional. Equivalent to detection of a new server.
|
|
570
|
+
* This method has no effect if called more often than once per 30 seconds.
|
|
571
|
+
*/
|
|
572
|
+
void hurryUp();
|
|
573
|
+
|
|
574
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
575
|
+
//! Actions of cacheClear()
|
|
576
|
+
//! @since 0.2.0
|
|
577
|
+
enum cacheAction {
|
|
578
|
+
Clean, //!< Remove channel(s) if unused. Optional for user code.
|
|
579
|
+
Drop, //!< Remove channel(s) unconditionally. Prevents reuse of open channel(s).
|
|
580
|
+
Disconnect, //!< Remove channels(s) unconditionally, and cancel any in-progress operations.
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
/** Channel cache maintenance.
|
|
584
|
+
*
|
|
585
|
+
* @param action cf. cacheAction
|
|
586
|
+
*
|
|
587
|
+
* @since 0.2.0 'name' and 'action' arguments. Defaults to previous behavior.
|
|
588
|
+
*/
|
|
589
|
+
void cacheClear(const std::string& name = std::string(), cacheAction action = Clean);
|
|
590
|
+
|
|
591
|
+
//! Ignore any search replies with these GUIDs
|
|
592
|
+
//! @since 0.2.0
|
|
593
|
+
void ignoreServerGUIDs(const std::vector<ServerGUID>& guids);
|
|
594
|
+
|
|
595
|
+
//! Compile report about peers and channels
|
|
596
|
+
//! @since 0.2.0
|
|
597
|
+
Report report(bool zero=true) const;
|
|
598
|
+
#endif
|
|
599
|
+
|
|
600
|
+
explicit operator bool() const { return pvt.operator bool(); }
|
|
601
|
+
size_t use_count() const { return pvt.use_count(); }
|
|
602
|
+
private:
|
|
603
|
+
std::shared_ptr<Pvt> pvt;
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
namespace detail {
|
|
607
|
+
struct PVRParser;
|
|
608
|
+
|
|
609
|
+
class PVXS_API CommonBase {
|
|
610
|
+
protected:
|
|
611
|
+
std::shared_ptr<Context::Pvt> ctx;
|
|
612
|
+
std::string _name;
|
|
613
|
+
std::string _server;
|
|
614
|
+
struct Req;
|
|
615
|
+
std::shared_ptr<Req> req;
|
|
616
|
+
unsigned _prio = 0u;
|
|
617
|
+
bool _autoexec = true;
|
|
618
|
+
bool _syncCancel = true;
|
|
619
|
+
|
|
620
|
+
CommonBase() {}
|
|
621
|
+
CommonBase(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) : ctx(ctx), _name(name) {}
|
|
622
|
+
~CommonBase();
|
|
623
|
+
|
|
624
|
+
void _rawRequest(const Value&);
|
|
625
|
+
void _field(const std::string& s);
|
|
626
|
+
void _record(const std::string& key, const void* value, StoreType vtype);
|
|
627
|
+
void _parse(const std::string& req);
|
|
628
|
+
Value _buildReq() const;
|
|
629
|
+
|
|
630
|
+
friend struct PVRParser;
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
class PVXS_API PRBase : public CommonBase {
|
|
634
|
+
protected:
|
|
635
|
+
struct Args;
|
|
636
|
+
std::shared_ptr<Args> _args;
|
|
637
|
+
|
|
638
|
+
PRBase() {}
|
|
639
|
+
PRBase(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) : CommonBase(ctx, name) {}
|
|
640
|
+
~PRBase();
|
|
641
|
+
|
|
642
|
+
void _set(const std::string& name, const void *ptr, StoreType type, bool required);
|
|
643
|
+
Value _builder(Value&& prototype) const;
|
|
644
|
+
Value _uriArgs() const;
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
//! Options common to all operations
|
|
648
|
+
template<typename SubBuilder, typename Base>
|
|
649
|
+
class CommonBuilder : public Base {
|
|
650
|
+
protected:
|
|
651
|
+
CommonBuilder() {}
|
|
652
|
+
constexpr CommonBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) : Base(ctx, name) {}
|
|
653
|
+
inline SubBuilder& _sb() { return static_cast<SubBuilder&>(*this); }
|
|
654
|
+
public:
|
|
655
|
+
//! Add field to pvRequest blob.
|
|
656
|
+
//! A more efficient alternative to @code pvRequest("field(name)") @endcode
|
|
657
|
+
SubBuilder& field(const std::string& fld) { this->_field(fld); return _sb(); }
|
|
658
|
+
|
|
659
|
+
/** Add a key/value option to the request.
|
|
660
|
+
*
|
|
661
|
+
* Well known options include:
|
|
662
|
+
*
|
|
663
|
+
* - queueSize : positive integer
|
|
664
|
+
* - block : bool
|
|
665
|
+
* - process : bool or string "true", "false", or "passive"
|
|
666
|
+
* - pipeline : bool
|
|
667
|
+
*
|
|
668
|
+
* A more efficient alternative to @code pvRequest("record[key=value]") @endcode
|
|
669
|
+
*/
|
|
670
|
+
template<typename T>
|
|
671
|
+
SubBuilder& record(const std::string& name, const T& val) {
|
|
672
|
+
const typename impl::StoreAs<T>::store_t& norm(impl::StoreTransform<T>::in(val));
|
|
673
|
+
this->_record(name, &norm, impl::StoreAs<T>::code);
|
|
674
|
+
return _sb();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/** Parse pvRequest string.
|
|
678
|
+
*
|
|
679
|
+
* Supported syntax is a list of zero or more entities
|
|
680
|
+
* separated by zero or more spaces.
|
|
681
|
+
*
|
|
682
|
+
* - ``field(<fld.name>)``
|
|
683
|
+
* - ``record[<key>=\<value>]``
|
|
684
|
+
*/
|
|
685
|
+
SubBuilder& pvRequest(const std::string& expr) { this->_parse(expr); return _sb(); }
|
|
686
|
+
|
|
687
|
+
//! Store raw pvRequest blob.
|
|
688
|
+
SubBuilder& rawRequest(const Value& r) { this->_rawRequest(r); return _sb(); }
|
|
689
|
+
|
|
690
|
+
SubBuilder& priority(int p) { this->_prio = p; return _sb(); }
|
|
691
|
+
SubBuilder& server(const std::string& s) { this->_server = s; return _sb(); }
|
|
692
|
+
|
|
693
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
694
|
+
// for GET/PUT control whether operations automatically proceed from INIT to EXEC
|
|
695
|
+
// cf. Operation::reExec()
|
|
696
|
+
SubBuilder& autoExec(bool b) { this->_autoexec = b; return _sb(); }
|
|
697
|
+
#endif
|
|
698
|
+
|
|
699
|
+
/** Controls whether Operation::cancel() and Subscription::cancel() synchronize.
|
|
700
|
+
*
|
|
701
|
+
* When true (the default) explicit or implicit cancel blocks until any
|
|
702
|
+
* in progress callback has completed. This makes safe some use of
|
|
703
|
+
* references in callbacks.
|
|
704
|
+
* @since 0.2.0
|
|
705
|
+
*/
|
|
706
|
+
SubBuilder& syncCancel(bool b) { this->_syncCancel = b; return _sb(); }
|
|
707
|
+
};
|
|
708
|
+
|
|
709
|
+
} // namespace detail
|
|
710
|
+
|
|
711
|
+
//! Prepare a remote GET or GET_FIELD (info) operation.
|
|
712
|
+
//! See Context::get()
|
|
713
|
+
class GetBuilder : public detail::CommonBuilder<GetBuilder, detail::CommonBase> {
|
|
714
|
+
std::function<void (const Value&)> _onInit;
|
|
715
|
+
std::function<void(Result&&)> _result;
|
|
716
|
+
bool _get = false;
|
|
717
|
+
PVXS_API
|
|
718
|
+
std::shared_ptr<Operation> _exec_info();
|
|
719
|
+
PVXS_API
|
|
720
|
+
std::shared_ptr<Operation> _exec_get();
|
|
721
|
+
public:
|
|
722
|
+
GetBuilder() {}
|
|
723
|
+
GetBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name, bool get) :CommonBuilder{ctx,name}, _get(get) {}
|
|
724
|
+
//! Callback through which result Value or an error will be delivered.
|
|
725
|
+
//! The functor is stored in the Operation returned by exec().
|
|
726
|
+
GetBuilder& result(std::function<void(Result&&)>&& cb) { _result = std::move(cb); return *this; }
|
|
727
|
+
|
|
728
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
729
|
+
// called during operation INIT phase for Get/Put/Monitor when remote type
|
|
730
|
+
// description is available.
|
|
731
|
+
GetBuilder& onInit(std::function<void (const Value&)>&& cb) { this->_onInit = std::move(cb); return *this; }
|
|
732
|
+
#endif
|
|
733
|
+
|
|
734
|
+
/** Execute the network operation.
|
|
735
|
+
* The caller must keep returned Operation pointer until completion
|
|
736
|
+
* or the operation will be implicitly canceled.
|
|
737
|
+
*/
|
|
738
|
+
inline std::shared_ptr<Operation> exec() {
|
|
739
|
+
return _get ? _exec_get() : _exec_info();
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
friend struct Context::Pvt;
|
|
743
|
+
friend class Context;
|
|
744
|
+
};
|
|
745
|
+
GetBuilder Context::info(const std::string& name) { return GetBuilder{pvt, name, false}; }
|
|
746
|
+
GetBuilder Context::get(const std::string& name) { return GetBuilder{pvt, name, true}; }
|
|
747
|
+
|
|
748
|
+
//! Prepare a remote PUT operation
|
|
749
|
+
//! See Context::put()
|
|
750
|
+
class PutBuilder : public detail::CommonBuilder<PutBuilder, detail::PRBase> {
|
|
751
|
+
std::function<void (const Value&)> _onInit;
|
|
752
|
+
std::function<Value(Value&&)> _builder;
|
|
753
|
+
std::function<void(Result&&)> _result;
|
|
754
|
+
bool _doGet = true;
|
|
755
|
+
public:
|
|
756
|
+
PutBuilder() {}
|
|
757
|
+
PutBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) :CommonBuilder{ctx,name} {}
|
|
758
|
+
|
|
759
|
+
/** If fetchPresent is true (the default). Then the Value passed to
|
|
760
|
+
* the build() callback will be initialized with a previous value for this PV.
|
|
761
|
+
*
|
|
762
|
+
* This will be necessary for situation like NTEnum to fetch the choices list.
|
|
763
|
+
* But may be undesirable when writing to array fields to avoid
|
|
764
|
+
* the expense of fetching a copy of the array to be overwritten.
|
|
765
|
+
*/
|
|
766
|
+
PutBuilder& fetchPresent(bool f) { _doGet = f; return *this; }
|
|
767
|
+
|
|
768
|
+
PutBuilder& set(const std::string& name, const void *ptr, StoreType type, bool required) {
|
|
769
|
+
_set(name, ptr, type, required);
|
|
770
|
+
return *this;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/** Utilize default .build() to assign a value to the named field.
|
|
774
|
+
*
|
|
775
|
+
* @param name The field name to attempt to assign.
|
|
776
|
+
* @param val The value to assign. cf. Value::from()
|
|
777
|
+
* @param required Whether to fail if this value can not be assigned to this field.
|
|
778
|
+
*/
|
|
779
|
+
template<typename T>
|
|
780
|
+
PutBuilder& set(const std::string& name, const T& val, bool required=true)
|
|
781
|
+
{
|
|
782
|
+
const typename impl::StoreAs<T>::store_t& norm(impl::StoreTransform<T>::in(val));
|
|
783
|
+
return set(name, &norm, impl::StoreAs<T>::code, required);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/** Provide the builder callback.
|
|
787
|
+
*
|
|
788
|
+
* Once the PV type information is received from the server,
|
|
789
|
+
* this function will be responsible for populating a Value
|
|
790
|
+
* which will actually be sent.
|
|
791
|
+
*
|
|
792
|
+
* The functor is stored in the Operation returned by exec().
|
|
793
|
+
*/
|
|
794
|
+
PutBuilder& build(std::function<Value(Value&&)>&& cb) { _builder = std::move(cb); return *this; }
|
|
795
|
+
|
|
796
|
+
/** Provide the operation result callback.
|
|
797
|
+
* This callback will be passed a Result which is either an empty Value (success)
|
|
798
|
+
* or an exception on error.
|
|
799
|
+
*
|
|
800
|
+
* The functor is stored in the Operation returned by exec().
|
|
801
|
+
*/
|
|
802
|
+
PutBuilder& result(std::function<void(Result&&)>&& cb) { _result = std::move(cb); return *this; }
|
|
803
|
+
|
|
804
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
805
|
+
// called during operation INIT phase for Get/Put/Monitor when remote type
|
|
806
|
+
// description is available.
|
|
807
|
+
PutBuilder& onInit(std::function<void (const Value&)>&& cb) { this->_onInit = std::move(cb); return *this; }
|
|
808
|
+
#endif
|
|
809
|
+
|
|
810
|
+
/** Execute the network operation.
|
|
811
|
+
* The caller must keep returned Operation pointer until completion
|
|
812
|
+
* or the operation will be implicitly canceled.
|
|
813
|
+
*/
|
|
814
|
+
PVXS_API
|
|
815
|
+
std::shared_ptr<Operation> exec();
|
|
816
|
+
|
|
817
|
+
friend struct Context::Pvt;
|
|
818
|
+
friend class Context;
|
|
819
|
+
};
|
|
820
|
+
PutBuilder Context::put(const std::string& name) { return PutBuilder{pvt, name}; }
|
|
821
|
+
|
|
822
|
+
//! Prepare a remote RPC operation.
|
|
823
|
+
//! See Context::rpc()
|
|
824
|
+
class RPCBuilder : public detail::CommonBuilder<RPCBuilder, detail::PRBase> {
|
|
825
|
+
Value _argument;
|
|
826
|
+
std::function<void(Result&&)> _result;
|
|
827
|
+
public:
|
|
828
|
+
RPCBuilder() {}
|
|
829
|
+
RPCBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) :CommonBuilder{ctx,name} {}
|
|
830
|
+
//! Callback through which result Value or an error will be delivered.
|
|
831
|
+
//! The functor is stored in the Operation returned by exec().
|
|
832
|
+
RPCBuilder& result(std::function<void(Result&&)>&& cb) { _result = std::move(cb); return *this; }
|
|
833
|
+
|
|
834
|
+
RPCBuilder& arg(const std::string& name, const void *ptr, StoreType type) {
|
|
835
|
+
_set(name, ptr, type, true);
|
|
836
|
+
return *this;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/** Provide argument value.
|
|
840
|
+
*
|
|
841
|
+
* @param name Argument name
|
|
842
|
+
* @param val The value to assign. cf. Value::from()
|
|
843
|
+
*/
|
|
844
|
+
template<typename T>
|
|
845
|
+
RPCBuilder& arg(const std::string& name, const T& val)
|
|
846
|
+
{
|
|
847
|
+
const typename impl::StoreAs<T>::store_t& norm(impl::StoreTransform<T>::in(val));
|
|
848
|
+
_set(name, &norm, impl::StoreAs<T>::code, true);
|
|
849
|
+
return *this;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/** Execute the network operation.
|
|
853
|
+
* The caller must keep returned Operation pointer until completion
|
|
854
|
+
* or the operation will be implicitly canceled.
|
|
855
|
+
*/
|
|
856
|
+
PVXS_API
|
|
857
|
+
std::shared_ptr<Operation> exec();
|
|
858
|
+
|
|
859
|
+
friend struct Context::Pvt;
|
|
860
|
+
friend class Context;
|
|
861
|
+
};
|
|
862
|
+
RPCBuilder Context::rpc(const std::string& name) { return RPCBuilder{pvt, name}; }
|
|
863
|
+
RPCBuilder Context::rpc(const std::string& name, const Value &arg) {
|
|
864
|
+
RPCBuilder ret{pvt, name};
|
|
865
|
+
ret._argument = arg;
|
|
866
|
+
return ret;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
//! Prepare a remote subscription
|
|
870
|
+
//! See Context::monitor()
|
|
871
|
+
class MonitorBuilder : public detail::CommonBuilder<MonitorBuilder, detail::CommonBase> {
|
|
872
|
+
std::function<void(Subscription&, const Value&)> _onInit;
|
|
873
|
+
std::function<void(Subscription&)> _event;
|
|
874
|
+
bool _maskConn = true;
|
|
875
|
+
bool _maskDisconn = false;
|
|
876
|
+
public:
|
|
877
|
+
MonitorBuilder() {}
|
|
878
|
+
MonitorBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& name) :CommonBuilder{ctx,name} {}
|
|
879
|
+
/** Install FIFO not-empty event callback.
|
|
880
|
+
*
|
|
881
|
+
* This functor will be called each time the Subscription event queue becomes
|
|
882
|
+
* not empty. A Subscription becomes empty when Subscription::pop() returns
|
|
883
|
+
* an empty/invalid Value.
|
|
884
|
+
*
|
|
885
|
+
* The functor is stored in the Subscription returned by exec().
|
|
886
|
+
*/
|
|
887
|
+
MonitorBuilder& event(std::function<void(Subscription&)>&& cb) { _event = std::move(cb); return *this; }
|
|
888
|
+
//! Include Connected exceptions in queue (default false).
|
|
889
|
+
MonitorBuilder& maskConnected(bool m = true) { _maskConn = m; return *this; }
|
|
890
|
+
//! Include Disconnected exceptions in queue (default true).
|
|
891
|
+
MonitorBuilder& maskDisconnected(bool m = true) { _maskDisconn = m; return *this; }
|
|
892
|
+
|
|
893
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
894
|
+
// called during operation INIT phase for Get/Put/Monitor when remote type
|
|
895
|
+
// description is available.
|
|
896
|
+
MonitorBuilder& onInit(std::function<void (Subscription&, const Value&)>&& cb) { this->_onInit = std::move(cb); return *this; }
|
|
897
|
+
#endif
|
|
898
|
+
|
|
899
|
+
//! Submit request to subscribe
|
|
900
|
+
PVXS_API
|
|
901
|
+
std::shared_ptr<Subscription> exec();
|
|
902
|
+
|
|
903
|
+
friend struct Context::Pvt;
|
|
904
|
+
friend class Context;
|
|
905
|
+
};
|
|
906
|
+
MonitorBuilder Context::monitor(const std::string& name) { return MonitorBuilder{pvt, name}; }
|
|
907
|
+
|
|
908
|
+
class RequestBuilder : public detail::CommonBuilder<RequestBuilder, detail::CommonBase>
|
|
909
|
+
{
|
|
910
|
+
public:
|
|
911
|
+
RequestBuilder() {}
|
|
912
|
+
//! Return composed pvRequest
|
|
913
|
+
Value build() const {
|
|
914
|
+
return _buildReq();
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
RequestBuilder Context::request() { return RequestBuilder{}; }
|
|
918
|
+
|
|
919
|
+
//! cf. Context::connect()
|
|
920
|
+
//! @since 0.2.0
|
|
921
|
+
class ConnectBuilder
|
|
922
|
+
{
|
|
923
|
+
std::shared_ptr<Context::Pvt> ctx;
|
|
924
|
+
std::string _pvname;
|
|
925
|
+
std::string _server;
|
|
926
|
+
std::function<void()> _onConn;
|
|
927
|
+
std::function<void()> _onDis;
|
|
928
|
+
bool _syncCancel = true;
|
|
929
|
+
public:
|
|
930
|
+
ConnectBuilder() {}
|
|
931
|
+
ConnectBuilder(const std::shared_ptr<Context::Pvt>& ctx, const std::string& pvname)
|
|
932
|
+
:ctx(ctx)
|
|
933
|
+
,_pvname(pvname)
|
|
934
|
+
{}
|
|
935
|
+
|
|
936
|
+
//! Handler to be invoked when channel becomes connected.
|
|
937
|
+
ConnectBuilder& onConnect(std::function<void()>&& cb) { _onConn = std::move(cb); return *this; }
|
|
938
|
+
//! Handler to be invoked when channel becomes disconnected.
|
|
939
|
+
ConnectBuilder& onDisconnect(std::function<void()>&& cb) { _onDis = std::move(cb); return *this; }
|
|
940
|
+
|
|
941
|
+
/** Controls whether Connect::~Connect() synchronizes.
|
|
942
|
+
*
|
|
943
|
+
* When true (the default) explicit or implicit cancel blocks until any
|
|
944
|
+
* in progress callback has completed. This makes safe some use of
|
|
945
|
+
* references in callbacks.
|
|
946
|
+
* @since 0.2.0
|
|
947
|
+
*/
|
|
948
|
+
ConnectBuilder& syncCancel(bool b) { this->_syncCancel = b; return *this; }
|
|
949
|
+
|
|
950
|
+
ConnectBuilder& server(const std::string& s) { this->_server = s; return *this; }
|
|
951
|
+
|
|
952
|
+
//! Submit request to connect
|
|
953
|
+
PVXS_API
|
|
954
|
+
std::shared_ptr<Connect> exec();
|
|
955
|
+
};
|
|
956
|
+
ConnectBuilder Context::connect(const std::string& pvname) { return ConnectBuilder{pvt, pvname}; }
|
|
957
|
+
|
|
958
|
+
//! Change of state event associated with a Context::discover()
|
|
959
|
+
struct Discovered {
|
|
960
|
+
//! What sort of event is this?
|
|
961
|
+
enum event_t : uint8_t {
|
|
962
|
+
Online=1, //!< Beacon from new server GUID
|
|
963
|
+
Timeout=2, //!< Beacon timeout for previous server
|
|
964
|
+
} event;
|
|
965
|
+
uint8_t peerVersion; //!< Last reported peer PVA protocol version.
|
|
966
|
+
std::string peer; //!< source of Beacon
|
|
967
|
+
std::string proto; //!< Advertised protocol. eg. "tcp"
|
|
968
|
+
std::string server;//!< Server protocol endpoint.
|
|
969
|
+
ServerGUID guid; //!< Server provided ID
|
|
970
|
+
epicsTime time; //!< Local system time of event
|
|
971
|
+
};
|
|
972
|
+
PVXS_API
|
|
973
|
+
std::ostream& operator<<(std::ostream& strm, const Discovered& evt);
|
|
974
|
+
//! Prepare a Context::discover() operation
|
|
975
|
+
//! @since 0.3.0
|
|
976
|
+
class DiscoverBuilder
|
|
977
|
+
{
|
|
978
|
+
std::shared_ptr<Context::Pvt> ctx;
|
|
979
|
+
std::function<void(const Discovered &)> _fn;
|
|
980
|
+
bool _syncCancel = true;
|
|
981
|
+
bool _ping = false;
|
|
982
|
+
public:
|
|
983
|
+
DiscoverBuilder(const std::shared_ptr<Context::Pvt>& ctx, std::function<void(const Discovered &)>&& fn)
|
|
984
|
+
:ctx(ctx)
|
|
985
|
+
,_fn(fn)
|
|
986
|
+
{}
|
|
987
|
+
|
|
988
|
+
/** Controls whether client will actively seek to immediately discover all servers.
|
|
989
|
+
*
|
|
990
|
+
* If false, then client will only wait for servers to periodically announce themselves.
|
|
991
|
+
*/
|
|
992
|
+
DiscoverBuilder& pingAll(bool b) { this->_ping = b; return *this; }
|
|
993
|
+
|
|
994
|
+
/** Controls whether Operation::cancel() synchronizes.
|
|
995
|
+
*
|
|
996
|
+
* When true (the default) explicit or implicit cancel blocks until any
|
|
997
|
+
* in progress callback has completed. This makes safe some use of
|
|
998
|
+
* references in callbacks.
|
|
999
|
+
*/
|
|
1000
|
+
DiscoverBuilder& syncCancel(bool b) { this->_syncCancel = b; return *this; }
|
|
1001
|
+
|
|
1002
|
+
//! Execute. The returned Operation will never complete.
|
|
1003
|
+
PVXS_API
|
|
1004
|
+
std::shared_ptr<Operation> exec();
|
|
1005
|
+
};
|
|
1006
|
+
DiscoverBuilder Context::discover(std::function<void (const Discovered &)> && fn) { return DiscoverBuilder(pvt, std::move(fn)); }
|
|
1007
|
+
|
|
1008
|
+
struct PVXS_API Config {
|
|
1009
|
+
/** List of unicast, multicast, and broadcast addresses to which search requests will be sent.
|
|
1010
|
+
*
|
|
1011
|
+
* Entries may take the forms:
|
|
1012
|
+
* - ``<ipaddr>[:<port#>]``
|
|
1013
|
+
* - ``<ipmultiaddr>[:<port>][,<ttl>][@<ifaceaddr>]``
|
|
1014
|
+
*/
|
|
1015
|
+
std::vector<std::string> addressList;
|
|
1016
|
+
|
|
1017
|
+
//! List of local interface addresses on which beacons may be received.
|
|
1018
|
+
//! Also constrains autoAddrList to only consider broadcast addresses of listed interfaces.
|
|
1019
|
+
//! Empty implies wildcard 0.0.0.0
|
|
1020
|
+
std::vector<std::string> interfaces;
|
|
1021
|
+
|
|
1022
|
+
//! List of TCP name servers.
|
|
1023
|
+
//! Client context will maintain connections, and send search requests, to these servers.
|
|
1024
|
+
//! @since 0.2.0
|
|
1025
|
+
std::vector<std::string> nameServers;
|
|
1026
|
+
|
|
1027
|
+
//! UDP port to bind. Default is 5076. May be zero, cf. Server::config() to find allocated port.
|
|
1028
|
+
unsigned short udp_port = 5076;
|
|
1029
|
+
//! Default TCP port for name servers
|
|
1030
|
+
//! @since 0.2.0
|
|
1031
|
+
unsigned short tcp_port = 5075;
|
|
1032
|
+
|
|
1033
|
+
//! Whether to extend the addressList with local interface broadcast addresses. (recommended)
|
|
1034
|
+
bool autoAddrList = true;
|
|
1035
|
+
|
|
1036
|
+
//! Inactivity timeout interval for TCP connections. (seconds)
|
|
1037
|
+
//! @since 0.2.0
|
|
1038
|
+
double tcpTimeout = 40.0;
|
|
1039
|
+
|
|
1040
|
+
private:
|
|
1041
|
+
bool BE = EPICS_BYTE_ORDER==EPICS_ENDIAN_BIG;
|
|
1042
|
+
bool UDP = true;
|
|
1043
|
+
public:
|
|
1044
|
+
|
|
1045
|
+
// compat
|
|
1046
|
+
static inline Config from_env() { return Config{}.applyEnv(); }
|
|
1047
|
+
|
|
1048
|
+
//! Default configuration using process environment
|
|
1049
|
+
static inline Config fromEnv() { return Config{}.applyEnv(); }
|
|
1050
|
+
|
|
1051
|
+
//! update using defined EPICS_PVA* environment variables
|
|
1052
|
+
Config& applyEnv();
|
|
1053
|
+
|
|
1054
|
+
typedef std::map<std::string, std::string> defs_t;
|
|
1055
|
+
//! update with definitions as with EPICS_PVA* environment variables
|
|
1056
|
+
//! Process environment is not changed.
|
|
1057
|
+
Config& applyDefs(const defs_t& defs);
|
|
1058
|
+
|
|
1059
|
+
//! extract definitions with environment variable names as keys.
|
|
1060
|
+
//! Process environment is not changed.
|
|
1061
|
+
void updateDefs(defs_t& defs) const;
|
|
1062
|
+
|
|
1063
|
+
/** Apply rules to translate current requested configuration
|
|
1064
|
+
* into one which can actually be loaded based on current host network configuration.
|
|
1065
|
+
*
|
|
1066
|
+
* Explicit use of expand() is optional as the Context ctor expands any Config given.
|
|
1067
|
+
* expand() is provided as a aid to help understand how Context::effective() is arrived at.
|
|
1068
|
+
*
|
|
1069
|
+
* @post autoAddrList==false
|
|
1070
|
+
*/
|
|
1071
|
+
void expand();
|
|
1072
|
+
|
|
1073
|
+
//! Create a new client Context using the current configuration.
|
|
1074
|
+
inline
|
|
1075
|
+
Context build() const {
|
|
1076
|
+
return Context(*this);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
#ifdef PVXS_EXPERT_API_ENABLED
|
|
1080
|
+
// for protocol compatibility testing
|
|
1081
|
+
inline Config& overrideSendBE(bool be) { BE = be; return *this; }
|
|
1082
|
+
inline bool sendBE() const { return BE; }
|
|
1083
|
+
inline Config& overrideShareUDP(bool share) { UDP = share; return *this; }
|
|
1084
|
+
inline bool shareUDP() const { return UDP; }
|
|
1085
|
+
#endif
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
PVXS_API
|
|
1089
|
+
std::ostream& operator<<(std::ostream& strm, const Config& conf);
|
|
1090
|
+
|
|
1091
|
+
} // namespace client
|
|
1092
|
+
} // namespace pvxs
|
|
1093
|
+
|
|
1094
|
+
#endif // PVXS_CLIENT_H
|