1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use RefCell;
use crateRecordId;
// 持久化相关接口
// ! 如果通过其他方式,比如 ic-stable-structures,使用了持久化内存,则不能够使用下面传统的方式进行升级持久化
/// 升级后恢复
/// 升级前保存
/*
引入包后, 直接使用如下代码即可拥有可恢复数据对象
// ================= 需要持久化的数据 ================
thread_local! {
// 存储系统数据
static STATE: RefCell<State> = RefCell::default();
}
// ==================== 升级时的恢复逻辑 ====================
#[ic_cdk::post_upgrade]
fn post_upgrade() {
STATE.with(|state| {
let record_id = ic_canister_kit::stable::restore_after_upgrade(state);
state.borrow_mut().upgrade(); // ! 恢复后要进行升级到最新版本
let schedule = state.borrow().schedule_find();
state.borrow_mut().init(CanisterInitialArg { schedule }); // ! 升级到最新版本后, 需要执行初始化操作
state.borrow_mut().schedule_reload(); // * 重置定时任务
let version = state.borrow().version();
if let Some(record_id) = record_id {
state
.borrow_mut()
.record_update(record_id, format!("Next version: {}", version));
}
});
}
// ==================== 升级时的保存逻辑,下次升级执行 ====================
#[ic_cdk::pre_upgrade]
fn pre_upgrade() {
STATE.with(|state| {
#[allow(clippy::unwrap_used)] // ? checked
state.borrow().pause_must_be_paused().unwrap(); // ! 必须是维护状态, 才可以升级
state.borrow_mut().schedule_stop(); // * 停止定时任务
ic_canister_kit::stable::store_before_upgrade(state);
let record_id = state.borrow_mut().record_push(
caller,
RecordTopics::Upgrade.topic(),
format!("Upgrade by {}", caller.to_text()),
);
ic_canister_kit::stable::store_before_upgrade(state, Some(record_id));
});
}
// ==================== 工具方法 ====================
/// 外界需要系统状态时
#[allow(unused)]
pub fn with_state<F, R>(callback: F) -> R
where
F: FnOnce(&State) -> R,
{
STATE.with(|_state| {
let state = _state.borrow(); // 取得不可变对象
callback(&state)
})
}
/// 需要可变系统状态时
#[allow(unused)]
pub fn with_mut_state_without_record<F, R>(callback: F) -> R
where
F: FnOnce(&mut State) -> R,
{
STATE.with(|state| {
let mut state = state.borrow_mut(); // 取得可变对象
callback(&mut state)
})
}
/// 需要可变系统状态时 // ! 变更操作一定要记录
#[allow(unused)]
pub fn with_mut_state<F, R>(callback: F, caller: CallerId, topic: RecordTopic, content: String) -> R
where
F: FnOnce(&mut State) -> (Option<String>, R),
{
STATE.with(|state| {
let mut state = state.borrow_mut(); // 取得可变对象
let record_id = state.record_push(caller, topic, content);
let (done, result) = callback(&mut state);
state.record_update(record_id, done.unwrap_or_default());
result
})
}
*/