max / goingson
| 1 | //! Problem sources: the pull side of the Problems inbox. |
| 2 | //! |
| 3 | //! GoingsOn pulls; sources never write `goingson.db`. That direction is forced |
| 4 | //! by the repo layout — wam lives in `MNW/`, GoingsOn in `Apps/`, and a |
| 5 | //! `wam promote` writing our database would need a path-dep on `goingson-core` |
| 6 | //! across repos — but it is also the better shape: task creation stays on the |
| 7 | //! side that owns tasks, and a source only has to expose a read surface. |
| 8 | //! |
| 9 | //! A source is defined here rather than in `goingson-core` because pulling is |
| 10 | //! integration, not storage: adapters speak HTTP and read config, neither of |
| 11 | //! which core knows about. Core owns the `Problem` model and the repository; |
| 12 | //! this module owns getting rows into it. |
| 13 | |
| 14 | use async_trait; |
| 15 | use NewProblem; |
| 16 | |
| 17 | |
| 18 | |
| 19 | pub use WamSource; |
| 20 | |
| 21 | /// Install the rustls crypto provider for tests. |
| 22 | /// |
| 23 | /// The app does this at startup (`main` and the mobile entry point); a unit test |
| 24 | /// that builds a reqwest client never runs either, and rustls panics with |
| 25 | /// "No provider set". Idempotent, so every test can call it. |
| 26 | |
| 27 | pub |
| 28 | static ONCE: Once = new; |
| 29 | ONCE.call_once |
| 30 | let _ = default_provider.install_default; |
| 31 | ; |
| 32 | |
| 33 | |
| 34 | /// A read surface over some external system's open problems. |
| 35 | /// |
| 36 | /// One implementation per source. `pull` returns what the source currently |
| 37 | /// reports; reconciling that against what GoingsOn already holds is the |
| 38 | /// repository's job, via the `(source, source_ref)` upsert, so an adapter never |
| 39 | /// has to know what it said last time. |
| 40 | |
| 41 | |
| 42 | /// The adapter's name, stored on every problem it produces and used to |
| 43 | /// filter the inbox. Must be stable: it is half the provenance key. |
| 44 | ; |
| 45 | |
| 46 | /// Fetch the source's current problems. |
| 47 | /// |
| 48 | /// Returns everything the source reports, including items it considers |
| 49 | /// resolved (flagged via `resolved_upstream`), so a fix upstream can settle |
| 50 | /// the mirrored row instead of leaving it open forever. |
| 51 | async ; |
| 52 | |
| 53 | |
| 54 | /// Why a pull failed. |
| 55 | /// |
| 56 | /// Separated from a generic error string because the inbox reacts differently |
| 57 | /// to each: an unconfigured source is not a problem to report, an unreachable |
| 58 | /// one is worth saying out loud but must not delete anything already mirrored. |
| 59 | |
| 60 | |
| 61 | /// The source has no endpoint configured. Not an error condition; the inbox |
| 62 | /// simply has nothing to pull from yet. |
| 63 | |
| 64 | NotConfigured, |
| 65 | |
| 66 | /// The source could not be reached, or refused the request. |
| 67 | /// |
| 68 | /// The adapter name is `name`, not `source`: thiserror reads a field called |
| 69 | /// `source` as the underlying error cause, which a `&str` cannot be. |
| 70 | |
| 71 | Unreachable , |
| 72 | |
| 73 | /// The source answered with something this adapter could not read. |
| 74 | |
| 75 | Malformed , |
| 76 | |
| 77 |