Add ability to share server file
This commit is contained in:
@ -8,6 +8,7 @@ namespace RageCoop.Client
|
||||
{
|
||||
internal static class DownloadManager
|
||||
{
|
||||
public static event EventHandler<string> DownloadCompleted;
|
||||
static DownloadManager()
|
||||
{
|
||||
Networking.RequestHandlers.Add(PacketType.FileTransferRequest, (data) =>
|
||||
@ -64,23 +65,26 @@ namespace RageCoop.Client
|
||||
private static readonly List<string> _zips = new List<string>();
|
||||
public static bool AddFile(int id, string name, long length)
|
||||
{
|
||||
Main.Logger.Debug($"Downloading file to {ResourceFolder}\\{name} , id:{id}");
|
||||
if (!Directory.Exists(ResourceFolder))
|
||||
var path = $"{ResourceFolder}\\{name}";
|
||||
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))
|
||||
{
|
||||
Main.Logger.Debug($"File already exists! canceling download:{name}");
|
||||
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, name));
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!name.EndsWith(".zip"))
|
||||
{
|
||||
Main.Logger.Error($"File download blocked! [{name}]");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
lock (InProgressDownloads)
|
||||
{
|
||||
InProgressDownloads.Add(id, new DownloadFile()
|
||||
@ -88,7 +92,7 @@ namespace RageCoop.Client
|
||||
FileID = id,
|
||||
FileName = name,
|
||||
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;
|
||||
@ -150,6 +154,7 @@ namespace RageCoop.Client
|
||||
_zips.Add(f.FileName);
|
||||
}
|
||||
Main.Logger.Info($"Download finished:{f.FileName}");
|
||||
DownloadCompleted?.Invoke(null, Path.Combine(ResourceFolder, f.FileName));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4,6 +4,7 @@ using RageCoop.Core;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RageCoop.Client
|
||||
{
|
||||
@ -148,6 +149,37 @@ namespace RageCoop.Client
|
||||
return _publicKeyReceived.WaitOne(timeout);
|
||||
}
|
||||
#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(id);
|
||||
handler(message.ReadBytes(len)).Pack(response);
|
||||
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered);
|
||||
Client.SendMessage(response, NetDeliveryMethod.ReliableOrdered,(int)ConnectionChannel.RequestResponse);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -279,6 +279,34 @@ namespace RageCoop.Client.Scripting
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
try
|
||||
{
|
||||
s.CurrentResource=d;
|
||||
s.OnStart();
|
||||
}
|
||||
catch(Exception ex)
|
||||
@ -118,6 +119,7 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
var r = new ClientResource()
|
||||
{
|
||||
Logger = Main.Logger,
|
||||
Scripts = new List<ClientScript>(),
|
||||
Name=Path.GetFileNameWithoutExtension(file.Name),
|
||||
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
||||
|
@ -15,7 +15,6 @@ namespace RageCoop.Client
|
||||
{
|
||||
internal class EntityPool
|
||||
{
|
||||
private static bool _trafficSpawning=true;
|
||||
public static object PedsLock = new object();
|
||||
private static Dictionary<int, SyncedPed> ID_Peds = new Dictionary<int, SyncedPed>();
|
||||
public static int CharactersCount { get { return ID_Peds.Count; } }
|
||||
|
@ -7,7 +7,7 @@ using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
@ -135,10 +135,34 @@ namespace RageCoop.Server.Scripting
|
||||
public class API
|
||||
{
|
||||
internal readonly Server Server;
|
||||
internal readonly Dictionary<string, Func<Stream>> RegisteredFiles=new Dictionary<string, Func<System.IO.Stream>>();
|
||||
internal API(Server server)
|
||||
{
|
||||
Server=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>
|
||||
/// Server side events
|
||||
@ -197,8 +221,24 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send CleanUpWorld to all players to delete all objects created by the server
|
||||
/// Register a file to be shared with clients
|
||||
/// </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>
|
||||
/// 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<string, Client> ClientsByName = new();
|
||||
internal Client _hostClient;
|
||||
internal string CurrentWeather;
|
||||
|
||||
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||
private Resources Resources;
|
||||
@ -58,7 +57,7 @@ namespace RageCoop.Server
|
||||
private Thread _announceThread;
|
||||
private Worker _worker;
|
||||
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";
|
||||
/// <summary>
|
||||
/// Instantiate a server.
|
||||
@ -239,17 +238,23 @@ namespace RageCoop.Server
|
||||
}
|
||||
private void Listen()
|
||||
{
|
||||
NetIncomingMessage msg=null;
|
||||
Logger?.Info("Listening for clients");
|
||||
while (!_stopping)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessMessage(MainNetServer.WaitMessage(200));
|
||||
msg=MainNetServer.WaitMessage(200);
|
||||
ProcessMessage(msg);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Logger?.Error("Error processing message");
|
||||
Logger?.Error(ex);
|
||||
if (msg!=null)
|
||||
{
|
||||
DisconnectAndLog(msg.SenderConnection, PacketType.Unknown, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger?.Info("Server is shutting down!");
|
||||
@ -342,7 +347,7 @@ namespace RageCoop.Server
|
||||
var response=MainNetServer.CreateMessage();
|
||||
response.Write((byte)PacketType.Response);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
@ -866,22 +871,25 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
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();
|
||||
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
fs.Seek(0, SeekOrigin.Begin);
|
||||
var total = fs.Length;
|
||||
id = id ==default? NewFileID(): id ;
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var total = stream.Length;
|
||||
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferRequest()
|
||||
{
|
||||
FileLength= total,
|
||||
Name=name,
|
||||
ID=id,
|
||||
},ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
|
||||
}, ConnectionChannel.File)?.Response!=FileResponse.NeedToDownload)
|
||||
{
|
||||
Logger?.Info($"Skipping file transfer \"{name}\" to {client.Username}");
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
return;
|
||||
}
|
||||
Logger?.Debug($"Initiating file transfer:{name}, {total}");
|
||||
@ -897,7 +905,7 @@ namespace RageCoop.Server
|
||||
{
|
||||
// 4 KB chunk
|
||||
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==0) { break; }
|
||||
@ -911,23 +919,23 @@ namespace RageCoop.Server
|
||||
FileChunk=chunk,
|
||||
},
|
||||
client, ConnectionChannel.File, NetDeliveryMethod.ReliableOrdered);
|
||||
transfer.Progress=read/fs.Length;
|
||||
if (updateCallback!=null) { updateCallback(transfer.Progress);}
|
||||
transfer.Progress=read/stream.Length;
|
||||
if (updateCallback!=null) { updateCallback(transfer.Progress); }
|
||||
|
||||
} while (thisRead>0);
|
||||
if(GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
|
||||
if (GetResponse<Packets.FileTransferResponse>(client, new Packets.FileTransferComplete()
|
||||
{
|
||||
ID= id,
|
||||
},ConnectionChannel.File)?.Response!=FileResponse.Completed)
|
||||
}, ConnectionChannel.File)?.Response!=FileResponse.Completed)
|
||||
{
|
||||
Logger.Warning($"File trasfer to {client.Username} failed: "+name);
|
||||
}
|
||||
fs.Close();
|
||||
fs.Dispose();
|
||||
}
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
Logger?.Debug($"All file chunks sent:{name}");
|
||||
InProgressFileTransfers.Remove(id);
|
||||
}
|
||||
private int NewFileID()
|
||||
internal int NewFileID()
|
||||
{
|
||||
int ID = 0;
|
||||
while ((ID==0)
|
||||
|
Reference in New Issue
Block a user