diff --git a/Hamakaze/Hamakaze.csproj b/Hamakaze/Hamakaze.csproj
deleted file mode 100644
index f208d30..0000000
--- a/Hamakaze/Hamakaze.csproj
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- net5.0
-
-
-
diff --git a/Hamakaze/Headers/HttpAcceptEncodingHeader.cs b/Hamakaze/Headers/HttpAcceptEncodingHeader.cs
deleted file mode 100644
index 47b60a7..0000000
--- a/Hamakaze/Headers/HttpAcceptEncodingHeader.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Hamakaze.Headers {
- public class HttpAcceptEncodingHeader : HttpHeader {
- public const string NAME = @"Accept-Encoding";
-
- public override string Name => NAME;
- public override object Value => string.Join(@", ", Encodings);
-
- public HttpEncoding[] Encodings { get; }
-
- public HttpAcceptEncodingHeader(string encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- ) { }
-
- public HttpAcceptEncodingHeader(string[] encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Select(HttpEncoding.Parse)
- ) {}
-
- public HttpAcceptEncodingHeader(IEnumerable encodings) {
- Encodings = (encodings ?? throw new ArgumentNullException(nameof(encodings))).ToArray();
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpConnectionHeader.cs b/Hamakaze/Headers/HttpConnectionHeader.cs
deleted file mode 100644
index 50b1318..0000000
--- a/Hamakaze/Headers/HttpConnectionHeader.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpConnectionHeader : HttpHeader {
- public const string NAME = @"Connection";
-
- public override string Name => NAME;
- public override object Value { get; }
-
- public const string CLOSE = @"close";
- public const string KEEP_ALIVE = @"keep-alive";
-
- public HttpConnectionHeader(string mode) {
- Value = mode ?? throw new ArgumentNullException(nameof(mode));
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpContentEncodingHeader.cs b/Hamakaze/Headers/HttpContentEncodingHeader.cs
deleted file mode 100644
index 9972819..0000000
--- a/Hamakaze/Headers/HttpContentEncodingHeader.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpContentEncodingHeader : HttpHeader {
- public const string NAME = @"Content-Encoding";
-
- public override string Name => NAME;
- public override object Value => string.Join(@", ", Encodings);
-
- public string[] Encodings { get; }
-
- public HttpContentEncodingHeader(string encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- ) { }
-
- public HttpContentEncodingHeader(string[] encodings) {
- Encodings = encodings ?? throw new ArgumentNullException(nameof(encodings));
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpContentLengthHeader.cs b/Hamakaze/Headers/HttpContentLengthHeader.cs
deleted file mode 100644
index 53f2d31..0000000
--- a/Hamakaze/Headers/HttpContentLengthHeader.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.IO;
-
-namespace Hamakaze.Headers {
- public class HttpContentLengthHeader : HttpHeader {
- public const string NAME = @"Content-Length";
-
- public override string Name => NAME;
- public override object Value => Stream?.Length ?? Length;
-
- private Stream Stream { get; }
- private long Length { get; }
-
- public HttpContentLengthHeader(Stream stream) {
- Stream = stream ?? throw new ArgumentNullException(nameof(stream));
- if(!stream.CanRead || !stream.CanSeek)
- throw new ArgumentException(@"Body must readable and seekable.", nameof(stream));
- }
-
- public HttpContentLengthHeader(long length) {
- Length = length;
- }
-
- public HttpContentLengthHeader(string length) {
- if(!long.TryParse(length, out long ll))
- throw new ArgumentException(@"Invalid length value.", nameof(length));
- Length = ll;
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpContentTypeHeader.cs b/Hamakaze/Headers/HttpContentTypeHeader.cs
deleted file mode 100644
index 8ef6846..0000000
--- a/Hamakaze/Headers/HttpContentTypeHeader.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpContentTypeHeader : HttpHeader {
- public const string NAME = @"Content-Type";
-
- public override string Name => NAME;
- public override object Value => MediaType.ToString();
-
- public HttpMediaType MediaType { get; }
-
- public HttpContentTypeHeader(string mediaType) {
- MediaType = HttpMediaType.Parse(mediaType ?? throw new ArgumentNullException(nameof(mediaType)));
- }
-
- public HttpContentTypeHeader(HttpMediaType mediaType) {
- MediaType = mediaType;
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpCustomHeader.cs b/Hamakaze/Headers/HttpCustomHeader.cs
deleted file mode 100644
index bfd7196..0000000
--- a/Hamakaze/Headers/HttpCustomHeader.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpCustomHeader : HttpHeader {
- public override string Name { get; }
- public override object Value { get; }
-
- public HttpCustomHeader(string name, object value) {
- Name = NormaliseName(name ?? throw new ArgumentNullException(nameof(name)));
- Value = value;
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpDateHeader.cs b/Hamakaze/Headers/HttpDateHeader.cs
deleted file mode 100644
index 91c36fe..0000000
--- a/Hamakaze/Headers/HttpDateHeader.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace Hamakaze.Headers {
- public class HttpDateHeader : HttpHeader {
- public const string NAME = @"Date";
-
- public override string Name => NAME;
- public override object Value { get; }
-
- public DateTimeOffset DateTime { get; }
-
- public HttpDateHeader(string dateString) {
- Value = dateString ?? throw new ArgumentNullException(nameof(dateString));
- DateTime = DateTimeOffset.ParseExact(dateString, @"r", CultureInfo.InvariantCulture);
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpHeader.cs b/Hamakaze/Headers/HttpHeader.cs
deleted file mode 100644
index b9f75fa..0000000
--- a/Hamakaze/Headers/HttpHeader.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace Hamakaze.Headers {
- public abstract class HttpHeader {
- public abstract string Name { get; }
- public abstract object Value { get; }
-
- public override string ToString() {
- return string.Format(@"{0}: {1}", Name, Value);
- }
-
- public static string NormaliseName(string name) {
- if(string.IsNullOrWhiteSpace(name))
- return string.Empty;
-
- string[] parts = name.ToLowerInvariant().Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
- for(int i = 0; i < parts.Length; ++i)
- parts[i] = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(parts[i]);
- return string.Join('-', parts);
- }
-
- public static HttpHeader Create(string name, object value) {
- return name switch {
- HttpTeHeader.NAME => new HttpTeHeader(value.ToString()),
- HttpDateHeader.NAME => new HttpDateHeader(value.ToString()),
- HttpHostHeader.NAME => new HttpHostHeader(value.ToString()),
- HttpServerHeader.NAME => new HttpServerHeader(value.ToString()),
- HttpUserAgentHeader.NAME => new HttpUserAgentHeader(value.ToString()),
- HttpKeepAliveHeader.NAME => new HttpKeepAliveHeader(value.ToString()),
- HttpConnectionHeader.NAME => new HttpConnectionHeader(value.ToString()),
- HttpContentTypeHeader.NAME => new HttpContentTypeHeader(value.ToString()),
- HttpContentLengthHeader.NAME => new HttpContentLengthHeader(value.ToString()),
- HttpAcceptEncodingHeader.NAME => new HttpAcceptEncodingHeader(value.ToString()),
- HttpContentEncodingHeader.NAME => new HttpContentEncodingHeader(value.ToString()),
- HttpTransferEncodingHeader.NAME => new HttpTransferEncodingHeader(value.ToString()),
- _ => new HttpCustomHeader(name, value),
- };
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpHostHeader.cs b/Hamakaze/Headers/HttpHostHeader.cs
deleted file mode 100644
index c263ff9..0000000
--- a/Hamakaze/Headers/HttpHostHeader.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Linq;
-using System.Text;
-
-namespace Hamakaze.Headers {
- public class HttpHostHeader : HttpHeader {
- public const string NAME = @"Host";
-
- public override string Name => NAME;
- public override object Value {
- get {
- StringBuilder sb = new();
- sb.Append(Host);
- if(Port != -1)
- sb.AppendFormat(@":{0}", Port);
- return sb.ToString();
- }
- }
-
- public string Host { get; }
- public int Port { get; }
- public bool IsSecure { get; }
-
- public HttpHostHeader(string host, int port) {
- Host = host;
- Port = port;
- }
-
- public HttpHostHeader(string hostAndPort) {
- string[] parts = hostAndPort.Split(':', 2, StringSplitOptions.TrimEntries);
- Host = parts.ElementAtOrDefault(0) ?? throw new ArgumentNullException(nameof(hostAndPort));
- if(!ushort.TryParse(parts.ElementAtOrDefault(1), out ushort port))
- throw new FormatException(@"Host is not in valid format.");
- Port = port;
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpKeepAliveHeader.cs b/Hamakaze/Headers/HttpKeepAliveHeader.cs
deleted file mode 100644
index d8ab2c3..0000000
--- a/Hamakaze/Headers/HttpKeepAliveHeader.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Hamakaze.Headers {
- public class HttpKeepAliveHeader : HttpHeader {
- public const string NAME = @"Keep-Alive";
-
- public override string Name => NAME;
- public override object Value {
- get {
- List parts = new();
- if(MaxIdle != TimeSpan.MaxValue)
- parts.Add(string.Format(@"timeout={0}", MaxIdle.TotalSeconds));
- if(MaxRequests >= 0)
- parts.Add(string.Format(@"max={0}", MaxRequests));
- return string.Join(@", ", parts);
- }
- }
-
- public TimeSpan MaxIdle { get; } = TimeSpan.MaxValue;
- public int MaxRequests { get; } = -1;
-
- public HttpKeepAliveHeader(string value) {
- IEnumerable kvps = (value ?? throw new ArgumentNullException(nameof(value))).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
-
- foreach(string kvp in kvps) {
- string[] parts = kvp.Split('=', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
- if(parts[0] == @"timeout" && int.TryParse(parts[1], out int timeout))
- MaxIdle = TimeSpan.FromSeconds(timeout);
- else if(parts[0] == @"max" && int.TryParse(parts[1], out int max))
- MaxRequests = max;
- }
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpServerHeader.cs b/Hamakaze/Headers/HttpServerHeader.cs
deleted file mode 100644
index c2d665f..0000000
--- a/Hamakaze/Headers/HttpServerHeader.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpServerHeader : HttpHeader {
- public const string NAME = @"Server";
-
- public override string Name => NAME;
- public override object Value { get; }
-
- public HttpServerHeader(string server) {
- Value = server ?? throw new ArgumentNullException(nameof(server));
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpTeHeader.cs b/Hamakaze/Headers/HttpTeHeader.cs
deleted file mode 100644
index 0ccc4c3..0000000
--- a/Hamakaze/Headers/HttpTeHeader.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Hamakaze.Headers {
- public class HttpTeHeader : HttpHeader {
- public const string NAME = @"TE";
-
- public override string Name => NAME;
- public override object Value => string.Join(@", ", Encodings);
-
- public HttpEncoding[] Encodings { get; }
-
- public HttpTeHeader(string encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- ) { }
-
- public HttpTeHeader(string[] encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Select(HttpEncoding.Parse)
- ) { }
-
- public HttpTeHeader(IEnumerable encodings) {
- Encodings = (encodings ?? throw new ArgumentNullException(nameof(encodings))).ToArray();
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpTransferEncodingHeader.cs b/Hamakaze/Headers/HttpTransferEncodingHeader.cs
deleted file mode 100644
index a62939a..0000000
--- a/Hamakaze/Headers/HttpTransferEncodingHeader.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpTransferEncodingHeader : HttpHeader {
- public const string NAME = @"Transfer-Encoding";
-
- public override string Name => NAME;
- public override object Value => string.Join(@", ", Encodings);
-
- public string[] Encodings { get; }
-
- public HttpTransferEncodingHeader(string encodings) : this(
- (encodings ?? throw new ArgumentNullException(nameof(encodings))).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- ) {}
-
- public HttpTransferEncodingHeader(string[] encodings) {
- Encodings = encodings ?? throw new ArgumentNullException(nameof(encodings));
- }
- }
-}
diff --git a/Hamakaze/Headers/HttpUserAgentHeader.cs b/Hamakaze/Headers/HttpUserAgentHeader.cs
deleted file mode 100644
index b8aa5ec..0000000
--- a/Hamakaze/Headers/HttpUserAgentHeader.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Hamakaze.Headers {
- public class HttpUserAgentHeader : HttpHeader {
- public const string NAME = @"User-Agent";
-
- public override string Name => NAME;
- public override object Value { get; }
-
- public HttpUserAgentHeader(string userAgent) {
- if(userAgent == null)
- throw new ArgumentNullException(nameof(userAgent));
-
- if(string.IsNullOrWhiteSpace(userAgent) || userAgent.Equals(HttpClient.USER_AGENT))
- Value = HttpClient.USER_AGENT;
- else
- Value = string.Format(@"{0} {1}", userAgent, HttpClient.USER_AGENT);
- }
- }
-}
diff --git a/Hamakaze/HttpClient.cs b/Hamakaze/HttpClient.cs
deleted file mode 100644
index be009b5..0000000
--- a/Hamakaze/HttpClient.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Hamakaze.Headers;
-using System;
-using System.Collections.Generic;
-
-namespace Hamakaze {
- public class HttpClient : IDisposable {
- public const string PRODUCT_STRING = @"HMKZ";
- public const string VERSION_MAJOR = @"1";
- public const string VERSION_MINOR = @"0";
- public const string USER_AGENT = PRODUCT_STRING + @"/" + VERSION_MAJOR + @"." + VERSION_MINOR;
-
- private static HttpClient InstanceValue { get; set; }
- public static HttpClient Instance {
- get {
- if(InstanceValue == null)
- InstanceValue = new HttpClient();
- return InstanceValue;
- }
- }
-
- private HttpConnectionManager Connections { get; }
- private HttpTaskManager Tasks { get; }
-
- public string DefaultUserAgent { get; set; } = USER_AGENT;
- public bool ReuseConnections { get; set; } = true;
- public IEnumerable AcceptedEncodings { get; set; } = new[] { HttpEncoding.GZip, HttpEncoding.Deflate, HttpEncoding.Brotli };
-
- public HttpClient() {
- Connections = new HttpConnectionManager();
- Tasks = new HttpTaskManager();
- }
-
- public HttpTask CreateTask(
- HttpRequestMessage request,
- Action onComplete = null,
- Action onError = null,
- Action onCancel = null,
- Action onDownloadProgress = null,
- Action onUploadProgress = null,
- Action onStateChange = null,
- bool disposeRequest = true,
- bool disposeResponse = true
- ) {
- if(request == null)
- throw new ArgumentNullException(nameof(request));
- if(string.IsNullOrWhiteSpace(request.UserAgent))
- request.UserAgent = DefaultUserAgent;
- if(!request.HasHeader(HttpAcceptEncodingHeader.NAME))
- request.AcceptedEncodings = AcceptedEncodings;
- request.Connection = ReuseConnections ? HttpConnectionHeader.KEEP_ALIVE : HttpConnectionHeader.CLOSE;
-
- HttpTask task = new(Connections, request, disposeRequest, disposeResponse);
-
- if(onComplete != null)
- task.OnComplete += onComplete;
- if(onError != null)
- task.OnError += onError;
- if(onCancel != null)
- task.OnCancel += onCancel;
- if(onDownloadProgress != null)
- task.OnDownloadProgress += onDownloadProgress;
- if(onUploadProgress != null)
- task.OnUploadProgress += onUploadProgress;
- if(onStateChange != null)
- task.OnStateChange += onStateChange;
-
- return task;
- }
-
- public void RunTask(HttpTask task) {
- Tasks.RunTask(task);
- }
-
- public void SendRequest(
- HttpRequestMessage request,
- Action onComplete = null,
- Action onError = null,
- Action onCancel = null,
- Action onDownloadProgress = null,
- Action onUploadProgress = null,
- Action onStateChange = null,
- bool disposeRequest = true,
- bool disposeResponse = true
- ) {
- RunTask(CreateTask(request, onComplete, onError, onCancel, onDownloadProgress, onUploadProgress, onStateChange, disposeRequest, disposeResponse));
- }
-
- public static void Send(
- HttpRequestMessage request,
- Action onComplete = null,
- Action onError = null,
- Action onCancel = null,
- Action onDownloadProgress = null,
- Action onUploadProgress = null,
- Action onStateChange = null,
- bool disposeRequest = true,
- bool disposeResponse = true
- ) {
- Instance.SendRequest(request, onComplete, onError, onCancel, onDownloadProgress, onUploadProgress, onStateChange, disposeRequest, disposeResponse);
- }
-
- private bool IsDisposed;
- ~HttpClient()
- => DoDispose();
- public void Dispose() {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- private void DoDispose() {
- if(IsDisposed)
- return;
- IsDisposed = true;
-
- Tasks.Dispose();
- Connections.Dispose();
- }
- }
-}
diff --git a/Hamakaze/HttpConnection.cs b/Hamakaze/HttpConnection.cs
deleted file mode 100644
index 8bb90d0..0000000
--- a/Hamakaze/HttpConnection.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Security.Authentication;
-using System.Threading;
-
-namespace Hamakaze {
- public class HttpConnection : IDisposable {
- public IPEndPoint EndPoint { get; }
- public Stream Stream { get; }
-
- public Socket Socket { get; }
- public NetworkStream NetworkStream { get; }
- public SslStream SslStream { get; }
-
- public string Host { get; }
- public bool IsSecure { get; }
-
- public bool HasTimedOut => MaxRequests == 0 || (DateTimeOffset.Now - LastOperation) > MaxIdle;
-
- public int MaxRequests { get; set; } = -1;
- public TimeSpan MaxIdle { get; set; } = TimeSpan.MaxValue;
- public DateTimeOffset LastOperation { get; private set; } = DateTimeOffset.Now;
-
- public bool InUse { get; private set; }
-
- public HttpConnection(string host, IPEndPoint endPoint, bool secure) {
- Host = host ?? throw new ArgumentNullException(nameof(host));
- EndPoint = endPoint ?? throw new ArgumentNullException(nameof(endPoint));
- IsSecure = secure;
-
- if(endPoint.AddressFamily is not AddressFamily.InterNetwork and not AddressFamily.InterNetworkV6)
- throw new ArgumentException(@"Address must be an IPv4 or IPv6 address.", nameof(endPoint));
-
- Socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) {
- NoDelay = true,
- Blocking = true,
- };
- Socket.Connect(endPoint);
-
- NetworkStream = new NetworkStream(Socket, true);
-
- if(IsSecure) {
- SslStream = new SslStream(NetworkStream, false, (s, ce, ch, e) => e == SslPolicyErrors.None, null);
- Stream = SslStream;
- SslStream.AuthenticateAsClient(Host, null, SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13, true);
- } else
- Stream = NetworkStream;
- }
-
- public void MarkUsed() {
- LastOperation = DateTimeOffset.Now;
- if(MaxRequests > 0)
- --MaxRequests;
- }
-
- public bool Acquire() {
- return !InUse && (InUse = true);
- }
-
- public void Release() {
- InUse = false;
- }
-
- private bool IsDisposed;
- ~HttpConnection()
- => DoDispose();
- public void Dispose() {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- private void DoDispose() {
- if(IsDisposed)
- return;
- IsDisposed = true;
- Stream.Dispose();
- }
- }
-}
diff --git a/Hamakaze/HttpConnectionManager.cs b/Hamakaze/HttpConnectionManager.cs
deleted file mode 100644
index a0c5853..0000000
--- a/Hamakaze/HttpConnectionManager.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Threading;
-
-namespace Hamakaze {
- public class HttpConnectionManager : IDisposable {
- private List Connections { get; } = new();
- private Mutex Lock { get; } = new();
-
- public HttpConnectionManager() {
- }
-
- private void AcquireLock() {
- if(!Lock.WaitOne(10000))
- throw new HttpConnectionManagerLockException();
- }
-
- private void ReleaseLock() {
- Lock.ReleaseMutex();
- }
-
- public HttpConnection CreateConnection(string host, IPEndPoint endPoint, bool secure) {
- if(host == null)
- throw new ArgumentNullException(nameof(host));
- if(endPoint == null)
- throw new ArgumentNullException(nameof(endPoint));
- HttpConnection conn = null;
- AcquireLock();
- try {
- conn = CreateConnectionInternal(host, endPoint, secure);
- } finally {
- ReleaseLock();
- }
- return conn;
- }
-
- private HttpConnection CreateConnectionInternal(string host, IPEndPoint endPoint, bool secure) {
- HttpConnection conn = new(host, endPoint, secure);
- Connections.Add(conn);
- return conn;
- }
-
- public HttpConnection GetConnection(string host, IPEndPoint endPoint, bool secure) {
- if(host == null)
- throw new ArgumentNullException(nameof(host));
- if(endPoint == null)
- throw new ArgumentNullException(nameof(endPoint));
- HttpConnection conn = null;
- AcquireLock();
- try {
- conn = GetConnectionInternal(host, endPoint, secure);
- } finally {
- ReleaseLock();
- }
- return conn;
- }
-
- private HttpConnection GetConnectionInternal(string host, IPEndPoint endPoint, bool secure) {
- CleanConnectionsInternal();
- HttpConnection conn = Connections.FirstOrDefault(c => host.Equals(c.Host) && endPoint.Equals(c.EndPoint) && c.IsSecure == secure && c.Acquire());
- if(conn == null) {
- conn = CreateConnectionInternal(host, endPoint, secure);
- conn.Acquire();
- }
- return conn;
- }
-
- public void EndConnection(HttpConnection conn) {
- if(conn == null)
- throw new ArgumentNullException(nameof(conn));
- AcquireLock();
- try {
- EndConnectionInternal(conn);
- } finally {
- ReleaseLock();
- }
- }
-
- private void EndConnectionInternal(HttpConnection conn) {
- Connections.Remove(conn);
- conn.Dispose();
- }
-
- public void CleanConnection() {
- AcquireLock();
- try {
- CleanConnectionsInternal();
- } finally {
- ReleaseLock();
- }
- }
-
- private void CleanConnectionsInternal() {
- IEnumerable conns = Connections.Where(x => x.HasTimedOut).ToArray();
- foreach(HttpConnection conn in conns) {
- Connections.Remove(conn);
- conn.Dispose();
- }
- }
-
- private bool IsDisposed;
- ~HttpConnectionManager()
- => DoDispose();
- public void Dispose() {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- private void DoDispose() {
- if(IsDisposed)
- return;
- IsDisposed = true;
-
- Lock.Dispose();
-
- foreach(HttpConnection conn in Connections)
- conn.Dispose();
- Connections.Clear();
- }
- }
-}
diff --git a/Hamakaze/HttpEncoding.cs b/Hamakaze/HttpEncoding.cs
deleted file mode 100644
index 5b6e3a5..0000000
--- a/Hamakaze/HttpEncoding.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using System.Globalization;
-using System.Text;
-
-namespace Hamakaze {
- public readonly struct HttpEncoding : IComparable, IEquatable {
- public const string DEFLATE = @"deflate";
- public const string GZIP = @"gzip";
- public const string XGZIP = @"x-gzip";
- public const string BROTLI = @"br";
- public const string IDENTITY = @"identity";
- public const string CHUNKED = @"chunked";
- public const string ANY = @"*";
-
- public static readonly HttpEncoding Any = new(ANY);
- public static readonly HttpEncoding None = new(ANY, 0f);
- public static readonly HttpEncoding Deflate = new(DEFLATE);
- public static readonly HttpEncoding GZip = new(GZIP);
- public static readonly HttpEncoding Brotli = new(BROTLI);
- public static readonly HttpEncoding Identity = new(IDENTITY);
-
- public string Name { get; }
- public float Quality { get; }
-
- public HttpEncoding(string name, float quality = 1f) {
- Name = name ?? throw new ArgumentNullException(nameof(name));
- Quality = quality;
- }
-
- public HttpEncoding WithQuality(float quality) {
- return new HttpEncoding(Name, quality);
- }
-
- public static HttpEncoding Parse(string encoding) {
- string[] parts = encoding.Split(';', StringSplitOptions.TrimEntries);
- float quality = 1f;
- encoding = parts[0];
-
- for(int i = 1; i < parts.Length; ++i)
- if(parts[i].StartsWith(@"q=")) {
- if(!float.TryParse(parts[i], out quality))
- quality = 1f;
- break;
- }
-
- return new HttpEncoding(encoding, quality);
- }
-
- public override string ToString() {
- StringBuilder sb = new();
- sb.Append(Name);
- if(Quality is >= 0f and < 1f)
- sb.AppendFormat(CultureInfo.InvariantCulture, @";q={0:0.0}", Quality);
- return sb.ToString();
- }
-
- public int CompareTo(HttpEncoding? other) {
- if(!other.HasValue || other.Value.Quality < Quality)
- return -1;
- if(other.Value.Quality > Quality)
- return 1;
- return 0;
- }
-
- public bool Equals(HttpEncoding? other) {
- return other.HasValue && Name.Equals(other.Value.Name) && Quality.Equals(other.Value.Quality);
- }
- }
-}
diff --git a/Hamakaze/HttpException.cs b/Hamakaze/HttpException.cs
deleted file mode 100644
index d6e0bce..0000000
--- a/Hamakaze/HttpException.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-
-namespace Hamakaze {
- public class HttpException : Exception {
- public HttpException(string message) : base(message) { }
- }
-
- public class HttpConnectionManagerException : HttpException {
- public HttpConnectionManagerException(string message) : base(message) { }
- }
- public class HttpConnectionManagerLockException : HttpConnectionManagerException {
- public HttpConnectionManagerLockException() : base(@"Failed to lock the connection manager in time.") { }
- }
-
- public class HttpTaskException : HttpException {
- public HttpTaskException(string message) : base(message) { }
- }
- public class HttpTaskAlreadyStartedException : HttpTaskException {
- public HttpTaskAlreadyStartedException() : base(@"Task has already started.") { }
- }
- public class HttpTaskInvalidStateException : HttpTaskException {
- public HttpTaskInvalidStateException() : base(@"Task has ended up in an invalid state.") { }
- }
- public class HttpTaskNoAddressesException : HttpTaskException {
- public HttpTaskNoAddressesException() : base(@"Could not find any addresses for this host.") { }
- }
- public class HttpTaskNoConnectionException : HttpTaskException {
- public HttpTaskNoConnectionException() : base(@"Was unable to create a connection with this host.") { }
- }
- public class HttpTaskRequestFailedException : HttpTaskException {
- public HttpTaskRequestFailedException() : base(@"Request failed for unknown reasons.") { }
- }
-
- public class HttpTaskManagerException : HttpException {
- public HttpTaskManagerException(string message) : base(message) { }
- }
- public class HttpTaskManagerLockException : HttpTaskManagerException {
- public HttpTaskManagerLockException() : base(@"Failed to reserve a thread.") { }
- }
-}
diff --git a/Hamakaze/HttpMediaType.cs b/Hamakaze/HttpMediaType.cs
deleted file mode 100644
index e3ca1e6..0000000
--- a/Hamakaze/HttpMediaType.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Hamakaze {
- public readonly struct HttpMediaType : IComparable, IEquatable {
- public const string TYPE_APPLICATION = @"application";
- public const string TYPE_AUDIO = @"audio";
- public const string TYPE_IMAGE = @"image";
- public const string TYPE_MESSAGE = @"message";
- public const string TYPE_MULTIPART = @"multipart";
- public const string TYPE_TEXT = @"text";
- public const string TYPE_VIDEO = @"video";
-
- public static readonly HttpMediaType OctetStream = new(TYPE_APPLICATION, @"octet-stream");
- public static readonly HttpMediaType FWIF = new(TYPE_APPLICATION, @"x.fwif");
- public static readonly HttpMediaType JSON = new(TYPE_APPLICATION, @"json");
- public static readonly HttpMediaType HTML = new(TYPE_TEXT, @"html", args: new[] { Param.UTF8 });
-
- public string Type { get; }
- public string Subtype { get; }
- public string Suffix { get; }
- public IEnumerable Params { get; }
-
- public HttpMediaType(string type, string subtype, string suffix = null, IEnumerable args = null) {
- Type = type ?? throw new ArgumentNullException(nameof(type));
- Subtype = subtype ?? throw new ArgumentNullException(nameof(subtype));
- Suffix = suffix ?? string.Empty;
- Params = args ?? Enumerable.Empty();
- }
-
- public string GetParamValue(string name) {
- foreach(Param param in Params)
- if(param.Name.ToLowerInvariant() == name)
- return param.Value;
- return null;
- }
-
- public static explicit operator HttpMediaType(string mediaTypeString) => Parse(mediaTypeString);
-
- public static HttpMediaType Parse(string mediaTypeString) {
- if(mediaTypeString == null)
- throw new ArgumentNullException(nameof(mediaTypeString));
-
- int slashIndex = mediaTypeString.IndexOf('/');
- if(slashIndex == -1)
- return OctetStream;
-
- string type = mediaTypeString[..slashIndex];
- string subtype = mediaTypeString[(slashIndex + 1)..];
- string suffix = null;
- IEnumerable args = null;
-
- int paramIndex = subtype.IndexOf(';');
- if(paramIndex != -1) {
- args = subtype[(paramIndex + 1)..]
- .Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
- .Select(Param.Parse);
- subtype = subtype[..paramIndex];
- }
-
- int suffixIndex = subtype.IndexOf('+');
- if(suffixIndex != -1) {
- suffix = subtype[(suffixIndex + 1)..];
- subtype = subtype[..suffixIndex];
- }
-
- return new HttpMediaType(type, subtype, suffix, args);
- }
-
- public override string ToString() {
- StringBuilder sb = new();
- sb.AppendFormat(@"{0}/{1}", Type, Subtype);
- if(!string.IsNullOrWhiteSpace(Suffix))
- sb.AppendFormat(@"+{0}", Suffix);
- if(Params.Any())
- sb.AppendFormat(@";{0}", string.Join(';', Params));
- return sb.ToString();
- }
-
- public int CompareTo(HttpMediaType? other) {
- if(!other.HasValue)
- return -1;
- int type = Type.CompareTo(other.Value.Type);
- if(type != 0)
- return type;
- int subtype = Subtype.CompareTo(other.Value.Subtype);
- if(subtype != 0)
- return subtype;
- int suffix = Suffix.CompareTo(other.Value.Suffix);
- if(suffix != 0)
- return suffix;
- int paramCount = Params.Count();
- int args = paramCount - other.Value.Params.Count();
- if(args != 0)
- return args;
- for(int i = 0; i < paramCount; ++i) {
- args = Params.ElementAt(i).CompareTo(other.Value.Params.ElementAt(i));
- if(args != 0)
- return args;
- }
- return 0;
- }
-
- public bool Equals(HttpMediaType? other) {
- if(!other.HasValue)
- return false;
- if(!Type.Equals(other.Value.Type) || !Subtype.Equals(other.Value.Subtype) || !Suffix.Equals(other.Value.Suffix))
- return false;
- int paramCount = Params.Count();
- if(paramCount != other.Value.Params.Count())
- return false;
- for(int i = 0; i < paramCount; ++i)
- if(!Params.ElementAt(i).Equals(other.Value.Params.ElementAt(i)))
- return false;
- return true;
- }
-
- public readonly struct Param : IComparable, IEquatable {
- public const string CHARSET = @"charset";
-
- public static readonly Param ASCII = new(CHARSET, @"us-ascii");
- public static readonly Param UTF8 = new(CHARSET, @"utf-8");
-
- public string Name { get; }
- public string Value { get; }
-
- public Param(string name, string value) {
- Name = name ?? throw new ArgumentNullException(nameof(name));
- Value = value ?? throw new ArgumentNullException(nameof(name));
- }
-
- public override string ToString() {
- return string.Format(@"{0}={1}", Name, Value);
- }
-
- public static explicit operator Param(string paramStr) => Parse(paramStr);
-
- public static Param Parse(string paramStr) {
- string[] parts = (paramStr ?? throw new ArgumentNullException(nameof(paramStr))).Split('=', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
- return new Param(parts[0], parts[1]);
- }
-
- public int CompareTo(Param? other) {
- if(!other.HasValue)
- return -1;
- int name = Name.CompareTo(other.Value.Name);
- return name != 0
- ? name
- : Value.CompareTo(other.Value.Value);
- }
-
- public bool Equals(Param? other) {
- return other.HasValue && Name.Equals(other.Value.Name) && Value.Equals(other.Value.Value);
- }
- }
- }
-}
diff --git a/Hamakaze/HttpMessage.cs b/Hamakaze/HttpMessage.cs
deleted file mode 100644
index cbfc22e..0000000
--- a/Hamakaze/HttpMessage.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using Hamakaze.Headers;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace Hamakaze {
- public abstract class HttpMessage : IDisposable {
- public abstract string ProtocolVersion { get; }
- public abstract IEnumerable Headers { get; }
- public abstract Stream Body { get; }
-
- public virtual bool HasBody => Body != null;
-
- protected bool OwnsBodyStream { get; set; }
-
- public virtual IEnumerable GetHeader(string header) {
- header = HttpHeader.NormaliseName(header);
- return Headers.Where(h => h.Name == header);
- }
-
- public virtual bool HasHeader(string header) {
- header = HttpHeader.NormaliseName(header);
- return Headers.Any(h => h.Name == header);
- }
-
- public virtual string GetHeaderLine(string header) {
- return string.Join(@", ", GetHeader(header).Select(h => h.Value));
- }
-
- private bool IsDisposed;
- ~HttpMessage()
- => DoDispose();
- public void Dispose() {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- protected void DoDispose() {
- if(IsDisposed)
- return;
- IsDisposed = true;
- if(OwnsBodyStream && Body != null)
- Body.Dispose();
- }
- }
-}
diff --git a/Hamakaze/HttpRequestMessage.cs b/Hamakaze/HttpRequestMessage.cs
deleted file mode 100644
index 6ce3ce3..0000000
--- a/Hamakaze/HttpRequestMessage.cs
+++ /dev/null
@@ -1,190 +0,0 @@
-using Hamakaze.Headers;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace Hamakaze {
- public class HttpRequestMessage : HttpMessage {
- public const string GET = @"GET";
- public const string PUT = @"PUT";
- public const string HEAD = @"HEAD";
- public const string POST = @"POST";
- public const string DELETE = @"DELETE";
-
- public override string ProtocolVersion => @"1.1";
-
- public string Method { get; }
- public string RequestTarget { get; }
-
- public bool IsSecure { get; }
-
- public string Host { get; }
- public ushort Port { get; }
- public bool IsDefaultPort { get; }
-
- public override IEnumerable Headers => HeaderList;
- private List HeaderList { get; } = new();
-
- private Stream BodyStream { get; set; }
- public override Stream Body {
- get {
- if(BodyStream == null) {
- OwnsBodyStream = true;
- SetBody(new MemoryStream());
- }
- return BodyStream;
- }
- }
-
- private static readonly string[] HEADERS_READONLY = new[] {
- HttpHostHeader.NAME, HttpContentLengthHeader.NAME,
- };
- private static readonly string[] HEADERS_SINGLE = new[] {
- HttpUserAgentHeader.NAME, HttpConnectionHeader.NAME, HttpAcceptEncodingHeader.NAME,
- };
-
- public IEnumerable AcceptedEncodings {
- get => HeaderList.Where(x => x.Name == HttpAcceptEncodingHeader.NAME).Cast().FirstOrDefault()?.Encodings
- ?? Enumerable.Empty();
-
- set {
- HeaderList.RemoveAll(x => x.Name == HttpAcceptEncodingHeader.NAME);
- HeaderList.Add(new HttpAcceptEncodingHeader(value));
- }
- }
-
- public string UserAgent {
- get => HeaderList.FirstOrDefault(x => x.Name == HttpUserAgentHeader.NAME)?.Value.ToString()
- ?? string.Empty;
- set {
- HeaderList.RemoveAll(x => x.Name == HttpUserAgentHeader.NAME);
- HeaderList.Add(new HttpUserAgentHeader(value));
- }
- }
-
- public string Connection {
- get => HeaderList.FirstOrDefault(x => x.Name == HttpConnectionHeader.NAME)?.Value.ToString()
- ?? string.Empty;
- set {
- HeaderList.RemoveAll(x => x.Name == HttpConnectionHeader.NAME);
- HeaderList.Add(new HttpConnectionHeader(value));
- }
- }
-
- public HttpMediaType ContentType {
- get => HeaderList.Where(x => x.Name == HttpContentTypeHeader.NAME).Cast().FirstOrDefault()?.MediaType
- ?? HttpMediaType.OctetStream;
- set {
- HeaderList.RemoveAll(x => x.Name == HttpContentTypeHeader.NAME);
- HeaderList.Add(new HttpContentTypeHeader(value));
- }
- }
-
- public HttpRequestMessage(string method, string uri) : this(
- method, new Uri(uri)
- ) {}
-
- public const ushort HTTP = 80;
- public const ushort HTTPS = 443;
-
- public HttpRequestMessage(string method, Uri uri) {
- Method = method ?? throw new ArgumentNullException(nameof(method));
- RequestTarget = uri.PathAndQuery;
- IsSecure = uri.Scheme.Equals(@"https", StringComparison.InvariantCultureIgnoreCase);
- Host = uri.Host;
- ushort defaultPort = (IsSecure ? HTTPS : HTTP);
- Port = uri.Port == -1 ? defaultPort : (ushort)uri.Port;
- IsDefaultPort = Port == defaultPort;
- HeaderList.Add(new HttpHostHeader(Host, IsDefaultPort ? -1 : Port));
- }
-
- public static bool IsHeaderReadOnly(string name)
- => HEADERS_READONLY.Contains(name ?? throw new ArgumentNullException(nameof(name)));
- public static bool IsHeaderSingleInstance(string name)
- => HEADERS_SINGLE.Contains(name ?? throw new ArgumentNullException(nameof(name)));
-
- public void SetHeader(string name, object value) {
- name = HttpHeader.NormaliseName(name ?? throw new ArgumentNullException(nameof(name)));
- if(IsHeaderReadOnly(name))
- throw new ArgumentException(@"This header is read-only.", nameof(name));
- HeaderList.RemoveAll(x => x.Name == name);
- HeaderList.Add(HttpHeader.Create(name, value));
- }
-
- public void AddHeader(string name, object value) {
- name = HttpHeader.NormaliseName(name ?? throw new ArgumentNullException(nameof(name)));
- if(IsHeaderReadOnly(name))
- throw new ArgumentException(@"This header is read-only.", nameof(name));
- if(IsHeaderSingleInstance(name))
- HeaderList.RemoveAll(x => x.Name == name);
- HeaderList.Add(HttpHeader.Create(name, value));
- }
-
- public void RemoveHeader(string name) {
- name = HttpHeader.NormaliseName(name ?? throw new ArgumentNullException(nameof(name)));
- if(IsHeaderReadOnly(name))
- throw new ArgumentException(@"This header is read-only.", nameof(name));
- HeaderList.RemoveAll(x => x.Name == name);
- }
-
- public void SetBody(Stream stream) {
- if(stream == null) {
- if(OwnsBodyStream)
- BodyStream?.Dispose();
- OwnsBodyStream = false;
- BodyStream = null;
- HeaderList.RemoveAll(x => x.Name == HttpContentLengthHeader.NAME);
- } else {
- if(!stream.CanRead || !stream.CanSeek)
- throw new ArgumentException(@"Body must readable and seekable.", nameof(stream));
- if(OwnsBodyStream)
- BodyStream?.Dispose();
- OwnsBodyStream = false;
- BodyStream = stream;
- HeaderList.Add(new HttpContentLengthHeader(BodyStream));
- }
- }
-
- public void SetBody(byte[] buffer) {
- SetBody(new MemoryStream(buffer));
- OwnsBodyStream = true;
- }
-
- public void SetBody(string str, Encoding encoding = null) {
- SetBody((encoding ?? Encoding.UTF8).GetBytes(str));
- }
-
- public void WriteTo(Stream stream, Action onProgress = null) {
- using(StreamWriter sw = new(stream, new ASCIIEncoding(), leaveOpen: true)) {
- sw.NewLine = "\r\n";
- sw.Write(Method);
- sw.Write(' ');
- sw.Write(RequestTarget);
- sw.Write(@" HTTP/");
- sw.WriteLine(ProtocolVersion);
- foreach(HttpHeader header in Headers)
- sw.WriteLine(header);
- sw.WriteLine();
- sw.Flush();
- }
-
- if(BodyStream != null) {
- const int bufferSize = 8192;
- byte[] buffer = new byte[bufferSize];
- int read;
- long totalRead = 0;
-
- onProgress?.Invoke(totalRead, BodyStream.Length);
-
- BodyStream.Seek(0, SeekOrigin.Begin);
- while((read = BodyStream.Read(buffer, 0, bufferSize)) > 0) {
- stream.Write(buffer, 0, read);
- totalRead += read;
- onProgress?.Invoke(totalRead, BodyStream.Length);
- }
- }
- }
- }
-}
diff --git a/Hamakaze/HttpResponseMessage.cs b/Hamakaze/HttpResponseMessage.cs
deleted file mode 100644
index c041e93..0000000
--- a/Hamakaze/HttpResponseMessage.cs
+++ /dev/null
@@ -1,265 +0,0 @@
-using Hamakaze.Headers;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.IO.Compression;
-using System.Linq;
-using System.Text;
-
-namespace Hamakaze {
- public class HttpResponseMessage : HttpMessage {
- public override string ProtocolVersion { get; }
- public int StatusCode { get; }
- public string StatusMessage { get; }
-
- public override IEnumerable Headers { get; }
-
- public override Stream Body { get; }
-
- public string Connection
- => Headers.FirstOrDefault(x => x.Name == HttpConnectionHeader.NAME)?.Value.ToString() ?? string.Empty;
- public string Server
- => Headers.FirstOrDefault(x => x.Name == HttpServerHeader.NAME)?.Value.ToString() ?? string.Empty;
- public DateTimeOffset Date
- => Headers.Where(x => x.Name == HttpDateHeader.NAME).Cast().FirstOrDefault()?.DateTime ?? DateTimeOffset.MinValue;
- public HttpMediaType ContentType
- => Headers.Where(x => x.Name == HttpContentTypeHeader.NAME).Cast().FirstOrDefault()?.MediaType
- ?? HttpMediaType.OctetStream;
- public Encoding ResponseEncoding
- => Encoding.GetEncoding(ContentType.GetParamValue(@"charset") ?? @"iso8859-1");
- public IEnumerable ContentEncodings
- => Headers.Where(x => x.Name == HttpContentEncodingHeader.NAME).Cast().FirstOrDefault()?.Encodings
- ?? Enumerable.Empty();
- public IEnumerable TransferEncodings
- => Headers.Where(x => x.Name == HttpTransferEncodingHeader.NAME).Cast().FirstOrDefault()?.Encodings
- ?? Enumerable.Empty();
-
- public HttpResponseMessage(
- int statusCode, string statusMessage, string protocolVersion,
- IEnumerable headers, Stream body
- ) {
- ProtocolVersion = protocolVersion ?? throw new ArgumentNullException(nameof(protocolVersion));
- StatusCode = statusCode;
- StatusMessage = statusMessage ?? string.Empty;
- Headers = (headers ?? throw new ArgumentNullException(nameof(headers))).ToArray();
- OwnsBodyStream = true;
- Body = body;
- }
-
- public byte[] GetBodyBytes() {
- if(Body == null)
- return null;
- if(Body is MemoryStream msBody)
- return msBody.ToArray();
- using MemoryStream ms = new();
- if(Body.CanSeek)
- Body.Seek(0, SeekOrigin.Begin);
- Body.CopyTo(ms);
- return ms.ToArray();
- }
-
- public string GetBodyString() {
- byte[] bytes = GetBodyBytes();
- return bytes == null || bytes.Length < 1
- ? string.Empty
- : ResponseEncoding.GetString(bytes);
- }
-
- // there's probably a less stupid way to do this, be my guest and call me an idiot
- private static void ProcessEncoding(Stack encodings, Stream stream, bool transfer) {
- using MemoryStream temp = new();
- bool inTemp = false;
-
- while(encodings.TryPop(out string encoding)) {
- Stream target = (inTemp = !inTemp) ? temp : stream,
- source = inTemp ? stream : temp;
-
- target.SetLength(0);
- source.Seek(0, SeekOrigin.Begin);
-
- switch(encoding) {
- case HttpEncoding.GZIP:
- case HttpEncoding.XGZIP:
- using(GZipStream gzs = new(source, CompressionMode.Decompress, true))
- gzs.CopyTo(target);
- break;
-
- case HttpEncoding.DEFLATE:
- using(DeflateStream def = new(source, CompressionMode.Decompress, true))
- def.CopyTo(target);
- break;
-
- case HttpEncoding.BROTLI:
- if(transfer)
- goto default;
- using(BrotliStream br = new(source, CompressionMode.Decompress, true))
- br.CopyTo(target);
- break;
-
- case HttpEncoding.IDENTITY:
- break;
-
- case HttpEncoding.CHUNKED:
- if(!transfer)
- goto default;
- throw new IOException(@"Invalid use of chunked encoding type in Transfer-Encoding header.");
-
- default:
- throw new IOException(@"Unsupported encoding supplied.");
- }
- }
-
- if(inTemp) {
- stream.SetLength(0);
- temp.Seek(0, SeekOrigin.Begin);
- temp.CopyTo(stream);
- }
- }
-
- public static HttpResponseMessage ReadFrom(Stream stream, Action onProgress = null) {
- // ignore this function, it doesn't exist
- string readLine() {
- const ushort crlf = 0x0D0A;
- using MemoryStream ms = new();
- int byt; ushort lastTwo = 0;
-
- for(; ; ) {
- byt = stream.ReadByte();
- if(byt == -1 && ms.Length == 0)
- return null;
-
- ms.WriteByte((byte)byt);
-
- lastTwo <<= 8;
- lastTwo |= (byte)byt;
- if(lastTwo == crlf) {
- ms.SetLength(ms.Length - 2);
- break;
- }
- }
-
- return Encoding.ASCII.GetString(ms.ToArray());
- }
-
- long contentLength = -1;
- Stack transferEncodings = null;
- Stack contentEncodings = null;
-
- // Read initial header
- string line = readLine();
- if(line == null)
- throw new IOException(@"Failed to read initial HTTP header.");
- if(!line.StartsWith(@"HTTP/"))
- throw new IOException(@"Response is not a valid HTTP message.");
- string[] parts = line[5..].Split(' ', 3);
- if(!int.TryParse(parts.ElementAtOrDefault(1), out int statusCode))
- throw new IOException(@"Invalid HTTP status code format.");
- string protocolVersion = parts.ElementAtOrDefault(0);
- string statusMessage = parts.ElementAtOrDefault(2);
-
- // Read header key-value pairs
- List headers = new();
-
- while((line = readLine()) != null) {
- if(string.IsNullOrWhiteSpace(line))
- break;
-
- parts = line.Split(':', 2, StringSplitOptions.TrimEntries);
- if(parts.Length < 2)
- throw new IOException(@"Invalid HTTP header in response.");
-
- string hName = HttpHeader.NormaliseName(parts.ElementAtOrDefault(0) ?? string.Empty),
- hValue = parts.ElementAtOrDefault(1);
- if(string.IsNullOrEmpty(hName))
- throw new IOException(@"Invalid HTTP header name.");
-
- HttpHeader header = HttpHeader.Create(hName, hValue);
-
- if(header is HttpContentLengthHeader hclh)
- contentLength = (long)hclh.Value;
- else if(header is HttpTransferEncodingHeader hteh)
- transferEncodings = new Stack(hteh.Encodings);
- else if(header is HttpContentEncodingHeader hceh)
- contentEncodings = new Stack(hceh.Encodings);
-
- headers.Add(header);
- }
-
- if(statusCode is < 200 or 201 or 204 or 205)
- contentLength = 0;
-
- Stream body = null;
- long totalRead = 0;
- const int buffer_size = 8192;
- byte[] buffer = new byte[buffer_size];
- int read;
-
- void readBuffer(long length = -1) {
- if(length == 0)
- return;
- long remaining = length;
- int bufferRead = buffer_size;
- if(bufferRead > length)
- bufferRead = (int)length;
-
- if(totalRead < 1)
- onProgress?.Invoke(0, contentLength);
-
- while((read = stream.Read(buffer, 0, bufferRead)) > 0) {
- body.Write(buffer, 0, read);
-
- totalRead += read;
- onProgress?.Invoke(totalRead, contentLength);
-
- if(length >= 0) {
- remaining -= read;
- if(remaining < 1)
- break;
- if(bufferRead > remaining)
- bufferRead = (int)remaining;
- }
- }
- }
-
- // Read body
- if(transferEncodings != null && transferEncodings.Any() && transferEncodings.Peek() == HttpEncoding.CHUNKED) {
- // oh no the poop is chunky
- transferEncodings.Pop();
- body = new MemoryStream();
-
- while((line = readLine()) != null) {
- if(string.IsNullOrWhiteSpace(line))
- break;
- if(!int.TryParse(line, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int chunkLength))
- throw new IOException(@"Failed to decode chunk length.");
- if(chunkLength == 0) // final chunk
- break;
- readBuffer(chunkLength);
- readLine();
- }
- readLine();
- } else if(contentLength != 0) {
- body = new MemoryStream();
- readBuffer(contentLength);
- readLine();
- }
-
- if(body != null)
- // Check if body is empty and null it again if so
- if(body.Length == 0) {
- body.Dispose();
- body = null;
- } else {
- if(transferEncodings != null)
- ProcessEncoding(transferEncodings, body, true);
- if(contentEncodings != null)
- ProcessEncoding(contentEncodings, body, false);
-
- body.Seek(0, SeekOrigin.Begin);
- }
-
- return new HttpResponseMessage(statusCode, statusMessage, protocolVersion, headers, body);
- }
- }
-}
diff --git a/Hamakaze/HttpTask.cs b/Hamakaze/HttpTask.cs
deleted file mode 100644
index ddcd212..0000000
--- a/Hamakaze/HttpTask.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-using Hamakaze.Headers;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-
-namespace Hamakaze {
- public class HttpTask {
- public TaskState State { get; private set; } = TaskState.Initial;
-
- public bool IsStarted
- => State != TaskState.Initial;
- public bool IsFinished
- => State == TaskState.Finished;
- public bool IsCancelled
- => State == TaskState.Cancelled;
- public bool IsErrored
- => Exception != null;
-
- public Exception Exception { get; private set; }
-
- public HttpRequestMessage Request { get; }
- public HttpResponseMessage Response { get; private set; }
- private HttpConnectionManager Connections { get; }
-
- private IEnumerable Addresses { get; set; }
- private HttpConnection Connection { get; set; }
-
- public bool DisposeRequest { get; set; }
- public bool DisposeResponse { get; set; }
-
- public event Action OnComplete;
- public event Action OnError;
- public event Action OnCancel;
- public event Action OnUploadProgress;
- public event Action OnDownloadProgress;
- public event Action OnStateChange;
-
- public HttpTask(HttpConnectionManager conns, HttpRequestMessage request, bool disposeRequest, bool disposeResponse) {
- Connections = conns ?? throw new ArgumentNullException(nameof(conns));
- Request = request ?? throw new ArgumentNullException(nameof(request));
- DisposeRequest = disposeRequest;
- DisposeResponse = disposeResponse;
- }
-
- public void Run() {
- if(IsStarted)
- throw new HttpTaskAlreadyStartedException();
- while(NextStep());
- }
-
- public void Cancel() {
- State = TaskState.Cancelled;
- OnStateChange?.Invoke(this, State);
- OnCancel?.Invoke(this);
- if(DisposeResponse)
- Response?.Dispose();
- if(DisposeRequest)
- Request?.Dispose();
- }
-
- private void Error(Exception ex) {
- Exception = ex;
- OnError?.Invoke(this, ex);
- Cancel();
- }
-
- public bool NextStep() {
- if(IsCancelled)
- return false;
-
- switch(State) {
- case TaskState.Initial:
- State = TaskState.Lookup;
- OnStateChange?.Invoke(this, State);
- DoLookup();
- break;
- case TaskState.Lookup:
- State = TaskState.Request;
- OnStateChange?.Invoke(this, State);
- DoRequest();
- break;
- case TaskState.Request:
- State = TaskState.Response;
- OnStateChange?.Invoke(this, State);
- DoResponse();
- break;
- case TaskState.Response:
- State = TaskState.Finished;
- OnStateChange?.Invoke(this, State);
- OnComplete?.Invoke(this, Response);
- if(DisposeResponse)
- Response?.Dispose();
- if(DisposeRequest)
- Request?.Dispose();
- return false;
- default:
- Error(new HttpTaskInvalidStateException());
- return false;
- }
-
- return true;
- }
-
- private void DoLookup() {
- try {
- Addresses = Dns.GetHostAddresses(Request.Host);
- } catch(Exception ex) {
- Error(ex);
- return;
- }
-
- if(!Addresses.Any())
- Error(new HttpTaskNoAddressesException());
- }
-
- private void DoRequest() {
- Exception exception = null;
-
- try {
- foreach(IPAddress addr in Addresses) {
- int tries = 0;
- IPEndPoint endPoint = new(addr, Request.Port);
-
- exception = null;
- Connection = Connections.GetConnection(Request.Host, endPoint, Request.IsSecure);
-
- retry:
- ++tries;
- try {
- Request.WriteTo(Connection.Stream, (p, t) => OnUploadProgress?.Invoke(this, p, t));
- break;
- } catch(IOException ex) {
- Connection.Dispose();
- Connection = Connections.GetConnection(Request.Host, endPoint, Request.IsSecure);
-
- if(tries < 2)
- goto retry;
-
- exception = ex;
- continue;
- } finally {
- Connection.MarkUsed();
- }
- }
- } catch(Exception ex) {
- Error(ex);
- }
-
- if(exception != null)
- Error(exception);
- else if(Connection == null)
- Error(new HttpTaskNoConnectionException());
- }
-
- private void DoResponse() {
- try {
- Response = HttpResponseMessage.ReadFrom(Connection.Stream, (p, t) => OnDownloadProgress?.Invoke(this, p, t));
- } catch(Exception ex) {
- Error(ex);
- return;
- }
-
- if(Response.Connection == HttpConnectionHeader.CLOSE)
- Connection.Dispose();
- if(Response == null)
- Error(new HttpTaskRequestFailedException());
-
- HttpKeepAliveHeader hkah = Response.Headers.Where(x => x.Name == HttpKeepAliveHeader.NAME).Cast().FirstOrDefault();
- if(hkah != null) {
- Connection.MaxIdle = hkah.MaxIdle;
- Connection.MaxRequests = hkah.MaxRequests;
- }
-
- Connection.Release();
- }
-
- public enum TaskState {
- Initial = 0,
- Lookup = 10,
- Request = 20,
- Response = 30,
- Finished = 40,
-
- Cancelled = -1,
- }
- }
-}
diff --git a/Hamakaze/HttpTaskManager.cs b/Hamakaze/HttpTaskManager.cs
deleted file mode 100644
index ef12439..0000000
--- a/Hamakaze/HttpTaskManager.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Threading;
-
-namespace Hamakaze {
- public class HttpTaskManager : IDisposable {
- private Semaphore Lock { get; set; }
-
- public HttpTaskManager(int maxThreads = 5) {
- Lock = new Semaphore(maxThreads, maxThreads);
- }
-
- public void RunTask(HttpTask task) {
- if(task == null)
- throw new ArgumentNullException(nameof(task));
- if(!Lock.WaitOne())
- throw new HttpTaskManagerLockException();
- new Thread(() => {
- try {
- task.Run();
- } finally {
- Lock?.Release();
- }
- }).Start();
- }
-
- private bool IsDisposed;
- ~HttpTaskManager()
- => DoDispose();
- public void Dispose() {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- private void DoDispose() {
- if(IsDisposed)
- return;
- IsDisposed = true;
- Lock.Dispose();
- Lock = null;
- }
- }
-}
diff --git a/SharpChat.sln b/SharpChat.sln
index 3230db2..75c6f6e 100644
--- a/SharpChat.sln
+++ b/SharpChat.sln
@@ -1,12 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.29025.244
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpChat", "SharpChat\SharpChat.csproj", "{DDB24C19-B802-4C96-AC15-0449C6FC77F2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpChatTest", "SharpChatTest\SharpChatTest.csproj", "{6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,10 +15,6 @@ Global
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.Build.0 = Release|Any CPU
- {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6CD6DB9D-E0FF-4DEB-8E28-0C3EA6BA26B2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SharpChat/ChatEventManager.cs b/SharpChat/ChatEventManager.cs
index 53593a7..35bc3a3 100644
--- a/SharpChat/ChatEventManager.cs
+++ b/SharpChat/ChatEventManager.cs
@@ -15,7 +15,7 @@ namespace SharpChat {
public ChatEventManager(ChatContext context) {
Context = context;
- if (!Database.HasDatabase && !WebDatabase.IsAvailable)
+ if (!Database.HasDatabase)
Events = new List();
}
@@ -27,9 +27,6 @@ namespace SharpChat {
lock(Events)
Events.Add(evt);
- if(WebDatabase.IsAvailable)
- WebDatabase.LogEvent(evt);
-
if(Database.HasDatabase)
Database.LogEvent(evt);
}
@@ -42,9 +39,6 @@ namespace SharpChat {
lock (Events)
Events.Remove(evt);
- if(WebDatabase.IsAvailable)
- WebDatabase.DeleteEvent(evt);
-
if (Database.HasDatabase)
Database.DeleteEvent(evt);
@@ -55,9 +49,6 @@ namespace SharpChat {
if (seqId < 1)
return null;
- if(WebDatabase.IsAvailable)
- return WebDatabase.GetEvent(seqId);
-
if (Database.HasDatabase)
return Database.GetEvent(seqId);
@@ -69,9 +60,6 @@ namespace SharpChat {
}
public IEnumerable GetTargetLog(IPacketTarget target, int amount = 20, int offset = 0) {
- if(WebDatabase.IsAvailable)
- return WebDatabase.GetEvents(target, amount, offset);
-
if (Database.HasDatabase)
return Database.GetEvents(target, amount, offset).Reverse();
diff --git a/SharpChat/ChatUser.cs b/SharpChat/ChatUser.cs
index 37735dc..70b2121 100644
--- a/SharpChat/ChatUser.cs
+++ b/SharpChat/ChatUser.cs
@@ -82,7 +82,6 @@ namespace SharpChat {
public string TargetName => @"@log";
- [Obsolete]
public ChatChannel Channel {
get {
lock(Channels)
@@ -94,7 +93,7 @@ namespace SharpChat {
public ChatChannel CurrentChannel { get; private set; }
public bool IsSilenced
- => SilencedUntil != null && DateTimeOffset.UtcNow - SilencedUntil <= TimeSpan.Zero;
+ => DateTimeOffset.UtcNow - SilencedUntil <= TimeSpan.Zero;
public bool HasSessions {
get {
diff --git a/SharpChat/Program.cs b/SharpChat/Program.cs
index 34c815b..e460bee 100644
--- a/SharpChat/Program.cs
+++ b/SharpChat/Program.cs
@@ -19,66 +19,12 @@ namespace SharpChat {
Console.WriteLine(@"============================================ DEBUG ==");
#endif
-#if DEBUG
- Console.WriteLine(@"HOLD A KEY TO START A TEST NOW");
- Thread.Sleep(1000);
- if (Console.KeyAvailable)
- switch (Console.ReadKey(true).Key) {
- case ConsoleKey.F:
- TestMisuzuAuth();
- return;
- }
-#endif
-
- WebDatabase.ReadConfig();
- if(!WebDatabase.IsAvailable)
- Database.ReadConfig();
+ Database.ReadConfig();
using ManualResetEvent mre = new ManualResetEvent(false);
using SockChatServer scs = new SockChatServer(PORT);
Console.CancelKeyPress += (s, e) => { e.Cancel = true; mre.Set(); };
mre.WaitOne();
}
-
-#if DEBUG
- private static void TestMisuzuAuth() {
- Console.WriteLine($@"Enter token found on {FlashiiUrls.BASE_URL}/login:");
- string[] token = Console.ReadLine().Split(new[] { '_' }, 2);
-
- System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
- httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(@"SharpChat");
-
- FlashiiAuth authRes = FlashiiAuth.Attempt(httpClient, new FlashiiAuthRequest {
- UserId = int.Parse(token[0]), Token = token[1], IPAddress = @"1.2.4.8"
- }).GetAwaiter().GetResult();
-
- if(authRes.Success) {
- Console.WriteLine(@"Auth success!");
- Console.WriteLine($@" User ID: {authRes.UserId}");
- Console.WriteLine($@" Username: {authRes.Username}");
- Console.WriteLine($@" Colour: {authRes.ColourRaw:X8}");
- Console.WriteLine($@" Hierarchy: {authRes.Rank}");
- Console.WriteLine($@" Silenced: {authRes.SilencedUntil}");
- Console.WriteLine($@" Perms: {authRes.Permissions}");
- } else {
- Console.WriteLine($@"Auth failed: {authRes.Reason}");
- return;
- }
-
- Console.WriteLine(@"Bumping last seen...");
- FlashiiBump.Submit(httpClient, new[] { new ChatUser(authRes) });
-
- Console.WriteLine(@"Fetching ban list...");
- IEnumerable bans = FlashiiBan.GetList(httpClient).GetAwaiter().GetResult();
- Console.WriteLine($@"{bans.Count()} BANS");
- foreach(FlashiiBan ban in bans) {
- Console.WriteLine($@"BAN INFO");
- Console.WriteLine($@" User ID: {ban.UserId}");
- Console.WriteLine($@" Username: {ban.Username}");
- Console.WriteLine($@" IP Address: {ban.UserIP}");
- Console.WriteLine($@" Expires: {ban.Expires}");
- }
- }
-#endif
}
}
diff --git a/SharpChat/WebDatabase.cs b/SharpChat/WebDatabase.cs
deleted file mode 100644
index 80e22d6..0000000
--- a/SharpChat/WebDatabase.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-using SharpChat.Events;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-
-namespace SharpChat {
- public static class WebDatabase {
- private static string EndPoint = null;
-
- public static bool IsAvailable
- => !string.IsNullOrWhiteSpace(EndPoint);
-
- public static void ReadConfig() {
- if(!File.Exists(@"webdb.txt"))
- return;
- string[] config = File.ReadAllLines(@"webdb.txt");
- if(config.Length < 1 && !string.IsNullOrWhiteSpace(config[0]))
- return;
- Init(config[0]);
- }
-
- public static void Init(string endPoint) {
- EndPoint = endPoint;
- }
-
- public static void Deinit() {
- EndPoint = null;
- }
-
- public static void LogEvent(IChatEvent evt) {
- if(evt.SequenceId < 1)
- evt.SequenceId = Database.GenerateId();
-
- string sId = evt.SequenceId.ToString();
- string sCreated = evt.DateTime.ToUnixTimeSeconds().ToString();
- string sType = evt.GetType().FullName;
- string sTarget = evt.Target.TargetName ?? string.Empty;
- string sFlags = ((byte)evt.Flags).ToString();
- string sData = JsonSerializer.Serialize(evt, evt.GetType());
- string sSender = evt.Sender?.UserId < 1 ? string.Empty : evt.Sender.UserId.ToString();
- string sSenderName = evt.Sender?.Username.ToString() ?? string.Empty;
- string sSenderColour = evt.Sender?.Colour.Raw.ToString() ?? string.Empty;
- string sSenderRank = evt.Sender?.Rank.ToString() ?? string.Empty;
- string sSenderNick = evt.Sender?.Nickname?.ToString() ?? string.Empty;
- string sSenderPerms = evt.Sender == null ? string.Empty : ((int)evt.Sender.Permissions).ToString();
- string sHash = string.Join('#', @"crev", sId, sCreated, sType, sTarget, sFlags, sSender, sSenderColour, sSenderRank, sSenderPerms, sSenderName, sSenderNick, sData);
-
- MultipartFormDataContent mfdc = new();
- mfdc.Add(new StringContent(sId), @"i");
- mfdc.Add(new StringContent(sCreated), @"c");
- mfdc.Add(new StringContent(sType), @"t");
- mfdc.Add(new StringContent(sTarget), @"l");
- mfdc.Add(new StringContent(sFlags), @"f");
- mfdc.Add(new StringContent(sData), @"d");
- mfdc.Add(new StringContent(sSender), @"s");
- mfdc.Add(new StringContent(sSenderName), @"su");
- mfdc.Add(new StringContent(sSenderColour), @"sc");
- mfdc.Add(new StringContent(sSenderRank), @"sr");
- mfdc.Add(new StringContent(sSenderNick), @"sn");
- mfdc.Add(new StringContent(sSenderPerms), @"sp");
-
- HttpRequestMessage request = new(HttpMethod.Post, EndPoint + @"?m=crev") {
- Content = mfdc,
- Headers = {
- { @"X-SharpChat-Signature", sHash.GetSignedHash() },
- }
- };
-
- SockChatServer.HttpClient.SendAsync(request).ContinueWith(x => {
- if(x.IsCompleted) {
- if(x.Result.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable values))
- Logger.Write($@"DBS - LogEvent: {values.FirstOrDefault()}");
- }
-
- if(x.IsFaulted)
- Logger.Write($@"DBS - LogEvent: {x.Exception}");
- }).Wait();
- }
-
- public static void DeleteEvent(IChatEvent evt) {
- string msgId = evt.SequenceId.ToString();
-
- using HttpRequestMessage request = new(HttpMethod.Delete, EndPoint + @"?m=deev&i=" + msgId) {
- Headers = {
- { @"X-SharpChat-Signature", (@"deev#" + msgId).GetSignedHash() },
- }
- };
-
- SockChatServer.HttpClient.SendAsync(request).ContinueWith(x => {
- if(x.IsCompleted) {
- if(x.Result.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable values))
- Logger.Write($@"DBS - DeleteEvent: {values.FirstOrDefault()}");
- }
-
- if(x.IsFaulted)
- Logger.Write($@"DBS - DeleteEvent: {x.Exception}");
- }).Wait();
- }
-
- private class DatabaseRow {
- [JsonPropertyName(@"i")]
- public long EventId { get; set; }
-
- [JsonPropertyName(@"s")]
- public long EventSenderId { get; set; }
-
- [JsonPropertyName(@"su")]
- public string EventSenderName { get; set; }
-
- [JsonPropertyName(@"sc")]
- public int EventSenderColour { get; set; }
-
- [JsonPropertyName(@"sr")]
- public int EventSenderRank { get; set; }
-
- [JsonPropertyName(@"sn")]
- public string EventSenderNick { get; set; }
-
- [JsonPropertyName(@"sp")]
- public int EventSenderPerms { get; set; }
-
- [JsonPropertyName(@"c")]
- public int EventCreated { get; set; }
-
- [JsonPropertyName(@"t")]
- public string EventType { get; set; }
-
- [JsonPropertyName(@"l")]
- public string EventTarget { get; set; }
-
- [JsonPropertyName(@"f")]
- public byte EventFlags { get; set; }
-
- [JsonPropertyName(@"d")]
- public string EventData { get; set; }
- }
-
- private static IChatEvent ReadEvent(DatabaseRow row, IPacketTarget target = null) {
- Type evtType = Type.GetType(row.EventType);
- IChatEvent evt = JsonSerializer.Deserialize(row.EventData, evtType) as IChatEvent;
- evt.SequenceId = row.EventId;
- evt.Target = target;
- evt.TargetName = target?.TargetName ?? row.EventTarget;
- evt.Flags = (ChatMessageFlags)row.EventFlags;
- evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(row.EventCreated);
-
- if(row.EventSenderId > 0) {
- evt.Sender = new BasicUser {
- UserId = row.EventSenderId,
- Username = row.EventSenderName,
- Colour = new ChatColour(row.EventSenderColour),
- Rank = row.EventSenderRank,
- Nickname = string.IsNullOrEmpty(row.EventSenderNick) ? null : row.EventSenderNick,
- Permissions = (ChatUserPermissions)row.EventSenderPerms
- };
- }
-
- return evt;
- }
-
- public static IChatEvent GetEvent(long seqId) {
- string sSeqId = seqId.ToString();
-
- using HttpRequestMessage request = new(HttpMethod.Get, EndPoint + @"?m=geev&i=" + sSeqId) {
- Headers = {
- { @"X-SharpChat-Signature", (@"geev#" + sSeqId).GetSignedHash() },
- }
- };
-
- // jesus christ what is this
- System.Runtime.CompilerServices.TaskAwaiter? awaiter = null;
- HttpResponseMessage response = null;
-
- try {
- awaiter = SockChatServer.HttpClient.SendAsync(request).GetAwaiter();
- response = awaiter.Value.GetResult();
-
- byte[] garbage = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
-
- return ReadEvent(
- (DatabaseRow)JsonSerializer.Deserialize(garbage, typeof(DatabaseRow))
- );
- } catch(Exception ex) {
- Logger.Write($@"DBS - GetEvent: {ex}");
- } finally {
- if(awaiter.HasValue && awaiter.Value.IsCompleted) {
- if(response != null && response.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable values))
- Logger.Write($@"DBS - GetEvent: {values.FirstOrDefault()}");
- }
- }
-
- return null;
- }
-
- public static IEnumerable GetEvents(IPacketTarget target, int amount, int offset) {
- List events = new();
-
- using HttpRequestMessage request = new(HttpMethod.Get, EndPoint + @"?m=feev&l=" + target.TargetName + @"&a=" + amount + @"&o=" + offset) {
- Headers = {
- { @"X-SharpChat-Signature", string.Join('#', @"feev", amount, offset, target.TargetName).GetSignedHash() },
- }
- };
-
- System.Runtime.CompilerServices.TaskAwaiter? awaiter = null;
- HttpResponseMessage response = null;
-
- try {
- awaiter = SockChatServer.HttpClient.SendAsync(request).GetAwaiter();
- response = awaiter.Value.GetResult();
-
- byte[] trash = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
-
- IEnumerable rows = (IEnumerable)JsonSerializer.Deserialize(trash, typeof(IEnumerable));
-
- foreach(DatabaseRow row in rows)
- events.Add(ReadEvent(row, target));
- } catch(Exception ex) {
- Logger.Write($@"DBS - GetEvents: {ex}");
- } finally {
- if(awaiter.HasValue && awaiter.Value.IsCompleted) {
- if(response != null && response.Headers.TryGetValues(@"X-SharpChat-Error", out IEnumerable values))
- Logger.Write($@"DBS - GetEvents: {values.FirstOrDefault()}");
- }
- }
-
- return events;
- }
- }
-}