feat(ios,p0): iOS P0 platform, audio fixes, channel UX
This commit is contained in:
@@ -454,7 +454,9 @@ async fn connection_task(
|
||||
Some(Err(e)) => {
|
||||
let msg = format!("{e}");
|
||||
let _ = ready_tx.send(Err(ProtocolError::DisconnectedEarly(msg.clone())));
|
||||
exit!(DisconnectReason::Error(format!("disconnected early: {msg}")));
|
||||
exit!(DisconnectReason::Error(format!(
|
||||
"disconnected early: {msg}"
|
||||
)));
|
||||
}
|
||||
None => {
|
||||
let msg = "event stream ended before snapshot".to_string();
|
||||
@@ -592,7 +594,11 @@ async fn connection_task(
|
||||
let expired: Vec<MessageHandle> = pending_moves
|
||||
.iter()
|
||||
.filter_map(|(handle, (_, deadline))| {
|
||||
if now >= *deadline { Some(*handle) } else { None }
|
||||
if now >= *deadline {
|
||||
Some(*handle)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for handle in expired {
|
||||
@@ -608,11 +614,14 @@ async fn connection_task(
|
||||
let snap = build_snapshot(&con);
|
||||
let _ = reply.send(snap);
|
||||
}
|
||||
Ok(Request::MoveToChannel { channel_id, password, reply }) => {
|
||||
Ok(Request::MoveToChannel {
|
||||
channel_id,
|
||||
password,
|
||||
reply,
|
||||
}) => {
|
||||
match move_self_to(&mut con, channel_id, password.as_deref()) {
|
||||
Ok(handle) => {
|
||||
let deadline =
|
||||
std::time::Instant::now() + Duration::from_secs(3);
|
||||
let deadline = std::time::Instant::now() + Duration::from_secs(3);
|
||||
pending_moves.insert(handle, (reply, deadline));
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -622,7 +631,11 @@ async fn connection_task(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Request::SetMuted { input, output, reply }) => {
|
||||
Ok(Request::SetMuted {
|
||||
input,
|
||||
output,
|
||||
reply,
|
||||
}) => {
|
||||
let r = set_self_muted(&mut con, input, output);
|
||||
let _ = reply.send(r);
|
||||
}
|
||||
@@ -785,8 +798,7 @@ fn sort_channels_tree_by<'a, T>(
|
||||
// Defensive: if a channel's `parent` does not appear anywhere
|
||||
// in the emitted tree (orphaned subtree) append it so it isn't
|
||||
// lost. We track emitted ids and dump anything else.
|
||||
let emitted: std::collections::HashSet<u64> =
|
||||
out.iter().map(|c| extract(c).0).collect();
|
||||
let emitted: std::collections::HashSet<u64> = out.iter().map(|c| extract(c).0).collect();
|
||||
let mut orphans: Vec<&'a T> = items
|
||||
.iter()
|
||||
.copied()
|
||||
@@ -916,10 +928,26 @@ mod tests {
|
||||
// iteration order. order=0 -> first; order=X means "comes
|
||||
// after the channel with id=X". Expected emitted order is
|
||||
// the linked-list walk: a -> b -> c -> d.
|
||||
let a = FakeChannel { id: 100, parent: 0, order: 0 };
|
||||
let b = FakeChannel { id: 200, parent: 0, order: 100 };
|
||||
let c = FakeChannel { id: 300, parent: 0, order: 200 };
|
||||
let d = FakeChannel { id: 400, parent: 0, order: 300 };
|
||||
let a = FakeChannel {
|
||||
id: 100,
|
||||
parent: 0,
|
||||
order: 0,
|
||||
};
|
||||
let b = FakeChannel {
|
||||
id: 200,
|
||||
parent: 0,
|
||||
order: 100,
|
||||
};
|
||||
let c = FakeChannel {
|
||||
id: 300,
|
||||
parent: 0,
|
||||
order: 200,
|
||||
};
|
||||
let d = FakeChannel {
|
||||
id: 400,
|
||||
parent: 0,
|
||||
order: 300,
|
||||
};
|
||||
// Deliberately shuffled inputs.
|
||||
let inputs: Vec<&FakeChannel> = vec![&c, &a, &d, &b];
|
||||
let sorted = sort_channels_tree_by(&inputs, extract);
|
||||
@@ -933,9 +961,21 @@ mod tests {
|
||||
// = 999 which does not exist among the siblings. c must
|
||||
// not be dropped — it falls back to the leftover bucket
|
||||
// appended sorted by id at the end.
|
||||
let a = FakeChannel { id: 100, parent: 0, order: 0 };
|
||||
let b = FakeChannel { id: 200, parent: 0, order: 100 };
|
||||
let c = FakeChannel { id: 300, parent: 0, order: 999 };
|
||||
let a = FakeChannel {
|
||||
id: 100,
|
||||
parent: 0,
|
||||
order: 0,
|
||||
};
|
||||
let b = FakeChannel {
|
||||
id: 200,
|
||||
parent: 0,
|
||||
order: 100,
|
||||
};
|
||||
let c = FakeChannel {
|
||||
id: 300,
|
||||
parent: 0,
|
||||
order: 999,
|
||||
};
|
||||
let inputs: Vec<&FakeChannel> = vec![&c, &a, &b];
|
||||
let sorted = sort_channels_tree_by(&inputs, extract);
|
||||
let ids: Vec<u64> = sorted.iter().map(|c| c.id).collect();
|
||||
@@ -951,10 +991,26 @@ mod tests {
|
||||
// │ └── a2 (id=12, parent=10, order=11)
|
||||
// └── b (id=20, order=10)
|
||||
// Expected emission: a, a1, a2, b
|
||||
let a = FakeChannel { id: 10, parent: 0, order: 0 };
|
||||
let a1 = FakeChannel { id: 11, parent: 10, order: 0 };
|
||||
let a2 = FakeChannel { id: 12, parent: 10, order: 11 };
|
||||
let b = FakeChannel { id: 20, parent: 0, order: 10 };
|
||||
let a = FakeChannel {
|
||||
id: 10,
|
||||
parent: 0,
|
||||
order: 0,
|
||||
};
|
||||
let a1 = FakeChannel {
|
||||
id: 11,
|
||||
parent: 10,
|
||||
order: 0,
|
||||
};
|
||||
let a2 = FakeChannel {
|
||||
id: 12,
|
||||
parent: 10,
|
||||
order: 11,
|
||||
};
|
||||
let b = FakeChannel {
|
||||
id: 20,
|
||||
parent: 0,
|
||||
order: 10,
|
||||
};
|
||||
let inputs: Vec<&FakeChannel> = vec![&b, &a2, &a, &a1];
|
||||
let sorted = sort_channels_tree_by(&inputs, extract);
|
||||
let ids: Vec<u64> = sorted.iter().map(|c| c.id).collect();
|
||||
@@ -966,8 +1022,16 @@ mod tests {
|
||||
// a says "comes after b"; b says "comes after a". The
|
||||
// walk must terminate (cycle guard) and both channels
|
||||
// must still appear in the output via the leftover path.
|
||||
let a = FakeChannel { id: 1, parent: 0, order: 2 };
|
||||
let b = FakeChannel { id: 2, parent: 0, order: 1 };
|
||||
let a = FakeChannel {
|
||||
id: 1,
|
||||
parent: 0,
|
||||
order: 2,
|
||||
};
|
||||
let b = FakeChannel {
|
||||
id: 2,
|
||||
parent: 0,
|
||||
order: 1,
|
||||
};
|
||||
let inputs: Vec<&FakeChannel> = vec![&a, &b];
|
||||
let sorted = sort_channels_tree_by(&inputs, extract);
|
||||
// Both reachable in some deterministic order (id-sorted
|
||||
|
||||
@@ -34,8 +34,7 @@ struct CacheEntry {
|
||||
at: Instant,
|
||||
}
|
||||
|
||||
static CACHE: Lazy<Mutex<HashMap<String, CacheEntry>>> =
|
||||
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
static CACHE: Lazy<Mutex<HashMap<String, CacheEntry>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
/// Resolve `host_input` to a list of socket addresses, preferring
|
||||
/// IPv4 over IPv6 so the upstream's first connect attempt is the
|
||||
@@ -189,8 +188,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn unresolvable_returns_dns_failed() {
|
||||
let r =
|
||||
resolve("nonexistent-server-for-chanora-tests.invalid").await;
|
||||
let r = resolve("nonexistent-server-for-chanora-tests.invalid").await;
|
||||
match r {
|
||||
Err(ProtocolError::DnsFailed { host, .. }) => {
|
||||
assert!(host.contains("nonexistent-server-for-chanora-tests.invalid"));
|
||||
|
||||
Reference in New Issue
Block a user