Modified the ReutersWneExtractor to use an external event handler.
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 13s

This commit is contained in:
feyris-tan 2026-05-04 22:12:17 +02:00
parent 0c0932e193
commit 5715e047a3
4 changed files with 112 additions and 12 deletions

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.ReutersWne
{
internal interface IWneHandler
{
void OnWneStoryComplete(WneStoryProgress wneStoryProgress, Stream value);
void OnWneStoryDetect(uint embeddedSessionId);
void OnWneStoryFail(uint sessionId);
void OnWneStoryProgress(WneStoryProgress wneStoryProgress)
}
}

View File

@ -6,7 +6,7 @@ using skyscraper5.Skyscraper.Plugins;
namespace skyscraper8.ReutersWne; namespace skyscraper8.ReutersWne;
[SkyscraperPlugin] [SkyscraperPlugin]
public class ReutersWneExtractor : ISkyscraperMpePlugin internal class ReutersWneExtractor : ISkyscraperMpePlugin
{ {
private ILog _logger; private ILog _logger;
public void ConnectToStorage(object[] connector) public void ConnectToStorage(object[] connector)
@ -169,6 +169,9 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
private void DeliverFile(WneStory story) private void DeliverFile(WneStory story)
{ {
Handler.OnWneStoryComplete(new WneStoryProgress(story), story.GetStream());
/*
//_logger.InfoFormat("Attempting to deliver story #{0}", story.SessionId); //_logger.InfoFormat("Attempting to deliver story #{0}", story.SessionId);
//_logger.InfoFormat("Expected number of blocks: {0}", story.ExpectedPayloadBlock); //_logger.InfoFormat("Expected number of blocks: {0}", story.ExpectedPayloadBlock);
@ -193,7 +196,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
FileStream fileStream = outFileInfo.OpenWrite(); FileStream fileStream = outFileInfo.OpenWrite();
listByteArrayStream.CopyTo(fileStream); listByteArrayStream.CopyTo(fileStream);
fileStream.Flush(); fileStream.Flush();
fileStream.Close(); fileStream.Close();*/
} }
private bool ParsePacketType3(Span<byte> udpPayload) private bool ParsePacketType3(Span<byte> udpPayload)
@ -226,6 +229,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
currentStory = new WneStory(sessionId); currentStory = new WneStory(sessionId);
wneStories.Add(sessionId, currentStory); wneStories.Add(sessionId, currentStory);
_logger.InfoFormat("Found new WNE story #{0}", sessionId); _logger.InfoFormat("Found new WNE story #{0}", sessionId);
Handler?.OnWneStoryDetect(sessionId);
} }
else else
{ {
@ -293,6 +297,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
if (!wneStories.ContainsKey(sessionId)) if (!wneStories.ContainsKey(sessionId))
{ {
_logger.InfoFormat("Found new WNE story #{0}", sessionId); _logger.InfoFormat("Found new WNE story #{0}", sessionId);
Handler?.OnWneStoryDetect(sessionId);
WneStory newStory = new WneStory(sessionId); WneStory newStory = new WneStory(sessionId);
newStory.EccGroup = udpPayload[8]; newStory.EccGroup = udpPayload[8];
if (udpPayload[11] == 0x07) if (udpPayload[11] == 0x07)
@ -330,6 +335,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
if (fourthUint != 0) if (fourthUint != 0)
{ {
OnError("Unexpected payload packet in story #{0}. Expected {1}, got {2}.", sessionId, 0, fourthUint); OnError("Unexpected payload packet in story #{0}. Expected {1}, got {2}.", sessionId, 0, fourthUint);
Handler?.OnWneStoryFail(sessionId);
return false; return false;
} }
uint thirdUint = udpPayload.ReadUInt32LittleEndian(8); uint thirdUint = udpPayload.ReadUInt32LittleEndian(8);
@ -339,11 +345,13 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
{ {
OnError("Expected payload block {0} but got {1}. This story ({2}) is incomplete and can not be recovered.", wneStories[sessionId].ExpectedPayloadBlock, thirdUint, sessionId); OnError("Expected payload block {0} but got {1}. This story ({2}) is incomplete and can not be recovered.", wneStories[sessionId].ExpectedPayloadBlock, thirdUint, sessionId);
wneStories[sessionId].Corrupted = true; wneStories[sessionId].Corrupted = true;
Handler?.OnWneStoryFail(sessionId);
} }
return false; return false;
} }
wneStories[sessionId].AppendPayloadBlock(udpPayload.Slice(16)); wneStories[sessionId].AppendPayloadBlock(udpPayload.Slice(16));
Handler.OnWneStoryProgress(new WneStoryProgress(wneStories[sessionId]));
return true; return true;
} }
} }
@ -353,6 +361,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
if (!wneStories.ContainsKey(sessionId)) if (!wneStories.ContainsKey(sessionId))
{ {
OnError("Missed announcement of story #{0}", sessionId); OnError("Missed announcement of story #{0}", sessionId);
Handler.OnWneStoryFail(sessionId);
return false; return false;
} }
outerStory = wneStories[sessionId]; outerStory = wneStories[sessionId];
@ -394,10 +403,12 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
{ {
wneStories.Add(embeddedSessionId, new WneStory(embeddedSessionId)); wneStories.Add(embeddedSessionId, new WneStory(embeddedSessionId));
_logger.InfoFormat("Found new embedded WNE story #{0}", embeddedSessionId); _logger.InfoFormat("Found new embedded WNE story #{0}", embeddedSessionId);
Handler?.OnWneStoryDetect(embeddedSessionId);
} }
else else
{ {
OnError("Missed announcement of embedded WNE story #{0}", embeddedSessionId); OnError("Missed announcement of embedded WNE story #{0}", embeddedSessionId);
Handler?.OnWneStoryFail(outerStory.SessionId);
return false; return false;
} }
} }
@ -413,6 +424,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
if (outerStory.ExpectedEccGroup != udpPayload[8]) if (outerStory.ExpectedEccGroup != udpPayload[8])
{ {
OnError("Expected ECC group {0} but got {1}", outerStory.ExpectedEccGroup, udpPayload[8]); OnError("Expected ECC group {0} but got {1}", outerStory.ExpectedEccGroup, udpPayload[8]);
Handler?.OnWneStoryFail(outerStory.SessionId);
return false; return false;
} }
@ -431,8 +443,8 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
{ {
if (udpPayload[12] != 0x01) if (udpPayload[12] != 0x01)
{ {
OnError("Expected Continuity Counter {0} but got {1}", OnError("Expected Continuity Counter {0} but got {1}", outerStory.ExpectedContinuityCounter, udpPayload[11]);
outerStory.ExpectedContinuityCounter, udpPayload[11]); Handler?.OnWneStoryFail(outerStory.SessionId);
return false; return false;
} }
@ -478,10 +490,12 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
{ {
OnError("Expected payload block {0} but got {1}. This story ({2}) is incomplete and can not be recovered.", wneStories[sessionId].ExpectedPayloadBlock, thirdUint, sessionId); OnError("Expected payload block {0} but got {1}. This story ({2}) is incomplete and can not be recovered.", wneStories[sessionId].ExpectedPayloadBlock, thirdUint, sessionId);
wneStories[sessionId].Corrupted = true; wneStories[sessionId].Corrupted = true;
Handler?.OnWneStoryFail(sessionId);
return false; return false;
} }
wneStories[sessionId].AppendPayloadBlock(udpPayload.Slice(16)); wneStories[sessionId].AppendPayloadBlock(udpPayload.Slice(16));
Handler?.OnWneStoryProgress(new WneStoryProgress(wneStories[sessionId]));
return true; return true;
} }
@ -498,6 +512,7 @@ public class ReutersWneExtractor : ISkyscraperMpePlugin
private HashSet<string> loggedErrors; private HashSet<string> loggedErrors;
private Dictionary<uint, WneStory> wneStories; private Dictionary<uint, WneStory> wneStories;
public IWneHandler Handler { get; set; }
private void OnError(string message, params object[] args) private void OnError(string message, params object[] args)
{ {

View File

@ -21,9 +21,37 @@ internal class WneStory : IDisposable
private List<byte[]> payloadBlocks; private List<byte[]> payloadBlocks;
public bool Corrupted; public bool Corrupted;
public bool Delivered; public bool Delivered;
public uint FileSize;
private MemoryStream preallocated;
private uint _fileSize;
public uint FileSize
{
get
{
return _fileSize;
}
set
{
if (payloadBlocks != null)
{
throw new NotImplementedException("Can't set the file size when a block was already delivered");
}
preallocated = new MemoryStream(new byte[_fileSize]);
_fileSize = value;
}
}
public long CaughtPayloadBytes;
public void AppendPayloadBlock(Span<byte> slice) public void AppendPayloadBlock(Span<byte> slice)
{
if (preallocated != null)
{
preallocated.Write(slice);
ExpectedPayloadBlock++;
CaughtPayloadBytes += slice.Length;
}
else
{ {
if (payloadBlocks == null) if (payloadBlocks == null)
{ {
@ -31,6 +59,8 @@ internal class WneStory : IDisposable
} }
payloadBlocks.Add(slice.ToArray()); payloadBlocks.Add(slice.ToArray());
ExpectedPayloadBlock++; ExpectedPayloadBlock++;
CaughtPayloadBytes += slice.Length;
}
} }
public bool IsEmpty() public bool IsEmpty()
@ -56,14 +86,23 @@ internal class WneStory : IDisposable
return true; return true;
} }
public ListByteArrayStream ToStream() public Stream ToStream()
{ {
if (Delivered) if (Delivered)
{ {
throw new InvalidOperationException("Cannot convert a delivered story to a stream."); throw new InvalidOperationException("Cannot convert a delivered story to a stream.");
} }
if (preallocated != null)
{
preallocated.Position = 0;
return preallocated;
}
else
{
return new ListByteArrayStream(payloadBlocks); return new ListByteArrayStream(payloadBlocks);
} }
}
public void Dispose() public void Dispose()
{ {
@ -71,4 +110,26 @@ internal class WneStory : IDisposable
payloadBlocks = null; payloadBlocks = null;
Delivered = true; Delivered = true;
} }
public WneStoryProgress GetProgress()
{
return new WneStoryProgress(this);
}
}
struct WneStoryProgress
{
internal WneStoryProgress(WneStory source)
{
this.Filename = source.SourceFileName;
this.SessionId = source.SessionId;
this.FileSize = source.FileSize;
this.FileCaught = source.CaughtPayloadBytes;
}
public string Filename { get; }
public uint SessionId { get; }
public uint FileSize { get; }
public long FileCaught { get; }
} }

View File

@ -151,6 +151,14 @@ namespace skyscraper8.Skyscraper.IO
continue; continue;
if (finishedSegments.Contains(segmentNames[i])) if (finishedSegments.Contains(segmentNames[i]))
continue; continue;
if (segmentNames[i].EndsWith(".m3u8"))
{
this.source = String.Format("{0}{1}",GetRoot(source), segmentNames[i]);
ReloadSegmentList();
return GetNextSegment();
}
if (string.IsNullOrEmpty(segmentNames[i]))
continue;
this.segmentIndex = i; this.segmentIndex = i;
this.finishedSegments.Add(segmentNames[i]); this.finishedSegments.Add(segmentNames[i]);