defmodule Dust do @moduledoc "Dust SDK — reactive global map client." @cloud_url "wss://dustlayer.io/ws/sync" @doc """ Returns the WebSocket URL for Dust's hosted cloud service at dustlayer.io. Use as the `:url` option when starting the supervisor against cloud: {Dust, stores: ["acme/site"], url: Dust.cloud_url(), token: token, cache: ...} """ def cloud_url, do: @cloud_url defmacro __using__(opts) do quote do use Dust.Instance, unquote(opts) end end def child_spec(opts) do %{ id: __MODULE__, start: {Dust.Supervisor, :start_link, [opts]}, type: :supervisor } end defdelegate get(store, path), to: Dust.SyncEngine defdelegate get_many(store, paths), to: Dust.SyncEngine defdelegate entry(store, path), to: Dust.SyncEngine defdelegate put(store, path, value), to: Dust.SyncEngine defdelegate put(store, path, value, opts), to: Dust.SyncEngine defdelegate delete(store, path), to: Dust.SyncEngine defdelegate delete(store, path, opts), to: Dust.SyncEngine defdelegate merge(store, path, map), to: Dust.SyncEngine defdelegate merge(store, path, map, opts), to: Dust.SyncEngine defdelegate increment(store, path, delta \\ 1), to: Dust.SyncEngine defdelegate increment(store, path, delta, opts), to: Dust.SyncEngine defdelegate add(store, path, member), to: Dust.SyncEngine defdelegate add(store, path, member, opts), to: Dust.SyncEngine defdelegate remove(store, path, member), to: Dust.SyncEngine defdelegate remove(store, path, member, opts), to: Dust.SyncEngine defdelegate put_file(store, path, source_path), to: Dust.SyncEngine defdelegate put_file(store, path, source_path, opts), to: Dust.SyncEngine defdelegate on(store, pattern, callback, opts \\ []), to: Dust.SyncEngine defdelegate watch(store, pattern, callback, opts \\ []), to: Dust.SyncEngine, as: :on defdelegate off(store, ref), to: Dust.SyncEngine defdelegate unsubscribe(store, ref), to: Dust.SyncEngine, as: :off defdelegate enum(store, pattern), to: Dust.SyncEngine defdelegate enum(store, pattern, opts), to: Dust.SyncEngine defdelegate range(store, from, to, opts \\ []), to: Dust.SyncEngine defdelegate status(store), to: Dust.SyncEngine defdelegate lease(store, key, opts \\ []), to: Dust.SyncEngine defdelegate renew(store, lease, opts \\ []), to: Dust.SyncEngine defdelegate release(store, lease), to: Dust.SyncEngine @doc """ Coordinated distributed cache-fill — compute `fun` once across the fleet and share the result. Returns `{:ok, %Dust.Flight{}}` or `{:error, reason}`. `fun` receives the held `%Dust.Lease{}` (or `nil` on the degraded `:run_local` path) and MUST return: * `{:publish, value}` — store `value` at `key` and return it. `value` must be a small pointer (put the bytes in S3/your DB). Publish a *definitive* negative (e.g. a genuinely empty result) so the freshness window holds and you don't recompute — classification is domain-specific (an empty page may be definitive; a 404 that will appear later is transient). * `{:abort, reason}` — release the lease, publish nothing, return `{:error, reason}`. Use this for *transient* failures so they aren't cached. **Prefer `{:abort, _}` over raising** for expected/transient errors: it releases the lease *immediately* (waiters re-elect at once), whereas a raised `fun` only frees the lease when `lease_ttl` expires (the heartbeat dies with the caller). Inside an Oban worker especially, abort cleanly rather than raise. Options: * `:fresh?` — `nil` (default) = presence mode (key exists ⇒ fresh; for done-forever results). A `(value -> boolean)` predicate = freshness mode (the value carries its own timestamp; refill when the predicate says so). * `:lease_ttl` — max in-flight fill time before the lease is stealable (default 30s; the lease is heartbeat-renewed while `fun` runs). * `:wait_timeout` — max a follower waits for the winner (default `lease_ttl + 5s`). * `:on_unavailable` — `:run_local` (default; run `fun` uncoordinated, never block — possible duplicate work, `coordinated?: false`) or `:error`. * `:lock_key` — the lease key (default a reserved sibling of `key`). **At-least-once, not exactly-once.** `fun` must be idempotent. """ defdelegate single_flight(store, key, fun, opts \\ []), to: Dust.SingleFlight, as: :run end