Add ability to share server file
This commit is contained in:
@ -8,6 +8,7 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
internal static class DownloadManager
|
internal static class DownloadManager
|
||||||
{
|
{
|
||||||
|
public static event EventHandler<string> DownloadCompleted;
|
||||||
static DownloadManager()
|
static DownloadManager()
|
||||||
{
|
{
|
||||||
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
|
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
|
||||||
@ -64,23 +65,26 @@ namespace RageCoop.Client
|
|||||||
private static readonly List<string> _zips = new List<string>();
|
private static readonly List<string> _zips = new List<string>();
|
||||||
public static bool AddFile(int id, string name, long length)
|
public static bool AddFile(int id, string name, long length)
|
||||||
{
|
{
|
||||||
Main.Logger.Debug($"Downloading file to {ResourceFolder}\\{name} , id:{id}");
|
var path = $"{ResourceFolder}\\{name}";
|
||||||
if (!Directory.Exists(ResourceFolder))
|
Main.Logger.Debug($"Downloading file to {path} , id:{id}");
|
||||||
|
if (!Directory.Exists(Directory.GetParent(path).FullName))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(ResourceFolder);
|
Directory.CreateDirectory(Directory.GetParent(path).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FileAlreadyExists(ResourceFolder, name, length))
|
if (FileAlreadyExists(ResourceFolder, name, length))
|
||||||
{
|
{
|
||||||
Main.Logger.Debug($"File already exists! canceling download:{name}");
|
Main.Logger.Debug($"File already exists! canceling download:{name}");
|
||||||
|
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if (!name.EndsWith(".zip"))
|
if (!name.EndsWith(".zip"))
|
||||||
{
|
{
|
||||||
Main.Logger.Error($"File download blocked! [{name}]");
|
Main.Logger.Error($"File download blocked! [{name}]");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
lock (InProgressDownloads)
|
lock (InProgressDownloads)
|
||||||
{
|
{
|
||||||
InProgressDownloads.Add(id, new DownloadFile()
|
InProgressDownloads.Add(id, new DownloadFile()
|
||||||
@ -88,7 +92,7 @@ namespace RageCoop.Client
|
|||||||
FileID = id,
|
FileID = id,
|
||||||
FileName = name,
|
FileName = name,
|
||||||
FileLength = length,
|
FileLength = length,
|
||||||
Stream = new FileStream($"{ResourceFolder}\\{name}", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
Stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -150,6 +154,7 @@ namespace RageCoop.Client
|
|||||||
_zips.Add(f.FileName);
|
_zips.Add(f.FileName);
|
||||||
}
|
}
|
||||||
Main.Logger.Info($"Download finished:{f.FileName}");
|
Main.Logger.Info($"Download finished:{f.FileName}");
|
||||||
|
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, f.FileName));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ using RageCoop.Core;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace RageCoop.Client
|
namespace RageCoop.Client
|
||||||
{
|
{
|
||||||
@ -148,6 +149,37 @@ namespace RageCoop.Client
|
|||||||
return _publicKeyReceived.WaitOne(timeout);
|
return _publicKeyReceived.WaitOne(timeout);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
internal static void GetResponse<T>(Packet request, Action<T> callback, ConnectionChannel channel = ConnectionChannel.RequestResponse) where T : Packet, new()
|
||||||
|
{
|
||||||
|
var received = new AutoResetEvent(false);
|
||||||
|
var id = NewRequestID();
|
||||||
|
PendingResponses.Add(id, (type, p) =>
|
||||||
|
{
|
||||||
|
var result = new T();
|
||||||
|
result.Unpack(p);
|
||||||
|
callback(result);
|
||||||
|
});
|
||||||
|
var msg = Client.CreateMessage();
|
||||||
|
msg.Write((byte)PacketType.Request);
|
||||||
|
msg.Write(id);
|
||||||
|
request.Pack(msg);
|
||||||
|
Client.SendMessage(msg, NetDeliveryMethod.ReliableOrdered, (int)channel);
|
||||||
|
}
|
||||||
|
private static int NewRequestID()
|
||||||
|
{
|
||||||
|
int ID = 0;
|
||||||
|
while ((ID==0)
|
||||||
|
|| PendingResponses.ContainsKey(ID))
|
||||||
|
{
|
||||||
|
byte[] rngBytes = new byte[4];
|
||||||
|
|
||||||
|
RandomNumberGenerator.Create().GetBytes(rngBytes);
|
||||||
|
|
||||||
|
// Convert the bytes into an integer
|
||||||
|
ID = BitConverter.ToInt32(rngBytes, 0);
|
||||||
|
}
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ namespace RageCoop.Client
|
|||||||
response.Write((byte)PacketType.Response);
|
response.Write((byte)PacketType.Response);
|
||||||
response.Write(id);
|
response.Write(id);
|
||||||
handler(message.ReadBytes(len)).Pack(response);
|
handler(message.ReadBytes(len)).Pack(response);
|
||||||
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered);
|
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered,(int)ConnectionChannel.RequestResponse);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,34 @@ namespace RageCoop.Client.Scripting
|
|||||||
handlers.Add(handler);
|
handlers.Add(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static void RequestSharedFile(string name,Action<string> callback)
|
||||||
|
{
|
||||||
|
EventHandler<string> handler = (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.EndsWith(name))
|
||||||
|
{
|
||||||
|
callback(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DownloadManager.DownloadCompleted+=handler;
|
||||||
|
Networking.GetResponse<Packets.FileTransferResponse>(new Packets.FileTransferRequest()
|
||||||
|
{
|
||||||
|
Name=name,
|
||||||
|
},
|
||||||
|
(p) =>
|
||||||
|
{
|
||||||
|
if(p.Response != FileResponse.Loaded)
|
||||||
|
{
|
||||||
|
DownloadManager.DownloadCompleted-=handler;
|
||||||
|
throw new ArgumentException("Requested file was not found on the server: "+name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
s.CurrentResource=d;
|
||||||
s.OnStart();
|
s.OnStart();
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
@ -118,6 +119,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
var r = new ClientResource()
|
var r = new ClientResource()
|
||||||
{
|
{
|
||||||
|
Logger = Main.Logger,
|
||||||
Scripts = new List<ClientScript>(),
|
Scripts = new List<ClientScript>(),
|
||||||
Name=Path.GetFileNameWithoutExtension(file.Name),
|
Name=Path.GetFileNameWithoutExtension(file.Name),
|
||||||
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
||||||
|
@ -15,7 +15,6 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
internal class EntityPool
|
internal class EntityPool
|
||||||
{
|
{
|
||||||
private static bool _trafficSpawning=true;
|
|
||||||
public static object PedsLock = new object();
|
public static object PedsLock = new object();
|
||||||
private static Dictionary<int, SyncedPed> ID_Peds = new Dictionary<int, SyncedPed>();
|
private static Dictionary<int, SyncedPed> ID_Peds = new Dictionary<int, SyncedPed>();
|
||||||
public static int CharactersCount { get { return ID_Peds.Count; } }
|
public static int CharactersCount { get { return ID_Peds.Count; } }
|
||||||
|
@ -7,7 +7,7 @@ using Lidgren.Network;
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Net;
|
using System.IO;
|
||||||
|
|
||||||
namespace RageCoop.Server.Scripting
|
namespace RageCoop.Server.Scripting
|
||||||
{
|
{
|
||||||
@ -135,10 +135,34 @@ namespace RageCoop.Server.Scripting
|
|||||||
public class API
|
public class API
|
||||||
{
|
{
|
||||||
internal readonly Server Server;
|
internal readonly Server Server;
|
||||||
|
internal readonly Dictionary<string, Func<Stream>> RegisteredFiles=new Dictionary<string, Func<System.IO.Stream>>();
|
||||||
internal API(Server server)
|
internal API(Server server)
|
||||||
{
|
{
|
||||||
Server=server;
|
Server=server;
|
||||||
Events=new(server);
|
Events=new(server);
|
||||||
|
Server.RequestHandlers.Add(PacketType.FileTransferRequest, (data,client) =>
|
||||||
|
{
|
||||||
|
var p = new Packets.FileTransferRequest();
|
||||||
|
p.Unpack(data);
|
||||||
|
var id=Server.NewFileID();
|
||||||
|
if(RegisteredFiles.TryGetValue(p.Name,out var s))
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
Server.SendFile(s(), p.Name, client,id);
|
||||||
|
});
|
||||||
|
return new Packets.FileTransferResponse()
|
||||||
|
{
|
||||||
|
ID=id,
|
||||||
|
Response=FileResponse.Loaded
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new Packets.FileTransferResponse()
|
||||||
|
{
|
||||||
|
ID=id,
|
||||||
|
Response=FileResponse.LoadFailed
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Server side events
|
/// Server side events
|
||||||
@ -197,8 +221,24 @@ namespace RageCoop.Server.Scripting
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send CleanUpWorld to all players to delete all objects created by the server
|
/// Register a file to be shared with clients
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="name">name of this file</param>
|
||||||
|
/// <param name="path">path to this file</param>
|
||||||
|
public void RegisterSharedFile(string name,string path)
|
||||||
|
{
|
||||||
|
RegisteredFiles.Add(name, () => { return File.OpenRead(path); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register a file to be shared with clients
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">name of this file</param>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
public void RegisterSharedFile(string name, ResourceFile file)
|
||||||
|
{
|
||||||
|
RegisteredFiles.Add(name, file.GetStream);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a new command chat command (Example: "/test")
|
/// Register a new command chat command (Example: "/test")
|
||||||
|
@ -46,7 +46,6 @@ namespace RageCoop.Server
|
|||||||
internal readonly Dictionary<long,Client> Clients = new();
|
internal readonly Dictionary<long,Client> Clients = new();
|
||||||
internal readonly Dictionary<string, Client> ClientsByName = new();
|
internal readonly Dictionary<string, Client> ClientsByName = new();
|
||||||
internal Client _hostClient;
|
internal Client _hostClient;
|
||||||
internal string CurrentWeather;
|
|
||||||
|
|
||||||
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||||
private Resources Resources;
|
private Resources Resources;
|
||||||
@ -58,7 +57,7 @@ namespace RageCoop.Server
|
|||||||
private Thread _announceThread;
|
private Thread _announceThread;
|
||||||
private Worker _worker;
|
private Worker _worker;
|
||||||
private Dictionary<int,Action<PacketType,byte[]>> PendingResponses=new();
|
private Dictionary<int,Action<PacketType,byte[]>> PendingResponses=new();
|
||||||
private Dictionary<PacketType, Func<byte[],Packet>> RequestHandlers=new();
|
internal Dictionary<PacketType, Func<byte[],Client,Packet>> RequestHandlers=new();
|
||||||
private readonly string _compatibleVersion = "V0_5";
|
private readonly string _compatibleVersion = "V0_5";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiate a server.
|
/// Instantiate a server.
|
||||||
@ -239,17 +238,23 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
private void Listen()
|
private void Listen()
|
||||||
{
|
{
|
||||||
|
NetIncomingMessage msg=null;
|
||||||
Logger?.Info("Listening for clients");
|
Logger?.Info("Listening for clients");
|
||||||
while (!_stopping)
|
while (!_stopping)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProcessMessage(MainNetServer.WaitMessage(200));
|
msg=MainNetServer.WaitMessage(200);
|
||||||
|
ProcessMessage(msg);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
Logger?.Error("Error processing message");
|
Logger?.Error("Error processing message");
|
||||||
Logger?.Error(ex);
|
Logger?.Error(ex);
|
||||||
|
if (msg!=null)
|
||||||
|
{
|
||||||
|
DisconnectAndLog(msg.SenderConnection, PacketType.Unknown, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger?.Info("Server is shutting down!");
|
Logger?.Info("Server is shutting down!");
|
||||||
@ -342,7 +347,7 @@ namespace RageCoop.Server
|
|||||||
var response=MainNetServer.CreateMessage();
|
var response=MainNetServer.CreateMessage();
|
||||||
response.Write((byte)PacketType.Response);
|
response.Write((byte)PacketType.Response);
|
||||||
response.Write(id);
|
response.Write(id);
|
||||||
handler(message.ReadBytes(message.ReadInt32())).Pack(response);
|
handler(message.ReadBytes(message.ReadInt32()),sender).Pack(response);
|
||||||
MainNetServer.SendMessage(response,message.SenderConnection,NetDeliveryMethod.ReliableOrdered);
|
MainNetServer.SendMessage(response,message.SenderConnection,NetDeliveryMethod.ReliableOrdered);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -866,22 +871,25 @@ namespace RageCoop.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
internal void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
||||||
|
{
|
||||||
|
SendFile(File.OpenRead(path), name,client,NewFileID(),updateCallback);
|
||||||
|
}
|
||||||
|
internal void SendFile(Stream stream, string name, Client client,int id=default, Action<float> updateCallback = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
int id = NewFileID();
|
id = id ==default? NewFileID(): id ;
|
||||||
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
fs.Seek(0, SeekOrigin.Begin);
|
var total = stream.Length;
|
||||||
var total = fs.Length;
|
|
||||||
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
|
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
|
||||||
{
|
{
|
||||||
FileLength= total,
|
FileLength= total,
|
||||||
Name=name,
|
Name=name,
|
||||||
ID=id,
|
ID=id,
|
||||||
},ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
|
}, ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
|
||||||
{
|
{
|
||||||
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
|
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
|
||||||
fs.Close();
|
stream.Close();
|
||||||
fs.Dispose();
|
stream.Dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
||||||
@ -897,7 +905,7 @@ namespace RageCoop.Server
|
|||||||
{
|
{
|
||||||
// 4 KB chunk
|
// 4 KB chunk
|
||||||
byte[] chunk = new byte[4096];
|
byte[] chunk = new byte[4096];
|
||||||
read += thisRead=fs.Read(chunk, 0, 4096);
|
read += thisRead=stream.Read(chunk, 0, 4096);
|
||||||
if (thisRead!=chunk.Length)
|
if (thisRead!=chunk.Length)
|
||||||
{
|
{
|
||||||
if (thisRead==0) { break; }
|
if (thisRead==0) { break; }
|
||||||
@ -911,23 +919,23 @@ namespace RageCoop.Server
|
|||||||
FileChunk=chunk,
|
FileChunk=chunk,
|
||||||
},
|
},
|
||||||
client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered);
|
client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered);
|
||||||
transfer.Progress=read/fs.Length;
|
transfer.Progress=read/stream.Length;
|
||||||
if (updateCallback!=null) { updateCallback(transfer.Progress);}
|
if (updateCallback!=null) { updateCallback(transfer.Progress); }
|
||||||
|
|
||||||
} while (thisRead>0);
|
} while (thisRead>0);
|
||||||
if(GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
|
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
|
||||||
{
|
{
|
||||||
ID= id,
|
ID= id,
|
||||||
},ConnectionChannel.File)?.Response!=FileResponse.Completed)
|
}, ConnectionChannel.File)?.Response!=FileResponse.Completed)
|
||||||
{
|
{
|
||||||
Logger.Warning($"File trasfer to {client.Username} failed: "+name);
|
Logger.Warning($"File trasfer to {client.Username} failed: "+name);
|
||||||
}
|
}
|
||||||
fs.Close();
|
stream.Close();
|
||||||
fs.Dispose();
|
stream.Dispose();
|
||||||
Logger?.Debug($"All file chunks sent:{name}");
|
Logger?.Debug($"All file chunks sent:{name}");
|
||||||
InProgressFileTransfers.Remove(id);
|
InProgressFileTransfers.Remove(id);
|
||||||
}
|
}
|
||||||
private int NewFileID()
|
internal int NewFileID()
|
||||||
{
|
{
|
||||||
int ID = 0;
|
int ID = 0;
|
||||||
while ((ID==0)
|
while ((ID==0)
|
||||||
|
Reference in New Issue
Block a user