| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- using Invercargill.DataStructures;
- using InvercargillJson;
- using Inversion;
- namespace Statum {
- /**
- * Resolves Statum actions to/from their auto-assigned GUID endpoints; the
- * design follows the old Spry 0.1 `PathProvider`, removed in Spry 0.2.
- *
- * Every action registered via {@link StatumConfigurator.action} is assigned a
- * random GUID and served at `/_statum/action/{guid}` by a single
- * {@link ActionEndpoint}. The same GUID (looked up by type) is used when an
- * {@link Statum.Model.ActionDto} reference is authored for embedding in state.
- *
- * GUIDs are random per process start; this is fine because action references
- * are re-embedded into state on every entrypoint load, so a stale GUID never
- * survives a page render.
- */
- public class ActionRegistry : Object {
- private Cryptography.EncryptionProvider encryption_provider = inject<Cryptography.EncryptionProvider>();
- private Dictionary<string, Type> guid_to_type = new Dictionary<string, Type>();
- private Dictionary<string, string> type_to_guid = new Dictionary<string, string>();
- /** Registers an action type and assigns it a GUID (idempotent). */
- public void register<TAction>() {
- register_type(typeof(TAction));
- }
- /** Registers an action type and assigns it a GUID (idempotent). */
- public void register_type(Type type) {
- var name = type.name();
- if (type_to_guid.has(name)) {
- return;
- }
- var guid = Uuid.string_random();
- guid_to_type[guid] = type;
- type_to_guid[name] = guid;
- }
- /** The GUID assigned to `TAction` (registering it first if needed). */
- public string guid_for<TAction>() {
- return guid_for_type(typeof(TAction));
- }
- /** The GUID assigned to `type` (registering it first if needed). */
- public string guid_for_type(Type type) {
- var name = type.name();
- string guid;
- if (type_to_guid.try_get(name, out guid)) {
- return guid;
- }
- register_type(type);
- type_to_guid.try_get(name, out guid);
- return guid;
- }
- /** Resolves a GUID back to its action type for dispatch, or `null`. */
- public Type? resolve(string guid) {
- Type type;
- if (guid_to_type.try_get(guid, out type)) {
- return type;
- }
- return null;
- }
- /** The seal namespace for `TAction`'s private data (its type name). */
- public string namespace_for<TAction>() {
- return typeof(TAction).name();
- }
- /** The seal namespace for `type`'s private data (its type name). */
- public string namespace_for_type(Type type) {
- return type.name();
- }
- /**
- * Authors an {@link Model.ActionDto} reference for `TAction` (no private
- * data) that the client can invoke via `stm-action`.
- */
- public Model.ActionDto author<TAction>(string method = "POST") {
- return new Model.ActionDto() {
- uri = @"/_statum/action/$(guid_for<TAction>())",
- method = method
- };
- }
- /**
- * Authors an {@link Model.ActionDto} reference for `TAction` carrying
- * `model` as sealed private data. The blob is sealed under
- * {@link namespace_for}'s namespace, which the matching
- * `TypedStatumAction<TPrivate>` handler decrypts with its per-type
- * namespace.
- *
- * (Named distinctly from {@link author} because Vala does not permit
- * methods that overload on generic arity.)
- */
- public Model.ActionDto author_private<TAction, TPrivate>(TPrivate model, string method = "POST") throws GLib.Error {
- var blob = encryption_provider.author_properties(
- namespace_for<TAction>(),
- GObjectMapping.to_properties((Object) model));
- return new Model.ActionDto() {
- uri = @"/_statum/action/$(guid_for<TAction>())",
- method = method,
- @private = blob
- };
- }
- }
- }
|