dev #1
@ -5,8 +5,6 @@ VisualStudioVersion = 17.0.31717.71
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luski.net", "Luski.net\Luski.net.csproj", "{3DF9B870-51B3-4338-84EC-75E4B8802F0C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luski.net", "Luski.net\Luski.net.csproj", "{3DF9B870-51B3-4338-84EC-75E4B8802F0C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luski.net.tests", "Luski.net.tests\Luski.net.tests.csproj", "{FCA149C8-379B-454A-962A-856F30965C4E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -17,10 +15,6 @@ Global
|
|||||||
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{3DF9B870-51B3-4338-84EC-75E4B8802F0C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{FCA149C8-379B-454A-962A-856F30965C4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FCA149C8-379B-454A-962A-856F30965C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FCA149C8-379B-454A-962A-856F30965C4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FCA149C8-379B-454A-962A-856F30965C4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
36
Luski.net/API.cs
Normal file
36
Luski.net/API.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Luski.net.Structures.Main;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
|
|
||||||
|
namespace Luski.net;
|
||||||
|
|
||||||
|
public class API
|
||||||
|
{
|
||||||
|
public Server<MainSocketAppUser> MainServer { get; internal set; }
|
||||||
|
internal List<Server<PublicSocketAppUser>> InternalServers { get; } = new();
|
||||||
|
public IReadOnlyList<Server<PublicSocketAppUser>> LoadedServers => InternalServers.AsReadOnly();
|
||||||
|
|
||||||
|
public Server<PublicSocketAppUser> GetPublicServer(string Domain, string Version = "v1")
|
||||||
|
{
|
||||||
|
IEnumerable<Server<PublicSocketAppUser>> isl = InternalServers.Where(a => (a.Domain == Domain && a.ApiVersion == Version));
|
||||||
|
if (isl.Any()) return isl.First();
|
||||||
|
Server<PublicSocketAppUser> s = new()
|
||||||
|
{
|
||||||
|
Domain = Domain,
|
||||||
|
ApiVersion = Version,
|
||||||
|
};
|
||||||
|
InternalServers.Add(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Server<MainSocketAppUser> GetMainServer(string Domain, string Version = "v1")
|
||||||
|
{
|
||||||
|
MainServer = new()
|
||||||
|
{
|
||||||
|
Domain = Domain,
|
||||||
|
ApiVersion = Version,
|
||||||
|
};
|
||||||
|
return MainServer;
|
||||||
|
}
|
||||||
|
}
|
@ -3,15 +3,16 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using JacobTechEncryption;
|
||||||
|
|
||||||
namespace Luski.net
|
namespace Luski.net
|
||||||
{
|
{
|
||||||
public static class Encryption
|
public static class ClientEncryption
|
||||||
{
|
{
|
||||||
internal static string? MyPublicKey;
|
internal static string? MyPublicKey;
|
||||||
internal static readonly UnicodeEncoding Encoder = new();
|
internal static readonly UnicodeEncoding Encoder = new();
|
||||||
@ -23,14 +24,6 @@ namespace Luski.net
|
|||||||
internal static string? outofkey = null;
|
internal static string? outofkey = null;
|
||||||
internal static string pw = "";
|
internal static string pw = "";
|
||||||
public static int NewKeySize = 4096;
|
public static int NewKeySize = 4096;
|
||||||
internal static string ServerPublicKey
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_serverpublickey is null) _serverpublickey = new HttpClient().GetAsync($"https://{Server.InternalDomain}/{Server.API_Ver}/Keys/PublicKey").Result.Content.ReadAsStringAsync().Result;
|
|
||||||
return _serverpublickey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void GenerateKeys()
|
public static void GenerateKeys()
|
||||||
{
|
{
|
||||||
@ -43,7 +36,7 @@ namespace Luski.net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void GenerateNewKeys(out string Public, out string Private)
|
public static void GenerateNewKeys(out string Public, out string Private)
|
||||||
{
|
{
|
||||||
using RSACryptoServiceProvider r = new(NewKeySize);
|
using RSACryptoServiceProvider r = new(NewKeySize);
|
||||||
Private = r.ToXmlString(true);
|
Private = r.ToXmlString(true);
|
||||||
@ -55,16 +48,22 @@ namespace Luski.net
|
|||||||
{
|
{
|
||||||
internal static void SetOfflineKey(string key)
|
internal static void SetOfflineKey(string key)
|
||||||
{
|
{
|
||||||
MakeFile(Server.GetKeyFilePath, pw);
|
MakeFile("Server.GetKeyFilePath", pw);
|
||||||
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString(Server.GetKeyFilePath, pw));
|
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
|
||||||
fileLayout.OfflineKey = key;
|
fileLayout.OfflineKey = key;
|
||||||
fileLayout.Save(Server.GetKeyFilePath, pw);
|
fileLayout.Save("Server.GetKeyFilePath", pw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LuskiDataFile GetFile()
|
||||||
|
{
|
||||||
|
MakeFile("Server.GetKeyFilePath", pw);
|
||||||
|
return JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw))!;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string? GetOfflineKey()
|
internal static string? GetOfflineKey()
|
||||||
{
|
{
|
||||||
MakeFile(Server.GetKeyFilePath, pw);
|
MakeFile("Server.GetKeyFilePath", pw);
|
||||||
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString(Server.GetKeyFilePath, pw));
|
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
|
||||||
return fileLayout?.OfflineKey;
|
return fileLayout?.OfflineKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,32 +121,13 @@ namespace Luski.net
|
|||||||
#pragma warning disable CS8603 // Possible null reference return.
|
#pragma warning disable CS8603 // Possible null reference return.
|
||||||
if (channel == 0) return myPrivateKey;
|
if (channel == 0) return myPrivateKey;
|
||||||
#pragma warning restore CS8603 // Possible null reference return.
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
MakeFile(Server.GetKeyFilePath, pw);
|
MakeFile("Server.GetKeyFilePath", pw);
|
||||||
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString(Server.GetKeyFilePath, pw));
|
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
|
||||||
lis = fileLayout?.channels?.Where(s => s.id == channel);
|
lis = fileLayout?.channels?.Where(s => s.id == channel);
|
||||||
if (lis?.Count() > 0)
|
if (lis?.Count() > 0)
|
||||||
{
|
{
|
||||||
return lis.First().key;
|
return lis.First().key;
|
||||||
}
|
}
|
||||||
foreach (Branch b in (Branch[])Enum.GetValues(typeof(Branch)))
|
|
||||||
{
|
|
||||||
if (b != Server.Branch)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string temp = GetKeyBranch(channel, b);
|
|
||||||
if (temp is not null)
|
|
||||||
{
|
|
||||||
AddKey(channel, temp);
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Exception("You dont have a key for that channel");
|
throw new Exception("You dont have a key for that channel");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -157,7 +137,7 @@ namespace Luski.net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetKeyBranch(long channel, Branch branch)
|
internal static string GetKeyBranch(long channel)
|
||||||
{
|
{
|
||||||
LuskiDataFile? fileLayout;
|
LuskiDataFile? fileLayout;
|
||||||
IEnumerable<ChannelLayout>? lis;
|
IEnumerable<ChannelLayout>? lis;
|
||||||
@ -166,8 +146,8 @@ namespace Luski.net
|
|||||||
#pragma warning disable CS8603 // Possible null reference return.
|
#pragma warning disable CS8603 // Possible null reference return.
|
||||||
if (channel == 0) return myPrivateKey;
|
if (channel == 0) return myPrivateKey;
|
||||||
#pragma warning restore CS8603 // Possible null reference return.
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
MakeFile(Server.GetKeyFilePathBr(branch.ToString()), pw);
|
MakeFile("Server.GetKeyFilePathBr(branch.ToString())", pw);
|
||||||
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString(Server.GetKeyFilePathBr(branch.ToString()), pw));
|
fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("", pw));
|
||||||
lis = fileLayout?.channels?.Where(s => s.id == channel);
|
lis = fileLayout?.channels?.Where(s => s.id == channel);
|
||||||
if (lis?.Count() > 0)
|
if (lis?.Count() > 0)
|
||||||
{
|
{
|
||||||
@ -184,10 +164,10 @@ namespace Luski.net
|
|||||||
|
|
||||||
public static void AddKey(long channel, string key)
|
public static void AddKey(long channel, string key)
|
||||||
{
|
{
|
||||||
MakeFile(Server.GetKeyFilePath, pw);
|
MakeFile("Server.GetKeyFilePath", pw);
|
||||||
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString(Server.GetKeyFilePath, pw));
|
LuskiDataFile? fileLayout = JsonSerializer.Deserialize<LuskiDataFile>(FileString("Server.GetKeyFilePath", pw));
|
||||||
fileLayout?.Addchannelkey(channel, key);
|
fileLayout?.Addchannelkey(channel, key);
|
||||||
fileLayout?.Save(Server.GetKeyFilePath, pw);
|
fileLayout?.Save("Server.GetKeyFilePath", pw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +190,7 @@ namespace Luski.net
|
|||||||
|
|
||||||
internal static LuskiDataFile GetDefualtDataFile()
|
internal static LuskiDataFile GetDefualtDataFile()
|
||||||
{
|
{
|
||||||
return GetDataFile(Server.GetKeyFilePath, pw);
|
return GetDataFile("Server.GetKeyFilePath", pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChannelLayout[]? channels { get; set; } = default!;
|
public ChannelLayout[]? channels { get; set; } = default!;
|
||||||
@ -273,6 +253,17 @@ namespace Luski.net
|
|||||||
chans?.Add(l);
|
chans?.Add(l);
|
||||||
channels = chans?.ToArray();
|
channels = chans?.ToArray();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chans.Remove(chans.Where(s => s.id == chan).First());
|
||||||
|
ChannelLayout l = new()
|
||||||
|
{
|
||||||
|
id = chan,
|
||||||
|
key = Key
|
||||||
|
};
|
||||||
|
chans?.Add(l);
|
||||||
|
channels = chans?.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +273,7 @@ namespace Luski.net
|
|||||||
public string key { get; set; } = default!;
|
public string key { get; set; } = default!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
public class AES
|
public class AES
|
||||||
{
|
{
|
||||||
public static string Encrypt(string path, string Password)
|
public static string Encrypt(string path, string Password)
|
||||||
@ -353,7 +344,7 @@ namespace Luski.net
|
|||||||
cs.Dispose();
|
cs.Dispose();
|
||||||
fsCrypt.Close();
|
fsCrypt.Close();
|
||||||
fsCrypt.Dispose();
|
fsCrypt.Dispose();
|
||||||
NewPath = p;*/
|
NewPath = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Decrypt(byte[] data, string Password, string File)
|
public static void Decrypt(byte[] data, string Password, string File)
|
||||||
@ -387,7 +378,7 @@ namespace Luski.net
|
|||||||
fsOut.Dispose();
|
fsOut.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
internal const int PasswordVersion = 0;
|
internal const int PasswordVersion = 0;
|
||||||
|
|
||||||
internal static byte[] LocalPasswordEncrypt(byte[] Password, int PasswordVersion = PasswordVersion)
|
internal static byte[] LocalPasswordEncrypt(byte[] Password, int PasswordVersion = PasswordVersion)
|
||||||
@ -403,10 +394,15 @@ namespace Luski.net
|
|||||||
{
|
{
|
||||||
return PasswordVersion switch
|
return PasswordVersion switch
|
||||||
{
|
{
|
||||||
0 => Convert.ToBase64String(Encrypt(LocalPasswordEncrypt(Password, PasswordVersion))),
|
0 => Convert.ToBase64String(Encryption.RSA.Encrypt(LocalPasswordEncrypt(Password, PasswordVersion), MyPublicKey)),
|
||||||
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
|
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
public static byte[] Hash(byte[] data)
|
||||||
|
{
|
||||||
|
return SHA256.Create().ComputeHash(data);
|
||||||
|
}
|
||||||
|
|
||||||
internal static byte[] Encrypt(string data)
|
internal static byte[] Encrypt(string data)
|
||||||
{
|
{
|
||||||
@ -427,7 +423,7 @@ namespace Luski.net
|
|||||||
{
|
{
|
||||||
using RSACryptoServiceProvider rsa = new();
|
using RSACryptoServiceProvider rsa = new();
|
||||||
rsa.FromXmlString(key);
|
rsa.FromXmlString(key);
|
||||||
int size = rsa.KeySize / 8;
|
int size = ((rsa.KeySize - 384) / 8) + 7;
|
||||||
double x = data.Length / (double)size;
|
double x = data.Length / (double)size;
|
||||||
int bbb = int.Parse(x.ToString().Split('.')[0]);
|
int bbb = int.Parse(x.ToString().Split('.')[0]);
|
||||||
if (x.ToString().Contains('.')) bbb++;
|
if (x.ToString().Contains('.')) bbb++;
|
||||||
@ -443,7 +439,7 @@ namespace Luski.net
|
|||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
decccc[i] = rsa.Encrypt(data.Skip(i * size).Take(size).ToArray(), false);
|
decccc[i] = rsa.Encrypt(data.Skip(i * size).Take(size).ToArray(), true);
|
||||||
});
|
});
|
||||||
foreach (byte[] dataa in decccc)
|
foreach (byte[] dataa in decccc)
|
||||||
{
|
{
|
||||||
@ -495,7 +491,7 @@ namespace Luski.net
|
|||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
decccc[i] = rsa.Decrypt(EncryptedText.Skip(i * size).Take(size).ToArray(), false);
|
decccc[i] = rsa.Decrypt(EncryptedText.Skip(i * size).Take(size).ToArray(), true);
|
||||||
});
|
});
|
||||||
foreach (byte[] data in decccc)
|
foreach (byte[] data in decccc)
|
||||||
{
|
{
|
||||||
@ -510,6 +506,6 @@ namespace Luski.net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return datasplitout;
|
return datasplitout;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +0,0 @@
|
|||||||
namespace Luski.net.Enums;
|
|
||||||
|
|
||||||
public enum Branch : short
|
|
||||||
{
|
|
||||||
Dev,
|
|
||||||
Beta,
|
|
||||||
Master,
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
namespace Luski.net.Enums;
|
namespace Luski.net.Enums;
|
||||||
|
|
||||||
internal enum DataType
|
public enum DataType
|
||||||
{
|
{
|
||||||
Message_Create,
|
Message_Create,
|
||||||
Status_Update,
|
Status_Update,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
namespace Luski.net.Enums;
|
namespace Luski.net.Enums.Main;
|
||||||
|
|
||||||
public enum ChannelType : short
|
public enum ChannelType : short
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace Luski.net.Enums;
|
namespace Luski.net.Enums.Main;
|
||||||
|
|
||||||
public enum FriendStatus
|
public enum FriendStatus
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Luski.net.Enums;
|
namespace Luski.net.Enums.Main;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum UserFlag : short
|
public enum UserFlag : short
|
6
Luski.net/Enums/Public/ChannelType.cs
Executable file
6
Luski.net/Enums/Public/ChannelType.cs
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Luski.net.Enums.Public;
|
||||||
|
|
||||||
|
public enum ChannelType : short
|
||||||
|
{
|
||||||
|
TextAndVoice = 0
|
||||||
|
}
|
9
Luski.net/Enums/ServerType.cs
Normal file
9
Luski.net/Enums/ServerType.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Luski.net.Enums;
|
||||||
|
|
||||||
|
public enum ServerType : byte
|
||||||
|
{
|
||||||
|
Public = 0,
|
||||||
|
Main = 1,
|
||||||
|
PublicSub = 2,
|
||||||
|
MainSub = 3
|
||||||
|
}
|
11
Luski.net/Interfaces/IAppUser.cs
Normal file
11
Luski.net/Interfaces/IAppUser.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
|
|
||||||
|
namespace Luski.net.Interfaces;
|
||||||
|
|
||||||
|
public interface IAppUser : IUser
|
||||||
|
{
|
||||||
|
public ErrorCode? Error { get; }
|
||||||
|
public string? ErrorMessage { get; }
|
||||||
|
public string Username { get; }
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
using Luski.net.Sound;
|
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static Luski.net.Exceptions;
|
|
||||||
|
|
||||||
namespace Luski.net.Interfaces;
|
|
||||||
|
|
||||||
public interface IAudioClient
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// the event is fired when your <see cref="IAudioClient"/> has joined the call
|
|
||||||
/// </summary>
|
|
||||||
event Func<Task> Connected;
|
|
||||||
/// <summary>
|
|
||||||
/// Tells you if you are muted
|
|
||||||
/// </summary>
|
|
||||||
bool Muted { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Tells you if you are deafned
|
|
||||||
/// </summary>
|
|
||||||
bool Deafened { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Toggles if you are speaking to your friends
|
|
||||||
/// </summary>
|
|
||||||
void ToggleMic();
|
|
||||||
/// <summary>
|
|
||||||
/// Toggles if you can hear audio
|
|
||||||
/// </summary>
|
|
||||||
void ToggleAudio();
|
|
||||||
/// <summary>
|
|
||||||
/// Changes what <see cref="RecordingDevice"/> the call gets its data from
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Device">This is the <see cref="RecordingDevice"/> you want to recored from</param>
|
|
||||||
/// <exception cref="NotConnectedException"></exception>
|
|
||||||
void RecordSoundFrom(RecordingDevice Device);
|
|
||||||
/// <summary>
|
|
||||||
/// Changes what <see cref="PlaybackDevice"/> the call gets its data from
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Device">This is the <see cref="PlaybackDevice"/> you want to heare outhers</param>
|
|
||||||
/// <exception cref="NotConnectedException"></exception>
|
|
||||||
void PlaySoundTo(PlaybackDevice Device);
|
|
||||||
/// <summary>
|
|
||||||
/// Joins the Voice call
|
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="MissingEventException"></exception>
|
|
||||||
void JoinCall();
|
|
||||||
void LeaveCall();
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Luski.net.Interfaces;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="ITextChannel"/> contains a list of variables that all channels from luski have
|
|
||||||
/// </summary>
|
|
||||||
public interface ITextChannel
|
|
||||||
{
|
|
||||||
long Id { get; }
|
|
||||||
string Title { get; }
|
|
||||||
string Description { get; }
|
|
||||||
string Key { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="ITextChannel.Type"/> returns the current <see cref="ChannelType"/> of the <see cref="ITextChannel"/>
|
|
||||||
/// </summary>
|
|
||||||
ChannelType Type { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Sends a <paramref name="Message"/> to the server for the currently selected <see cref="ITextChannel"/>
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Message">The messate you want to send to the server</param>
|
|
||||||
Task<Task> SendMessage(string Message, params File[] Files);
|
|
||||||
Task<Task> SendKeysToUsers();
|
|
||||||
Task<SocketMessage> GetMessage(long ID);
|
|
||||||
Task<IReadOnlyList<SocketMessage>> GetMessages(long Message_Id, int count = 50);
|
|
||||||
Task<IReadOnlyList<SocketMessage>> GetMessages(int count = 50);
|
|
||||||
Task<byte[]> GetPicture();
|
|
||||||
IReadOnlyList<IUser> Members { get; }
|
|
||||||
}
|
|
38
Luski.net/Interfaces/IServer.cs
Normal file
38
Luski.net/Interfaces/IServer.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using Luski.net.Structures;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
|
|
||||||
|
namespace Luski.net.Interfaces;
|
||||||
|
|
||||||
|
public interface IServer
|
||||||
|
{
|
||||||
|
public IAppUser IAppUser { get; }
|
||||||
|
public string Cache { get; }
|
||||||
|
public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS;
|
||||||
|
|
||||||
|
public HttpResponseMessage GetFromServer(string Path, CancellationToken CancellationToken,
|
||||||
|
params KeyValuePair<string, string?>[] Headers);
|
||||||
|
|
||||||
|
public Task GetFromServer(string Path, string File, CancellationToken CancellationToken,
|
||||||
|
params KeyValuePair<string, string?>[] Headers);
|
||||||
|
|
||||||
|
public Task<Tresult> GetFromServer<Tresult>(string Path, JsonTypeInfo<Tresult> Type,
|
||||||
|
CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
|
where Tresult : IncomingHTTP, new();
|
||||||
|
|
||||||
|
public Task<Tresult> SendServer<Tvalue, Tresult>(string Path, Tvalue Payload,
|
||||||
|
JsonTypeInfo<Tvalue> jsonTypeInfo, JsonTypeInfo<Tresult> ReturnjsonTypeInfo,
|
||||||
|
CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
|
where Tvalue : IWebRequest where Tresult : IncomingHTTP, new();
|
||||||
|
|
||||||
|
public Task<Tresult> SendServer<Tresult>(string Path, string File, JsonTypeInfo<Tresult> ReturnjsonTypeInfo,
|
||||||
|
CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
|
where Tresult : IncomingHTTP, new();
|
||||||
|
public Task<Tuser> GetUser<Tuser>(long UserID, CancellationToken CancellationToken) where Tuser : SocketUserBase, new();
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
using Luski.net.Enums;
|
using System.Threading;
|
||||||
|
using Luski.net.Enums;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
|
||||||
namespace Luski.net.Interfaces;
|
namespace Luski.net.Interfaces;
|
||||||
|
|
||||||
@ -15,12 +17,7 @@ public interface IUser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cerrent username of the user
|
/// The cerrent username of the user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Username { get; }
|
string DisplayName { get; }
|
||||||
/// <summary>
|
|
||||||
/// The current tag for the user
|
|
||||||
/// <para>Ex: #1234</para>
|
|
||||||
/// </summary>
|
|
||||||
//short Tag { get; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current status of the user
|
/// The current status of the user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,16 +27,16 @@ public interface IUser
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
PictureType PictureType { get; }
|
PictureType PictureType { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the current flags of a user
|
|
||||||
/// </summary>
|
|
||||||
UserFlag Flags { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the current avatar of the user
|
/// Gets the current avatar of the user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<byte[]> GetAvatar();
|
Task<byte[]> GetAvatar(CancellationToken CancellationToken);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current user key
|
/// Gets the current user key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string> GetUserKey();
|
Task<long> GetUserKey(CancellationToken CancellationToken);
|
||||||
|
/// <summary>
|
||||||
|
/// The server that the user comes from
|
||||||
|
/// </summary>
|
||||||
|
IServer Server { get; }
|
||||||
}
|
}
|
||||||
|
6
Luski.net/Interfaces/IWebRequest.cs
Normal file
6
Luski.net/Interfaces/IWebRequest.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Luski.net.Interfaces;
|
||||||
|
|
||||||
|
public interface IWebRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Luski.net.Enums;
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes.BaseTypes;
|
namespace Luski.net.JsonTypes.BaseTypes;
|
||||||
|
|
||||||
internal class HTTPRequest
|
internal class HTTPRequest : IWebRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("data_type")]
|
[JsonPropertyName("data_type")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
|
@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace Luski.net.JsonTypes.BaseTypes;
|
namespace Luski.net.JsonTypes.BaseTypes;
|
||||||
|
|
||||||
internal class IncomingWSS
|
public class IncomingWSS
|
||||||
{
|
{
|
||||||
[JsonPropertyName("type")]
|
[JsonPropertyName("type")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
@ -18,7 +18,7 @@ internal class IncomingWSS
|
|||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
||||||
WriteIndented = false)]
|
WriteIndented = false)]
|
||||||
internal partial class IncomingWSSContext : JsonSerializerContext
|
public partial class IncomingWSSContext : JsonSerializerContext
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.Interfaces;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Text.Json.Serialization.Metadata;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes.BaseTypes;
|
|
||||||
|
|
||||||
[Browsable(false)]
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public abstract class SocketUserBase : IncomingHTTP, IUser
|
|
||||||
{
|
|
||||||
[JsonPropertyName("id")]
|
|
||||||
[JsonInclude]
|
|
||||||
public long Id { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("username")]
|
|
||||||
[JsonInclude]
|
|
||||||
public string Username { get; internal set; } = default!;
|
|
||||||
// [JsonPropertyName("tag")]
|
|
||||||
//[JsonInclude]
|
|
||||||
//public short Tag { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("status")]
|
|
||||||
[JsonInclude]
|
|
||||||
public UserStatus Status { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("picture_type")]
|
|
||||||
[JsonInclude]
|
|
||||||
public PictureType PictureType { get; internal set; } = default!;
|
|
||||||
|
|
||||||
[JsonPropertyName("flags")]
|
|
||||||
[JsonInclude]
|
|
||||||
public UserFlag Flags { get; internal set; } = default!;
|
|
||||||
|
|
||||||
public async Task<byte[]> GetAvatar()
|
|
||||||
{
|
|
||||||
if (Server.Cache != null)
|
|
||||||
{
|
|
||||||
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}");
|
|
||||||
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}");
|
|
||||||
}
|
|
||||||
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<string> GetUserKey()
|
|
||||||
{
|
|
||||||
if (Server._user is null) throw new Exception("you are not loged in");
|
|
||||||
if (Id == Server._user.Id && Encryption.MyPublicKey is not null) return Task.FromResult(Encryption.MyPublicKey);
|
|
||||||
string data = Server.GetFromServer($"Keys/GetUserKey/{Id}").Content.ReadAsStringAsync().Result;
|
|
||||||
return Task.FromResult(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static async Task<TUser> GetUser<TUser>(long UserId, JsonTypeInfo<TUser> Json) where TUser : SocketUserBase, new()
|
|
||||||
{
|
|
||||||
TUser user;
|
|
||||||
if (Server.poeople is null) Server.poeople = new();
|
|
||||||
if (Server.poeople.Count > 0 && Server.poeople.Any(s => s.Id == UserId))
|
|
||||||
{
|
|
||||||
TUser temp = Server.poeople.Where(s => s is TUser && s.Id == UserId).Cast<TUser>().FirstOrDefault()!;
|
|
||||||
if (temp is SocketRemoteUser && (temp as SocketRemoteUser)!.Channel == null)
|
|
||||||
{
|
|
||||||
foreach (SocketDMChannel chan in Server.chans.Where(s => s is SocketDMChannel).Cast<SocketDMChannel>())
|
|
||||||
{
|
|
||||||
if (chan.Type == ChannelType.DM && chan.Id != 0 && chan.MemberIdList is not null)
|
|
||||||
{
|
|
||||||
if (chan.MemberIdList.Any(s => s == UserId)) (temp as SocketRemoteUser)!.Channel = chan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return temp!;
|
|
||||||
}
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Server.CanRequest)
|
|
||||||
{
|
|
||||||
user = await Server.GetFromServer("socketuser",
|
|
||||||
Json,
|
|
||||||
new System.Collections.Generic.KeyValuePair<string, string?>("id", UserId.ToString()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user is null) throw new Exception("Server did not return a user");
|
|
||||||
if (Server.poeople.Count > 0 && Server.poeople.Any(s => s.Id == UserId))
|
|
||||||
{
|
|
||||||
foreach (IUser? p in Server.poeople.Where(s => s.Id == UserId))
|
|
||||||
{
|
|
||||||
Server.poeople.Remove(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Server._user is not null && UserId != 0 && UserId != Server._user.Id)
|
|
||||||
{
|
|
||||||
foreach (SocketDMChannel chan in Server.chans.Where(s => s is SocketDMChannel).Cast<SocketDMChannel>())
|
|
||||||
{
|
|
||||||
if (chan.Id != 0 && chan.MemberIdList is not null)
|
|
||||||
{
|
|
||||||
if (chan.MemberIdList.Any(s => s == UserId)) (user as SocketRemoteUser)!.Channel = chan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Server.poeople.Add(user);
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketUserBase))]
|
|
||||||
[JsonSourceGenerationOptions(
|
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
|
||||||
WriteIndented = false,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
|
|
||||||
internal partial class SocketUserBaseContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -5,18 +5,12 @@ namespace Luski.net.JsonTypes.HTTP;
|
|||||||
|
|
||||||
internal class FriendRequest : HTTPRequest
|
internal class FriendRequest : HTTPRequest
|
||||||
{
|
{
|
||||||
|
[JsonPropertyName("code")]
|
||||||
|
[JsonInclude]
|
||||||
|
public string code { get; set; } = default!;
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public long Id { get; set; } = default!;
|
public long Id { get; set; } = default!;
|
||||||
[JsonPropertyName("subtype")]
|
|
||||||
[JsonInclude]
|
|
||||||
public int SubType { get; set; } = default!;
|
|
||||||
[JsonPropertyName("username")]
|
|
||||||
[JsonInclude]
|
|
||||||
public string Username { get; set; } = default!;
|
|
||||||
[JsonPropertyName("tag")]
|
|
||||||
[JsonInclude]
|
|
||||||
public short Tag { get; set; } = default!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(FriendRequest))]
|
[JsonSerializable(typeof(FriendRequest))]
|
||||||
|
21
Luski.net/JsonTypes/OfflineData.cs
Normal file
21
Luski.net/JsonTypes/OfflineData.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
|
||||||
|
namespace Luski.net.JsonTypes;
|
||||||
|
|
||||||
|
public class OfflineData : IncomingHTTP
|
||||||
|
{
|
||||||
|
[JsonPropertyName("data")]
|
||||||
|
[JsonInclude]
|
||||||
|
public string[]? Data { get; internal set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(OfflineData))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
|
WriteIndented = false)]
|
||||||
|
internal partial class OfflineDataContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,178 +0,0 @@
|
|||||||
using Luski.net.Interfaces;
|
|
||||||
using Luski.net.JsonTypes.BaseTypes;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
|
||||||
|
|
||||||
public class SocketAppUser : SocketUserBase
|
|
||||||
{
|
|
||||||
[JsonPropertyName("email")]
|
|
||||||
[JsonInclude]
|
|
||||||
public string Email { get; internal set; } = default!;
|
|
||||||
[JsonIgnore]
|
|
||||||
public IReadOnlyList<SocketChannel> Channels
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_Channels is null || ChannelIdList is not null)
|
|
||||||
{
|
|
||||||
if (ChannelIdList.Length != 0)
|
|
||||||
{
|
|
||||||
_Channels = new List<SocketChannel>();
|
|
||||||
foreach (long channel in ChannelIdList)
|
|
||||||
{
|
|
||||||
SocketChannel s = SocketChannel.GetChannel(channel, SocketChannelContext.Default.SocketChannel).Result;
|
|
||||||
Server.chans.Remove(s);
|
|
||||||
switch (s.Type)
|
|
||||||
{
|
|
||||||
case Enums.ChannelType.GROUP:
|
|
||||||
_Channels.Add(SocketChannel.GetChannel(channel, SocketGroupChannelContext.Default.SocketGroupChannel).Result);
|
|
||||||
break;
|
|
||||||
case Enums.ChannelType.DM:
|
|
||||||
_Channels.Add(SocketChannel.GetChannel(channel, SocketDMChannelContext.Default.SocketDMChannel).Result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else _Channels = new List<SocketChannel>();
|
|
||||||
}
|
|
||||||
return _Channels.AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[JsonIgnore]
|
|
||||||
public IReadOnlyList<SocketRemoteUser> FriendRequests
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_FriendRequests is null || FriendRequestsRaw is not null)
|
|
||||||
{
|
|
||||||
_FriendRequests = new();
|
|
||||||
if (ChannelIdList.Length != 0 && FriendRequestsRaw is not null)
|
|
||||||
{
|
|
||||||
foreach (FR person in FriendRequestsRaw)
|
|
||||||
{
|
|
||||||
//_Friends.Add(SocketRemoteUser.GetUser(person));
|
|
||||||
long id = person.user_id == Id ? person.from : person.user_id;
|
|
||||||
SocketRemoteUser frq = GetUser(id, SocketRemoteUserContext.Default.SocketRemoteUser).Result;
|
|
||||||
_FriendRequests.Add(frq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else _FriendRequests = new();
|
|
||||||
}
|
|
||||||
return _FriendRequests.AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[JsonIgnore]
|
|
||||||
public IReadOnlyList<SocketRemoteUser> Friends
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_Friends is null || FriendIdList is not null)
|
|
||||||
{
|
|
||||||
if (ChannelIdList.Length != 0)
|
|
||||||
{
|
|
||||||
_Friends = new List<SocketRemoteUser>();
|
|
||||||
foreach (long person in FriendIdList)
|
|
||||||
{
|
|
||||||
_Friends.Add(GetUser(person, SocketRemoteUserContext.Default.SocketRemoteUser).Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else _Friends = new List<SocketRemoteUser>();
|
|
||||||
}
|
|
||||||
return _Friends.AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[JsonPropertyName("selected_channel")]
|
|
||||||
[JsonInclude]
|
|
||||||
public long SelectedChannel { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("channels")]
|
|
||||||
[JsonInclude]
|
|
||||||
public long[] ChannelIdList { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("friends")]
|
|
||||||
[JsonInclude]
|
|
||||||
public long[] FriendIdList { get; internal set; } = default!;
|
|
||||||
[JsonPropertyName("friend_requests")]
|
|
||||||
[JsonInclude]
|
|
||||||
public FR[] FriendRequestsRaw { get; internal set; } = default!;
|
|
||||||
[JsonIgnore]
|
|
||||||
private List<SocketChannel> _Channels = default!;
|
|
||||||
[JsonIgnore]
|
|
||||||
private List<SocketRemoteUser> _Friends = default!;
|
|
||||||
[JsonIgnore]
|
|
||||||
private List<SocketRemoteUser> _FriendRequests = default!;
|
|
||||||
|
|
||||||
public class FR
|
|
||||||
{
|
|
||||||
public long from { get; set; } = default!;
|
|
||||||
public long user_id { get; set; } = default!;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddFriend(SocketRemoteUser User)
|
|
||||||
{
|
|
||||||
if (Server.poeople.Any(s => s.Id == User.Id))
|
|
||||||
{
|
|
||||||
IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
|
|
||||||
foreach (IUser item in b)
|
|
||||||
{
|
|
||||||
Server.poeople.Remove(item);
|
|
||||||
}
|
|
||||||
Server.poeople.Add(User);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Server.poeople.Add(User);
|
|
||||||
}
|
|
||||||
_Friends.Add(User);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RemoveFriendRequest(SocketRemoteUser User)
|
|
||||||
{
|
|
||||||
if (Server.poeople.Any(s => s.Id == User.Id))
|
|
||||||
{
|
|
||||||
IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
|
|
||||||
foreach (IUser item in b)
|
|
||||||
{
|
|
||||||
Server.poeople.Remove(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Server.poeople.Add(User);
|
|
||||||
foreach (SocketRemoteUser user in _FriendRequests)
|
|
||||||
{
|
|
||||||
if (User.Id == user.Id)
|
|
||||||
{
|
|
||||||
_FriendRequests.Remove(User);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddFriendRequest(SocketRemoteUser User)
|
|
||||||
{
|
|
||||||
if (Server.poeople.Any(s => s.Id == User.Id))
|
|
||||||
{
|
|
||||||
IEnumerable<IUser> b = Server.poeople.Where(s => s.Id == User.Id);
|
|
||||||
foreach (IUser item in b)
|
|
||||||
{
|
|
||||||
Server.poeople.Remove(item);
|
|
||||||
}
|
|
||||||
Server.poeople.Add(User);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Server.poeople.Add(User);
|
|
||||||
}
|
|
||||||
_FriendRequests.Add(User);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketAppUser))]
|
|
||||||
[JsonSourceGenerationOptions(
|
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
|
||||||
WriteIndented = false,
|
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
|
|
||||||
internal partial class SocketAppUserContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
using Luski.net.JsonTypes.BaseTypes;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
|
||||||
|
|
||||||
public class SocketDMChannel : SocketTextChannel
|
|
||||||
{
|
|
||||||
public SocketRemoteUser User
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_user is null)
|
|
||||||
{
|
|
||||||
var list = MemberIdList.ToList();
|
|
||||||
list.Remove(Server._user!.Id);
|
|
||||||
_user = SocketUserBase.GetUser(list.FirstOrDefault(), SocketRemoteUserContext.Default.SocketRemoteUser).Result;
|
|
||||||
}
|
|
||||||
return _user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public SocketRemoteUser _user = null!;
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketDMChannel))]
|
|
||||||
[JsonSourceGenerationOptions(
|
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
|
||||||
WriteIndented = false)]
|
|
||||||
internal partial class SocketDMChannelContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -13,21 +13,17 @@
|
|||||||
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
<RepositoryUrl>https://github.com/JacobTech-com/Luski.net</RepositoryUrl>
|
||||||
<IncludeSymbols>True</IncludeSymbols>
|
<IncludeSymbols>True</IncludeSymbols>
|
||||||
<FileVersion>1.0.0</FileVersion>
|
<FileVersion>1.0.0</FileVersion>
|
||||||
<Version>1.1.4-alpha</Version>
|
<Version>1.1.3-alpha23</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="JacobTechEncryption" Version="1.0.1" />
|
||||||
<PackageReference Include="websocketsharp.core" Version="1.0.0" />
|
<PackageReference Include="websocketsharp.core" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Sockets\" />
|
|
||||||
<Folder Include="Sound\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Target Name="CustomActionsAfterPublish" AfterTargets="Pack">
|
<Target Name="CustomActionsAfterPublish" AfterTargets="Pack">
|
||||||
<Message Text="Actions AfterPublish: $(PackageId).$(PackageVersion).nupkg" Importance="high" />
|
<Message Text="Actions AfterPublish: $(PackageId).$(PackageVersion).nupkg" Importance="high" />
|
||||||
<Exec Command="nuget push -Source https://nuget.jacobtech.com/v3/index.json bin\Release\$(PackageId).$(PackageVersion).nupkg" />
|
<Exec Command="nuget push -Source https://nuget.jacobtech.com/v3/index.json bin/Release/$(PackageId).$(PackageVersion).nupkg" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
174
Luski.net/Server.Account.cs
Normal file
174
Luski.net/Server.Account.cs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using JacobTechEncryption.Enums;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.JsonTypes.WSS;
|
||||||
|
using Luski.net.Structures.Main;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
|
using WebSocketSharp;
|
||||||
|
using File = System.IO.File;
|
||||||
|
|
||||||
|
namespace Luski.net;
|
||||||
|
|
||||||
|
public partial class Server<TUser>
|
||||||
|
{
|
||||||
|
public void Login(string Email, string Password, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
Both(Email, Password, CancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateAccount(string Email, string Password, string Username, string PFP, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
Both(Email, Password, CancellationToken, Username, PFP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Both(string Email, string Password, CancellationToken CancellationToken, string? Username = null, string? pfp = null)
|
||||||
|
{
|
||||||
|
if (!ClientEncryption.Generating)
|
||||||
|
{
|
||||||
|
ClientEncryption.GenerateKeys();
|
||||||
|
}
|
||||||
|
while (!ClientEncryption.Generated) { }
|
||||||
|
|
||||||
|
login = true;
|
||||||
|
Login json;
|
||||||
|
List<KeyValuePair<string, string?>> heads = new()
|
||||||
|
{
|
||||||
|
new("key", ClientEncryption.MyPublicKey),
|
||||||
|
new("username", Convert.ToBase64String(Encryption.RSA.Encrypt(Email, ClientEncryption.MyPublicKey, EncoderType.UTF8))),
|
||||||
|
new("password", ClientEncryption.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password)))
|
||||||
|
};
|
||||||
|
if (File.Exists("LastPassVer.txt") && int.TryParse(File.ReadAllText("LastPassVer.txt"), out int lpv) && lpv < ClientEncryption.PasswordVersion && lpv >= 0)
|
||||||
|
{
|
||||||
|
heads.Add(new("old_password", ClientEncryption.RemotePasswordEncrypt(Encoding.UTF8.GetBytes(Password), lpv)));
|
||||||
|
heads.Add(new("old_version", lpv.ToString()));
|
||||||
|
}
|
||||||
|
if (pfp is not null)
|
||||||
|
{
|
||||||
|
heads.Add(new("username", Username));
|
||||||
|
json = SendServer(
|
||||||
|
"CreateAccount",
|
||||||
|
pfp,
|
||||||
|
LoginContext.Default.Login,
|
||||||
|
CancellationToken,
|
||||||
|
heads.ToArray()).Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json = GetFromServer(
|
||||||
|
"Login",
|
||||||
|
LoginContext.Default.Login,
|
||||||
|
CancellationToken,
|
||||||
|
heads.ToArray()).Result;
|
||||||
|
}
|
||||||
|
if (json.Error is not null) throw new Exception($"Luski appears to be down at the current moment: {json.ErrorMessage}");
|
||||||
|
if (ClientEncryption.ofkey is null || ClientEncryption.outofkey is null) throw new Exception("Something went wrong generating the offline keys");
|
||||||
|
login = false;
|
||||||
|
if (json is not null && json.Error is null)
|
||||||
|
{
|
||||||
|
ServerOut = new WebSocket($"wss://{Domain}/WSS/{ApiVersion}");
|
||||||
|
ServerOut.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12;
|
||||||
|
ServerOut.OnMessage += DataFromServer;
|
||||||
|
ServerOut.WaitTime = new TimeSpan(0, 0, 5);
|
||||||
|
ServerOut.OnError += ServerOut_OnError;
|
||||||
|
ServerOut.Connect();
|
||||||
|
SendServer(new WSSLogin() { Token = json.Token! }, WSSLoginContext.Default.WSSLogin);
|
||||||
|
while (Token is null && Error is null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
if (Error is not null)
|
||||||
|
{
|
||||||
|
throw new Exception(Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token is null) throw new Exception("Server did not send a token");
|
||||||
|
CanRequest = true;
|
||||||
|
long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(
|
||||||
|
Token.Split('.')[0]
|
||||||
|
)));
|
||||||
|
TUser t = new();
|
||||||
|
User = t switch
|
||||||
|
{
|
||||||
|
MainSocketAppUser => (GetUser(id, MainSocketAppUserContext.Default.MainSocketAppUser,
|
||||||
|
CancellationToken.None)
|
||||||
|
.Result as TUser)!,
|
||||||
|
_ => (GetUser(id, PublicSocketAppUserContext.Default.PublicSocketAppUser, CancellationToken.None)
|
||||||
|
.Result as TUser)!
|
||||||
|
};
|
||||||
|
if (User is null || User.Error is not null)
|
||||||
|
{
|
||||||
|
string error = "User was null";
|
||||||
|
if (User is not null && User.Error is not null) error = $"{User.Error}: {User.ErrorMessage}";
|
||||||
|
throw new Exception($"Something went wrong getting your user infermation\n{error}");
|
||||||
|
}
|
||||||
|
Console.WriteLine("User got");
|
||||||
|
Console.WriteLine("Insert");
|
||||||
|
//User.Email = Email;
|
||||||
|
_ = UpdateStatus(UserStatus.Online, CancellationToken);
|
||||||
|
Console.WriteLine("stat");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ClientEncryption.pw = Email.ToLower() + Password;
|
||||||
|
_ = ClientEncryption.File.GetOfflineKey();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ClientEncryption.pw = Email + Password;
|
||||||
|
var temp222 = ClientEncryption.File.LuskiDataFile.GetDefualtDataFile();
|
||||||
|
ClientEncryption.pw = Email.ToLower() + Password;
|
||||||
|
if (temp222 is not null) temp222.Save("key.lsk", ClientEncryption.pw);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Token = null;
|
||||||
|
Error = null;
|
||||||
|
ServerOut.Close();
|
||||||
|
throw new Exception("The key file you have is getting the wrong pasword. Type your Email in the same way you creaated your account to fix this error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine("req offline");
|
||||||
|
OfflineData offlinedata = GetFromServer("Keys/GetOfflineData", OfflineDataContext.Default.OfflineData, CancellationToken).Result;
|
||||||
|
if (offlinedata.Data is not null && offlinedata.Data.Any()) Console.WriteLine(offlinedata.Data);
|
||||||
|
if (offlinedata is not null && offlinedata.Error is null && offlinedata.Data is not null && offlinedata.Data.Length > 0)
|
||||||
|
{
|
||||||
|
foreach (string keyex in offlinedata.Data)
|
||||||
|
{
|
||||||
|
Console.WriteLine(keyex);
|
||||||
|
KeyExchange? okd = JsonSerializer.Deserialize<KeyExchange>(keyex);
|
||||||
|
Console.WriteLine(okd);
|
||||||
|
if (okd is not null && !string.IsNullOrEmpty(okd.key))
|
||||||
|
{
|
||||||
|
Console.WriteLine(okd.channel);
|
||||||
|
Console.WriteLine(okd.key);
|
||||||
|
ClientEncryption.File.Channels.AddKey(okd.channel, Encoding.UTF8.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(okd.key), ClientEncryption.File.GetOfflineKey())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine("lpv");
|
||||||
|
System.IO.File.WriteAllText("LastPassVer.txt", ClientEncryption.PasswordVersion.ToString());
|
||||||
|
ClientEncryption.File.SetOfflineKey(ClientEncryption.ofkey);
|
||||||
|
using HttpClient setkey = new();
|
||||||
|
setkey.DefaultRequestHeaders.Add("token", Token);
|
||||||
|
_ = setkey.PostAsync($"https://{Domain}/{ApiVersion}/Keys/SetOfflineKey", new StringContent(ClientEncryption.outofkey)).Result;
|
||||||
|
//_ = User.Channels;
|
||||||
|
foreach (var ch in chans)
|
||||||
|
{
|
||||||
|
_ = ch.Members;
|
||||||
|
}
|
||||||
|
ClientEncryption.outofkey = null;
|
||||||
|
ClientEncryption.ofkey = null;
|
||||||
|
}
|
||||||
|
else throw new Exception(json?.ErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Luski.net;
|
|
||||||
|
|
||||||
public sealed partial class Server : IDisposable
|
|
||||||
{
|
|
||||||
~Server()
|
|
||||||
{
|
|
||||||
try { if (Directory.Exists(Cache)) Directory.Delete(Cache, true); } catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
try { if (Directory.Exists(Cache)) Directory.Delete(Cache, true); } catch { }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using Luski.net.JsonTypes.BaseTypes;
|
|
||||||
using Luski.net.JsonTypes.WSS;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using WebSocketSharp;
|
|
||||||
using File = System.IO.File;
|
|
||||||
|
|
||||||
namespace Luski.net;
|
|
||||||
|
|
||||||
public sealed partial class Server
|
|
||||||
{
|
|
||||||
internal Server(string Email, string Password, Branch branch = Branch.Master, string? Username = null, string? pfp = null)
|
|
||||||
{
|
|
||||||
if (!Encryption.Generating)
|
|
||||||
{
|
|
||||||
Encryption.GenerateKeys();
|
|
||||||
}
|
|
||||||
while (!Encryption.Generated) { }
|
|
||||||
InternalDomain = $"api.{branch}.luski.JacobTech.com";
|
|
||||||
Branch = branch;
|
|
||||||
login = true;
|
|
||||||
Login json;
|
|
||||||
List<KeyValuePair<string, string?>> heads = new()
|
|
||||||
{
|
|
||||||
new("key", Encryption.MyPublicKey),
|
|
||||||
new("email", Convert.ToBase64String(Encryption.Encrypt(Email))),
|
|
||||||
new("password", Encryption.RemotePasswordEncrypt(Encryption.Encoder.GetBytes(Password)))
|
|
||||||
};
|
|
||||||
if (File.Exists("LastPassVer.txt") && int.TryParse(File.ReadAllText("LastPassVer.txt"), out int lpv) && lpv < Encryption.PasswordVersion && lpv >= 0)
|
|
||||||
{
|
|
||||||
heads.Add(new("old_password", Encryption.RemotePasswordEncrypt(Encryption.Encoder.GetBytes(Password), lpv)));
|
|
||||||
heads.Add(new("old_version", lpv.ToString()));
|
|
||||||
}
|
|
||||||
if (pfp is not null)
|
|
||||||
{
|
|
||||||
heads.Add(new("username", Username));
|
|
||||||
json = SendServer(
|
|
||||||
"CreateAccount",
|
|
||||||
pfp,
|
|
||||||
LoginContext.Default.Login,
|
|
||||||
heads.ToArray()).Result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
json = GetFromServer(
|
|
||||||
"Login",
|
|
||||||
LoginContext.Default.Login,
|
|
||||||
heads.ToArray()).Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.Error is not null) throw new Exception($"Luski appears to be down at the current moment: {json.ErrorMessage}");
|
|
||||||
if (Encryption.ofkey is null || Encryption.outofkey is null) throw new Exception("Something went wrong generating the offline keys");
|
|
||||||
login = false;
|
|
||||||
if (json is not null && json.Error is null)
|
|
||||||
{
|
|
||||||
ServerOut = new WebSocket($"wss://{InternalDomain}/WSS/{API_Ver}");
|
|
||||||
ServerOut.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls13;
|
|
||||||
ServerOut.OnMessage += DataFromServer;
|
|
||||||
ServerOut.WaitTime = new TimeSpan(0, 0, 5);
|
|
||||||
ServerOut.OnError += ServerOut_OnError;
|
|
||||||
ServerOut.Connect();
|
|
||||||
string Infermation = $"{{\"token\": \"{json.Token}\"}}";
|
|
||||||
SendServer(new WSSLogin() { Token = json.Token! }, WSSLoginContext.Default.WSSLogin);
|
|
||||||
while (Token is null && Error is null)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
if (Error is not null)
|
|
||||||
{
|
|
||||||
throw new Exception(Error);
|
|
||||||
}
|
|
||||||
if (Token is null) throw new Exception("Server did not send a token");
|
|
||||||
CanRequest = true;
|
|
||||||
_user = SocketUserBase.GetUser(long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[0]))), SocketAppUserContext.Default.SocketAppUser).Result;
|
|
||||||
if (_user is null || _user.Error is not null) throw new Exception("Something went wrong getting your user infermation");
|
|
||||||
_ = _user.Channels;
|
|
||||||
foreach (var ch in chans)
|
|
||||||
{
|
|
||||||
_ = ch.Members;
|
|
||||||
}
|
|
||||||
_user.Email = Email;
|
|
||||||
_ = UpdateStatus(UserStatus.Online);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Encryption.pw = Email.ToLower() + Password;
|
|
||||||
_ = Encryption.File.GetOfflineKey();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Encryption.pw = Email + Password;
|
|
||||||
var temp222 = Encryption.File.LuskiDataFile.GetDefualtDataFile();
|
|
||||||
Encryption.pw = Email.ToLower() + Password;
|
|
||||||
if (temp222 is not null) temp222.Save(GetKeyFilePath, Encryption.pw);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Token = null;
|
|
||||||
Error = null;
|
|
||||||
ServerOut.Close();
|
|
||||||
throw new Exception("The key file you have is getting the wrong pasword. Type your Email in the same way you creaated your account to fix this error.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OfflineKeyData offlinedata = GetFromServer("Keys/GetOfflineData", OfflineKeyDataContext.Default.OfflineKeyData).Result;
|
|
||||||
if (string.IsNullOrEmpty(Encryption.File.GetOfflineKey())) Encryption.File.SetOfflineKey(Encryption.ofkey);
|
|
||||||
if (offlinedata is not null && offlinedata.Error is null && offlinedata.keys is not null)
|
|
||||||
{
|
|
||||||
foreach (KeyExchange key in offlinedata.keys)
|
|
||||||
{
|
|
||||||
Encryption.File.Channels.AddKey(key.channel, Encryption.Encoder.GetString(Encryption.Decrypt(Convert.FromBase64String(key.key), Encryption.File.GetOfflineKey())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.IO.File.WriteAllText("LastPassVer.txt", Encryption.PasswordVersion.ToString());
|
|
||||||
Encryption.File.SetOfflineKey(Encryption.ofkey);
|
|
||||||
using HttpClient setkey = new();
|
|
||||||
setkey.DefaultRequestHeaders.Add("token", Token);
|
|
||||||
_ = setkey.PostAsync($"https://{InternalDomain}/{API_Ver}/Keys/SetOfflineKey", new StringContent(Encryption.outofkey)).Result;
|
|
||||||
Encryption.outofkey = null;
|
|
||||||
Encryption.ofkey = null;
|
|
||||||
}
|
|
||||||
else throw new Exception(json?.ErrorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using Luski.net.JsonTypes.WSS;
|
|
||||||
using WebSocketSharp;
|
|
||||||
|
|
||||||
namespace Luski.net;
|
|
||||||
|
|
||||||
public sealed partial class Server
|
|
||||||
{
|
|
||||||
internal Server(string Email, string Password, string Username, byte[] PFP, Branch branch = Branch.Master)
|
|
||||||
{
|
|
||||||
Encryption.pw = Email.ToLower() + Password;
|
|
||||||
if (!Encryption.Generating)
|
|
||||||
{
|
|
||||||
Encryption.GenerateKeys();
|
|
||||||
}
|
|
||||||
while (!Encryption.Generated) { }
|
|
||||||
if (Encryption.ofkey is null || Encryption.outofkey is null) throw new Exception("Something went wrong generating the offline keys");
|
|
||||||
string Result;
|
|
||||||
InternalDomain = $"api.{branch}.luski.JacobTech.com";
|
|
||||||
Branch = branch;
|
|
||||||
using (HttpClient web = new())
|
|
||||||
{
|
|
||||||
web.DefaultRequestHeaders.Add("key", Encryption.MyPublicKey);
|
|
||||||
web.DefaultRequestHeaders.Add("email", Convert.ToBase64String(Encryption.Encrypt(Email)));
|
|
||||||
web.DefaultRequestHeaders.Add("password", Convert.ToBase64String(Encryption.Encrypt(Password)));
|
|
||||||
web.DefaultRequestHeaders.Add("username", Username);
|
|
||||||
HttpResponseMessage? d = web.PostAsync($"https://{InternalDomain}/{API_Ver}/CreateAccount", new StringContent(Convert.ToBase64String(PFP))).Result;
|
|
||||||
if (d is null || !d.IsSuccessStatusCode) throw new Exception("Luski appears to be down at the current moment");
|
|
||||||
Result = d.Content.ReadAsStringAsync().Result;
|
|
||||||
web.DefaultRequestHeaders.Clear();
|
|
||||||
}
|
|
||||||
Login? json = JsonSerializer.Deserialize(Result, LoginContext.Default.Login);
|
|
||||||
if (json is not null && json.Error is null)
|
|
||||||
{
|
|
||||||
ServerOut = new WebSocket($"wss://{InternalDomain}/{API_Ver}");
|
|
||||||
ServerOut.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls13;
|
|
||||||
ServerOut.OnMessage += DataFromServer;
|
|
||||||
ServerOut.WaitTime = new TimeSpan(0, 0, 5);
|
|
||||||
ServerOut.OnError += ServerOut_OnError;
|
|
||||||
ServerOut.Connect();
|
|
||||||
string Infermation = $"{{\"token\": \"{json.Token}\"}}";
|
|
||||||
SendServer(new WSSLogin() { Token = json.Token}, WSSLoginContext.Default.WSSLogin);
|
|
||||||
while (Token is null && Error is null)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
if (Error is not null)
|
|
||||||
{
|
|
||||||
throw new Exception(Error);
|
|
||||||
}
|
|
||||||
if (Token is null) throw new Exception("Server did not send a token");
|
|
||||||
CanRequest = true;
|
|
||||||
string data;
|
|
||||||
using (HttpClient web = new())
|
|
||||||
{
|
|
||||||
web.DefaultRequestHeaders.Add("token", Token);
|
|
||||||
web.DefaultRequestHeaders.Add("id", Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[0])));
|
|
||||||
data = web.GetAsync($"https://{InternalDomain}/{API_Ver}/SocketUser").Result.Content.ReadAsStringAsync().Result;
|
|
||||||
}
|
|
||||||
_user = JsonSerializer.Deserialize<SocketAppUser>(data);
|
|
||||||
if (_user is null || _user.Error is not null) throw new Exception("Something went wrong getting your user infermation");
|
|
||||||
_ = _user.Channels;
|
|
||||||
foreach (var ch in chans)
|
|
||||||
{
|
|
||||||
_ = ch.Members;
|
|
||||||
}
|
|
||||||
_user.Email = Email;
|
|
||||||
UpdateStatus(UserStatus.Online);
|
|
||||||
Encryption.File.SetOfflineKey(Encryption.ofkey);
|
|
||||||
using HttpClient setkey = new();
|
|
||||||
setkey.DefaultRequestHeaders.Add("token", Token);
|
|
||||||
_ = setkey.PostAsync($"https://{InternalDomain}/{API_Ver}/Keys/SetOfflineKey", new StringContent(Encryption.outofkey)).Result;
|
|
||||||
Encryption.outofkey = null;
|
|
||||||
Encryption.ofkey = null;
|
|
||||||
}
|
|
||||||
else throw new Exception(json?.ErrorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Server CreateAccount(string Email, string Password, string Username, byte[] PFP, Branch branch = Branch.Master)
|
|
||||||
{
|
|
||||||
return new Server(Email, Password, Username, PFP, branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Server CreateAccount(string Email, string Password, string Username, string PFP, Branch branch = Branch.Master)
|
|
||||||
{
|
|
||||||
return new Server(Email, Password, branch, Username, PFP);
|
|
||||||
}
|
|
||||||
}
|
|
13
Luski.net/Server.Events.cs
Executable file → Normal file
13
Luski.net/Server.Events.cs
Executable file → Normal file
@ -1,21 +1,20 @@
|
|||||||
using Luski.net.Interfaces;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.Structures;
|
||||||
|
|
||||||
namespace Luski.net;
|
namespace Luski.net;
|
||||||
|
|
||||||
public sealed partial class Server
|
public partial class Server<TUser>
|
||||||
{
|
{
|
||||||
public event Func<SocketMessage, Task>? MessageReceived;
|
public event Func<SocketMessage, Task>? MessageReceived;
|
||||||
|
|
||||||
public event Func<IUser, IUser, Task>? UserStatusUpdate;
|
public event Func<IUser, IUser, Task>? UserStatusUpdate;
|
||||||
|
|
||||||
public event Func<SocketRemoteUser, Task>? ReceivedFriendRequest;
|
public event Func<MainSocketRemoteUser, Task>? ReceivedFriendRequest;
|
||||||
|
|
||||||
public event Func<SocketRemoteUser, bool, Task>? FriendRequestResult;
|
public event Func<MainSocketRemoteUser, bool, Task>? FriendRequestResult;
|
||||||
|
|
||||||
public event Func<ITextChannel, SocketRemoteUser, Task>? IncommingCall;
|
|
||||||
|
|
||||||
public event Func<Exception, Task>? OnError;
|
public event Func<Exception, Task>? OnError;
|
||||||
}
|
}
|
74
Luski.net/Server.Globals.cs
Executable file → Normal file
74
Luski.net/Server.Globals.cs
Executable file → Normal file
@ -1,31 +1,28 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.Interfaces;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using Luski.net.Sockets;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.Structures.Main;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
using WebSocketSharp;
|
using WebSocketSharp;
|
||||||
|
|
||||||
namespace Luski.net;
|
namespace Luski.net;
|
||||||
|
|
||||||
public sealed partial class Server
|
public partial class Server<TUser> where TUser : class, IAppUser, new()
|
||||||
{
|
{
|
||||||
internal static string JT { get { return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/JacobTech"; } }
|
public ServerType ServerType { get; internal set; } = ServerType.Public;
|
||||||
internal static SocketAudioClient? AudioClient = null;
|
public string Domain { get; internal set; } = default!;
|
||||||
internal static string? Token = null, Error = null;
|
public IAppUser IAppUser => User;
|
||||||
internal static bool CanRequest = false;
|
public TUser User { get; internal set; }
|
||||||
internal static SocketAppUser? _user;
|
public string ApiVersion { get; internal set; } = "v1";
|
||||||
internal static string InternalDomain = "api.master.luski.jacobtech.com", platform = "win-x64";
|
private WebSocket? ServerOut;
|
||||||
internal static Branch Branch;
|
internal string? Token = null, Error = null, gen = null;
|
||||||
internal static double Percent = 0.5;
|
internal bool CanRequest = false, login = false;
|
||||||
private static WebSocket? ServerOut;
|
internal List<IUser> poeople = new();
|
||||||
private static string? gen = null;
|
internal List<MainSocketChannel> chans { get; set; } = new();
|
||||||
private static bool login = false;
|
public string Cache
|
||||||
|
|
||||||
public string Domain { get { return InternalDomain; } }
|
|
||||||
|
|
||||||
internal static string Cache
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -34,13 +31,9 @@ public sealed partial class Server
|
|||||||
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
|
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
|
||||||
string path = JT + "/Luski/";
|
string path = JT + "/Luski/";
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
path += Branch.ToString() + "/";
|
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
|
||||||
path += platform + "/";
|
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
|
||||||
path += "Data/";
|
path += "Data/";
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
path += _user?.Id + "/";
|
path += User.Id + "/";
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
path += "Cache/";
|
path += "Cache/";
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
@ -53,31 +46,18 @@ public sealed partial class Server
|
|||||||
return gen;
|
return gen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal const string API_Ver = "v1";
|
|
||||||
internal static List<IUser> poeople = new();
|
internal static string JT
|
||||||
internal static List<SocketChannel> chans { get; set; } = new();
|
|
||||||
internal static string GetKeyFilePath
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return GetKeyFilePathBr(Branch.ToString());
|
string tmp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JacobTech");
|
||||||
}
|
if (OperatingSystem.IsLinux())
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetKeyFilePathBr(string br)
|
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
|
tmp = Path.Combine(Environment.GetEnvironmentVariable("HOME")!, ".config/");
|
||||||
string path = JT + "/Luski/";
|
tmp += "JacobTech";
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
}
|
||||||
path += br + "/";
|
return tmp;
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
}
|
||||||
path += platform + "/";
|
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
|
||||||
path += "Data/";
|
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
|
||||||
path += _user?.Id + "/";
|
|
||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
|
||||||
path += "keys.lsk";
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
77
Luski.net/Server.Incoming.cs
Executable file → Normal file
77
Luski.net/Server.Incoming.cs
Executable file → Normal file
@ -1,25 +1,39 @@
|
|||||||
using Luski.net.Enums;
|
using System;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using Luski.net.Enums;
|
||||||
using Luski.net.JsonTypes;
|
using Luski.net.JsonTypes;
|
||||||
using Luski.net.JsonTypes.BaseTypes;
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
using Luski.net.JsonTypes.HTTP;
|
using Luski.net.JsonTypes.HTTP;
|
||||||
using Luski.net.JsonTypes.WSS;
|
using Luski.net.JsonTypes.WSS;
|
||||||
using System;
|
using Luski.net.Structures;
|
||||||
using System.Text.Json;
|
using Luski.net.Structures.Main;
|
||||||
using WebSocketSharp;
|
using WebSocketSharp;
|
||||||
|
|
||||||
namespace Luski.net
|
namespace Luski.net;
|
||||||
|
|
||||||
|
public partial class Server<TUser>
|
||||||
{
|
{
|
||||||
public sealed partial class Server
|
private void ServerOut_OnError(object? sender, WebSocketSharp.ErrorEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (OnError is not null) OnError.Invoke(new Exception(e.Message));
|
||||||
|
}
|
||||||
|
|
||||||
private void DataFromServer(object? sender, MessageEventArgs e)
|
private void DataFromServer(object? sender, MessageEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.IsPing) return;
|
if (e.IsPing) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine("From Server: {0}", e.Data);
|
||||||
IncomingWSS? data = JsonSerializer.Deserialize(e.Data, IncomingWSSContext.Default.IncomingWSS);
|
IncomingWSS? data = JsonSerializer.Deserialize(e.Data, IncomingWSSContext.Default.IncomingWSS);
|
||||||
switch (data?.Type)
|
switch (data?.Type)
|
||||||
{
|
{
|
||||||
case DataType.Login:
|
case DataType.Login:
|
||||||
|
Console.WriteLine("Pre auth");
|
||||||
WSSLogin n = JsonSerializer.Deserialize(e.Data, WSSLoginContext.Default.WSSLogin)!;
|
WSSLogin n = JsonSerializer.Deserialize(e.Data, WSSLoginContext.Default.WSSLogin)!;
|
||||||
Token = n.Token;
|
Token = n.Token;
|
||||||
|
Console.WriteLine("Token: {0}",Token);
|
||||||
break;
|
break;
|
||||||
case DataType.Error:
|
case DataType.Error:
|
||||||
if (Token is null)
|
if (Token is null)
|
||||||
@ -40,7 +54,7 @@ namespace Luski.net
|
|||||||
SocketMessage? m = JsonSerializer.Deserialize<SocketMessage>(e.Data);
|
SocketMessage? m = JsonSerializer.Deserialize<SocketMessage>(e.Data);
|
||||||
if (m is not null)
|
if (m is not null)
|
||||||
{
|
{
|
||||||
m.decrypt(Encryption.File.Channels.GetKey(m.ChannelID));
|
m.decrypt(ClientEncryption.File.Channels.GetKey(m.ChannelID), CancellationToken.None);
|
||||||
_ = MessageReceived.Invoke(m);
|
_ = MessageReceived.Invoke(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,9 +65,9 @@ namespace Luski.net
|
|||||||
StatusUpdate? SU = JsonSerializer.Deserialize<StatusUpdate>(e.Data);
|
StatusUpdate? SU = JsonSerializer.Deserialize<StatusUpdate>(e.Data);
|
||||||
if (SU is not null)
|
if (SU is not null)
|
||||||
{
|
{
|
||||||
SocketRemoteUser after = SocketUserBase.GetUser(SU.id, SocketRemoteUserContext.Default.SocketRemoteUser).Result;
|
MainSocketRemoteUser after = GetUser(SU.id, MainSocketRemoteUserContext.Default.MainSocketRemoteUser, CancellationToken.None).Result;
|
||||||
after.Status = SU.after;
|
after.Status = SU.after;
|
||||||
SocketRemoteUser before = after.Clone();
|
MainSocketRemoteUser before = after.Clone();
|
||||||
before.Status = SU.before;
|
before.Status = SU.before;
|
||||||
_ = UserStatusUpdate.Invoke(before, after);
|
_ = UserStatusUpdate.Invoke(before, after);
|
||||||
}
|
}
|
||||||
@ -62,57 +76,56 @@ namespace Luski.net
|
|||||||
case DataType.Friend_Request:
|
case DataType.Friend_Request:
|
||||||
if (ReceivedFriendRequest is not null)
|
if (ReceivedFriendRequest is not null)
|
||||||
{
|
{
|
||||||
FriendRequest? request = JsonSerializer.Deserialize(e.Data, FriendRequestContext.Default.FriendRequest);
|
FriendRequest? request =
|
||||||
if (request is not null) _ = ReceivedFriendRequest.Invoke(SocketUserBase.GetUser(request.Id, SocketRemoteUserContext.Default.SocketRemoteUser).Result);
|
JsonSerializer.Deserialize(e.Data, FriendRequestContext.Default.FriendRequest);
|
||||||
|
if (request is not null)
|
||||||
|
_ = ReceivedFriendRequest.Invoke(GetUser(request.Id,
|
||||||
|
MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
|
||||||
|
CancellationToken.None).Result);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DataType.Friend_Request_Result:
|
case DataType.Friend_Request_Result:
|
||||||
if (FriendRequestResult is not null)
|
if (FriendRequestResult is not null)
|
||||||
{
|
{
|
||||||
FriendRequestResult? FRR = JsonSerializer.Deserialize<FriendRequestResult>(e.Data);
|
FriendRequestResult? FRR = JsonSerializer.Deserialize<FriendRequestResult>(e.Data);
|
||||||
if (FRR is not null && FRR.Channel is not null && FRR.Id is not null && FRR.Result is not null)
|
if (FRR is not null && FRR.Channel is not null && FRR.Id is not null &&
|
||||||
|
FRR.Result is not null)
|
||||||
{
|
{
|
||||||
SocketDMChannel chan = SocketChannel.GetChannel((long)FRR.Channel, SocketDMChannelContext.Default.SocketDMChannel).Result;
|
MainSocketDMChannel chan = GetChannel((long)FRR.Channel,
|
||||||
|
MainSocketDMChannelContext.Default.MainSocketDMChannel,
|
||||||
|
CancellationToken.None).Result;
|
||||||
chans.Add(chan);
|
chans.Add(chan);
|
||||||
SocketRemoteUser from1 = SocketUserBase.GetUser((long)FRR.Id, SocketRemoteUserContext.Default.SocketRemoteUser).Result;
|
MainSocketRemoteUser from1 = GetUser((long)FRR.Id,
|
||||||
from1.Channel = chan;
|
MainSocketRemoteUserContext.Default.MainSocketRemoteUser,
|
||||||
|
CancellationToken.None).Result;
|
||||||
|
//from1.Channel = chan;
|
||||||
_ = FriendRequestResult.Invoke(from1, (bool)FRR.Result);
|
_ = FriendRequestResult.Invoke(from1, (bool)FRR.Result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DataType.Call_Info:
|
|
||||||
if (IncommingCall is not null)
|
|
||||||
{
|
|
||||||
callinfoinc? ci = JsonSerializer.Deserialize<callinfoinc>(e.Data);
|
|
||||||
if (ci is not null) _ = IncommingCall.Invoke(SocketChannel.GetChannel(ci.channel, SocketTextChannelContext.Default.SocketTextChannel).Result, SocketUserBase.GetUser(ci.from, SocketRemoteUserContext.Default.SocketRemoteUser).Result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DataType.Call_Data:
|
|
||||||
if (AudioClient is not null)
|
|
||||||
{
|
|
||||||
AudioClient.Givedata(e.Data);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DataType.Key_Exchange:
|
case DataType.Key_Exchange:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
|
KeyExchange? KE = JsonSerializer.Deserialize<KeyExchange>(e.Data);
|
||||||
if (KE is not null) Encryption.File.Channels.AddKey(KE.channel, Encryption.Encoder.GetString(Encryption.Decrypt(Convert.FromBase64String(KE.key))));
|
if (KE is not null)
|
||||||
|
ClientEncryption.File.Channels.AddKey(KE.channel,
|
||||||
|
ClientEncryption.Encoder.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(KE.key), ClientEncryption.ofkey)));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (OnError is not null) OnError.Invoke(ex);
|
if (OnError is not null) OnError.Invoke(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
Console.WriteLine("Unknown");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception exception)
|
||||||
private class callinfoinc
|
|
||||||
{
|
{
|
||||||
public long channel { get; set; } = default!;
|
if (OnError is not null) _ = OnError.Invoke(exception);
|
||||||
public long from { get; set; } = default!;
|
else throw exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +0,0 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Luski.net;
|
|
||||||
|
|
||||||
public sealed partial class Server
|
|
||||||
{
|
|
||||||
public static async Task<Server> Login(string Email, string Password, Branch branch = Branch.Master)
|
|
||||||
{
|
|
||||||
return new Server(Email, Password, branch);
|
|
||||||
}
|
|
||||||
}
|
|
349
Luski.net/Server.cs
Executable file → Normal file
349
Luski.net/Server.cs
Executable file → Normal file
@ -1,191 +1,79 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.Interfaces;
|
|
||||||
using Luski.net.JsonTypes;
|
|
||||||
using Luski.net.JsonTypes.BaseTypes;
|
|
||||||
using Luski.net.JsonTypes.HTTP;
|
|
||||||
using Luski.net.Sockets;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using Luski.net.JsonTypes.HTTP;
|
||||||
|
using Luski.net.Structures;
|
||||||
|
using Luski.net.Structures.Main;
|
||||||
|
using Luski.net.Structures.Public;
|
||||||
|
using File = System.IO.File;
|
||||||
|
|
||||||
namespace Luski.net;
|
namespace Luski.net;
|
||||||
|
|
||||||
public sealed partial class Server
|
public partial class Server<TUser> : IServer
|
||||||
{
|
{
|
||||||
#pragma warning disable CA1822 // Mark members as static
|
internal Server()
|
||||||
/// <summary>
|
{ }
|
||||||
/// Creates an audio client for the <paramref name="channel_id"/> you want to talk on
|
|
||||||
/// </summary>
|
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
|
||||||
/// <param name="ID">The channel <see cref="ITextChannel.ID"/> you want to talk on</param>
|
|
||||||
/// <returns><seealso cref="IAudioClient"/></returns>
|
|
||||||
public IAudioClient CreateAudioClient(long channel_id)
|
|
||||||
{
|
{
|
||||||
// if (AudioClient != null) throw new Exception("audio client alread created");
|
if (Cache != null)
|
||||||
SocketAudioClient client = new(channel_id, OnError);
|
{
|
||||||
AudioClient = client;
|
bool isc = File.Exists($"{Cache}/servers/{Domain}");
|
||||||
return client;
|
if (!isc) await GetFromServer($"socketserver/Avatar/", $"{Cache}/servers/{Domain}-{ApiVersion}", CancellationToken);
|
||||||
|
}
|
||||||
|
return File.ReadAllBytes($"{Cache}/servers/{Domain}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SocketRemoteUser> SendFriendResult(long user, bool answer)
|
public async Task<Tuser> GetUser<Tuser>(long UserID, CancellationToken CancellationToken) where Tuser : SocketUserBase, new()
|
||||||
{
|
{
|
||||||
|
Tuser user = new();
|
||||||
FriendRequestResult json = await SendServer("FriendRequestResult",
|
switch (user)
|
||||||
new FriendRequestResultOut()
|
|
||||||
{
|
{
|
||||||
Id = user,
|
case MainSocketAppUser:
|
||||||
Result = answer
|
user = (GetUser(UserID, MainSocketAppUserContext.Default.MainSocketAppUser, CancellationToken).Result as Tuser)!;
|
||||||
},
|
break;
|
||||||
FriendRequestResultOutContext.Default.FriendRequestResultOut,
|
case PublicSocketAppUser:
|
||||||
FriendRequestResultContext.Default.FriendRequestResult);
|
user = (GetUser(UserID, PublicSocketAppUserContext.Default.PublicSocketAppUser, CancellationToken).Result as Tuser)!;
|
||||||
|
break;
|
||||||
if (json is not null && json.Error is null && json.ErrorMessage is null && answer && json.Channel is not null)
|
case SocketUserBase:
|
||||||
{
|
user = (GetUser(UserID, SocketUserBaseContext.Default.SocketUserBase, CancellationToken).Result as Tuser)!;
|
||||||
SocketDMChannel chan = await SocketChannel.GetChannel((long)json.Channel, SocketDMChannelContext.Default.SocketDMChannel);
|
break;
|
||||||
_ = chan.StartKeyProcessAsync();
|
case null:
|
||||||
chans.Add(chan);
|
throw new NullReferenceException(nameof(Tuser));
|
||||||
}
|
default:
|
||||||
else
|
throw new Exception("Unknown channel type");
|
||||||
{
|
|
||||||
throw new Exception(json?.Error.ToString());
|
|
||||||
}
|
|
||||||
return SocketUserBase.GetUser(user, SocketRemoteUserContext.Default.SocketRemoteUser).Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SocketRemoteUser> SendFriendRequest(long user)
|
return user;
|
||||||
{
|
|
||||||
FriendRequestResult? json = await SendServer("FriendRequest", new FriendRequest() { Id = user, SubType = 0 }, FriendRequestContext.Default.FriendRequest, FriendRequestResultContext.Default.FriendRequestResult);
|
|
||||||
|
|
||||||
if (json.StatusCode != HttpStatusCode.Accepted)
|
|
||||||
{
|
|
||||||
if (json is not null && json.Error is not null)
|
|
||||||
{
|
|
||||||
switch ((ErrorCode)(int)json.Error)
|
|
||||||
{
|
|
||||||
case ErrorCode.InvalidToken:
|
|
||||||
throw new Exception("Your current token is no longer valid");
|
|
||||||
case ErrorCode.ServerError:
|
|
||||||
throw new Exception($"Error from server: {json.ErrorMessage}");
|
|
||||||
case ErrorCode.InvalidPostData:
|
|
||||||
throw new Exception("The post data dent to the server is not the correct format. This may be because you app is couropt or you are using the wron API version");
|
|
||||||
case ErrorCode.Forbidden:
|
|
||||||
throw new Exception("You already have an outgoing request or the persone is not real");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json is not null && json.Channel is not null)
|
public async Task<TChannel> GetChannel<TChannel>(long Channel, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
|
||||||
{
|
|
||||||
SocketDMChannel chan = await SocketChannel.GetChannel((long)json.Channel, (JsonTypeInfo<SocketDMChannel>)SocketDMChannelContext.Default.SocketDMChannel);
|
|
||||||
_ = chan.StartKeyProcessAsync();
|
|
||||||
chans.Add(chan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketRemoteUser b = await SocketUserBase.GetUser(user, SocketRemoteUserContext.Default.SocketRemoteUser);
|
|
||||||
b.FriendStatus = FriendStatus.PendingOut;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SocketRemoteUser> SendFriendRequest(string username, short tag)
|
|
||||||
{
|
|
||||||
FriendRequestResult json = await SendServer("FriendRequest", new FriendRequest() { Username = username, Tag = tag, SubType = 1 }, FriendRequestContext.Default.FriendRequest, FriendRequestResultContext.Default.FriendRequestResult);
|
|
||||||
|
|
||||||
if (json is not null && json.Error is not null)
|
|
||||||
{
|
|
||||||
throw (ErrorCode)(int)json.Error switch
|
|
||||||
{
|
|
||||||
ErrorCode.InvalidToken => new Exception("Your current token is no longer valid"),
|
|
||||||
ErrorCode.ServerError => new Exception("Error from server: " + json.ErrorMessage),
|
|
||||||
ErrorCode.InvalidPostData => new Exception("The post data dent to the server is not the correct format. This may be because you app is couropt or you are using the wron API version"),
|
|
||||||
ErrorCode.Forbidden => new Exception("You already have an outgoing request or the persone is not real"),
|
|
||||||
_ => new Exception(JsonSerializer.Serialize(json)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (json is not null && json.Channel is not null && json.Id is not null)
|
|
||||||
{
|
|
||||||
SocketDMChannel chan = await SocketChannel.GetChannel(json.Channel.Value, (JsonTypeInfo<SocketDMChannel>)SocketDMChannelContext.Default.SocketDMChannel);
|
|
||||||
_ = chan.StartKeyProcessAsync();
|
|
||||||
chans.Add(chan);
|
|
||||||
return await SocketUserBase.GetUser((long)json.Id, SocketRemoteUserContext.Default.SocketRemoteUser);
|
|
||||||
}
|
|
||||||
else throw new Exception("missing data from server");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sends the server a request to update the <paramref name="Status"/> of you account
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="Status">The <see cref="UserStatus"/> you want to set your status to</param>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public async Task<Task> UpdateStatus(UserStatus Status)
|
|
||||||
{
|
|
||||||
if (_user is null) throw new Exception("You must login to make a request");
|
|
||||||
IncomingHTTP? data = await SendServer("SocketUserProfile/Status", new Status() { UserStatus = Status }, StatusContext.Default.Status, IncomingHTTPContext.Default.IncomingHTTP);
|
|
||||||
if (data.Error is not null && ((int)data.StatusCode < 200 || (int)data.StatusCode > 299))
|
|
||||||
{
|
|
||||||
if (data?.ErrorMessage is not null) throw new Exception(data.ErrorMessage);
|
|
||||||
if (data?.Error is not null) throw new Exception(((int)data.Error).ToString());
|
|
||||||
else throw new Exception("Something went worng");
|
|
||||||
}
|
|
||||||
|
|
||||||
_user.Status = Status;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ChangeChannel(long Channel)
|
|
||||||
{
|
|
||||||
if (_user is null) throw new Exception("You must login to make a request");
|
|
||||||
IncomingHTTP? data = await SendServer("ChangeChannel", new Channel() { Id = Channel }, ChannelContext.Default.Channel, IncomingHTTPContext.Default.IncomingHTTP);
|
|
||||||
if (data.StatusCode != HttpStatusCode.Accepted)
|
|
||||||
{
|
|
||||||
if (data?.Error is not null)
|
|
||||||
{
|
|
||||||
switch (data.Error)
|
|
||||||
{
|
|
||||||
case ErrorCode.InvalidToken:
|
|
||||||
throw new Exception("Your current token is no longer valid");
|
|
||||||
case ErrorCode.ServerError:
|
|
||||||
throw new Exception("Error from server: " + data.ErrorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else throw new Exception("Something went worng");
|
|
||||||
}
|
|
||||||
|
|
||||||
_user.SelectedChannel = Channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Task> SendMessage(string Message, long Channel, params JsonTypes.File[] Files) => (await GetChannel<SocketTextChannel>(Channel)).SendMessage(Message, Files);
|
|
||||||
|
|
||||||
public void SetMultiThreadPercent(double num)
|
|
||||||
{
|
|
||||||
if (num < 1 || num > 100) throw new Exception("Number must be from 1 - 100");
|
|
||||||
Percent = num / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SocketMessage> GetMessage(long MessageId) => await SocketMessage.GetMessage(MessageId);
|
|
||||||
|
|
||||||
public async Task<SocketRemoteUser> GetUser(long UserID) => await SocketUserBase.GetUser(UserID, SocketRemoteUserContext.Default.SocketRemoteUser);
|
|
||||||
|
|
||||||
public async Task<TChannel> GetChannel<TChannel>(long Channel) where TChannel : SocketChannel, new()
|
|
||||||
{
|
{
|
||||||
TChannel Return = new();
|
TChannel Return = new();
|
||||||
switch (Return)
|
switch (Return)
|
||||||
{
|
{
|
||||||
case SocketDMChannel:
|
case MainSocketDMChannel:
|
||||||
Return = (await SocketChannel.GetChannel(Channel, SocketDMChannelContext.Default.SocketDMChannel) as TChannel)!;
|
Return = (await GetChannel(Channel, MainSocketDMChannelContext.Default.MainSocketDMChannel, CancellationToken) as TChannel)!;
|
||||||
break;
|
break;
|
||||||
case SocketGroupChannel:
|
case MainSocketGroupChannel:
|
||||||
Return = (await SocketChannel.GetChannel(Channel, SocketGroupChannelContext.Default.SocketGroupChannel) as TChannel)!;
|
Return = (await GetChannel(Channel, MainSocketGroupChannelContext.Default.MainSocketGroupChannel, CancellationToken) as TChannel)!;
|
||||||
break;
|
break;
|
||||||
case SocketTextChannel:
|
case MainSocketTextChannel:
|
||||||
Return = (await SocketChannel.GetChannel(Channel, SocketTextChannelContext.Default.SocketTextChannel) as TChannel)!;
|
Return = (await GetChannel(Channel, MainSocketTextChannelContext.Default.MainSocketTextChannel, CancellationToken) as TChannel)!;
|
||||||
break;
|
break;
|
||||||
case SocketChannel:
|
case MainSocketChannel:
|
||||||
Return = (await SocketChannel.GetChannel(Channel, SocketChannelContext.Default.SocketChannel) as TChannel)!;
|
Return = (await GetChannel(Channel, MainSocketChannelContext.Default.MainSocketChannel, CancellationToken) as TChannel)!;
|
||||||
break;
|
break;
|
||||||
case null:
|
case null:
|
||||||
throw new NullReferenceException(nameof(TChannel));
|
throw new NullReferenceException(nameof(TChannel));
|
||||||
@ -195,83 +83,168 @@ public sealed partial class Server
|
|||||||
return Return;
|
return Return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<TChannel> GetChannel<TChannel>(long id, JsonTypeInfo<TChannel> Json, CancellationToken CancellationToken) where TChannel : MainSocketChannel, new()
|
||||||
public SocketAppUser CurrentUser
|
|
||||||
{
|
{
|
||||||
get
|
TChannel request;
|
||||||
|
if (chans.Count > 0 && chans.Any(s => s.Id == id))
|
||||||
{
|
{
|
||||||
if (_user is null) throw new Exception("You must Login first");
|
return chans.Where(s => s is TChannel && s.Id == id).Cast<TChannel>().FirstOrDefault()!;
|
||||||
return _user;
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (CanRequest)
|
||||||
|
{
|
||||||
|
request = await GetFromServer($"SocketChannel/Get/{id}", Json, CancellationToken);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822 // Mark members as static
|
if (request is null) throw new Exception("Something was wrong with the server responce");
|
||||||
|
if (request.Error is null)
|
||||||
private void ServerOut_OnError(object? sender, WebSocketSharp.ErrorEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (OnError is not null) OnError.Invoke(new Exception(e.Message));
|
if (chans.Count > 0 && chans.Any(s => s.Id == request.Id))
|
||||||
|
{
|
||||||
|
foreach (MainSocketChannel? p in chans.Where(s => s.Id == request.Id))
|
||||||
|
{
|
||||||
|
chans.Remove(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chans.Add(request);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
throw request.Error switch
|
||||||
|
{
|
||||||
|
ErrorCode.InvalidToken => new Exception("Your current token is no longer valid"),
|
||||||
|
ErrorCode.Forbidden => new Exception("The server rejected your request"),
|
||||||
|
ErrorCode.ServerError => new Exception("Error from server: " + request.ErrorMessage),
|
||||||
|
ErrorCode.InvalidURL or ErrorCode.MissingHeader => new Exception(request.ErrorMessage),
|
||||||
|
_ => new Exception($"Unknown data: '{request.ErrorMessage}'"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Move to new Data layout")]
|
public async Task<SocketMessage> GetMessage(long id, CancellationToken CancellationToken)
|
||||||
internal static void SendServer(string data)
|
|
||||||
{
|
{
|
||||||
ServerOut?.Send(data);
|
SocketMessage message;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (CanRequest)
|
||||||
|
{
|
||||||
|
message = await GetFromServer("socketmessage",
|
||||||
|
SocketMessageContext.Default.SocketMessage,
|
||||||
|
CancellationToken,
|
||||||
|
new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message is not null) return message;
|
||||||
|
throw new Exception("Server did not return a message");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS
|
/// <summary>
|
||||||
|
/// Sends the server a request to update the <paramref name="Status"/> of you account
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Status">The <see cref="UserStatus"/> you want to set your status to</param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public async Task<Task> UpdateStatus(UserStatus Status, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
IncomingHTTP? data = await SendServer("SocketUserProfile/Status", new Status() { UserStatus = Status }, StatusContext.Default.Status, IncomingHTTPContext.Default.IncomingHTTP, CancellationToken);
|
||||||
|
if (data.Error is not null && ((int)data.StatusCode < 200 || (int)data.StatusCode > 299))
|
||||||
|
{
|
||||||
|
if (data?.ErrorMessage is not null) throw new Exception(data.ErrorMessage);
|
||||||
|
if (data?.Error is not null) throw new Exception(((int)data.Error).ToString());
|
||||||
|
else throw new Exception("Something went worng");
|
||||||
|
}
|
||||||
|
|
||||||
|
(User as SocketUserBase)!.Status = Status;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<Tuser> GetUser<Tuser>(long UserId, JsonTypeInfo<Tuser> Json, CancellationToken CancellationToken) where Tuser : SocketUserBase, new()
|
||||||
|
{
|
||||||
|
Tuser user;
|
||||||
|
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
|
||||||
|
{
|
||||||
|
Tuser temp = poeople.Where(s => s is Tuser && s.Id == UserId).Cast<Tuser>().FirstOrDefault()!;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (CanRequest)
|
||||||
|
{
|
||||||
|
user = await GetFromServer("socketuser",
|
||||||
|
Json,
|
||||||
|
CancellationToken,
|
||||||
|
new KeyValuePair<string, string?>("id", UserId.ToString()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user is null) throw new Exception("Server did not return a user");
|
||||||
|
if (poeople.Count > 0 && poeople.Any(s => s.Id == UserId))
|
||||||
|
{
|
||||||
|
foreach (IUser? p in poeople.Where(s => s.Id == UserId))
|
||||||
|
{
|
||||||
|
poeople.Remove(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poeople.Add(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS
|
||||||
{
|
{
|
||||||
ServerOut?.Send(JsonSerializer.Serialize(Payload, jsonTypeInfo));
|
ServerOut?.Send(JsonSerializer.Serialize(Payload, jsonTypeInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static HttpResponseMessage GetFromServer(string Path, params KeyValuePair<string, string?>[] Headers)
|
public HttpResponseMessage GetFromServer(string Path, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
{
|
{
|
||||||
using HttpClient web = new();
|
using HttpClient web = new();
|
||||||
web.Timeout = TimeSpan.FromSeconds(10);
|
web.Timeout = TimeSpan.FromSeconds(10);
|
||||||
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
return web.GetAsync($"https://{InternalDomain}/{API_Ver}/{Path}").Result;
|
return web.GetAsync($"https://{Domain}/{ApiVersion}/{Path}", cancellationToken: CancellationToken).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Task GetFromServer(string Path, string File, params KeyValuePair<string, string?>[] Headers)
|
public Task GetFromServer(string Path, string File, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
{
|
{
|
||||||
using HttpClient web = new();
|
using HttpClient web = new();
|
||||||
web.Timeout = TimeSpan.FromMinutes(10);
|
web.Timeout = TimeSpan.FromMinutes(10);
|
||||||
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
HttpResponseMessage Response = web.GetAsync($"https://{InternalDomain}/{API_Ver}/{Path}").Result;
|
HttpResponseMessage Response = web.GetAsync($"https://{Domain}/{ApiVersion}/{Path}", CancellationToken).Result;
|
||||||
Stream stream = Response.Content.ReadAsStreamAsync().Result;
|
Stream stream = Response.Content.ReadAsStreamAsync(CancellationToken).Result;
|
||||||
using FileStream fs = System.IO.File.Create(File);
|
using FileStream fs = System.IO.File.Create(File);
|
||||||
stream.CopyTo(fs);
|
stream.CopyTo(fs);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<Tresult> GetFromServer<Tresult>(string Path, JsonTypeInfo<Tresult> Type, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
public async Task<Tresult> GetFromServer<Tresult>(string Path, JsonTypeInfo<Tresult> Type, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
||||||
{
|
{
|
||||||
HttpResponseMessage ServerResponce = GetFromServer(Path, Headers);
|
HttpResponseMessage ServerResponce = GetFromServer(Path, CancellationToken, Headers);
|
||||||
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync().Result, Type);
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, Type);
|
||||||
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<Tresult> SendServer<Tvalue, Tresult>(string Path, Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, params KeyValuePair<string, string?>[] Headers) where Tvalue : HTTPRequest where Tresult : IncomingHTTP, new()
|
public async Task<Tresult> SendServer<Tvalue, Tresult>(string Path, Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tvalue : IWebRequest where Tresult : IncomingHTTP, new()
|
||||||
{
|
{
|
||||||
using HttpClient web = new();
|
using HttpClient web = new();
|
||||||
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
HttpResponseMessage ServerResponce = web.PostAsJsonAsync($"https://{InternalDomain}/{API_Ver}/{Path}", Payload, jsonTypeInfo).Result;
|
HttpResponseMessage ServerResponce = web.PostAsJsonAsync($"https://{Domain}/{ApiVersion}/{Path}", Payload, jsonTypeInfo, CancellationToken).Result;
|
||||||
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
Tresult error = new() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
Tresult error = new() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
if (string.IsNullOrWhiteSpace(ServerResponce.Content.ReadAsStringAsync().Result)) return error;
|
if (string.IsNullOrWhiteSpace(ServerResponce.Content.ReadAsStringAsync(CancellationToken).Result)) return error;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync().Result, ReturnjsonTypeInfo);
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, ReturnjsonTypeInfo);
|
||||||
if (temp is null) return error;
|
if (temp is null) return error;
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
catch { return error; }
|
catch { return error; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<Tresult> SendServer<Tresult>(string Path, string File, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
public async Task<Tresult> SendServer<Tresult>(string Path, string File, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
||||||
{
|
{
|
||||||
var fs = System.IO.File.OpenRead(File);
|
var fs = System.IO.File.OpenRead(File);
|
||||||
try
|
try
|
||||||
@ -280,11 +253,11 @@ public sealed partial class Server
|
|||||||
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
web.Timeout = new TimeSpan(0, 10, 0);
|
web.Timeout = new TimeSpan(0, 10, 0);
|
||||||
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
HttpResponseMessage ServerResponce = web.PostAsync($"https://{InternalDomain}/{API_Ver}/{Path}", new StreamContent(fs)).Result;
|
HttpResponseMessage ServerResponce = web.PostAsync($"https://{Domain}/{ApiVersion}/{Path}", new StreamContent(fs), CancellationToken).Result;
|
||||||
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync().Result, ReturnjsonTypeInfo);
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, ReturnjsonTypeInfo);
|
||||||
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
97
Luski.net/Server.old.Globals.cs
Executable file
97
Luski.net/Server.old.Globals.cs
Executable file
@ -0,0 +1,97 @@
|
|||||||
|
/*using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.Sockets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using WebSocketSharp;
|
||||||
|
|
||||||
|
namespace Luski.net;
|
||||||
|
|
||||||
|
public sealed partial class Serverold
|
||||||
|
{
|
||||||
|
internal static string JT
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string tmp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JacobTech");
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
tmp = Path.Combine(Environment.GetEnvironmentVariable("HOME")!, ".config/");
|
||||||
|
tmp += "JacobTech";
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static SocketAudioClient? AudioClient = null;
|
||||||
|
internal static string? Token = null, Error = null;
|
||||||
|
internal static bool CanRequest = false;
|
||||||
|
internal static SocketAppUser? _user;
|
||||||
|
internal static string platform = "win-x64";
|
||||||
|
internal static Branch Branch;
|
||||||
|
internal static double Percent = 0.5;
|
||||||
|
private static WebSocket? ServerOut;
|
||||||
|
private static string? gen = null;
|
||||||
|
private static bool login = false;
|
||||||
|
|
||||||
|
public static SocketServer CurrentServer = null!;
|
||||||
|
|
||||||
|
internal static string Cache
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (gen is null)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
|
||||||
|
string path = JT + "/Luski/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += Branch.ToString() + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += platform + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += "Data/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += _user?.Id + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += "Cache/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += Path.GetRandomFileName() + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
gen = path;
|
||||||
|
}
|
||||||
|
if (!Directory.Exists($"{gen}/avatars")) Directory.CreateDirectory($"{gen}/avatars");
|
||||||
|
if (!Directory.Exists($"{gen}/channels")) Directory.CreateDirectory($"{gen}/channels");
|
||||||
|
return gen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal static List<IUser> poeople = new();
|
||||||
|
internal static List<SocketChannel> chans { get; set; } = new();
|
||||||
|
internal static string GetKeyFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetKeyFilePathBr(Branch.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetKeyFilePathBr(string br)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(JT)) Directory.CreateDirectory(JT);
|
||||||
|
string path = JT + "/Luski/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += br + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += platform + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += "Data/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += _user?.Id + "/";
|
||||||
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
|
path += "keys.lsk";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
281
Luski.net/Server.old.cs
Executable file
281
Luski.net/Server.old.cs
Executable file
@ -0,0 +1,281 @@
|
|||||||
|
/*using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using Luski.net.JsonTypes.HTTP;
|
||||||
|
using Luski.net.Sockets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Luski.net;
|
||||||
|
|
||||||
|
public sealed partial class Serverold
|
||||||
|
{
|
||||||
|
#pragma warning disable CA1822 // Mark members as static
|
||||||
|
public async Task<MainSocketRemoteUser> SendFriendResult(long user, bool answer, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
|
||||||
|
FriendRequestResult json = await SendServer(_user!.Servers.First(),"FriendRequestResult",
|
||||||
|
new FriendRequestResultOut()
|
||||||
|
{
|
||||||
|
Id = user,
|
||||||
|
Result = answer
|
||||||
|
},
|
||||||
|
FriendRequestResultOutContext.Default.FriendRequestResultOut,
|
||||||
|
FriendRequestResultContext.Default.FriendRequestResult,
|
||||||
|
CancellationToken);
|
||||||
|
|
||||||
|
if (json is not null && json.Error is null && json.ErrorMessage is null && answer && json.Channel is not null)
|
||||||
|
{
|
||||||
|
SocketDMChannel chan = await SocketChannel.GetChannel((long)json.Channel, SocketDMChannelContext.Default.SocketDMChannel, CancellationToken, _user!.Servers.First());
|
||||||
|
_ = chan.StartKeyProcessAsync(CancellationToken);
|
||||||
|
chans.Add(chan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception(json?.Error.ToString());
|
||||||
|
}
|
||||||
|
return SocketUserBase.GetUser(user, SocketRemoteUserContext.Default.SocketRemoteUser, CancellationToken, _user!.Servers.First()).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MainSocketRemoteUser> SendFriendRequest(long code, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
string ccode = Convert.ToBase64String(Encryption.Hash(Encryption.Encoder.GetBytes(code.ToString())));
|
||||||
|
FriendRequestResult? json = await SendServer(_user!.Servers.First(),"FriendRequest", new FriendRequest() { code = ccode}, FriendRequestContext.Default.FriendRequest, FriendRequestResultContext.Default.FriendRequestResult, CancellationToken);
|
||||||
|
|
||||||
|
if (json.StatusCode != HttpStatusCode.Accepted)
|
||||||
|
{
|
||||||
|
if (json is not null && json.Error is not null)
|
||||||
|
{
|
||||||
|
switch ((ErrorCode)(int)json.Error)
|
||||||
|
{
|
||||||
|
case ErrorCode.InvalidToken:
|
||||||
|
throw new Exception("Your current token is no longer valid");
|
||||||
|
case ErrorCode.ServerError:
|
||||||
|
throw new Exception($"Error from server: {json.ErrorMessage}");
|
||||||
|
case ErrorCode.InvalidPostData:
|
||||||
|
throw new Exception("The post data dent to the server is not the correct format. This may be because you app is couropt or you are using the wron API version");
|
||||||
|
case ErrorCode.Forbidden:
|
||||||
|
throw new Exception("You already have an outgoing request or the persone is not real");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json is not null && json.Channel is not null)
|
||||||
|
{
|
||||||
|
SocketDMChannel chan = await SocketChannel.GetChannel((long)json.Channel, (JsonTypeInfo<SocketDMChannel>)SocketDMChannelContext.Default.SocketDMChannel, CancellationToken, _user!.Servers.First());
|
||||||
|
_ = chan.StartKeyProcessAsync(CancellationToken);
|
||||||
|
chans.Add(chan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainSocketRemoteUser b = await SocketUserBase.GetUser(code, SocketRemoteUserContext.Default.SocketRemoteUser, CancellationToken, _user!.Servers.First());
|
||||||
|
if (json.Channel is not null)
|
||||||
|
b.FriendStatus = FriendStatus.Friends;
|
||||||
|
else
|
||||||
|
b.FriendStatus = FriendStatus.PendingOut;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the server a request to update the <paramref name="Status"/> of you account
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Status">The <see cref="UserStatus"/> you want to set your status to</param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public async Task<Task> UpdateStatus(UserStatus Status, CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
if (_user is null) throw new Exception("You must login to make a request");
|
||||||
|
IncomingHTTP? data = await SendServer(_user!.Servers.First(),"SocketUserProfile/Status", new Status() { UserStatus = Status }, StatusContext.Default.Status, IncomingHTTPContext.Default.IncomingHTTP, CancellationToken);
|
||||||
|
if (data.Error is not null && ((int)data.StatusCode < 200 || (int)data.StatusCode > 299))
|
||||||
|
{
|
||||||
|
if (data?.ErrorMessage is not null) throw new Exception(data.ErrorMessage);
|
||||||
|
if (data?.Error is not null) throw new Exception(((int)data.Error).ToString());
|
||||||
|
else throw new Exception("Something went worng");
|
||||||
|
}
|
||||||
|
|
||||||
|
_user.Status = Status;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ChangeChannel(long Channel, CancellationToken CancellationToken, SocketServer Server)
|
||||||
|
{
|
||||||
|
if (_user is null) throw new Exception("You must login to make a request");
|
||||||
|
IncomingHTTP? data = await SendServer(Server, "ChangeChannel", new Channel() { Id = Channel }, ChannelContext.Default.Channel, IncomingHTTPContext.Default.IncomingHTTP, CancellationToken);
|
||||||
|
if (data.StatusCode != HttpStatusCode.Accepted)
|
||||||
|
{
|
||||||
|
if (data?.Error is not null)
|
||||||
|
{
|
||||||
|
switch (data.Error)
|
||||||
|
{
|
||||||
|
case ErrorCode.InvalidToken:
|
||||||
|
throw new Exception("Your current token is no longer valid");
|
||||||
|
case ErrorCode.ServerError:
|
||||||
|
throw new Exception("Error from server: " + data.ErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else throw new Exception("Something went worng");
|
||||||
|
}
|
||||||
|
|
||||||
|
_user.SelectedChannel = Channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SendMessage(string Message, long Channel, SocketServer Server, CancellationToken CancellationToken, params JsonTypes.File[] Files)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = GetChannel<SocketTextChannel>(Channel, CancellationToken, Server).Result.SendMessage(Message, CancellationToken, Files);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (OnError is not null) _ = OnError.Invoke(e);
|
||||||
|
else throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMultiThreadPercent(double num)
|
||||||
|
{
|
||||||
|
if (num < 1 || num > 100) throw new Exception("Number must be from 1 - 100");
|
||||||
|
Percent = num / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SocketMessage> GetMessage(long MessageId, CancellationToken CancellationToken, SocketServer Server) => await SocketMessage.GetMessage(MessageId, CancellationToken, Server);
|
||||||
|
|
||||||
|
public async Task<MainSocketRemoteUser> GetUser(long UserID, CancellationToken CancellationToken, SocketServer Server) => await SocketUserBase.GetUser(UserID, SocketRemoteUserContext.Default.SocketRemoteUser, CancellationToken, Server);
|
||||||
|
|
||||||
|
public async Task<TChannel> GetChannel<TChannel>(long Channel, CancellationToken CancellationToken, SocketServer Server) where TChannel : SocketChannel, new()
|
||||||
|
{
|
||||||
|
TChannel Return = new();
|
||||||
|
switch (Return)
|
||||||
|
{
|
||||||
|
case SocketDMChannel:
|
||||||
|
Return = (await SocketChannel.GetChannel(Channel, SocketDMChannelContext.Default.SocketDMChannel, CancellationToken, Server) as TChannel)!;
|
||||||
|
break;
|
||||||
|
case SocketGroupChannel:
|
||||||
|
Return = (await SocketChannel.GetChannel(Channel, SocketGroupChannelContext.Default.SocketGroupChannel, CancellationToken, Server) as TChannel)!;
|
||||||
|
break;
|
||||||
|
case SocketTextChannel:
|
||||||
|
Return = (await SocketChannel.GetChannel(Channel, SocketTextChannelContext.Default.SocketTextChannel, CancellationToken, Server) as TChannel)!;
|
||||||
|
break;
|
||||||
|
case SocketChannel:
|
||||||
|
Return = (await SocketChannel.GetChannel(Channel, SocketChannelContext.Default.SocketChannel, CancellationToken, Server) as TChannel)!;
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
throw new NullReferenceException(nameof(TChannel));
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown channel type");
|
||||||
|
}
|
||||||
|
return Return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SocketAppUser CurrentUser
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_user is null) throw new Exception("You must Login first");
|
||||||
|
return _user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1822 // Mark members as static
|
||||||
|
|
||||||
|
private void ServerOut_OnError(object? sender, WebSocketSharp.ErrorEventArgs e)
|
||||||
|
{
|
||||||
|
if (OnError is not null) OnError.Invoke(new Exception(e.Message));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Move to new Data layout")]
|
||||||
|
internal static void SendServer(string data)
|
||||||
|
{
|
||||||
|
ServerOut?.Send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SendServer<Tvalue>(Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo) where Tvalue : IncomingWSS
|
||||||
|
{
|
||||||
|
ServerOut?.Send(JsonSerializer.Serialize(Payload, jsonTypeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static HttpResponseMessage GetFromServer(SocketServer Server, string Path, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
|
{
|
||||||
|
using HttpClient web = new();
|
||||||
|
web.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
|
return web.GetAsync($"https://{Server.Domain}/{Server.ApiVersion}/{Path}", cancellationToken: CancellationToken).Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Task GetFromServer(SocketServer Server, string Path, string File, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers)
|
||||||
|
{
|
||||||
|
using HttpClient web = new();
|
||||||
|
web.Timeout = TimeSpan.FromMinutes(10);
|
||||||
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
|
HttpResponseMessage Response = web.GetAsync($"https://{Server.Domain}/{Server.ApiVersion}/{Path}", CancellationToken).Result;
|
||||||
|
Stream stream = Response.Content.ReadAsStreamAsync(CancellationToken).Result;
|
||||||
|
using FileStream fs = System.IO.File.Create(File);
|
||||||
|
stream.CopyTo(fs);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<Tresult> GetFromServer<Tresult>(SocketServer Server, string Path, JsonTypeInfo<Tresult> Type, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
||||||
|
{
|
||||||
|
HttpResponseMessage ServerResponce = GetFromServer(Server, Path, CancellationToken, Headers);
|
||||||
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, Type);
|
||||||
|
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<Tresult> SendServer<Tvalue, Tresult>(SocketServer Server, string Path, Tvalue Payload, JsonTypeInfo<Tvalue> jsonTypeInfo, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tvalue : IWebRequest where Tresult : IncomingHTTP, new()
|
||||||
|
{
|
||||||
|
using HttpClient web = new();
|
||||||
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
|
HttpResponseMessage ServerResponce = web.PostAsJsonAsync($"https://{Server.Domain}/{Server.ApiVersion}/{Path}", Payload, jsonTypeInfo, CancellationToken).Result;
|
||||||
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
|
Tresult error = new() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
|
if (string.IsNullOrWhiteSpace(ServerResponce.Content.ReadAsStringAsync(CancellationToken).Result)) return error;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, ReturnjsonTypeInfo);
|
||||||
|
if (temp is null) return error;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
catch { return error; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<Tresult> SendServer<Tresult>(SocketServer Server, string Path, string File, JsonTypeInfo<Tresult> ReturnjsonTypeInfo, CancellationToken CancellationToken, params KeyValuePair<string, string?>[] Headers) where Tresult : IncomingHTTP, new()
|
||||||
|
{
|
||||||
|
var fs = System.IO.File.OpenRead(File);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using HttpClient web = new();
|
||||||
|
if (!login) web.DefaultRequestHeaders.Add("token", Token);
|
||||||
|
web.Timeout = new TimeSpan(0, 10, 0);
|
||||||
|
if (Headers is not null && Headers.Length > 0) foreach (KeyValuePair<string, string?> header in Headers) web.DefaultRequestHeaders.Add(header.Key, header.Value);
|
||||||
|
HttpResponseMessage ServerResponce = web.PostAsync($"https://{Server.Domain}/{Server.ApiVersion}/{Path}", new StreamContent(fs), CancellationToken).Result;
|
||||||
|
if (!ServerResponce.IsSuccessStatusCode) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with status code {(int)ServerResponce.StatusCode}:{ServerResponce.StatusCode}" };
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Tresult? temp = JsonSerializer.Deserialize(ServerResponce.Content.ReadAsStreamAsync(CancellationToken).Result, ReturnjsonTypeInfo);
|
||||||
|
if (temp is null) return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" };
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
catch { return new Tresult() { StatusCode = ServerResponce.StatusCode, Error = ErrorCode.ServerError, ErrorMessage = $"Server responded with empty data" }; }
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fs.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -1,388 +0,0 @@
|
|||||||
using Luski.net.Enums;
|
|
||||||
using Luski.net.Interfaces;
|
|
||||||
using Luski.net.JsonTypes.BaseTypes;
|
|
||||||
using Luski.net.Sound;
|
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using static Luski.net.Exceptions;
|
|
||||||
|
|
||||||
namespace Luski.net.Sockets
|
|
||||||
{
|
|
||||||
internal class SocketAudioClient : IAudioClient
|
|
||||||
{
|
|
||||||
internal SocketAudioClient(long Channel, Func<Exception, Task>? error)
|
|
||||||
{
|
|
||||||
this.Channel = Channel;
|
|
||||||
errorin = error;
|
|
||||||
Muted = false;
|
|
||||||
PrototolClient.DataComplete += new Protocol.DelegateDataComplete(OnProtocolClient_DataComplete);
|
|
||||||
DataRecived += SocketAudioClient_DataRecived;
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Func<Task>? Connected;
|
|
||||||
|
|
||||||
public bool Muted { get; private set; }
|
|
||||||
|
|
||||||
public bool Deafened { get; private set; }
|
|
||||||
|
|
||||||
public void ToggleMic()
|
|
||||||
{
|
|
||||||
if (Muted == true)
|
|
||||||
{
|
|
||||||
Muted = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Muted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleAudio()
|
|
||||||
{
|
|
||||||
if (Deafened == true)
|
|
||||||
{
|
|
||||||
Deafened = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Deafened = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RecordSoundFrom(RecordingDevice Device)
|
|
||||||
{
|
|
||||||
if (Connectedb)
|
|
||||||
{
|
|
||||||
StartRecordingFromSounddevice_Client(Device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotConnectedException(this, "The call has not been connected yet!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlaySoundTo(PlaybackDevice Device)
|
|
||||||
{
|
|
||||||
if (Connectedb)
|
|
||||||
{
|
|
||||||
StartPlayingToSounddevice_Client(Device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new NotConnectedException(this, "The call has not been connected yet!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void JoinCall()
|
|
||||||
{
|
|
||||||
if (Connected == null)
|
|
||||||
{
|
|
||||||
throw new MissingEventException("Connected");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//get info
|
|
||||||
string data;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Server.CanRequest)
|
|
||||||
{
|
|
||||||
using HttpClient web = new();
|
|
||||||
web.DefaultRequestHeaders.Add("token", Server.Token);
|
|
||||||
web.DefaultRequestHeaders.Add("id", Channel.ToString());
|
|
||||||
data = web.GetAsync($"https://{Server.InternalDomain}/{Server.API_Ver}/GetCallInfo").Result.Content.ReadAsStringAsync().Result;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
call? json = JsonSerializer.Deserialize<call>(data);
|
|
||||||
Server.SendServer(JsonRequest.Send(DataType.Join_Call, JsonRequest.JoinCall(Channel)).ToString());
|
|
||||||
Samples = json.samples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class call : IncomingHTTP
|
|
||||||
{
|
|
||||||
public int samples { get; set; } = default!;
|
|
||||||
public string[] members { get; set; } = default!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LeaveCall()
|
|
||||||
{
|
|
||||||
Server.SendServer(JsonRequest.Send(DataType.Leave_Call, JsonRequest.JoinCall(Channel)).ToString());
|
|
||||||
StopRecordingFromSounddevice_Client();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Protocol PrototolClient = new(ProtocolTypes.LH, Encoding.Default);
|
|
||||||
private JitterBuffer RecordingJitterBuffer = new(null, JitterBuffer, 20);
|
|
||||||
private JitterBuffer PlayingJitterBuffer = new(null, JitterBuffer, 20);
|
|
||||||
private readonly Func<Exception, Task>? errorin;
|
|
||||||
private event Func<string, Task> DataRecived;
|
|
||||||
private static readonly uint JitterBuffer = 5;
|
|
||||||
private readonly int BitsPerSample = 16;
|
|
||||||
private long SequenceNumber = 4596;
|
|
||||||
private readonly int Channels = 1;
|
|
||||||
private Recorder? RecorderClient;
|
|
||||||
private bool Connectedb = false;
|
|
||||||
private bool recording = false;
|
|
||||||
private long m_TimeStamp = 0;
|
|
||||||
private Player? PlayerClient;
|
|
||||||
private readonly long Channel;
|
|
||||||
|
|
||||||
private void StopPlayingToSounddevice_Client()
|
|
||||||
{
|
|
||||||
if (PlayerClient != null)
|
|
||||||
{
|
|
||||||
PlayerClient.Close();
|
|
||||||
PlayerClient = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayingJitterBuffer != null)
|
|
||||||
{
|
|
||||||
PlayingJitterBuffer.Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SocketAudioClient_DataRecived(string arg)
|
|
||||||
{
|
|
||||||
cdata d = JsonSerializer.Deserialize<cdata>(arg);
|
|
||||||
byte[] data = Convert.FromBase64String(d.data);
|
|
||||||
PrototolClient.Receive_LH(this, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class cdata
|
|
||||||
{
|
|
||||||
public string data { get; set; } = default!;
|
|
||||||
public long from { get; set; } = default!;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SendData(byte[] data)
|
|
||||||
{
|
|
||||||
if (!Connectedb)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Server.SendServer(JsonRequest.Send(DataType.Call_Data, JsonRequest.SendCallData(PrototolClient.ToBytes(data), Channel)));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Givedata(dynamic data)
|
|
||||||
{
|
|
||||||
DataRecived.Invoke(((object)data).ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _samp;
|
|
||||||
|
|
||||||
internal int Samples
|
|
||||||
{
|
|
||||||
get => _samp;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_samp = value;
|
|
||||||
Connectedb = true;
|
|
||||||
if (Connected is not null) Connected.Invoke();
|
|
||||||
PlaySoundTo(Devices.GetDefaltPlaybackDevice());
|
|
||||||
RecordSoundFrom(Devices.GetDefaltRecordingDevice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool playing = false;
|
|
||||||
|
|
||||||
private void StartPlayingToSounddevice_Client(PlaybackDevice device)
|
|
||||||
{
|
|
||||||
if (playing)
|
|
||||||
{
|
|
||||||
StopPlayingToSounddevice_Client();
|
|
||||||
}
|
|
||||||
playing = true;
|
|
||||||
if (PlayingJitterBuffer != null)
|
|
||||||
{
|
|
||||||
PlayingJitterBuffer.DataAvailable -= new JitterBuffer.DelegateDataAvailable(OnJitterBufferClientDataAvailablePlaying);
|
|
||||||
|
|
||||||
PlayingJitterBuffer = new JitterBuffer(null, JitterBuffer, 20);
|
|
||||||
PlayingJitterBuffer.DataAvailable += new JitterBuffer.DelegateDataAvailable(OnJitterBufferClientDataAvailablePlaying);
|
|
||||||
PlayingJitterBuffer.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayerClient == null)
|
|
||||||
{
|
|
||||||
PlayerClient = new Player();
|
|
||||||
PlayerClient.Open(device.Name, Samples, BitsPerSample, Channels, (int)JitterBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnJitterBufferClientDataAvailablePlaying(object sender, RTPPacket rtp)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (PlayerClient != null)
|
|
||||||
{
|
|
||||||
if (PlayerClient.Opened)
|
|
||||||
{
|
|
||||||
if (Deafened == false)
|
|
||||||
{
|
|
||||||
byte[] linearBytes = Utils.MuLawToLinear(rtp.Data, BitsPerSample, Channels);
|
|
||||||
PlayerClient.PlayData(linearBytes, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.StackFrame sf = new(true);
|
|
||||||
errorin?.Invoke(new Exception(string.Format("Exception: {0} StackTrace: {1}. FileName: {2} Method: {3} Line: {4}", ex.Message, ex.StackTrace, sf.GetFileName(), sf.GetMethod(), sf.GetFileLineNumber())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartRecordingFromSounddevice_Client(RecordingDevice device)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (recording)
|
|
||||||
{
|
|
||||||
StopRecordingFromSounddevice_Client();
|
|
||||||
}
|
|
||||||
recording = true;
|
|
||||||
InitJitterBufferClientRecording();
|
|
||||||
int bufferSize = 0;
|
|
||||||
bufferSize = Utils.GetBytesPerInterval((uint)Samples, BitsPerSample, Channels) * 4;
|
|
||||||
|
|
||||||
if (bufferSize > 0)
|
|
||||||
{
|
|
||||||
RecorderClient = new Recorder();
|
|
||||||
RecorderClient.DataRecorded += new Recorder.DelegateDataRecorded(OnDataReceivedFromSoundcard_Client);
|
|
||||||
|
|
||||||
if (RecorderClient.Start(device.Name, Samples, BitsPerSample, Channels, 8, bufferSize))
|
|
||||||
{
|
|
||||||
|
|
||||||
RecordingJitterBuffer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
errorin.Invoke(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StopRecordingFromSounddevice_Client()
|
|
||||||
{
|
|
||||||
RecorderClient.Stop();
|
|
||||||
|
|
||||||
RecorderClient.DataRecorded -= new Recorder.DelegateDataRecorded(OnDataReceivedFromSoundcard_Client);
|
|
||||||
RecorderClient = null;
|
|
||||||
|
|
||||||
RecordingJitterBuffer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitJitterBufferClientRecording()
|
|
||||||
{
|
|
||||||
if (RecordingJitterBuffer != null)
|
|
||||||
{
|
|
||||||
RecordingJitterBuffer.DataAvailable -= new JitterBuffer.DelegateDataAvailable(OnJitterBufferClientDataAvailableRecording);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordingJitterBuffer = new JitterBuffer(null, 8, 20);
|
|
||||||
RecordingJitterBuffer.DataAvailable += new JitterBuffer.DelegateDataAvailable(OnJitterBufferClientDataAvailableRecording);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnJitterBufferClientDataAvailableRecording(object sender, RTPPacket rtp)
|
|
||||||
{
|
|
||||||
if (Muted == false && rtp != null && rtp.Data != null && rtp.Data.Length > 0)
|
|
||||||
{
|
|
||||||
byte[] rtpBytes = rtp.ToBytes();
|
|
||||||
SendData(rtpBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDataReceivedFromSoundcard_Client(byte[] data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
int bytesPerInterval = Utils.GetBytesPerInterval((uint)Samples, BitsPerSample, Channels);
|
|
||||||
int count = data.Length / bytesPerInterval;
|
|
||||||
int currentPos = 0;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
byte[] partBytes = new byte[bytesPerInterval];
|
|
||||||
Array.Copy(data, currentPos, partBytes, 0, bytesPerInterval);
|
|
||||||
currentPos += bytesPerInterval;
|
|
||||||
RTPPacket rtp = ToRTPPacket(partBytes, BitsPerSample, Channels);
|
|
||||||
|
|
||||||
RecordingJitterBuffer.AddData(rtp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RTPPacket ToRTPPacket(byte[] linearData, int bitsPerSample, int channels)
|
|
||||||
{
|
|
||||||
byte[] mulaws = Utils.LinearToMulaw(linearData, bitsPerSample, channels);
|
|
||||||
|
|
||||||
RTPPacket rtp = new()
|
|
||||||
{
|
|
||||||
Data = mulaws,
|
|
||||||
CSRCCount = 0,
|
|
||||||
Extension = false,
|
|
||||||
HeaderLength = RTPPacket.MinHeaderLength,
|
|
||||||
Marker = false,
|
|
||||||
Padding = false,
|
|
||||||
PayloadType = 0,
|
|
||||||
Version = 2,
|
|
||||||
SourceId = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
rtp.SequenceNumber = Convert.ToUInt16(SequenceNumber);
|
|
||||||
SequenceNumber++;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
SequenceNumber = 0;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
rtp.Timestamp = Convert.ToUInt32(m_TimeStamp);
|
|
||||||
m_TimeStamp += mulaws.Length;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
m_TimeStamp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnProtocolClient_DataComplete(object sender, byte[] data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (PlayerClient != null && PlayerClient.Opened)
|
|
||||||
{
|
|
||||||
RTPPacket rtp = new(data);
|
|
||||||
|
|
||||||
if (rtp.Data != null)
|
|
||||||
{
|
|
||||||
if (PlayingJitterBuffer != null)
|
|
||||||
{
|
|
||||||
PlayingJitterBuffer.AddData(rtp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
public static class Devices
|
|
||||||
{
|
|
||||||
public static RecordingDevice GetDefaltRecordingDevice()
|
|
||||||
{
|
|
||||||
return GetRecordingDevices()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlaybackDevice GetDefaltPlaybackDevice()
|
|
||||||
{
|
|
||||||
return GetPlaybackDevices()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IReadOnlyList<RecordingDevice> GetRecordingDevices()
|
|
||||||
{
|
|
||||||
List<string> RecordingNames = WinSound.GetRecordingNames();
|
|
||||||
List<RecordingDevice> RecordingDevices = new();
|
|
||||||
foreach (string Device in RecordingNames)
|
|
||||||
{
|
|
||||||
RecordingDevices.Add(new RecordingDevice(Device));
|
|
||||||
}
|
|
||||||
return RecordingDevices.AsReadOnly();
|
|
||||||
}
|
|
||||||
public static IReadOnlyList<PlaybackDevice> GetPlaybackDevices()
|
|
||||||
{
|
|
||||||
List<string> PlaybackName = WinSound.GetPlaybackNames();
|
|
||||||
List<PlaybackDevice> PlaybackDevices = new();
|
|
||||||
foreach (string Device in PlaybackName)
|
|
||||||
{
|
|
||||||
PlaybackDevices.Add(new PlaybackDevice(Device));
|
|
||||||
}
|
|
||||||
return PlaybackDevices.AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RecordingDevice
|
|
||||||
{
|
|
||||||
internal RecordingDevice(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlaybackDevice
|
|
||||||
{
|
|
||||||
internal PlaybackDevice(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class JitterBuffer
|
|
||||||
{
|
|
||||||
internal JitterBuffer(object? sender, uint maxRTPPackets, uint timerIntervalInMilliseconds)
|
|
||||||
{
|
|
||||||
if (maxRTPPackets < 2)
|
|
||||||
{
|
|
||||||
throw new Exception("Wrong Arguments. Minimum maxRTPPackets is 2");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Sender = sender;
|
|
||||||
Maximum = maxRTPPackets;
|
|
||||||
IntervalInMilliseconds = timerIntervalInMilliseconds;
|
|
||||||
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object? m_Sender = null;
|
|
||||||
private readonly EventTimer m_Timer = new();
|
|
||||||
private readonly Queue<RTPPacket> m_Buffer = new();
|
|
||||||
private RTPPacket m_LastRTPPacket = new();
|
|
||||||
private bool m_Underflow = true;
|
|
||||||
private bool m_Overflow = false;
|
|
||||||
|
|
||||||
internal delegate void DelegateDataAvailable(object sender, RTPPacket packet);
|
|
||||||
internal event DelegateDataAvailable? DataAvailable;
|
|
||||||
|
|
||||||
internal uint Maximum { get; } = 10;
|
|
||||||
internal uint IntervalInMilliseconds { get; } = 20;
|
|
||||||
private void Init()
|
|
||||||
{
|
|
||||||
InitTimer();
|
|
||||||
}
|
|
||||||
private void InitTimer()
|
|
||||||
{
|
|
||||||
m_Timer.TimerTick += new EventTimer.DelegateTimerTick(OnTimerTick);
|
|
||||||
}
|
|
||||||
internal void Start()
|
|
||||||
{
|
|
||||||
m_Timer.Start(IntervalInMilliseconds);
|
|
||||||
m_Underflow = true;
|
|
||||||
}
|
|
||||||
internal void Stop()
|
|
||||||
{
|
|
||||||
m_Timer.Stop();
|
|
||||||
m_Buffer.Clear();
|
|
||||||
}
|
|
||||||
private void OnTimerTick()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (DataAvailable != null)
|
|
||||||
{
|
|
||||||
if (m_Buffer.Count > 0)
|
|
||||||
{
|
|
||||||
if (m_Overflow)
|
|
||||||
{
|
|
||||||
if (m_Buffer.Count <= Maximum / 2)
|
|
||||||
{
|
|
||||||
m_Overflow = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Underflow)
|
|
||||||
{
|
|
||||||
if (m_Buffer.Count < Maximum / 2)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Underflow = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_LastRTPPacket = m_Buffer.Dequeue();
|
|
||||||
DataAvailable(m_Sender, m_LastRTPPacket);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Overflow = false;
|
|
||||||
|
|
||||||
if (m_LastRTPPacket != null && m_Underflow == false)
|
|
||||||
{
|
|
||||||
if (m_LastRTPPacket.Data != null)
|
|
||||||
{
|
|
||||||
m_Underflow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(string.Format("JitterBuffer.cs | OnTimerTick() | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal void AddData(RTPPacket packet)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (m_Overflow == false)
|
|
||||||
{
|
|
||||||
if (m_Buffer.Count <= Maximum)
|
|
||||||
{
|
|
||||||
m_Buffer.Enqueue(packet);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Overflow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(string.Format("JitterBuffer.cs | AddData() | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,417 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal unsafe class Player
|
|
||||||
{
|
|
||||||
internal Player()
|
|
||||||
{
|
|
||||||
|
|
||||||
delegateWaveOutProc = new Win32.DelegateWaveOutProc(WaveOutProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LockerClass Locker = new();
|
|
||||||
private readonly LockerClass LockerCopy = new();
|
|
||||||
private IntPtr hWaveOut = IntPtr.Zero;
|
|
||||||
private string WaveOutDeviceName = "";
|
|
||||||
private bool IsWaveOutOpened = false;
|
|
||||||
private bool IsThreadPlayWaveOutRunning = false;
|
|
||||||
private bool IsClosed = false;
|
|
||||||
private bool IsPaused = false;
|
|
||||||
private bool IsStarted = false;
|
|
||||||
private bool IsBlocking = false;
|
|
||||||
private int SamplesPerSecond = 8000;
|
|
||||||
private int BitsPerSample = 16;
|
|
||||||
private int Channels = 1;
|
|
||||||
private int BufferCount = 8;
|
|
||||||
private readonly int BufferLength = 1024;
|
|
||||||
private Win32.WAVEHDR*[] WaveOutHeaders;
|
|
||||||
private readonly Win32.DelegateWaveOutProc delegateWaveOutProc;
|
|
||||||
private Thread? ThreadPlayWaveOut;
|
|
||||||
private readonly AutoResetEvent AutoResetEventDataPlayed = new(false);
|
|
||||||
|
|
||||||
internal delegate void DelegateStopped();
|
|
||||||
internal event DelegateStopped? PlayerClosed;
|
|
||||||
internal event DelegateStopped? PlayerStopped;
|
|
||||||
|
|
||||||
internal bool Opened => IsWaveOutOpened & IsClosed == false;
|
|
||||||
|
|
||||||
internal bool Playing
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Opened && IsStarted)
|
|
||||||
{
|
|
||||||
foreach (Win32.WAVEHDR* pHeader in WaveOutHeaders)
|
|
||||||
{
|
|
||||||
if (IsHeaderInqueue(*pHeader))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CreateWaveOutHeaders()
|
|
||||||
{
|
|
||||||
WaveOutHeaders = new Win32.WAVEHDR*[BufferCount];
|
|
||||||
int createdHeaders = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < BufferCount; i++)
|
|
||||||
{
|
|
||||||
WaveOutHeaders[i] = (Win32.WAVEHDR*)Marshal.AllocHGlobal(sizeof(Win32.WAVEHDR));
|
|
||||||
|
|
||||||
WaveOutHeaders[i]->dwLoops = 0;
|
|
||||||
WaveOutHeaders[i]->dwUser = IntPtr.Zero;
|
|
||||||
WaveOutHeaders[i]->lpNext = IntPtr.Zero;
|
|
||||||
WaveOutHeaders[i]->reserved = IntPtr.Zero;
|
|
||||||
WaveOutHeaders[i]->lpData = Marshal.AllocHGlobal(BufferLength);
|
|
||||||
WaveOutHeaders[i]->dwBufferLength = (uint)BufferLength;
|
|
||||||
WaveOutHeaders[i]->dwBytesRecorded = 0;
|
|
||||||
WaveOutHeaders[i]->dwFlags = 0;
|
|
||||||
|
|
||||||
Win32.MMRESULT hr = Win32.waveOutPrepareHeader(hWaveOut, WaveOutHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
|
|
||||||
{
|
|
||||||
createdHeaders++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (createdHeaders == BufferCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FreeWaveOutHeaders()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (WaveOutHeaders != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < WaveOutHeaders.Length; i++)
|
|
||||||
{
|
|
||||||
Win32.MMRESULT hr = Win32.waveOutUnprepareHeader(hWaveOut, WaveOutHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
while (count <= 100 && (WaveOutHeaders[i]->dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) == Win32.WaveHdrFlags.WHDR_INQUEUE)
|
|
||||||
{
|
|
||||||
Thread.Sleep(20);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((WaveOutHeaders[i]->dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) != Win32.WaveHdrFlags.WHDR_INQUEUE)
|
|
||||||
{
|
|
||||||
if (WaveOutHeaders[i]->lpData != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(WaveOutHeaders[i]->lpData);
|
|
||||||
WaveOutHeaders[i]->lpData = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.Write(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartThreadPlayWaveOut()
|
|
||||||
{
|
|
||||||
if (IsThreadPlayWaveOutRunning == false)
|
|
||||||
{
|
|
||||||
ThreadPlayWaveOut = new System.Threading.Thread(new System.Threading.ThreadStart(OnThreadPlayWaveOut));
|
|
||||||
IsThreadPlayWaveOutRunning = true;
|
|
||||||
ThreadPlayWaveOut.Name = "PlayWaveOut";
|
|
||||||
ThreadPlayWaveOut.Priority = System.Threading.ThreadPriority.Highest;
|
|
||||||
ThreadPlayWaveOut.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool OpenWaveOut()
|
|
||||||
{
|
|
||||||
if (hWaveOut == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
if (IsWaveOutOpened == false)
|
|
||||||
{
|
|
||||||
Win32.WAVEFORMATEX waveFormatEx = new()
|
|
||||||
{
|
|
||||||
wFormatTag = (ushort)Win32.WaveFormatFlags.WAVE_FORMAT_PCM,
|
|
||||||
nChannels = (ushort)Channels,
|
|
||||||
nSamplesPerSec = (ushort)SamplesPerSecond,
|
|
||||||
wBitsPerSample = (ushort)BitsPerSample
|
|
||||||
};
|
|
||||||
waveFormatEx.nBlockAlign = (ushort)((waveFormatEx.wBitsPerSample * waveFormatEx.nChannels) >> 3);
|
|
||||||
waveFormatEx.nAvgBytesPerSec = waveFormatEx.nBlockAlign * waveFormatEx.nSamplesPerSec;
|
|
||||||
|
|
||||||
int deviceId = WinSound.GetWaveOutDeviceIdByName(WaveOutDeviceName);
|
|
||||||
Win32.MMRESULT hr = Win32.waveOutOpen(ref hWaveOut, deviceId, ref waveFormatEx, delegateWaveOutProc, 0, (int)Win32.WaveProcFlags.CALLBACK_FUNCTION);
|
|
||||||
|
|
||||||
if (hr != Win32.MMRESULT.MMSYSERR_NOERROR)
|
|
||||||
{
|
|
||||||
IsWaveOutOpened = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GCHandle.Alloc(hWaveOut, GCHandleType.Pinned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IsWaveOutOpened = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool Open(string waveOutDeviceName, int samplesPerSecond, int bitsPerSample, int channels, int bufferCount)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
if (Opened == false)
|
|
||||||
{
|
|
||||||
|
|
||||||
WaveOutDeviceName = waveOutDeviceName;
|
|
||||||
SamplesPerSecond = samplesPerSecond;
|
|
||||||
BitsPerSample = bitsPerSample;
|
|
||||||
Channels = channels;
|
|
||||||
BufferCount = Math.Max(bufferCount, 1);
|
|
||||||
|
|
||||||
if (OpenWaveOut())
|
|
||||||
{
|
|
||||||
if (CreateWaveOutHeaders())
|
|
||||||
{
|
|
||||||
StartThreadPlayWaveOut();
|
|
||||||
IsClosed = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Start | {0}", ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool PlayData(byte[] datas, bool isBlocking)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Opened)
|
|
||||||
{
|
|
||||||
int index = GetNextFreeWaveOutHeaderIndex();
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
IsBlocking = isBlocking;
|
|
||||||
|
|
||||||
if (WaveOutHeaders[index]->dwBufferLength != datas.Length)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(WaveOutHeaders[index]->lpData);
|
|
||||||
WaveOutHeaders[index]->lpData = Marshal.AllocHGlobal(datas.Length);
|
|
||||||
WaveOutHeaders[index]->dwBufferLength = (uint)datas.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
WaveOutHeaders[index]->dwBufferLength = (uint)datas.Length;
|
|
||||||
WaveOutHeaders[index]->dwUser = (IntPtr)index;
|
|
||||||
Marshal.Copy(datas, 0, WaveOutHeaders[index]->lpData, datas.Length);
|
|
||||||
|
|
||||||
IsStarted = true;
|
|
||||||
Win32.MMRESULT hr = Win32.waveOutWrite(hWaveOut, WaveOutHeaders[index], sizeof(Win32.WAVEHDR));
|
|
||||||
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
|
|
||||||
{
|
|
||||||
if (isBlocking)
|
|
||||||
{
|
|
||||||
AutoResetEventDataPlayed.WaitOne();
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("No free WaveOut Buffer found | {0}", DateTime.Now.ToLongTimeString()));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("PlayData | {0}", ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool Close()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
if (Opened)
|
|
||||||
{
|
|
||||||
IsClosed = true;
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
while (Win32.waveOutReset(hWaveOut) != Win32.MMRESULT.MMSYSERR_NOERROR && count <= 100)
|
|
||||||
{
|
|
||||||
Thread.Sleep(50);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeWaveOutHeaders();
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
while (Win32.waveOutClose(hWaveOut) != Win32.MMRESULT.MMSYSERR_NOERROR && count <= 100)
|
|
||||||
{
|
|
||||||
Thread.Sleep(50);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsWaveOutOpened = false;
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Close | {0}", ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetNextFreeWaveOutHeaderIndex()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < WaveOutHeaders.Length; i++)
|
|
||||||
{
|
|
||||||
if (IsHeaderPrepared(*WaveOutHeaders[i]) && !IsHeaderInqueue(*WaveOutHeaders[i]))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsHeaderPrepared(Win32.WAVEHDR header)
|
|
||||||
{
|
|
||||||
return (header.dwFlags & Win32.WaveHdrFlags.WHDR_PREPARED) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsHeaderInqueue(Win32.WAVEHDR header)
|
|
||||||
{
|
|
||||||
return (header.dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WaveOutProc(IntPtr hWaveOut, Win32.WOM_Messages msg, IntPtr dwInstance, Win32.WAVEHDR* pWaveHeader, IntPtr lParam)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
//Open
|
|
||||||
case Win32.WOM_Messages.OPEN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Done
|
|
||||||
case Win32.WOM_Messages.DONE:
|
|
||||||
IsStarted = true;
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Close
|
|
||||||
case Win32.WOM_Messages.CLOSE:
|
|
||||||
IsStarted = false;
|
|
||||||
IsWaveOutOpened = false;
|
|
||||||
IsPaused = false;
|
|
||||||
IsClosed = true;
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
hWaveOut = IntPtr.Zero;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Player.cs | waveOutProc() | {0}", ex.Message));
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnThreadPlayWaveOut()
|
|
||||||
{
|
|
||||||
while (Opened && !IsClosed)
|
|
||||||
{
|
|
||||||
AutoResetEventDataPlayed.WaitOne();
|
|
||||||
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
if (Opened && !IsClosed)
|
|
||||||
{
|
|
||||||
IsThreadPlayWaveOutRunning = true;
|
|
||||||
|
|
||||||
if (!Playing)
|
|
||||||
{
|
|
||||||
if (IsStarted)
|
|
||||||
{
|
|
||||||
IsStarted = false;
|
|
||||||
if (PlayerStopped != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PlayerStopped();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Player Stopped | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsBlocking)
|
|
||||||
{
|
|
||||||
AutoResetEventDataPlayed.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
IsThreadPlayWaveOutRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayerClosed != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PlayerClosed();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Player Closed | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal enum ProtocolTypes
|
|
||||||
{
|
|
||||||
LH
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class Protocol
|
|
||||||
{
|
|
||||||
internal Protocol(ProtocolTypes type, Encoding encoding)
|
|
||||||
{
|
|
||||||
m_ProtocolType = type;
|
|
||||||
m_Encoding = encoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly List<byte> m_DataBuffer = new();
|
|
||||||
private const int m_MaxBufferLength = 10000;
|
|
||||||
private readonly ProtocolTypes m_ProtocolType = ProtocolTypes.LH;
|
|
||||||
private readonly Encoding m_Encoding = Encoding.Default;
|
|
||||||
internal object m_LockerReceive = new();
|
|
||||||
|
|
||||||
internal delegate void DelegateDataComplete(object sender, byte[] data);
|
|
||||||
internal delegate void DelegateExceptionAppeared(object sender, Exception ex);
|
|
||||||
internal event DelegateDataComplete DataComplete;
|
|
||||||
internal event DelegateExceptionAppeared ExceptionAppeared;
|
|
||||||
|
|
||||||
internal byte[] ToBytes(byte[] data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] bytesLength = BitConverter.GetBytes(data.Length);
|
|
||||||
|
|
||||||
byte[] allBytes = new byte[bytesLength.Length + data.Length];
|
|
||||||
Array.Copy(bytesLength, allBytes, bytesLength.Length);
|
|
||||||
Array.Copy(data, 0, allBytes, bytesLength.Length, data.Length);
|
|
||||||
|
|
||||||
return allBytes;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ExceptionAppeared(null, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Receive_LH(object sender, byte[] data)
|
|
||||||
{
|
|
||||||
lock (m_LockerReceive)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_DataBuffer.AddRange(data);
|
|
||||||
|
|
||||||
if (m_DataBuffer.Count > m_MaxBufferLength)
|
|
||||||
{
|
|
||||||
m_DataBuffer.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = m_DataBuffer.Take(4).ToArray();
|
|
||||||
int length = BitConverter.ToInt32(bytes.ToArray(), 0);
|
|
||||||
|
|
||||||
if (length > m_MaxBufferLength)
|
|
||||||
{
|
|
||||||
m_DataBuffer.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (m_DataBuffer.Count >= length + 4)
|
|
||||||
{
|
|
||||||
byte[] message = m_DataBuffer.Skip(4).Take(length).ToArray();
|
|
||||||
|
|
||||||
DataComplete?.Invoke(sender, message);
|
|
||||||
m_DataBuffer.RemoveRange(0, length + 4);
|
|
||||||
|
|
||||||
if (m_DataBuffer.Count > 4)
|
|
||||||
{
|
|
||||||
bytes = m_DataBuffer.Take(4).ToArray();
|
|
||||||
length = BitConverter.ToInt32(bytes.ToArray(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
m_DataBuffer.Clear();
|
|
||||||
ExceptionAppeared(null, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class RTPPacket
|
|
||||||
{
|
|
||||||
internal RTPPacket()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal RTPPacket(byte[] data)
|
|
||||||
{
|
|
||||||
Parse(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int MinHeaderLength = 12;
|
|
||||||
internal int HeaderLength = MinHeaderLength;
|
|
||||||
internal int Version = 0;
|
|
||||||
internal bool Padding = false;
|
|
||||||
internal bool Extension = false;
|
|
||||||
internal int CSRCCount = 0;
|
|
||||||
internal bool Marker = false;
|
|
||||||
internal int PayloadType = 0;
|
|
||||||
internal ushort SequenceNumber = 0;
|
|
||||||
internal uint Timestamp = 0;
|
|
||||||
internal uint SourceId = 0;
|
|
||||||
internal byte[]? Data;
|
|
||||||
internal ushort ExtensionHeaderId = 0;
|
|
||||||
internal ushort ExtensionLengthAsCount = 0;
|
|
||||||
internal int ExtensionLengthInBytes = 0;
|
|
||||||
|
|
||||||
private void Parse(byte[] data)
|
|
||||||
{
|
|
||||||
if (data.Length >= MinHeaderLength)
|
|
||||||
{
|
|
||||||
Version = ValueFromByte(data[0], 6, 2);
|
|
||||||
Padding = Convert.ToBoolean(ValueFromByte(data[0], 5, 1));
|
|
||||||
Extension = Convert.ToBoolean(ValueFromByte(data[0], 4, 1));
|
|
||||||
CSRCCount = ValueFromByte(data[0], 0, 4);
|
|
||||||
Marker = Convert.ToBoolean(ValueFromByte(data[1], 7, 1));
|
|
||||||
PayloadType = ValueFromByte(data[1], 0, 7);
|
|
||||||
HeaderLength = MinHeaderLength + (CSRCCount * 4);
|
|
||||||
|
|
||||||
//Sequence Nummer
|
|
||||||
byte[] seqNum = new byte[2];
|
|
||||||
seqNum[0] = data[3];
|
|
||||||
seqNum[1] = data[2];
|
|
||||||
SequenceNumber = BitConverter.ToUInt16(seqNum, 0);
|
|
||||||
|
|
||||||
//TimeStamp
|
|
||||||
byte[] timeStmp = new byte[4];
|
|
||||||
timeStmp[0] = data[7];
|
|
||||||
timeStmp[1] = data[6];
|
|
||||||
timeStmp[2] = data[5];
|
|
||||||
timeStmp[3] = data[4];
|
|
||||||
Timestamp = BitConverter.ToUInt32(timeStmp, 0);
|
|
||||||
|
|
||||||
//SourceId
|
|
||||||
byte[] srcId = new byte[4];
|
|
||||||
srcId[0] = data[8];
|
|
||||||
srcId[1] = data[9];
|
|
||||||
srcId[2] = data[10];
|
|
||||||
srcId[3] = data[11];
|
|
||||||
SourceId = BitConverter.ToUInt32(srcId, 0);
|
|
||||||
|
|
||||||
if (Extension)
|
|
||||||
{
|
|
||||||
byte[] extHeaderId = new byte[2];
|
|
||||||
extHeaderId[1] = data[HeaderLength + 0];
|
|
||||||
extHeaderId[0] = data[HeaderLength + 1];
|
|
||||||
ExtensionHeaderId = BitConverter.ToUInt16(extHeaderId, 0);
|
|
||||||
|
|
||||||
byte[] extHeaderLength16 = new byte[2];
|
|
||||||
extHeaderLength16[1] = data[HeaderLength + 2];
|
|
||||||
extHeaderLength16[0] = data[HeaderLength + 3];
|
|
||||||
ExtensionLengthAsCount = BitConverter.ToUInt16(extHeaderLength16.ToArray(), 0);
|
|
||||||
|
|
||||||
ExtensionLengthInBytes = ExtensionLengthAsCount * 4;
|
|
||||||
HeaderLength += ExtensionLengthInBytes + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
Data = new byte[data.Length - HeaderLength];
|
|
||||||
Array.Copy(data, HeaderLength, Data, 0, data.Length - HeaderLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int ValueFromByte(byte value, int startPos, int length)
|
|
||||||
{
|
|
||||||
byte mask = 0;
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
mask = (byte)(mask | 0x1 << startPos + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte result = (byte)((value & mask) >> startPos);
|
|
||||||
return Convert.ToInt32(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal byte[] ToBytes()
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[HeaderLength + Data.Length];
|
|
||||||
|
|
||||||
//Byte 0
|
|
||||||
bytes[0] = (byte)(Version << 6);
|
|
||||||
bytes[0] |= (byte)(Convert.ToInt32(Padding) << 5);
|
|
||||||
bytes[0] |= (byte)(Convert.ToInt32(Extension) << 4);
|
|
||||||
bytes[0] |= (byte)(Convert.ToInt32(CSRCCount));
|
|
||||||
|
|
||||||
//Byte 1
|
|
||||||
bytes[1] = (byte)(Convert.ToInt32(Marker) << 7);
|
|
||||||
bytes[1] |= (byte)(Convert.ToInt32(PayloadType));
|
|
||||||
|
|
||||||
//Byte 2 + 3
|
|
||||||
byte[] bytesSequenceNumber = BitConverter.GetBytes(SequenceNumber);
|
|
||||||
bytes[2] = bytesSequenceNumber[1];
|
|
||||||
bytes[3] = bytesSequenceNumber[0];
|
|
||||||
|
|
||||||
//Byte 4 bis 7
|
|
||||||
byte[] bytesTimeStamp = BitConverter.GetBytes(Timestamp);
|
|
||||||
bytes[4] = bytesTimeStamp[3];
|
|
||||||
bytes[5] = bytesTimeStamp[2];
|
|
||||||
bytes[6] = bytesTimeStamp[1];
|
|
||||||
bytes[7] = bytesTimeStamp[0];
|
|
||||||
|
|
||||||
//Byte 8 bis 11
|
|
||||||
byte[] bytesSourceId = BitConverter.GetBytes(SourceId);
|
|
||||||
bytes[8] = bytesSourceId[3];
|
|
||||||
bytes[9] = bytesSourceId[2];
|
|
||||||
bytes[10] = bytesSourceId[1];
|
|
||||||
bytes[11] = bytesSourceId[0];
|
|
||||||
|
|
||||||
Array.Copy(Data, 0, bytes, HeaderLength, Data.Length);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,340 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal unsafe class Recorder
|
|
||||||
{
|
|
||||||
internal Recorder()
|
|
||||||
{
|
|
||||||
delegateWaveInProc = new Win32.DelegateWaveInProc(WaveInProc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LockerClass Locker = new();
|
|
||||||
private readonly LockerClass LockerCopy = new();
|
|
||||||
private IntPtr hWaveIn = IntPtr.Zero;
|
|
||||||
private string WaveInDeviceName = "";
|
|
||||||
private bool IsWaveInOpened = false;
|
|
||||||
private bool IsWaveInStarted = false;
|
|
||||||
private bool IsThreadRecordingRunning = false;
|
|
||||||
private bool IsDataIncomming = false;
|
|
||||||
private bool Stopped = false;
|
|
||||||
private int SamplesPerSecond = 8000;
|
|
||||||
private int BitsPerSample = 16;
|
|
||||||
private int Channels = 1;
|
|
||||||
private int BufferCount = 8;
|
|
||||||
private int BufferSize = 1024;
|
|
||||||
private Win32.WAVEHDR*[] WaveInHeaders;
|
|
||||||
private Win32.WAVEHDR* CurrentRecordedHeader;
|
|
||||||
private readonly Win32.DelegateWaveInProc delegateWaveInProc;
|
|
||||||
private Thread ThreadRecording;
|
|
||||||
private readonly AutoResetEvent AutoResetEventDataRecorded = new(false);
|
|
||||||
|
|
||||||
internal delegate void DelegateStopped();
|
|
||||||
internal delegate void DelegateDataRecorded(byte[] bytes);
|
|
||||||
internal event DelegateStopped RecordingStopped;
|
|
||||||
internal event DelegateDataRecorded DataRecorded;
|
|
||||||
|
|
||||||
internal bool Started => IsWaveInStarted && IsWaveInOpened && IsThreadRecordingRunning;
|
|
||||||
|
|
||||||
private bool CreateWaveInHeaders()
|
|
||||||
{
|
|
||||||
WaveInHeaders = new Win32.WAVEHDR*[BufferCount];
|
|
||||||
int createdHeaders = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < BufferCount; i++)
|
|
||||||
{
|
|
||||||
WaveInHeaders[i] = (Win32.WAVEHDR*)Marshal.AllocHGlobal(sizeof(Win32.WAVEHDR));
|
|
||||||
|
|
||||||
WaveInHeaders[i]->dwLoops = 0;
|
|
||||||
WaveInHeaders[i]->dwUser = IntPtr.Zero;
|
|
||||||
WaveInHeaders[i]->lpNext = IntPtr.Zero;
|
|
||||||
WaveInHeaders[i]->reserved = IntPtr.Zero;
|
|
||||||
WaveInHeaders[i]->lpData = Marshal.AllocHGlobal(BufferSize);
|
|
||||||
WaveInHeaders[i]->dwBufferLength = (uint)BufferSize;
|
|
||||||
WaveInHeaders[i]->dwBytesRecorded = 0;
|
|
||||||
WaveInHeaders[i]->dwFlags = 0;
|
|
||||||
|
|
||||||
Win32.MMRESULT hr = Win32.waveInPrepareHeader(hWaveIn, WaveInHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
|
|
||||||
{
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
hr = Win32.waveInAddBuffer(hWaveIn, WaveInHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
}
|
|
||||||
createdHeaders++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (createdHeaders == BufferCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FreeWaveInHeaders()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (WaveInHeaders != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < WaveInHeaders.Length; i++)
|
|
||||||
{
|
|
||||||
Win32.MMRESULT hr = Win32.waveInUnprepareHeader(hWaveIn, WaveInHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
while (count <= 100 && (WaveInHeaders[i]->dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) == Win32.WaveHdrFlags.WHDR_INQUEUE)
|
|
||||||
{
|
|
||||||
Thread.Sleep(20);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((WaveInHeaders[i]->dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) != Win32.WaveHdrFlags.WHDR_INQUEUE)
|
|
||||||
{
|
|
||||||
if (WaveInHeaders[i]->lpData != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(WaveInHeaders[i]->lpData);
|
|
||||||
WaveInHeaders[i]->lpData = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.Write(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartThreadRecording()
|
|
||||||
{
|
|
||||||
if (Started == false)
|
|
||||||
{
|
|
||||||
ThreadRecording = new Thread(new ThreadStart(OnThreadRecording));
|
|
||||||
IsThreadRecordingRunning = true;
|
|
||||||
ThreadRecording.Name = "Recording";
|
|
||||||
ThreadRecording.Priority = ThreadPriority.Highest;
|
|
||||||
ThreadRecording.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool OpenWaveIn()
|
|
||||||
{
|
|
||||||
if (hWaveIn == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
if (IsWaveInOpened == false)
|
|
||||||
{
|
|
||||||
Win32.WAVEFORMATEX waveFormatEx = new()
|
|
||||||
{
|
|
||||||
wFormatTag = (ushort)Win32.WaveFormatFlags.WAVE_FORMAT_PCM,
|
|
||||||
nChannels = (ushort)Channels,
|
|
||||||
nSamplesPerSec = (ushort)SamplesPerSecond,
|
|
||||||
wBitsPerSample = (ushort)BitsPerSample
|
|
||||||
};
|
|
||||||
waveFormatEx.nBlockAlign = (ushort)((waveFormatEx.wBitsPerSample * waveFormatEx.nChannels) >> 3);
|
|
||||||
waveFormatEx.nAvgBytesPerSec = waveFormatEx.nBlockAlign * waveFormatEx.nSamplesPerSec;
|
|
||||||
|
|
||||||
int deviceId = WinSound.GetWaveInDeviceIdByName(WaveInDeviceName);
|
|
||||||
Win32.MMRESULT hr = Win32.waveInOpen(ref hWaveIn, deviceId, ref waveFormatEx, delegateWaveInProc, 0, (int)Win32.WaveProcFlags.CALLBACK_FUNCTION);
|
|
||||||
|
|
||||||
if (hWaveIn == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
IsWaveInOpened = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GCHandle.Alloc(hWaveIn, GCHandleType.Pinned);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IsWaveInOpened = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool Start(string waveInDeviceName, int samplesPerSecond, int bitsPerSample, int channels, int bufferCount, int bufferSize)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
if (Started == false)
|
|
||||||
{
|
|
||||||
WaveInDeviceName = waveInDeviceName;
|
|
||||||
SamplesPerSecond = samplesPerSecond;
|
|
||||||
BitsPerSample = bitsPerSample;
|
|
||||||
Channels = channels;
|
|
||||||
BufferCount = bufferCount;
|
|
||||||
BufferSize = bufferSize;
|
|
||||||
|
|
||||||
if (OpenWaveIn())
|
|
||||||
{
|
|
||||||
if (CreateWaveInHeaders())
|
|
||||||
{
|
|
||||||
Win32.MMRESULT hr = Win32.waveInStart(hWaveIn);
|
|
||||||
if (hr == Win32.MMRESULT.MMSYSERR_NOERROR)
|
|
||||||
{
|
|
||||||
IsWaveInStarted = true;
|
|
||||||
StartThreadRecording();
|
|
||||||
Stopped = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Start | {0}", ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool Stop()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
if (Started)
|
|
||||||
{
|
|
||||||
Stopped = true;
|
|
||||||
IsThreadRecordingRunning = false;
|
|
||||||
|
|
||||||
CloseWaveIn();
|
|
||||||
|
|
||||||
AutoResetEventDataRecorded.Set();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Stop | {0}", ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseWaveIn()
|
|
||||||
{
|
|
||||||
Win32.MMRESULT hr = Win32.waveInStop(hWaveIn);
|
|
||||||
|
|
||||||
int resetCount = 0;
|
|
||||||
while (IsAnyWaveInHeaderInState(Win32.WaveHdrFlags.WHDR_INQUEUE) & resetCount < 20)
|
|
||||||
{
|
|
||||||
hr = Win32.waveInReset(hWaveIn);
|
|
||||||
Thread.Sleep(50);
|
|
||||||
resetCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeWaveInHeaders();
|
|
||||||
hr = Win32.waveInClose(hWaveIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsAnyWaveInHeaderInState(Win32.WaveHdrFlags state)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < WaveInHeaders.Length; i++)
|
|
||||||
{
|
|
||||||
if ((WaveInHeaders[i]->dwFlags & state) == state)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WaveInProc(IntPtr hWaveIn, Win32.WIM_Messages msg, IntPtr dwInstance, Win32.WAVEHDR* pWaveHdr, IntPtr lParam)
|
|
||||||
{
|
|
||||||
switch (msg)
|
|
||||||
{
|
|
||||||
//Open
|
|
||||||
case Win32.WIM_Messages.OPEN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Data
|
|
||||||
case Win32.WIM_Messages.DATA:
|
|
||||||
IsDataIncomming = true;
|
|
||||||
CurrentRecordedHeader = pWaveHdr;
|
|
||||||
AutoResetEventDataRecorded.Set();
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Close
|
|
||||||
case Win32.WIM_Messages.CLOSE:
|
|
||||||
IsDataIncomming = false;
|
|
||||||
IsWaveInOpened = false;
|
|
||||||
AutoResetEventDataRecorded.Set();
|
|
||||||
this.hWaveIn = IntPtr.Zero;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnThreadRecording()
|
|
||||||
{
|
|
||||||
while (Started && !Stopped)
|
|
||||||
{
|
|
||||||
AutoResetEventDataRecorded.WaitOne();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Started && !Stopped)
|
|
||||||
{
|
|
||||||
if (CurrentRecordedHeader->dwBytesRecorded > 0)
|
|
||||||
{
|
|
||||||
if (DataRecorded != null && IsDataIncomming)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] bytes = new byte[CurrentRecordedHeader->dwBytesRecorded];
|
|
||||||
Marshal.Copy(CurrentRecordedHeader->lpData, bytes, 0, (int)CurrentRecordedHeader->dwBytesRecorded);
|
|
||||||
|
|
||||||
DataRecorded(bytes);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Recorder.cs | OnThreadRecording() | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < WaveInHeaders.Length; i++)
|
|
||||||
{
|
|
||||||
if ((WaveInHeaders[i]->dwFlags & Win32.WaveHdrFlags.WHDR_INQUEUE) == 0)
|
|
||||||
{
|
|
||||||
Win32.MMRESULT hr = Win32.waveInAddBuffer(hWaveIn, WaveInHeaders[i], sizeof(Win32.WAVEHDR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lock (Locker)
|
|
||||||
{
|
|
||||||
IsWaveInStarted = false;
|
|
||||||
IsThreadRecordingRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RecordingStopped != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RecordingStopped();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(string.Format("Recording Stopped | {0}", ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class EventTimer
|
|
||||||
{
|
|
||||||
internal EventTimer()
|
|
||||||
{
|
|
||||||
m_DelegateTimeEvent = new Win32.TimerEventHandler(OnTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool m_IsRunning = false;
|
|
||||||
private uint m_Milliseconds = 20;
|
|
||||||
private uint m_TimerId = 0;
|
|
||||||
private GCHandle m_GCHandleTimer;
|
|
||||||
private uint m_UserData = 0;
|
|
||||||
private uint m_ResolutionInMilliseconds = 0;
|
|
||||||
|
|
||||||
private readonly Win32.TimerEventHandler m_DelegateTimeEvent;
|
|
||||||
internal delegate void DelegateTimerTick();
|
|
||||||
internal event DelegateTimerTick? TimerTick;
|
|
||||||
|
|
||||||
internal void Start(uint milliseconds)
|
|
||||||
{
|
|
||||||
m_Milliseconds = milliseconds;
|
|
||||||
|
|
||||||
Win32.TimeCaps tc = new();
|
|
||||||
Win32.TimeGetDevCaps(ref tc, (uint)Marshal.SizeOf(typeof(Win32.TimeCaps)));
|
|
||||||
m_ResolutionInMilliseconds = Math.Max(tc.wPeriodMin, 0);
|
|
||||||
|
|
||||||
Win32.TimeBeginPeriod(m_ResolutionInMilliseconds);
|
|
||||||
|
|
||||||
m_TimerId = Win32.TimeSetEvent(m_Milliseconds, m_ResolutionInMilliseconds, m_DelegateTimeEvent, ref m_UserData, Win32.TIME_PERIODIC);
|
|
||||||
if (m_TimerId > 0)
|
|
||||||
{
|
|
||||||
m_GCHandleTimer = GCHandle.Alloc(m_TimerId, GCHandleType.Pinned);
|
|
||||||
m_IsRunning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void Stop()
|
|
||||||
{
|
|
||||||
if (m_TimerId > 0)
|
|
||||||
{
|
|
||||||
_ = Win32.TimeKillEvent(m_TimerId);
|
|
||||||
Win32.TimeEndPeriod(m_ResolutionInMilliseconds);
|
|
||||||
|
|
||||||
if (m_GCHandleTimer.IsAllocated)
|
|
||||||
{
|
|
||||||
m_GCHandleTimer.Free();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_TimerId = 0;
|
|
||||||
m_IsRunning = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimer(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2)
|
|
||||||
{
|
|
||||||
TimerTick?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,195 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class Utils
|
|
||||||
{
|
|
||||||
internal Utils()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int SIGN_BIT = 0x80;
|
|
||||||
private const int QUANT_MASK = 0xf;
|
|
||||||
private const int SEG_SHIFT = 4;
|
|
||||||
private const int SEG_MASK = 0x70;
|
|
||||||
private const int BIAS = 0x84;
|
|
||||||
private const int CLIP = 8159;
|
|
||||||
private static readonly short[] seg_uend = new short[] { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF };
|
|
||||||
|
|
||||||
internal static int GetBytesPerInterval(uint SamplesPerSecond, int BitsPerSample, int Channels)
|
|
||||||
{
|
|
||||||
int blockAlign = ((BitsPerSample * Channels) >> 3);
|
|
||||||
int bytesPerSec = (int)(blockAlign * SamplesPerSecond);
|
|
||||||
uint sleepIntervalFactor = 1000 / 20;
|
|
||||||
int bytesPerInterval = (int)(bytesPerSec / sleepIntervalFactor);
|
|
||||||
|
|
||||||
return bytesPerInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int MulawToLinear(int ulaw)
|
|
||||||
{
|
|
||||||
ulaw = ~ulaw;
|
|
||||||
int t = ((ulaw & QUANT_MASK) << 3) + BIAS;
|
|
||||||
t <<= (ulaw & SEG_MASK) >> SEG_SHIFT;
|
|
||||||
return ((ulaw & SIGN_BIT) > 0 ? (BIAS - t) : (t - BIAS));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static short Search(short val, short[] table, short size)
|
|
||||||
{
|
|
||||||
short i;
|
|
||||||
int index = 0;
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
if (val <= table[index])
|
|
||||||
{
|
|
||||||
return (i);
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
return (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte Linear2ulaw(short pcm_val)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Get the sign and the magnitude of the value. */
|
|
||||||
pcm_val = (short)(pcm_val >> 2);
|
|
||||||
short mask;
|
|
||||||
if (pcm_val < 0)
|
|
||||||
{
|
|
||||||
pcm_val = (short)-pcm_val;
|
|
||||||
mask = 0x7F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mask = 0xFF;
|
|
||||||
}
|
|
||||||
/* clip the magnitude */
|
|
||||||
if (pcm_val > CLIP)
|
|
||||||
{
|
|
||||||
pcm_val = CLIP;
|
|
||||||
}
|
|
||||||
pcm_val += (BIAS >> 2);
|
|
||||||
|
|
||||||
/* Convert the scaled magnitude to segment number. */
|
|
||||||
short seg = Search(pcm_val, seg_uend, 8);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Combine the sign, segment, quantization bits;
|
|
||||||
* and complement the code word.
|
|
||||||
*/
|
|
||||||
/* out of range, return maximum value. */
|
|
||||||
if (seg >= 8)
|
|
||||||
{
|
|
||||||
return (byte)(0x7F ^ mask);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
byte uval = (byte)((seg << 4) | ((pcm_val >> (seg + 1)) & 0xF));
|
|
||||||
return ((byte)(uval ^ mask));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] MuLawToLinear(byte[] bytes, int bitsPerSample, int channels)
|
|
||||||
{
|
|
||||||
int blockAlign = channels * bitsPerSample / 8;
|
|
||||||
|
|
||||||
byte[] result = new byte[bytes.Length * blockAlign];
|
|
||||||
for (int i = 0, counter = 0; i < bytes.Length; i++, counter += blockAlign)
|
|
||||||
{
|
|
||||||
int value = MulawToLinear(bytes[i]);
|
|
||||||
byte[] values = BitConverter.GetBytes(value);
|
|
||||||
|
|
||||||
switch (bitsPerSample)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
switch (channels)
|
|
||||||
{
|
|
||||||
//8 Bit 1 Channel
|
|
||||||
case 1:
|
|
||||||
result[counter] = values[0];
|
|
||||||
break;
|
|
||||||
|
|
||||||
//8 Bit 2 Channel
|
|
||||||
case 2:
|
|
||||||
result[counter] = values[0];
|
|
||||||
result[counter + 1] = values[0];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
switch (channels)
|
|
||||||
{
|
|
||||||
//16 Bit 1 Channel
|
|
||||||
case 1:
|
|
||||||
result[counter] = values[0];
|
|
||||||
result[counter + 1] = values[1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
//16 Bit 2 Channels
|
|
||||||
case 2:
|
|
||||||
result[counter] = values[0];
|
|
||||||
result[counter + 1] = values[1];
|
|
||||||
result[counter + 2] = values[0];
|
|
||||||
result[counter + 3] = values[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static byte[] LinearToMulaw(byte[] bytes, int bitsPerSample, int channels)
|
|
||||||
{
|
|
||||||
int blockAlign = channels * bitsPerSample / 8;
|
|
||||||
|
|
||||||
byte[] result = new byte[bytes.Length / blockAlign];
|
|
||||||
int resultIndex = 0;
|
|
||||||
for (int i = 0; i < result.Length; i++)
|
|
||||||
{
|
|
||||||
switch (bitsPerSample)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
switch (channels)
|
|
||||||
{
|
|
||||||
//8 Bit 1 Channel
|
|
||||||
case 1:
|
|
||||||
result[i] = Linear2ulaw(bytes[resultIndex]);
|
|
||||||
resultIndex += 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//8 Bit 2 Channel
|
|
||||||
case 2:
|
|
||||||
result[i] = Linear2ulaw(bytes[resultIndex]);
|
|
||||||
resultIndex += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
switch (channels)
|
|
||||||
{
|
|
||||||
//16 Bit 1 Channel
|
|
||||||
case 1:
|
|
||||||
result[i] = Linear2ulaw(BitConverter.ToInt16(bytes, resultIndex));
|
|
||||||
resultIndex += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//16 Bit 2 Channels
|
|
||||||
case 2:
|
|
||||||
result[i] = Linear2ulaw(BitConverter.ToInt16(bytes, resultIndex));
|
|
||||||
resultIndex += 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,104 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class WaveFile
|
|
||||||
{
|
|
||||||
internal WaveFile()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal const int WAVE_FORMAT_PCM = 1;
|
|
||||||
|
|
||||||
|
|
||||||
internal static WaveFileHeader Read(string fileName)
|
|
||||||
{
|
|
||||||
WaveFileHeader header = ReadHeader(fileName);
|
|
||||||
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static WaveFileHeader ReadHeader(string fileName)
|
|
||||||
{
|
|
||||||
WaveFileHeader header = new();
|
|
||||||
|
|
||||||
if (File.Exists(fileName))
|
|
||||||
{
|
|
||||||
FileStream fs = new(fileName, FileMode.Open, FileAccess.Read);
|
|
||||||
BinaryReader rd = new(fs, Encoding.UTF8);
|
|
||||||
|
|
||||||
if (fs.CanRead)
|
|
||||||
{
|
|
||||||
header.RIFF = rd.ReadChars(4);
|
|
||||||
header.RiffSize = (uint)rd.ReadInt32();
|
|
||||||
header.RiffFormat = rd.ReadChars(4);
|
|
||||||
|
|
||||||
header.FMT = rd.ReadChars(4);
|
|
||||||
header.FMTSize = (uint)rd.ReadInt32();
|
|
||||||
header.FMTPos = fs.Position;
|
|
||||||
header.AudioFormat = rd.ReadInt16();
|
|
||||||
header.Channels = rd.ReadInt16();
|
|
||||||
header.SamplesPerSecond = (uint)rd.ReadInt32();
|
|
||||||
header.BytesPerSecond = (uint)rd.ReadInt32();
|
|
||||||
header.BlockAlign = rd.ReadInt16();
|
|
||||||
header.BitsPerSample = rd.ReadInt16();
|
|
||||||
|
|
||||||
fs.Seek(header.FMTPos + header.FMTSize, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
header.DATA = rd.ReadChars(4);
|
|
||||||
header.DATASize = (uint)rd.ReadInt32();
|
|
||||||
header.DATAPos = (int)fs.Position;
|
|
||||||
|
|
||||||
if (new string(header.DATA).ToUpper() != "DATA")
|
|
||||||
{
|
|
||||||
uint DataChunkSize = header.DATASize + 8;
|
|
||||||
fs.Seek(DataChunkSize, SeekOrigin.Current);
|
|
||||||
header.DATASize = (uint)(fs.Length - header.DATAPos - DataChunkSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header.DATASize <= fs.Length - header.DATAPos)
|
|
||||||
{
|
|
||||||
header.Payload = rd.ReadBytes((int)header.DATASize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rd.Close();
|
|
||||||
fs.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class WaveFileHeader
|
|
||||||
{
|
|
||||||
internal WaveFileHeader()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal char[] RIFF = new char[4];
|
|
||||||
internal uint RiffSize = 8;
|
|
||||||
internal char[] RiffFormat = new char[4];
|
|
||||||
|
|
||||||
internal char[] FMT = new char[4];
|
|
||||||
internal uint FMTSize = 16;
|
|
||||||
internal short AudioFormat;
|
|
||||||
internal short Channels;
|
|
||||||
internal uint SamplesPerSecond;
|
|
||||||
internal uint BytesPerSecond;
|
|
||||||
internal short BlockAlign;
|
|
||||||
internal short BitsPerSample;
|
|
||||||
|
|
||||||
internal char[] DATA = new char[4];
|
|
||||||
internal uint DATASize;
|
|
||||||
|
|
||||||
internal byte[] Payload = Array.Empty<byte>();
|
|
||||||
|
|
||||||
internal int DATAPos = 44;
|
|
||||||
internal long FMTPos = 20;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,241 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal unsafe class Win32
|
|
||||||
{
|
|
||||||
internal Win32()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal const int WAVE_MAPPER = -1;
|
|
||||||
|
|
||||||
internal const int WT_EXECUTEDEFAULT = 0x00000000;
|
|
||||||
internal const int WT_EXECUTEINIOTHREAD = 0x00000001;
|
|
||||||
internal const int WT_EXECUTEINTIMERTHREAD = 0x00000020;
|
|
||||||
internal const int WT_EXECUTEINPERSISTENTTHREAD = 0x00000080;
|
|
||||||
|
|
||||||
internal const int TIME_ONESHOT = 0;
|
|
||||||
internal const int TIME_PERIODIC = 1;
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
|
|
||||||
internal struct WAVEOUTCAPS
|
|
||||||
{
|
|
||||||
internal short wMid;
|
|
||||||
internal short wPid;
|
|
||||||
internal int vDriverVersion;
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
|
||||||
internal string szPname;
|
|
||||||
internal uint dwFormats;
|
|
||||||
internal short wChannels;
|
|
||||||
internal short wReserved;
|
|
||||||
internal int dwSupport;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
|
|
||||||
internal struct WAVEINCAPS
|
|
||||||
{
|
|
||||||
internal short wMid;
|
|
||||||
internal short wPid;
|
|
||||||
internal int vDriverVersion;
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
|
||||||
internal string szPname;
|
|
||||||
internal uint dwFormats;
|
|
||||||
internal short wChannels;
|
|
||||||
internal short wReserved;
|
|
||||||
internal int dwSupport;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal struct WAVEFORMATEX
|
|
||||||
{
|
|
||||||
internal ushort wFormatTag;
|
|
||||||
internal ushort nChannels;
|
|
||||||
internal uint nSamplesPerSec;
|
|
||||||
internal uint nAvgBytesPerSec;
|
|
||||||
internal ushort nBlockAlign;
|
|
||||||
internal ushort wBitsPerSample;
|
|
||||||
internal ushort cbSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum MMRESULT : uint
|
|
||||||
{
|
|
||||||
MMSYSERR_NOERROR = 0,
|
|
||||||
MMSYSERR_ERROR = 1,
|
|
||||||
MMSYSERR_BADDEVICEID = 2,
|
|
||||||
MMSYSERR_NOTENABLED = 3,
|
|
||||||
MMSYSERR_ALLOCATED = 4,
|
|
||||||
MMSYSERR_INVALHANDLE = 5,
|
|
||||||
MMSYSERR_NODRIVER = 6,
|
|
||||||
MMSYSERR_NOMEM = 7,
|
|
||||||
MMSYSERR_NOTSUPPORTED = 8,
|
|
||||||
MMSYSERR_BADERRNUM = 9,
|
|
||||||
MMSYSERR_INVALFLAG = 10,
|
|
||||||
MMSYSERR_INVALPARAM = 11,
|
|
||||||
MMSYSERR_HANDLEBUSY = 12,
|
|
||||||
MMSYSERR_INVALIDALIAS = 13,
|
|
||||||
MMSYSERR_BADDB = 14,
|
|
||||||
MMSYSERR_KEYNOTFOUND = 15,
|
|
||||||
MMSYSERR_READERROR = 16,
|
|
||||||
MMSYSERR_WRITEERROR = 17,
|
|
||||||
MMSYSERR_DELETEERROR = 18,
|
|
||||||
MMSYSERR_VALNOTFOUND = 19,
|
|
||||||
MMSYSERR_NODRIVERCB = 20,
|
|
||||||
WAVERR_BADFORMAT = 32,
|
|
||||||
WAVERR_STILLPLAYING = 33,
|
|
||||||
WAVERR_UNPREPARED = 34
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
internal enum WaveHdrFlags : uint
|
|
||||||
{
|
|
||||||
WHDR_DONE = 1,
|
|
||||||
WHDR_PREPARED = 2,
|
|
||||||
WHDR_BEGINLOOP = 4,
|
|
||||||
WHDR_ENDLOOP = 8,
|
|
||||||
WHDR_INQUEUE = 16
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
internal enum WaveProcFlags : int
|
|
||||||
{
|
|
||||||
CALLBACK_NULL = 0,
|
|
||||||
CALLBACK_FUNCTION = 0x30000,
|
|
||||||
CALLBACK_EVENT = 0x50000,
|
|
||||||
CALLBACK_WINDOW = 0x10000,
|
|
||||||
CALLBACK_THREAD = 0x20000,
|
|
||||||
WAVE_FORMAT_QUERY = 1,
|
|
||||||
WAVE_MAPPED = 4,
|
|
||||||
WAVE_FORMAT_DIRECT = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
internal enum HRESULT : long
|
|
||||||
{
|
|
||||||
S_OK = 0L,
|
|
||||||
S_FALSE = 1L
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
internal enum WaveFormatFlags : int
|
|
||||||
{
|
|
||||||
WAVE_FORMAT_PCM = 0x0001
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
||||||
internal struct WAVEHDR
|
|
||||||
{
|
|
||||||
internal IntPtr lpData;
|
|
||||||
internal uint dwBufferLength;
|
|
||||||
internal uint dwBytesRecorded;
|
|
||||||
internal IntPtr dwUser;
|
|
||||||
internal WaveHdrFlags dwFlags;
|
|
||||||
internal uint dwLoops;
|
|
||||||
internal IntPtr lpNext;
|
|
||||||
internal IntPtr reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal struct TimeCaps
|
|
||||||
{
|
|
||||||
internal uint wPeriodMin;
|
|
||||||
internal uint wPeriodMax;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal enum WOM_Messages : int
|
|
||||||
{
|
|
||||||
OPEN = 0x03BB,
|
|
||||||
CLOSE = 0x03BC,
|
|
||||||
DONE = 0x03BD
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum WIM_Messages : int
|
|
||||||
{
|
|
||||||
OPEN = 0x03BE,
|
|
||||||
CLOSE = 0x03BF,
|
|
||||||
DATA = 0x03C0
|
|
||||||
}
|
|
||||||
|
|
||||||
internal delegate void DelegateWaveOutProc(IntPtr hWaveOut, WOM_Messages msg, IntPtr dwInstance, WAVEHDR* pWaveHdr, IntPtr lParam);
|
|
||||||
internal delegate void DelegateWaveInProc(IntPtr hWaveIn, WIM_Messages msg, IntPtr dwInstance, WAVEHDR* pWaveHdr, IntPtr lParam);
|
|
||||||
internal delegate void DelegateTimerProc(IntPtr lpParameter, bool TimerOrWaitFired);
|
|
||||||
internal delegate void TimerEventHandler(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent")]
|
|
||||||
internal static extern uint TimeSetEvent(uint msDelay, uint msResolution, TimerEventHandler handler, ref uint userCtx, uint eventType);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeKillEvent")]
|
|
||||||
internal static extern uint TimeKillEvent(uint timerId);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeGetDevCaps")]
|
|
||||||
internal static extern MMRESULT TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeBeginPeriod")]
|
|
||||||
internal static extern MMRESULT TimeBeginPeriod(uint uPeriod);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeEndPeriod")]
|
|
||||||
internal static extern MMRESULT TimeEndPeriod(uint uPeriod);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
||||||
internal static extern MMRESULT waveOutOpen(ref IntPtr hWaveOut, int uDeviceID, ref WAVEFORMATEX lpFormat, DelegateWaveOutProc dwCallBack, int dwInstance, int dwFlags);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll")]
|
|
||||||
internal static extern MMRESULT waveInOpen(ref IntPtr hWaveIn, int deviceId, ref WAVEFORMATEX wfx, DelegateWaveInProc dwCallBack, int dwInstance, int dwFlags);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInStart(IntPtr hWaveIn);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
||||||
internal static extern uint waveInGetDevCaps(int index, ref WAVEINCAPS pwic, int cbwic);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern uint waveInGetNumDevs();
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
||||||
internal static extern uint waveOutGetDevCaps(int index, ref WAVEOUTCAPS pwoc, int cbwoc);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern uint waveOutGetNumDevs();
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
||||||
internal static extern MMRESULT waveOutWrite(IntPtr hWaveOut, WAVEHDR* pwh, int cbwh);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "waveOutPrepareHeader", CharSet = CharSet.Auto)]
|
|
||||||
internal static extern MMRESULT waveOutPrepareHeader(IntPtr hWaveOut, WAVEHDR* lpWaveOutHdr, int uSize);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, EntryPoint = "waveOutUnprepareHeader", CharSet = CharSet.Auto)]
|
|
||||||
internal static extern MMRESULT waveOutUnprepareHeader(IntPtr hWaveOut, WAVEHDR* lpWaveOutHdr, int uSize);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "waveInStop", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInStop(IntPtr hWaveIn);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "waveInReset", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInReset(IntPtr hWaveIn);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "waveOutReset", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveOutReset(IntPtr hWaveOut);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInPrepareHeader(IntPtr hWaveIn, WAVEHDR* pwh, int cbwh);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInUnprepareHeader(IntPtr hWaveIn, WAVEHDR* pwh, int cbwh);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "waveInAddBuffer", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInAddBuffer(IntPtr hWaveIn, WAVEHDR* pwh, int cbwh);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveInClose(IntPtr hWaveIn);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
||||||
internal static extern MMRESULT waveOutClose(IntPtr hWaveOut);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll")]
|
|
||||||
internal static extern MMRESULT waveOutPause(IntPtr hWaveOut);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "waveOutRestart", SetLastError = true)]
|
|
||||||
internal static extern MMRESULT waveOutRestart(IntPtr hWaveOut);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Luski.net.Sound
|
|
||||||
{
|
|
||||||
internal class LockerClass
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class WinSound
|
|
||||||
{
|
|
||||||
internal WinSound()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<string> GetPlaybackNames()
|
|
||||||
{
|
|
||||||
List<string> list = new();
|
|
||||||
Win32.WAVEOUTCAPS waveOutCap = new();
|
|
||||||
|
|
||||||
uint num = Win32.waveOutGetNumDevs();
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
uint hr = Win32.waveOutGetDevCaps(i, ref waveOutCap, Marshal.SizeOf(typeof(Win32.WAVEOUTCAPS)));
|
|
||||||
if (hr == (int)Win32.HRESULT.S_OK)
|
|
||||||
{
|
|
||||||
list.Add(waveOutCap.szPname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<string> GetRecordingNames()
|
|
||||||
{
|
|
||||||
List<string> list = new();
|
|
||||||
Win32.WAVEINCAPS waveInCap = new();
|
|
||||||
|
|
||||||
uint num = Win32.waveInGetNumDevs();
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
uint hr = Win32.waveInGetDevCaps(i, ref waveInCap, Marshal.SizeOf(typeof(Win32.WAVEINCAPS)));
|
|
||||||
if (hr == (int)Win32.HRESULT.S_OK)
|
|
||||||
{
|
|
||||||
list.Add(waveInCap.szPname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int GetWaveInDeviceIdByName(string name)
|
|
||||||
{
|
|
||||||
uint num = Win32.waveInGetNumDevs();
|
|
||||||
|
|
||||||
Win32.WAVEINCAPS caps = new();
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
Win32.HRESULT hr = (Win32.HRESULT)Win32.waveInGetDevCaps(i, ref caps, Marshal.SizeOf(typeof(Win32.WAVEINCAPS)));
|
|
||||||
if (hr == Win32.HRESULT.S_OK)
|
|
||||||
{
|
|
||||||
if (caps.szPname == name)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Win32.WAVE_MAPPER;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int GetWaveOutDeviceIdByName(string name)
|
|
||||||
{
|
|
||||||
uint num = Win32.waveOutGetNumDevs();
|
|
||||||
|
|
||||||
Win32.WAVEOUTCAPS caps = new();
|
|
||||||
for (int i = 0; i < num; i++)
|
|
||||||
{
|
|
||||||
Win32.HRESULT hr = (Win32.HRESULT)Win32.waveOutGetDevCaps(i, ref caps, Marshal.SizeOf(typeof(Win32.WAVEOUTCAPS)));
|
|
||||||
if (hr == Win32.HRESULT.S_OK)
|
|
||||||
{
|
|
||||||
if (caps.szPname == name)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Win32.WAVE_MAPPER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,12 +9,16 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures;
|
||||||
|
|
||||||
public class File : IncomingHTTP
|
public class File : IncomingHTTP
|
||||||
{
|
{
|
||||||
|
public IServer Server { get; internal set; }
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
[JsonPropertyName("name")]
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; internal set; } = default!;
|
public string Name { get; internal set; } = default!;
|
||||||
@ -29,7 +33,7 @@ public class File : IncomingHTTP
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
internal string loc { get; set; } = default!;
|
internal string loc { get; set; } = default!;
|
||||||
|
|
||||||
public async void DownloadBytes(string Loc, long key)
|
public async Task DownloadBytes(string Loc, long key, CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
//using HttpClient web = new();
|
//using HttpClient web = new();
|
||||||
//web.DefaultRequestHeaders.Add("token", Server.Token);
|
//web.DefaultRequestHeaders.Add("token", Server.Token);
|
||||||
@ -37,9 +41,9 @@ public class File : IncomingHTTP
|
|||||||
//IncomingHTTP? request = JsonSerializer.Deserialize(web.GetAsync($"https://{Server.Domain}/{Server.API_Ver}/SocketMessage/GetFile").Result.Content.ReadAsStringAsync().Result, IncomingHTTPContext.Default.IncomingHTTP);
|
//IncomingHTTP? request = JsonSerializer.Deserialize(web.GetAsync($"https://{Server.Domain}/{Server.API_Ver}/SocketMessage/GetFile").Result.Content.ReadAsStringAsync().Result, IncomingHTTPContext.Default.IncomingHTTP);
|
||||||
string path = Path.GetTempFileName();
|
string path = Path.GetTempFileName();
|
||||||
|
|
||||||
await Server.GetFromServer($"SocketMessage/GetFile/{Id}", path);
|
await Server.GetFromServer($"SocketMessage/GetFile/{Id}", path, CancellationToken);
|
||||||
string Key = (key == 0 ? Encryption.MyPublicKey : Encryption.File.Channels.GetKey(key))!;
|
string Key = (key == 0 ? ClientEncryption.MyPublicKey : ClientEncryption.File.Channels.GetKey(key))!;
|
||||||
Encryption.AES.Decrypt(System.IO.File.ReadAllBytes(path), Key, Loc);
|
Encryption.AES.DecryptToFile(System.IO.File.ReadAllBytes(path), Key, Loc);
|
||||||
/*
|
/*
|
||||||
if (request is not null && request.Error is not null)
|
if (request is not null && request.Error is not null)
|
||||||
{
|
{
|
||||||
@ -78,25 +82,29 @@ public class File : IncomingHTTP
|
|||||||
loc = path;
|
loc = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<long> Upload(string keyy)
|
private bool Uploaded = false;
|
||||||
|
|
||||||
|
internal async Task<long> Upload(string keyy, CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
if (Name != null) Name = Convert.ToBase64String(Encryption.Encrypt(Name, keyy));
|
if (Uploaded) return Id;
|
||||||
Debug.WriteLine("uploading");
|
if (Name != null) Name = Convert.ToBase64String(Encryption.RSA.Encrypt(Encoding.UTF8.GetBytes(Name), keyy));
|
||||||
string NPath = Encryption.AES.Encrypt(loc, keyy);
|
string NPath = Encryption.AES.EncryptFile(loc, keyy);
|
||||||
File sf = await Server.SendServer(
|
File sf = await Server.SendServer(
|
||||||
"SocketMessage/UploadFile",
|
"SocketMessage/UploadFile",
|
||||||
NPath,
|
NPath,
|
||||||
FileContext.Default.File,
|
FileContext.Default.File,
|
||||||
|
CancellationToken,
|
||||||
new KeyValuePair<string, string?>("name", Name));
|
new KeyValuePair<string, string?>("name", Name));
|
||||||
try { System.IO.File.Delete(NPath); } catch { }
|
try { System.IO.File.Delete(NPath); } catch { }
|
||||||
Debug.WriteLine("done uploading");
|
|
||||||
if (sf.Error is not null) throw new Exception(sf.ErrorMessage);
|
if (sf.Error is not null) throw new Exception(sf.ErrorMessage);
|
||||||
|
Id = sf.Id;
|
||||||
|
Uploaded = true;
|
||||||
return sf.Id;
|
return sf.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void decrypt()
|
internal void decrypt()
|
||||||
{
|
{
|
||||||
if (Name is not null) Name = Encryption.Encoder.GetString(Encryption.Decrypt(Convert.FromBase64String(Name), key));
|
if (Name is not null) Name = Encoding.UTF8.GetString(Encryption.RSA.Decrypt(Convert.FromBase64String(Name), key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
194
Luski.net/Structures/Main/MainSocketAppUser.cs
Executable file
194
Luski.net/Structures/Main/MainSocketAppUser.cs
Executable file
@ -0,0 +1,194 @@
|
|||||||
|
using System;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Enums.Main;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
|
||||||
|
namespace Luski.net.Structures.Main;
|
||||||
|
|
||||||
|
public class MainSocketAppUser : SocketUserBase, IAppUser
|
||||||
|
{
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
[JsonInclude]
|
||||||
|
public string Username { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("flags")]
|
||||||
|
[JsonInclude]
|
||||||
|
public UserFlag Flags { get; internal set; } = default!;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<MainSocketChannel> Channels
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_Channels is null || ChannelIdList is not null)
|
||||||
|
{
|
||||||
|
if (ChannelIdList.Length != 0)
|
||||||
|
{
|
||||||
|
_Channels = new List<MainSocketChannel>();
|
||||||
|
foreach (long channel in ChannelIdList)
|
||||||
|
{
|
||||||
|
MainSocketChannel s = (Server as Server<MainSocketAppUser>).GetChannel(channel,
|
||||||
|
MainSocketChannelContext.Default.MainSocketChannel, CancellationToken.None).Result;
|
||||||
|
(Server as Server<MainSocketAppUser>)!.chans.Remove(s);
|
||||||
|
switch (s.Type)
|
||||||
|
{
|
||||||
|
case ChannelType.GROUP:
|
||||||
|
_Channels.Add((Server as Server<MainSocketAppUser>).GetChannel(channel,
|
||||||
|
MainSocketGroupChannelContext.Default.MainSocketGroupChannel, CancellationToken.None).Result);
|
||||||
|
break;
|
||||||
|
case ChannelType.DM:
|
||||||
|
_Channels.Add((Server as Server<MainSocketAppUser>).GetChannel(channel,
|
||||||
|
MainSocketDMChannelContext.Default.MainSocketDMChannel, CancellationToken.None).Result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else _Channels = new List<MainSocketChannel>();
|
||||||
|
}
|
||||||
|
return _Channels.AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<MainSocketRemoteUser> FriendRequests
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_FriendRequests is null || FriendRequestsRaw is not null)
|
||||||
|
{
|
||||||
|
_FriendRequests = new();
|
||||||
|
if (ChannelIdList.Length != 0 && FriendRequestsRaw is not null)
|
||||||
|
{
|
||||||
|
foreach (FR person in FriendRequestsRaw)
|
||||||
|
{
|
||||||
|
//_Friends.Add(SocketRemoteUser.GetUser(person));
|
||||||
|
long id = person.user_id == Id ? person.from : person.user_id;
|
||||||
|
MainSocketRemoteUser frq = Server.GetUser<MainSocketRemoteUser>(id, CancellationToken.None).Result;
|
||||||
|
_FriendRequests.Add(frq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else _FriendRequests = new();
|
||||||
|
}
|
||||||
|
return _FriendRequests.AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<MainSocketRemoteUser> Friends
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_Friends is null || FriendIdList is not null)
|
||||||
|
{
|
||||||
|
if (ChannelIdList.Length != 0)
|
||||||
|
{
|
||||||
|
_Friends = new List<MainSocketRemoteUser>();
|
||||||
|
foreach (long person in FriendIdList)
|
||||||
|
{
|
||||||
|
_Friends.Add(Server.GetUser<MainSocketRemoteUser>(person, CancellationToken.None).Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else _Friends = new List<MainSocketRemoteUser>();
|
||||||
|
}
|
||||||
|
return _Friends.AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[JsonPropertyName("selected_channel")]
|
||||||
|
[JsonInclude]
|
||||||
|
public long SelectedChannel { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("channels")]
|
||||||
|
[JsonInclude]
|
||||||
|
public long[] ChannelIdList { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("friends")]
|
||||||
|
[JsonInclude]
|
||||||
|
public long[] FriendIdList { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("friend_requests")]
|
||||||
|
[JsonInclude]
|
||||||
|
public FR[] FriendRequestsRaw { get; internal set; } = default!;
|
||||||
|
[JsonIgnore]
|
||||||
|
private List<MainSocketChannel> _Channels = default!;
|
||||||
|
[JsonIgnore]
|
||||||
|
private List<MainSocketRemoteUser> _Friends = default!;
|
||||||
|
[JsonIgnore]
|
||||||
|
private List<MainSocketRemoteUser> _FriendRequests = default!;
|
||||||
|
|
||||||
|
public class FR
|
||||||
|
{
|
||||||
|
public long from { get; set; } = default!;
|
||||||
|
public long user_id { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddFriend(MainSocketRemoteUser User)
|
||||||
|
{
|
||||||
|
if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
|
||||||
|
{
|
||||||
|
IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
|
||||||
|
foreach (IUser item in b)
|
||||||
|
{
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
|
||||||
|
}
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Add(User);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Add(User);
|
||||||
|
}
|
||||||
|
_Friends.Add(User);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RemoveFriendRequest(MainSocketRemoteUser User)
|
||||||
|
{
|
||||||
|
if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
|
||||||
|
{
|
||||||
|
IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
|
||||||
|
foreach (IUser item in b)
|
||||||
|
{
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Add(User);
|
||||||
|
foreach (MainSocketRemoteUser user in _FriendRequests)
|
||||||
|
{
|
||||||
|
if (User.Id == user.Id)
|
||||||
|
{
|
||||||
|
_FriendRequests.Remove(User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddFriendRequest(MainSocketRemoteUser User)
|
||||||
|
{
|
||||||
|
if ((Server as Server<MainSocketAppUser>)!.poeople.Any(s => s.Id == User.Id))
|
||||||
|
{
|
||||||
|
IEnumerable<IUser> b = (Server as Server<MainSocketAppUser>)!.poeople.Where(s => s.Id == User.Id);
|
||||||
|
foreach (IUser item in b)
|
||||||
|
{
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Remove(item);
|
||||||
|
}
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Add(User);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(Server as Server<MainSocketAppUser>)!.poeople.Add(User);
|
||||||
|
}
|
||||||
|
_FriendRequests.Add(User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(MainSocketAppUser))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
||||||
|
WriteIndented = false,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
|
||||||
|
internal partial class MainSocketAppUserContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -9,10 +9,15 @@ using System.Net.Http;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Luski.net.JsonTypes.WSS;
|
using Luski.net.JsonTypes.WSS;
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using JacobTechEncryption.Enums;
|
||||||
|
using Luski.net.Enums.Main;
|
||||||
|
using Luski.net.JsonTypes;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures.Main;
|
||||||
|
|
||||||
public class SocketChannel : IncomingHTTP
|
public class MainSocketChannel : IncomingHTTP
|
||||||
{
|
{
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
@ -29,6 +34,7 @@ public class SocketChannel : IncomingHTTP
|
|||||||
[JsonPropertyName("type")]
|
[JsonPropertyName("type")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public ChannelType Type { get; internal set; } = default!;
|
public ChannelType Type { get; internal set; } = default!;
|
||||||
|
public IServer Server { get; internal set; }
|
||||||
[JsonPropertyName("members")]
|
[JsonPropertyName("members")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public long[] MemberIdList { get; internal set; } = default!;
|
public long[] MemberIdList { get; internal set; } = default!;
|
||||||
@ -43,8 +49,8 @@ public class SocketChannel : IncomingHTTP
|
|||||||
_members = new();
|
_members = new();
|
||||||
foreach (long member in MemberIdList)
|
foreach (long member in MemberIdList)
|
||||||
{
|
{
|
||||||
if (member != Server._user!.Id) _members.Add(SocketUserBase.GetUser(member, SocketRemoteUserContext.Default.SocketRemoteUser).Result);
|
if (member != Server.IAppUser!.Id) _members.Add(Server.GetUser<MainSocketRemoteUser>(member, CancellationToken.None).Result);
|
||||||
else _members.Add(Server._user);
|
else _members.Add(Server.IAppUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _members.AsReadOnly();
|
return _members.AsReadOnly();
|
||||||
@ -53,31 +59,31 @@ public class SocketChannel : IncomingHTTP
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private List<IUser> _members = new();
|
private List<IUser> _members = new();
|
||||||
|
|
||||||
public async Task<Task> SendKeysToUsers()
|
public Task SendKeysToUsers(CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
if (Key is null)
|
if (Key is null)
|
||||||
{
|
{
|
||||||
StartKeyProcessAsync().Wait();
|
StartKeyProcessAsync(CancellationToken).Wait();
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * Server.Percent) * 2.0));
|
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 50) * 2.0));
|
||||||
if (num == 0) num = 1;
|
if (num == 0) num = 1;
|
||||||
string? lkey = Encryption.File.Channels.GetKey(Id);
|
string? lkey = ClientEncryption.File.Channels.GetKey(Id);
|
||||||
Parallel.ForEach(Members, new ParallelOptions()
|
Parallel.ForEach(Members, new ParallelOptions()
|
||||||
{
|
{
|
||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, async i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
if (i.Id != Server._user?.Id)
|
if (i.Id != (Server as Server<MainSocketAppUser>).User?.Id)
|
||||||
{
|
{
|
||||||
string key = await i.GetUserKey();
|
long key = i.GetUserKey(CancellationToken).Result;
|
||||||
if (!string.IsNullOrEmpty(key))
|
if (true)
|
||||||
{
|
{
|
||||||
WSSKeyExchange send = new()
|
WSSKeyExchange send = new()
|
||||||
{
|
{
|
||||||
to = i.Id,
|
to = i.Id,
|
||||||
channel = Id,
|
channel = Id,
|
||||||
key = Convert.ToBase64String(Encryption.Encrypt(lkey, key))
|
key = Convert.ToBase64String(Encryption.RSA.Encrypt(lkey, key.ToString(), EncoderType.UTF8))
|
||||||
};
|
};
|
||||||
Server.SendServer(send, WSSKeyExchangeContext.Default.WSSKeyExchange);
|
Server.SendServer(send, WSSKeyExchangeContext.Default.WSSKeyExchange);
|
||||||
}
|
}
|
||||||
@ -86,17 +92,17 @@ public class SocketChannel : IncomingHTTP
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task StartKeyProcessAsync()
|
internal Task StartKeyProcessAsync(CancellationToken CancellationToken)
|
||||||
{
|
{/*
|
||||||
Encryption.GenerateNewKeys(out string Public, out string Private);
|
ClientEncryption.GenerateNewKeys(out string Public, out string Private);
|
||||||
Key = Public;
|
Key = Public;
|
||||||
HttpResponseMessage b;
|
HttpResponseMessage b;
|
||||||
using (HttpClient web = new())
|
using (HttpClient web = new())
|
||||||
{
|
{
|
||||||
web.DefaultRequestHeaders.Add("token", Server.Token);
|
web.DefaultRequestHeaders.Add("token", Luski.net.Server.Token);
|
||||||
b = web.PostAsync($"https://{Server.InternalDomain}/{Server.API_Ver}/SocketChannel/SetKey/{Id}", new StringContent(Key)).Result;
|
b = web.PostAsync($"https://{Server.Domain}/{Server.ApiVersion}/SocketChannel/SetKey/{Id}", new StringContent(Key), CancellationToken).Result;
|
||||||
}
|
}
|
||||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * Server.Percent) * 2.0));
|
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * Luski.net.Server.Percent) * 2.0));
|
||||||
if (num == 0) num = 1;
|
if (num == 0) num = 1;
|
||||||
Encryption.File.Channels.AddKey(Id, Private);
|
Encryption.File.Channels.AddKey(Id, Private);
|
||||||
Parallel.ForEach(Members, new ParallelOptions()
|
Parallel.ForEach(Members, new ParallelOptions()
|
||||||
@ -104,9 +110,9 @@ public class SocketChannel : IncomingHTTP
|
|||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
if (i.Id != Server._user?.Id)
|
if (i.Id != Luski.net.Server._user?.Id)
|
||||||
{
|
{
|
||||||
string key = i.GetUserKey().Result;
|
string key = i.GetUserKey(CancellationToken, Server).Result;
|
||||||
if (!string.IsNullOrEmpty(key))
|
if (!string.IsNullOrEmpty(key))
|
||||||
{
|
{
|
||||||
WSSKeyExchange send = new()
|
WSSKeyExchange send = new()
|
||||||
@ -115,59 +121,20 @@ public class SocketChannel : IncomingHTTP
|
|||||||
channel = Id,
|
channel = Id,
|
||||||
key = Convert.ToBase64String(Encryption.Encrypt(Private, key))
|
key = Convert.ToBase64String(Encryption.Encrypt(Private, key))
|
||||||
};
|
};
|
||||||
Server.SendServer(send, WSSKeyExchangeContext.Default.WSSKeyExchange);
|
Luski.net.Server.SendServer(send, WSSKeyExchangeContext.Default.WSSKeyExchange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
}
|
return Task.CompletedTask;
|
||||||
|
|
||||||
internal static async Task<TChannel> GetChannel<TChannel>(long id, JsonTypeInfo<TChannel> Json) where TChannel : SocketChannel, new()
|
|
||||||
{
|
|
||||||
TChannel request;
|
|
||||||
if (Server.chans is null) Server.chans = new();
|
|
||||||
if (Server.chans.Count > 0 && Server.chans.Any(s => s.Id == id))
|
|
||||||
{
|
|
||||||
return Server.chans.Where(s => s is TChannel && s.Id == id).Cast<TChannel>().FirstOrDefault()!;
|
|
||||||
}
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Server.CanRequest)
|
|
||||||
{
|
|
||||||
request = await Server.GetFromServer($"SocketChannel/Get/{id}", Json);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (request is null) throw new Exception("Something was wrong with the server responce");
|
|
||||||
if (request.Error is null)
|
|
||||||
{
|
|
||||||
if (Server.chans is null) Server.chans = new();
|
|
||||||
if (Server.chans.Count > 0 && Server.chans.Any(s => s.Id == request.Id))
|
|
||||||
{
|
|
||||||
foreach (SocketChannel? p in Server.chans.Where(s => s.Id == request.Id))
|
|
||||||
{
|
|
||||||
Server.chans.Remove(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Server.chans.Add(request);
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
throw request.Error switch
|
|
||||||
{
|
|
||||||
ErrorCode.InvalidToken => new Exception("Your current token is no longer valid"),
|
|
||||||
ErrorCode.Forbidden => new Exception("The server rejected your request"),
|
|
||||||
ErrorCode.ServerError => new Exception("Error from server: " + request.ErrorMessage),
|
|
||||||
ErrorCode.InvalidURL or ErrorCode.MissingHeader => new Exception(request.ErrorMessage),
|
|
||||||
_ => new Exception($"Unknown data: '{request.ErrorMessage}'"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketChannel))]
|
[JsonSerializable(typeof(MainSocketChannel))]
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
WriteIndented = false)]
|
WriteIndented = false)]
|
||||||
internal partial class SocketChannelContext : JsonSerializerContext
|
internal partial class MainSocketChannelContext : JsonSerializerContext
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
34
Luski.net/Structures/Main/MainSocketDMChannel.cs
Executable file
34
Luski.net/Structures/Main/MainSocketDMChannel.cs
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Luski.net.Structures.Main;
|
||||||
|
|
||||||
|
public class MainSocketDMChannel : MainSocketTextChannel
|
||||||
|
{
|
||||||
|
public MainSocketRemoteUser User
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_user is null)
|
||||||
|
{
|
||||||
|
var list = MemberIdList.ToList();
|
||||||
|
list.Remove(Server.IAppUser.Id);
|
||||||
|
_user = Server.GetUser<MainSocketRemoteUser>(list.FirstOrDefault(), CancellationToken.None).Result;
|
||||||
|
}
|
||||||
|
return _user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public MainSocketRemoteUser _user = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(MainSocketDMChannel))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
|
WriteIndented = false)]
|
||||||
|
internal partial class MainSocketDMChannelContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,20 +1,20 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures.Main;
|
||||||
|
|
||||||
public class SocketGroupChannel : SocketTextChannel
|
public class MainSocketGroupChannel : MainSocketTextChannel
|
||||||
{
|
{
|
||||||
[JsonPropertyName("owner")]
|
[JsonPropertyName("owner")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public long Owner { get; internal set; } = default!;
|
public long Owner { get; internal set; } = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketGroupChannel))]
|
[JsonSerializable(typeof(MainSocketGroupChannel))]
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
WriteIndented = false)]
|
WriteIndented = false)]
|
||||||
internal partial class SocketGroupChannelContext : JsonSerializerContext
|
internal partial class MainSocketGroupChannelContext : JsonSerializerContext
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
@ -7,29 +7,29 @@ using System.Net.Http;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.Enums.Main;
|
||||||
|
using Luski.net.Structures;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures;
|
||||||
|
|
||||||
public class SocketRemoteUser : SocketUserBase
|
public class MainSocketRemoteUser : SocketUserBase
|
||||||
{
|
{
|
||||||
[JsonPropertyName("friend_status")]
|
[JsonPropertyName("friend_status")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public FriendStatus FriendStatus { get; internal set; } = default!;
|
public FriendStatus FriendStatus { get; internal set; } = default!;
|
||||||
[JsonIgnore]
|
|
||||||
public SocketDMChannel Channel { get; internal set; } = default!;
|
|
||||||
|
|
||||||
internal SocketRemoteUser Clone()
|
internal MainSocketRemoteUser Clone()
|
||||||
{
|
{
|
||||||
return (SocketRemoteUser)MemberwiseClone();
|
return (MainSocketRemoteUser)MemberwiseClone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketRemoteUser))]
|
[JsonSerializable(typeof(MainSocketRemoteUser))]
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
WriteIndented = false)]
|
WriteIndented = false)]
|
||||||
internal partial class SocketRemoteUserContext : JsonSerializerContext
|
internal partial class MainSocketRemoteUserContext : JsonSerializerContext
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
@ -7,32 +7,36 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using JacobTechEncryption.Enums;
|
||||||
|
using Luski.net.Enums.Main;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures.Main;
|
||||||
|
|
||||||
public class SocketTextChannel : SocketChannel, ITextChannel
|
public class MainSocketTextChannel : MainSocketChannel
|
||||||
{
|
{
|
||||||
public async Task<SocketMessage> GetMessage(long ID)
|
public async Task<SocketMessage> GetMessage(long ID, CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
return await SocketMessage.GetMessage(ID);
|
return await (Server as Server<MainSocketAppUser>)!.GetMessage(ID, CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<byte[]> GetPicture()
|
public async Task<byte[]> GetPicture(CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
if (Type == ChannelType.DM) return Members.First().GetAvatar().Result;
|
if (Type == ChannelType.DM) return Members.First().GetAvatar(CancellationToken).Result;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Server.Cache != null)
|
if (Server.Cache != null)
|
||||||
{
|
{
|
||||||
bool isc = System.IO.File.Exists($"{Server.Cache}/channels/{Id}");
|
bool isc = System.IO.File.Exists($"{Server.Cache}/channels/{Id}");
|
||||||
if (!isc) await Server.GetFromServer($"SocketChannel/GetPicture/{Id}", $"{Server.Cache}/channels/{Id}");
|
if (!isc) await Server.GetFromServer($"SocketChannel/GetPicture/{Id}", $"{Server.Cache}/channels/{Id}", CancellationToken);
|
||||||
}
|
}
|
||||||
return System.IO.File.ReadAllBytes($"{Server.Cache}/channels/{Id}");
|
return System.IO.File.ReadAllBytes($"{Server.Cache}/channels/{Id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<SocketMessage>> GetMessages(long Message_Id, int count = 50)
|
public async Task<IReadOnlyList<SocketMessage>> GetMessages(long Message_Id, CancellationToken CancellationToken, int count = 50)
|
||||||
{
|
{
|
||||||
if (count > 200)
|
if (count > 200)
|
||||||
{
|
{
|
||||||
@ -46,15 +50,16 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
{
|
{
|
||||||
SocketBulkMessage data = await Server.GetFromServer("SocketBulkMessage",
|
SocketBulkMessage data = await Server.GetFromServer("SocketBulkMessage",
|
||||||
SocketBulkMessageContext.Default.SocketBulkMessage,
|
SocketBulkMessageContext.Default.SocketBulkMessage,
|
||||||
|
CancellationToken,
|
||||||
new KeyValuePair<string, string?>("channel_id", Id.ToString()),
|
new KeyValuePair<string, string?>("channel_id", Id.ToString()),
|
||||||
new KeyValuePair<string, string?>("messages", count.ToString()),
|
new KeyValuePair<string, string?>("messages", count.ToString()),
|
||||||
new KeyValuePair<string, string?>("mostrecentid", Message_Id.ToString()));
|
new KeyValuePair<string, string?>("mostrecentid", Message_Id.ToString()));
|
||||||
if (data.Error is null)
|
if (data.Error is null)
|
||||||
{
|
{
|
||||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * Server.Percent) * 2.0));
|
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
|
||||||
if (num == 0) num = 1;
|
if (num == 0) num = 1;
|
||||||
|
|
||||||
string? key = Encryption.File.Channels.GetKey(Id);
|
string? key = ClientEncryption.File.Channels.GetKey(Id);
|
||||||
if (data is null) throw new Exception("Invalid data from server");
|
if (data is null) throw new Exception("Invalid data from server");
|
||||||
if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
|
if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
|
||||||
Parallel.ForEach(data.Messages, new ParallelOptions()
|
Parallel.ForEach(data.Messages, new ParallelOptions()
|
||||||
@ -62,7 +67,7 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
i.decrypt(key);
|
i.decrypt(key, CancellationToken);
|
||||||
});
|
});
|
||||||
key = null;
|
key = null;
|
||||||
return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
|
return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
|
||||||
@ -74,7 +79,7 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<SocketMessage>> GetMessages(int count = 50)
|
public async Task<IReadOnlyList<SocketMessage>> GetMessages(CancellationToken CancellationToken, int count = 50)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -88,24 +93,29 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
DateTime start = DateTime.Now;
|
||||||
SocketBulkMessage data = await Server.GetFromServer("SocketBulkMessage",
|
SocketBulkMessage data = await Server.GetFromServer("SocketBulkMessage",
|
||||||
SocketBulkMessageContext.Default.SocketBulkMessage,
|
SocketBulkMessageContext.Default.SocketBulkMessage,
|
||||||
|
CancellationToken,
|
||||||
new KeyValuePair<string, string?>("id", Id.ToString()),
|
new KeyValuePair<string, string?>("id", Id.ToString()),
|
||||||
new KeyValuePair<string, string?>("messages", count.ToString()));
|
new KeyValuePair<string, string?>("messages", count.ToString()));
|
||||||
|
Console.WriteLine($"Messages downloaded in {(DateTime.Now - start).TotalSeconds}");
|
||||||
|
start = DateTime.Now;
|
||||||
if (data is not null && !data.Error.HasValue)
|
if (data is not null && !data.Error.HasValue)
|
||||||
{
|
{
|
||||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * Server.Percent) * 2.0));
|
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 5) * 2.0));
|
||||||
if (num == 0) num = 1;
|
if (num == 0) num = 1;
|
||||||
string? key = Encryption.File.Channels.GetKey(Id);
|
string? key = ClientEncryption.File.Channels.GetKey(Id);
|
||||||
if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
|
if (data.Messages is null) data.Messages = Array.Empty<SocketMessage>();
|
||||||
Parallel.ForEach(data.Messages, new ParallelOptions()
|
Parallel.ForEach(data.Messages, new ParallelOptions()
|
||||||
{
|
{
|
||||||
MaxDegreeOfParallelism = num
|
MaxDegreeOfParallelism = num
|
||||||
}, i =>
|
}, i =>
|
||||||
{
|
{
|
||||||
i.decrypt(key);
|
i.decrypt(key, CancellationToken);
|
||||||
});
|
});
|
||||||
key = null;
|
key = null;
|
||||||
|
Console.WriteLine($"Messages decrypted in {(DateTime.Now - start).TotalSeconds}");
|
||||||
return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
|
return await Task.FromResult(data.Messages.ToList().AsReadOnly() as IReadOnlyList<SocketMessage>);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -128,13 +138,13 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Task> SendMessage(string Message, params File?[] Files)
|
public async Task<Task> SendMessage(string Message, CancellationToken CancellationToken, params File?[] Files)
|
||||||
{
|
{
|
||||||
string key = Encryption.File.Channels.GetKey(Id);
|
string key = ClientEncryption.File.Channels.GetKey(Id);
|
||||||
if (Id == 0) key = Encryption.ServerPublicKey;
|
if (Id == 0) key = "";//ClientEncryption.ServerPublicKey;
|
||||||
HTTP.Message m = new()
|
JsonTypes.HTTP.Message m = new()
|
||||||
{
|
{
|
||||||
Context = Convert.ToBase64String(Encryption.Encrypt(Message, key)),
|
Context = Convert.ToBase64String(Encryption.RSA.Encrypt(Message, key, EncoderType.UTF8)),
|
||||||
Channel = Id,
|
Channel = Id,
|
||||||
};
|
};
|
||||||
if (Files is not null && Files.Length > 0)
|
if (Files is not null && Files.Length > 0)
|
||||||
@ -145,24 +155,24 @@ public class SocketTextChannel : SocketChannel, ITextChannel
|
|||||||
File? ff = Files[i];
|
File? ff = Files[i];
|
||||||
if (ff is not null)
|
if (ff is not null)
|
||||||
{
|
{
|
||||||
bb.Add(await ff.Upload(key));
|
bb.Add(await ff.Upload(key, CancellationToken));
|
||||||
Files[i] = null;
|
Files[i] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.Files = bb.ToArray();
|
m.Files = bb.ToArray();
|
||||||
}
|
}
|
||||||
IncomingHTTP data = await Server.SendServer("socketmessage", m, HTTP.MessageContext.Default.Message, IncomingHTTPContext.Default.IncomingHTTP);
|
IncomingHTTP data = await Server.SendServer("socketmessage", m, net.JsonTypes.HTTP.MessageContext.Default.Message, IncomingHTTPContext.Default.IncomingHTTP, CancellationToken);
|
||||||
if (data.Error is not null && data.ErrorMessage != "Server responded with empty data") throw new Exception(data.ErrorMessage);
|
if (data.Error is not null && data.ErrorMessage != "Server responded with empty data") throw new Exception(data.ErrorMessage);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketTextChannel))]
|
[JsonSerializable(typeof(MainSocketTextChannel))]
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
||||||
WriteIndented = false)]
|
WriteIndented = false)]
|
||||||
internal partial class SocketTextChannelContext : JsonSerializerContext
|
internal partial class MainSocketTextChannelContext : JsonSerializerContext
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
35
Luski.net/Structures/Public/PublicSocketAppUser.cs
Executable file
35
Luski.net/Structures/Public/PublicSocketAppUser.cs
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Enums.Main;
|
||||||
|
|
||||||
|
namespace Luski.net.Structures.Public;
|
||||||
|
|
||||||
|
public class PublicSocketAppUser : SocketUserBase, IAppUser
|
||||||
|
{
|
||||||
|
[JsonPropertyName("selected_channel")]
|
||||||
|
[JsonInclude]
|
||||||
|
public long SelectedChannel { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
[JsonInclude]
|
||||||
|
public string Username { get; internal set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(PublicSocketAppUser))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
||||||
|
WriteIndented = false,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
|
||||||
|
internal partial class PublicSocketAppUserContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using Luski.net.JsonTypes.BaseTypes;
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures;
|
||||||
|
|
||||||
internal class SocketBulkMessage : IncomingHTTP
|
internal class SocketBulkMessage : IncomingHTTP
|
||||||
{
|
{
|
||||||
@ -11,7 +11,6 @@ internal class SocketBulkMessage : IncomingHTTP
|
|||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketBulkMessage))]
|
[JsonSerializable(typeof(SocketBulkMessage))]
|
||||||
[JsonSerializable(typeof(SocketAppUser))]
|
|
||||||
[JsonSourceGenerationOptions(
|
[JsonSourceGenerationOptions(
|
||||||
GenerationMode = JsonSourceGenerationMode.Default,
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
|
@ -3,14 +3,18 @@ using Luski.net.JsonTypes.BaseTypes;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JacobTechEncryption;
|
||||||
|
|
||||||
namespace Luski.net.JsonTypes;
|
namespace Luski.net.Structures;
|
||||||
|
|
||||||
public class SocketMessage : IncomingHTTP
|
public class SocketMessage : IncomingHTTP
|
||||||
{
|
{
|
||||||
|
public IServer Server { get; }
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public long Id { get; internal set; } = default!;
|
public long Id { get; internal set; } = default!;
|
||||||
@ -26,29 +30,16 @@ public class SocketMessage : IncomingHTTP
|
|||||||
[JsonPropertyName("files")]
|
[JsonPropertyName("files")]
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public File[]? Files { get; internal set; } = default!;
|
public File[]? Files { get; internal set; } = default!;
|
||||||
public async Task<SocketTextChannel> GetChannel()
|
public async Task<IUser> GetAuthor(CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
if (Server.chans.Any(s => s.Id == ChannelID))
|
if (Server.IAppUser!.Id != AuthorID) return await Server.GetUser<SocketUserBase>(AuthorID, CancellationToken);
|
||||||
{
|
else return Server.IAppUser;
|
||||||
return (SocketTextChannel)Server.chans.Where(s => s.Id == ChannelID).First();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SocketTextChannel ch = await SocketChannel.GetChannel(ChannelID, SocketTextChannelContext.Default.SocketTextChannel);
|
|
||||||
Server.chans.Add(ch);
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task<IUser> GetAuthor()
|
|
||||||
{
|
|
||||||
if (Server._user!.Id != AuthorID) return await SocketUserBase.GetUser(AuthorID, SocketRemoteUserContext.Default.SocketRemoteUser);
|
|
||||||
else return Server._user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void decrypt(string? key)
|
internal void decrypt(string? key, CancellationToken CancellationToken)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
|
if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
|
||||||
Context = Encryption.Encoder.GetString(Encryption.Decrypt(Convert.FromBase64String(Context), key));
|
Context = Encoding.UTF8.GetString(Encryption.AES.Decrypt(Convert.FromBase64String(Context), key));
|
||||||
if (Files is not null && Files.Length > 0)
|
if (Files is not null && Files.Length > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Files.Length; i++)
|
for (int i = 0; i < Files.Length; i++)
|
||||||
@ -58,22 +49,6 @@ public class SocketMessage : IncomingHTTP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal static async Task<SocketMessage> GetMessage(long id)
|
|
||||||
{
|
|
||||||
SocketMessage message;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Server.CanRequest)
|
|
||||||
{
|
|
||||||
message = await Server.GetFromServer("socketmessage",
|
|
||||||
SocketMessageContext.Default.SocketMessage,
|
|
||||||
new System.Collections.Generic.KeyValuePair<string, string?>("msg_id", id.ToString()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (message is not null) return message;
|
|
||||||
throw new Exception("Server did not return a message");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonSerializable(typeof(SocketMessage))]
|
[JsonSerializable(typeof(SocketMessage))]
|
53
Luski.net/Structures/SocketUserBase.cs
Normal file
53
Luski.net/Structures/SocketUserBase.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Luski.net.Enums;
|
||||||
|
using Luski.net.Interfaces;
|
||||||
|
using Luski.net.JsonTypes.BaseTypes;
|
||||||
|
|
||||||
|
namespace Luski.net.Structures;
|
||||||
|
|
||||||
|
public class SocketUserBase : IncomingHTTP, IUser
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
[JsonInclude]
|
||||||
|
public long Id { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
[JsonInclude]
|
||||||
|
public string DisplayName { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("status")]
|
||||||
|
[JsonInclude]
|
||||||
|
public UserStatus Status { get; internal set; } = default!;
|
||||||
|
[JsonPropertyName("picture_type")]
|
||||||
|
[JsonInclude]
|
||||||
|
public PictureType PictureType { get; internal set; } = default!;
|
||||||
|
[JsonIgnore]
|
||||||
|
public IServer Server { get; internal set; } = default!;
|
||||||
|
|
||||||
|
public async Task<byte[]> GetAvatar(CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
if (Server.Cache != null)
|
||||||
|
{
|
||||||
|
bool isc = System.IO.File.Exists($"{Server.Cache}/avatars/{Id}");
|
||||||
|
if (!isc) await Server.GetFromServer($"socketuserprofile/Avatar/{Id}", $"{Server.Cache}/avatars/{Id}", CancellationToken);
|
||||||
|
}
|
||||||
|
return System.IO.File.ReadAllBytes($"{Server.Cache}/avatars/{Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<long> GetUserKey(CancellationToken CancellationToken)
|
||||||
|
{
|
||||||
|
string data = Server.GetFromServer($"Keys/GetUserKey/{Id}", CancellationToken).Content.ReadAsStringAsync().Result;
|
||||||
|
return Task.FromResult(long.Parse(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonSerializable(typeof(SocketUserBase))]
|
||||||
|
[JsonSourceGenerationOptions(
|
||||||
|
GenerationMode = JsonSourceGenerationMode.Default,
|
||||||
|
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
|
||||||
|
WriteIndented = false,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
|
||||||
|
internal partial class SocketUserBaseContext : JsonSerializerContext
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user