Line data Source code
1 : /**
2 : * @file application.hpp
3 : * @brief FIX 应用层接口定义
4 : *
5 : * 定义业务逻辑与会话层的分离接口,允许用户实现自定义的
6 : * 业务消息处理逻辑,而无需修改底层会话管理代码。
7 : */
8 :
9 : #pragma once
10 :
11 : #include <string>
12 : #include <functional>
13 : #include "fix/fix_codec.hpp"
14 :
15 : namespace fix40 {
16 :
17 : // 前置声明
18 : class Session;
19 : class IStore;
20 :
21 : /**
22 : * @struct SessionID
23 : * @brief FIX 会话标识符
24 : *
25 : * 唯一标识一个 FIX 会话,由发送方和接收方的 CompID 组成。
26 : * 用于在多会话环境中区分不同的连接。
27 : */
28 : struct SessionID {
29 : std::string senderCompID; ///< 发送方标识符
30 : std::string targetCompID; ///< 接收方标识符
31 :
32 : /**
33 : * @brief 默认构造函数
34 : */
35 2754 : SessionID() = default;
36 :
37 : /**
38 : * @brief 构造会话标识符
39 : * @param sender 发送方 CompID
40 : * @param target 接收方 CompID
41 : */
42 83 : SessionID(const std::string& sender, const std::string& target)
43 83 : : senderCompID(sender), targetCompID(target) {}
44 :
45 : /**
46 : * @brief 转换为字符串表示
47 : * @return std::string 格式为 "sender->target"
48 : */
49 77 : std::string to_string() const {
50 154 : return senderCompID + "->" + targetCompID;
51 : }
52 :
53 : /**
54 : * @brief 相等比较
55 : */
56 28 : bool operator==(const SessionID& other) const {
57 56 : return senderCompID == other.senderCompID &&
58 56 : targetCompID == other.targetCompID;
59 : }
60 :
61 : /**
62 : * @brief 不等比较
63 : */
64 1 : bool operator!=(const SessionID& other) const {
65 1 : return !(*this == other);
66 : }
67 : };
68 :
69 : /**
70 : * @class Application
71 : * @brief FIX 应用层抽象接口
72 : *
73 : * 该接口将业务逻辑与 FIX 会话层分离。Session 负责处理会话层消息
74 : * (Logon、Logout、Heartbeat、TestRequest),而业务消息(如订单、
75 : * 执行报告等)则委托给 Application 实现类处理。
76 : *
77 : * @par 回调分类
78 : * - 业务消息回调:fromApp / toApp
79 : * - 管理消息回调:fromAdmin / toAdmin
80 : * - 生命周期回调:onLogon / onLogout
81 : *
82 : * @par 线程安全
83 : * @warning Application 的回调方法可能被多个工作线程并发调用!
84 : *
85 : * 由于 FixServer 使用线程池,不同客户端连接绑定到不同工作线程,
86 : * 当多个客户端同时发送消息时,fromApp() 会被并发调用。
87 : *
88 : * 推荐的线程安全实现方式:
89 : * 1. fromApp() 只做轻量操作:将消息封装后 push 到无锁队列
90 : * 2. 由独立的业务处理线程(如撮合引擎)从队列消费并处理
91 : * 3. 避免在 fromApp() 中执行耗时操作或持有锁
92 : *
93 : * @par 异常处理
94 : * Session 会捕获 Application 回调中抛出的异常,记录日志后继续运行。
95 : * 但强烈建议在 Application 实现中自行处理异常,避免依赖外部捕获。
96 : *
97 : * @par 生命周期
98 : * Application 实例的生命周期应由 Server/Client 管理,
99 : * 且必须比关联的 Session 更长。Session 仅持有裸指针。
100 : *
101 : * @par 使用示例
102 : * @code
103 : * class MyTradingApp : public Application {
104 : * public:
105 : * void onLogon(const SessionID& sessionID) override {
106 : * LOG() << "Session logged on: " << sessionID.to_string();
107 : * }
108 : *
109 : * void fromApp(const FixMessage& msg, const SessionID& sessionID) override {
110 : * // 推荐:只做轻量操作,push 到队列
111 : * order_queue_.enqueue({msg, sessionID});
112 : * }
113 : * };
114 : * @endcode
115 : */
116 : class Application {
117 : public:
118 : /**
119 : * @brief 虚析构函数
120 : */
121 34 : virtual ~Application() = default;
122 :
123 : // =========================================================================
124 : // 生命周期回调
125 : // =========================================================================
126 :
127 : /**
128 : * @brief 会话登录成功回调
129 : * @param sessionID 已建立的会话标识符
130 : *
131 : * 当 FIX 会话成功建立(收到 Logon 确认)后调用。
132 : * 可用于初始化交易状态、订阅行情等。
133 : *
134 : * @note 可能被多个工作线程并发调用
135 : */
136 : virtual void onLogon(const SessionID& sessionID) = 0;
137 :
138 : /**
139 : * @brief 会话登出回调
140 : * @param sessionID 即将断开的会话标识符
141 : *
142 : * 当 FIX 会话即将断开(收到 Logout 或连接关闭)时调用。
143 : * 可用于清理交易状态、取消未完成订单等。
144 : *
145 : * @note 可能被多个工作线程并发调用
146 : */
147 : virtual void onLogout(const SessionID& sessionID) = 0;
148 :
149 : // =========================================================================
150 : // 业务消息回调
151 : // =========================================================================
152 :
153 : /**
154 : * @brief 收到业务消息回调
155 : * @param msg 收到的 FIX 业务消息
156 : * @param sessionID 消息来源的会话标识符
157 : *
158 : * 当收到非会话层消息(MsgType 不是 A/0/1/5)时调用。
159 : * 典型的业务消息包括:
160 : * - D: NewOrderSingle(新订单)
161 : * - F: OrderCancelRequest(撤单请求)
162 : * - 8: ExecutionReport(执行报告)
163 : *
164 : * @warning 可能被多个工作线程并发调用!
165 : * 推荐实现:只做轻量操作,将消息 push 到无锁队列
166 : */
167 : virtual void fromApp(const FixMessage& msg, const SessionID& sessionID) = 0;
168 :
169 : /**
170 : * @brief 发送业务消息前回调
171 : * @param msg 即将发送的 FIX 业务消息(可修改)
172 : * @param sessionID 发送消息的会话标识符
173 : *
174 : * 在业务消息发送前调用,可用于:
175 : * - 记录审计日志
176 : * - 添加/修改字段
177 : * - 消息验证
178 : *
179 : * 默认实现为空,子类可选择性重写。
180 : *
181 : * @note 可能被多个工作线程并发调用
182 : */
183 0 : virtual void toApp(FixMessage& msg, const SessionID& sessionID) {
184 : (void)msg;
185 : (void)sessionID;
186 0 : }
187 :
188 : // =========================================================================
189 : // 管理消息回调(可选)
190 : // =========================================================================
191 :
192 : /**
193 : * @brief 收到管理消息回调
194 : * @param msg 收到的 FIX 管理消息
195 : * @param sessionID 消息来源的会话标识符
196 : *
197 : * 当收到会话层消息(Logon/Logout/Heartbeat/TestRequest)时调用。
198 : * 默认实现为空,子类可选择性重写用于日志记录等。
199 : *
200 : * @note 管理消息由 Session 自动处理,此回调仅用于通知
201 : */
202 0 : virtual void fromAdmin(const FixMessage& msg, const SessionID& sessionID) {
203 : (void)msg;
204 : (void)sessionID;
205 0 : }
206 :
207 : /**
208 : * @brief 发送管理消息前回调
209 : * @param msg 即将发送的 FIX 管理消息(可修改)
210 : * @param sessionID 发送消息的会话标识符
211 : *
212 : * 在发送 Logon/Logout/Heartbeat/TestRequest 前调用。
213 : * 默认实现为空,子类可选择性重写用于日志记录等。
214 : */
215 0 : virtual void toAdmin(FixMessage& msg, const SessionID& sessionID) {
216 : (void)msg;
217 : (void)sessionID;
218 0 : }
219 :
220 : // =========================================================================
221 : // 可选:持久化能力探测
222 : // =========================================================================
223 :
224 : /**
225 : * @brief 获取持久化存储接口(可选)
226 : *
227 : * 用于让网络层/会话层组件以“依赖倒置”的方式获取持久化能力:
228 : * - 当返回非空时,Session 可以将消息与会话序列号写入 store,用于断线恢复与 ResendRequest。
229 : * - 默认实现返回 nullptr,表示当前 Application 不提供持久化能力。
230 : *
231 : * @return IStore* 存储接口指针,可能为 nullptr
232 : */
233 0 : virtual IStore* getStore() const { return nullptr; }
234 : };
235 :
236 : } // namespace fix40
|