consolidate more tables

This commit is contained in:
2026-04-10 18:09:33 -04:00
parent 8b80f2a600
commit 2bb5d31777
18 changed files with 236 additions and 236 deletions
+1 -5
View File
@@ -135,15 +135,11 @@ pub fn on_disconnect(ctx: &ReducerContext) {
sync_server_member_info(&ctx.db, ctx.sender());
if let Some(vs) = ctx.db.voice_state().identity().find(ctx.sender()) {
ctx.db.voice_state().delete(vs);
}
if let Some(ta) = ctx.db.typing_activity().identity().find(ctx.sender()) {
ctx.db.typing_activity().delete(ta);
}
clear_signaling_for_user(&ctx.db, ctx.sender());
clear_user_presence(&ctx.db, ctx.sender());
}
#[spacetimedb::reducer]
+41 -69
View File
@@ -8,13 +8,13 @@ pub fn set_typing(ctx: &ReducerContext, channel_id: u64, typing: bool) {
ctx.db.typing_activity().identity().update(TypingActivity {
identity: ctx.sender(),
channel_id,
is_typing: typing,
typing: typing,
});
} else {
ctx.db.typing_activity().insert(TypingActivity {
identity: ctx.sender(),
channel_id,
is_typing: typing,
typing: typing,
});
}
}
@@ -465,23 +465,6 @@ pub fn extend_subscription(ctx: &ReducerContext, channel_id: u64, earliest_seq_i
}
}
#[spacetimedb::reducer]
pub fn set_talking(ctx: &ReducerContext, talking: bool, channel_id: u64) {
if let Some(_) = ctx.db.voice_activity().identity().find(ctx.sender()) {
ctx.db.voice_activity().identity().update(VoiceActivity {
identity: ctx.sender(),
channel_id,
is_talking: talking,
});
} else {
ctx.db.voice_activity().insert(VoiceActivity {
identity: ctx.sender(),
channel_id,
is_talking: talking,
});
}
}
#[spacetimedb::reducer]
pub fn create_server(ctx: &ReducerContext, name: String) {
validate_name(&name).expect("Invalid name");
@@ -660,44 +643,42 @@ pub fn join_voice(ctx: &ReducerContext, channel_id: u64) {
panic!("Invalid voice channel");
}
if let Some(existing) = ctx.db.voice_state().identity().find(ctx.sender()) {
if existing.channel_id != channel_id {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
if state.channel_id != channel_id {
clear_signaling_for_user(&ctx.db, ctx.sender());
ctx.db.voice_state().identity().update(VoiceState {
identity: ctx.sender(),
channel_id,
is_sharing_screen: false,
is_muted: false,
is_deafened: false,
});
state.channel_id = channel_id;
state.is_sharing_screen = false;
state.is_talking = false;
state.watching = None;
ctx.db.user_state().identity().update(state);
}
} else {
ctx.db.voice_state().insert(VoiceState {
ctx.db.user_state().insert(UserState {
identity: ctx.sender(),
channel_id,
is_sharing_screen: false,
is_muted: false,
is_deafened: false,
is_talking: false,
watching: None,
});
}
}
#[spacetimedb::reducer]
pub fn set_sharing_screen(ctx: &ReducerContext, sharing: bool) {
if let Some(mut state) = ctx.db.voice_state().identity().find(ctx.sender()) {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.is_sharing_screen = sharing;
ctx.db.voice_state().identity().update(state);
ctx.db.user_state().identity().update(state);
if !sharing {
let watching: Vec<_> = ctx
.db
.watching()
.watchee()
.filter(ctx.sender())
.map(|w| w.id)
// Clean up watching state for people watching ME
let watchers: Vec<_> = ctx.db.user_state().iter()
.filter(|s| s.watching == Some(ctx.sender()))
.collect();
for id in watching {
ctx.db.watching().id().delete(id);
for mut w in watchers {
w.watching = None;
ctx.db.user_state().identity().update(w);
}
let signals: Vec<_> = ctx
@@ -717,60 +698,51 @@ pub fn set_sharing_screen(ctx: &ReducerContext, sharing: bool) {
#[spacetimedb::reducer]
pub fn set_mute(ctx: &ReducerContext, muted: bool) {
if let Some(mut state) = ctx.db.voice_state().identity().find(ctx.sender()) {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.is_muted = muted;
ctx.db.voice_state().identity().update(state);
ctx.db.user_state().identity().update(state);
}
}
#[spacetimedb::reducer]
pub fn set_deafen(ctx: &ReducerContext, deafened: bool) {
if let Some(mut state) = ctx.db.voice_state().identity().find(ctx.sender()) {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.is_deafened = deafened;
ctx.db.voice_state().identity().update(state);
ctx.db.user_state().identity().update(state);
}
}
#[spacetimedb::reducer]
pub fn start_watching(ctx: &ReducerContext, watchee: Identity, channel_id: u64) {
pub fn set_talking(ctx: &ReducerContext, talking: bool) {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.is_talking = talking;
ctx.db.user_state().identity().update(state);
}
}
#[spacetimedb::reducer]
pub fn start_watching(ctx: &ReducerContext, watchee: Identity) {
if ctx.sender() == watchee {
return;
}
for w in ctx.db.watching().watcher().filter(ctx.sender()) {
if w.watchee == watchee {
return;
}
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.watching = Some(watchee);
ctx.db.user_state().identity().update(state);
}
ctx.db.watching().insert(Watching {
id: 0,
watcher: ctx.sender(),
watchee,
channel_id,
});
}
#[spacetimedb::reducer]
pub fn stop_watching(ctx: &ReducerContext, watchee: Identity) {
let to_delete: Vec<_> = ctx
.db
.watching()
.watcher()
.filter(ctx.sender())
.filter(|w| w.watchee == watchee)
.map(|w| w.id)
.collect();
for id in to_delete {
ctx.db.watching().id().delete(id);
pub fn stop_watching(ctx: &ReducerContext) {
if let Some(mut state) = ctx.db.user_state().identity().find(ctx.sender()) {
state.watching = None;
ctx.db.user_state().identity().update(state);
}
}
#[spacetimedb::reducer]
pub fn leave_voice(ctx: &ReducerContext) {
if let Some(_) = ctx.db.voice_state().identity().find(ctx.sender()) {
ctx.db.voice_state().identity().delete(ctx.sender());
}
clear_signaling_for_user(&ctx.db, ctx.sender());
clear_user_presence(&ctx.db, ctx.sender());
}
#[spacetimedb::reducer]
+9 -25
View File
@@ -87,9 +87,9 @@ pub struct DirectMessage {
#[index(btree)]
pub is_open_recipient: bool,
}
#[spacetimedb::table(accessor = voice_state, public)]
pub struct VoiceState {
#[spacetimedb::table(accessor = user_state)]
#[derive(Clone)]
pub struct UserState {
#[primary_key]
pub identity: Identity,
#[index(btree)]
@@ -97,28 +97,8 @@ pub struct VoiceState {
pub is_sharing_screen: bool,
pub is_muted: bool,
pub is_deafened: bool,
}
#[spacetimedb::table(accessor = voice_activity, public)]
pub struct VoiceActivity {
#[primary_key]
pub identity: Identity,
#[index(btree)]
pub channel_id: u64,
pub is_talking: bool,
}
#[spacetimedb::table(accessor = watching, public)]
pub struct Watching {
#[primary_key]
#[auto_inc]
pub id: u64,
#[index(btree)]
pub watcher: Identity,
#[index(btree)]
pub watchee: Identity,
#[index(btree)]
pub channel_id: u64,
pub watching: Option<Identity>,
}
#[derive(spacetimedb::SpacetimeType, Clone, Copy, Debug, PartialEq)]
@@ -128,6 +108,7 @@ pub enum SignalKind {
IceCandidate,
}
#[derive(spacetimedb::SpacetimeType, Clone, Copy, Debug, PartialEq)]
pub enum MediaType {
Voice,
@@ -226,14 +207,17 @@ pub struct Image {
}
#[spacetimedb::table(accessor = typing_activity, public)]
#[derive(Clone)]
pub struct TypingActivity {
#[primary_key]
#[index(btree)]
pub identity: Identity,
#[index(btree)]
pub channel_id: u64,
pub is_typing: bool,
pub typing: bool,
}
#[spacetimedb::table(accessor = recent_message)]
pub struct RecentMessage {
#[primary_key]
+7 -14
View File
@@ -265,20 +265,6 @@ pub fn get_visible_image_ids_read_only(db: &LocalReadOnly, identity: Identity) -
}
pub fn clear_signaling_for_user(db: &Local, identity: Identity) {
if let Some(va) = db.voice_activity().identity().find(identity) {
db.voice_activity().delete(va);
}
let watchers: Vec<_> = db.watching().watcher().filter(identity).collect();
for row in watchers {
db.watching().delete(row);
}
let watchees: Vec<_> = db.watching().watchee().filter(identity).collect();
for row in watchees {
db.watching().delete(row);
}
for row in db
.webrtc_signal()
.sender()
@@ -297,6 +283,13 @@ pub fn clear_signaling_for_user(db: &Local, identity: Identity) {
}
}
pub fn clear_user_presence(db: &Local, identity: Identity) {
if let Some(state) = db.user_state().identity().find(identity) {
db.user_state().delete(state);
}
clear_signaling_for_user(db, identity);
}
pub fn auto_join_community_server(db: &Local, identity: Identity) {
let community_server = db.server().name().filter(&"Zep".to_string()).next();
if let Some(s) = community_server {
+71 -1
View File
@@ -1,6 +1,6 @@
use crate::tables::*;
use crate::utils::*;
use spacetimedb::{Identity, Query, Timestamp, ViewContext};
use spacetimedb::{Identity, Query, Table, Timestamp, ViewContext};
#[derive(spacetimedb::SpacetimeType)]
pub struct VisibleImageRow {
@@ -27,6 +27,40 @@ pub struct VisibleMessageRow {
pub is_encrypted: bool,
}
#[spacetimedb::view(accessor = visible_typing_activity, public)]
pub fn visible_typing_activity(ctx: &ViewContext) -> Vec<TypingActivity> {
let identity = ctx.sender();
let mut results = Vec::new();
// 1. Server channels
for member in ctx.db.server_member().identity().filter(identity) {
if let Some(s) = ctx.db.server().id().find(member.server_id) {
for chan_meta in s.channels {
for activity in ctx.db.typing_activity().channel_id().filter(chan_meta.id) {
results.push(activity);
}
}
}
}
// 2. DM channels
let mut dm_channel_ids = Vec::new();
for dm in ctx.db.direct_message().sender().filter(identity) {
dm_channel_ids.push(dm.channel_id);
}
for dm in ctx.db.direct_message().recipient().filter(identity) {
dm_channel_ids.push(dm.channel_id);
}
for channel_id in dm_channel_ids {
for activity in ctx.db.typing_activity().channel_id().filter(channel_id) {
results.push(activity);
}
}
results
}
#[derive(spacetimedb::SpacetimeType)]
pub struct MyChannelSubscriptionRow {
pub identity: Identity,
@@ -226,6 +260,42 @@ pub fn visible_images(ctx: &ViewContext) -> Vec<VisibleImageRow> {
results
}
#[spacetimedb::view(accessor = visible_user_states, public)]
pub fn visible_user_states(ctx: &ViewContext) -> Vec<UserState> {
let identity = ctx.sender();
let mut results = std::collections::HashMap::new();
// 1. My own state
if let Some(my_state) = ctx.db.user_state().identity().find(identity) {
results.insert(my_state.identity, my_state.clone());
}
// 2. States in my servers
for member in ctx.db.server_member().identity().filter(identity) {
if let Some(s) = ctx.db.server().id().find(member.server_id) {
for chan_meta in s.channels {
for state in ctx.db.user_state().channel_id().filter(chan_meta.id) {
results.insert(state.identity, state.clone());
}
}
}
}
// 3. States in my DMs
for dm in ctx.db.direct_message().sender().filter(identity) {
for state in ctx.db.user_state().channel_id().filter(dm.channel_id) {
results.insert(state.identity, state.clone());
}
}
for dm in ctx.db.direct_message().recipient().filter(identity) {
for state in ctx.db.user_state().channel_id().filter(dm.channel_id) {
results.insert(state.identity, state.clone());
}
}
results.into_values().collect()
}
#[spacetimedb::view(accessor = visible_webrtc_signals, public)]
pub fn visible_webrtc_signals(ctx: &ViewContext) -> Vec<WebRTCSignal> {
let identity = ctx.sender();