internal.h 27 KB

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