move everything into http module

This commit is contained in:
dr-frmr 2023-11-17 12:59:52 -05:00
parent 18df6332b4
commit b39531166e
No known key found for this signature in database
10 changed files with 183 additions and 651 deletions

View File

@ -1,51 +1,15 @@
use crate::types::*;
use crate::http::types::*;
use anyhow::Result;
use http::header::{HeaderMap, HeaderName, HeaderValue};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use thiserror::Error;
// Test http_client with these commands in the terminal
// !message our http_client {"method": "GET", "url": "https://jsonplaceholder.typicode.com/posts", "headers": {}}
// !message our http_client {"method": "POST", "url": "https://jsonplaceholder.typicode.com/posts", "headers": {"Content-Type": "application/json"}}
// !message our http_client {"method": "PUT", "url": "https://jsonplaceholder.typicode.com/posts", "headers": {"Content-Type": "application/json"}}
//
// http_client.rs types
//
#[derive(Debug, Serialize, Deserialize)]
pub struct HttpRequest {
pub method: String, // must parse to http::Method
pub version: Option<String>, // must parse to http::Version
pub url: String, // must parse to url::Url
pub headers: HashMap<String, String>,
// BODY is stored in the payload, as bytes
// TIMEOUT is stored in the message expect_response
}
#[derive(Debug, Serialize, Deserialize)]
pub struct HttpResponse {
pub status: u16,
pub headers: HashMap<String, String>,
// BODY is stored in the payload, as bytes
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum HttpClientError {
#[error("http_client: request could not be parsed to HttpRequest: {}.", req)]
BadRequest { req: String },
#[error("http_client: http method not supported: {}", method)]
BadMethod { method: String },
#[error("http_client: url could not be parsed: {}", url)]
BadUrl { url: String },
#[error("http_client: http version not supported: {}", version)]
BadVersion { version: String },
#[error("http_client: failed to execute request {}", error)]
RequestFailed { error: String },
}
pub async fn http_client(
our_name: String,
send_to_loop: MessageSender,

4
src/http/mod.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod client;
pub mod server;
pub mod types;
pub mod utils;

View File

@ -1,11 +1,10 @@
use crate::http_server::server_fns::*;
use crate::http::utils::*;
use crate::http::types::*;
use crate::register;
use crate::types::*;
use anyhow::Result;
use futures::SinkExt;
use futures::StreamExt;
use route_recognizer::Router;
use std::collections::HashMap;
use std::net::SocketAddr;
@ -17,16 +16,26 @@ use warp::http::{header::HeaderValue, StatusCode};
use warp::ws::{WebSocket, Ws};
use warp::{Filter, Reply};
mod server_fns;
// types and constants
type HttpSender = tokio::sync::oneshot::Sender<HttpResponse>;
type HttpResponseSenders = Arc<Mutex<HashMap<u64, (String, HttpSender)>>>;
type PathBindings = Arc<RwLock<Router<BoundPath>>>;
// node -> ID -> random ID
/// http driver
/// HTTP server: a runtime module that handles HTTP requests at a given port.
/// The server accepts bindings-requests from apps. These can be used in two ways:
///
/// 1. The app can bind to a path and receive all subsequent requests in the form
/// of an [`HttpRequest`] to that path.
/// They will be responsible for generating HTTP responses in the form of an
/// [`HttpResponse`] to those requests.
///
/// 2. The app can bind static content to a path. The server will handle all subsequent
/// requests, serving that static content. It will only respond to `GET` requests.
///
///
/// In addition to binding on paths, the HTTP server can receive incoming WebSocket connections
/// and pass them to a targeted app. The server will handle encrypting and decrypting messages
/// over these connections.
pub async fn http_server(
our_name: String,
our_port: u16,
@ -37,7 +46,6 @@ pub async fn http_server(
) -> Result<()> {
let http_response_senders = Arc::new(Mutex::new(HashMap::new()));
let websockets: WebSockets = Arc::new(Mutex::new(HashMap::new()));
let ws_proxies: WebSocketProxies = Arc::new(Mutex::new(HashMap::new())); // channel_id -> node
// Add RPC path
let mut bindings_map: Router<BoundPath> = Router::new();
@ -49,15 +57,6 @@ pub async fn http_server(
};
bindings_map.add("/rpc:sys:uqbar/message", rpc_bound_path);
// Add encryptor binding
let encryptor_bound_path = BoundPath {
app: ProcessId::from_str("encryptor:sys:uqbar").unwrap(),
authenticated: false,
local_only: true,
original_path: "/encryptor:sys:uqbar".to_string(),
};
bindings_map.add("/encryptor:sys:uqbar", encryptor_bound_path);
let path_bindings: PathBindings = Arc::new(RwLock::new(bindings_map));
let _ = tokio::join!(
@ -90,7 +89,6 @@ pub async fn http_server(
http_response_senders.clone(),
path_bindings.clone(),
websockets.clone(),
ws_proxies.clone(),
jwt_secret_bytes.clone(),
send_to_loop.clone(),
print_tx.clone(),
@ -848,13 +846,3 @@ async fn handler(
}
Ok(response)
}
pub async fn find_open_port(start_at: u16) -> Option<u16> {
for port in start_at..=u16::MAX {
let bind_addr = format!("0.0.0.0:{}", port);
if is_port_available(&bind_addr).await {
return Some(port);
}
}
None
}

121
src/http/types.rs Normal file
View File

@ -0,0 +1,121 @@
use crate::types::Address;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;
/// HTTP Request type that can be shared over WASM boundary to apps.
#[derive(Debug, Serialize, Deserialize)]
pub struct HttpRequest {
pub method: String, // must parse to http::Method
pub version: Option<String>, // must parse to http::Version
pub url: String, // must parse to url::Url
pub headers: HashMap<String, String>,
// BODY is stored in the payload, as bytes
// TIMEOUT is stored in the message expect_response
}
/// HTTP Response type that can be shared over WASM boundary to apps.
#[derive(Debug, Serialize, Deserialize)]
pub struct HttpResponse {
pub status: u16,
pub headers: HashMap<String, String>,
// BODY is stored in the payload, as bytes
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum HttpClientError {
#[error("http_client: request could not be parsed to HttpRequest: {}.", req)]
BadRequest { req: String },
#[error("http_client: http method not supported: {}", method)]
BadMethod { method: String },
#[error("http_client: url could not be parsed: {}", url)]
BadUrl { url: String },
#[error("http_client: http version not supported: {}", version)]
BadVersion { version: String },
#[error("http_client: failed to execute request {}", error)]
RequestFailed { error: String },
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum HttpServerError {
#[error("http_server: json is None")]
NoJson,
#[error("http_server: response not ok")]
ResponseError,
#[error("http_server: bytes are None")]
NoBytes,
#[error(
"http_server: JSON payload could not be parsed to HttpClientRequest: {error}. Got {:?}.",
json
)]
BadJson { json: String, error: String },
#[error("http_server: path binding error: {:?}", error)]
PathBind { error: String },
}
#[derive(Debug, Serialize, Deserialize)]
pub struct JwtClaims {
pub username: String,
pub expiration: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WebSocketServerTarget {
pub node: String,
pub id: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WebSocketPush {
pub target: WebSocketServerTarget,
pub is_text: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ServerAction {
pub action: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum HttpServerAction {
BindPath {
path: String,
authenticated: bool,
local_only: bool,
},
WebSocketPush(WebSocketPush),
ServerAction(ServerAction),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WsRegister {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WsMessage {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
pub target: Address,
pub json: Option<serde_json::Value>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EncryptedWsMessage {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
pub target: Address,
pub encrypted: String, // Encrypted JSON as hex with the 32-byte authentication tag appended
pub nonce: String, // Hex of the 12-byte nonce
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum WebSocketClientMessage {
WsRegister(WsRegister),
WsMessage(WsMessage),
EncryptedWsMessage(EncryptedWsMessage),
}

View File

@ -1,3 +1,4 @@
use crate::http::types::*;
use crate::types::*;
use futures::stream::SplitSink;
use hmac::{Hmac, Mac};
@ -230,6 +231,16 @@ pub fn deserialize_headers(hashmap: HashMap<String, String>) -> HeaderMap {
header_map
}
pub async fn find_open_port(start_at: u16) -> Option<u16> {
for port in start_at..=u16::MAX {
let bind_addr = format!("0.0.0.0:{}", port);
if is_port_available(&bind_addr).await {
return Some(port);
}
}
None
}
pub async fn is_port_available(bind_addr: &str) -> bool {
TcpListener::bind(bind_addr).await.is_ok()
}

View File

@ -2169,7 +2169,7 @@ async fn make_event_loop(
let _ = persist_state(&our_name, &send_to_loop, &process_map).await;
let _ = responder.send(true);
},
t::CapMessage::Drop { on, cap, responder } => {
t::CapMessage::_Drop { on, cap, responder } => {
// remove cap from process map
let Some(entry) = process_map.get_mut(&on) else {
let _ = responder.send(false);

View File

@ -1,422 +0,0 @@
use super::bindings::component::uq_process::types as wit;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
//
// process-facing kernel types, used for process
// management and message-passing
// matches types in uqbar.wit
//
pub type Context = Vec<u8>;
pub type NodeId = String; // QNS domain name
/// process ID is a formatted unique identifier that contains
/// the publishing node's ID, the package name, and finally the process name.
/// the process name can be a random number, or a name chosen by the user.
/// the formatting is as follows:
/// `[process name]:[package name]:[node ID]`
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct ProcessId {
process_name: String,
package_name: String,
publisher_node: NodeId,
}
#[allow(dead_code)]
impl ProcessId {
/// generates a random u64 number if process_name is not declared
pub fn new(process_name: &str, package_name: &str, publisher_node: &str) -> Self {
ProcessId {
process_name: process_name.into(),
package_name: package_name.into(),
publisher_node: publisher_node.into(),
}
}
pub fn from_str(input: &str) -> Result<Self, ProcessIdParseError> {
// split string on colons into 3 segments
let mut segments = input.split(':');
let process_name = segments
.next()
.ok_or(ProcessIdParseError::MissingField)?
.to_string();
let package_name = segments
.next()
.ok_or(ProcessIdParseError::MissingField)?
.to_string();
let publisher_node = segments
.next()
.ok_or(ProcessIdParseError::MissingField)?
.to_string();
if segments.next().is_some() {
return Err(ProcessIdParseError::TooManyColons);
}
Ok(ProcessId {
process_name,
package_name,
publisher_node,
})
}
pub fn to_string(&self) -> String {
[
self.process_name.as_str(),
self.package_name.as_str(),
self.publisher_node.as_str(),
]
.join(":")
}
pub fn process(&self) -> &str {
&self.process_name
}
pub fn package(&self) -> &str {
&self.package_name
}
pub fn publisher_node(&self) -> &str {
&self.publisher_node
}
pub fn en_wit(&self) -> wit::ProcessId {
wit::ProcessId {
process_name: self.process_name.clone(),
package_name: self.package_name.clone(),
publisher_node: self.publisher_node.clone(),
}
}
pub fn de_wit(wit: wit::ProcessId) -> ProcessId {
ProcessId {
process_name: wit.process_name,
package_name: wit.package_name,
publisher_node: wit.publisher_node,
}
}
}
#[derive(Debug)]
pub enum ProcessIdParseError {
TooManyColons,
MissingField,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct Address {
pub node: NodeId,
pub process: ProcessId,
}
impl Address {
pub fn en_wit(&self) -> wit::Address {
wit::Address {
node: self.node.clone(),
process: self.process.en_wit(),
}
}
pub fn de_wit(wit: wit::Address) -> Address {
Address {
node: wit.node,
process: ProcessId {
process_name: wit.process.process_name,
package_name: wit.process.package_name,
publisher_node: wit.process.publisher_node,
},
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Payload {
pub mime: Option<String>, // MIME type
pub bytes: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Request {
pub inherit: bool,
pub expects_response: Option<u64>, // number of seconds until timeout
pub ipc: Vec<u8>,
pub metadata: Option<String>, // JSON-string
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Response {
pub inherit: bool,
pub ipc: Vec<u8>,
pub metadata: Option<String>, // JSON-string
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Message {
Request(Request),
Response((Response, Option<Context>)),
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct Capability {
pub issuer: Address,
pub params: String, // JSON-string
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct SignedCapability {
pub issuer: Address,
pub params: String, // JSON-string
pub signature: Vec<u8>, // signed by the kernel, so we can verify that the kernel issued it
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SendError {
pub kind: SendErrorKind,
pub target: Address,
pub message: Message,
pub payload: Option<Payload>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum SendErrorKind {
Offline,
Timeout,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum OnPanic {
None,
Restart,
Requests(Vec<(Address, Request, Option<Payload>)>),
}
impl OnPanic {
pub fn is_restart(&self) -> bool {
match self {
OnPanic::None => false,
OnPanic::Restart => true,
OnPanic::Requests(_) => false,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum KernelCommand {
StartProcess {
id: ProcessId,
wasm_bytes_handle: u128,
on_panic: OnPanic,
initial_capabilities: HashSet<SignedCapability>,
public: bool,
},
KillProcess(ProcessId), // this is extrajudicial killing: we might lose messages!
// kernel only
RebootProcess {
process_id: ProcessId,
persisted: PersistedProcess,
},
Shutdown,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum KernelResponse {
StartedProcess,
StartProcessError,
KilledProcess(ProcessId),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PersistedProcess {
pub wasm_bytes_handle: u128,
// pub drive: String,
// pub full_path: String,
pub on_panic: OnPanic,
pub capabilities: HashSet<Capability>,
pub public: bool, // marks if a process allows messages from any process
}
#[derive(Debug, Serialize, Deserialize)]
pub struct VfsRequest {
pub drive: String,
pub action: VfsAction,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum VfsAction {
New,
Add {
full_path: String,
entry_type: AddEntryType,
},
Rename {
full_path: String,
new_full_path: String,
},
Delete(String),
WriteOffset {
full_path: String,
offset: u64,
},
SetSize {
full_path: String,
size: u64,
},
GetPath(u128),
GetHash(String),
GetEntry(String),
GetFileChunk {
full_path: String,
offset: u64,
length: u64,
},
GetEntryLength(String),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum AddEntryType {
Dir,
NewFile, // add a new file to fs and add name in vfs
ExistingFile { hash: u128 }, // link an existing file in fs to a new name in vfs
ZipArchive,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum GetEntryType {
Dir,
File,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum VfsResponse {
Ok,
Err(VfsError),
GetPath(Option<String>),
GetHash(Option<u128>),
GetEntry {
// file bytes in payload, if entry was a file
is_file: bool,
children: Vec<String>,
},
GetFileChunk, // chunk in payload
GetEntryLength(u64),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum VfsError {
BadDriveName,
BadDescriptor,
NoCap,
EntryNotFound,
}
#[allow(dead_code)]
impl VfsError {
pub fn kind(&self) -> &str {
match *self {
VfsError::BadDriveName => "BadDriveName",
VfsError::BadDescriptor => "BadDescriptor",
VfsError::NoCap => "NoCap",
VfsError::EntryNotFound => "EntryNotFound",
}
}
}
//
// package types
//
pub type PackageVersion = (u32, u32, u32);
/// the type that gets deserialized from `metadata.json` in a package
#[derive(Debug, Serialize, Deserialize)]
pub struct PackageMetadata {
pub package: String,
pub publisher: String,
pub version: PackageVersion,
pub description: Option<String>,
pub website: Option<String>,
}
/// the type that gets deserialized from each entry in the array in `manifest.json`
#[derive(Debug, Serialize, Deserialize)]
pub struct PackageManifestEntry {
pub process_name: String,
pub process_wasm_path: String,
pub on_panic: OnPanic,
pub request_networking: bool,
pub request_messaging: Vec<String>,
pub public: bool,
}
//
// conversions between wit types and kernel types (annoying!)
//
pub fn de_wit_request(wit: wit::Request) -> Request {
Request {
inherit: wit.inherit,
expects_response: wit.expects_response,
ipc: wit.ipc,
metadata: wit.metadata,
}
}
pub fn en_wit_request(request: Request) -> wit::Request {
wit::Request {
inherit: request.inherit,
expects_response: request.expects_response,
ipc: request.ipc,
metadata: request.metadata,
}
}
pub fn de_wit_response(wit: wit::Response) -> Response {
Response {
inherit: wit.inherit,
ipc: wit.ipc,
metadata: wit.metadata,
}
}
pub fn en_wit_response(response: Response) -> wit::Response {
wit::Response {
inherit: response.inherit,
ipc: response.ipc,
metadata: response.metadata,
}
}
pub fn de_wit_payload(wit: Option<wit::Payload>) -> Option<Payload> {
match wit {
None => None,
Some(wit) => Some(Payload {
mime: wit.mime,
bytes: wit.bytes,
}),
}
}
pub fn en_wit_payload(load: Option<Payload>) -> Option<wit::Payload> {
match load {
None => None,
Some(load) => Some(wit::Payload {
mime: load.mime,
bytes: load.bytes,
}),
}
}
pub fn de_wit_signed_capability(wit: wit::SignedCapability) -> SignedCapability {
SignedCapability {
issuer: Address {
node: wit.issuer.node,
process: ProcessId {
process_name: wit.issuer.process.process_name,
package_name: wit.issuer.process.package_name,
publisher_node: wit.issuer.process.publisher_node,
},
},
params: wit.params,
signature: wit.signature,
}
}
pub fn en_wit_signed_capability(cap: SignedCapability) -> wit::SignedCapability {
wit::SignedCapability {
issuer: cap.issuer.en_wit(),
params: cap.params,
signature: cap.signature,
}
}

View File

@ -10,8 +10,7 @@ use tokio::{fs, time::timeout};
mod eth_rpc;
mod filesystem;
mod http_client;
mod http_server;
mod http;
mod kernel;
mod keygen;
mod net;
@ -193,7 +192,7 @@ async fn main() {
// username, networking key, and routing info.
// if any do not match, we should prompt user to create a "transaction"
// that updates their PKI info on-chain.
let http_server_port = http_server::find_open_port(8080).await.unwrap();
let http_server_port = http::utils::find_open_port(8080).await.unwrap();
println!("login or register at http://localhost:{}", http_server_port);
let (kill_tx, kill_rx) = oneshot::channel::<bool>();
@ -317,7 +316,7 @@ async fn main() {
fs_kill_recv,
fs_kill_confirm_send,
));
tasks.spawn(http_server::http_server(
tasks.spawn(http::server::http_server(
our.name.clone(),
http_server_port,
decoded_keyfile.jwt_secret_bytes.clone(),
@ -325,7 +324,7 @@ async fn main() {
kernel_message_sender.clone(),
print_sender.clone(),
));
tasks.spawn(http_client::http_client(
tasks.spawn(http::client::http_client(
our.name.clone(),
kernel_message_sender.clone(),
http_client_receiver,

View File

@ -17,7 +17,6 @@ use warp::{
Filter, Rejection, Reply,
};
use crate::http_server;
use crate::keygen;
use crate::types::*;
@ -29,7 +28,7 @@ pub fn generate_jwt(jwt_secret_bytes: &[u8], username: String) -> Option<String>
Err(_) => return None,
};
let claims = JwtClaims {
let claims = crate::http::types::JwtClaims {
username: username.clone(),
expiration: 0,
};
@ -304,7 +303,7 @@ async fn handle_info(
};
// TODO: if IP is localhost, don't allow registration as direct
let ws_port = http_server::find_open_port(9000).await.unwrap();
let ws_port = crate::http::utils::find_open_port(9000).await.unwrap();
let our = Identity {
networking_key: format!("0x{}", public_key),

View File

@ -18,10 +18,10 @@ lazy_static::lazy_static! {
//
// types shared between kernel and processes. frustratingly, this is an exact copy
// of the types in process_lib/src/kernel_types.rs
// of the types in process_lib
// this is because even though the types are identical, they will not match when
// used in the kernel context which generates bindings differently than the process
// standard library. make sure to keep this synced with kernel_types.rs
// standard library. make sure to keep this synced with process_lib.
//
pub type Context = Vec<u8>;
pub type NodeId = String; // QNS domain name
@ -382,7 +382,7 @@ pub fn de_wit_on_panic(wit: wit::OnPanic) -> OnPanic {
}
}
//
// END SYNC WITH kernel_types.rs
// END SYNC WITH process_lib
//
//
@ -488,6 +488,24 @@ pub struct KernelMessage {
pub signed_capabilities: Option<Vec<SignedCapability>>,
}
impl std::fmt::Display for KernelMessage {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{{\n id: {},\n source: {},\n target: {},\n rsvp: {},\n message: {},\n payload: {}\n}}",
self.id,
self.source,
self.target,
match &self.rsvp {
Some(rsvp) => rsvp.to_string(),
None => "None".to_string()
},
self.message,
self.payload.is_some(),
)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WrappedSendError {
pub id: u64,
@ -509,17 +527,6 @@ pub struct Printout {
// -> kernel sets `Some(A) = Rsvp` for B's request to C
pub type Rsvp = Option<Address>;
//
// boot/startup specific types???
//
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BootOutboundRequest {
pub target_process: ProcessId,
pub json: Option<String>,
pub bytes: Option<Vec<u8>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum DebugCommand {
Toggle,
@ -545,7 +552,6 @@ pub enum KernelCommand {
Shutdown,
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum CapMessage {
Add {
@ -553,7 +559,7 @@ pub enum CapMessage {
cap: Capability,
responder: tokio::sync::oneshot::Sender<bool>,
},
Drop {
_Drop {
// not used yet!
on: ProcessId,
cap: Capability,
@ -598,14 +604,6 @@ pub struct ProcessContext {
pub context: Option<Context>,
}
//
// runtime-module-specific types
//
//
// filesystem.rs types
//
pub type PackageVersion = (u32, u32, u32);
/// the type that gets deserialized from `metadata.json` in a package
@ -832,133 +830,3 @@ impl VfsError {
}
}
}
//
// custom kernel displays
//
impl std::fmt::Display for KernelMessage {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{{\n id: {},\n source: {},\n target: {},\n rsvp: {},\n message: {},\n payload: {}\n}}",
self.id,
self.source,
self.target,
match &self.rsvp {
Some(rsvp) => rsvp.to_string(),
None => "None".to_string()
},
self.message,
self.payload.is_some(),
)
}
}
//
// http_server.rs types
//
#[derive(Debug, Serialize, Deserialize)]
pub struct HttpResponse {
pub status: u16,
pub headers: HashMap<String, String>,
pub body: Option<Vec<u8>>, // TODO does this use a lot of memory?
}
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum HttpServerError {
#[error("http_server: json is None")]
NoJson,
#[error("http_server: response not ok")]
ResponseError,
#[error("http_server: bytes are None")]
NoBytes,
#[error(
"http_server: JSON payload could not be parsed to HttpClientRequest: {error}. Got {:?}.",
json
)]
BadJson { json: String, error: String },
#[error("http_server: path binding error: {:?}", error)]
PathBind { error: String },
}
#[allow(dead_code)]
impl HttpServerError {
pub fn kind(&self) -> &str {
match *self {
HttpServerError::NoJson { .. } => "NoJson",
HttpServerError::NoBytes { .. } => "NoBytes",
HttpServerError::BadJson { .. } => "BadJson",
HttpServerError::ResponseError { .. } => "ResponseError",
HttpServerError::PathBind { .. } => "PathBind",
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct JwtClaims {
pub username: String,
pub expiration: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WebSocketServerTarget {
pub node: String,
pub id: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WebSocketPush {
pub target: WebSocketServerTarget,
pub is_text: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ServerAction {
pub action: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum HttpServerMessage {
BindPath {
path: String,
authenticated: bool,
local_only: bool,
},
WebSocketPush(WebSocketPush),
ServerAction(ServerAction),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WsRegister {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WsMessage {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
pub target: Address,
pub json: Option<serde_json::Value>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EncryptedWsMessage {
pub ws_auth_token: String,
pub auth_token: String,
pub channel_id: String,
pub target: Address,
pub encrypted: String, // Encrypted JSON as hex with the 32-byte authentication tag appended
pub nonce: String, // Hex of the 12-byte nonce
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum WebSocketClientMessage {
WsRegister(WsRegister),
WsMessage(WsMessage),
EncryptedWsMessage(EncryptedWsMessage),
}