diff --git a/.gitignore b/.gitignore index 64a3b66337..df5e062b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ contracts/track_and_trace/bin/ contracts/track_and_trace/target/ contracts/track_and_trace/src/messages/ +sdk/Cargo.lock +sdk/target + # Node **/node_modules **/package-lock.json diff --git a/contracts/track_and_trace/Cargo.toml b/contracts/track_and_trace/Cargo.toml index 2631ed63e6..d4f7d3f97e 100644 --- a/contracts/track_and_trace/Cargo.toml +++ b/contracts/track_and_trace/Cargo.toml @@ -25,10 +25,7 @@ rust-crypto = "0.2.36" rustc-serialize = "0.3.22" sawtooth-zmq = "0.8.2-dev5" clap = "2" -protobuf = "2" +grid-sdk = { path = "../../sdk" } log = "0.3.0" log4rs = "0.7.0" - -[build-dependencies] -protoc-rust = "2" -glob = "0.2" +protobuf = "2" diff --git a/contracts/track_and_trace/Dockerfile b/contracts/track_and_trace/Dockerfile index 4c3a2d6098..8bf934fff2 100644 --- a/contracts/track_and_trace/Dockerfile +++ b/contracts/track_and_trace/Dockerfile @@ -52,9 +52,14 @@ RUN apt-get update && apt-get install -y protobuf-compiler # - /grid/contracts/track_and_trace/src/messages/ WORKDIR /grid RUN USER=root cargo new --bin contracts/track_and_trace +RUN USER=root cargo new --lib sdk --name grid-sdk + +# copy grid-sdk to build track and trace +WORKDIR /grid/sdk +COPY sdk ./ WORKDIR /grid/contracts/track_and_trace -COPY Cargo.toml Cargo.lock* ./ +COPY contracts/track_and_trace/Cargo.toml contracts/track_and_trace/Cargo.lock* ./ RUN cargo build ENV PATH=$PATH:/grid/contracts/track_and_trace/target/debug/ diff --git a/contracts/track_and_trace/src/handler.rs b/contracts/track_and_trace/src/handler.rs index 47941e6de6..dae7cabd48 100644 --- a/contracts/track_and_trace/src/handler.rs +++ b/contracts/track_and_trace/src/handler.rs @@ -18,26 +18,42 @@ use protobuf::RepeatedField; use std::collections::HashMap; +use grid_sdk::protos::track_and_trace_agent::{Agent, AgentContainer}; +use grid_sdk::protos::track_and_trace_payload::{ + AnswerProposalAction, AnswerProposalAction_Response, CreateAgentAction, + CreateProposalAction, CreateRecordAction, CreateRecordTypeAction, FinalizeRecordAction, + RevokeReporterAction, SCPayload, UpdatePropertiesAction, SCPayload_Action +}; +use grid_sdk::protos::track_and_trace_property::{ + Property, PropertyContainer, PropertyPage, PropertyPageContainer, + PropertyPage_ReportedValue, PropertySchema, PropertySchema_DataType, PropertyValue, + Property_Reporter, +}; +use grid_sdk::protos::track_and_trace_proposal::{ + Proposal, ProposalContainer, Proposal_Role, Proposal_Status, +}; +use grid_sdk::protos::track_and_trace_record::{ + Record, RecordContainer, RecordType, RecordTypeContainer, Record_AssociatedAgent, +}; +use sawtooth_sdk::messages::processor::TpProcessRequest; use sawtooth_sdk::processor::handler::ApplyError; use sawtooth_sdk::processor::handler::TransactionContext; use sawtooth_sdk::processor::handler::TransactionHandler; -use sawtooth_sdk::messages::processor::TpProcessRequest; -use messages::*; use addressing::*; const PROPERTY_PAGE_MAX_LENGTH: usize = 256; #[derive(Debug, Clone)] enum Action { - CreateAgent(payload::CreateAgentAction), - CreateRecord(payload::CreateRecordAction), - FinalizeRecord(payload::FinalizeRecordAction), - CreateRecordType(payload::CreateRecordTypeAction), - UpdateProperties(payload::UpdatePropertiesAction), - CreateProposal(payload::CreateProposalAction), - AnswerProposal(payload::AnswerProposalAction), - RevokeReporter(payload::RevokeReporterAction), + CreateAgent(CreateAgentAction), + CreateRecord(CreateRecordAction), + FinalizeRecord(FinalizeRecordAction), + CreateRecordType(CreateRecordTypeAction), + UpdateProperties(UpdatePropertiesAction), + CreateProposal(CreateProposalAction), + AnswerProposal(AnswerProposalAction), + RevokeReporter(RevokeReporterAction), } struct SupplyChainPayload { @@ -47,18 +63,18 @@ struct SupplyChainPayload { impl SupplyChainPayload { pub fn new(payload: &[u8]) -> Result, ApplyError> { - let payload: payload::SCPayload = match protobuf::parse_from_bytes(payload) { + let payload: SCPayload = match protobuf::parse_from_bytes(payload) { Ok(payload) => payload, Err(_) => { return Err(ApplyError::InvalidTransaction(String::from( "Cannot deserialize payload", - ))) + ))); } }; let supply_chain_action = payload.get_action(); let action = match supply_chain_action { - payload::SCPayload_Action::CREATE_AGENT => { + SCPayload_Action::CREATE_AGENT => { let create_agent = payload.get_create_agent(); if create_agent.get_name() == "" { return Err(ApplyError::InvalidTransaction(String::from( @@ -67,7 +83,7 @@ impl SupplyChainPayload { } Action::CreateAgent(create_agent.clone()) } - payload::SCPayload_Action::CREATE_RECORD => { + SCPayload_Action::CREATE_RECORD => { let create_record = payload.get_create_record(); if create_record.get_record_id() == "" { return Err(ApplyError::InvalidTransaction(String::from( @@ -76,10 +92,10 @@ impl SupplyChainPayload { } Action::CreateRecord(create_record.clone()) } - payload::SCPayload_Action::FINALIZE_RECORD => { + SCPayload_Action::FINALIZE_RECORD => { Action::FinalizeRecord(payload.get_finalize_record().clone()) } - payload::SCPayload_Action::CREATE_RECORD_TYPE => { + SCPayload_Action::CREATE_RECORD_TYPE => { let create_record_type = payload.get_create_record_type(); if create_record_type.get_name() == "" { return Err(ApplyError::InvalidTransaction(String::from( @@ -102,16 +118,16 @@ impl SupplyChainPayload { Action::CreateRecordType(create_record_type.clone()) } - payload::SCPayload_Action::UPDATE_PROPERTIES => { + SCPayload_Action::UPDATE_PROPERTIES => { Action::UpdateProperties(payload.get_update_properties().clone()) } - payload::SCPayload_Action::CREATE_PROPOSAL => { + SCPayload_Action::CREATE_PROPOSAL => { Action::CreateProposal(payload.get_create_proposal().clone()) } - payload::SCPayload_Action::ANSWER_PROPOSAL => { + SCPayload_Action::ANSWER_PROPOSAL => { Action::AnswerProposal(payload.get_answer_proposal().clone()) } - payload::SCPayload_Action::REVOKE_REPORTER => { + SCPayload_Action::REVOKE_REPORTER => { Action::RevokeReporter(payload.get_revoke_reporter().clone()) } }; @@ -119,7 +135,7 @@ impl SupplyChainPayload { 0 => { return Err(ApplyError::InvalidTransaction(String::from( "Timestamp is not set", - ))) + ))); } x => x, }; @@ -148,20 +164,19 @@ impl<'a> SupplyChainState<'a> { SupplyChainState { context: context } } - pub fn get_record(&mut self, record_id: &str) -> Result, ApplyError> { + pub fn get_record(&mut self, record_id: &str) -> Result, ApplyError> { let address = make_record_address(record_id); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let records: record::RecordContainer = - match protobuf::parse_from_bytes(packed.as_slice()) { - Ok(records) => records, - Err(_) => { - return Err(ApplyError::InternalError(String::from( - "Cannot deserialize record container", - ))) - } - }; + let records: RecordContainer = match protobuf::parse_from_bytes(packed.as_slice()) { + Ok(records) => records, + Err(_) => { + return Err(ApplyError::InternalError(String::from( + "Cannot deserialize record container", + ))); + } + }; for record in records.get_entries() { if record.record_id == record_id { @@ -174,11 +189,7 @@ impl<'a> SupplyChainState<'a> { } } - pub fn set_record( - &mut self, - record_id: &str, - record: record::Record, - ) -> Result<(), ApplyError> { + pub fn set_record(&mut self, record_id: &str, record: Record) -> Result<(), ApplyError> { let address = make_record_address(record_id); let d = self.context.get_state(vec![address.clone()])?; let mut record_container = match d { @@ -187,10 +198,10 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize record container", - ))) + ))); } }, - None => record::RecordContainer::new(), + None => RecordContainer::new(), }; // remove old record if it exists and sort the records by record id let records = record_container.get_entries().to_vec(); @@ -219,7 +230,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize record container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -230,21 +241,18 @@ impl<'a> SupplyChainState<'a> { Ok(()) } - pub fn get_record_type( - &mut self, - type_name: &str, - ) -> Result, ApplyError> { + pub fn get_record_type(&mut self, type_name: &str) -> Result, ApplyError> { let address = make_record_type_address(type_name); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let record_types: record::RecordTypeContainer = + let record_types: RecordTypeContainer = match protobuf::parse_from_bytes(packed.as_slice()) { Ok(record_types) => record_types, Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize record type container", - ))) + ))); } }; @@ -262,7 +270,7 @@ impl<'a> SupplyChainState<'a> { pub fn set_record_type( &mut self, type_name: &str, - record_type: record::RecordType, + record_type: RecordType, ) -> Result<(), ApplyError> { let address = make_record_type_address(type_name); let d = self.context.get_state(vec![address.clone()])?; @@ -272,10 +280,10 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize record container", - ))) + ))); } }, - None => record::RecordTypeContainer::new(), + None => RecordTypeContainer::new(), }; record_types.entries.push(record_type); @@ -285,7 +293,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize record type container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -296,18 +304,18 @@ impl<'a> SupplyChainState<'a> { Ok(()) } - pub fn get_agent(&mut self, agent_id: &str) -> Result, ApplyError> { + pub fn get_agent(&mut self, agent_id: &str) -> Result, ApplyError> { let address = make_agent_address(agent_id); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let agents: agent::AgentContainer = + let agents: AgentContainer = match protobuf::parse_from_bytes(packed.as_slice()) { Ok(agents) => agents, Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize agent container", - ))) + ))); } }; @@ -322,7 +330,7 @@ impl<'a> SupplyChainState<'a> { } } - pub fn set_agent(&mut self, agent_id: &str, agent: agent::Agent) -> Result<(), ApplyError> { + pub fn set_agent(&mut self, agent_id: &str, agent: Agent) -> Result<(), ApplyError> { let address = make_agent_address(agent_id); let d = self.context.get_state(vec![address.clone()])?; let mut agents = match d { @@ -331,10 +339,10 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize agent container", - ))) + ))); } }, - None => agent::AgentContainer::new(), + None => AgentContainer::new(), }; agents.entries.push(agent); @@ -344,7 +352,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize agent container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -359,18 +367,18 @@ impl<'a> SupplyChainState<'a> { &mut self, record_id: &str, property_name: &str, - ) -> Result, ApplyError> { + ) -> Result, ApplyError> { let address = make_property_address(record_id, property_name, 0); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let properties: property::PropertyContainer = + let properties: PropertyContainer = match protobuf::parse_from_bytes(packed.as_slice()) { Ok(properties) => properties, Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize property container", - ))) + ))); } }; @@ -389,7 +397,7 @@ impl<'a> SupplyChainState<'a> { &mut self, record_id: &str, property_name: &str, - property: property::Property, + property: Property, ) -> Result<(), ApplyError> { let address = make_property_address(record_id, property_name, 0); let d = self.context.get_state(vec![address.clone()])?; @@ -399,10 +407,10 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize property container", - ))) + ))); } }, - None => property::PropertyContainer::new(), + None => PropertyContainer::new(), }; // remove old property if it exists and sort the properties by name let properties = property_container.get_entries().to_vec(); @@ -429,7 +437,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize property container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -445,18 +453,18 @@ impl<'a> SupplyChainState<'a> { record_id: &str, property_name: &str, page: u32, - ) -> Result, ApplyError> { + ) -> Result, ApplyError> { let address = make_property_address(record_id, property_name, page); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let property_pages: property::PropertyPageContainer = + let property_pages: PropertyPageContainer = match protobuf::parse_from_bytes(packed.as_slice()) { Ok(property_pages) => property_pages, Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize property page container", - ))) + ))); } }; @@ -476,7 +484,7 @@ impl<'a> SupplyChainState<'a> { record_id: &str, property_name: &str, page_num: u32, - property_page: property::PropertyPage, + property_page: PropertyPage, ) -> Result<(), ApplyError> { let address = make_property_address(record_id, property_name, page_num); let d = self.context.get_state(vec![address.clone()])?; @@ -486,10 +494,10 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize property page container", - ))) + ))); } }, - None => property::PropertyPageContainer::new(), + None => PropertyPageContainer::new(), }; // remove old property page if it exists and sort the property pages by name let pages = property_pages.get_entries().to_vec(); @@ -516,7 +524,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize property page container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -531,18 +539,18 @@ impl<'a> SupplyChainState<'a> { &mut self, record_id: &str, agent_id: &str, - ) -> Result, ApplyError> { + ) -> Result, ApplyError> { let address = make_proposal_address(record_id, agent_id); let d = self.context.get_state(vec![address])?; match d { Some(packed) => { - let proposals: proposal::ProposalContainer = + let proposals: ProposalContainer = match protobuf::parse_from_bytes(packed.as_slice()) { Ok(property_pages) => property_pages, Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot deserialize proposal container", - ))) + ))); } }; @@ -556,7 +564,7 @@ impl<'a> SupplyChainState<'a> { &mut self, record_id: &str, agent_id: &str, - proposals: proposal::ProposalContainer, + proposals: ProposalContainer, ) -> Result<(), ApplyError> { let address = make_proposal_address(record_id, agent_id); let serialized = match proposals.write_to_bytes() { @@ -564,7 +572,7 @@ impl<'a> SupplyChainState<'a> { Err(_) => { return Err(ApplyError::InternalError(String::from( "Cannot serialize proposal container", - ))) + ))); } }; let mut sets = HashMap::new(); @@ -593,7 +601,7 @@ impl SupplyChainTransactionHandler { fn _create_agent( &self, - payload: payload::CreateAgentAction, + payload: CreateAgentAction, mut state: SupplyChainState, signer: &str, timestamp: u64, @@ -604,13 +612,13 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Agent already exists: {}", name - ))) + ))); } Ok(None) => (), Err(err) => return Err(err), } - let mut new_agent = agent::Agent::new(); + let mut new_agent = Agent::new(); new_agent.set_public_key(signer.to_string()); new_agent.set_name(name.to_string()); new_agent.set_timestamp(timestamp); @@ -621,7 +629,7 @@ impl SupplyChainTransactionHandler { fn _create_record( &self, - payload: payload::CreateRecordAction, + payload: CreateRecordAction, mut state: SupplyChainState, signer: &str, timestamp: u64, @@ -632,7 +640,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Agent is not register: {}", signer - ))) + ))); } Err(err) => return Err(err), } @@ -642,7 +650,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record already exists: {}", record_id - ))) + ))); } Ok(None) => (), Err(err) => return Err(err), @@ -655,14 +663,14 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record Type does not exist {}", type_name - ))) + ))); } Err(err) => return Err(err), }; - let mut type_schemata: HashMap<&str, property::PropertySchema> = HashMap::new(); - let mut required_properties: HashMap<&str, property::PropertySchema> = HashMap::new(); - let mut provided_properties: HashMap<&str, property::PropertyValue> = HashMap::new(); + let mut type_schemata: HashMap<&str, PropertySchema> = HashMap::new(); + let mut required_properties: HashMap<&str, PropertySchema> = HashMap::new(); + let mut provided_properties: HashMap<&str, PropertyValue> = HashMap::new(); for property in record_type.get_properties() { type_schemata.insert(property.get_name(), property.clone()); if property.get_required() { @@ -690,7 +698,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Provided property {} is not in schemata", provided_name - ))) + ))); } }; let provided_type = provided_properties.data_type; @@ -712,12 +720,12 @@ impl SupplyChainTransactionHandler { ))); }; } - let mut new_record = record::Record::new(); + let mut new_record = Record::new(); new_record.set_record_id(record_id.to_string()); new_record.set_record_type(type_name.to_string()); new_record.set_field_final(false); - let mut owner = record::Record_AssociatedAgent::new(); + let mut owner = Record_AssociatedAgent::new(); owner.set_agent_id(signer.to_string()); owner.set_timestamp(timestamp); new_record.owners.push(owner.clone()); @@ -725,13 +733,13 @@ impl SupplyChainTransactionHandler { state.set_record(record_id, new_record)?; - let mut reporter = property::Property_Reporter::new(); + let mut reporter = Property_Reporter::new(); reporter.set_public_key(signer.to_string()); reporter.set_authorized(true); reporter.set_index(0); for (property_name, property) in type_schemata { - let mut new_property = property::Property::new(); + let mut new_property = Property::new(); new_property.set_name(property_name.to_string()); new_property.set_record_id(record_id.to_string()); new_property.set_data_type(property.get_data_type()); @@ -740,15 +748,17 @@ impl SupplyChainTransactionHandler { new_property.set_wrapped(false); new_property.set_fixed(property.get_fixed()); new_property.set_number_exponent(property.get_number_exponent()); - new_property.set_enum_options( - RepeatedField::from_vec(property.get_enum_options().to_vec())); - new_property.set_struct_properties( - RepeatedField::from_vec(property.get_struct_properties().to_vec())); + new_property.set_enum_options(RepeatedField::from_vec( + property.get_enum_options().to_vec(), + )); + new_property.set_struct_properties(RepeatedField::from_vec( + property.get_struct_properties().to_vec(), + )); new_property.set_unit(property.get_unit().to_string()); state.set_property(record_id, property_name, new_property.clone())?; - let mut new_property_page = property::PropertyPage::new(); + let mut new_property_page = PropertyPage::new(); new_property_page.set_name(property_name.to_string()); new_property_page.set_record_id(record_id.to_string()); @@ -774,7 +784,7 @@ impl SupplyChainTransactionHandler { fn _finalize_record( &self, - payload: payload::FinalizeRecordAction, + payload: FinalizeRecordAction, mut state: SupplyChainState, signer: &str, ) -> Result<(), ApplyError> { @@ -785,7 +795,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record does not exist: {}", record_id - ))) + ))); } Err(err) => return Err(err), }; @@ -794,7 +804,7 @@ impl SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Owner was not found", - ))) + ))); } }; let custodian = match final_record.custodians.last() { @@ -802,7 +812,7 @@ impl SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Custodian was not found", - ))) + ))); } }; @@ -827,7 +837,7 @@ impl SupplyChainTransactionHandler { fn _create_record_type( &self, - payload: payload::CreateRecordTypeAction, + payload: CreateRecordTypeAction, mut state: SupplyChainState, signer: &str, ) -> Result<(), ApplyError> { @@ -837,12 +847,12 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Agent is not register: {}", signer - ))) + ))); } Err(err) => return Err(err), } let name = payload.get_name(); - let mut provided_properties: HashMap<&str, property::PropertySchema> = HashMap::new(); + let mut provided_properties: HashMap<&str, PropertySchema> = HashMap::new(); for property in payload.get_properties() { provided_properties.insert(property.get_name(), property.clone()); } @@ -851,12 +861,12 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record type already exists: {}", signer - ))) + ))); } Ok(None) => (), Err(err) => return Err(err), } - let mut record_type = record::RecordType::new(); + let mut record_type = RecordType::new(); record_type.set_name(name.to_string()); record_type.set_properties(RepeatedField::from_vec(payload.get_properties().to_vec())); @@ -867,7 +877,7 @@ impl SupplyChainTransactionHandler { fn _update_properties( &self, - payload: payload::UpdatePropertiesAction, + payload: UpdatePropertiesAction, mut state: SupplyChainState, signer: &str, timestamp: u64, @@ -879,7 +889,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record does not exist: {}", record_id - ))) + ))); } Err(err) => return Err(err), }; @@ -903,7 +913,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record does not have provided poperty: {}", name - ))) + ))); } Err(err) => return Err(err), }; @@ -944,20 +954,16 @@ impl SupplyChainTransactionHandler { Ok(None) => { return Err(ApplyError::InvalidTransaction(String::from( "Property page does not exist", - ))) + ))); } Err(err) => return Err(err), }; - let reported_value = match self._make_new_reported_value( - reporter_index, - timestamp, - update, - &prop, - ) { - Ok(reported_value) => reported_value, - Err(err) => return Err(err), - }; + let reported_value = + match self._make_new_reported_value(reporter_index, timestamp, update, &prop) { + Ok(reported_value) => reported_value, + Err(err) => return Err(err), + }; page.reported_values.push(reported_value); page.reported_values .sort_by_key(|rv| (rv.clone().timestamp, rv.clone().reporter_index)); @@ -974,7 +980,7 @@ impl SupplyChainTransactionHandler { new_page } Ok(None) => { - let mut new_page = property::PropertyPage::new(); + let mut new_page = PropertyPage::new(); new_page.set_name(name.to_string()); new_page.set_record_id(record_id.to_string()); new_page @@ -996,7 +1002,7 @@ impl SupplyChainTransactionHandler { fn _create_proposal( &self, - payload: payload::CreateProposalAction, + payload: CreateProposalAction, mut state: SupplyChainState, signer: &str, timestamp: u64, @@ -1012,7 +1018,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Issuing agent does not exist: {}", signer - ))) + ))); } Err(err) => return Err(err), }; @@ -1023,26 +1029,27 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Receiving agent does not exist: {}", receiving_agent - ))) + ))); } Err(err) => return Err(err), }; let mut proposals = match state.get_proposal_container(&record_id, &receiving_agent) { Ok(Some(proposals)) => proposals, - Ok(None) => proposal::ProposalContainer::new(), + Ok(None) => ProposalContainer::new(), Err(err) => return Err(err), }; - let mut open_proposals = Vec::::new(); + let mut open_proposals = Vec::::new(); for prop in proposals.get_entries() { - if prop.status == proposal::Proposal_Status::OPEN { + if prop.status == Proposal_Status::OPEN { open_proposals.push(prop.clone()); } } for prop in open_proposals { - if prop.get_receiving_agent() == receiving_agent && prop.get_role() == role + if prop.get_receiving_agent() == receiving_agent + && prop.get_role() == role && prop.get_record_id() == record_id { return Err(ApplyError::InvalidTransaction(String::from( @@ -1057,7 +1064,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record does not exist: {}", record_id - ))) + ))); } Err(err) => return Err(err), }; @@ -1069,13 +1076,13 @@ impl SupplyChainTransactionHandler { ))); } - if role == proposal::Proposal_Role::OWNER || role == proposal::Proposal_Role::REPORTER { + if role == Proposal_Role::OWNER || role == Proposal_Role::REPORTER { let owner = match proposal_record.owners.last() { Some(owner) => owner, None => { return Err(ApplyError::InvalidTransaction(String::from( "Owner not found", - ))) + ))); } }; if owner.get_agent_id() != signer { @@ -1085,13 +1092,13 @@ impl SupplyChainTransactionHandler { } } - if role == proposal::Proposal_Role::CUSTODIAN { + if role == Proposal_Role::CUSTODIAN { let custodian = match proposal_record.custodians.last() { Some(custodian) => custodian, None => { return Err(ApplyError::InvalidTransaction(String::from( "Custodian not found", - ))) + ))); } }; @@ -1102,14 +1109,14 @@ impl SupplyChainTransactionHandler { } } - let mut new_proposal = proposal::Proposal::new(); + let mut new_proposal = Proposal::new(); new_proposal.set_record_id(record_id.to_string()); new_proposal.set_timestamp(timestamp); new_proposal.set_issuing_agent(signer.to_string()); new_proposal.set_receiving_agent(receiving_agent.to_string()); new_proposal.set_role(role); new_proposal.set_properties(properties); - new_proposal.set_status(proposal::Proposal_Status::OPEN); + new_proposal.set_status(Proposal_Status::OPEN); proposals.entries.push(new_proposal); proposals.entries.sort_by_key(|p| { @@ -1126,7 +1133,7 @@ impl SupplyChainTransactionHandler { fn _answer_proposal( &self, - payload: payload::AnswerProposalAction, + payload: AnswerProposalAction, mut state: SupplyChainState, signer: &str, timestamp: u64, @@ -1141,7 +1148,7 @@ impl SupplyChainTransactionHandler { Ok(None) => { return Err(ApplyError::InvalidTransaction(String::from( "Proposal does not exist", - ))) + ))); } Err(err) => return Err(err), }; @@ -1153,7 +1160,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "No open proposals found for record {} for {}", record_id, receiving_agent - ))) + ))); } }; @@ -1161,9 +1168,10 @@ impl SupplyChainTransactionHandler { let mut count = 0; for prop in proposals.get_entries() { - if prop.get_receiving_agent() == receiving_agent && prop.get_role() == role + if prop.get_receiving_agent() == receiving_agent + && prop.get_role() == role && prop.get_record_id() == record_id - && prop.status == proposal::Proposal_Status::OPEN + && prop.status == Proposal_Status::OPEN { current_proposal = prop.clone(); exists = true; @@ -1181,23 +1189,23 @@ impl SupplyChainTransactionHandler { } match response { - payload::AnswerProposalAction_Response::CANCEL => { + AnswerProposalAction_Response::CANCEL => { if current_proposal.get_issuing_agent() != signer { return Err(ApplyError::InvalidTransaction(String::from( "Only the issuing agent can cancel a proposal", ))); } - current_proposal.status = proposal::Proposal_Status::CANCELED; + current_proposal.status = Proposal_Status::CANCELED; } - payload::AnswerProposalAction_Response::REJECT => { + AnswerProposalAction_Response::REJECT => { if current_proposal.get_receiving_agent() != signer { return Err(ApplyError::InvalidTransaction(String::from( "Only the receiving agent can reject a proposal", ))); } - current_proposal.status = proposal::Proposal_Status::REJECTED; + current_proposal.status = Proposal_Status::REJECTED; } - payload::AnswerProposalAction_Response::ACCEPT => { + AnswerProposalAction_Response::ACCEPT => { if current_proposal.get_receiving_agent() != signer { return Err(ApplyError::InvalidTransaction(String::from( "Only the receiving agent can Accept a proposal", @@ -1210,7 +1218,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record in proposal does not exist: {}", record_id - ))) + ))); } Err(err) => return Err(err), }; @@ -1220,7 +1228,7 @@ impl SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Owner not found", - ))) + ))); } }; @@ -1229,14 +1237,14 @@ impl SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Custodian not found", - ))) + ))); } }; match role { - proposal::Proposal_Role::OWNER => { + Proposal_Role::OWNER => { if owner.get_agent_id() != current_proposal.get_issuing_agent() { - current_proposal.status = proposal::Proposal_Status::CANCELED; + current_proposal.status = Proposal_Status::CANCELED; info!("Record owner does not match the issuing agent of the proposal"); // remove old proposal and replace with new one proposals.entries.remove(proposal_index); @@ -1248,11 +1256,15 @@ impl SupplyChainTransactionHandler { p.clone().timestamp, ) }); - state.set_proposal_container(&record_id, &receiving_agent, proposals)?; + state.set_proposal_container( + &record_id, + &receiving_agent, + proposals, + )?; return Ok(()); } - let mut new_owner = record::Record_AssociatedAgent::new(); + let mut new_owner = Record_AssociatedAgent::new(); new_owner.set_agent_id(receiving_agent.to_string()); new_owner.set_timestamp(timestamp); proposal_record.owners.push(new_owner); @@ -1265,7 +1277,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "RecordType does not exist: {}", proposal_record.get_record_type() - ))) + ))); } Err(err) => return Err(err), }; @@ -1277,15 +1289,13 @@ impl SupplyChainTransactionHandler { Ok(None) => { return Err(ApplyError::InvalidTransaction(String::from( "Property does not exist", - ))) + ))); } Err(err) => return Err(err), }; let mut authorized = false; - let mut new_reporters: Vec< - property::Property_Reporter, - > = Vec::new(); + let mut new_reporters: Vec = Vec::new(); let temp_prob = prop.clone(); let reporters = temp_prob.get_reporters(); for reporter in reporters { @@ -1304,7 +1314,7 @@ impl SupplyChainTransactionHandler { } if !authorized { - let mut reporter = property::Property_Reporter::new(); + let mut reporter = Property_Reporter::new(); reporter.set_public_key(receiving_agent.to_string()); reporter.set_authorized(true); reporter.set_index(prop.reporters.len() as u32); @@ -1314,11 +1324,11 @@ impl SupplyChainTransactionHandler { prop.set_reporters(RepeatedField::from_vec(new_reporters)); state.set_property(record_id, prop.get_name(), prop.clone())?; } - current_proposal.status = proposal::Proposal_Status::ACCEPTED; + current_proposal.status = Proposal_Status::ACCEPTED; } - proposal::Proposal_Role::CUSTODIAN => { + Proposal_Role::CUSTODIAN => { if custodian.get_agent_id() != current_proposal.get_issuing_agent() { - current_proposal.status = proposal::Proposal_Status::CANCELED; + current_proposal.status = Proposal_Status::CANCELED; info!( "Record custodian does not match the issuing agent of the proposal" ); @@ -1339,16 +1349,16 @@ impl SupplyChainTransactionHandler { )?; } - let mut new_custodian = record::Record_AssociatedAgent::new(); + let mut new_custodian = Record_AssociatedAgent::new(); new_custodian.set_agent_id(receiving_agent.to_string()); new_custodian.set_timestamp(timestamp); proposal_record.custodians.push(new_custodian.clone()); state.set_record(record_id, proposal_record)?; - current_proposal.status = proposal::Proposal_Status::ACCEPTED; + current_proposal.status = Proposal_Status::ACCEPTED; } - proposal::Proposal_Role::REPORTER => { + Proposal_Role::REPORTER => { if owner.get_agent_id() != current_proposal.get_issuing_agent() { - current_proposal.status = proposal::Proposal_Status::CANCELED; + current_proposal.status = Proposal_Status::CANCELED; info!("Record owner does not match the issuing agent of the proposal"); // remove old proposal and replace with new one proposals.entries.remove(proposal_index); @@ -1360,11 +1370,15 @@ impl SupplyChainTransactionHandler { p.clone().timestamp, ) }); - state.set_proposal_container(&record_id, &receiving_agent, proposals)?; + state.set_proposal_container( + &record_id, + &receiving_agent, + proposals, + )?; return Ok(()); } - let mut reporter = property::Property_Reporter::new(); + let mut reporter = Property_Reporter::new(); reporter.set_public_key(receiving_agent.to_string()); reporter.set_authorized(true); @@ -1374,7 +1388,7 @@ impl SupplyChainTransactionHandler { Ok(None) => { return Err(ApplyError::InvalidTransaction(String::from( "Property does not exist", - ))) + ))); } Err(err) => return Err(err), }; @@ -1382,7 +1396,7 @@ impl SupplyChainTransactionHandler { prop.reporters.push(reporter.clone()); state.set_property(record_id, prop_name, prop)?; } - current_proposal.status = proposal::Proposal_Status::ACCEPTED; + current_proposal.status = Proposal_Status::ACCEPTED; } } } @@ -1404,7 +1418,7 @@ impl SupplyChainTransactionHandler { fn _revoke_reporter( &self, - payload: payload::RevokeReporterAction, + payload: RevokeReporterAction, mut state: SupplyChainState, signer: &str, ) -> Result<(), ApplyError> { @@ -1418,7 +1432,7 @@ impl SupplyChainTransactionHandler { return Err(ApplyError::InvalidTransaction(format!( "Record does not exists: {}", record_id - ))) + ))); } Err(err) => return Err(err), }; @@ -1428,7 +1442,7 @@ impl SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Owner was not found", - ))) + ))); } }; @@ -1451,12 +1465,12 @@ impl SupplyChainTransactionHandler { Ok(None) => { return Err(ApplyError::InvalidTransaction(format!( "Property does not exists" - ))) + ))); } Err(err) => return Err(err), }; - let mut new_reporters: Vec = Vec::new(); + let mut new_reporters: Vec = Vec::new(); let mut revoked = false; for reporter in prop.get_reporters() { if reporter.get_public_key() == reporter_id { @@ -1491,50 +1505,52 @@ impl SupplyChainTransactionHandler { &self, reporter_index: u32, timestamp: u64, - value: &property::PropertyValue, - property: &property::Property, - ) -> Result { - let mut reported_value = property::PropertyPage_ReportedValue::new(); + value: &PropertyValue, + property: &Property, + ) -> Result { + let mut reported_value = PropertyPage_ReportedValue::new(); reported_value.set_reporter_index(reporter_index); reported_value.set_timestamp(timestamp); match value.get_data_type() { - property::PropertySchema_DataType::TYPE_UNSET => { + PropertySchema_DataType::TYPE_UNSET => { return Err(ApplyError::InvalidTransaction(String::from( "DataType is not set", - ))) + ))); } - property::PropertySchema_DataType::BYTES => { + PropertySchema_DataType::BYTES => { reported_value.set_bytes_value(value.get_bytes_value().to_vec()) } - property::PropertySchema_DataType::BOOLEAN => { + PropertySchema_DataType::BOOLEAN => { reported_value.set_boolean_value(value.get_boolean_value()) } - property::PropertySchema_DataType::NUMBER => { + PropertySchema_DataType::NUMBER => { reported_value.set_number_value(value.get_number_value()) } - property::PropertySchema_DataType::STRING => { + PropertySchema_DataType::STRING => { reported_value.set_string_value(value.get_string_value().to_string()) } - property::PropertySchema_DataType::ENUM => { + PropertySchema_DataType::ENUM => { let enum_name = value.get_enum_value().to_string(); - let enum_index = match property.enum_options.iter() - .position(|name| name == &enum_name) { - Some(index) => index, - None => { - return Err(ApplyError::InvalidTransaction(format!( - "Provided enum name is not a valid option: {}", - enum_name, - ))) - } - }; + let enum_index = match property + .enum_options + .iter() + .position(|name| name == &enum_name) + { + Some(index) => index, + None => { + return Err(ApplyError::InvalidTransaction(format!( + "Provided enum name is not a valid option: {}", + enum_name, + ))); + } + }; reported_value.set_enum_value(enum_index as u32) } - property::PropertySchema_DataType::STRUCT => { - match self._validate_struct_values( - &value.struct_values, - &property.struct_properties - ) { + PropertySchema_DataType::STRUCT => { + match self + ._validate_struct_values(&value.struct_values, &property.struct_properties) + { Ok(_) => (), Err(e) => return Err(e), } @@ -1542,7 +1558,7 @@ impl SupplyChainTransactionHandler { let struct_values = RepeatedField::from_vec(value.get_struct_values().to_vec()); reported_value.set_struct_values(struct_values) } - property::PropertySchema_DataType::LOCATION => { + PropertySchema_DataType::LOCATION => { reported_value.set_location_value(value.get_location_value().clone()) } }; @@ -1551,39 +1567,38 @@ impl SupplyChainTransactionHandler { fn _validate_struct_values( &self, - struct_values: &RepeatedField, - schema_values: &RepeatedField + struct_values: &RepeatedField, + schema_values: &RepeatedField, ) -> Result<(), ApplyError> { if struct_values.len() != schema_values.len() { return Err(ApplyError::InvalidTransaction(format!( "Provided struct does not match schema length: {:?} != {:?}", struct_values.len(), schema_values.len(), - ))) + ))); } for schema in schema_values.iter() { let value = match struct_values.iter().find(|val| val.name == schema.name) { Some(val) => val, - None => return Err(ApplyError::InvalidTransaction(format!( - "Provided struct missing required property from schema: {}", - schema.name, - ))) + None => { + return Err(ApplyError::InvalidTransaction(format!( + "Provided struct missing required property from schema: {}", + schema.name, + ))); + } }; if value.data_type != schema.data_type { return Err(ApplyError::InvalidTransaction(format!( "Struct property \"{}\" must have data type: {:?}", - schema.name, - schema.data_type, - ))) + schema.name, schema.data_type, + ))); } - if schema.data_type == property::PropertySchema_DataType::STRUCT { - match self._validate_struct_values( - &value.struct_values, - &schema.struct_properties - ) { + if schema.data_type == PropertySchema_DataType::STRUCT { + match self._validate_struct_values(&value.struct_values, &schema.struct_properties) + { Ok(_) => (), Err(e) => return Err(e), } @@ -1622,7 +1637,7 @@ impl TransactionHandler for SupplyChainTransactionHandler { None => { return Err(ApplyError::InvalidTransaction(String::from( "Request must contain a payload", - ))) + ))); } }; diff --git a/contracts/track_and_trace/src/main.rs b/contracts/track_and_trace/src/main.rs index 3e32919f7d..898f113231 100644 --- a/contracts/track_and_trace/src/main.rs +++ b/contracts/track_and_trace/src/main.rs @@ -18,19 +18,19 @@ extern crate crypto; extern crate log4rs; #[macro_use] extern crate log; +extern crate grid_sdk; extern crate protobuf; extern crate rustc_serialize; extern crate sawtooth_sdk; -mod handler; mod addressing; -mod messages; +mod handler; -use std::process; use log::LogLevelFilter; use log4rs::append::console::ConsoleAppender; use log4rs::config::{Appender, Config, Root}; use log4rs::encode::pattern::PatternEncoder; +use std::process; use sawtooth_sdk::processor::TransactionProcessor; @@ -44,7 +44,7 @@ fn main() { "connection endpoint for validator") (@arg verbose: -v --verbose +multiple "increase output verbosity")) - .get_matches(); + .get_matches(); let endpoint = matches .value_of("connect") diff --git a/docker-compose-installed.yaml b/docker-compose-installed.yaml index bd5a640437..7377d96100 100644 --- a/docker-compose-installed.yaml +++ b/docker-compose-installed.yaml @@ -29,7 +29,7 @@ services: - no_proxy depends_on: - validator - entrypoint: grid-track-and-trace-tp -C tcp://validator:4004 + entrypoint: grid-track-and-trace-tp -C tcp://validator:4004 -v validator: image: hyperledger/sawtooth-validator:1.0 diff --git a/docker-compose.yaml b/docker-compose.yaml index fe621eaa15..e9cd6363c1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -21,7 +21,8 @@ services: image: grid-track-and-trace-tp container_name: grid-track-and-trace-tp build: - context: contracts/track_and_trace/ + context: . + dockerfile: contracts/track_and_trace/Dockerfile args: - http_proxy - https_proxy @@ -32,6 +33,7 @@ services: - 'no_proxy=rest-api,eth0,validator,${no_proxy}' volumes: - .:/grid + - /grid/sdk - /grid/contracts/track_and_trace/target - /grid/contracts/track_and_trace/src/messages entrypoint: | diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml new file mode 100644 index 0000000000..5261d81667 --- /dev/null +++ b/sdk/Cargo.toml @@ -0,0 +1,28 @@ +# Copyright 2019 Cargill Incorporated +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[package] +name = "grid-sdk" +version = "0.1.0" +authors = ["Cargill Incorporated"] +description = "Grid SDK" +homepage = "https://grid.hyperledger.org" +edition = "2018" + +[dependencies] +protobuf = "2" + +[build-dependencies] +protoc-rust = "2" +glob = "0.2" diff --git a/contracts/track_and_trace/build.rs b/sdk/build.rs similarity index 54% rename from contracts/track_and_trace/build.rs rename to sdk/build.rs index 4014992e83..bf601e0e35 100644 --- a/contracts/track_and_trace/build.rs +++ b/sdk/build.rs @@ -18,35 +18,54 @@ extern crate glob; extern crate protoc_rust; +use std::env; use std::fs; +use std::fs::File; use std::io::Write; +use std::path::Path; + use protoc_rust::Customize; fn main() { // Generate protobuf files - let proto_src_files = glob_simple("../../protos/*.proto"); + let proto_src_files = glob_simple("protos/*.proto"); println!("{:?}", proto_src_files); - fs::create_dir_all("src/messages").unwrap(); + let out_dir = env::var("OUT_DIR").expect("No OUT_DIR env variable"); + let dest_path = Path::new(&out_dir).join("protos"); + fs::create_dir_all(&dest_path).expect("Unable to create proto destination directory"); + + let mod_file_content = proto_src_files + .iter() + .map(|proto_file| { + let proto_path = Path::new(proto_file); + format!( + "pub mod {};", + proto_path + .file_stem() + .expect("Unable to extract stem") + .to_str() + .expect("Unable to extract filename") + ) + }) + .collect::>() + .join("\n"); + + let mut mod_file = File::create(dest_path.join("mod.rs")).unwrap(); + mod_file + .write_all(mod_file_content.as_bytes()) + .expect("Unable to write mod file"); protoc_rust::run(protoc_rust::Args { - out_dir: "src/messages", + out_dir: &dest_path.to_str().expect("Invalid proto destination path"), input: &proto_src_files .iter() .map(|a| a.as_ref()) .collect::>(), - includes: &["src", "../../protos"], + includes: &["src", "protos"], customize: Customize::default(), - }).expect("unable to run protoc"); - - let mut file = fs::File::create("src/messages/mod.rs").unwrap(); - for filename in proto_src_files.iter() { - file.write_all(path_to_mod(&filename).as_bytes()).unwrap(); - } -} - -fn path_to_mod(filename: &String) -> String { - filename.replace("../../protos/", "pub mod ").replace(".proto", ";\n") + }) + .expect("unable to run protoc"); } fn glob_simple(pattern: &str) -> Vec { diff --git a/protos/agent.proto b/sdk/protos/track_and_trace_agent.proto similarity index 100% rename from protos/agent.proto rename to sdk/protos/track_and_trace_agent.proto diff --git a/protos/payload.proto b/sdk/protos/track_and_trace_payload.proto similarity index 97% rename from protos/payload.proto rename to sdk/protos/track_and_trace_payload.proto index 196af36143..2187221e92 100644 --- a/protos/payload.proto +++ b/sdk/protos/track_and_trace_payload.proto @@ -15,8 +15,8 @@ syntax = "proto3"; -import "property.proto"; -import "proposal.proto"; +import "track_and_trace_property.proto"; +import "track_and_trace_proposal.proto"; message SCPayload { diff --git a/protos/property.proto b/sdk/protos/track_and_trace_property.proto similarity index 100% rename from protos/property.proto rename to sdk/protos/track_and_trace_property.proto diff --git a/protos/proposal.proto b/sdk/protos/track_and_trace_proposal.proto similarity index 100% rename from protos/proposal.proto rename to sdk/protos/track_and_trace_proposal.proto diff --git a/protos/record.proto b/sdk/protos/track_and_trace_record.proto similarity index 97% rename from protos/record.proto rename to sdk/protos/track_and_trace_record.proto index fabea61c40..c36eab0448 100644 --- a/protos/record.proto +++ b/sdk/protos/track_and_trace_record.proto @@ -15,7 +15,7 @@ syntax = "proto3"; -import "property.proto"; +import "track_and_trace_property.proto"; message Record { diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs new file mode 100644 index 0000000000..1a762592b4 --- /dev/null +++ b/sdk/src/lib.rs @@ -0,0 +1,15 @@ +// Copyright 2019 Cargill Incorporated +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod protos; diff --git a/sdk/src/protos.rs b/sdk/src/protos.rs new file mode 100644 index 0000000000..31a00dcad1 --- /dev/null +++ b/sdk/src/protos.rs @@ -0,0 +1,77 @@ +// Copyright 2018 Bitwise IO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::error::Error as StdError; + +#[derive(Debug)] +pub enum ProtoConversionError { + SerializationError(String), + InvalidTypeError(String), +} + +impl StdError for ProtoConversionError { + fn description(&self) -> &str { + match *self { + ProtoConversionError::SerializationError(ref msg) => msg, + ProtoConversionError::InvalidTypeError(ref msg) => msg, + } + } + + fn cause(&self) -> Option<&StdError> { + match *self { + ProtoConversionError::SerializationError(_) => None, + ProtoConversionError::InvalidTypeError(_) => None, + } + } +} + +impl std::fmt::Display for ProtoConversionError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + ProtoConversionError::SerializationError(ref s) => { + write!(f, "SerializationError: {}", s) + } + ProtoConversionError::InvalidTypeError(ref s) => write!(f, "InvalidTypeError: {}", s), + } + } +} + +pub trait FromProto

: Sized { + fn from_proto(other: P) -> Result; +} + +pub trait FromNative: Sized { + fn from_native(other: N) -> Result; +} + +pub trait IntoNative: Sized +where + T: FromProto, +{ + fn into_native(self) -> Result { + FromProto::from_proto(self) + } +} + +pub trait IntoProto: Sized +where + T: FromNative, +{ + fn into_proto(self) -> Result { + FromNative::from_native(self) + } +} + +// Includes the autogenerated protobuf messages +include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));