This commit is contained in:
111
server-rs/crates/api-server/src/work_play_tracking.rs
Normal file
111
server-rs/crates/api-server/src/work_play_tracking.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
use module_runtime::RuntimeTrackingScopeKind;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::{
|
||||
auth::AuthenticatedAccessToken,
|
||||
request_context::RequestContext,
|
||||
state::AppState,
|
||||
tracking::{TrackingEventDraft, record_tracking_event_after_success},
|
||||
};
|
||||
|
||||
pub(crate) const WORK_PLAY_START_EVENT_KEY: &str = "work_play_start";
|
||||
|
||||
pub(crate) struct WorkPlayTrackingDraft {
|
||||
pub play_type: &'static str,
|
||||
pub work_id: String,
|
||||
pub user_id: String,
|
||||
pub owner_user_id: Option<String>,
|
||||
pub profile_id: Option<String>,
|
||||
pub run_id: Option<String>,
|
||||
pub source_route: &'static str,
|
||||
pub extra: Value,
|
||||
}
|
||||
|
||||
impl WorkPlayTrackingDraft {
|
||||
pub(crate) fn new(
|
||||
play_type: &'static str,
|
||||
work_id: impl Into<String>,
|
||||
authenticated: &AuthenticatedAccessToken,
|
||||
source_route: &'static str,
|
||||
) -> Self {
|
||||
let user_id = authenticated.claims().user_id().to_string();
|
||||
Self {
|
||||
play_type,
|
||||
work_id: work_id.into(),
|
||||
user_id,
|
||||
owner_user_id: None,
|
||||
profile_id: None,
|
||||
run_id: None,
|
||||
source_route,
|
||||
extra: json!({}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn owner_user_id(mut self, owner_user_id: impl Into<String>) -> Self {
|
||||
self.owner_user_id = Some(owner_user_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn profile_id(mut self, profile_id: impl Into<String>) -> Self {
|
||||
self.profile_id = Some(profile_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn run_id(mut self, run_id: impl Into<String>) -> Self {
|
||||
self.run_id = Some(run_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn extra(mut self, extra: Value) -> Self {
|
||||
self.extra = extra;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// 作品级正式游玩埋点:scope 固定为 work,scope_id 固定为稳定作品 ID。
|
||||
/// 中文注释:该埋点用于“某作品被多少用户玩过”等分析,写入失败不阻断 runtime 主流程。
|
||||
pub(crate) async fn record_work_play_start_after_success(
|
||||
state: &AppState,
|
||||
request_context: &RequestContext,
|
||||
draft: WorkPlayTrackingDraft,
|
||||
) {
|
||||
let mut metadata = json!({
|
||||
"operation": WORK_PLAY_START_EVENT_KEY,
|
||||
"playType": draft.play_type,
|
||||
"workId": draft.work_id,
|
||||
"sourceRoute": draft.source_route,
|
||||
});
|
||||
metadata["userId"] = json!(draft.user_id);
|
||||
if let Some(owner_user_id) = draft.owner_user_id.as_deref() {
|
||||
metadata["ownerUserId"] = json!(owner_user_id);
|
||||
}
|
||||
if let Some(profile_id) = draft.profile_id.as_deref() {
|
||||
metadata["profileId"] = json!(profile_id);
|
||||
}
|
||||
if let Some(run_id) = draft.run_id.as_deref() {
|
||||
metadata["runId"] = json!(run_id);
|
||||
}
|
||||
if !draft.extra.is_null() {
|
||||
metadata["extra"] = draft.extra;
|
||||
}
|
||||
|
||||
let mut tracking = TrackingEventDraft::new(WORK_PLAY_START_EVENT_KEY, draft.play_type);
|
||||
tracking.scope_kind = RuntimeTrackingScopeKind::Work;
|
||||
tracking.scope_id = draft.work_id;
|
||||
tracking.user_id = Some(draft.user_id);
|
||||
tracking.owner_user_id = draft.owner_user_id;
|
||||
tracking.profile_id = draft.profile_id;
|
||||
tracking.metadata = metadata;
|
||||
|
||||
record_tracking_event_after_success(state, request_context, tracking).await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn work_play_event_key_is_stable() {
|
||||
assert_eq!(WORK_PLAY_START_EVENT_KEY, "work_play_start");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user