EntrypointRouteTable.vala 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. using Astralis;
  4. namespace Statum {
  5. /**
  6. * A successful match of a request URI against an entrypoint route.
  7. */
  8. public class EntrypointMatch : Object {
  9. /** The entrypoint handler type bound to the matched route. */
  10. public Type entrypoint_type { get; set; }
  11. /** Route parameters captured from the matched route. */
  12. public ReadOnlyAssociative<string, string> route_params { get; set; default = new Dictionary<string, string>(); }
  13. }
  14. /**
  15. * Singleton table of `(route, entrypoint type)` pairs, populated by
  16. * {@link StatumConfigurator.add_page}.
  17. *
  18. * The {@link EntrypointEndpoint} matches the `uri` query parameter against
  19. * this table (using the same `{param}` segment matching as the Astralis
  20. * router) so that a page and its entrypoint agree on routing.
  21. */
  22. public class EntrypointRouteTable : Object {
  23. private Series<EntrypointRegistration> registrations = new Series<EntrypointRegistration>();
  24. /** Registers an entrypoint type for `route`. */
  25. public void register(EndpointRoute route, Type entrypoint_type) {
  26. registrations.add(new EntrypointRegistration(route, entrypoint_type));
  27. }
  28. /**
  29. * Matches `uri` against the registered routes, returning the bound
  30. * entrypoint type and any captured route parameters, or `null`.
  31. */
  32. public EntrypointMatch? match(string uri) {
  33. var path_components = Wrap.array<string>(uri.split("/"))
  34. .where(c => c.length != 0)
  35. .to_array();
  36. foreach (var registration in registrations) {
  37. var route_segments = registration.route.route_segments.to_array();
  38. var matched = try_match(path_components, route_segments);
  39. if (matched != null) {
  40. return new EntrypointMatch() {
  41. entrypoint_type = registration.entrypoint_type,
  42. route_params = (!)matched
  43. };
  44. }
  45. }
  46. return null;
  47. }
  48. private static Dictionary<string, string>? try_match(string[] path, string[] route_segments) {
  49. if (path.length != route_segments.length) {
  50. return null;
  51. }
  52. var params = new Dictionary<string, string>();
  53. for (var i = 0; i < path.length; i++) {
  54. var pattern = route_segments[i];
  55. var value = path[i];
  56. if (pattern.has_prefix("{") && pattern.has_suffix("}")) {
  57. params.set(pattern.substring(1, pattern.length - 2), value);
  58. } else if (pattern != value) {
  59. return null;
  60. }
  61. }
  62. return params;
  63. }
  64. private class EntrypointRegistration : Object {
  65. public EndpointRoute route { get; private set; }
  66. public Type entrypoint_type { get; private set; }
  67. public EntrypointRegistration(EndpointRoute route, Type entrypoint_type) {
  68. this.route = route;
  69. this.entrypoint_type = entrypoint_type;
  70. }
  71. }
  72. }
  73. }