Add: ProtocolLib
This commit is contained in:
parent
801bf3b95d
commit
bee08f34e6
2
ProtocolLib/.gitignore
vendored
Normal file
2
ProtocolLib/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
bin
|
||||
obj
|
12
ProtocolLib/PacketIO/IPacketFile.cs
Normal file
12
ProtocolLib/PacketIO/IPacketFile.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace PacketIO;
|
||||
|
||||
public interface IPacketFile : IDisposable
|
||||
{
|
||||
public PacketFileType GetFileType();
|
||||
|
||||
public string GetFileName();
|
||||
|
||||
public long GetFileSize();
|
||||
|
||||
public IEnumerable<IPacketFile> EnumerableFiles();
|
||||
}
|
53
ProtocolLib/PacketIO/PacketDirectory.cs
Normal file
53
ProtocolLib/PacketIO/PacketDirectory.cs
Normal file
@ -0,0 +1,53 @@
|
||||
namespace PacketIO;
|
||||
|
||||
public class PacketDirectory : IPacketFile
|
||||
{
|
||||
private string fileName;
|
||||
private List<IPacketFile> files;
|
||||
|
||||
public PacketDirectory(string fileName, params IPacketFile[] files)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
this.files = new List<IPacketFile>();
|
||||
this.files.AddRange(files);
|
||||
}
|
||||
|
||||
public IEnumerable<IPacketFile> EnumerableFiles()
|
||||
{
|
||||
return this.files.ToList();
|
||||
}
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
public long GetFileSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public PacketFileType GetFileType()
|
||||
{
|
||||
return PacketFileType.Directory;
|
||||
}
|
||||
|
||||
public long AddFile(IPacketFile file)
|
||||
{
|
||||
this.files.Add(file);
|
||||
return this.files.LongCount();
|
||||
}
|
||||
|
||||
public bool RemoveFile(IPacketFile file)
|
||||
{
|
||||
return this.files.Remove(file);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (IPacketFile file in this.EnumerableFiles())
|
||||
{
|
||||
file.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
60
ProtocolLib/PacketIO/PacketFile.cs
Normal file
60
ProtocolLib/PacketIO/PacketFile.cs
Normal file
@ -0,0 +1,60 @@
|
||||
namespace PacketIO;
|
||||
|
||||
public class PacketFile : IPacketFile
|
||||
{
|
||||
private string fileName;
|
||||
private Stream stream;
|
||||
|
||||
public PacketFile(string fileName)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
this.stream = new MemoryStream();
|
||||
}
|
||||
|
||||
public PacketFile(string fileName, Stream stream)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public IEnumerable<IPacketFile> EnumerableFiles()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
public long GetFileSize()
|
||||
{
|
||||
return this.stream.Length;
|
||||
}
|
||||
|
||||
public PacketFileType GetFileType()
|
||||
{
|
||||
return PacketFileType.File;
|
||||
}
|
||||
|
||||
public async ValueTask<int> ReadAsync(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int read = await this.stream.ReadAsync(buffer, offset, count).ConfigureAwait(false);
|
||||
return read;
|
||||
}
|
||||
|
||||
public async ValueTask WriteAsync(byte[] buffer, int offset, int count)
|
||||
{
|
||||
await this.stream.WriteAsync(buffer, offset, count).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public void Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
this.stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.stream.Dispose();
|
||||
}
|
||||
}
|
11
ProtocolLib/PacketIO/PacketFileType.cs
Normal file
11
ProtocolLib/PacketIO/PacketFileType.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace PacketIO;
|
||||
|
||||
[Flags]
|
||||
public enum PacketFileType : byte
|
||||
{
|
||||
None = 0,
|
||||
|
||||
File = 0x02 << 0,
|
||||
|
||||
Directory = 0x02 << 1,
|
||||
}
|
150
ProtocolLib/PacketIO/TreePacketFile.cs
Normal file
150
ProtocolLib/PacketIO/TreePacketFile.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System.Text;
|
||||
|
||||
namespace PacketIO;
|
||||
|
||||
public class TreePacketFile
|
||||
{
|
||||
public static async ValueTask WriteTreeFiles(Stream stream, params IPacketFile[] files)
|
||||
{
|
||||
foreach (IPacketFile file in files)
|
||||
{
|
||||
await WriteTreeFile(stream, file).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask WriteTreeFile(Stream stream, IPacketFile file)
|
||||
{
|
||||
byte fileType = (byte) file.GetFileType();
|
||||
string fileName = file.GetFileName();
|
||||
long fileSize = file.GetFileSize();
|
||||
|
||||
byte[] fileNameBuffer = Encoding.UTF8.GetBytes(fileName);
|
||||
|
||||
byte[] buffer = new byte[sizeof(byte) + sizeof(int) + sizeof(long) + fileNameBuffer.Length];
|
||||
buffer[0] = fileType;
|
||||
Array.Copy(BitConverter.GetBytes(fileNameBuffer.Length), 0, buffer, 1, sizeof(int));
|
||||
Array.Copy(BitConverter.GetBytes(fileSize), 0, buffer, 5, sizeof(long));
|
||||
Array.Copy(fileNameBuffer, 0, buffer, 13, fileNameBuffer.Length);
|
||||
|
||||
await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
|
||||
switch (file.GetFileType())
|
||||
{
|
||||
case PacketFileType.Directory:
|
||||
{
|
||||
long fileCount = file.EnumerableFiles().LongCount();
|
||||
buffer = BitConverter.GetBytes(fileCount);
|
||||
await stream.WriteAsync(buffer, 0, sizeof(long));
|
||||
|
||||
await WriteTreeFiles(stream, file.EnumerableFiles().ToArray()).ConfigureAwait(false);
|
||||
break;
|
||||
}
|
||||
case PacketFileType.File:
|
||||
{
|
||||
int c;
|
||||
buffer = new byte[8192];
|
||||
PacketFile packetFile = (PacketFile) file;
|
||||
packetFile.Seek(0, SeekOrigin.Begin);
|
||||
do
|
||||
{
|
||||
c = await packetFile.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
|
||||
await stream.WriteAsync(buffer, 0, c).ConfigureAwait(false);
|
||||
} while (c > 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static async ValueTask<IEnumerable<IPacketFile>> ReadTreeFiles(Stream stream)
|
||||
{
|
||||
List<IPacketFile> files = new List<IPacketFile>();
|
||||
|
||||
IPacketFile? file = null;
|
||||
do
|
||||
{
|
||||
file = await ReadTreeFile(stream).ConfigureAwait(false);
|
||||
if (file is object)
|
||||
{
|
||||
files.Add(file);
|
||||
}
|
||||
} while (file is object);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public static async ValueTask<IPacketFile?> ReadTreeFile(Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[sizeof(byte) + sizeof(int) + sizeof(long)];
|
||||
int c = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (c <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
PacketFileType fileType = (PacketFileType) buffer[0];
|
||||
int fileNameBufferSize = BitConverter.ToInt32(buffer, 1);
|
||||
long fileSize = BitConverter.ToInt64(buffer, 5);
|
||||
|
||||
buffer = new byte[fileNameBufferSize];
|
||||
c = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (c <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string fileName = Encoding.UTF8.GetString(buffer);
|
||||
|
||||
switch (fileType)
|
||||
{
|
||||
case PacketFileType.Directory:
|
||||
{
|
||||
buffer = new byte[sizeof(long)];
|
||||
c = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
if (c <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
long fileCount = BitConverter.ToInt64(buffer, 0);
|
||||
|
||||
PacketDirectory directory = new PacketDirectory(fileName);
|
||||
for (long i = 0 ; i < fileCount ; i++)
|
||||
{
|
||||
IPacketFile? file = await ReadTreeFile(stream).ConfigureAwait(false);
|
||||
if (file is null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
directory.AddFile(file);
|
||||
}
|
||||
|
||||
return directory;
|
||||
}
|
||||
case PacketFileType.File:
|
||||
{
|
||||
PacketFile file = new PacketFile(fileName);
|
||||
|
||||
buffer = new byte[8192];
|
||||
long remainedSize = fileSize;
|
||||
long readed = 0;
|
||||
do
|
||||
{
|
||||
int leftSize = (int) Math.Min(buffer.Length, fileSize - readed);
|
||||
c = await stream.ReadAsync(buffer, 0, leftSize).ConfigureAwait(false);
|
||||
await file.WriteAsync(buffer, 0, c).ConfigureAwait(false);
|
||||
remainedSize -= c;
|
||||
readed += c;
|
||||
} while (remainedSize > 0);
|
||||
|
||||
file.Seek(0, SeekOrigin.Begin);
|
||||
return file;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
71
ProtocolLib/Program.cs
Normal file
71
ProtocolLib/Program.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using PacketIO;
|
||||
|
||||
namespace ProtocolLib;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Make tree file.
|
||||
using (FileStream fs = new FileStream("tree.bin", FileMode.OpenOrCreate))
|
||||
{
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo("i");
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
|
||||
{
|
||||
using (PacketFile file = new PacketFile(fileInfo.Name, fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)))
|
||||
{
|
||||
TreePacketFile.WriteTreeFile(fs, file).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get files from tree file.
|
||||
using (FileStream fs = new FileStream("tree.bin", FileMode.OpenOrCreate))
|
||||
{
|
||||
IEnumerable<IPacketFile> files = TreePacketFile.ReadTreeFiles(fs).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
foreach (IPacketFile ifile in files)
|
||||
{
|
||||
PacketFile file = (PacketFile) ifile;
|
||||
using (FileStream outStream = new FileStream(file.GetFileName(), FileMode.OpenOrCreate))
|
||||
{
|
||||
byte[] buffer = new byte[8192];
|
||||
int c;
|
||||
while ((c = file.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false).GetAwaiter().GetResult()) > 0)
|
||||
{
|
||||
outStream.Write(buffer, 0, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Paket test.
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
PacketStream packetStream = new PacketStream(ms);
|
||||
|
||||
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("Hello, World!!!");
|
||||
foreach (Packet packet in PacketFactory.CreatePacket(DataOperator.Connect, DataType.Binary, buffer))
|
||||
{
|
||||
packetStream.WritePacket(packet).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Packet? packet1 = null;
|
||||
do
|
||||
{
|
||||
packet1 = packetStream.ReadPacket().ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
if (packet1 is object)
|
||||
{
|
||||
Console.Write($"{System.Text.Encoding.UTF8.GetString(packet1.Payload)}");
|
||||
}
|
||||
} while (packet1 is object);
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
10
ProtocolLib/ProtocolLib.csproj
Normal file
10
ProtocolLib/ProtocolLib.csproj
Normal file
@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
15
ProtocolLib/ProtocolLib/ByteConverter.cs
Normal file
15
ProtocolLib/ProtocolLib/ByteConverter.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
internal static class ByteConverter
|
||||
{
|
||||
public static byte[] Convert(bool value)
|
||||
{
|
||||
byte[] buffer = BitConverter.GetBytes(value);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse(buffer);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
12
ProtocolLib/ProtocolLib/DataOperator.cs
Normal file
12
ProtocolLib/ProtocolLib/DataOperator.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
public enum DataOperator : byte
|
||||
{
|
||||
None = 0x00,
|
||||
|
||||
Connect = 0x02 << 0,
|
||||
|
||||
Request = 0x02 << 1,
|
||||
|
||||
Response = 0x02 << 2,
|
||||
}
|
8
ProtocolLib/ProtocolLib/DataType.cs
Normal file
8
ProtocolLib/ProtocolLib/DataType.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
public enum DataType : byte
|
||||
{
|
||||
None = 0x00,
|
||||
|
||||
Binary = 0x02 << 0,
|
||||
}
|
79
ProtocolLib/ProtocolLib/PackeFactory.cs
Normal file
79
ProtocolLib/ProtocolLib/PackeFactory.cs
Normal file
@ -0,0 +1,79 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
public static class PacketFactory
|
||||
{
|
||||
public static readonly int MAX_PAYLOAD_SIZE = 810;
|
||||
|
||||
/// <summary>
|
||||
/// 指定されたバイト配列からパケットを作成する。
|
||||
/// </summary>
|
||||
/// <param name="dataOperator">オペレータの種類</param>
|
||||
/// <param name="dataType">データの種類</param>
|
||||
/// <param name="data">バイトデータ</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Packet> CreatePacket(DataOperator dataOperator, DataType dataType, byte[] data)
|
||||
{
|
||||
List<Packet> packets = new List<Packet>();
|
||||
|
||||
long packetNumber = 0;
|
||||
int remainedSize = data.Length;
|
||||
do
|
||||
{
|
||||
int packSize = Math.Min(MAX_PAYLOAD_SIZE, remainedSize);
|
||||
byte[] payload = data.AsSpan(data.Length - remainedSize, packSize).ToArray();
|
||||
|
||||
Packet packet = new Packet()
|
||||
{
|
||||
Operator = dataOperator,
|
||||
Type = dataType,
|
||||
PacketNumber = packetNumber,
|
||||
PayloadSize = packSize,
|
||||
Payload = payload,
|
||||
};
|
||||
|
||||
packets.Add(packet);
|
||||
remainedSize -= packSize;
|
||||
} while (remainedSize > 0);
|
||||
|
||||
return packets;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定されたバイト配列からパケットを作成する。
|
||||
/// </summary>
|
||||
/// <param name="dataOperator">オペレータの種類</param>
|
||||
/// <param name="dataType">データの種類</param>
|
||||
/// <param name="data">バイトデータ</param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<Packet> CreatePacket(DataOperator dataOperator, DataType dataType, Stream stream)
|
||||
{
|
||||
List<Packet> packets = new List<Packet>();
|
||||
|
||||
long packetNumber = 0;
|
||||
long remainedSize = stream.Length;
|
||||
do
|
||||
{
|
||||
int packSize = (int) Math.Min(MAX_PAYLOAD_SIZE, remainedSize);
|
||||
byte[] payload = new byte[packSize];
|
||||
int c = stream.Read(payload, 0, payload.Length);
|
||||
if (c <= 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
Packet packet = new Packet()
|
||||
{
|
||||
Operator = dataOperator,
|
||||
Type = dataType,
|
||||
PacketNumber = packetNumber,
|
||||
PayloadSize = packSize,
|
||||
Payload = payload,
|
||||
};
|
||||
|
||||
packets.Add(packet);
|
||||
remainedSize -= packSize;
|
||||
} while (remainedSize > 0);
|
||||
|
||||
return packets;
|
||||
}
|
||||
}
|
14
ProtocolLib/ProtocolLib/Packet.cs
Normal file
14
ProtocolLib/ProtocolLib/Packet.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
public class Packet
|
||||
{
|
||||
public DataOperator Operator { get; set; }
|
||||
|
||||
public DataType Type { get; set; }
|
||||
|
||||
public long PacketNumber { get; set;}
|
||||
|
||||
public int PayloadSize { get; set; }
|
||||
|
||||
public byte[] Payload { get; set; }
|
||||
}
|
70
ProtocolLib/ProtocolLib/PacketStream.cs
Normal file
70
ProtocolLib/ProtocolLib/PacketStream.cs
Normal file
@ -0,0 +1,70 @@
|
||||
namespace ProtocolLib;
|
||||
|
||||
public class PacketStream
|
||||
{
|
||||
private Stream stream;
|
||||
|
||||
public PacketStream(Stream stream)
|
||||
{
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public async ValueTask WritePacket(Packet packet)
|
||||
{
|
||||
byte[] buffer = this.PacketToBytes(packet);
|
||||
await this.stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask<Packet?> ReadPacket()
|
||||
{
|
||||
byte[] buffer = new byte[2 + sizeof(long) + sizeof(int)];
|
||||
int r = await this.stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (r <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DataOperator dataOperator = (DataOperator) buffer[0];
|
||||
DataType dataType = (DataType) buffer[1];
|
||||
long packetNumber = BitConverter.ToInt64(buffer, 2);
|
||||
int payloadSize = BitConverter.ToInt32(buffer, 10);
|
||||
if (payloadSize < 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
buffer = new byte[payloadSize];
|
||||
r = await this.stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (r <= 0)
|
||||
{
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
Packet packet = new Packet()
|
||||
{
|
||||
Operator = dataOperator,
|
||||
Type = dataType,
|
||||
PacketNumber = packetNumber,
|
||||
PayloadSize = payloadSize,
|
||||
Payload = buffer,
|
||||
};
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
private byte[] PacketToBytes(Packet packet)
|
||||
{
|
||||
byte[] buffer = new byte[2 + sizeof(long) + sizeof(int) + packet.PayloadSize];
|
||||
|
||||
buffer[0] = (byte) packet.Operator;
|
||||
buffer[1] = (byte) packet.Type;
|
||||
|
||||
byte[] temp = BitConverter.GetBytes(packet.PacketNumber);
|
||||
Array.Copy(temp, 0, buffer, 2, temp.Length);
|
||||
temp = BitConverter.GetBytes(packet.PayloadSize);
|
||||
Array.Copy(temp, 0, buffer, 10, temp.Length);
|
||||
Array.Copy(packet.Payload, 0, buffer, 14, packet.PayloadSize);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user