feat: add work-level play tracking
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-05-09 19:56:59 +08:00
parent 32a1530ab1
commit 3ad1075227
24 changed files with 1452 additions and 105 deletions

View File

@@ -529,6 +529,7 @@ pub mod record_custom_world_profile_like_procedure;
pub mod record_custom_world_profile_play_procedure;
pub mod record_daily_login_tracking_event_and_return_procedure;
pub mod record_puzzle_work_like_procedure;
pub mod record_tracking_event_and_return_procedure;
pub mod record_visual_novel_runtime_event_procedure;
pub mod redeem_profile_referral_invite_code_procedure;
pub mod redeem_profile_reward_code_procedure;
@@ -662,6 +663,7 @@ pub mod runtime_snapshot_row_type;
pub mod runtime_snapshot_table;
pub mod runtime_snapshot_type;
pub mod runtime_snapshot_upsert_input_type;
pub mod runtime_tracking_event_input_type;
pub mod runtime_tracking_event_procedure_result_type;
pub mod runtime_tracking_scope_kind_type;
pub mod save_puzzle_form_draft_procedure;
@@ -1323,6 +1325,7 @@ pub use record_custom_world_profile_like_procedure::record_custom_world_profile_
pub use record_custom_world_profile_play_procedure::record_custom_world_profile_play;
pub use record_daily_login_tracking_event_and_return_procedure::record_daily_login_tracking_event_and_return;
pub use record_puzzle_work_like_procedure::record_puzzle_work_like;
pub use record_tracking_event_and_return_procedure::record_tracking_event_and_return;
pub use record_visual_novel_runtime_event_procedure::record_visual_novel_runtime_event;
pub use redeem_profile_referral_invite_code_procedure::redeem_profile_referral_invite_code;
pub use redeem_profile_reward_code_procedure::redeem_profile_reward_code;
@@ -1456,6 +1459,7 @@ pub use runtime_snapshot_row_type::RuntimeSnapshotRow;
pub use runtime_snapshot_table::*;
pub use runtime_snapshot_type::RuntimeSnapshot;
pub use runtime_snapshot_upsert_input_type::RuntimeSnapshotUpsertInput;
pub use runtime_tracking_event_input_type::RuntimeTrackingEventInput;
pub use runtime_tracking_event_procedure_result_type::RuntimeTrackingEventProcedureResult;
pub use runtime_tracking_scope_kind_type::RuntimeTrackingScopeKind;
pub use save_puzzle_form_draft_procedure::save_puzzle_form_draft;

View File

@@ -0,0 +1,59 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::runtime_tracking_event_input_type::RuntimeTrackingEventInput;
use super::runtime_tracking_event_procedure_result_type::RuntimeTrackingEventProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct RecordTrackingEventAndReturnArgs {
pub input: RuntimeTrackingEventInput,
}
impl __sdk::InModule for RecordTrackingEventAndReturnArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `record_tracking_event_and_return`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait record_tracking_event_and_return {
fn record_tracking_event_and_return(&self, input: RuntimeTrackingEventInput) {
self.record_tracking_event_and_return_then(input, |_, _| {});
}
fn record_tracking_event_and_return_then(
&self,
input: RuntimeTrackingEventInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeTrackingEventProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
impl record_tracking_event_and_return for super::RemoteProcedures {
fn record_tracking_event_and_return_then(
&self,
input: RuntimeTrackingEventInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeTrackingEventProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, RuntimeTrackingEventProcedureResult>(
"record_tracking_event_and_return",
RecordTrackingEventAndReturnArgs { input },
__callback,
);
}
}

View File

@@ -0,0 +1,26 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::runtime_tracking_scope_kind_type::RuntimeTrackingScopeKind;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct RuntimeTrackingEventInput {
pub event_id: String,
pub event_key: String,
pub scope_kind: RuntimeTrackingScopeKind,
pub scope_id: String,
pub user_id: Option<String>,
pub owner_user_id: Option<String>,
pub profile_id: Option<String>,
pub module_key: Option<String>,
pub metadata_json: String,
pub occurred_at_micros: i64,
}
impl __sdk::InModule for RuntimeTrackingEventInput {
type Module = super::RemoteModule;
}

View File

@@ -339,22 +339,60 @@ impl SpacetimeClient {
&self,
user_id: String,
) -> Result<(), SpacetimeClientError> {
let procedure_input = build_runtime_profile_task_center_get_input(user_id)
.map_err(SpacetimeClientError::validation_failed)?
.into();
let normalized_user_id = user_id.trim().to_string();
let occurred_at_micros =
shared_kernel::offset_datetime_to_unix_micros(time::OffsetDateTime::now_utc());
let day_key = runtime_profile_beijing_day_key(occurred_at_micros);
self.record_tracking_event(
format!("daily-login:{}:{}", normalized_user_id, day_key),
"daily_login".to_string(),
DomainRuntimeTrackingScopeKind::User,
normalized_user_id.clone(),
Some(normalized_user_id.clone()),
Some(normalized_user_id),
None,
Some("profile".to_string()),
"{}".to_string(),
occurred_at_micros,
)
.await
}
pub async fn record_tracking_event(
&self,
event_id: String,
event_key: String,
scope_kind: DomainRuntimeTrackingScopeKind,
scope_id: String,
user_id: Option<String>,
owner_user_id: Option<String>,
profile_id: Option<String>,
module_key: Option<String>,
metadata_json: String,
occurred_at_micros: i64,
) -> Result<(), SpacetimeClientError> {
let procedure_input = crate::module_bindings::RuntimeTrackingEventInput {
event_id,
event_key,
scope_kind: map_runtime_tracking_scope_kind(scope_kind),
scope_id,
user_id,
owner_user_id,
profile_id,
module_key,
metadata_json,
occurred_at_micros,
};
self.call_after_connect(move |connection, sender| {
connection
.procedures()
.record_daily_login_tracking_event_and_return_then(
procedure_input,
move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_tracking_event_procedure_result);
send_once(&sender, mapped);
},
);
.record_tracking_event_and_return_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_runtime_tracking_event_procedure_result);
send_once(&sender, mapped);
});
})
.await
}
@@ -885,3 +923,9 @@ impl SpacetimeClient {
.await
}
}
fn runtime_profile_beijing_day_key(occurred_at_micros: i64) -> i64 {
const PROFILE_TASK_BEIJING_OFFSET_MICROS: i64 = 28_800_000_000;
const PROFILE_RUNTIME_DAY_MICROS: i64 = 86_400_000_000;
(occurred_at_micros + PROFILE_TASK_BEIJING_OFFSET_MICROS).div_euclid(PROFILE_RUNTIME_DAY_MICROS)
}