Exemplo n.º 1
0
        private void writeRegisterHub(RemoteHub hubToRegistration)
        {
            Debug.Assert(Monitor.IsEntered(_sync));

            _outputBufferWritter.Write((byte)PackageType.HubIsAvailable);
            _outputBufferWritter.Write(hubToRegistration.Id);
            _outputBufferWritter.Write(hubToRegistration.Name);
            _outputBufferWritter.Write(hubToRegistration._connections.GetShortedDistance() + 1);

            _writeSeqNumber++;
        }
Exemplo n.º 2
0
        private void processSinglePackage(List <Action> doAfter, long senderId)
        {
            var packageStart = (int)_inputBuffer.Position;
            var packageType  = (PackageType)_inputBufferReader.ReadByte();

            switch (packageType)
            {
            case PackageType.ReadyForDisconnect:
            {
                if (State == HubConnectionState.Disconnecting)
                {
                    _reconnectOnFail = false;

                    doAfter.Add(onDisconnected);

                    return;
                }

                break;
            }

            case PackageType.Disconnect:
            {
                _reconnectOnFail = false;

                State = HubConnectionState.Disconnecting;
                doAfter.Add(onDisconnected);

                writeReadyForDisconnect();
                break;
            }

            case PackageType.HelloResponse:
            case PackageType.Hello:
            {
                var hubId = _inputBufferReader.ReadInt64();
                var name  = _inputBufferReader.ReadString();

                if ((packageType == PackageType.Hello && State == HubConnectionState.NotInitialized) ||
                    (packageType == PackageType.HelloResponse && State == HubConnectionState.HelloSent))
                {
                    lock (_localHub._knownHubs)
                    {
                        if (!_localHub._knownHubs.TryGetValue(hubId, out var hub))
                        {
                            _localHub._knownHubs[hubId] = hub = new RemoteHub(new TypesMapLayer(_localHub._registeredInderfaces));
                        }

                        RemoteHub = hub;
                        hub.Id    = hubId;
                        hub.Name  = name;
                        hub._connections.Set(this, 0);
                    }

                    _allHubs.Add(hubId);
                    if (senderId == -1)
                    {
                        senderId = hubId;
                    }

                    if (packageType == PackageType.Hello)
                    {
                        writeHelloResponse();
                    }

                    if (_localHub.PathThrough)
                    {
                        // to this about all
                        forAllHubs((_, otherHub) =>
                            {
                                if (RemoteHub.Id != otherHub.Id)
                                {
                                    writeRegisterHub(otherHub);
                                }
                            });

                        doAfter.Add(() =>
                            {
                                // to all about this
                                forAllHubConnections(false, hubConn => // only those that are connected directly
                                {
                                    hubConn.writeRegisterHub(RemoteHub);
                                    return(true);
                                });
                            });
                    }

                    doAfter.Add(() =>
                        {
                            lock (_sync)
                            {
                                lock (_localHub._knownInterfaces)
                                {
                                    foreach (var @interface in _localHub._knownInterfaces)
                                    {
                                        var localReg = @interface.Value.LocalImplementation != null;
                                        if (!localReg && !_localHub.PathThrough)
                                        {
                                            continue;
                                        }

                                        var count = !_localHub.PathThrough ? 1 : @interface.Value.Hubs.Count + (localReg ? 1 : 0);

                                        var hubs     = new long[count];
                                        var intIds   = new uint[count];
                                        var versions = new int[count];

                                        if (_localHub.PathThrough)
                                        {
                                            for (var i = 0; i < @interface.Value.Hubs.Count; i++)
                                            {
                                                hubs[i]     = @interface.Value.Hubs[i].Hub.Id;
                                                intIds[i]   = @interface.Value.Hubs[i].InterfaceId;
                                                versions[i] = @interface.Value.Hubs[i].Version;
                                            }
                                        }

                                        if (localReg)
                                        {
                                            hubs[count - 1]     = _localHub.Id;
                                            intIds[count - 1]   = @interface.Value.LocalId;
                                            versions[count - 1] = @interface.Value.LocalVersion;
                                        }

                                        writeRegisterInterface(hubs, @interface.Key, intIds, versions);
                                    }

                                    FlushOutputBuffer();
                                }
                            }
                        });

                    //Thread.CurrentThread.Name = "Workder for connection from \"" + LocalHub.Name + "\" (" + LocalHub.Id + ") to \"" + RemoteHub.Name + "\" (" + RemoteHub.Id + ")";
                    State = HubConnectionState.Active;

                    onConnected();
                }
                else
                {
                    writeError(ErrorCode.UnexpectedHello, "Unexpected hello");
                    FlushOutputBuffer();
                }

                break;
            }

            case PackageType.HubIsAvailable:
            {
                var hubId    = _inputBufferReader.ReadInt64();
                var hubName  = _inputBufferReader.ReadString();
                var distance = _inputBufferReader.ReadInt32();

                if (_allHubs.Contains(hubId))
                {
                    break;
                }

                _allHubs.Add(hubId);

                var hub = _localHub.HubIsAvailableThrough(this, hubId, distance, hubName);

                if (_localHub.PathThrough)
                {
                    doAfter.Add(() =>
                        {
                            forAllHubConnections(false, hubConn => // only those that are connected directly
                            {
                                hubConn.writeRegisterHub(hub);
                                return(true);
                            });
                        });
                }

                break;
            }

            case PackageType.HubIsUnavailable:
            {
                var hubId = _inputBufferReader.ReadInt64();

                lock (_localHub._knownHubs)
                {
                    if (!_localHub._knownHubs.ContainsKey(hubId))
                    {
                        break;
                    }
                }

                _localHub.HubIsUnavailableThrough(this, hubId);

                doAfter.Add(() =>
                    {
                        forAllHubConnections(false, hubConn => // only those that are connected directly
                        {
                            hubConn.writeUnRegisterHub(hubId);
                            return(true);
                        });
                    });

                break;
            }

            case PackageType.RegisterInterface:
            {
                var interfaceName = _inputBufferReader.ReadString();
                var hubsCount     = (int)_inputBufferReader.ReadByte();

                var hubs         = new long[hubsCount];
                var interfaceIds = new uint[hubsCount];
                var versions     = new int[hubsCount];
                for (var i = 0; i < hubsCount; i++)
                {
                    hubs[i]         = _inputBufferReader.ReadInt64();
                    interfaceIds[i] = _inputBufferReader.ReadUInt32();
                    versions[i]     = _inputBufferReader.ReadInt32();
                }

                lock (_localHub._knownInterfaces)
                {
                    if (_localHub._knownInterfaces.TryGetValue(interfaceName, out var @interface))
                    {
                        var wPos = 0;
                        lock (@interface.Hubs)
                        {
                            for (var i = 0; i < hubs.Length; i++)
                            {
                                var hubId = hubs[i];

                                var knownHub = false;
                                for (var j = 0; j < @interface.Hubs.Count && !knownHub; j++)
                                {
                                    knownHub |= @interface.Hubs[j].Hub.Id == hubId;
                                }

                                if (!knownHub)
                                {
                                    if (wPos != i)
                                    {
                                        hubs[wPos]         = hubId;
                                        interfaceIds[wPos] = interfaceIds[i];
                                        versions[wPos]     = versions[i];
                                    }

                                    wPos++;

                                    tryAddInterfaceToHubOrWriteError(@interface, hubId, interfaceIds[i], versions[i]);
                                }
                            }
                        }

                        if (_localHub.PathThrough)
                        {
                            if (wPos == hubs.Length)     // Все хабы новые. Нужно передать весь пакет дальше
                            {
                                var pos = _inputBuffer.Position;
                                _inputBuffer.Position = packageStart;
                                var blob = _inputBufferReader.ReadBytes((int)(pos - packageStart));

                                doAfter.Add(() =>
                                    {
                                        forAllHubConnections(false, connection =>
                                        {
                                            connection.writeBlob(blob);
                                            return(true);
                                        });
                                    });
                            }
                            else if (wPos > 0)     // О части хабов мы уже знали. Нужно сформировать новый пакет и передать дальше
                            {
                                Array.Resize(ref hubs, wPos);
                                Array.Resize(ref interfaceIds, wPos);
                                Array.Resize(ref versions, wPos);
                                doAfter.Add(() =>
                                    {
                                        forAllHubConnections(false, connection => // only those that are connected directly
                                        {
                                            connection.writeRegisterInterface(hubs, interfaceName, interfaceIds, versions);
                                            return(true);
                                        });
                                    });
                            }
                        }
                    }
                    else     // Интерфейс неизвестен. Нужно создать его и передать весь пакет как есть дальше
                    {
                        @interface = new SharedInterface(interfaceName);
                        for (var i = 0; i < hubs.Length; i++)
                        {
                            tryAddInterfaceToHubOrWriteError(@interface, hubs[i], interfaceIds[i], versions[i]);
                        }

                        _localHub._knownInterfaces.Add(interfaceName, @interface);

                        if (_localHub.PathThrough)
                        {
                            var pos = _inputBuffer.Position;
                            _inputBuffer.Position = packageStart;
                            var blob = _inputBufferReader.ReadBytes((int)(pos - packageStart));

                            doAfter.Add(() =>
                                {
                                    forAllHubConnections(false, connection =>
                                    {
                                        connection.writeBlob(blob);
                                        return(true);
                                    });
                                });
                        }
                    }
                }

                break;
            }

            case PackageType.RetransmitTo:
            {
                var receiverId  = _inputBufferReader.ReadInt64();
                var senderHubId = _inputBufferReader.ReadInt64();
                var size        = _inputBufferReader.ReadUInt16();

                if (receiverId == _localHub.Id)
                {
                    processReceived(doAfter, senderHubId, size);
                }
                else
                {
                    if (!_localHub.PathThrough)
                    {
                        _inputBuffer.Position += size;
                        writeError(ErrorCode.UnknownHub, "Unknown hub #" + receiverId);
                        break;
                    }

                    var headerSize = (int)(_inputBuffer.Position - packageStart);
                    _inputBuffer.Position = packageStart;
                    var blob = _inputBufferReader.ReadBytes(size + headerSize);

                    doAfter.Add(() =>
                        {
                            RemoteHub receiverHub;
                            lock (_localHub._knownHubs)
                            {
                                if (!_localHub._knownHubs.TryGetValue(receiverId, out receiverHub))
                                {
                                    writeError(ErrorCode.UnknownHub, "Unknown hub #" + receiverId);
                                    return;
                                }
                            }

                            using var connection = receiverHub._connections.GetLockedConenction();
                            connection.Value.writeBlob(blob);
                            connection.Value.FlushOutputBuffer();
                        });
                }

                break;
            }

            case PackageType.Call:
            {
                var awaitId = _inputBufferReader.ReadInt32();
                var size    = _inputBufferReader.ReadUInt16();
                var code    = _inputBufferReader.ReadBytes(size);

                _localHub.Eval(senderId, awaitId, code);
                break;
            }

            case PackageType.Result:
            {
                var awaitId = _inputBufferReader.ReadInt32();
                var size    = _inputBufferReader.ReadUInt16();
                var code    = _inputBufferReader.ReadBytes(size);

                _localHub.SetResult(awaitId, code);
                break;
            }

            case PackageType.Exception:
            {
                var awaitId = _inputBufferReader.ReadInt32();
                var message = _inputBufferReader.ReadString();

                _localHub.SetException(awaitId, message);
                break;
            }

            case PackageType.Error:
            {
                var errorCode = _inputBufferReader.ReadInt32();
                var message   = _inputBufferReader.ReadString();
                // TODO
                break;
            }

            case PackageType.Ping:
            {
                writePong();
                break;
            }

            case PackageType.Pong:
            {
                break;
            }

            case PackageType.StreamGetInfo:
            {
                var streamId = _inputBufferReader.ReadInt32();

                doAfter.Add(() =>
                    {
                        RemoteHub remoteHub;
                        lock (_localHub._knownHubs)
                        {
                            if (!_localHub._knownHubs.TryGetValue(senderId, out remoteHub))
                            {
                                writeError(ErrorCode.UnknownHub, "Unknown hub #" + senderId);
                                return;
                            }
                        }

                        using var connection = remoteHub._connections.GetLockedConenction();
                        var got    = false;
                        var stream = default(RegisteredStream);
                        lock (_localHub._streams)
                        {
                            got = _localHub._streams.TryGetValue(streamId, out stream);
                        }

                        if (got)
                        {
                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamInfo(
                                    streamId,
                                    stream.Stream.Length,
                                    stream.Stream.Position,
                                    stream.Stream.CanSeek,
                                    stream.Stream.CanWrite,
                                    stream.Stream.CanRead);
                            });
                        }
                        else
                        {
                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamInfo(streamId, 0, 0, false, false, false);
                            });
                        }

                        connection.Value.FlushOutputBuffer();
                    });

                break;
            }

            case PackageType.StreamInfo:
            {
                var streamId = _inputBufferReader.ReadInt32();
                var length   = _inputBufferReader.ReadInt64();
                var position = _inputBufferReader.ReadInt64();
                var flags    = _inputBufferReader.ReadByte();

                TaskCompletionSource <RemoteStream> remoteStreamTask;
                lock (_localHub._remoteStreams)
                {
                    _localHub._remoteStreams.TryGetValue((senderId, streamId), out remoteStreamTask);
                }

                doAfter.Add(() =>
                    {
                        if (remoteStreamTask != null)
                        {
                            if ((flags & 3) != 0)
                            {
                                if (remoteStreamTask.Task.IsCompleted)
                                {
                                    var stream = remoteStreamTask.Task.Result;
                                    stream.SetCanRead((flags & 1) != 0);
                                    stream.SetCanWrite((flags & 2) != 0);
                                    stream.SetCanSeek((flags & 4) != 0);
                                    stream.SetPosition(position);
                                    stream.SetLengthInternal(length);
                                }
                                else
                                {
                                    remoteStreamTask
                                    .SetResult(
                                        new RemoteStream(
                                            _localHub,
                                            _localHub._knownHubs[senderId],
                                            streamId,
                                            length,
                                            position,
                                            (flags & 1) != 0,
                                            (flags & 2) != 0,
                                            (flags & 4) != 0));
                                }
                            }
                            else
                            {
                                remoteStreamTask.SetException(new KeyNotFoundException("Unknown stream"));
                            }
                        }
                    });

                break;
            }

            case PackageType.StreamRead:
            {
                var streamId = _inputBufferReader.ReadInt32();
                var count    = _inputBufferReader.ReadUInt16();

                doAfter.Add(() =>
                    {
                        RemoteHub remoteHub;
                        lock (_localHub._knownHubs)
                        {
                            if (!_localHub._knownHubs.TryGetValue(senderId, out remoteHub))
                            {
                                writeError(ErrorCode.UnknownHub, "Unknown hub #" + senderId);
                                return;
                            }
                        }

                        using var connection = remoteHub._connections.GetLockedConenction();
                        lock (_localHub._streams)
                        {
                            if (_localHub._streams.TryGetValue(streamId, out var stream))
                            {
                                var buffer = new byte[count];
                                var r      = stream.Stream.Read(buffer);

                                connection.Value.WriteRetransmitTo(
                                    senderId,
                                    _ =>
                                {
                                    connection.Value.WriteStreamInfo(streamId,
                                                                     stream.Stream.Length,
                                                                     stream.Stream.Position,
                                                                     stream.Stream.CanSeek,
                                                                     stream.Stream.CanWrite,
                                                                     stream.Stream.CanRead);
                                    connection.Value.WriteStreamData(streamId, new Span <byte>(buffer, 0, r));
                                });
                            }
                            else
                            {
                                connection.Value.WriteRetransmitTo(
                                    senderId,
                                    _ =>
                                {
                                    connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                                });
                            }
                        }

                        connection.Value.FlushOutputBuffer();
                    });

                break;
            }

            case PackageType.StreamData:
            {
                var streamId = _inputBufferReader.ReadInt32();
                var count    = _inputBufferReader.ReadUInt16();
                var data     = _inputBufferReader.ReadBytes(count);

                TaskCompletionSource <RemoteStream> remoteStreamTask;
                lock (_localHub._remoteStreams)
                {
                    _localHub._remoteStreams.TryGetValue((senderId, streamId), out remoteStreamTask);
                }

                if (remoteStreamTask != null && remoteStreamTask.Task.IsCompleted)
                {
                    var stream = remoteStreamTask.Task.Result;
                    stream.ReceiveData(data);
                }

                break;
            }

            case PackageType.StreamSeek:
            {
                var streamId = _inputBufferReader.ReadInt32();
                var offset   = _inputBufferReader.ReadInt64();
                var origin   = (SeekOrigin)_inputBufferReader.ReadByte();

                doAfter.Add(() =>
                    {
                        RemoteHub remoteHub;
                        lock (_localHub._knownHubs)
                        {
                            if (!_localHub._knownHubs.TryGetValue(senderId, out remoteHub))
                            {
                                writeError(ErrorCode.UnknownHub, "Unknown hub #" + senderId);
                                return;
                            }
                        }

                        using var connection = remoteHub._connections.GetLockedConenction();
                        var got       = false;
                        var regStream = default(RegisteredStream);
                        lock (_localHub._streams)
                        {
                            got = _localHub._streams.TryGetValue(streamId, out regStream);
                        }

                        if (got)
                        {
                            var stream = regStream.Stream;
                            stream.Seek(offset, origin);

                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamInfo(
                                    streamId,
                                    stream.Length,
                                    stream.Position,
                                    stream.CanSeek,
                                    stream.CanWrite,
                                    stream.CanRead);
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }
                        else
                        {
                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }


                        connection.Value.FlushOutputBuffer();
                    });

                break;
            }

            case PackageType.StreamSetLength:
            {
                var streamId  = _inputBufferReader.ReadInt32();
                var newLength = _inputBufferReader.ReadInt64();

                doAfter.Add(() =>
                    {
                        RemoteHub remoteHub;
                        lock (_localHub._knownHubs)
                        {
                            if (!_localHub._knownHubs.TryGetValue(senderId, out remoteHub))
                            {
                                writeError(ErrorCode.UnknownHub, "Unknown hub #" + senderId);
                                return;
                            }
                        }

                        using var connection = remoteHub._connections.GetLockedConenction();
                        var got       = false;
                        var regStream = default(RegisteredStream);
                        lock (_localHub._streams)
                        {
                            got = _localHub._streams.TryGetValue(streamId, out regStream);
                        }

                        if (got)
                        {
                            var stream = regStream.Stream;
                            stream.SetLength(newLength);

                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamInfo(streamId, stream.Length, stream.Position, stream.CanSeek, stream.CanWrite, stream.CanRead);
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }
                        else
                        {
                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }

                        connection.Value.FlushOutputBuffer();
                    });

                break;
            }

            case PackageType.StreamWrite:
            {
                var streamId = _inputBufferReader.ReadInt32();
                var count    = _inputBufferReader.ReadUInt16();
                var data     = _inputBufferReader.ReadBytes(count);

                doAfter.Add(() =>
                    {
                        RemoteHub remoteHub;
                        lock (_localHub._knownHubs)
                        {
                            if (!_localHub._knownHubs.TryGetValue(senderId, out remoteHub))
                            {
                                writeError(ErrorCode.UnknownHub, "Unknown hub #" + senderId);
                                return;
                            }
                        }

                        using var connection = remoteHub._connections.GetLockedConenction();
                        var got       = false;
                        var regStream = default(RegisteredStream);
                        lock (_localHub._streams)
                        {
                            got = _localHub._streams.TryGetValue(streamId, out regStream);
                        }

                        if (got)
                        {
                            var stream = regStream.Stream;
                            stream.Write(data);

                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamInfo(streamId, stream.Length, stream.Position, stream.CanSeek, stream.CanWrite, stream.CanRead);
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }
                        else
                        {
                            connection.Value.WriteRetransmitTo(
                                senderId,
                                _ =>
                            {
                                connection.Value.WriteStreamData(streamId, Array.Empty <byte>());
                            });
                        }

                        connection.Value.FlushOutputBuffer();
                    });

                break;
            }

            case PackageType.StreamClose:
            {
                var streamId = _inputBufferReader.ReadInt32();

                lock (_localHub._streams)
                {
                    if (_localHub._streams.TryGetValue(streamId, out var stream))
                    {
                        stream.Stream.Close();

                        _localHub._streams.Remove(streamId);
                    }
                }

                break;
            }

            default: throw new NotImplementedException($"Support of package {packageType} not implemented yet");
            }
        }
Exemplo n.º 3
0
 public HubDisconnectedException(RemoteHub remoteHub, Hub localHub, string message = null)
     : base(message ?? "Remote hub has disconnected")
 {
     RemoteHub = remoteHub;
     LocalHub  = localHub;
 }