/// <summary> /// Initializes a new instance of the <see cref="DefaultPipelineProcessor{TPackageInfo}"/> class. /// </summary> /// <param name="receiveFilter">The initializing receive filter.</param> /// <param name="maxPackageLength">The max package size.</param> public DefaultPipelineProcessor(IReceiveFilter <TPackageInfo> receiveFilter, int maxPackageLength = 0) { m_ReceiveFilter = receiveFilter; m_ReceiveCache = new BufferList(); m_MaxPackageLength = maxPackageLength; }
/// <summary> /// Filters the received data. /// </summary> /// <param name="data">The received data.</param> /// <param name="rest">The length of the rest data after filtering.</param> /// <returns>the received packageInfo instance</returns> public virtual TPackageInfo Filter(BufferList data, out int rest) { rest = 0; int searchEndMarkOffset; int searchEndMarkLength; var currentSegment = data.Last; var readBuffer = currentSegment.Array; var offset = currentSegment.Offset; var length = currentSegment.Count; int totalParsed = 0; if (!m_FoundBegin) { int pos = readBuffer.SearchMark(offset, length, m_BeginSearchState, out totalParsed); if (pos < 0) { //All received data is part of the begin mark if (m_BeginSearchState.Matched > 0 && data.Total == m_BeginSearchState.Matched) { return(default(TPackageInfo)); } //Invalid data, contains invalid data before the regular begin mark State = FilterState.Error; return(default(TPackageInfo)); } //Found the matched begin mark if (pos != offset)//But not at the beginning, contains invalid data before the regular begin mark { State = FilterState.Error; return(default(TPackageInfo)); } //Found start mark, then search end mark m_FoundBegin = true; searchEndMarkOffset = offset + totalParsed; //Reach end if (offset + length <= searchEndMarkOffset) { return(default(TPackageInfo)); } searchEndMarkLength = offset + length - searchEndMarkOffset; } else//Already found begin mark { searchEndMarkOffset = offset; searchEndMarkLength = length; } while (true) { int parsedLength; var endPos = readBuffer.SearchMark(searchEndMarkOffset, searchEndMarkLength, m_EndSearchState, out parsedLength); //Haven't found end mark if (endPos < 0) { return(default(TPackageInfo)); } totalParsed += parsedLength; //include begin mark if the mark is found in this round receiving rest = length - totalParsed; var packageInfo = ResolvePackage(this.GetBufferStream(data)); if (!ReferenceEquals(packageInfo, default(TPackageInfo))) { Reset(); return(packageInfo); } if (rest > 0) { searchEndMarkOffset = endPos + m_EndSearchState.Mark.Length; searchEndMarkLength = rest; continue; } //Not found end mark return(default(TPackageInfo)); } }
/// <summary> /// Processes the input segment. /// </summary> /// <param name="segment">The input segment.</param> /// <returns> /// the processing result /// </returns> public virtual ProcessResult Process(ArraySegment <byte> segment) { var receiveCache = m_ReceiveCache; receiveCache.Add(segment); var rest = 0; var currentReceiveFilter = m_ReceiveFilter; SingleItemList <IPackageInfo> singlePackage = null; List <IPackageInfo> packageList = null; while (true) { var lastItemLength = receiveCache.Last.Count; var packageInfo = currentReceiveFilter.Filter(receiveCache, out rest); if (currentReceiveFilter.State == FilterState.Error) { return(ProcessResult.Create(ProcessState.Error)); } if (m_MaxPackageLength > 0) { var length = receiveCache.Total; if (length > m_MaxPackageLength) { return(ProcessResult.Create(ProcessState.Error, string.Format("Max package length: {0}, current processed length: {1}", m_MaxPackageLength, length))); } } var nextReceiveFilter = currentReceiveFilter.NextReceiveFilter; // don't reset the filter if no request is resolved if (packageInfo != null) { currentReceiveFilter.Reset(); } if (nextReceiveFilter != null) { currentReceiveFilter = nextReceiveFilter; m_ReceiveFilter = currentReceiveFilter; } // continue receive if (packageInfo == null) { if (rest > 0) { var last = receiveCache.Last; if (rest != lastItemLength) { PushResetData(segment, rest); } continue; } return(ProcessResult.Create(ProcessState.Cached, GetNotNullOne(packageList, singlePackage))); } if (packageList != null) { packageList.Add(packageInfo); } else if (singlePackage == null) { singlePackage = new SingleItemList <IPackageInfo>(packageInfo); } else { if (packageList == null) { packageList = new List <IPackageInfo>(); } packageList.Add(singlePackage[0]); packageList.Add(packageInfo); singlePackage = null; } if (packageInfo is IBufferedPackageInfo && // is a buffered package (packageInfo as IBufferedPackageInfo).Data is BufferList) // and it uses receive buffer directly { // so we need to create a new receive buffer container to use m_ReceiveCache = receiveCache = new BufferList(); if (rest <= 0) { return(ProcessResult.Create(ProcessState.Cached, GetNotNullOne(packageList, singlePackage))); } } else { m_ReceiveCache.Clear(); if (rest <= 0) { return(ProcessResult.Create(ProcessState.Completed, GetNotNullOne(packageList, singlePackage))); } } PushResetData(segment, rest); } }
/// <summary> /// Processes the input segment. /// </summary> /// <param name="segment">The input segment.</param> /// <param name="state">The buffer state.</param> /// <returns> /// the processing result /// </returns> public virtual ProcessResult Process(ArraySegment <byte> segment, IBufferState state) { var receiveCache = m_ReceiveCache; receiveCache.Add(segment, state); var rest = 0; var currentReceiveFilter = m_ReceiveFilter; while (true) { var packageInfo = currentReceiveFilter.Filter(receiveCache, out rest); if (currentReceiveFilter.State == FilterState.Error) { m_BufferRecycler.Return(receiveCache.GetAllCachedItems(), 0, receiveCache.Count); return(ProcessResult.Create(ProcessState.Error)); } if (m_MaxPackageLength > 0) { var length = receiveCache.Total; if (length > m_MaxPackageLength) { m_BufferRecycler.Return(receiveCache.GetAllCachedItems(), 0, receiveCache.Count); return(ProcessResult.Create(ProcessState.Error, string.Format("Max package length: {0}, current processed length: {1}", m_MaxPackageLength, length))); } } var nextReceiveFilter = currentReceiveFilter.NextReceiveFilter; currentReceiveFilter.Reset(); if (nextReceiveFilter != null) { currentReceiveFilter = nextReceiveFilter; m_ReceiveFilter = currentReceiveFilter; } //Receive continue if (packageInfo == null) { if (rest > 0) { if (rest != segment.Count) { ReturnOtherThanLastBuffer(); PushResetData(segment, rest, state); } continue; } return(ProcessResult.Create(ProcessState.Cached)); } m_PackageHandler.Handle(packageInfo); if (packageInfo is IBufferedPackageInfo && // is a buffered package (packageInfo as IBufferedPackageInfo).Data is BufferList) // and it uses receive buffer directly { // so we need to create a new receive buffer container to use m_ReceiveCache = receiveCache = new BufferList(); if (rest <= 0) { return(ProcessResult.Create(ProcessState.Cached)); } } else { ReturnOtherThanLastBuffer(); if (rest <= 0) { return(ProcessResult.Create(ProcessState.Completed)); } } PushResetData(segment, rest, state); } }