ChannelSubscriptionEndpoint.vala 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. using InvercargillJson;
  4. using Inversion;
  5. using Astralis;
  6. namespace Statum {
  7. /**
  8. * `PATCH /_statum/channel/{id}` — adds or removes a channel's subscriptions.
  9. *
  10. * The request body is `{ "subscribe": [keys…], "unsubscribe": [keys…] }`.
  11. * For each newly-subscribed key, if the {@link StateService} has the slot
  12. * cached, its current frame is pushed immediately so a fresh client sees the
  13. * latest state right away (mirroring `server.php`). Responds `204 No Content`.
  14. */
  15. public class ChannelSubscriptionEndpoint : Object, Endpoint {
  16. private ChannelEndpoint channel_endpoint = inject<ChannelEndpoint>();
  17. private StateService state_service = inject<StateService>();
  18. public async HttpResult handle_request(HttpContext http_context, RouteContext route_context) throws GLib.Error {
  19. var id = route_context.mapped_parameters.get_or_default("id");
  20. if (id == null || !channel_endpoint.has_channel((!)id)) {
  21. return new HttpStringResult("No such channel", StatusCode.NOT_FOUND);
  22. }
  23. var body = yield http_context.request.request_body.read_all();
  24. var body_str = body.to_raw_string();
  25. Enumerable<string> subscribe_keys = Iterate.nothing<string>();
  26. Enumerable<string> unsubscribe_keys = Iterate.nothing<string>();
  27. if (body_str.strip().length > 0) {
  28. var body_element = new JsonElement.from_string(body_str);
  29. var root = body_element.as<JsonObject>();
  30. subscribe_keys = read_string_array(root, "subscribe");
  31. unsubscribe_keys = read_string_array(root, "unsubscribe");
  32. }
  33. foreach (var key in unsubscribe_keys) {
  34. channel_endpoint.unsubscribe((!)id, key);
  35. }
  36. foreach (var key in subscribe_keys) {
  37. channel_endpoint.subscribe((!)id, key);
  38. var slot = state_service.get_slot(key);
  39. if (slot != null) {
  40. var frame = state_service.sign_slot(key);
  41. if (frame != null) {
  42. var frame_json = serialize_frame((!)frame);
  43. yield channel_endpoint.push_set(key, frame_json);
  44. }
  45. }
  46. }
  47. return new HttpEmptyResult(StatusCode.NO_CONTENT);
  48. }
  49. private static string serialize_frame(Model.FrameDto frame) throws GLib.Error {
  50. return new JsonElement.from_properties(Model.FrameDto.get_mapper().map_from(frame)).stringify();
  51. }
  52. private static Enumerable<string> read_string_array(JsonObject root, string key) throws GLib.Error {
  53. var array = root.get_array(key);
  54. if (array == null) {
  55. return Iterate.nothing<string>();
  56. }
  57. var result = new Series<string>();
  58. foreach (var element in (!)array) {
  59. result.add(element.as<string>());
  60. }
  61. return result;
  62. }
  63. }
  64. }