Skip to content
This repository was archived by the owner on Feb 3, 2023. It is now read-only.

WIP: Splitting Context into ConductorContext and InstanceContext #2064

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/conductor_lib/src/conductor/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ impl Conductor {
/// and
/// - dna_hash_computed_from_file: from the hash computed from the loaded DNA of the file.dna
fn check_dna_consistency_from_all_sources(
ctx: &holochain_core::context::Context,
ctx: &holochain_core::context::ConductorContext,
dna_hash_from_conductor_config: &HashString,
dna_hash_computed: &HashString,
dna_hash_computed_from_file: &HashString,
Expand Down
5 changes: 3 additions & 2 deletions crates/conductor_lib/src/context_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::{
};

use holochain_metrics::{DefaultMetricPublisher, MetricPublisher, MetricPublisherConfig};
use holochain_core::context::ConductorContext;

/// This type helps building [context objects](struct.Context.html) that need to be
/// passed in to Holochain intances.
Expand Down Expand Up @@ -190,7 +191,7 @@ impl ContextBuilder {
/// Actually creates the context.
/// Defaults to memory storages, an in-memory network config and a fake agent called "alice".
/// The persister gets set to SimplePersister based on the chain storage.
pub fn spawn(self) -> Context {
pub fn spawn(self) -> ConductorContext {
let chain_storage = self
.chain_storage
.unwrap_or_else(|| Arc::new(RwLock::new(MemoryStorage::new())));
Expand All @@ -204,7 +205,7 @@ impl ContextBuilder {
.metric_publisher
.unwrap_or_else(|| Arc::new(RwLock::new(DefaultMetricPublisher::default())));

Context::new(
ConductorContext::new(
&self
.instance_name
.unwrap_or_else(|| "Anonymous-instance".to_string()),
Expand Down
35 changes: 15 additions & 20 deletions crates/conductor_lib/src/holochain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ use jsonrpc_core::IoHandler;
use std::sync::Arc;

use holochain_metrics::with_latency_publishing;
use holochain_core::context::ConductorContext;

/// contains a Holochain application instance
pub struct Holochain {
Expand All @@ -126,9 +127,7 @@ pub struct Holochain {
impl Holochain {
/// create a new Holochain instance. Ensure that they are built w/ the same
/// HDK Version, or log a warning.
pub fn new(dna: Dna, context: Arc<Context>) -> HolochainResult<Self> {
let instance = Instance::new(context.clone());

pub fn new(dna: Dna, conductor_context: Arc<ConductorContext>) -> HolochainResult<Self> {
for zome in dna.zomes.values() {
let maybe_json_string = run_dna(
Some("{}".as_bytes().to_vec()),
Expand All @@ -149,23 +148,17 @@ impl Holochain {
}
}

Self::from_dna_and_context_and_instance(dna, context, instance)
}
let new_state = StateWrapper::new(conductor_context.clone());
let mut instance = Instance::new(new_state, conductor_context.clone());

fn from_dna_and_context_and_instance(
dna: Dna,
context: Arc<Context>,
mut instance: Instance,
) -> HolochainResult<Self> {
let name = dna.name.clone();
let result = instance.initialize(Some(dna), context.clone());
let result = instance.initialize(Some(dna), conductor_context.clone());

match result {
Ok(new_context) => {
Ok(instance_context) => {
log_debug!(context, "conductor: {} instantiated", name);
let hc = Holochain {
instance: Some(instance),
context: Some(new_context),
context: Some(instance_context),
active: false,
};
Ok(hc)
Expand All @@ -174,16 +167,18 @@ impl Holochain {
}
}

pub fn load(context: Arc<Context>) -> Result<Self, HolochainError> {
let persister = SimplePersister::new(context.dht_storage.clone());
let loaded_state = persister.load(context.clone())?.ok_or_else(|| {

pub fn load(conductor_context: Arc<ConductorContext>) -> Result<Self, HolochainError> {
let persister = SimplePersister::new(conductor_context.dht_storage.clone());
let loaded_state = persister.load(conductor_context.clone())?.ok_or_else(|| {
HolochainError::ErrorGeneric("State could not be loaded due to NoneError".to_string())
})?;
let mut instance = Instance::from_state(loaded_state, context.clone());
let new_context = instance.initialize(None, context)?;
let loaded_state = StateWrapper::from(loaded_state);
let mut instance = Instance::new(loaded_state, conductor_context.clone());
let instance_context = instance.initialize(None, conductor_context)?;
Ok(Holochain {
instance: Some(instance),
context: Some(new_context),
context: Some(instance_context),
active: false,
})
}
Expand Down
4 changes: 0 additions & 4 deletions crates/core/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::{
network::{
direct_message::DirectMessage,
entry_aspect::EntryAspect,
entry_with_header::EntryWithHeader,
query::{GetLinksNetworkQuery, NetworkQueryResult},
state::NetworkState,
},
Expand Down Expand Up @@ -126,9 +125,6 @@ pub enum Action {
/// Does not validate, assumes referenced entry is valid.
HoldAspect(EntryAspect),

//action for updating crudstatus
CrudStatus((EntryWithHeader, CrudStatus)),

// ----------------
// Network actions:
// ----------------
Expand Down
113 changes: 70 additions & 43 deletions crates/core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,32 +78,22 @@ pub struct InstanceStats {
pub offline: bool,
}

/// Context holds the components that parts of a Holochain instance need in order to operate.
/// This includes components that are injected from the outside like persister
/// but also the store of the instance that gets injected before passing on the context
/// to inner components/reducers.
#[derive(Clone)]
pub struct Context {
pub struct ConductorContext {
pub(crate) instance_name: String,
pub agent_id: AgentId,
pub persister: Arc<RwLock<dyn Persister>>,
state: Option<Arc<RwLock<StateWrapper>>>,
pub action_channel: Option<Sender<ActionWrapper>>,
pub observer_channel: Option<Sender<Observer>>,
pub chain_storage: Arc<RwLock<dyn ContentAddressableStorage>>,
pub dht_storage: Arc<RwLock<dyn ContentAddressableStorage>>,
pub eav_storage: Arc<RwLock<dyn EntityAttributeValueStorage<Attribute>>>,
pub p2p_config: P2pConfig,
pub conductor_api: ConductorApi,
pub(crate) signal_tx: Option<Sender<Signal>>,
pub(crate) instance_is_alive: Arc<AtomicBool>,
pub state_dump_logging: bool,
thread_pool: ThreadPool,
pub redux_wants_write: Arc<AtomicBool>,
pub metric_publisher: Arc<RwLock<dyn MetricPublisher>>,
pub(crate) signal_tx: Sender<Signal>,
pub thread_pool: ThreadPool,
}

impl Context {
impl ConductorContext {
// test_check_conductor_api() is used to inject a conductor_api with a working
// mock of agent/sign to be used in tests.
// There are two different implementations of this function below which get pulled
Expand All @@ -130,7 +120,6 @@ impl Context {
conductor_api.unwrap_or_else(|| Arc::new(RwLock::new(mock_conductor_api(agent_id))))
}

#[allow(clippy::too_many_arguments)]
pub fn new(
instance_name: &str,
agent_id: AgentId,
Expand All @@ -140,18 +129,14 @@ impl Context {
eav: Arc<RwLock<dyn EntityAttributeValueStorage<Attribute>>>,
p2p_config: P2pConfig,
conductor_api: Option<Arc<RwLock<IoHandler>>>,
signal_tx: Option<SignalSender>,
signal_tx: SignalSender,
state_dump_logging: bool,
metric_publisher: Arc<RwLock<dyn MetricPublisher>>,
) -> Self {
Context {
ConductorContext {
instance_name: instance_name.to_owned(),
agent_id: agent_id.clone(),
persister,
state: None,
action_channel: None,
signal_tx,
observer_channel: None,
chain_storage,
dht_storage,
eav_storage: eav,
Expand All @@ -160,47 +145,89 @@ impl Context {
conductor_api,
agent_id,
)),
instance_is_alive: Arc::new(AtomicBool::new(true)),
state_dump_logging,
thread_pool: ThreadPool::new().expect("Could not create thread pool for futures"),
redux_wants_write: Arc::new(AtomicBool::new(false)),
metric_publisher,
signal_tx,
thread_pool: ThreadPool::new().expect("Could not create thread pool for futures"),
}
}
}

/// Context holds the components that parts of a Holochain instance need in order to operate.
/// This includes components that are injected from the outside like persister
/// but also the store of the instance that gets injected before passing on the context
/// to inner components/reducers.
#[derive(Clone)]
pub struct Context {
state: Arc<RwLock<StateWrapper>>,
pub network: Arc<NetworkState>,
pub action_channel: Sender<ActionWrapper>,
pub observer_channel: Option<Sender<Observer>>,
pub conductor_api: ConductorApi,
pub(crate) signal_tx: Sender<Signal>,
pub(crate) instance_is_alive: Arc<AtomicBool>,
pub state_dump_logging: bool,
thread_pool: ThreadPool,
pub redux_wants_write: Arc<AtomicBool>,
pub metric_publisher: Arc<RwLock<dyn MetricPublisher>>,
}

impl Context {
// test_check_conductor_api() is used to inject a conductor_api with a working
// mock of agent/sign to be used in tests.
// There are two different implementations of this function below which get pulled
// in depending on if "test" is in the build config, or not.
// This allows unit tests of core to not have to deal with a conductor_api.
#[cfg(not(test))]
fn test_check_conductor_api(
conductor_api: Option<Arc<RwLock<IoHandler>>>,
_agent_id: AgentId,
) -> Arc<RwLock<IoHandler>> {
// If you get here through this panic make sure that the context passed into the instance
// gets created with a real conductor API. In test config it will be populated with mock API
// that implements agent/sign with the mock_signer. We need this for testing but should
// never use that code in production!
// Hence the two different cases here.
conductor_api.expect("Context can't be created without conductor API")
}

#[cfg(test)]
fn test_check_conductor_api(
conductor_api: Option<Arc<RwLock<IoHandler>>>,
agent_id: AgentId,
) -> Arc<RwLock<IoHandler>> {
conductor_api.unwrap_or_else(|| Arc::new(RwLock::new(mock_conductor_api(agent_id))))
}

#[allow(clippy::too_many_arguments)]
pub fn new_with_channels(
pub fn new(
instance_name: &str,
agent_id: AgentId,
persister: Arc<RwLock<dyn Persister>>,
action_channel: Option<Sender<ActionWrapper>>,
signal_tx: Option<Sender<Signal>>,
observer_channel: Option<Sender<Observer>>,
cas: Arc<RwLock<dyn ContentAddressableStorage>>,
chain_storage: Arc<RwLock<dyn ContentAddressableStorage>>,
dht_storage: Arc<RwLock<dyn ContentAddressableStorage>>,
eav: Arc<RwLock<dyn EntityAttributeValueStorage<Attribute>>>,
p2p_config: P2pConfig,
conductor_api: Option<Arc<RwLock<IoHandler>>>,
signal_tx: Option<SignalSender>,
state_dump_logging: bool,
metric_publisher: Arc<RwLock<dyn MetricPublisher>>,
) -> Result<Context, HolochainError> {
Ok(Context {
instance_name: instance_name.to_owned(),
agent_id: agent_id.clone(),
persister,
) -> Self {
Context {
state: None,
action_channel,
action_channel: None,
signal_tx,
observer_channel,
chain_storage: cas.clone(),
dht_storage: cas,
eav_storage: eav,
p2p_config,
conductor_api: ConductorApi::new(Self::test_check_conductor_api(None, agent_id)),
observer_channel: None,
conductor_api: ConductorApi::new(Self::test_check_conductor_api(
conductor_api,
agent_id,
)),
instance_is_alive: Arc::new(AtomicBool::new(true)),
state_dump_logging,
thread_pool: ThreadPool::new().expect("Could not create thread pool for futures"),
thread_pool,
redux_wants_write: Arc::new(AtomicBool::new(false)),
metric_publisher,
})
}
}

/// Returns the name of this context instance.
Expand Down
Loading