Untitled
unknown
plain_text
7 months ago
4.7 kB
25
Indexable
Never
x #[macro_use] extern crate serde; use candid::{Decode, Encode}; use ic_cdk::api::time; use ic_stable_structures::memory_manager::{MemoryId, MemoryManager, VirtualMemory}; use ic_stable_structures::{BoundedStorable, Cell, DefaultMemoryImpl, StableBTreeMap, Storable}; use std::{borrow::Cow, cell::RefCell}; type Memory = VirtualMemory<DefaultMemoryImpl>; type IdCell = Cell<u64, Memory>; #[derive(candid::CandidType, Clone, Serialize, Deserialize, Default)] struct Message { id: u64, title: String, body: String, attachment_url: String, created_at: u64, updated_at: Option<u64>, } // a trait that must be implemented for a struct that is stored in a stable struct impl Storable for Message { fn to_bytes(&self) -> std::borrow::Cow<[u8]> { Cow::Owned(Encode!(self).unwrap()) } fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { Decode!(bytes.as_ref(), Self).unwrap() } } // another trait that must be implemented for a struct that is stored in a stable struct impl BoundedStorable for Message { const MAX_SIZE: u32 = 1024; const IS_FIXED_SIZE: bool = false; } thread_local! { static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> = RefCell::new( MemoryManager::init(DefaultMemoryImpl::default()) ); static ID_COUNTER: RefCell<IdCell> = RefCell::new( IdCell::init(MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(0))), 0) .expect("Cannot create a counter") ); static STORAGE: RefCell<StableBTreeMap<u64, Message, Memory>> = RefCell::new(StableBTreeMap::init( MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(1))) )); } #[derive(candid::CandidType, Serialize, Deserialize, Default)] struct MessagePayload { title: String, body: String, attachment_url: String, } #[ic_cdk::query] fn get_message(id: u64) -> Result<Message, Error> { match _get_message(&id) { Some(message) => Ok(message), None => Err(Error::NotFound { msg: format!("a message with id={} not found", id), }), } } #[ic_cdk::update] fn add_message(message: MessagePayload) -> Option<Message> { let id = ID_COUNTER .with(|counter| { let current_value = *counter.borrow().get(); counter.borrow_mut().set(current_value + 1) }) .expect("cannot increment id counter"); let message = Message { id, title: message.title, body: message.body, attachment_url: message.attachment_url, created_at: time(), updated_at: None, }; do_insert(&message); Some(message) } #[ic_cdk::update] fn update_message(id: u64, payload: MessagePayload) -> Result<Message, Error> { match STORAGE.with(|service| service.borrow().get(&id)) { Some(mut message) => { message.attachment_url = payload.attachment_url; message.body = payload.body; message.title = payload.title; message.updated_at = Some(time()); do_insert(&message); Ok(message) } None => Err(Error::NotFound { msg: format!( "couldn't update a message with id={}. message not found", id ), }), } } // helper method to perform insert. fn do_insert(message: &Message) { STORAGE.with(|service| service.borrow_mut().insert(message.id, message.clone())); } #[ic_cdk::update] fn delete_message(id: u64) -> Result<Message, Error> { match STORAGE.with(|service| service.borrow_mut().remove(&id)) { Some(message) => Ok(message), None => Err(Error::NotFound { msg: format!( "couldn't delete a message with id={}. message not found.", id ), }), } } #[derive(candid::CandidType, Deserialize, Serialize)] enum Error { NotFound { msg: String }, } // a helper method to get a message by id. used in get_message/update_message fn _get_message(id: &u64) -> Option<Message> { STORAGE.with(|service| service.borrow().get(id)) } // need this to generate candid ic_cdk::export_candid!();
Leave a Comment