using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace ScreenConnect; public class VirtualStreamSender : IDisposable, IMessageProcessor { private class Entry { public IReadStreamProducer StreamProducer; public Stream Stream; public long LastStreamReadTime; } private Dictionary streamMap; private Proc messageHandler; private Proc streamCompleteHandler; public void Dispose() { Reset(); } private void DisposeEntryQuietly(Entry entry) { entry.StreamProducer.DisposeQuietly(); if (entry.Stream != null) { entry.Stream.DisposeQuietly(); } } public void Reset() { lock (streamMap) { foreach (Entry value in streamMap.Values) { DisposeEntryQuietly(value); } streamMap.Clear(); } } public IEnumerable RegisterVirtualFiles(IEnumerable fileDatas, string basePath = null) { return fileDatas.Select((FileData _) => new VirtualFileInfo { StreamID = RegisterVirtualStream(_), FilePath = ((basePath == null) ? _.FilePath : Path.Combine(basePath, _.FilePath)).ConvertBothSlashesToChar('/'), CreationTime = _.CreationTime, LastWriteTime = _.LastWriteTime, LastAccessTime = _.LastAccessTime, Size = _.Size, IsDirectory = _.IsDirectory }); } public Guid RegisterVirtualStream(IReadStreamProducer streamProducer) { Guid guid = Guid.NewGuid(); lock (streamMap) { streamMap.Add(guid, new Entry { StreamProducer = streamProducer, LastStreamReadTime = Singleton.Instance.GetMillisecondCount() }); return guid; } } public void CloseExpiredStreamsQuietly() { lock (streamMap) { if (streamMap.Count == 0) { return; } long earliestValidLastStreamReadTime = Singleton.Instance.GetMillisecondCount() - 60000; streamMap.RemoveAll(delegate(Guid key, Entry value) { if (value.LastStreamReadTime > earliestValidLastStreamReadTime) { return false; } DisposeEntryQuietly(value); return true; }); } } public long GetSentByteCount(Guid streamID) { lock (streamMap) { if (!streamMap.TryGetValue(streamID, out var value) || value.Stream == null) { return -1L; } return value.Stream.Position; } } public VirtualStreamSender(Proc messageHandler, Proc streamCompleteHandler) { this.messageHandler = messageHandler; this.streamCompleteHandler = streamCompleteHandler; streamMap = new Dictionary(); } public bool ProcessMessage(VirtualStreamControlMessage message) { Entry value = null; lock (streamMap) { if (!streamMap.TryGetValue(message.StreamID, out value)) { return false; } } RequestVirtualStreamDataMessage requestVirtualStreamDataMessage = message as RequestVirtualStreamDataMessage; if (requestVirtualStreamDataMessage != null && requestVirtualStreamDataMessage.RequestedPosition == 0L) { if (value.Stream != null) { Extensions.DisposeQuietly(ref value.Stream); streamCompleteHandler(); } } else if (requestVirtualStreamDataMessage != null) { try { if (value.Stream == null) { value.Stream = value.StreamProducer.OpenReadStream(); value.LastStreamReadTime = Singleton.Instance.GetMillisecondCount(); } long num = requestVirtualStreamDataMessage.RequestedPosition - value.Stream.Position; while (num > 0) { byte[] array = new byte[Math.Min(num, 2896L)]; int num2 = value.Stream.Read(array, 0, array.Length); VirtualStreamDataMessage arg = new VirtualStreamDataMessage { StreamID = message.StreamID, Data = new ArraySegment(array, 0, num2) }; messageHandler(arg); num -= num2; value.LastStreamReadTime = Singleton.Instance.GetMillisecondCount(); if (num2 == 0) { break; } } } catch (Exception ex) { TypeTrace.TraceException(ex); } } else if (message is ReleaseVirtualStreamMessage) { lock (streamMap) { DisposeEntryQuietly(value); streamMap.Remove(message.StreamID); } } return true; } }