ContinuationProvider.vala 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. using Astralis;
  2. using Invercargill.DataStructures;
  3. using Inversion;
  4. namespace Spry {
  5. public class ContinuationProvider : SseEndpoint {
  6. private Dictionary<string, Component> components = new Dictionary<string, Component>();
  7. private Dictionary<string, bool> active_channels = new Dictionary<string, bool>();
  8. public override uint retry_interval { get { return 500; } }
  9. public async override void new_connection(HttpContext http_context, RouteContext route_context, SseStream stream) {
  10. var continuation_id = route_context.mapped_parameters.get_or_default("token");
  11. Component component = null;
  12. lock(active_channels) {
  13. if(components.try_get(continuation_id, out component)) {
  14. active_channels[continuation_id] = true;
  15. }
  16. }
  17. try {
  18. if(component == null) {
  19. yield stream.send_event(new SseEvent.with_type("_spry-close", "404"));
  20. }
  21. try {
  22. yield component.continuation(stream);
  23. }
  24. catch(Error e) {
  25. warning(@"Component $(component.get_type().name()) threw exception in follow up: $(e.message)");
  26. yield stream.send_event(new SseEvent.with_type("_spry-close", "500"));
  27. }
  28. yield stream.send_event(new SseEvent.with_type("_spry-close", "200"));
  29. }
  30. catch(Error e) {
  31. warning("Failed to send '_spry-close' event: " + e.message);
  32. return;
  33. }
  34. }
  35. public string get_continuation_path(Component component) {
  36. var id = Uuid.string_random();
  37. components[id] = component;
  38. active_channels[id] = false;
  39. // Remove component after 60 seconds if no connection has been made
  40. Timeout.add_seconds_once(60, () => clean(id));
  41. return @"/_spry/cnu/$id";
  42. }
  43. private void clean(string id) {
  44. bool active;
  45. lock(active_channels){
  46. if(!active_channels.try_get(id, out active)) {
  47. components.remove(id);
  48. return;
  49. }
  50. if(!active) {
  51. components.remove(id);
  52. active_channels.remove(id);
  53. }
  54. }
  55. }
  56. }
  57. }