StatumDirectives.vala 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. using Astralis;
  4. namespace Statum {
  5. /**
  6. * Helpers for rendering Statum directive responses.
  7. */
  8. public class StatumDirectives : Object {
  9. /** The content type that distinguishes a Statum directive response. */
  10. public const string CONTENT_TYPE = "application/vnd.statum+json";
  11. /**
  12. * Builds the short-circuit response an endpoint returns when the request
  13. * carried slots the server does not have in memory: a `transmit(retry)`
  14. * per missing key (plus an `invalidate` per untrustworthy frame
  15. * signature). The client re-sends the frames to the slot post endpoint,
  16. * drops any that fail verification, then re-issues the original request.
  17. */
  18. public static HttpResult transmit_result(Lot<string> transmit_keys, Lot<string>? invalid_signatures = null) throws GLib.Error {
  19. var directives = new Series<Model.DirectiveDto>();
  20. foreach (var key in transmit_keys) {
  21. directives.add(new Model.TransmitDirectiveDto.with(key, true));
  22. }
  23. return to_result(directives, invalid_signatures);
  24. }
  25. /**
  26. * Renders a lot of directives as the JSON array response served by every
  27. * directive-returning endpoint, with the Statum content type and
  28. * `Cache-Control: no-store`.
  29. *
  30. * Any invalid frame `signature`s are appended as `invalidate` directives
  31. * so the client drops slots whose frames the server could not trust.
  32. * Stale slot keys are auto-signed and appended as `set` directives so the
  33. * client refreshes outdated snapshots.
  34. */
  35. public static HttpResult to_result(
  36. Lot<Model.DirectiveDto> directives,
  37. Lot<string>? invalid_signatures = null,
  38. StateService? state_service = null,
  39. Lot<string>? stale_keys = null) throws GLib.Error {
  40. var rendered = new Series<Model.DirectiveDto>();
  41. foreach (var directive in directives) {
  42. rendered.add(directive);
  43. }
  44. if (invalid_signatures != null) {
  45. foreach (var signature in (!)invalid_signatures) {
  46. rendered.add(new Model.InvalidateDirectiveDto.with_signature(signature));
  47. }
  48. }
  49. if (state_service != null && stale_keys != null) {
  50. foreach (var key in (!)stale_keys) {
  51. var frame = state_service.sign_slot(key);
  52. if (frame != null) {
  53. rendered.add(new Model.SetDirectiveDto.with_frame((!)frame));
  54. }
  55. }
  56. }
  57. var json = Model.DirectiveDto.serialize_array(rendered);
  58. var result = new HttpStringResult(json.stringify());
  59. result.set_header("Content-Type", CONTENT_TYPE);
  60. result.set_header("Cache-Control", "no-store");
  61. return result;
  62. }
  63. }
  64. }