diff --git a/examples~/quickstart/client/module_bindings/IdentityConnectedReducer.cs b/examples~/quickstart/client/module_bindings/IdentityConnectedReducer.cs new file mode 100644 index 00000000..36fd4604 --- /dev/null +++ b/examples~/quickstart/client/module_bindings/IdentityConnectedReducer.cs @@ -0,0 +1,17 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD. +// + +#nullable enable + +using System; +using SpacetimeDB; + +namespace SpacetimeDB.Types +{ + [SpacetimeDB.Type] + public partial class IdentityConnected : IReducerArgs + { + uint IReducerArgs.ReducerIndex => 0; + } +} diff --git a/examples~/quickstart/client/module_bindings/IdentityDisconnectedReducer.cs b/examples~/quickstart/client/module_bindings/IdentityDisconnectedReducer.cs new file mode 100644 index 00000000..79ba1703 --- /dev/null +++ b/examples~/quickstart/client/module_bindings/IdentityDisconnectedReducer.cs @@ -0,0 +1,17 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD. +// + +#nullable enable + +using System; +using SpacetimeDB; + +namespace SpacetimeDB.Types +{ + [SpacetimeDB.Type] + public partial class IdentityDisconnected : IReducerArgs + { + uint IReducerArgs.ReducerIndex => 1; + } +} diff --git a/examples~/quickstart/client/module_bindings/InitReducer.cs b/examples~/quickstart/client/module_bindings/InitReducer.cs new file mode 100644 index 00000000..a8ed3e04 --- /dev/null +++ b/examples~/quickstart/client/module_bindings/InitReducer.cs @@ -0,0 +1,17 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD. +// + +#nullable enable + +using System; +using SpacetimeDB; + +namespace SpacetimeDB.Types +{ + [SpacetimeDB.Type] + public partial class Init : IReducerArgs + { + uint IReducerArgs.ReducerIndex => 2; + } +} diff --git a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs index 15106671..68c6845c 100644 --- a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs +++ b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs @@ -12,7 +12,7 @@ namespace SpacetimeDB.Types [SpacetimeDB.Type] public partial class SendMessage : IReducerArgs { - string IReducerArgs.ReducerName => "send_message"; + uint IReducerArgs.ReducerIndex => 3; public string Text = ""; } diff --git a/examples~/quickstart/client/module_bindings/SetNameReducer.cs b/examples~/quickstart/client/module_bindings/SetNameReducer.cs index 83a0b728..d17c24d7 100644 --- a/examples~/quickstart/client/module_bindings/SetNameReducer.cs +++ b/examples~/quickstart/client/module_bindings/SetNameReducer.cs @@ -12,7 +12,7 @@ namespace SpacetimeDB.Types [SpacetimeDB.Type] public partial class SetName : IReducerArgs { - string IReducerArgs.ReducerName => "set_name"; + uint IReducerArgs.ReducerIndex => 4; public string Name = ""; } diff --git a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs index 726f56d0..078fc09c 100644 --- a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs +++ b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs @@ -65,6 +65,54 @@ public sealed class RemoteReducers : RemoteBase { internal RemoteReducers(DbConnection conn, SetReducerFlags SetReducerFlags) : base(conn) { this.SetCallReducerFlags = SetReducerFlags; } internal readonly SetReducerFlags SetCallReducerFlags; + public delegate void IdentityConnectedHandler(EventContext ctx); + public event IdentityConnectedHandler? OnIdentityConnected; + + public void IdentityConnected() + { + conn.InternalCallReducer(new IdentityConnected { }, this.SetCallReducerFlags.IdentityConnectedFlags); + } + + public bool InvokeIdentityConnected(EventContext ctx, IdentityConnected args) + { + if (OnIdentityConnected == null) return false; + OnIdentityConnected( + ctx + ); + return true; + } + public delegate void IdentityDisconnectedHandler(EventContext ctx); + public event IdentityDisconnectedHandler? OnIdentityDisconnected; + + public void IdentityDisconnected() + { + conn.InternalCallReducer(new IdentityDisconnected { }, this.SetCallReducerFlags.IdentityDisconnectedFlags); + } + + public bool InvokeIdentityDisconnected(EventContext ctx, IdentityDisconnected args) + { + if (OnIdentityDisconnected == null) return false; + OnIdentityDisconnected( + ctx + ); + return true; + } + public delegate void InitHandler(EventContext ctx); + public event InitHandler? OnInit; + + public void Init() + { + conn.InternalCallReducer(new Init { }, this.SetCallReducerFlags.InitFlags); + } + + public bool InvokeInit(EventContext ctx, Init args) + { + if (OnInit == null) return false; + OnInit( + ctx + ); + return true; + } public delegate void SendMessageHandler(EventContext ctx, string text); public event SendMessageHandler? OnSendMessage; @@ -104,6 +152,12 @@ public bool InvokeSetName(EventContext ctx, SetName args) public sealed class SetReducerFlags { internal SetReducerFlags() { } + internal CallReducerFlags IdentityConnectedFlags; + public void IdentityConnected(CallReducerFlags flags) { this.IdentityConnectedFlags = flags; } + internal CallReducerFlags IdentityDisconnectedFlags; + public void IdentityDisconnected(CallReducerFlags flags) { this.IdentityDisconnectedFlags = flags; } + internal CallReducerFlags InitFlags; + public void Init(CallReducerFlags flags) { this.InitFlags = flags; } internal CallReducerFlags SendMessageFlags; public void SendMessage(CallReducerFlags flags) { this.SendMessageFlags = flags; } internal CallReducerFlags SetNameFlags; @@ -126,11 +180,12 @@ internal EventContext(DbConnection conn, Event reducerEvent) : base(con [Type] public partial record Reducer : TaggedEnum<( + IdentityConnected IdentityConnected, + IdentityDisconnected IdentityDisconnected, + Init Init, SendMessage SendMessage, SetName SetName, - Unit StdbNone, - Unit StdbIdentityConnected, - Unit StdbIdentityDisconnected + Unit StdbNone )>; public class DbConnection : DbConnectionBase { @@ -143,21 +198,20 @@ public DbConnection() SetReducerFlags = new(); Reducers = new(this, this.SetReducerFlags); - clientDB.AddTable("message", Db.Message); - clientDB.AddTable("user", Db.User); + clientDB.AddTable(0, Db.Message); + clientDB.AddTable(1, Db.User); } - protected override Reducer ToReducer(TransactionUpdate update) + protected override Reducer ToReducer(uint reducerIdx, TransactionUpdate update) { var encodedArgs = update.ReducerCall.Args; - return update.ReducerCall.ReducerName switch - { - "send_message" => new Reducer.SendMessage(BSATNHelpers.Decode(encodedArgs)), - "set_name" => new Reducer.SetName(BSATNHelpers.Decode(encodedArgs)), - "" => new Reducer.StdbNone(default), - "__identity_connected__" => new Reducer.StdbIdentityConnected(default), - "__identity_disconnected__" => new Reducer.StdbIdentityDisconnected(default), - "" => new Reducer.StdbNone(default), + return reducerIdx switch { + 0 => new Reducer.IdentityConnected(BSATNHelpers.Decode(encodedArgs)), + 1 => new Reducer.IdentityDisconnected(BSATNHelpers.Decode(encodedArgs)), + 2 => new Reducer.Init(BSATNHelpers.Decode(encodedArgs)), + 3 => new Reducer.SendMessage(BSATNHelpers.Decode(encodedArgs)), + 4 => new Reducer.SetName(BSATNHelpers.Decode(encodedArgs)), + 4294967295 => new Reducer.StdbNone(default), var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } @@ -168,13 +222,13 @@ protected override IEventContext ToEventContext(Event reducerEvent) => protected override bool Dispatch(IEventContext context, Reducer reducer) { var eventContext = (EventContext)context; - return reducer switch - { + return reducer switch { + Reducer.IdentityConnected(var args) => Reducers.InvokeIdentityConnected(eventContext, args), + Reducer.IdentityDisconnected(var args) => Reducers.InvokeIdentityDisconnected(eventContext, args), + Reducer.Init(var args) => Reducers.InvokeInit(eventContext, args), Reducer.SendMessage(var args) => Reducers.InvokeSendMessage(eventContext, args), Reducer.SetName(var args) => Reducers.InvokeSetName(eventContext, args), - Reducer.StdbNone or - Reducer.StdbIdentityConnected or - Reducer.StdbIdentityDisconnected => true, + Reducer.StdbNone => true, _ => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}") }; } diff --git a/src/ClientCache.cs b/src/ClientCache.cs index 9e01e327..430e287c 100644 --- a/src/ClientCache.cs +++ b/src/ClientCache.cs @@ -12,29 +12,29 @@ public class ClientCache { private readonly IDbConnection conn; - private readonly Dictionary tables = new(); + private readonly Dictionary tables = new(); public ClientCache(IDbConnection conn) => this.conn = conn; - public void AddTable(string name, IRemoteTableHandle table) + public void AddTable(uint tableIdx, IRemoteTableHandle table) where Row : IDatabaseRow, new() { - if (!tables.TryAdd(name, table)) + if (!tables.TryAdd(tableIdx, table)) { - Log.Error($"Table with name already exists: {name}"); + Log.Error($"Table with index already exists: {tableIdx}"); } - table.Initialize(name, conn); + table.Initialize(tableIdx, conn); } - internal IRemoteTableHandle? GetTable(string name) + internal IRemoteTableHandle? GetTable(uint tableIdx) { - if (tables.TryGetValue(name, out var table)) + if (tables.TryGetValue(tableIdx, out var table)) { return table; } - Log.Error($"We don't know that this table is: {name}"); + Log.Error($"We don't know that this table is: {tableIdx}"); return null; } diff --git a/src/Event.cs b/src/Event.cs index b637e698..29cc844a 100644 --- a/src/Event.cs +++ b/src/Event.cs @@ -6,7 +6,7 @@ public interface IEventContext { } public interface IReducerArgs : BSATN.IStructuralReadWrite { - string ReducerName { get; } + uint ReducerIndex { get; } } [Type] diff --git a/src/SpacetimeDB/ClientApi/AfterConnecting.cs b/src/SpacetimeDB/ClientApi/AfterConnecting.cs new file mode 100644 index 00000000..a141c3f0 --- /dev/null +++ b/src/SpacetimeDB/ClientApi/AfterConnecting.cs @@ -0,0 +1,35 @@ +#nullable enable + +using System; +using SpacetimeDB; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.ClientApi +{ + [SpacetimeDB.Type] + [DataContract] + public partial class AfterConnecting + { + [DataMember(Name = "identity_token")] + public SpacetimeDB.ClientApi.IdentityToken IdentityToken; + [DataMember(Name = "ids_to_names")] + public SpacetimeDB.ClientApi.IdsToNames IdsToNames; + + public AfterConnecting( + SpacetimeDB.ClientApi.IdentityToken IdentityToken, + SpacetimeDB.ClientApi.IdsToNames IdsToNames + ) + { + this.IdentityToken = IdentityToken; + this.IdsToNames = IdsToNames; + } + + public AfterConnecting() + { + this.IdentityToken = new(); + this.IdsToNames = new(); + } + + } +} diff --git a/src/SpacetimeDB/ClientApi/CallReducer.cs b/src/SpacetimeDB/ClientApi/CallReducer.cs index 212d9bb3..be60a49a 100644 --- a/src/SpacetimeDB/ClientApi/CallReducer.cs +++ b/src/SpacetimeDB/ClientApi/CallReducer.cs @@ -15,8 +15,8 @@ namespace SpacetimeDB.ClientApi [DataContract] public partial class CallReducer { - [DataMember(Name = "reducer")] - public string Reducer; + [DataMember(Name = "reducer_id")] + public uint ReducerId; [DataMember(Name = "args")] public byte[] Args; [DataMember(Name = "request_id")] @@ -25,13 +25,13 @@ public partial class CallReducer public byte Flags; public CallReducer( - string Reducer, + uint ReducerId, byte[] Args, uint RequestId, byte Flags ) { - this.Reducer = Reducer; + this.ReducerId = ReducerId; this.Args = Args; this.RequestId = RequestId; this.Flags = Flags; @@ -39,7 +39,6 @@ byte Flags public CallReducer() { - this.Reducer = ""; this.Args = Array.Empty(); } diff --git a/src/SpacetimeDB/ClientApi/IdsToNames.cs b/src/SpacetimeDB/ClientApi/IdsToNames.cs new file mode 100644 index 00000000..f9f2e0f4 --- /dev/null +++ b/src/SpacetimeDB/ClientApi/IdsToNames.cs @@ -0,0 +1,45 @@ +#nullable enable + +using System; +using SpacetimeDB; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace SpacetimeDB.ClientApi +{ + [SpacetimeDB.Type] + [DataContract] + public partial class IdsToNames + { + [DataMember(Name = "reducer_ids")] + public System.Collections.Generic.List ReducerIds; + [DataMember(Name = "reducer_names")] + public System.Collections.Generic.List ReducerNames; + [DataMember(Name = "table_ids")] + public System.Collections.Generic.List TableIds; + [DataMember(Name = "table_names")] + public System.Collections.Generic.List TableNames; + + public IdsToNames( + System.Collections.Generic.List ReducerIds, + System.Collections.Generic.List ReducerNames, + System.Collections.Generic.List TableIds, + System.Collections.Generic.List TableNames + ) + { + this.ReducerIds = ReducerIds; + this.ReducerNames = ReducerNames; + this.TableIds = TableIds; + this.TableNames = TableNames; + } + + public IdsToNames() + { + ReducerIds = new(); + ReducerNames = new(); + TableIds = new(); + TableNames = new(); + } + + } +} diff --git a/src/SpacetimeDB/ClientApi/OneOffTable.cs b/src/SpacetimeDB/ClientApi/OneOffTable.cs index fe667b18..e7d9f5a9 100644 --- a/src/SpacetimeDB/ClientApi/OneOffTable.cs +++ b/src/SpacetimeDB/ClientApi/OneOffTable.cs @@ -15,23 +15,22 @@ namespace SpacetimeDB.ClientApi [DataContract] public partial class OneOffTable { - [DataMember(Name = "table_name")] - public string TableName; + [DataMember(Name = "table_id")] + public uint TableId; [DataMember(Name = "rows")] public SpacetimeDB.ClientApi.BsatnRowList Rows; public OneOffTable( - string TableName, + uint TableId, SpacetimeDB.ClientApi.BsatnRowList Rows ) { - this.TableName = TableName; + this.TableId = TableId; this.Rows = Rows; } public OneOffTable() { - this.TableName = ""; this.Rows = new(); } diff --git a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs index f8acaffd..665112f2 100644 --- a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs +++ b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs @@ -15,8 +15,6 @@ namespace SpacetimeDB.ClientApi [DataContract] public partial class ReducerCallInfo { - [DataMember(Name = "reducer_name")] - public string ReducerName; [DataMember(Name = "reducer_id")] public uint ReducerId; [DataMember(Name = "args")] @@ -25,13 +23,11 @@ public partial class ReducerCallInfo public uint RequestId; public ReducerCallInfo( - string ReducerName, uint ReducerId, byte[] Args, uint RequestId ) { - this.ReducerName = ReducerName; this.ReducerId = ReducerId; this.Args = Args; this.RequestId = RequestId; @@ -39,7 +35,6 @@ uint RequestId public ReducerCallInfo() { - this.ReducerName = ""; this.Args = Array.Empty(); } diff --git a/src/SpacetimeDB/ClientApi/ServerMessage.cs b/src/SpacetimeDB/ClientApi/ServerMessage.cs index f66fdd98..d7b9f9a8 100644 --- a/src/SpacetimeDB/ClientApi/ServerMessage.cs +++ b/src/SpacetimeDB/ClientApi/ServerMessage.cs @@ -14,7 +14,7 @@ public partial record ServerMessage : SpacetimeDB.TaggedEnum<( SpacetimeDB.ClientApi.InitialSubscription InitialSubscription, SpacetimeDB.ClientApi.TransactionUpdate TransactionUpdate, SpacetimeDB.ClientApi.TransactionUpdateLight TransactionUpdateLight, - SpacetimeDB.ClientApi.IdentityToken IdentityToken, + SpacetimeDB.ClientApi.AfterConnecting AfterConnecting, SpacetimeDB.ClientApi.OneOffQueryResponse OneOffQueryResponse )>; } diff --git a/src/SpacetimeDB/ClientApi/TableUpdate.cs b/src/SpacetimeDB/ClientApi/TableUpdate.cs index d3265065..157c440c 100644 --- a/src/SpacetimeDB/ClientApi/TableUpdate.cs +++ b/src/SpacetimeDB/ClientApi/TableUpdate.cs @@ -17,8 +17,6 @@ public partial class TableUpdate { [DataMember(Name = "table_id")] public uint TableId; - [DataMember(Name = "table_name")] - public string TableName; [DataMember(Name = "num_rows")] public ulong NumRows; [DataMember(Name = "updates")] @@ -26,20 +24,17 @@ public partial class TableUpdate public TableUpdate( uint TableId, - string TableName, ulong NumRows, System.Collections.Generic.List Updates ) { this.TableId = TableId; - this.TableName = TableName; this.NumRows = NumRows; this.Updates = Updates; } public TableUpdate() { - this.TableName = ""; this.Updates = new(); } diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs index b3cb22e5..f588b7b2 100644 --- a/src/SpacetimeDBClient.cs +++ b/src/SpacetimeDBClient.cs @@ -98,6 +98,7 @@ public interface IDbConnection void Disconnect(); internal Task RemoteQuery(string query) where T : IDatabaseRow, new(); + string TableName(uint tableIdx); } public abstract class DbConnectionBase : IDbConnection @@ -147,7 +148,7 @@ struct DbOp private bool connectionClosed; protected readonly ClientCache clientDB; - protected abstract Reducer ToReducer(TransactionUpdate update); + protected abstract Reducer ToReducer(uint reducerIdx, TransactionUpdate update); protected abstract IEventContext ToEventContext(Event reducerEvent); private readonly Dictionary> waitingOneOffQueries = new(); @@ -156,6 +157,29 @@ struct DbOp private readonly Thread networkMessageProcessThread; public readonly Stats stats = new(); + private Dictionary reducerIdToIdx = new(); + private List reducerIdxToId = new(); + private List reducerIdxToName = new(); + private Dictionary tableIdToIdx = new(); + private List tableIdxToName = new(); + private void InitIds(IdsToNames idsToNames) + { + reducerIdxToId = idsToNames.ReducerIds; + reducerIdxToName = idsToNames.ReducerNames; + tableIdxToName = idsToNames.TableNames; + + for (int reducerIdx = 0; reducerIdx < reducerIdxToId.Count; reducerIdx++) + { + reducerIdToIdx.Add(reducerIdxToId[reducerIdx], (uint)reducerIdx); + } + for (int tableIdx = 0; tableIdx < idsToNames.TableIds.Count; tableIdx++) + { + tableIdToIdx.Add(idsToNames.TableIds[tableIdx], (uint)tableIdx); + } + } + string IDbConnection.TableName(uint tableIdx) => tableIdxToName[(int)tableIdx]; + private string TableIdToName(uint tableId) => tableIdxToName[(int)tableIdToIdx[tableId]]; + protected DbConnectionBase() { clientDB = new(this); @@ -342,11 +366,11 @@ void PreProcessMessages() { foreach (var update in updates.Tables) { - var tableName = update.TableName; - var table = clientDB.GetTable(tableName); + var tableIdx = tableIdToIdx[update.TableId]; + var table = clientDB.GetTable(tableIdx); if (table == null) { - Log.Error($"Unknown table name: {tableName}"); + Log.Error($"Unknown table name: {update.TableId}"); continue; } @@ -437,7 +461,7 @@ List PreProcessDatabaseUpdate(DatabaseUpdate updates) { if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null)) { - Log.Warn($"Update with the same primary key was applied multiple times! tableName={update.TableName}"); + Log.Warn($"Update with the same primary key was applied multiple times! tableName={TableIdToName(update.TableId)}"); // TODO(jdetter): Is this a correctable error? This would be a major error on the // SpacetimeDB side. continue; @@ -472,7 +496,7 @@ List PreProcessDatabaseUpdate(DatabaseUpdate updates) { if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null)) { - Log.Warn($"Update with the same primary key was applied multiple times! tableName={update.TableName}"); + Log.Warn($"Update with the same primary key was applied multiple times! tableName={TableIdToName(update.TableId)}"); // TODO(jdetter): Is this a correctable error? This would be a major error on the // SpacetimeDB side. continue; @@ -538,6 +562,7 @@ PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed) // Convert the generic event arguments in to a domain specific event object try { + var reducerIdx = reducerIdToIdx[transactionUpdate.ReducerCall.ReducerId]; reducerEvent = new( DateTimeOffset.FromUnixTimeMilliseconds((long)transactionUpdate.Timestamp.Microseconds / 1000), transactionUpdate.Status switch @@ -550,7 +575,7 @@ PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed) transactionUpdate.CallerIdentity, transactionUpdate.CallerAddress, transactionUpdate.EnergyQuantaUsed.Quanta, - ToReducer(transactionUpdate)); + ToReducer(reducerIdx, transactionUpdate)); } catch (Exception e) { @@ -565,7 +590,8 @@ PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed) case ServerMessage.TransactionUpdateLight(var update): dbOps = PreProcessDatabaseUpdate(update.Update); break; - case ServerMessage.IdentityToken(var identityToken): + case ServerMessage.AfterConnecting(var afterConnecting): + InitIds(afterConnecting.IdsToNames); break; case ServerMessage.OneOffQueryResponse(var resp): PreProcessOneOffQuery(resp); @@ -781,7 +807,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed) case ServerMessage.TransactionUpdate(var transactionUpdate): { - var reducer = transactionUpdate.ReducerCall.ReducerName; + var reducer = reducerIdxToName[(int)reducerIdToIdx[transactionUpdate.ReducerCall.ReducerId]]; stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.TransactionUpdate)},reducer={reducer}"); var hostDuration = TimeSpan.FromMilliseconds(transactionUpdate.HostExecutionDurationMicros / 1000.0d); stats.AllReducersTracker.InsertRequest(hostDuration, $"reducer={reducer}"); @@ -828,9 +854,10 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed) } break; } - case ServerMessage.IdentityToken(var identityToken): + case ServerMessage.AfterConnecting(var afterConnecting): try { + var identityToken = afterConnecting.IdentityToken; Identity = identityToken.Identity; onConnect?.Invoke(identityToken.Identity, identityToken.Token); } @@ -863,10 +890,14 @@ public void InternalCallReducer(T args, CallReducerFlags flags) return; } + var reducerIdx = (int)args.ReducerIndex; + var reducerId = reducerIdxToId[reducerIdx]; + var reducerName = reducerIdxToName[reducerIdx]; + webSocket.Send(new ClientMessage.CallReducer(new CallReducer( - args.ReducerName, + reducerId, IStructuralReadWrite.ToBytes(args), - stats.ReducerRequestTracker.StartTrackingRequest(args.ReducerName), + stats.ReducerRequestTracker.StartTrackingRequest(reducerName), (byte)flags ))); } @@ -938,11 +969,11 @@ T[] LogAndThrow(string error) } var resultTable = result.Tables[0]; - var cacheTable = clientDB.GetTable(resultTable.TableName); + var cacheTable = clientDB.GetTable(resultTable.TableId); if (cacheTable?.ClientTableType != typeof(T)) { - return LogAndThrow($"Mismatched result type, expected {typeof(T)} but got {resultTable.TableName}"); + return LogAndThrow($"Mismatched result type, expected {typeof(T)} but got {TableIdToName(resultTable.TableId)}"); } return BsatnRowListIter(resultTable.Rows) diff --git a/src/Table.cs b/src/Table.cs index d3ebf918..127fe84c 100644 --- a/src/Table.cs +++ b/src/Table.cs @@ -38,19 +38,19 @@ public interface IRemoteTableHandle internal void InvokeBeforeDelete(IEventContext context, IDatabaseRow row); internal void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow); - internal void Initialize(string name, IDbConnection conn); + internal void Initialize(uint tableIdx, IDbConnection conn); } public abstract class RemoteTableHandle : IRemoteTableHandle where EventContext : class, IEventContext where Row : IDatabaseRow, new() { - string? name; + uint tableIdx; IDbConnection? conn; - void IRemoteTableHandle.Initialize(string name, IDbConnection conn) + void IRemoteTableHandle.Initialize(uint tableIdx, IDbConnection conn) { - this.name = name; + this.tableIdx = tableIdx; this.conn = conn; } @@ -106,7 +106,7 @@ bool IRemoteTableHandle.DeleteEntry(byte[] rowBytes) protected IEnumerable Query(Func filter) => Iter().Where(filter); public Task RemoteQuery(string query) => - conn!.RemoteQuery($"SELECT * FROM {name!} {query}"); + conn!.RemoteQuery($"SELECT * FROM {conn.TableName(tableIdx)!} {query}"); void IRemoteTableHandle.InvokeInsert(IEventContext context, IDatabaseRow row) => OnInsert?.Invoke((EventContext)context, (Row)row); diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs index d293c126..9e0cbf06 100644 --- a/tests~/SnapshotTests.cs +++ b/tests~/SnapshotTests.cs @@ -96,13 +96,16 @@ public void Exception(Exception e) } } - private static ServerMessage.IdentityToken SampleId(string identity, string token, string address) => - new(new() + private static IdentityToken SampleId(string identity, string token, string address) => + new() { Identity = Identity.From(Convert.FromBase64String(identity)), Token = token, Address = Address.From(Convert.FromBase64String(address)) ?? throw new InvalidDataException("address") - }); + }; + + private static ServerMessage.AfterConnecting SampleHandshake(string identity, string token, string address, IdsToNames idsToNames) => + new(new(SampleId(identity, token, address), idsToNames)); private static ServerMessage.InitialSubscription SampleSubscriptionUpdate( uint requestId, @@ -123,7 +126,7 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate( string callerIdentity, string callerAddress, uint requestId, - string reducerName, + uint reducerId, ulong energyQuantaUsed, ulong hostExecutionDuration, List updates, @@ -141,7 +144,7 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate( ReducerCall = new() { RequestId = requestId, - ReducerName = reducerName, + ReducerId = reducerId, Args = args ?? [] }, Status = new UpdateStatus.Committed(new() @@ -152,13 +155,11 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate( private static TableUpdate SampleUpdate( uint tableId, - string tableName, List inserts, List deletes ) where T : IStructuralReadWrite => new() { TableId = tableId, - TableName = tableName, NumRows = (ulong)(inserts.Count + deletes.Count), Updates = [new CompressableQueryUpdate.Uncompressed(new QueryUpdate( EncodeRowList(deletes), EncodeRowList(inserts)))] @@ -190,7 +191,7 @@ private static byte[] Encode(in T value) where T : IStructuralReadWrite } private static TableUpdate SampleUserInsert(string identity, string? name, bool online) => - SampleUpdate(4097, "user", [new User + SampleUpdate(4097, [new User { Identity = Identity.From(Convert.FromBase64String(identity)), Name = name, @@ -198,7 +199,7 @@ private static TableUpdate SampleUserInsert(string identity, string? name, bool }], []); private static TableUpdate SampleUserUpdate(string identity, string? oldName, string? newName, bool oldOnline, bool newOnline) => - SampleUpdate(4097, "user", [new User + SampleUpdate(4097, [new User { Identity = Identity.From(Convert.FromBase64String(identity)), Name = newName, @@ -211,7 +212,7 @@ private static TableUpdate SampleUserUpdate(string identity, string? oldName, st }]); private static TableUpdate SampleMessage(string identity, ulong sent, string text) => - SampleUpdate(4098, "message", [new Message + SampleUpdate(4098, [new Message { Sender = Identity.From(Convert.FromBase64String(identity)), Sent = sent, @@ -219,55 +220,61 @@ private static TableUpdate SampleMessage(string identity, ulong sent, string tex }], []); private static ServerMessage[] SampleDump() => [ - SampleId( + SampleHandshake( "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJoZXhfaWRlbnRpdHkiOiI4ZjkwY2M5NGE5OTY4ZGY2ZDI5N2JhYTY2NTAzYTg5M2IxYzM0YjBiMDAyNjhhNTE0ODk4ZGQ5NTRiMGRhMjBiIiwiaWF0IjoxNzE4NDg3NjY4LCJleHAiOm51bGx9.PSn481bLRqtFwIh46nOXDY14X3GKbz8t4K4GmBmz50loU6xzeL7zDdCh1V2cmiQsoGq8Erxg0r_6b6Y5SqKoBA", - "Vd4dFzcEzhLHJ6uNL8VXFg==" + "Vd4dFzcEzhLHJ6uNL8VXFg==", + new IdsToNames( + [], + [], + [4097, 4098], + ["user", "message"] + ) ), SampleSubscriptionUpdate( 1, 366, [SampleUserInsert("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, true)] ), SampleTransactionUpdate(0, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 0, "unknown-reducer", 0, 40, [], null + 0, 50, 0, 40, [], null ), SampleTransactionUpdate( 1718487763059031, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 0, "__identity_connected__", 1957615, 66, [SampleUserInsert("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, true)], + 0, 0, 1957615, 66, [SampleUserInsert("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, true)], null ), SampleTransactionUpdate( 1718487768057579, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==", - 1, "set_name", 4345615, 70, [SampleUserUpdate("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, "A", true, true)], + 1, 4, 4345615, 70, [SampleUserUpdate("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, "A", true, true)], Encode(new SetName { Name = "A" }) ), SampleTransactionUpdate( 1718487775346381, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 1, "send_message", 2779615, 57, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487775346381, "Hello, A!")], + 1, 3, 2779615, 57, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487775346381, "Hello, A!")], Encode(new SendMessage { Text = "Hello, A!" }) ), SampleTransactionUpdate( 1718487777307855, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 2, "set_name", 4268615, 98, [SampleUserUpdate("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, "B", true, true)], + 2, 4, 4268615, 98, [SampleUserUpdate("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, "B", true, true)], Encode(new SetName { Name = "B" }) ), SampleTransactionUpdate( 1718487783175083, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==", - 2, "send_message", 2677615, 40, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487783175083, "Hello, B!")], + 2, 3, 2677615, 40, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487783175083, "Hello, B!")], Encode(new SendMessage { Text = "Hello, B!" }) ), SampleTransactionUpdate( 1718487787645364, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 3, "send_message", 2636615, 28, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487787645364, "Goodbye!")], + 3, 3, 2636615, 28, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487787645364, "Goodbye!")], Encode(new SendMessage { Text = "Goodbye!" }) ), SampleTransactionUpdate( 1718487791901504, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==", - 0, "__identity_disconnected__", 3595615, 75, [SampleUserUpdate("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "B", "B", true, false)], + 0, 1, 3595615, 75, [SampleUserUpdate("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "B", "B", true, false)], null ), SampleTransactionUpdate( 1718487794937841, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==", - 3, "send_message", 2636615, 34, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487794937841, "Goodbye!")], + 3, 3, 2636615, 34, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487794937841, "Goodbye!")], Encode(new SendMessage { Text = "Goodbye!" }) ), ];