File sharing fixes: canceling transfers, displaying transfers & progress server-side, invalid sub files aren't selected or sent

This commit is contained in:
Regalis
2016-02-27 00:25:13 +02:00
parent 9f8f4e290e
commit 7309201b11
9 changed files with 217 additions and 83 deletions
+14
View File
@@ -417,6 +417,20 @@ namespace Barotrauma
//Hull.DebugDraw = !Hull.DebugDraw; //Hull.DebugDraw = !Hull.DebugDraw;
//Ragdoll.DebugDraw = !Ragdoll.DebugDraw; //Ragdoll.DebugDraw = !Ragdoll.DebugDraw;
GameMain.DebugDraw = !GameMain.DebugDraw; GameMain.DebugDraw = !GameMain.DebugDraw;
break;
case "sendrandomdata":
int messageCount = 1;
if (commands.Length>1) int.TryParse(commands[1], out messageCount);
for (int i = 0; i < messageCount; i++ )
{
if (GameMain.Server!=null)
{
GameMain.Server.SendRandomData();
}
}
break; break;
case "netstats": case "netstats":
if (GameMain.Server == null) return; if (GameMain.Server == null) return;
+1 -1
View File
@@ -7,7 +7,7 @@ namespace Barotrauma
{ {
public static Queue<GUIComponent> MessageBoxes = new Queue<GUIComponent>(); public static Queue<GUIComponent> MessageBoxes = new Queue<GUIComponent>();
const int DefaultWidth=400, DefaultHeight=200; const int DefaultWidth=400, DefaultHeight=250;
//public delegate bool OnClickedHandler(GUIButton button, object obj); //public delegate bool OnClickedHandler(GUIButton button, object obj);
//public OnClickedHandler OnClicked; //public OnClickedHandler OnClicked;
+7 -3
View File
@@ -631,10 +631,14 @@ namespace Barotrauma
if (extension == ".sub") if (extension == ".sub")
{ {
Stream stream = SaveUtil.DecompressFiletoStream(file); Stream stream = null;
if (stream == null) try
{ {
DebugConsole.ThrowError("Loading submarine ''" + file + "'' failed!"); stream = SaveUtil.DecompressFiletoStream(file);
}
catch (Exception e)
{
DebugConsole.ThrowError("Loading submarine ''" + file + "'' failed!", e);
return null; return null;
} }
@@ -2,6 +2,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace Barotrauma.Networking namespace Barotrauma.Networking
{ {
@@ -18,7 +19,7 @@ namespace Barotrauma.Networking
private FileStream writeStream; private FileStream writeStream;
private int timeStarted; private int timeStarted;
private string filePath; private string downloadFolder;
private FileTransferType fileType; private FileTransferType fileType;
@@ -28,11 +29,6 @@ namespace Barotrauma.Networking
private set; private set;
} }
public string FilePath
{
get { return filePath; }
}
public ulong FileSize public ulong FileSize
{ {
get { return length; } get { return length; }
@@ -69,14 +65,13 @@ namespace Barotrauma.Networking
public float Progress public float Progress
{ {
get { return (float)received / (float)length; } get { return (float)received / (float)length; }
} }
public FileStreamReceiver(NetClient client, string filePath, FileTransferType fileType, OnFinished onFinished) public FileStreamReceiver(NetClient client, string filePath, FileTransferType fileType, OnFinished onFinished)
{ {
this.client = client; this.client = client;
this.filePath = filePath; this.downloadFolder = filePath;
this.fileType = fileType; this.fileType = fileType;
this.onFinished = onFinished; this.onFinished = onFinished;
@@ -92,8 +87,10 @@ namespace Barotrauma.Networking
} }
catch (Exception e) catch (Exception e)
{ {
DebugConsole.ThrowError("Error while receiving file ''"+FileName+"''", e); ErrorMessage = "Error while receiving file ''"+FileName+"'' {"+e.Message+"}";
Status = FileTransferStatus.Error; DeleteFile();
if (onFinished != null) onFinished(this);
} }
} }
@@ -102,21 +99,18 @@ namespace Barotrauma.Networking
if (fileSize > MaxFileSize) if (fileSize > MaxFileSize)
{ {
ErrorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")"; ErrorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")";
Status = FileTransferStatus.Error;
return false; return false;
} }
if (type != (byte)fileType) if (type != (byte)fileType)
{ {
ErrorMessage = "Unexpected file type ''"+type+"'' (expected "+fileType+")"; ErrorMessage = "Unexpected file type ''" + type + "'' (expected " + fileType + ")";
Status = FileTransferStatus.Error;
return false; return false;
} }
if (!Regex.Match(fileName, @"^[\w\- ]+[\w\-. ]*$").Success) if (!Regex.Match(fileName, @"^[\w\- ]+[\w\-. ]*$").Success)
{ {
ErrorMessage = "Illegal characters in file name ''"+fileName+"''"; ErrorMessage = "Illegal characters in file name ''" + fileName + "''";
Status = FileTransferStatus.Error;
return false; return false;
} }
@@ -125,9 +119,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferType.Submarine: case (byte)FileTransferType.Submarine:
if (Path.GetExtension(fileName) != ".sub") if (Path.GetExtension(fileName) != ".sub")
{ {
ErrorMessage = "Wrong file extension ''" + Path.GetExtension(fileName)+"''! (Expected .sub)"; ErrorMessage = "Wrong file extension ''" + Path.GetExtension(fileName) + "''! (Expected .sub)";
Status = FileTransferStatus.Error;
return false; return false;
} }
break; break;
@@ -138,12 +130,17 @@ namespace Barotrauma.Networking
public void DeleteFile() public void DeleteFile()
{ {
string file = Path.Combine(filePath, FileName); if (FileName == null) return;
writeStream.Flush(); string file = Path.Combine(downloadFolder, FileName);
writeStream.Close();
writeStream.Dispose(); if (writeStream!=null)
writeStream = null; {
writeStream.Flush();
writeStream.Close();
writeStream.Dispose();
writeStream = null;
}
Status = FileTransferStatus.Canceled; Status = FileTransferStatus.Canceled;
@@ -170,9 +167,9 @@ namespace Barotrauma.Networking
if (length == 0) if (length == 0)
{ {
if (!Directory.Exists(filePath)) if (!string.IsNullOrWhiteSpace(downloadFolder) && !Directory.Exists(downloadFolder))
{ {
Directory.CreateDirectory(filePath); Directory.CreateDirectory(downloadFolder);
} }
byte fileTypeByte = inc.ReadByte(); byte fileTypeByte = inc.ReadByte();
@@ -183,11 +180,12 @@ namespace Barotrauma.Networking
if (!ValidateInitialData(fileTypeByte, FileName, length)) if (!ValidateInitialData(fileTypeByte, FileName, length))
{ {
Status = FileTransferStatus.Error; Status = FileTransferStatus.Error;
DeleteFile();
if (onFinished != null) onFinished(this); if (onFinished != null) onFinished(this);
return; return;
} }
writeStream = new FileStream(Path.Combine(filePath, FileName), FileMode.Create, FileAccess.Write, FileShare.None); writeStream = new FileStream(Path.Combine(downloadFolder, FileName), FileMode.Create, FileAccess.Write, FileShare.None);
timeStarted = Environment.TickCount; timeStarted = Environment.TickCount;
Status = FileTransferStatus.NotStarted; Status = FileTransferStatus.NotStarted;
@@ -218,11 +216,61 @@ namespace Barotrauma.Networking
if (received >= length) if (received >= length)
{ {
Status = FileTransferStatus.Finished; writeStream.Flush();
writeStream.Close();
writeStream.Dispose();
writeStream = null;
Status = IsReceivedFileValid() ? FileTransferStatus.Finished : FileTransferStatus.Error;
if (onFinished!=null) onFinished(this); if (onFinished!=null) onFinished(this);
if (Status == FileTransferStatus.Error) DeleteFile();
Dispose();
} }
} }
private bool IsReceivedFileValid()
{
switch (fileType)
{
case FileTransferType.Submarine:
string file = Path.Combine(downloadFolder, FileName);
Stream stream = null;
try
{
stream = SaveUtil.DecompressFiletoStream(file);
}
catch (Exception e)
{
ErrorMessage = "Loading submarine ''" + file + "'' failed! {"+ e.Message + "}";
return false;
}
if (stream == null)
{
ErrorMessage = "Decompressing submarine file''" + file + "'' failed!";
return false;
}
try
{
stream.Position = 0;
var doc = XDocument.Load(stream); //ToolBox.TryLoadXml(file);
stream.Close();
stream.Dispose();
}
catch
{
ErrorMessage = "Failed to parse submarine file ''"+file+"''!";
return false;
}
break;
}
return true;
}
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@@ -11,7 +11,7 @@ namespace Barotrauma.Networking
enum FileTransferType enum FileTransferType
{ {
Unknown, Submarine Unknown, Submarine, Cancel
} }
class FileStreamSender : IDisposable class FileStreamSender : IDisposable
@@ -39,6 +39,20 @@ namespace Barotrauma.Networking
private set; private set;
} }
public float Progress
{
get { return inputStream == null ? 0.0f : (float)sentOffset / (float)inputStream.Length; }
}
public int Sent
{
get { return sentOffset; }
}
public long FileSize
{
get { return inputStream == null ? 0 : inputStream.Length; }
}
public static FileStreamSender Create(NetConnection conn, string fileName, FileTransferType fileType) public static FileStreamSender Create(NetConnection conn, string fileName, FileTransferType fileType)
{ {
@@ -68,7 +82,10 @@ namespace Barotrauma.Networking
public void Update(float deltaTime) public void Update(float deltaTime)
{ {
if (inputStream == null) return; if (inputStream == null ||
Status == FileTransferStatus.Canceled ||
Status == FileTransferStatus.Error ||
Status == FileTransferStatus.Finished) return;
waitTimer -= deltaTime; waitTimer -= deltaTime;
if (waitTimer > 0.0f) return; if (waitTimer > 0.0f) return;
@@ -115,6 +132,11 @@ namespace Barotrauma.Networking
} }
} }
public void CancelTransfer()
{
Status = FileTransferStatus.Canceled;
}
public void Dispose() public void Dispose()
{ {
+6 -1
View File
@@ -713,6 +713,11 @@ namespace Barotrauma.Networking
fileStreamReceiver.DeleteFile(); fileStreamReceiver.DeleteFile();
fileStreamReceiver.Dispose(); fileStreamReceiver.Dispose();
fileStreamReceiver = null; fileStreamReceiver = null;
NetOutgoingMessage msg = client.CreateMessage();
msg.Write((byte)PacketTypes.RequestFile);
msg.Write((byte)FileTransferType.Cancel);
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
} }
} }
@@ -736,7 +741,7 @@ namespace Barotrauma.Networking
{ {
if (receiver.Status == FileTransferStatus.Error) if (receiver.Status == FileTransferStatus.Error)
{ {
new GUIMessageBox("Error while receiving file from server", receiver.ErrorMessage); new GUIMessageBox("Error while receiving file from server", receiver.ErrorMessage, 400, 350);
receiver.DeleteFile(); receiver.DeleteFile();
} }
+75 -33
View File
@@ -312,13 +312,36 @@ namespace Barotrauma.Networking
foreach (Client c in ConnectedClients) foreach (Client c in ConnectedClients)
{ {
if (c.FileStreamSender!=null && Rand.Range(0.0f, 1.0f)<0.01f) if (c.FileStreamSender != null)
{ {
var clientNameBox = GameMain.NetLobbyScreen.PlayerList.FindChild(c.name);
var clientInfo = clientNameBox.FindChild(c.FileStreamSender);
if (clientInfo==null)
{
clientInfo = new GUIFrame(new Rectangle(0,0,180,0), Color.Transparent, Alignment.TopRight, null, clientNameBox);
clientInfo.UserData = c.FileStreamSender;
new GUIProgressBar(new Rectangle(0, 4, 0, clientInfo.Rect.Height-8), Color.Green, GUI.Style, 0.0f, Alignment.Left, clientInfo).IsHorizontal = true;
new GUITextBlock(new Rectangle(0,2,0,0), "", GUI.Style, Alignment.TopLeft, Alignment.Left | Alignment.CenterY, clientInfo, true, GUI.SmallFont);
}
else
{
var progressBar = clientInfo.GetChild<GUIProgressBar>();
progressBar.BarSize = c.FileStreamSender.Progress;
var progressText = clientInfo.GetChild<GUITextBlock>();
progressText.Text = c.FileStreamSender.FileName + " " +
MathUtils.GetBytesReadable(c.FileStreamSender.Sent) + " / " + MathUtils.GetBytesReadable(c.FileStreamSender.FileSize);
}
c.FileStreamSender.Update(deltaTime); c.FileStreamSender.Update(deltaTime);
if (c.FileStreamSender.Status == FileTransferStatus.Finished || if (c.FileStreamSender.Status == FileTransferStatus.Finished ||
c.FileStreamSender.Status == FileTransferStatus.Error) c.FileStreamSender.Status == FileTransferStatus.Error ||
c.FileStreamSender.Status == FileTransferStatus.Canceled)
{ {
clientNameBox.RemoveChild(clientInfo);
c.FileStreamSender.Dispose(); c.FileStreamSender.Dispose();
c.FileStreamSender = null; c.FileStreamSender = null;
} }
@@ -522,11 +545,13 @@ namespace Barotrauma.Networking
var outmsg = server.CreateMessage(); var outmsg = server.CreateMessage();
outmsg.Write((byte)PacketTypes.RequestFile); outmsg.Write((byte)PacketTypes.RequestFile);
outmsg.Write(false); outmsg.Write(false);
outmsg.Write("File downloads disabled by the server");
server.SendMessage(outmsg, dataSender.Connection, NetDeliveryMethod.ReliableUnordered);
break; break;
} }
byte fileType = inc.ReadByte(); byte fileType = inc.ReadByte();
string fileName = inc.ReadString(); string fileName = fileType == (byte)FileTransferType.Cancel ? "" : inc.ReadString();
switch (fileType) switch (fileType)
{ {
@@ -544,6 +569,12 @@ namespace Barotrauma.Networking
if (fileStreamSender != null) dataSender.FileStreamSender = fileStreamSender; if (fileStreamSender != null) dataSender.FileStreamSender = fileStreamSender;
} }
break; break;
case (byte)FileTransferType.Cancel:
if (dataSender.FileStreamSender != null)
{
dataSender.FileStreamSender.CancelTransfer();
}
break;
default: default:
DebugConsole.ThrowError("Unknown file type was requested ("+fileType+")"); DebugConsole.ThrowError("Unknown file type was requested ("+fileType+")");
break; break;
@@ -1079,6 +1110,12 @@ namespace Barotrauma.Networking
server.SendMessage(outmsg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0); server.SendMessage(outmsg, server.Connections, NetDeliveryMethod.ReliableUnordered, 0);
} }
if (client.FileStreamSender != null)
{
client.FileStreamSender.Dispose();
client.FileStreamSender = null;
}
AddChatMessage(msg, ChatMessageType.Server); AddChatMessage(msg, ChatMessageType.Server);
UpdateCrewFrame(); UpdateCrewFrame();
@@ -1516,38 +1553,38 @@ namespace Barotrauma.Networking
/// sends some random data to the clients /// sends some random data to the clients
/// use for debugging purposes /// use for debugging purposes
/// </summary> /// </summary>
//public void SendRandomData() public void SendRandomData()
//{ {
// NetOutgoingMessage msg = server.CreateMessage(); NetOutgoingMessage msg = server.CreateMessage();
// switch (Rand.Int(5)) switch (Rand.Int(5))
// { {
// case 0: case 0:
// msg.WriteEnum(PacketTypes.NetworkEvent); msg.Write((byte)PacketTypes.NetworkEvent);
// msg.Write(Rand.Int(Enum.GetNames(typeof(NetworkEventType)).Length)); msg.Write((byte)Rand.Int(Enum.GetNames(typeof(NetworkEventType)).Length));
// msg.Write(Rand.Int(MapEntity.mapEntityList.Count)); msg.Write((ushort)Rand.Int(MapEntity.mapEntityList.Count));
// break; break;
// case 1: case 1:
// msg.WriteEnum(PacketTypes.NetworkEvent); msg.Write((byte)PacketTypes.NetworkEvent);
// msg.WriteEnum(NetworkEventType.ComponentUpdate); msg.Write((byte)NetworkEventType.ComponentUpdate);
// msg.Write((int)Item.ItemList[Rand.Int(Item.ItemList.Count)].ID); msg.Write((int)Item.ItemList[Rand.Int(Item.ItemList.Count)].ID);
// msg.Write(Rand.Int(8)); msg.Write(Rand.Int(8));
// break; break;
// case 2: case 2:
// msg.Write((byte)Enum.GetNames(typeof(PacketTypes)).Length); msg.Write((byte)Enum.GetNames(typeof(PacketTypes)).Length);
// break; break;
// case 3: case 3:
// msg.Write((byte)PacketTypes.UpdateNetLobby); msg.Write((byte)PacketTypes.UpdateNetLobby);
// break; break;
// } }
// int bitCount = Rand.Int(100); int bitCount = Rand.Int(100);
// for (int i = 0; i < bitCount; i++) for (int i = 0; i < bitCount; i++)
// { {
// msg.Write(Rand.Int(2) == 0); msg.Write(Rand.Int(2) == 0);
// } }
// SendMessage(msg, (Rand.Int(2) == 0) ? NetDeliveryMethod.ReliableOrdered : NetDeliveryMethod.Unreliable, null); SendMessage(msg, (Rand.Int(2) == 0) ? NetDeliveryMethod.ReliableOrdered : NetDeliveryMethod.Unreliable, null);
//} }
public override void Disconnect() public override void Disconnect()
{ {
@@ -1559,6 +1596,11 @@ namespace Barotrauma.Networking
log.Save(); log.Save();
} }
foreach (Client client in ConnectedClients)
{
if (client.FileStreamSender != null) client.FileStreamSender.Dispose();
}
server.Shutdown("The server has shut down"); server.Shutdown("The server has shut down");
} }
} }
+12 -13
View File
@@ -55,6 +55,11 @@ namespace Barotrauma
get { return modeList; } get { return modeList; }
} }
public GUIListBox PlayerList
{
get { return playerList; }
}
public GUIFrame InfoFrame public GUIFrame InfoFrame
{ {
get { return infoFrame; } get { return infoFrame; }
@@ -505,14 +510,11 @@ namespace Barotrauma
{ {
valueChanged = true; valueChanged = true;
//Submarine sub = (Submarine)obj;
//submarine already loaded var hash = (obj as Submarine).MD5Hash;
//if (Submarine.Loaded != null && sub.FilePath == Submarine.Loaded.FilePath) return true;
//sub.Load(); //hash will be null if opening the sub file failed -> don't select the sub
return hash.Hash != null;
return true;
} }
public void UpdateSubList() public void UpdateSubList()
@@ -657,10 +659,7 @@ namespace Barotrauma
public void ClearPlayers() public void ClearPlayers()
{ {
for (int i = 1; i<playerList.CountChildren; i++) playerList.ClearChildren();
{
playerList.RemoveChild(playerList.children[i]);
}
} }
public override void Update(double deltaTime) public override void Update(double deltaTime)
@@ -948,9 +947,9 @@ namespace Barotrauma
if (sub.MD5Hash.Hash != md5Hash) if (sub.MD5Hash.Hash != md5Hash)
{ {
var requestFileBox = new GUIMessageBox("Submarine not found!", var requestFileBox = new GUIMessageBox("Submarine not found!",
"Your version of the map file ''" + sub.Name + "'' doesn't match the server's version!" "Your version of the map file ''" + sub.Name + "'' doesn't match the server's version! "
+"\nYour file: " + sub.Name + "(MD5 hash : " + sub.MD5Hash.Hash + ")" +"Your file: " + sub.Name + "(MD5 hash: " + sub.MD5Hash.Hash + ") "
+"\nServer's file: " + subName + "(MD5 hash : " + md5Hash + ")\n" +"Server's file: " + subName + "(MD5 hash: " + md5Hash + ")\n "
+"Do you want to download the file from the server host?", new string[] { "Yes", "No" }, 400, 300); +"Do you want to download the file from the server host?", new string[] { "Yes", "No" }, 400, 300);
requestFileBox.Buttons[0].UserData = subName; requestFileBox.Buttons[0].UserData = subName;
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close; requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
Binary file not shown.