Update wire protocol to version 7 and enhance presence management features
- Bumped the wire protocol version to 7, reflecting significant changes in the communication structure. - Introduced a new presence message type for real-time occupancy updates, including node activity and individual presence states. - Updated the API to include a directory endpoint for fetching short id→name mappings, improving client-side name resolution. - Revised the map snapshot structure to be static, with people and current lessons now handled through the presence stream. - Enhanced client-side handling of presence updates, including UI adjustments to display live occupancy and activity. - Updated documentation to reflect the new protocol features and changes in presence management. - Added tests to validate the new presence functionalities and ensure robust handling of real-time data.
This commit is contained in:
@@ -85,6 +85,17 @@ public class ProtocolCodecTests
|
||||
Assert.Equal(message, ProtocolCodec.ReadSetSpeed(buffer[..length]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkipEmpty_IsASingleByte()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
|
||||
|
||||
var length = ProtocolCodec.WriteSkipEmpty(buffer);
|
||||
|
||||
Assert.Equal(1, length);
|
||||
Assert.Equal(MessageType.ClientSkipEmpty, ProtocolCodec.PeekMessageType(buffer[..length]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Welcome_RoundTripsAndIsFourBytes()
|
||||
{
|
||||
@@ -110,17 +121,44 @@ public class ProtocolCodecTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clock_RoundTripsAndIsFifteenBytes()
|
||||
public void Clock_RoundTripsAndIsTwentyFourBytes()
|
||||
{
|
||||
var message = new ServerClockMessage(7, 1_333_432_800_000, Running: true, SpeedIndex: 2);
|
||||
var message = new ServerClockMessage(
|
||||
7,
|
||||
1_333_432_800_000,
|
||||
Running: true,
|
||||
SpeedIndex: 2,
|
||||
SkipAllowed: true,
|
||||
SkipTargetUnixMs: 1_333_516_800_000);
|
||||
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
|
||||
|
||||
var length = ProtocolCodec.WriteClock(buffer, message);
|
||||
|
||||
Assert.Equal(15, length);
|
||||
Assert.Equal(24, length);
|
||||
Assert.Equal((byte)MessageType.ServerClock, buffer[0]);
|
||||
Assert.Equal(7, BitConverter.ToInt32(buffer[1..5]));
|
||||
Assert.Equal(1_333_432_800_000, BitConverter.ToInt64(buffer[5..13]));
|
||||
Assert.Equal(1, buffer[13]);
|
||||
Assert.Equal(2, buffer[14]);
|
||||
Assert.Equal(1, buffer[15]);
|
||||
Assert.Equal(1_333_516_800_000, BitConverter.ToInt64(buffer[16..24]));
|
||||
Assert.Equal(message, ProtocolCodec.ReadClock(buffer[..length]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Clock_WithoutSkip_WritesZeroTarget()
|
||||
{
|
||||
var message = new ServerClockMessage(1, 0, Running: false, SpeedIndex: 1);
|
||||
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
|
||||
|
||||
var length = ProtocolCodec.WriteClock(buffer, message);
|
||||
var read = ProtocolCodec.ReadClock(buffer[..length]);
|
||||
|
||||
Assert.Equal(24, length);
|
||||
Assert.False(read.SkipAllowed);
|
||||
Assert.Equal(0, read.SkipTargetUnixMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SchoolGone_RoundTripsAndIsFiveBytes()
|
||||
{
|
||||
@@ -164,34 +202,45 @@ public class ProtocolCodecTests
|
||||
Assert.Equal(0, read.Nodes[0].PupilSlots);
|
||||
Assert.Equal([new MapSnapshotItem("Стул", 2)], read.Nodes[1].Items);
|
||||
Assert.Equal(["Директор"], read.Nodes[1].Positions);
|
||||
Assert.Equal("", read.Nodes[0].ActivitySubject);
|
||||
Assert.Empty(read.Nodes[0].Present);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapSnapshot_RoundTripsOccupancyAfterPositions()
|
||||
public void Presence_RoundTripsAndWritesHeaderOffsets()
|
||||
{
|
||||
var message = new ServerMapSnapshotMessage(3, [
|
||||
new MapSnapshotNode(
|
||||
3,
|
||||
"classroom-101",
|
||||
"floor-1",
|
||||
"Класс 101",
|
||||
16,
|
||||
[new MapSnapshotItem("Парта", 16)],
|
||||
[],
|
||||
"Математика",
|
||||
"5А",
|
||||
["Иванова Ольга Михайловна", "Соколов Иван Петрович"]),
|
||||
]);
|
||||
var buffer = new byte[ProtocolCodec.MapSnapshotSize(message)];
|
||||
var message = new ServerPresenceMessage(
|
||||
7,
|
||||
[
|
||||
new PresenceNode("classroom-101", 18, "Математика", "5А"),
|
||||
new PresenceNode("corridor-1", 4),
|
||||
],
|
||||
[
|
||||
new PresencePerson("f0.c0", "classroom-101", PresenceState.Here),
|
||||
new PresencePerson("f3.p1", "corridor-1", PresenceState.Walking),
|
||||
]);
|
||||
var buffer = new byte[ProtocolCodec.PresenceSize(message)];
|
||||
|
||||
var length = ProtocolCodec.WriteMapSnapshot(buffer, message);
|
||||
var read = ProtocolCodec.ReadMapSnapshot(buffer.AsSpan(0, length));
|
||||
var length = ProtocolCodec.WritePresence(buffer, message);
|
||||
|
||||
Assert.Equal((byte)MessageType.ServerPresence, buffer[0]);
|
||||
Assert.Equal(7, BitConverter.ToInt32(buffer.AsSpan(1, 4)));
|
||||
Assert.Equal((ushort)2, BitConverter.ToUInt16(buffer.AsSpan(5, 2)));
|
||||
Assert.Equal(length, ProtocolCodec.PresenceSize(message));
|
||||
|
||||
var read = ProtocolCodec.ReadPresence(buffer.AsSpan(0, length));
|
||||
Assert.Equal(message.SchoolId, read.SchoolId);
|
||||
Assert.Equal(2, read.Nodes.Count);
|
||||
Assert.Equal("classroom-101", read.Nodes[0].Id);
|
||||
Assert.Equal(18, read.Nodes[0].Count);
|
||||
Assert.Equal("Математика", read.Nodes[0].ActivitySubject);
|
||||
Assert.Equal("5А", read.Nodes[0].ActivityClass);
|
||||
Assert.Equal(["Иванова Ольга Михайловна", "Соколов Иван Петрович"], read.Nodes[0].Present);
|
||||
Assert.Equal("corridor-1", read.Nodes[1].Id);
|
||||
Assert.Equal(4, read.Nodes[1].Count);
|
||||
Assert.Equal("", read.Nodes[1].ActivitySubject);
|
||||
Assert.Equal(2, read.People.Count);
|
||||
Assert.Equal("f0.c0", read.People[0].Id);
|
||||
Assert.Equal("classroom-101", read.People[0].NodeId);
|
||||
Assert.Equal(PresenceState.Here, read.People[0].State);
|
||||
Assert.Equal(PresenceState.Walking, read.People[1].State);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -287,7 +336,9 @@ public class ProtocolCodecTests
|
||||
{
|
||||
// Handlers size clock/welcome/pong buffers from this constant; map snapshots use MaxMessageSize.
|
||||
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
|
||||
var clock = ProtocolCodec.WriteClock(buffer, new ServerClockMessage(1, long.MaxValue, true, 4));
|
||||
var clock = ProtocolCodec.WriteClock(
|
||||
buffer,
|
||||
new ServerClockMessage(1, long.MaxValue, true, 4, SkipAllowed: true, SkipTargetUnixMs: long.MaxValue));
|
||||
|
||||
Assert.True(clock <= ProtocolCodec.MaxFrameSize);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user