internal.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include <string_view>
  7. #include <variant>
  8. #include "../../../middleware/bap/family_unsubscription.h"
  9. #include "../../../middleware/bap/frame.h"
  10. #include "../../../middleware/queuez/subscription.h"
  11. #include "../../web_service/web_service_runtime.h"
  12. #include "../internal.h"
  13. #include "activity_message/definition.h"
  14. #include "queuez/definition.h"
  15. #include "transactions/definition.h"
  16. namespace sunrise::server::bap::encrypted {
  17. /** Response-body codecs picked by the authenticated request service. */
  18. enum class BodyCodec : std::uint8_t {
  19. empty,
  20. accountTranslationResponse,
  21. activityHostManagerResponse,
  22. activityMessageRequest,
  23. activityHostResponse,
  24. clientConfigResponse,
  25. familySubscription,
  26. familyUnsubscription,
  27. matchmakingResponse,
  28. steamCertificate,
  29. userMessageResponse,
  30. webService,
  31. };
  32. /** Equipment mutation and the exact QueueZ after-image promised by its response. */
  33. struct EquipmentSwapTransaction {
  34. state::PendingEquipmentSwap pending{};
  35. queuez::EquipmentSwap update{};
  36. };
  37. /** Socket mutation and the exact QueueZ after-image promised by its response. */
  38. struct SocketPlugTransaction {
  39. state::PendingSocketPlug pending{};
  40. queuez::SocketPlug update{};
  41. };
  42. /** Subclass ability selection and the exact QueueZ after-image promised by its response. */
  43. struct SubclassSelectionTransaction {
  44. state::PendingSubclassSelection pending{};
  45. queuez::SubclassSelection update{};
  46. };
  47. /** Item-state mutation and the exact QueueZ character after-image promised by its response. */
  48. struct ItemStateTransaction {
  49. state::PendingItemState pending{};
  50. queuez::EquipmentSwap update{};
  51. };
  52. /** Current-activity mutation and the exact QueueZ character after-image sent with its reply. */
  53. struct CurrentActivityTransaction {
  54. state::PendingCurrentActivity pending{};
  55. queuez::EquipmentSwap update{};
  56. };
  57. /** Character acquisition and its exact QueueZ after-image. */
  58. struct ItemAcquisitionTransaction {
  59. state::PendingItemAcquisition pending{};
  60. queuez::ItemAcquisition update{};
  61. };
  62. /** Profile acquisition and its exact account/resident QueueZ after-image. */
  63. struct ProfileItemAcquisitionTransaction {
  64. state::PendingProfileItemAcquisition pending{};
  65. queuez::ProfileItemAcquisition update{};
  66. };
  67. /** Dismantle mutation and its exact QueueZ after-image. */
  68. struct ItemDismantleTransaction {
  69. state::PendingItemDismantle pending{};
  70. queuez::ItemDismantle update{};
  71. };
  72. /** Optional side effect produced while decoding one authenticated service body. */
  73. struct ServiceOutcome {
  74. bool hasSubscription{};
  75. middleware::queuez::Subscription subscription{};
  76. bool hasUnsubscription{};
  77. middleware::bap::family_unsubscription::Request unsubscription{};
  78. bool hasChangeCharacter{};
  79. queuez::ChangeCharacter changeCharacter{};
  80. bool hasSelectCharacter{};
  81. queuez::SelectCharacter selectCharacter{};
  82. /** One service owns at most one independently versioned transaction. */
  83. using Transaction = std::variant<std::monostate,
  84. state::activity::PendingAllocation,
  85. activity_message::ActivityPlan,
  86. state::matchmaking::PendingMutation,
  87. EquipmentSwapTransaction,
  88. SubclassSelectionTransaction,
  89. SocketPlugTransaction,
  90. ItemStateTransaction,
  91. CurrentActivityTransaction,
  92. ItemAcquisitionTransaction,
  93. ProfileItemAcquisitionTransaction,
  94. ItemDismantleTransaction,
  95. state::PendingSettingsUpdate>;
  96. Transaction transaction{};
  97. };
  98. /** @return The service transaction of the requested type, or null for another route. */
  99. template <typename Transaction>
  100. [[nodiscard]] Transaction* transaction_if(ServiceOutcome& outcome) noexcept {
  101. return std::get_if<Transaction>(&outcome.transaction);
  102. }
  103. /** @return The service transaction of the requested type, or null for another route. */
  104. template <typename Transaction>
  105. [[nodiscard]] const Transaction* transaction_if(const ServiceOutcome& outcome) noexcept {
  106. return std::get_if<Transaction>(&outcome.transaction);
  107. }
  108. /** Outbound delivery behavior picked for one authenticated request service. */
  109. enum class ResponseMode : std::uint8_t {
  110. none,
  111. reply,
  112. /** Processes a request body and may emit notifications without a status response. */
  113. uncorrelatedPush,
  114. };
  115. /** Static response metadata for one supported encrypted request service. */
  116. struct ServiceRoute {
  117. ResponseMode responseMode{};
  118. middleware::bap::ResponseService response{};
  119. BodyCodec bodyCodec{};
  120. std::string_view successEvent{};
  121. };
  122. /** Owns encrypted service-to-response routing. */
  123. namespace routing {
  124. [[nodiscard]] bool resolve(std::uint16_t request, ServiceRoute& route) noexcept;
  125. } // namespace routing
  126. /** Owns failure reporting for encrypted requests. */
  127. namespace diagnostics {
  128. void report_failure(std::uint16_t service, std::string_view stage) noexcept;
  129. /** Reports one refusal that names which branch refused. */
  130. void report_failure(std::uint16_t service,
  131. std::string_view stage,
  132. std::string_view reason) noexcept;
  133. } // namespace diagnostics
  134. /** Owns correlated reply construction for one authenticated request. */
  135. namespace reply {
  136. /**
  137. * Encodes, seals, and frames one correlated status-200 reply.
  138. * @param scratch Lock-owned transform buffers.
  139. * @param route Service route data naming the response service.
  140. * @param taskId Request correlation id to echo.
  141. * @param key Active AES-GCM session key.
  142. * @param nonce Send-direction nonce for this reply.
  143. * @param body Encoded response body, which is empty when its codec refused.
  144. * @param framedSize Receives the complete outer-frame size, or zero on failure.
  145. * @return True when the payload, seal, and outer frame all fit.
  146. */
  147. [[nodiscard]] bool encode(Scratch& scratch,
  148. const ServiceRoute& route,
  149. std::uint32_t taskId,
  150. std::span<const std::byte, state::kAesKeySize> key,
  151. std::span<const std::byte, state::kBapNonceSize> nonce,
  152. std::span<const std::byte> body,
  153. std::size_t& framedSize) noexcept;
  154. } // namespace reply
  155. /** Owns request-body processing for an encrypted service route. */
  156. namespace body {
  157. /**
  158. * Processes a request body and encodes a correlated body when the route needs one.
  159. * @param route Service route data found earlier.
  160. * @param queuezState Queuez versions and residents set up by this BAP peer.
  161. * @param activity Exact ActivityClient generation owned by this BAP session.
  162. * @param rosterDecode Last complete msg-5 identity map delivered on this connection.
  163. * @param matchmakingContext State-owned logical context for this BAP session.
  164. * @param requestBody Borrowed decrypted request body.
  165. * @param output Caller-owned response-body storage.
  166. * @param written Receives encoded body bytes.
  167. * @param outcome Receives one validated transport action or deferred State transaction.
  168. * @return True when the chosen body codec succeeds.
  169. */
  170. [[nodiscard]] bool process(const ServiceRoute& route,
  171. const queuez::SessionState& queuezState,
  172. const ActivityClientBinding& activity,
  173. const RosterDecodeMap& rosterDecode,
  174. state::matchmaking::ContextHandle matchmakingContext,
  175. std::span<const std::byte> requestBody,
  176. std::span<std::byte> output,
  177. std::size_t& written,
  178. ServiceOutcome& outcome) noexcept;
  179. } // namespace body
  180. /** Owns server-initiated encrypted frames appended after correlated replies. */
  181. namespace push {
  182. /**
  183. * Canonicalizes the account ahead of the family-specific snapshot dispatch.
  184. * Families 0, 3 and 4 each take their own account snapshot, and the roster is built before the
  185. * account companion, so a migration performed inside one family's builder would leave the others
  186. * describing a different account: a Family-3 character record naming an emote instance the
  187. * Family-4 manifest has already replaced, with no correction published afterwards. Running it
  188. * ahead of every builder is what keeps the three images talking about one account.
  189. * Idempotent, and one relaxed load once the answer can no longer change, so calling it from every
  190. * entry point that reaches a builder costs nothing.
  191. */
  192. void ensure_account_canonical() noexcept;
  193. /**
  194. * Appends the queuez snapshots one subscription needs, including the Family-4 companion.
  195. * A snapshot that cannot be built is reported and skipped. The subscribe is answered either way,
  196. * because a request left without a response kills the link on the Client's missing-recipient path.
  197. * @param scratch Lock-owned transform buffers.
  198. * @param before Queuez state visible to the current BAP peer.
  199. * @param subscription Family the Client picked.
  200. * @param key Active AES-GCM session key.
  201. * @param nonce Push-direction nonce, advanced once per appended frame.
  202. * @param response Caller-owned output containing the existing response prefix.
  203. * @param written Existing byte count, updated after each complete push is appended.
  204. * @param after Receives the queuez state published after caller output is copied.
  205. * @param armsRepush Receives whether the Family-4 companion needs its delayed second copy.
  206. * @param armsBannerRepush Receives whether a family-zero body needs its delayed second copy.
  207. */
  208. void append_queuez_notification(Scratch& scratch,
  209. const queuez::SessionState& before,
  210. const middleware::queuez::Subscription& subscription,
  211. std::span<const std::byte, state::kAesKeySize> key,
  212. std::array<std::byte, state::kBapNonceSize>& nonce,
  213. std::span<std::byte> response,
  214. std::size_t& written,
  215. queuez::SessionState& after,
  216. bool& armsRepush,
  217. bool& armsBannerRepush) noexcept;
  218. /** Appends one next-version full Family-4 snapshot used to resynchronize another peer. */
  219. [[nodiscard]] bool
  220. append_account_resync_notification(Scratch& scratch,
  221. const queuez::SessionState& before,
  222. std::span<const std::byte, state::kAesKeySize> key,
  223. std::array<std::byte, state::kBapNonceSize>& nonce,
  224. std::span<std::byte> response,
  225. std::size_t& written,
  226. queuez::SessionState& after) noexcept;
  227. /**
  228. * Appends the family-zero banner pair as its own notification.
  229. * Sent twice per boot at the same version, which is what survives the state-1 DECLARED race.
  230. * `after` records the delivery, or a later 504 move cannot name the record it must release.
  231. * @param scratch Lock-owned transform buffers.
  232. * @param before Queuez state the pair is delivered against.
  233. * @param familyRootSoid Root the Client subscribed for Family 3.
  234. * @param key Active AES-GCM session key.
  235. * @param nonce Push-direction nonce, advanced only by a complete frame.
  236. * @param response Caller-owned output containing prior frames.
  237. * @param written Existing byte count, updated by a complete frame.
  238. * @param after Receives the state carrying the recorded delivery.
  239. * @return True when the banner frame is appended.
  240. */
  241. [[nodiscard]] bool append_banner_notification(Scratch& scratch,
  242. const queuez::SessionState& before,
  243. std::uint64_t familyRootSoid,
  244. std::span<const std::byte, state::kAesKeySize> key,
  245. std::array<std::byte, state::kBapNonceSize>& nonce,
  246. std::span<std::byte> response,
  247. std::size_t& written,
  248. queuez::SessionState& after) noexcept;
  249. /**
  250. * Appends the family-zero pair that follows an opcode-504 pick.
  251. * The Client holds the objIdx-1 buffer for one character at a time, so the pair moves with it. A
  252. * pick naming the character it already holds republishes the pair in place.
  253. * @param before Queuez state after the family-four move.
  254. * @param selectedCharacter Character the pick named.
  255. * @param key Active AES-GCM session key.
  256. * @param nonce Push-direction nonce, advanced only by a complete frame.
  257. * @param response Caller-owned output containing prior frames.
  258. * @param written Existing byte count, updated by a complete frame.
  259. * @param after Receives the state published once the frame is copied.
  260. * @return True when a frame went out and `after` carries the advanced ladder.
  261. */
  262. [[nodiscard]] bool
  263. append_banner_move_notification(Scratch& scratch,
  264. const queuez::SessionState& before,
  265. std::uint64_t selectedCharacter,
  266. std::span<const std::byte, state::kAesKeySize> key,
  267. std::array<std::byte, state::kBapNonceSize>& nonce,
  268. std::span<std::byte> response,
  269. std::size_t& written,
  270. queuez::SessionState& after) noexcept;
  271. /**
  272. * Appends the fixed opcode-505 Family-4 selection patch.
  273. * @param scratch Lock-owned transform buffers.
  274. * @param change Staged queuez after-image and account definition.
  275. * @param key Active AES-GCM session key.
  276. * @param nonce Push-direction nonce after the correlated svc-11 response.
  277. * @param response Caller-owned output containing the existing response prefix.
  278. * @param written Existing byte count, updated after the complete push is appended.
  279. * @return True when the exact 17-byte patch and complete svc-123 frame fit.
  280. */
  281. [[nodiscard]] bool
  282. append_change_character_notification(Scratch& scratch,
  283. const queuez::ChangeCharacter& change,
  284. std::span<const std::byte, state::kAesKeySize> key,
  285. std::span<const std::byte, state::kBapNonceSize> nonce,
  286. std::span<std::byte> response,
  287. std::size_t& written) noexcept;
  288. /**
  289. * Appends the opcode-504 Family-4 move to the picked character.
  290. * @param scratch Lock-owned transform buffers.
  291. * @param select Staged after-image, object definitions, and both character keys.
  292. * @param key Active AES-GCM session key.
  293. * @param nonce Push-direction nonce after the correlated svc-11 response.
  294. * @param response Caller-owned output containing the existing response prefix.
  295. * @param written Existing byte count, updated after the complete push is appended.
  296. * @return True when the 3 object operations and the whole svc-123 frame fit.
  297. */
  298. [[nodiscard]] bool
  299. append_select_character_notification(Scratch& scratch,
  300. const queuez::SelectCharacter& select,
  301. std::span<const std::byte, state::kAesKeySize> key,
  302. std::span<const std::byte, state::kBapNonceSize> nonce,
  303. std::span<std::byte> response,
  304. std::size_t& written) noexcept;
  305. /** Appends the opcode-403 Family-4 character upsert that exposes the equipped item swap. */
  306. [[nodiscard]] bool
  307. append_equipment_swap_notification(Scratch& scratch,
  308. const queuez::EquipmentSwap& swap,
  309. const state::PendingEquipmentSwap& mutation,
  310. std::span<const std::byte, state::kAesKeySize> key,
  311. std::span<const std::byte, state::kBapNonceSize> nonce,
  312. std::span<std::byte> response,
  313. std::size_t& written) noexcept;
  314. /** Appends the Family-4 character upsert carrying the character's new current activity. */
  315. [[nodiscard]] bool
  316. append_current_activity_notification(Scratch& scratch,
  317. const queuez::EquipmentSwap& swap,
  318. const state::PendingCurrentActivity& mutation,
  319. std::span<const std::byte, state::kAesKeySize> key,
  320. std::span<const std::byte, state::kBapNonceSize> nonce,
  321. std::span<std::byte> response,
  322. std::size_t& written) noexcept;
  323. /** Appends the opcode-406 Family-4 character upsert carrying changed inventory-row flags. */
  324. [[nodiscard]] bool
  325. append_item_state_notification(Scratch& scratch,
  326. const queuez::EquipmentSwap& update,
  327. const state::PendingItemState& mutation,
  328. std::span<const std::byte, state::kAesKeySize> key,
  329. std::span<const std::byte, state::kBapNonceSize> nonce,
  330. std::span<std::byte> response,
  331. std::size_t& written) noexcept;
  332. /**
  333. * Appends the same-character Family-0 appearance upsert paired with one equipment swap.
  334. * The update owns its nonce advance only after the complete notification fits.
  335. */
  336. [[nodiscard]] bool
  337. append_equipment_appearance_refresh_notification(Scratch& scratch,
  338. const queuez::CharacterAppearanceRefresh& refresh,
  339. const state::PendingEquipmentSwap& mutation,
  340. std::span<const std::byte, state::kAesKeySize> key,
  341. std::array<std::byte, state::kBapNonceSize>& nonce,
  342. std::span<std::byte> response,
  343. std::size_t& written) noexcept;
  344. /** Appends the Family-0 refresh owed by a socket change on an equipped item. */
  345. [[nodiscard]] bool
  346. append_socket_appearance_refresh_notification(Scratch& scratch,
  347. const queuez::CharacterAppearanceRefresh& refresh,
  348. const state::PendingSocketPlug& mutation,
  349. std::span<const std::byte, state::kAesKeySize> key,
  350. std::array<std::byte, state::kBapNonceSize>& nonce,
  351. std::span<std::byte> response,
  352. std::size_t& written) noexcept;
  353. /** Appends the Family-0 character ability refresh owed by a subclass selection. */
  354. [[nodiscard]] bool
  355. append_subclass_appearance_refresh_notification(Scratch& scratch,
  356. const queuez::CharacterAppearanceRefresh& refresh,
  357. const state::PendingSubclassSelection& mutation,
  358. std::span<const std::byte, state::kAesKeySize> key,
  359. std::array<std::byte, state::kBapNonceSize>& nonce,
  360. std::span<std::byte> response,
  361. std::size_t& written) noexcept;
  362. /** Appends a Family-3 character record followed by the changed account roster after equip. */
  363. [[nodiscard]] bool
  364. append_equipment_roster_refresh_notification(Scratch& scratch,
  365. const queuez::RosterAppearanceRefresh& refresh,
  366. const state::PendingEquipmentSwap& mutation,
  367. std::span<const std::byte, state::kAesKeySize> key,
  368. std::array<std::byte, state::kBapNonceSize>& nonce,
  369. std::span<std::byte> response,
  370. std::size_t& written) noexcept;
  371. /** Appends a Family-3 character-only appearance refresh after an equipped socket change. */
  372. [[nodiscard]] bool
  373. append_socket_roster_refresh_notification(Scratch& scratch,
  374. const queuez::RosterAppearanceRefresh& refresh,
  375. const state::PendingSocketPlug& mutation,
  376. std::span<const std::byte, state::kAesKeySize> key,
  377. std::array<std::byte, state::kBapNonceSize>& nonce,
  378. std::span<std::byte> response,
  379. std::size_t& written) noexcept;
  380. /** Appends a Family-3 character-only appearance refresh after a subclass selection. */
  381. [[nodiscard]] bool
  382. append_subclass_roster_refresh_notification(Scratch& scratch,
  383. const queuez::RosterAppearanceRefresh& refresh,
  384. const state::PendingSubclassSelection& mutation,
  385. std::span<const std::byte, state::kAesKeySize> key,
  386. std::array<std::byte, state::kBapNonceSize>& nonce,
  387. std::span<std::byte> response,
  388. std::size_t& written) noexcept;
  389. /** Refreshes the selected character's complete Family-0 appearance from committed State. */
  390. [[nodiscard]] bool
  391. append_account_resync_appearance_notification(Scratch& scratch,
  392. const queuez::SessionState& before,
  393. std::span<const std::byte, state::kAesKeySize> key,
  394. std::array<std::byte, state::kBapNonceSize>& nonce,
  395. std::span<std::byte> response,
  396. std::size_t& written,
  397. queuez::SessionState& after) noexcept;
  398. /** Refreshes the selected character and account roster from committed State. */
  399. [[nodiscard]] bool
  400. append_account_resync_roster_notification(Scratch& scratch,
  401. const queuez::SessionState& before,
  402. std::span<const std::byte, state::kAesKeySize> key,
  403. std::array<std::byte, state::kBapNonceSize>& nonce,
  404. std::span<std::byte> response,
  405. std::size_t& written,
  406. queuez::SessionState& after) noexcept;
  407. /** Appends the opcode-903 Family-4 item-instance upsert exposing one socket selection. */
  408. [[nodiscard]] bool
  409. append_socket_plug_notification(Scratch& scratch,
  410. const queuez::SocketPlug& socketPlug,
  411. const state::PendingSocketPlug& mutation,
  412. std::span<const std::byte, state::kAesKeySize> key,
  413. std::span<const std::byte, state::kBapNonceSize> nonce,
  414. std::span<std::byte> response,
  415. std::size_t& written) noexcept;
  416. /** Appends the opcode-801 Family-4 subclass item-instance upsert. */
  417. [[nodiscard]] bool
  418. append_subclass_selection_notification(Scratch& scratch,
  419. const queuez::SubclassSelection& selection,
  420. const state::PendingSubclassSelection& mutation,
  421. std::span<const std::byte, state::kAesKeySize> key,
  422. std::span<const std::byte, state::kBapNonceSize> nonce,
  423. std::span<std::byte> response,
  424. std::size_t& written) noexcept;
  425. /** Appends a Family-4 character upsert plus newly acquired item-instance upsert. */
  426. [[nodiscard]] bool
  427. append_item_acquisition_notification(Scratch& scratch,
  428. const queuez::ItemAcquisition& acquisition,
  429. const state::PendingItemAcquisition& mutation,
  430. std::span<const std::byte, state::kAesKeySize> key,
  431. std::span<const std::byte, state::kBapNonceSize> nonce,
  432. std::span<std::byte> response,
  433. std::size_t& written) noexcept;
  434. /** Appends one full Family-4 account upsert for a profile-stack acquisition. */
  435. [[nodiscard]] bool
  436. append_profile_item_acquisition_notification(Scratch& scratch,
  437. const queuez::ProfileItemAcquisition& acquisition,
  438. const state::PendingProfileItemAcquisition& mutation,
  439. std::span<const std::byte, state::kAesKeySize> key,
  440. std::span<const std::byte, state::kBapNonceSize> nonce,
  441. std::span<std::byte> response,
  442. std::size_t& written) noexcept;
  443. /** Appends a Family-4 character upsert followed by one empty item-instance release. */
  444. [[nodiscard]] bool
  445. append_item_dismantle_notification(Scratch& scratch,
  446. const queuez::ItemDismantle& dismantle,
  447. const state::PendingItemDismantle& mutation,
  448. std::span<const std::byte, state::kAesKeySize> key,
  449. std::span<const std::byte, state::kBapNonceSize> nonce,
  450. std::span<std::byte> response,
  451. std::size_t& written) noexcept;
  452. } // namespace push
  453. } // namespace sunrise::server::bap::encrypted