Skip to content

Commit

Permalink
feat(iroh): add node wide default author for documents (#2299)
Browse files Browse the repository at this point in the history
## Description

This adds the notion of a node-wide default author for documents.

The default author can be retrieved via `iroh.authors.default()`. On
persistent nodes, on first start a new author is created and its public
key is saved to `IROH_DATA_DIR/default-author` (as a base32 string). For
in-memory nodes, a new author is created.

When trying to delete the default author via `iroh.authors.delete`, an
error is returned, stating that the default author may not be deleted.

The default author can be changed with `iroh.authors.set_default`.

If the `default-author` file is deleted manually, a new default author
will be created on the next start.

## Breaking Changes

* Added `iroh.authors.default()`, which returns the author id of a
single default author per node
* Added `iroh.authors.set_default(&self, author_id: AuthorId)`, which
allows to set the default author for the node
* `iroh::util::path::IrohPaths` enum gained new variant `DefaultAuthor`

## Notes & open questions

There are certainly other ways to go around the interactions between the
iroh-local notion of a default author and the author database in the
iroh-docs store. Quoting from discord (this PR implements option B.1):

> if you delete the default author with the author api, what should
happen?
>* A: default author remains in place, further operations with it fail
>  * A.1: on next start new default author is created automatically
>  * A.2: next start fails, says "delete default_author file by hand"
>* B: deletion of default author fails. 
> * B1: that's the way it is, only way to delete it is to delete
`default-author` file by hand and restart the node
>  * B2: add `set_default_author` rpc call
>* C: a new default author is created and set always & automatically

## Change checklist

- [x] Self-review.
- [x] Documentation updates if relevant.
- [x] Tests if relevant.
- [x] All breaking changes documented.

---------

Co-authored-by: dignifiedquire <[email protected]>
  • Loading branch information
Frando and dignifiedquire authored May 23, 2024
1 parent d635d93 commit c8690a2
Show file tree
Hide file tree
Showing 14 changed files with 531 additions and 105 deletions.
16 changes: 12 additions & 4 deletions iroh-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,36 +115,44 @@ impl Cli {

match self.command {
Commands::Console => {
let env = ConsoleEnv::for_console(data_dir)?;
let data_dir_owned = data_dir.to_owned();
if self.start {
let config = NodeConfig::load(self.config.as_deref()).await?;
start::run_with_command(
&config,
data_dir,
RunType::SingleCommandNoAbort,
|iroh| async move { console::run(&iroh, &env).await },
|iroh| async move {
let env = ConsoleEnv::for_console(data_dir_owned, &iroh).await?;
console::run(&iroh, &env).await
},
)
.await
} else {
crate::logging::init_terminal_logging()?;
let iroh = QuicIroh::connect(data_dir).await.context("rpc connect")?;
let env = ConsoleEnv::for_console(data_dir_owned, &iroh).await?;
console::run(&iroh, &env).await
}
}
Commands::Rpc(command) => {
let env = ConsoleEnv::for_cli(data_dir)?;
let data_dir_owned = data_dir.to_owned();
if self.start {
let config = NodeConfig::load(self.config.as_deref()).await?;
start::run_with_command(
&config,
data_dir,
RunType::SingleCommandAbortable,
|iroh| async move { command.run(&iroh, &env).await },
move |iroh| async move {
let env = ConsoleEnv::for_cli(data_dir_owned, &iroh).await?;
command.run(&iroh, &env).await
},
)
.await
} else {
crate::logging::init_terminal_logging()?;
let iroh = QuicIroh::connect(data_dir).await.context("rpc connect")?;
let env = ConsoleEnv::for_cli(data_dir_owned, &iroh).await?;
command.run(&iroh, &env).await
}
}
Expand Down
17 changes: 17 additions & 0 deletions iroh-cli/src/commands/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ pub enum AuthorCommands {
Export { author: AuthorId },
/// Import an author
Import { author: String },
/// Print the default author for this node.
Default {
/// Switch to the default author (only in the Iroh console).
#[clap(long)]
switch: bool,
},
/// List authors.
#[clap(alias = "ls")]
List,
Expand All @@ -47,6 +53,17 @@ impl AuthorCommands {
println!("{}", author_id);
}
}
Self::Default { switch } => {
if switch && !env.is_console() {
bail!("The --switch flag is only supported within the Iroh console.");
}
let author_id = iroh.authors.default().await?;
println!("{}", author_id);
if switch {
env.set_author(author_id)?;
println!("Active author is now {}", fmt_short(author_id.as_bytes()));
}
}
Self::New { switch } => {
if switch && !env.is_console() {
bail!("The --switch flag is only supported within the Iroh console.");
Expand Down
15 changes: 7 additions & 8 deletions iroh-cli/src/commands/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Repl {
pub fn run(self) -> anyhow::Result<()> {
let mut rl =
DefaultEditor::with_config(Config::builder().check_cursor_position(true).build())?;
let history_path = ConsolePaths::History.with_root(self.env.iroh_data_dir());
let history_path = ConsolePaths::History.with_iroh_data_dir(self.env.iroh_data_dir());
rl.load_history(&history_path).ok();
loop {
// prepare a channel to receive a signal from the main thread when a command completed
Expand Down Expand Up @@ -87,13 +87,12 @@ impl Repl {

pub fn prompt(&self) -> String {
let mut pwd = String::new();
if let Some(author) = &self.env.author(None).ok() {
pwd.push_str(&format!(
"{}{} ",
"author:".blue(),
fmt_short(author.as_bytes()).blue().bold(),
));
}
let author = self.env.author();
pwd.push_str(&format!(
"{}{} ",
"author:".blue(),
fmt_short(author.as_bytes()).blue().bold(),
));
if let Some(doc) = &self.env.doc(None).ok() {
pwd.push_str(&format!(
"{}{} ",
Expand Down
10 changes: 6 additions & 4 deletions iroh-cli/src/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ impl DocCommands {
value,
} => {
let doc = get_doc(iroh, env, doc).await?;
let author = env.author(author)?;
let author = author.unwrap_or(env.author());
let key = key.as_bytes().to_vec();
let value = value.as_bytes().to_vec();
let hash = doc.set_bytes(author, key, value).await?;
Expand All @@ -372,7 +372,7 @@ impl DocCommands {
prefix,
} => {
let doc = get_doc(iroh, env, doc).await?;
let author = env.author(author)?;
let author = author.unwrap_or(env.author());
let prompt =
format!("Deleting all entries whose key starts with {prefix}. Continue?");
if Confirm::new()
Expand Down Expand Up @@ -453,7 +453,7 @@ impl DocCommands {
no_prompt,
} => {
let doc = get_doc(iroh, env, doc).await?;
let author = env.author(author)?;
let author = author.unwrap_or(env.author());
let mut prefix = prefix.unwrap_or_else(|| String::from(""));

if prefix.ends_with('/') {
Expand Down Expand Up @@ -979,7 +979,9 @@ mod tests {
let author = client.authors.create().await.context("author create")?;

// set up command, getting iroh node
let cli = ConsoleEnv::for_console(data_dir.path()).context("ConsoleEnv")?;
let cli = ConsoleEnv::for_console(data_dir.path().to_owned(), &node)
.await
.context("ConsoleEnv")?;
let iroh = iroh::client::QuicIroh::connect(data_dir.path())
.await
.context("rpc connect")?;
Expand Down
Loading

0 comments on commit c8690a2

Please sign in to comment.