private Aggregate <TData> ApplyEvent(Aggregate <TData> aggregate, Event <TDiff> @event)
 => new Aggregate <TData>()
 {
     Data    = _differ.Patch(aggregate.Data, @event.EventData),
     Id      = aggregate.Id,
     Version = @event.Version
 };
Beispiel #2
0
        public Client(
            TRemoteState initialRemoteState,
            IReadOnlyDictionary <int, TLocalState> localStatesByTick,
            IDiffer <TLocalState> localStateDiffer,
            IDiffer <TRemoteState> remoteStateDiffer,
            EndPoint localEndPoint,
            EndPoint remoteEndPoint,
            TimeSpan sendInterval
            )
        {
            if (!remoteStatesByTick.TryAdd(0, initialRemoteState))
            {
                throw new InvalidOperationException("Could not add initial tick.");
            }

            connection = new Connection(
                localEndPoint,
                remoteEndPoint,
                (buffer, index, size) => {
                using (var reader = new BinaryReader(new MemoryStream(buffer, index, size, writable: false))) {
                    totalBytesReceived += size;
                    AckedLocalTick      = reader.ReadInt32();

                    int oldRemoteTick = reader.ReadInt32();
                    int newRemoteTick = reader.ReadInt32();

                    //Console.WriteLine($"Received: ackedLocalTick = {ackedLocalTick}, oldRemoteTick = {oldRemoteTick}, newRemoteTick = {newRemoteTick}, ackingRemoteTick = {ackingRemoteTick}");

                    // only patch remote state if newer
                    if (AckingRemoteTick < newRemoteTick)
                    {
                        var remoteState = remoteStatesByTick[oldRemoteTick];
                        remoteStateDiffer.Patch(ref remoteState, reader);
                        if (!remoteStatesByTick.TryAdd(newRemoteTick, remoteState))
                        {
                            throw new InvalidOperationException($"Could not add new tick {newRemoteTick}.");
                        }

                        AckingRemoteTick = newRemoteTick;
                    }
                }
            });

            sendThread = new Thread(() => {
                var memoryStream = new MemoryStream();
                FixedTimer(_ => {
                    if (!Connected)
                    {
                        return;
                    }

                    using (var writer = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true)) {
                        writer.SetOffset(0);
                        writer.Write(AckingRemoteTick);

                        TLocalState ackedLocalState;
                        TLocalState localState;
                        bool ticked;
                        lock (localTickMutex) {
                            writer.Write(AckedLocalTick);
                            writer.Write(localTick);

                            //Console.WriteLine($"Sending: ackingRemoteTick = {ackingRemoteTick}, ackedLocalTick = {ackedLocalTick}, localTick = {localTick}");
                            ticked = AckedLocalTick < localTick;

                            ackedLocalState = localStatesByTick[AckedLocalTick];
                            localState      = localStatesByTick[localTick];
                        }

                        if (ticked)
                        {
                            localStateDiffer.Diff(ackedLocalState, localState, writer);
                        }

                        if (memoryStream.Position > int.MaxValue)
                        {
                            throw new OverflowException();
                        }

                        connection.SendMessage(memoryStream.GetBuffer(), 0, writer.GetOffset());
                        totalBytesSent += writer.GetOffset();
                    }
                }, sendInterval, cancellationTokenSource.Token);
            });
            sendThread.Start();
        }