aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-hsservice/src/svc/publish.rs
blob: 029a5fc1b63b2e65954bf8ed49b9adf1b7022b4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! Publish and maintain onion service descriptors

#![allow(clippy::needless_pass_by_value)] // TODO HSS REMOVE.

mod backoff;
mod descriptor;
mod err;
mod reactor;

use futures::task::SpawnExt;
use postage::watch;
use std::sync::Arc;
use tracing::error;

use tor_circmgr::hspool::HsCircPool;
use tor_hscrypto::pk::HsId;
use tor_netdir::NetDirProvider;
use tor_rtcompat::Runtime;

use crate::ipt_set::IptsPublisherView;
use crate::OnionServiceConfig;

use err::PublisherError;
use reactor::{Reactor, ReactorError, ReactorState};

/// A handle for the Hsdir Publisher for an onion service.
///
/// This handle represents a set of tasks that identify the hsdirs for each
/// relevant time period, construct descriptors, publish them, and keep them
/// up-to-date.
pub(crate) struct Publisher {
    // TODO HSS: Write the contents here.
    //
    // I'm assuming that each Publisher knows its current keys, keeps track of
    // the current relevant time periods, and knows the current
    // status for uploading to each HsDir.
    //
    // Some of these contents may actually wind up belonging to a reactor
    // task.
}

impl Publisher {
    /// Create and launch a new publisher.
    ///
    /// When it launches, it will know no keys or introduction points,
    /// and will therefore not upload any descriptors.
    pub(crate) async fn new<R: Runtime>(
        runtime: R,
        hsid: HsId,
        dir_provider: Arc<dyn NetDirProvider>,
        circpool: Arc<HsCircPool<R>>,
        config: OnionServiceConfig,
        ipt_watcher: IptsPublisherView,
        config_rx: watch::Receiver<OnionServiceConfig>,
    ) -> Result<Self, PublisherError> {
        let state = ReactorState::new(circpool);
        let Ok(reactor) = Reactor::new(
            runtime.clone(),
            hsid,
            dir_provider,
            state,
            config,
            ipt_watcher,
            config_rx,
        )
        .await
        else {
            error!("failed to create reactor");
            panic!();
        };

        // TODO: Do we really want to launch now, or later?
        runtime
            .spawn(async move {
                let _result: Result<(), ReactorError> = reactor.run().await;
            })
            .map_err(|e| PublisherError::from_spawn("publisher reactor task", e))?;

        Ok(Self {})
    }

    /// Inform this publisher that its set of keys has changed.
    ///
    /// TODO HSS: Either this needs to take new keys as an argument, or there
    /// needs to be a source of keys (including public keys) in Publisher.
    pub(crate) fn new_hs_keys(&self, keys: ()) {
        todo!()
    }

    /// Return our current status.
    //
    // TODO HSS: There should also be a postage::Watcher -based stream of status
    // change events.
    pub(crate) fn status(&self) -> PublisherStatus {
        todo!()
    }

    // TODO HSS: We may also need to update descriptors based on configuration
    // or authentication changes.
}

/// Current status of our attempts to publish an onion service descriptor.
#[derive(Debug, Clone)]
pub(crate) struct PublisherStatus {
    // TODO HSS add fields
}

//
// Our main loop has to look something like:

// Whenever time period or keys or netdir changes: Check whether our list of
// HsDirs has changed.  If it is, add and/or remove hsdirs as needed.

// "when learning about new keys, new intro points, or new configurations,
// or whenever the time period changes: Mark descriptors dirty."

// Whenever descriptors are dirty, we have enough info to generate
// descriptors, and we aren't upload-rate-limited: Generate new descriptors
// and mark descriptors clean.  Mark all hsdirs as needing new versions of
// this descriptor.

// While any hsdir does not have the latest version of its any descriptor:
// upload it.  Retry with usual timeouts on failure."

// TODO HSS: tests