private static void IncomingLocalItemBuild(PacketHeader packetHeader, Connection connection, ItemAssemblyConfig assemblyConfig)
{
//We start the build in the DFS task factory as it will be a long lived task
//BuildTaskFactory.StartNew(() =>
Action assembleAction = new Action(() =>
{
DistributedItem newItem = null;
byte[] itemBytes = null;
try
{
if (assemblyConfig == null)
throw new NullReferenceException("AssemblyConfig should not be null.");
if (DFS.loggingEnabled) DFS._DFSLogger.Debug("IncomingLocalItemBuild from " + connection + " for item " + assemblyConfig.CompleteDataCheckSum + ".");
//We check to see if we already have the necessary file locally
lock (globalDFSLocker)
{
if (swarmedItemsDict.ContainsKey(assemblyConfig.CompleteDataCheckSum))
{
if (swarmedItemsDict[assemblyConfig.CompleteDataCheckSum].Data.ItemBytesLength != assemblyConfig.TotalItemSizeInBytes)
throw new Exception("Possible MD5 conflict detected.");
else
newItem = swarmedItemsDict[assemblyConfig.CompleteDataCheckSum];
}
else
{
newItem = new DistributedItem(assemblyConfig);
swarmedItemsDict.Add(assemblyConfig.CompleteDataCheckSum, newItem);
}
}
//Ensure all possible local listeners are added here
List<ConnectionInfo> seedConnectionInfoList = (from current in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP) select new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, current, true)).ToList();
foreach (ConnectionInfo info in seedConnectionInfoList)
newItem.SwarmChunkAvailability.AddOrUpdateCachedPeerChunkFlags(info, newItem.SwarmChunkAvailability.PeerChunkAvailability(NetworkComms.NetworkIdentifier), newItem.SwarmChunkAvailability.PeerIsSuperPeer(NetworkComms.NetworkIdentifier), false);
//Build the item from the swarm
//If the item is already complete this will return immediately
newItem.AssembleItem((int)(ItemBuildTimeoutSecsPerMB * (assemblyConfig.TotalItemSizeInBytes / (1024.0 * 1024.0))));
//Once complete we pass the item bytes back into network comms
//If an exception is thrown we will probably not call this method, timeouts in other areas should then handle and can restart the build.
if (newItem.LocalItemComplete() && assemblyConfig.CompletedPacketType != "")
{
if (DFS.loggingEnabled) DFS._DFSLogger.Debug("IncomingLocalItemBuild completed for item with MD5 " + assemblyConfig.CompleteDataCheckSum + ". Item build target is " + assemblyConfig.ItemBuildMode + ".");
itemBytes = newItem.GetCompletedItemBytes();
}
else if (assemblyConfig.CompletedPacketType != "")
RemoveItem(assemblyConfig.CompleteDataCheckSum);
if (DFS.loggingEnabled)
{
Exception exceptionToLogWith = new Exception("Build completed successfully. Logging was enabled so saving build log.");
string fileName = "DFSItemBuildLog_" + newItem.ItemIdentifier + "_" + NetworkComms.NetworkIdentifier;
if (newItem != null)
LogTools.LogException(exceptionToLogWith, fileName, newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; }));
else
LogTools.LogException(exceptionToLogWith, fileName, "newItem==null so no build log was available.");
}
}
catch (ObjectDisposedException)
{
//The item was closed during assemble, no need to log an errors here
RemoveItem(assemblyConfig.CompleteDataCheckSum);
}
catch (CommsException e)
{
//Crap an error has happened, let people know we probably don't have a good file
RemoveItem(assemblyConfig.CompleteDataCheckSum);
//connection.CloseConnection(true, 30);
//LogTools.LogException(e, "CommsError_IncomingLocalItemBuild");
if (newItem != null)
LogTools.LogException(e, "Error_IncomingLocalItemBuildComms", newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; }));
else
LogTools.LogException(e, "Error_IncomingLocalItemBuildComms", "newItem==null so no build log was available.");
}
catch (Exception e)
{
//Crap an error has happened, let people know we probably don't have a good file
RemoveItem(assemblyConfig.CompleteDataCheckSum);
//connection.CloseConnection(true, 31);
if (newItem != null)
LogTools.LogException(e, "Error_IncomingLocalItemBuild", newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; }));
else
LogTools.LogException(e, "Error_IncomingLocalItemBuild", "newItem==null so no build log was available.");
}
//finally
//{
//Putting any code here appears to cause a sigsegv fault on leaving the finally in mono
//Just moved the code out to below as it makes no difference
//}
//Regardless of if the item completed we call the necessary packet handlers
//If there was a build error we just pass null data to the handlers so that the errors can get called up the relevant stack traces.
try
{
PacketHeader itemPacketHeader = new PacketHeader(assemblyConfig.CompletedPacketType, newItem == null ? 0 : newItem.Data.ItemBytesLength);
//We set the item checksum so that the entire distributed item can be easily retrieved later
itemPacketHeader.SetOption(PacketHeaderStringItems.PacketIdentifier, newItem == null ? "" : newItem.ItemTypeStr + "|" + newItem.ItemIdentifier + "|" + newItem.Data.CompleteDataCheckSum);
var dataStream = (itemBytes == null ? new MemoryStream(new byte[0], 0, 0, false, true) : new MemoryStream(itemBytes, 0, itemBytes.Length, false, true));
var sendRecieveOptions = new SendReceiveOptions<NullSerializer>(new Dictionary<string, string>());
NetworkComms.TriggerAllPacketHandlers(itemPacketHeader, connection, dataStream, sendRecieveOptions);
}
catch (Exception ex)
{
LogTools.LogException(ex, "Error_IncomingLocalItemBuildFinal");
}
});
if (BuildTaskFactory == null)
LogTools.LogException(new NullReferenceException("BuildTaskFactory is null in IncomingLocalItemBuild"), "IncomingLocalBuildError");
else
//Thread buildThread = new Thread(buildAction);
//buildThread.Name = "DFS_" + assemblyConfig.ItemIdentifier + "_Build";
//buildThread.Start();
BuildTaskFactory.StartNew(assembleAction);
}