Actions.vala 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using Statum;
  2. using Invercargill;
  3. using Invercargill.DataStructures;
  4. namespace Example {
  5. /**
  6. * `POST /_statum/action/{guid}` — logs in: reads the submitted name, builds a
  7. * session `auth` slot (with a typed private `is_admin` flag) carrying a
  8. * `logout` action reference, and redirects home.
  9. */
  10. public class LoginAction : StatumAction {
  11. public override async DirectiveBuilder handle() throws GLib.Error {
  12. var name = "guest";
  13. if (request.form != null) {
  14. var submitted = request.form.get_field("name");
  15. if (submitted != null && ((!)submitted).length > 0) {
  16. name = (!)submitted;
  17. }
  18. }
  19. var is_admin = name == "admin";
  20. var auth_public = new PropertyDictionary();
  21. auth_public.set_native<string>("name", name);
  22. auth_public.set_native<string>("role", is_admin ? "admin" : "member");
  23. auth_public["logout"] = action_registry.author<LogoutAction>().to_element();
  24. var auth_private = new PropertyDictionary();
  25. auth_private.set_native<bool>("is_admin", is_admin);
  26. var slot = state_service.new_slot(Scope.SESSION, new State() {
  27. type_name = "auth",
  28. public_data = auth_public,
  29. private_data = auth_private
  30. });
  31. return directives().set(slot).navigate("/");
  32. }
  33. }
  34. /**
  35. * `POST /_statum/action/{guid}` — logs out: clears the held `auth` slot
  36. * (server cache + clear directive) and redirects home.
  37. */
  38. public class LogoutAction : StatumAction {
  39. public override async DirectiveBuilder handle() throws GLib.Error {
  40. HeldSlot auth;
  41. if (request.held.try_get("auth", out auth)) {
  42. yield state_service.clear_slot(auth.key);
  43. return directives().clear(auth.key).navigate("/");
  44. }
  45. return directives().navigate("/");
  46. }
  47. }
  48. /**
  49. * `POST /_statum/action/{guid}` — bumps the counter by the typed private
  50. * `delta`, updating the held `counter` slot (sign + auto-push to subscribed
  51. * channels) and re-embedding the `bump` reference in the new public data.
  52. */
  53. public class BumpCounterAction : TypedStatumAction<CounterPrivate> {
  54. public override async DirectiveBuilder handle() throws GLib.Error {
  55. var delta = request_private != null ? ((!)request_private).delta : 1;
  56. HeldSlot held_counter;
  57. if (!request.held.try_get("counter", out held_counter)) {
  58. return directives().error("No counter slot held");
  59. }
  60. var slot = state_service.get_slot(held_counter.key);
  61. if (slot == null || ((!)slot).current_state == null) {
  62. return directives().error("Counter slot not found");
  63. }
  64. var current = ((!)slot).current_state;
  65. var value = GObjectMapping.get_int(current.public_data, "value") ?? 0;
  66. var new_public = new PropertyDictionary();
  67. new_public.set_native<int>("value", value + delta);
  68. var bump_private = new CounterPrivate();
  69. bump_private.delta = delta;
  70. new_public["bump"] = action_registry
  71. .author_private<BumpCounterAction, CounterPrivate>(bump_private)
  72. .to_element();
  73. var new_state = new State() {
  74. type_name = "counter",
  75. public_data = new_public,
  76. private_data = new PropertyDictionary()
  77. };
  78. return directives().update(held_counter.key, new_state);
  79. }
  80. }
  81. }