2
0

3 Коммиты 28eaf91e10 ... 3066400930

Автор SHA1 Сообщение Дата
  Matthew Carr 3066400930 Modified the PoC protocol contract and actor implementation. 2 лет назад
  Matthew Carr d54e2c55bf Added a new deploy script to upload the site to freja. 2 лет назад
  Matthew Carr 43f461f7a9 Renamed btmsg to bttp. 2 лет назад

+ 27 - 27
Cargo.lock

@@ -285,8 +285,8 @@ version = "0.1.0"
 dependencies = [
 dependencies = [
  "anyhow",
  "anyhow",
  "btlib",
  "btlib",
- "btmsg",
  "btserde",
  "btserde",
+ "bttp",
  "bytes",
  "bytes",
  "fuse-backend-rs",
  "fuse-backend-rs",
  "futures",
  "futures",
@@ -323,8 +323,8 @@ dependencies = [
  "btfproto",
  "btfproto",
  "btlib",
  "btlib",
  "btlib-tests",
  "btlib-tests",
- "btmsg",
  "btserde",
  "btserde",
+ "bttp",
  "ctor",
  "ctor",
  "env_logger",
  "env_logger",
  "figment",
  "figment",
@@ -345,8 +345,8 @@ dependencies = [
  "btfproto",
  "btfproto",
  "btfproto-tests",
  "btfproto-tests",
  "btlib",
  "btlib",
- "btmsg",
  "btserde",
  "btserde",
+ "bttp",
  "ctor",
  "ctor",
  "env_logger",
  "env_logger",
  "figment",
  "figment",
@@ -411,29 +411,6 @@ dependencies = [
  "tempdir",
  "tempdir",
 ]
 ]
 
 
-[[package]]
-name = "btmsg"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "btlib",
- "btserde",
- "bytes",
- "chrono",
- "ctor",
- "env_logger",
- "futures",
- "lazy_static",
- "log",
- "quinn",
- "rustls",
- "serde",
- "tokio",
- "tokio-stream",
- "tokio-util",
- "zerocopy",
-]
-
 [[package]]
 [[package]]
 name = "btprovision"
 name = "btprovision"
 version = "0.1.0"
 version = "0.1.0"
@@ -455,8 +432,8 @@ dependencies = [
  "anyhow",
  "anyhow",
  "btlib",
  "btlib",
  "btlib-tests",
  "btlib-tests",
- "btmsg",
  "btserde",
  "btserde",
+ "bttp",
  "bytes",
  "bytes",
  "ctor",
  "ctor",
  "env_logger",
  "env_logger",
@@ -478,6 +455,29 @@ dependencies = [
  "serde-big-array",
  "serde-big-array",
 ]
 ]
 
 
+[[package]]
+name = "bttp"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "btlib",
+ "btserde",
+ "bytes",
+ "chrono",
+ "ctor",
+ "env_logger",
+ "futures",
+ "lazy_static",
+ "log",
+ "quinn",
+ "rustls",
+ "serde",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "zerocopy",
+]
+
 [[package]]
 [[package]]
 name = "bumpalo"
 name = "bumpalo"
 version = "3.11.1"
 version = "3.11.1"

+ 1 - 1
README.md

@@ -26,7 +26,7 @@ by the [tpm](./btlib/crypto/tpm/index.html) module.
 * [btrun](./btrun/index.html): Contains the actor runtime.
 * [btrun](./btrun/index.html): Contains the actor runtime.
 * [btserde](./btserde/index.html): Defines the serde compact binary serialization format used to
 * [btserde](./btserde/index.html): Defines the serde compact binary serialization format used to
 store data on disk and transmit over the network.
 store data on disk and transmit over the network.
-* [btmsg](./btmsg/index.html): Defines the message passing interface.
+* [bttp](./bttp/index.html): Defines the message passing interface.
 * [btfproto](./btfproto/index.html): Defines the message protocol used to communicate with file
 * [btfproto](./btfproto/index.html): Defines the message protocol used to communicate with file
 servers.
 servers.
 * [btfsd](./btfsd/index.html): Implements a file server daemon.
 * [btfsd](./btfsd/index.html): Implements a file server daemon.

+ 1 - 1
crates/btfproto/Cargo.toml

@@ -13,7 +13,7 @@ default = ["client", "server", "local-fs"]
 
 
 [dependencies]
 [dependencies]
 btlib = { path = "../btlib" }
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 serde = { version = "^1.0.136", features = ["derive"] }
 serde = { version = "^1.0.136", features = ["derive"] }
 paste = "1.0.11"
 paste = "1.0.11"
 log = "0.4.17"
 log = "0.4.17"

+ 1 - 1
crates/btfproto/src/client.rs

@@ -3,7 +3,7 @@
 use crate::{msg::*, server::FsProvider, Handle, Inode};
 use crate::{msg::*, server::FsProvider, Handle, Inode};
 
 
 use btlib::{bterr, crypto::ConcretePub, BlockPath, IssuedProcRec, Result};
 use btlib::{bterr, crypto::ConcretePub, BlockPath, IssuedProcRec, Result};
-use btmsg::{DeserCallback, Transmitter};
+use bttp::{DeserCallback, Transmitter};
 
 
 use core::future::{ready, Future, Ready};
 use core::future::{ready, Future, Ready};
 use futures::FutureExt;
 use futures::FutureExt;

+ 8 - 8
crates/btfproto/src/msg.rs

@@ -5,7 +5,7 @@ use super::{Handle, Inode};
 use btlib::{
 use btlib::{
     bterr, crypto::ConcretePub, BlockMetaSecrets, DirEntry, DirEntryKind, Epoch, IssuedProcRec,
     bterr, crypto::ConcretePub, BlockMetaSecrets, DirEntry, DirEntryKind, Epoch, IssuedProcRec,
 };
 };
-use btmsg::CallMsg;
+use bttp::CallMsg;
 use core::time::Duration;
 use core::time::Duration;
 use paste::paste;
 use paste::paste;
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
@@ -149,7 +149,7 @@ impl BitOr<libc::mode_t> for FileType {
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
 #[repr(i32)]
 #[repr(i32)]
 /// The generators for the group of [Flags].
 /// The generators for the group of [Flags].
-/// 
+///
 /// These are mostly values from libc, save for several custom values. Note that the presence of a
 /// These are mostly values from libc, save for several custom values. Note that the presence of a
 /// flag in this enum does not guarantee it's supported.
 /// flag in this enum does not guarantee it's supported.
 /// The standard libc `O_*` value which corresponds to each variant is given in the variant's
 /// The standard libc `O_*` value which corresponds to each variant is given in the variant's
@@ -281,7 +281,7 @@ impl Flags {
     }
     }
 
 
     /// Asserts that these flags allow a file to be read.
     /// Asserts that these flags allow a file to be read.
-    /// 
+    ///
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     pub fn assert_readable(self) -> Result<(), io::Error> {
     pub fn assert_readable(self) -> Result<(), io::Error> {
         if !self.readable() {
         if !self.readable() {
@@ -292,7 +292,7 @@ impl Flags {
     }
     }
 
 
     /// Asserts that these flags allow a file to be written.
     /// Asserts that these flags allow a file to be written.
-    /// 
+    ///
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     /// If the assertion fails then an [io::Error] with the errno [libc::EACCES] is returned.
     pub fn assert_writeable(self) -> Result<(), io::Error> {
     pub fn assert_writeable(self) -> Result<(), io::Error> {
         if !self.writeable() {
         if !self.writeable() {
@@ -361,7 +361,7 @@ pub struct Attrs {
 
 
 #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
 #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
 /// A type for indicating which fields in [Attrs] have been set and which should be ignored.
 /// A type for indicating which fields in [Attrs] have been set and which should be ignored.
-/// 
+///
 /// This method was chosen over using [Option] for greater efficiency on the wire.
 /// This method was chosen over using [Option] for greater efficiency on the wire.
 pub struct AttrsSet(u16);
 pub struct AttrsSet(u16);
 
 
@@ -431,7 +431,7 @@ impl BitOrAssign<Self> for AttrsSet {
 }
 }
 
 
 /// A filesystem entry.
 /// A filesystem entry.
-/// 
+///
 /// This struct includes attributes of a file as well as cache control
 /// This struct includes attributes of a file as well as cache control
 /// information for how long it may be cached.
 /// information for how long it may be cached.
 #[derive(Debug, Serialize, Deserialize)]
 #[derive(Debug, Serialize, Deserialize)]
@@ -561,7 +561,7 @@ pub struct LinkReply {
 }
 }
 
 
 /// A request to remove a name referring to an inode.
 /// A request to remove a name referring to an inode.
-/// 
+///
 /// If the inode becomes orphaned, it is removed from durable storage.
 /// If the inode becomes orphaned, it is removed from durable storage.
 #[derive(Serialize, Deserialize)]
 #[derive(Serialize, Deserialize)]
 pub struct Unlink<'a> {
 pub struct Unlink<'a> {
@@ -617,7 +617,7 @@ pub struct Close {
 }
 }
 
 
 /// A request to forget about an inode which was previously referenced.
 /// A request to forget about an inode which was previously referenced.
-/// 
+///
 /// This message must be sent
 /// This message must be sent
 /// so the server knows when it can free resources associated with the inode.
 /// so the server knows when it can free resources associated with the inode.
 /// If `N` [Entry] structs are sent in a reply to [Lookup] messages, then the caller must send one
 /// If `N` [Entry] structs are sent in a reply to [Lookup] messages, then the caller must send one

+ 2 - 2
crates/btfproto/src/server.rs

@@ -1,13 +1,13 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! Code for creating filesystem servers.
 //! Code for creating filesystem servers.
-//! 
+//!
 //! The [FsProvider] trait defines the interface that a filesystem server
 //! The [FsProvider] trait defines the interface that a filesystem server
 //! must implement.
 //! must implement.
 //! A new server can be created using the [new_fs_server] function.
 //! A new server can be created using the [new_fs_server] function.
 use crate::msg::{Read as ReadMsg, *};
 use crate::msg::{Read as ReadMsg, *};
 
 
 use btlib::{crypto::Creds, BlockPath, Result};
 use btlib::{crypto::Creds, BlockPath, Result};
-use btmsg::{MsgCallback, MsgReceived, Receiver};
+use bttp::{MsgCallback, MsgReceived, Receiver};
 use core::future::Future;
 use core::future::Future;
 use std::{net::IpAddr, ops::Deref, sync::Arc};
 use std::{net::IpAddr, ops::Deref, sync::Arc};
 
 

+ 1 - 1
crates/btfsd/Cargo.toml

@@ -7,7 +7,7 @@ edition = "2021"
 
 
 [dependencies]
 [dependencies]
 btlib = { path = "../btlib" }
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btfproto = { path = "../btfproto" }
 btfproto = { path = "../btfproto" }
 btconfig = { path = "../btconfig" }
 btconfig = { path = "../btconfig" }
 btconsole = { path = "../btconsole" }
 btconsole = { path = "../btconsole" }

+ 1 - 1
crates/btfsd/autobuild.sh

@@ -1,4 +1,4 @@
 #!/usr/bin/env bash
 #!/usr/bin/env bash
 # Automatically builds btconsole and btconsole-client when files in their respective crates change.
 # Automatically builds btconsole and btconsole-client when files in their respective crates change.
 set -euo pipefail
 set -euo pipefail
-RUST_LOG=warn,btfsd=debug,btconsole=debug,btmsg=debug cargo watch -- sh -c 'cd ../btconsole-client && trunk build && cd - && cargo run'
+RUST_LOG=warn,btfsd=debug,btconsole=debug,bttp=debug cargo watch -- sh -c 'cd ../btconsole-client && trunk build && cd - && cargo run'

+ 3 - 3
crates/btfsd/src/main.rs

@@ -6,7 +6,7 @@ use btfproto::{
     server::{new_fs_server, FsProvider},
     server::{new_fs_server, FsProvider},
 };
 };
 use btlib::{bterr, crypto::Creds, error::DisplayErr, log::BuilderExt, Result};
 use btlib::{bterr, crypto::Creds, error::DisplayErr, log::BuilderExt, Result};
-use btmsg::Receiver;
+use bttp::Receiver;
 use figment::{providers::Serialized, Figment};
 use figment::{providers::Serialized, Figment};
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
 use std::{net::IpAddr, path::PathBuf, sync::Arc};
 use std::{net::IpAddr, path::PathBuf, sync::Arc};
@@ -95,8 +95,8 @@ mod tests {
         AuthzAttrs, BlockMetaSecrets, Epoch, IssuedProcRec, Principaled, ProcRec,
         AuthzAttrs, BlockMetaSecrets, Epoch, IssuedProcRec, Principaled, ProcRec,
     };
     };
     use btlib_tests::{CredStoreTestingExt, TpmCredStoreHarness};
     use btlib_tests::{CredStoreTestingExt, TpmCredStoreHarness};
-    use btmsg::BlockAddr;
     use btserde::from_slice;
     use btserde::from_slice;
+    use bttp::BlockAddr;
     use std::net::{IpAddr, Ipv4Addr};
     use std::net::{IpAddr, Ipv4Addr};
     use std::{future::ready, net::Ipv6Addr, time::Duration};
     use std::{future::ready, net::Ipv6Addr, time::Duration};
     use swtpm_harness::SwtpmHarness;
     use swtpm_harness::SwtpmHarness;
@@ -896,7 +896,7 @@ mod tests {
         let node_creds = case.harness.cred_store().node_creds().unwrap();
         let node_creds = case.harness.cred_store().node_creds().unwrap();
         let bind_path = node_creds.writecap().unwrap().bind_path();
         let bind_path = node_creds.writecap().unwrap().bind_path();
         let block_addr = Arc::new(BlockAddr::new(LOCALHOST, Arc::new(bind_path)));
         let block_addr = Arc::new(BlockAddr::new(LOCALHOST, Arc::new(bind_path)));
-        let tx = btmsg::Transmitter::new(block_addr, Arc::new(user_creds))
+        let tx = bttp::Transmitter::new(block_addr, Arc::new(user_creds))
             .await
             .await
             .unwrap();
             .unwrap();
         let client = FsClient::new(tx);
         let client = FsClient::new(tx);

+ 1 - 1
crates/btfuse/Cargo.toml

@@ -11,7 +11,7 @@ btlib = { path = "../btlib" }
 btserde = { path = "../btserde" }
 btserde = { path = "../btserde" }
 swtpm-harness = { path = "../swtpm-harness" }
 swtpm-harness = { path = "../swtpm-harness" }
 btfproto = { path = "../btfproto" }
 btfproto = { path = "../btfproto" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btconfig = { path = "../btconfig" }
 btconfig = { path = "../btconfig" }
 tokio = { version = "1.24.2", features = ["rt", "rt-multi-thread"] }
 tokio = { version = "1.24.2", features = ["rt", "rt-multi-thread"] }
 fuse-backend-rs = { version = "0.9.6", features = ["async-io"] }
 fuse-backend-rs = { version = "0.9.6", features = ["async-io"] }

+ 3 - 3
crates/btfuse/src/main.rs

@@ -11,7 +11,7 @@ use btlib::{
     crypto::{Creds, CredsPriv},
     crypto::{Creds, CredsPriv},
     Result,
     Result,
 };
 };
-use btmsg::{BlockAddr, Transmitter};
+use bttp::{BlockAddr, Transmitter};
 use serde::{Deserialize, Serialize};
 use serde::{Deserialize, Serialize};
 use std::{
 use std::{
     fs::{self},
     fs::{self},
@@ -191,7 +191,7 @@ mod test {
         log::BuilderExt,
         log::BuilderExt,
         Epoch, Principaled,
         Epoch, Principaled,
     };
     };
-    use btmsg::Receiver;
+    use bttp::Receiver;
     use ctor::ctor;
     use ctor::ctor;
     use std::{
     use std::{
         ffi::{OsStr, OsString},
         ffi::{OsStr, OsString},
@@ -858,7 +858,7 @@ mod config_tests {
 
 
     use btconfig::CredStoreConfig;
     use btconfig::CredStoreConfig;
     use btlib::BlockPath;
     use btlib::BlockPath;
-    use btmsg::BlockAddr;
+    use bttp::BlockAddr;
     use figment::Jail;
     use figment::Jail;
 
 
     #[test]
     #[test]

+ 3 - 3
crates/btlib/src/crypto.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! This module contains types providing the cryptographic primitives necessary to implement
 //! This module contains types providing the cryptographic primitives necessary to implement
 //! Blocktree.
 //! Blocktree.
-//! 
+//!
 //! The [openssl] create is used for all of these primitives,
 //! The [openssl] create is used for all of these primitives,
 //! none of them are directly implemented in this module.
 //! none of them are directly implemented in this module.
 //! Rather, the types here wrap the functionality provided by OpenSSL in a more convenient
 //! Rather, the types here wrap the functionality provided by OpenSSL in a more convenient
@@ -56,7 +56,7 @@ use strum_macros::{Display, EnumDiscriminants, FromRepr};
 use zeroize::{ZeroizeOnDrop, Zeroizing};
 use zeroize::{ZeroizeOnDrop, Zeroizing};
 
 
 /// The encryption of some type `T`.
 /// The encryption of some type `T`.
-/// 
+///
 /// This type is just e wrapper around a [Vec] of [u8] which remembers the type it was serialized
 /// This type is just e wrapper around a [Vec] of [u8] which remembers the type it was serialized
 /// and encrypted from.
 /// and encrypted from.
 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
@@ -75,7 +75,7 @@ impl<T> Ciphertext<T> {
 }
 }
 
 
 /// A signature over the serialization of a type `T`.
 /// A signature over the serialization of a type `T`.
-/// 
+///
 /// This struct allows the signature over a serialization of `T` to be stored together with a
 /// This struct allows the signature over a serialization of `T` to be stored together with a
 /// signature over  it.
 /// signature over  it.
 pub struct Signed<T> {
 pub struct Signed<T> {

+ 1 - 1
crates/btrun/Cargo.toml

@@ -7,7 +7,7 @@ edition = "2021"
 
 
 [dependencies]
 [dependencies]
 btlib = { path = "../btlib" }
 btlib = { path = "../btlib" }
-btmsg = { path = "../btmsg" }
+bttp = { path = "../bttp" }
 btserde = { path = "../btserde" }
 btserde = { path = "../btserde" }
 tokio = { version = "1.23.0", features = ["rt-multi-thread"] }
 tokio = { version = "1.23.0", features = ["rt-multi-thread"] }
 futures = "0.3.25"
 futures = "0.3.25"

+ 130 - 127
crates/btrun/src/lib.rs

@@ -13,8 +13,8 @@ use std::{
 };
 };
 
 
 use btlib::{bterr, crypto::Creds, error::StringError, BlockPath, Result};
 use btlib::{bterr, crypto::Creds, error::StringError, BlockPath, Result};
-use btmsg::{DeserCallback, MsgCallback, Receiver, Replier, Transmitter};
 use btserde::{field_helpers::smart_ptr, from_slice, to_vec, write_to};
 use btserde::{field_helpers::smart_ptr, from_slice, to_vec, write_to};
+use bttp::{DeserCallback, MsgCallback, Receiver, Replier, Transmitter};
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 use tokio::{
 use tokio::{
     sync::{mpsc, oneshot, Mutex, RwLock},
     sync::{mpsc, oneshot, Mutex, RwLock},
@@ -177,7 +177,7 @@ impl Runtime {
         let act_name = self.actor_name(act_id);
         let act_name = self.actor_name(act_id);
         let (tx, rx) = mpsc::channel::<Envelope<Msg>>(MAILBOX_LIMIT);
         let (tx, rx) = mpsc::channel::<Envelope<Msg>>(MAILBOX_LIMIT);
         // The deliverer closure is responsible for deserializing messages received over the wire
         // The deliverer closure is responsible for deserializing messages received over the wire
-        // and delivering them to the actor's mailbox and sending replies to call messages.
+        // and delivering them to the actor's mailbox, and sending replies to call messages.
         let deliverer = {
         let deliverer = {
             let buffer = Arc::new(Mutex::new(Vec::<u8>::new()));
             let buffer = Arc::new(Mutex::new(Vec::<u8>::new()));
             let tx = tx.clone();
             let tx = tx.clone();
@@ -286,6 +286,19 @@ impl Display for RuntimeError {
 
 
 impl std::error::Error for RuntimeError {}
 impl std::error::Error for RuntimeError {}
 
 
+#[allow(dead_code)]
+/// Represents the terminal state of an actor, where it stops processing messages and halts.
+struct End;
+
+#[allow(dead_code)]
+/// Delivered to an actor implementation when it starts up.
+pub struct Activate {
+    /// A reference to the `Runtime` which is running this actor.
+    rt: &'static Runtime,
+    /// The ID assigned to this actor.
+    act_id: Uuid,
+}
+
 /// Deserializes replies sent over the wire.
 /// Deserializes replies sent over the wire.
 struct ReplyCallback<T> {
 struct ReplyCallback<T> {
     _phantom: PhantomData<T>,
     _phantom: PhantomData<T>,
@@ -385,7 +398,7 @@ impl RuntimeCallback {
 impl MsgCallback for RuntimeCallback {
 impl MsgCallback for RuntimeCallback {
     type Arg<'de> = WireMsg<'de>;
     type Arg<'de> = WireMsg<'de>;
     type CallFut<'de> = impl 'de + Future<Output = Result<()>>;
     type CallFut<'de> = impl 'de + Future<Output = Result<()>>;
-    fn call<'de>(&'de self, arg: btmsg::MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de> {
+    fn call<'de>(&'de self, arg: bttp::MsgReceived<Self::Arg<'de>>) -> Self::CallFut<'de> {
         async move {
         async move {
             let (_, body, replier) = arg.into_parts();
             let (_, body, replier) = arg.into_parts();
             if body.to.path() == self.rt.path() {
             if body.to.path() == self.rt.path() {
@@ -466,6 +479,10 @@ pub trait CallMsg: Serialize + DeserializeOwned + Send + Sync {
 /// Trait for messages which expect exactly zero replies.
 /// Trait for messages which expect exactly zero replies.
 pub trait SendMsg: CallMsg {}
 pub trait SendMsg: CallMsg {}
 
 
+/// A type used to express when a reply is not expected for a message type.
+#[derive(Serialize, Deserialize)]
+enum NoReply {}
+
 /// The maximum number of messages which can be kept in an actor's mailbox.
 /// The maximum number of messages which can be kept in an actor's mailbox.
 const MAILBOX_LIMIT: usize = 32;
 const MAILBOX_LIMIT: usize = 32;
 
 
@@ -477,11 +494,11 @@ struct WireMsg<'a> {
     payload: &'a [u8],
     payload: &'a [u8],
 }
 }
 
 
-impl<'a> btmsg::CallMsg<'a> for WireMsg<'a> {
+impl<'a> bttp::CallMsg<'a> for WireMsg<'a> {
     type Reply<'r> = WireReply<'r>;
     type Reply<'r> = WireReply<'r>;
 }
 }
 
 
-impl<'a> btmsg::SendMsg<'a> for WireMsg<'a> {}
+impl<'a> bttp::SendMsg<'a> for WireMsg<'a> {}
 
 
 #[derive(Serialize, Deserialize)]
 #[derive(Serialize, Deserialize)]
 enum WireReply<'a> {
 enum WireReply<'a> {
@@ -504,10 +521,8 @@ impl<'de> WireEnvelope<'de> {
     }
     }
 }
 }
 
 
-/// Wraps a message to indicate if it was sent with `call` or `send`.
-///
-/// If the message was sent with call, then this enum will contain a channel that can be used to
-/// reply to it.
+/// Wrapper around a message type `T` which indicates who the message is from and, if the message
+/// was dispatched with `call`, provides a channel to reply to it.
 pub struct Envelope<T: CallMsg> {
 pub struct Envelope<T: CallMsg> {
     from: ActorName,
     from: ActorName,
     reply: Option<oneshot::Sender<T::Reply>>,
     reply: Option<oneshot::Sender<T::Reply>>,
@@ -656,8 +671,8 @@ mod tests {
         log::BuilderExt,
         log::BuilderExt,
     };
     };
     use btlib_tests::TEST_STORE;
     use btlib_tests::TEST_STORE;
-    use btmsg::BlockAddr;
     use btserde::to_vec;
     use btserde::to_vec;
+    use bttp::BlockAddr;
     use ctor::ctor;
     use ctor::ctor;
     use lazy_static::lazy_static;
     use lazy_static::lazy_static;
     use std::{
     use std::{
@@ -788,37 +803,46 @@ mod tests {
         assert_eq!(0, LOCAL_RT.num_running().await);
         assert_eq!(0, LOCAL_RT.num_running().await);
     }
     }
 
 
-    struct Activate {
-        rt: &'static Runtime,
-        act_id: Uuid,
-    }
+    // The following code is a proof-of-concept for what types should be generated for a
+    // simple ping-pong protocol:
+    //
+    // protocol! {
+    //     ClientInit?Activate -> SentPing, Listening!Ping
+    //     ServerInit?Activate -> Listening
+    //     Listening?Ping -> End, SentPing!Ping::Reply
+    //     SentPing?Ping::Reply -> End
+    // }
+    //
+    // In words, the protocol is described as follows.
+    // 1. The ClientInit state receives the Activate message. It returns the SentPing state and a
+    //    Ping message to be sent to the Listening state.
+    // 2. The ServerInit state receives the Activate message. It returns the Listening state.
+    // 3. When the Listening state receives the Ping message it returns the End state and a
+    //    Ping::Reply message to be sent to the SentPing state.
+    // 4. When the SentPing state receives the Ping::Reply message it returns the End state.
+    //
+    // The End state represents an end to the session described by the protocol. When an actor
+    // transitions to the End state its function returns.
+    // The generated actor implementation is the sender of the Activate message.
+    // When a state is expecting a Reply message, an error occurs if the message is not received
+    // in a timely manner.
 
 
     #[derive(Serialize, Deserialize)]
     #[derive(Serialize, Deserialize)]
     struct Ping;
     struct Ping;
     impl CallMsg for Ping {
     impl CallMsg for Ping {
-        type Reply = ();
+        type Reply = PingReply;
     }
     }
-    impl SendMsg for Ping {}
 
 
+    // I was tempted to name this "Pong", but the proc macro wouldn't think to do that.
     #[derive(Serialize, Deserialize)]
     #[derive(Serialize, Deserialize)]
-    struct Pong;
-    impl CallMsg for Pong {
-        type Reply = ();
-    }
-    impl SendMsg for Pong {}
+    struct PingReply;
 
 
     trait ClientInit {
     trait ClientInit {
         type AfterActivate: SentPing;
         type AfterActivate: SentPing;
-        type HandleActivateFut: Future<Output = Result<Self::AfterActivate>>;
+        type HandleActivateFut: Future<Output = Result<(Self::AfterActivate, Ping)>>;
         fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut;
         fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut;
     }
     }
 
 
-    trait SentPing {
-        type AfterPong: Returned;
-        type HandlePongFut: Future<Output = Result<Self::AfterPong>>;
-        fn handle_pong(self, msg: Envelope<Pong>) -> Self::HandlePongFut;
-    }
-
     trait ServerInit {
     trait ServerInit {
         type AfterActivate: Listening;
         type AfterActivate: Listening;
         type HandleActivateFut: Future<Output = Result<Self::AfterActivate>>;
         type HandleActivateFut: Future<Output = Result<Self::AfterActivate>>;
@@ -826,109 +850,77 @@ mod tests {
     }
     }
 
 
     trait Listening {
     trait Listening {
-        type AfterPing: Returned;
-        type HandlePingFut: Future<Output = Result<Self::AfterPing>>;
-        fn handle_ping(self, msg: Envelope<Ping>) -> Self::HandlePingFut;
+        type HandlePingFut: Future<Output = Result<(End, PingReply)>>;
+        fn handle_ping(self, msg: Ping) -> Self::HandlePingFut;
     }
     }
 
 
-    trait Returned {}
-
-    struct ReturnedState;
-
-    impl Returned for ReturnedState {}
-
-    trait PingProtocol {
-        type Client: ClientInit;
-        type Server: ServerInit;
+    trait SentPing {
+        type HandleReplyFut: Future<Output = Result<End>>;
+        fn handle_reply(self, msg: PingReply) -> Self::HandleReplyFut;
     }
     }
 
 
     #[derive(Serialize, Deserialize)]
     #[derive(Serialize, Deserialize)]
     enum PingProtocolMsg {
     enum PingProtocolMsg {
         Ping(Ping),
         Ping(Ping),
-        Pong(Pong),
+        PingReply(PingReply),
     }
     }
     impl CallMsg for PingProtocolMsg {
     impl CallMsg for PingProtocolMsg {
-        type Reply = ();
+        type Reply = PingProtocolMsg;
     }
     }
     impl SendMsg for PingProtocolMsg {}
     impl SendMsg for PingProtocolMsg {}
 
 
-    #[allow(dead_code)]
-    enum PingClientState {
-        Init(ClientInitState),
-        SentPing(ClientState),
-        Returned(ReturnedState),
-    }
-
-    #[allow(dead_code)]
-    enum PingServerState {
-        ServerInit(ServerInitState),
-        Listening(ServerState),
-        Returned(ReturnedState),
-    }
-
-    struct ClientInitState {
-        server_name: ActorName,
-    }
-
-    struct ClientState;
+    struct ClientInitState;
 
 
     impl ClientInit for ClientInitState {
     impl ClientInit for ClientInitState {
         type AfterActivate = ClientState;
         type AfterActivate = ClientState;
-        type HandleActivateFut = impl Future<Output = Result<Self::AfterActivate>>;
-        fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut {
-            async move {
-                let from = msg.rt.actor_name(msg.act_id);
-                // TODO: This implementation should not know about PingProtocolMsg. It should be
-                // able to send Ping directly.
-                msg.rt
-                    .send(self.server_name, from, PingProtocolMsg::Ping(Ping))
-                    .await?;
-                Ok(ClientState)
-            }
+        type HandleActivateFut = impl Future<Output = Result<(Self::AfterActivate, Ping)>>;
+        fn handle_activate(self, _msg: Activate) -> Self::HandleActivateFut {
+            ready(Ok((ClientState, Ping)))
         }
         }
     }
     }
 
 
+    struct ClientState;
+
     impl SentPing for ClientState {
     impl SentPing for ClientState {
-        type AfterPong = ReturnedState;
-        type HandlePongFut = Ready<Result<Self::AfterPong>>;
-        fn handle_pong(self, _msg: Envelope<Pong>) -> Self::HandlePongFut {
-            ready(Ok(ReturnedState))
+        type HandleReplyFut = Ready<Result<End>>;
+        fn handle_reply(self, _msg: PingReply) -> Self::HandleReplyFut {
+            ready(Ok(End))
         }
         }
     }
     }
 
 
+    #[allow(dead_code)]
+    enum PingClientState {
+        Init(ClientInitState),
+        SentPing(ClientState),
+        End(End),
+    }
+
     struct ServerInitState;
     struct ServerInitState;
 
 
-    struct ServerState {
-        rt: &'static Runtime,
-        act_id: Uuid,
-    }
+    struct ServerState;
 
 
     impl ServerInit for ServerInitState {
     impl ServerInit for ServerInitState {
         type AfterActivate = ServerState;
         type AfterActivate = ServerState;
         type HandleActivateFut = Ready<Result<Self::AfterActivate>>;
         type HandleActivateFut = Ready<Result<Self::AfterActivate>>;
-        fn handle_activate(self, msg: Activate) -> Self::HandleActivateFut {
-            ready(Ok(ServerState {
-                rt: msg.rt,
-                act_id: msg.act_id,
-            }))
+        fn handle_activate(self, _msg: Activate) -> Self::HandleActivateFut {
+            ready(Ok(ServerState))
         }
         }
     }
     }
 
 
     impl Listening for ServerState {
     impl Listening for ServerState {
-        type AfterPing = ReturnedState;
-        type HandlePingFut = impl Future<Output = Result<Self::AfterPing>>;
-        fn handle_ping(self, msg: Envelope<Ping>) -> Self::HandlePingFut {
-            async move {
-                let to = msg.from;
-                let from = self.rt.actor_name(self.act_id);
-                // TODO: This implementation should not know about PingProtocolMsg. It should be
-                // able to send Pong directly.
-                self.rt.send(to, from, PingProtocolMsg::Pong(Pong)).await?;
-                Ok(ReturnedState)
-            }
+        type HandlePingFut = impl Future<Output = Result<(End, PingReply)>>;
+        fn handle_ping(self, _msg: Ping) -> Self::HandlePingFut {
+            ready(Ok((End, PingReply)))
         }
         }
     }
     }
 
 
+    #[allow(dead_code)]
+    enum PingServerState {
+        ServerInit(ServerInitState),
+        Listening(ServerState),
+        End(End),
+    }
+
     async fn ping_server(
     async fn ping_server(
         counter: Arc<AtomicU8>,
         counter: Arc<AtomicU8>,
         rt: &'static Runtime,
         rt: &'static Runtime,
@@ -941,20 +933,22 @@ mod tests {
             PingServerState::Listening(state)
             PingServerState::Listening(state)
         };
         };
         while let Some(envelope) = mailbox.recv().await {
         while let Some(envelope) = mailbox.recv().await {
-            let (msg, replier, from) = envelope.split();
+            let (msg, replier, _from) = envelope.split();
             match (state, msg) {
             match (state, msg) {
                 (PingServerState::Listening(listening_state), PingProtocolMsg::Ping(msg)) => {
                 (PingServerState::Listening(listening_state), PingProtocolMsg::Ping(msg)) => {
-                    let envelope = Envelope::new(msg, replier, from);
-                    state = PingServerState::Returned(
-                        listening_state.handle_ping(envelope).await.unwrap(),
-                    );
+                    let (new_state, reply) = listening_state.handle_ping(msg).await.unwrap();
+                    state = PingServerState::End(new_state);
+                    if let Err(_) = replier.unwrap().send(PingProtocolMsg::PingReply(reply)) {
+                        panic!("Failed to send Ping reply.");
+                    }
                 }
                 }
-                _ => {
-                    log::error!("Ping protocol violation.");
-                    break;
+                (_prev_state, _) => {
+                    panic!("Ping protocol violation.");
+                    // A real implementation should assign the previous state and log the error.
+                    // state = prev_state;
                 }
                 }
             }
             }
-            if let PingServerState::Returned(_) = state {
+            if let PingServerState::End(_) = state {
                 break;
                 break;
             }
             }
         }
         }
@@ -965,30 +959,20 @@ mod tests {
         counter: Arc<AtomicU8>,
         counter: Arc<AtomicU8>,
         server_name: ActorName,
         server_name: ActorName,
         rt: &'static Runtime,
         rt: &'static Runtime,
-        mut mailbox: mpsc::Receiver<Envelope<PingProtocolMsg>>,
+        _mailbox: mpsc::Receiver<Envelope<PingProtocolMsg>>,
         act_id: Uuid,
         act_id: Uuid,
     ) {
     ) {
-        let mut state = {
-            let init = ClientInitState { server_name };
-            let state = init.handle_activate(Activate { rt, act_id }).await.unwrap();
-            PingClientState::SentPing(state)
-        };
-        while let Some(envelope) = mailbox.recv().await {
-            let (msg, replier, from) = envelope.split();
-            match (state, msg) {
-                (PingClientState::SentPing(curr_state), PingProtocolMsg::Pong(msg)) => {
-                    let envelope = Envelope::new(msg, replier, from);
-                    state =
-                        PingClientState::Returned(curr_state.handle_pong(envelope).await.unwrap());
-                }
-                _ => {
-                    log::error!("Ping protocol violation.");
-                    break;
-                }
-            }
-            if let PingClientState::Returned(_) = state {
-                break;
-            }
+        let init = ClientInitState;
+        let (state, msg) = init.handle_activate(Activate { rt, act_id }).await.unwrap();
+        let from = rt.actor_name(act_id);
+        let reply = rt
+            .call(server_name, from, PingProtocolMsg::Ping(msg))
+            .await
+            .unwrap();
+        if let PingProtocolMsg::PingReply(msg) = reply {
+            state.handle_reply(msg).await.unwrap();
+        } else {
+            panic!("Incorrect message type sent in reply to Ping.");
         }
         }
         counter.fetch_sub(1, Ordering::SeqCst);
         counter.fetch_sub(1, Ordering::SeqCst);
     }
     }
@@ -1017,10 +1001,29 @@ mod tests {
             while counter.load(Ordering::SeqCst) > 0 && Instant::now() < deadline {
             while counter.load(Ordering::SeqCst) > 0 && Instant::now() < deadline {
                 tokio::time::sleep(Duration::from_millis(20)).await;
                 tokio::time::sleep(Duration::from_millis(20)).await;
             }
             }
+            // Check that both tasks finished successfully and we didn't just timeout.
+            assert_eq!(0, counter.load(Ordering::SeqCst));
 
 
             // TODO: Should actor which return be removed from the runtime automatically?
             // TODO: Should actor which return be removed from the runtime automatically?
             RUNTIME.take(&server_name).await.unwrap();
             RUNTIME.take(&server_name).await.unwrap();
             RUNTIME.take(&client_name).await.unwrap();
             RUNTIME.take(&client_name).await.unwrap();
         });
         });
     }
     }
+
+    // Here's another protocol example. This is the Customer and Travel Agency protocol used as an
+    // example in the survey paper "Behavioral Types in Programming Languages."
+    //
+    // protocol! {
+    //     CustomerInit?Activate -> Choosing
+    //     AgencyInit?Activate -> Listening
+    //     Choosing?Choice -> Choosing, Listening!Query|Accept|Reject
+    //     Listening?Query -> Listening, Choosing!Query::Reply
+    //     Choosing?Query::Reply -> Choosing
+    //     Listening?Accept -> End, Choosing!Accept::Reply
+    //     Choosing?Accept::Reply -> End
+    //     Listening?Reject -> End, Choosing!Reject:Reply
+    //     Choosing?Reject::Reply -> End
+    // }
+    //
+    // The Choice message is from the runtime itself. It represents receiving input from a user.
 }
 }

+ 1 - 1
crates/btmsg/Cargo.lock → crates/bttp/Cargo.lock

@@ -206,7 +206,7 @@ dependencies = [
 ]
 ]
 
 
 [[package]]
 [[package]]
-name = "btmsg"
+name = "bttp"
 version = "0.1.0"
 version = "0.1.0"
 dependencies = [
 dependencies = [
  "btlib",
  "btlib",

+ 1 - 1
crates/btmsg/Cargo.toml → crates/bttp/Cargo.toml

@@ -1,5 +1,5 @@
 [package]
 [package]
-name = "btmsg"
+name = "bttp"
 version = "0.1.0"
 version = "0.1.0"
 edition = "2021"
 edition = "2021"
 
 

+ 0 - 0
crates/btmsg/src/common.rs → crates/bttp/src/common.rs


+ 1 - 1
crates/btmsg/src/lib.rs → crates/bttp/src/lib.rs

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // SPDX-License-Identifier: AGPL-3.0-or-later
 //! This crate contains the implementation of the secure message transport `bttp`.
 //! This crate contains the implementation of the secure message transport `bttp`.
-//! 
+//!
 //! A `bttp` server is implemented by [Receiver] and a client by [Transmitter].
 //! A `bttp` server is implemented by [Receiver] and a client by [Transmitter].
 #![feature(impl_trait_in_assoc_type)]
 #![feature(impl_trait_in_assoc_type)]
 
 

+ 0 - 0
crates/btmsg/src/receiver.rs → crates/bttp/src/receiver.rs


+ 0 - 0
crates/btmsg/src/serialization.rs → crates/bttp/src/serialization.rs


+ 0 - 0
crates/btmsg/src/tls.rs → crates/bttp/src/tls.rs


+ 0 - 0
crates/btmsg/src/transmitter.rs → crates/bttp/src/transmitter.rs


+ 1 - 1
crates/btmsg/tests/tests.rs → crates/bttp/tests/tests.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // SPDX-License-Identifier: AGPL-3.0-or-later
 #![feature(impl_trait_in_assoc_type)]
 #![feature(impl_trait_in_assoc_type)]
 
 
-use btmsg::*;
+use bttp::*;
 
 
 use btlib::{
 use btlib::{
     crypto::{ConcreteCreds, Creds, CredsPriv},
     crypto::{ConcreteCreds, Creds, CredsPriv},

+ 1 - 1
website/content/en/_index.html

@@ -41,7 +41,7 @@ Information in the filesystem secured with confidentiality and integrity protect
 Key management is handled by the platform.
 Key management is handled by the platform.
 {{% /blocks/feature %}}
 {{% /blocks/feature %}}
 
 
-{{% blocks/feature icon="fa-solid fa-envelope" title="Message Passing" url="./rustdoc/btmsg/index.html" %}}
+{{% blocks/feature icon="fa-solid fa-envelope" title="Message Passing" url="./rustdoc/bttp/index.html" %}}
 Apps are implemented as message passing actors.
 Apps are implemented as message passing actors.
 Messages are addressed using filesystem paths.
 Messages are addressed using filesystem paths.
 The platform uses mutual TLS authentication to ensure your messages are only seen by their intended
 The platform uses mutual TLS authentication to ensure your messages are only seen by their intended

+ 12 - 0
website/deploy-linode.sh

@@ -0,0 +1,12 @@
+#!/bin/sh
+# Deploys the site using s3cmd.
+# Make sure 'website/public/' has been purged then updated  using 'docs/build-docs.sh'
+# before running this script.
+# If you don't purge 'website/public/', you may get unexpected results.
+# To display information about the website configuration on Linode run:
+# ```s3cmd ws-info s3://blocktree```
+# If you need to setup s3cmd checkout the documentation on Linode's website:
+# https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/
+# The guide for deploying a Hugo site is also useful:
+# https://www.linode.com/docs/guides/host-static-site-object-storage/
+s3cmd --no-mime-magic --acl-public --delete-removed --delete-after sync public/ s3://www.blocktree.systems

+ 3 - 11
website/deploy.sh

@@ -1,12 +1,4 @@
 #!/bin/sh
 #!/bin/sh
-# Deploys the site using s3cmd.
-# Make sure 'website/public/' has been purged then updated  using 'docs/build-docs.sh'
-# before running this script.
-# Note that you must purge 'website/public/' or you may get unexpected results.
-# To display information about the website configuration on Linode run:
-# ```s3cmd ws-info s3://blocktree```
-# If you need to setup s3cmd checkout the documentation on Linode's website:
-# https://www.linode.com/docs/products/storage/object-storage/guides/s3cmd/
-# The guide for deploying a Hugo site is also useful:
-# https://www.linode.com/docs/guides/host-static-site-object-storage/
-s3cmd --no-mime-magic --acl-public --delete-removed --delete-after sync public/ s3://www.blocktree.systems
+# Deploys the site to freja using rsync.
+echo Deploying to freja...
+rsync -rav --delete public/ freja:/srv/http/www.blocktree.systems/