VLink  2.0.0
A high-performance communication middleware
client_impl.h
浏览该文件的文档.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 /**
25  * @file client_impl.h
26  * @brief Transport-neutral backbone shared by every method-model client implementation.
27  *
28  * @details
29  * This is an internal implementation header used by the public @c Client template;
30  * application code should depend on @c client.h instead. @c ClientImpl extends
31  * @c NodeImpl with the connectivity bookkeeping that lets a client wait for its
32  * counterpart server and issue blocking calls. Concrete transports such as
33  * @c DdsClientImpl or @c ShmClientImpl derive from this class and implement the
34  * pure virtual @c is_connected() and @c call() entry points.
35  *
36  * @par ImplType
37  * The constructor stamps @c impl_type with @c kClient. The base @c NodeImpl
38  * surfaces this value to discovery, bag, and proxy layers so they can route
39  * status callbacks correctly.
40  *
41  * @par Role table
42  * | Concern | Owner in this hierarchy |
43  * | --------------------- | ------------------------------------------- |
44  * | Wire send / receive | Transport subclass (e.g. @c DdsClientImpl) |
45  * | Connection detection | @c ClientImpl (helper condition variable) |
46  * | Blocking call timing | @c ClientImpl + @c AckManager in subclass |
47  * | Connect callback fan | @c ClientImpl::detect_connected() |
48  *
49  * @par Internal API contract
50  * | Method | Provided by | Notes |
51  * | ---------------------------- | ------------------- | ------------------------------------------------ |
52  * | @c is_connected() const | Subclass override | Queries the live transport handle. |
53  * | @c call(req, cb, timeout) | Subclass override | Performs the blocking round-trip. |
54  * | @c update_connected() | This class | Invoked from discovery threads on state change. |
55  * | @c detect_connected(cb) | This class | Stores the user callback and primes it. |
56  * | @c wait_for_connected(t) | This class | Sleeps on the helper condition variable. |
57  * | @c interrupt() | This class | Wakes waiters when the node is being shut down. |
58  *
59  * @par Internal Notes
60  * @c is_resp_type captures whether the public @c Client template expects a
61  * response payload; backends that implement fire-and-forget RPC flavours may
62  * read it to skip the response wait.
63  */
64 
65 #pragma once
66 
67 #include <chrono>
68 #include <memory>
69 
70 #include "./node_impl.h"
71 
72 namespace vlink {
73 
74 /**
75  * @class ClientImpl
76  * @brief Connection-aware base class for method-model client implementations.
77  *
78  * @details
79  * Owns the helper condition variable used by @c wait_for_connected() and the
80  * cached @c ConnectCallback delivered via @c detect_connected(). Backends are
81  * expected to push presence updates by calling @c update_connected() whenever
82  * the discovery layer reports a server appear / disappear event.
83  */
85  public:
86  /**
87  * @brief Releases the helper state held by the base class.
88  */
89  ~ClientImpl() override;
90 
91  /**
92  * @brief Wakes blocked waiters and forwards the interrupt to @c NodeImpl.
93  *
94  * @details
95  * Marks the node interrupted, notifies the helper condition variable so any
96  * @c wait_for_connected() call returns @c false promptly, and delegates the
97  * rest of the shutdown handshake to @c NodeImpl::interrupt(). Transport
98  * subclasses commonly override this to also cancel pending @c AckManager
99  * requests.
100  */
101  void interrupt() override;
102 
103  /**
104  * @brief Registers @p callback to fire whenever the server presence changes.
105  *
106  * @details
107  * If the connection is already established at registration time, @p callback
108  * is invoked with @c true before this method returns. Subsequent transitions
109  * are forwarded by @c update_connected().
110  *
111  * @param callback Callable @c void(bool) to be notified on connect / disconnect.
112  */
113  virtual void detect_connected(ConnectCallback&& callback);
114 
115  /**
116  * @brief Blocks until a server becomes reachable or @p timeout elapses.
117  *
118  * @details
119  * Returns immediately when @c is_connected() already reports @c true.
120  * Otherwise sleeps on the helper condition variable that is poked by
121  * @c update_connected() and by @c interrupt(). A negative @p timeout, such
122  * as @c Timeout::kInfinite, disables the deadline.
123  *
124  * @param timeout Maximum sleep duration.
125  * @return @c true when the server appeared in time; @c false on timeout or interruption.
126  */
127  virtual bool wait_for_connected(std::chrono::milliseconds timeout);
128 
129  /**
130  * @brief Reports whether the transport currently holds a path to a server.
131  *
132  * @details
133  * Pure virtual; subclasses query their underlying discovery handle. Called
134  * by both @c wait_for_connected() and @c update_connected() to compute state
135  * transitions.
136  *
137  * @return @c true when a server is reachable; @c false otherwise.
138  */
139  [[nodiscard]] virtual bool is_connected() const = 0;
140 
141  /**
142  * @brief Performs a synchronous round-trip with the remote server.
143  *
144  * @details
145  * Pure virtual; subclasses send @p req_data, wait for the matching response
146  * (typically through @c AckManager) and invoke @p callback with the received
147  * bytes once a frame arrives.
148  *
149  * @param req_data Serialised request payload.
150  * @param callback Callable @c void(const Bytes&) receiving the response bytes.
151  * @param timeout Maximum wait duration; negative for unlimited.
152  * @return @c true on success; @c false on timeout, interruption or transport error.
153  */
154  virtual bool call(const Bytes& req_data, MsgCallback&& callback, std::chrono::milliseconds timeout) = 0;
155 
156  /**
157  * @brief Notifies the base class that the underlying connection state may have changed.
158  *
159  * @details
160  * Compares @c is_connected() against the helper cache; when the value flips
161  * the condition variable is signalled and any registered @c ConnectCallback
162  * is delivered. Intended to run on the transport's discovery / listener
163  * thread, not on the application thread.
164  */
166 
167  bool is_resp_type{false}; ///< @c true when the public @c Client expects a response payload.
168 
169  protected:
170  /**
171  * @brief Stamps the node as @c kClient and prepares the helper state.
172  */
174 
175  private:
176  std::unique_ptr<struct ClientImplHelper> helper_;
177 
179 };
180 
181 } // namespace vlink
#define VLINK_EXPORT
Definition: macros.h:81
#define VLINK_DISALLOW_COPY_AND_ASSIGN(classname)
Deletes the copy constructor and copy-assignment operator of classname.
Definition: macros.h:174
Foundational base classes shared by every transport-backed VLink node.