// 事件系统 —— 移植自 rust event.rs + 补齐 issues/127·132「事件代码腿」
// 权威码表:jeeflow-doc/docs/spec/11-events.md §11.3(A 套整型 1..9,规范名逐字对齐)
// 4 号位复用:原 ProcessTaskEnd 引擎从不 fire(全联邦死码),复用于 CcCreate(issues/102·104)
// 5..9 为 issues/132 §5.2 定稿新增;10+ 预留(超时催办/自动通过,本轮不发,仅占号防分叉)
///|
/// 规范名 ↔ 构造子映射(构造子为本栈实际命名,name() 透出 spec §11.3 权威 SCREAMING 名):
/// 1 PROCESS_INSTANCE_START / 2 PROCESS_INSTANCE_END / 3 PROCESS_TASK_START / 4 CC_CREATE
/// 5 TASK_COMPLETE / 6 TASK_REJECT / 7 TASK_TRANSFER / 8 TASK_WITHDRAW / 9 INSTANCE_TERMINATED
pub(all) enum ProcessEventType {
ProcessInstanceStart
ProcessInstanceEnd
ProcessTaskStart
CcCreate
TaskComplete
TaskReject
TaskTransfer
TaskWithdraw
InstanceTerminated
// 10+ 预留:超时催办 / 超时自动通过 …(spec §11.4「明确不发」——八栈无时钟扫描器,发了无触发源)
} derive(Eq, Debug)
///|
pub fn ProcessEventType::code(self : ProcessEventType) -> Int {
match self {
ProcessInstanceStart => 1
ProcessInstanceEnd => 2
ProcessTaskStart => 3
CcCreate => 4
TaskComplete => 5
TaskReject => 6
TaskTransfer => 7
TaskWithdraw => 8
InstanceTerminated => 9
}
}
///|
pub fn ProcessEventType::from_code(code : Int) -> ProcessEventType? {
match code {
1 => Some(ProcessInstanceStart)
2 => Some(ProcessInstanceEnd)
3 => Some(ProcessTaskStart)
4 => Some(CcCreate)
5 => Some(TaskComplete)
6 => Some(TaskReject)
7 => Some(TaskTransfer)
8 => Some(TaskWithdraw)
9 => Some(InstanceTerminated)
_ => None
}
}
///|
/// spec §11.3 规范名(集成层跨语言判据一律用规范名,不得拿数字码当判据)
pub fn ProcessEventType::name(self : ProcessEventType) -> String {
match self {
ProcessInstanceStart => "PROCESS_INSTANCE_START"
ProcessInstanceEnd => "PROCESS_INSTANCE_END"
ProcessTaskStart => "PROCESS_TASK_START"
CcCreate => "CC_CREATE"
TaskComplete => "TASK_COMPLETE"
TaskReject => "TASK_REJECT"
TaskTransfer => "TASK_TRANSFER"
TaskWithdraw => "TASK_WITHDRAW"
InstanceTerminated => "INSTANCE_TERMINATED"
}
}
///|
pub(all) struct ProcessEvent {
event_type : ProcessEventType
source_id : Int64
data : @json.FlowData
/// 抄送人 id(仅 CcCreate;直传事件体,集成层监听器免反查 cc 表)
cc_actor_id : String?
}
///|
pub fn ProcessEvent::event_type(self : ProcessEvent) -> ProcessEventType {
self.event_type
}
///|
pub fn ProcessEvent::source_id(self : ProcessEvent) -> Int64 {
self.source_id
}
///|
pub fn ProcessEvent::cc_actor_id(self : ProcessEvent) -> String? {
self.cc_actor_id
}
///|
pub fn ProcessEvent::make(event_type : ProcessEventType, source_id : Int64) -> ProcessEvent {
{ event_type, source_id, data: @json.FlowData::new(), cc_actor_id: None }
}
///|
pub fn ProcessEvent::with_data(self : ProcessEvent, data : @json.FlowData) -> ProcessEvent {
{ ..self, data }
}
///|
pub fn ProcessEvent::with_cc_actor_id(self : ProcessEvent, cc_actor_id : String) -> ProcessEvent {
{ ..self, cc_actor_id: Some(cc_actor_id) }
}
///|
/// 事件发布:逐监听器兜底(issues/104 P2)——单监听器异常只捕获不传播,
/// 不影响引擎主流程、不中断后续监听器。监听器形态为闭包数组(Ctx 装配)。
pub async fn notify(
event : ProcessEvent,
listeners : Array[(async (ProcessEvent) -> Unit raise @error.JeeflowError)]
) -> Unit raise @error.JeeflowError {
for listener in listeners {
try {
(listener)(event)
} catch {
err => println(listener_error_warning(event, err)) // F08 口径下半句(audit8 R19):逐支隔离+带原因 ERROR 日志;文案判据在 listener_error_warning
}
}
}
///|
/// 监听器异常隔离的诊断日志文案(F08 裁定完整口径=「每支 try/catch + 带原因 ERROR 日志」的
/// 后半句;audit8 R19 补齐)。抽纯函数的理由同 engine 的 custom_*_warning:println 的效果在
/// 测试里读不回来,判据留在纯函数、副作用留在调用点。
pub fn listener_error_warning(event : ProcessEvent, err : @error.JeeflowError) -> String {
let event_name = event.event_type().name()
let source_id = event.source_id()
let reason = err.message()
"[jeeflow] ERROR 事件监听器异常已隔离 event=\{event_name} sourceId=\{source_id} err=\{reason}(不回滚主流程、不中断后续监听器)"
}
// ── 显式 extend(implicit_impl_as_method 弃办:impl 的方法不再被隐式提升为常规方法)──
// 由 scripts/moon_warn_w2.py 从编译器消息里生成;一行一个 (类型, trait),可 diff 可复审。
pub extend ProcessEventType with Eq::{equal, not_equal}
pub extend ProcessEventType with Debug::{to_repr}