private void tryAddInterfaceToHubOrWriteError(SharedInterface @interface, long hubId, uint interfaceInHubId, int version) { RemoteHub hub; lock (_localHub._knownHubs) { if (!_localHub._knownHubs.TryGetValue(hubId, out hub)) { writeError(ErrorCode.UnknownHub, "Unknown hub #" + hubId); return; } } @interface.Hubs.Add(new RemoteHubInterfaceLink(hub, interfaceInHubId, version)); lock (hub._interfaces) hub._interfaces.Add(@interface.Name); }
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"); } }