VLink  2.0.0
A high-performance communication middleware
publisher_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 publisher_impl.h
26  * @brief Transport-neutral base class for every event-model publisher implementation.
27  *
28  * @details
29  * This is an internal implementation header used by the public @c Publisher
30  * template; applications should depend on @c publisher.h. @c PublisherImpl
31  * extends @c NodeImpl with the publish-side bookkeeping that lets a transport
32  * detect subscriber presence and dispatch payloads either as serialised bytes
33  * (the common case) or as zero-copy in-process @c IntraData (only the intra
34  * backend overrides that path).
35  *
36  * @par ImplType
37  * The constructor stamps @c impl_type with @c kPublisher, allowing discovery
38  * and recording layers to label the produced frames correctly.
39  *
40  * @par Lifecycle
41  * - Construction stamps the impl type and prepares the helper state.
42  * - The public @c Publisher template calls @c init() once the conf is wired.
43  * - @c detect_subscribers() may be installed at any time; if a subscriber is
44  * already known it fires once immediately.
45  * - @c write() (overload chosen by the user) produces frames until @c interrupt()
46  * is called, after which @c reset_interrupted() can be used to resume.
47  *
48  * @par Role table
49  * | Capability | Owner |
50  * | --------------------------- | ----------------------------------------------------- |
51  * | Serialised write path | Subclass override of @c write(const Bytes&) |
52  * | Zero-copy intra write | @c IntraPublisherImpl override of @c write(IntraData) |
53  * | Subscriber presence query | Subclass override of @c has_subscribers() |
54  * | Presence change publishing | @c update_subscribers() in this class |
55  * | Wait-for-subscriber gate | @c wait_for_subscribers() / helper CV |
56  *
57  * @par Internal API contract
58  * | Method | Default | Subclass duty |
59  * | ------------------------------------- | ----------------------- | -------------------------- |
60  * | @c has_subscribers() const | Pure virtual | Query transport |
61  * | @c write(const Bytes&) | Pure virtual | Publish wire frame |
62  * | @c write(const IntraData&) | Warns, returns @c false | Only intra:// overrides |
63  * | @c detect_subscribers(cb) | Stores callback | Usually inherited |
64  * | @c wait_for_subscribers(timeout) | Helper CV wait | Usually inherited |
65  * | @c update_subscribers() | Implemented here | Call from transport thread |
66  */
67 
68 #pragma once
69 
70 #include <chrono>
71 #include <memory>
72 
73 #include "./node_impl.h"
74 
75 namespace vlink {
76 
77 /**
78  * @class PublisherImpl
79  * @brief Publish-side base shared by every transport-specific publisher.
80  *
81  * @details
82  * Owns the helper condition variable and connect-callback storage that back
83  * @c Publisher<T>::wait_for_subscribers() and
84  * @c Publisher<T>::detect_subscribers(). Transports invoke
85  * @c update_subscribers() from their discovery threads whenever the subscriber
86  * count flips between zero and non-zero.
87  */
89  public:
90  /**
91  * @brief Releases the helper state.
92  */
93  ~PublisherImpl() override;
94 
95  /**
96  * @brief Wakes waiters and forwards the interrupt to @c NodeImpl.
97  *
98  * @details
99  * Marks the node interrupted and notifies the helper condition variable so
100  * pending @c wait_for_subscribers() calls return @c false promptly.
101  */
102  void interrupt() override;
103 
104  /**
105  * @brief Registers @p callback to fire when subscriber presence changes.
106  *
107  * @details
108  * The callback is invoked with @c true when the first subscriber appears and
109  * with @c false after the last one drops. When subscribers are already
110  * known at registration time the callback is primed with @c true before
111  * this function returns.
112  *
113  * @param callback Callable @c void(bool) describing the new presence.
114  */
115  virtual void detect_subscribers(ConnectCallback&& callback);
116 
117  /**
118  * @brief Blocks until at least one subscriber is reachable or @p timeout elapses.
119  *
120  * @details
121  * Returns immediately when @c has_subscribers() already reports @c true.
122  * Negative timeouts (e.g. @c Timeout::kInfinite) wait indefinitely.
123  *
124  * @param timeout Wait budget; negative disables the deadline.
125  * @return @c true when a subscriber arrived in time; @c false otherwise.
126  */
127  virtual bool wait_for_subscribers(std::chrono::milliseconds timeout);
128 
129  /**
130  * @brief Reports whether at least one subscriber is currently connected.
131  *
132  * @details
133  * Pure virtual; subclasses query their discovery handle. Used by both
134  * @c wait_for_subscribers() and @c update_subscribers() to detect state
135  * transitions.
136  *
137  * @return @c true when a subscriber is reachable.
138  */
139  [[nodiscard]] virtual bool has_subscribers() const = 0;
140 
141  /**
142  * @brief Publishes a serialised payload to every connected subscriber.
143  *
144  * @details
145  * Pure virtual. @p msg_data is produced by @c Serializer::serialize() at
146  * the public layer.
147  *
148  * @param msg_data Serialised payload bytes.
149  * @return @c true when the frame was successfully delivered or queued.
150  */
151  virtual bool write(const Bytes& msg_data) = 0;
152 
153  /**
154  * @brief Publishes an in-process payload without serialisation.
155  *
156  * @details
157  * Default implementation warns and returns @c false; only
158  * @c IntraPublisherImpl forwards the shared payload directly to co-located
159  * subscribers.
160  *
161  * @param intra_data Shared payload pointer.
162  * @return @c true when the message was dispatched; @c false otherwise.
163  */
164  virtual bool write(const IntraData& intra_data);
165 
166  /**
167  * @brief Notifies the base class that subscriber presence may have changed.
168  *
169  * @details
170  * Compares @c has_subscribers() against the helper cache; on a transition
171  * the condition variable is signalled and the stored @c ConnectCallback is
172  * invoked. Intended for use from transport discovery threads.
173  */
175 
176  protected:
177  /**
178  * @brief Stamps the node as @c kPublisher and primes the helper state.
179  */
181 
182  private:
183  std::unique_ptr<struct PublisherImplHelper> helper_;
184 
186 };
187 
188 } // 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.