1231 lines
45 KiB
C#
1231 lines
45 KiB
C#
|
|
||
|
using LiteDB;
|
||
|
using Newtonsoft.Json;
|
||
|
using WebSocketSharp;
|
||
|
using WebSocketSharp.Server;
|
||
|
using Tesses.WebServer;
|
||
|
using Chatr;
|
||
|
using System.Collections.Generic;
|
||
|
using System;
|
||
|
using System.Linq;
|
||
|
using System.Net.Http;
|
||
|
namespace Tesses.Chatr.Server
|
||
|
{
|
||
|
|
||
|
|
||
|
public static class DataBase
|
||
|
{
|
||
|
private const string SessionCollectionName = "Sessions";
|
||
|
private const string AccountCollectionName="Accounts";
|
||
|
private const string MessageCollectionName="Messages";
|
||
|
|
||
|
private const string NotificationCollectionName="Notifications";
|
||
|
private const string BotCollectionName = "Bots";
|
||
|
|
||
|
private static LiteDatabase _db;
|
||
|
public static void SetDb(string path)
|
||
|
{
|
||
|
_db=new LiteDatabase(path);
|
||
|
Accounts=_db.GetCollection<Account>(AccountCollectionName);
|
||
|
Sessions=_db.GetCollection<Session>(SessionCollectionName);
|
||
|
Messages=_db.GetCollection<Message>(MessageCollectionName);
|
||
|
Bots=_db.GetCollection<Bot>(BotCollectionName);
|
||
|
Notifications=_db.GetCollection<Notification>(NotificationCollectionName);
|
||
|
}
|
||
|
public static ILiteCollection<Notification> Notifications {get;private set;}
|
||
|
public static ILiteCollection<Account> Accounts {get;private set;}
|
||
|
public static ILiteCollection<Session> Sessions {get;private set;}
|
||
|
public static ILiteCollection<Message> Messages {get;private set;}
|
||
|
//public static ILiteCollection<Notif>? Messages {get;private set;}
|
||
|
public static ILiteCollection<Bot> Bots {get;private set;}
|
||
|
|
||
|
public static void Dispose()
|
||
|
{
|
||
|
_db?.Dispose();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public class WSConnection : WebSocketBehavior
|
||
|
{
|
||
|
private Account account;
|
||
|
private Bot bot;
|
||
|
|
||
|
protected override void OnClose(CloseEventArgs e)
|
||
|
{
|
||
|
if(bot != null)
|
||
|
{
|
||
|
UserManagement.Bots[bot.Id].Remove(this);
|
||
|
}
|
||
|
if(account != null)
|
||
|
{
|
||
|
UserManagement.Humans[account.Id].Remove(this);
|
||
|
}
|
||
|
}
|
||
|
private void Send(ChatrWSMsg msg)
|
||
|
{
|
||
|
if(this.ConnectionState == WebSocketState.Open)
|
||
|
{
|
||
|
try{
|
||
|
Send(JsonConvert.SerializeObject(msg));
|
||
|
}catch(Exception ex)
|
||
|
{
|
||
|
_=ex;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
protected override void OnMessage(MessageEventArgs e)
|
||
|
{
|
||
|
if(e.IsText)
|
||
|
{
|
||
|
|
||
|
var chattrMsg=JsonConvert.DeserializeObject<ChatrWSMsg>(e.Data);
|
||
|
if(chattrMsg!=null){
|
||
|
IPacketData packet;
|
||
|
if(chattrMsg.IsType(PacketType.ClearAll,out packet))
|
||
|
{
|
||
|
if(account != null && bot == null)
|
||
|
{
|
||
|
var clrAll=(ClearAllPacket)packet;
|
||
|
string[] p=clrAll.UserStr.Split(new char[]{'-'},2,StringSplitOptions.RemoveEmptyEntries);
|
||
|
if(p.Length < 1) return;
|
||
|
|
||
|
string human_name = p[0]== "me" ? account.Username : p[0];
|
||
|
if(p.Length ==1)
|
||
|
{
|
||
|
//its human
|
||
|
foreach(var msg in UserManagement.GetMessages(account,human_name).ToList())
|
||
|
{
|
||
|
DataBase.Messages.Delete(msg.Id);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(p[0] != "me")
|
||
|
{
|
||
|
//we send clear all message to other person
|
||
|
ClearAllPacket pkt=new ClearAllPacket();
|
||
|
pkt.UserStr=account.Username;
|
||
|
UserManagement.SendClearAll(pkt);
|
||
|
}
|
||
|
|
||
|
}else{
|
||
|
|
||
|
//its a bot
|
||
|
foreach(var msg in UserManagement.GetMessages(account,human_name,p[1]).ToList())
|
||
|
{
|
||
|
DataBase.Messages.Delete(msg.Id);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(chattrMsg.IsType(PacketType.NotificationEventFire,out packet))
|
||
|
{
|
||
|
if(account != null && bot == null)
|
||
|
{
|
||
|
var noFire=(NotificationEventFirePacket)packet;
|
||
|
Console.WriteLine(JsonConvert.SerializeObject(noFire));
|
||
|
noFire.DestinationUserName = account.Username;
|
||
|
UserManagement.HandleNotificationEventFirePacket(noFire);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
if(chattrMsg.IsType(PacketType.Notification,out packet))
|
||
|
{
|
||
|
|
||
|
if(bot == null || !bot.Permissions.CanSendNotifications || account != null) return; //users can't send notifications
|
||
|
|
||
|
|
||
|
var notification = (NotificationPacket)packet;
|
||
|
if(notification.UserName != "me" && !bot.Permissions.CanSendMessagesToOtherPeople) return;
|
||
|
if(DataBase.Accounts != null && DataBase.Notifications != null && notification != null && !string.IsNullOrWhiteSpace(notification.UserName))
|
||
|
{
|
||
|
var bUser = DataBase.Accounts.FindById(bot.UserId);
|
||
|
if(bUser != null){
|
||
|
long destId = notification.UserName == "me" ? bot.UserId : UserManagement.GetUserId(notification.UserName);
|
||
|
|
||
|
var not= DataBase.Notifications.FindOne(ee=>ee.SourceBotId == bot.Id && ee.SourceUserId == bot.UserId && ee.BotNotificationId == notification.BotNotificationId);
|
||
|
if(not != null)
|
||
|
{
|
||
|
|
||
|
if(!string.IsNullOrWhiteSpace(notification.Body))
|
||
|
{
|
||
|
not.Body=notification.Body;
|
||
|
}else{
|
||
|
not.Body="";
|
||
|
}
|
||
|
not.NotificationButtons.Clear();
|
||
|
foreach(var item in notification.NotificationButtons)
|
||
|
{
|
||
|
not.NotificationButtons.Add(item);
|
||
|
}
|
||
|
not.OnClick=notification.OnClick;
|
||
|
if(!string.IsNullOrWhiteSpace(notification.Title))
|
||
|
{
|
||
|
not.Title=notification.Title;
|
||
|
|
||
|
}else{
|
||
|
not.Title = "";
|
||
|
}
|
||
|
bool isMe = notification.UserName == "me";
|
||
|
|
||
|
string botowneruserName= isMe ? "me" : bUser.Username;
|
||
|
|
||
|
string botusername = bot.BotUserName;
|
||
|
not.BotUserString = $"{botowneruserName}-{botusername}";
|
||
|
DataBase.Notifications.Update(not);
|
||
|
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
Console.WriteLine("NN");
|
||
|
not=new Notification();
|
||
|
if(!string.IsNullOrWhiteSpace(notification.Body))
|
||
|
{
|
||
|
not.Body=notification.Body;
|
||
|
}else{
|
||
|
not.Body="";
|
||
|
}
|
||
|
not.NotificationButtons.Clear();
|
||
|
foreach(var item in notification.NotificationButtons)
|
||
|
{
|
||
|
not.NotificationButtons.Add(item);
|
||
|
}
|
||
|
not.OnClick=notification.OnClick;
|
||
|
if(!string.IsNullOrWhiteSpace(notification.Title))
|
||
|
{
|
||
|
not.Title=notification.Title;
|
||
|
|
||
|
}else{
|
||
|
not.Title = "";
|
||
|
}
|
||
|
if(!string.IsNullOrWhiteSpace(notification.BotNotificationId))
|
||
|
{
|
||
|
not.BotNotificationId=notification.BotNotificationId;
|
||
|
} else{
|
||
|
not.BotNotificationId="";
|
||
|
}
|
||
|
not.SourceBotId = bot.Id;
|
||
|
not.SourceUserId = bot.UserId;
|
||
|
not.DestinationUserId=destId;
|
||
|
bool isMe = notification.UserName == "me";
|
||
|
|
||
|
|
||
|
string botowneruserName= isMe ? "me" : bUser.Username;
|
||
|
|
||
|
string botusername = bot.BotUserName;
|
||
|
not.BotUserString = $"{botowneruserName}-{botusername}";
|
||
|
var bson=DataBase.Notifications.Insert(not);
|
||
|
not.Id=bson.AsInt64;
|
||
|
notification.Id=bson.AsInt64;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
UserManagement.SendNotification(not);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(chattrMsg.IsType(PacketType.AuthenticateUser,out packet))
|
||
|
{
|
||
|
var authUser=(AuthenticationUserPacket)packet;
|
||
|
//authenticate this as a user
|
||
|
var res=UserManagement.Authenticate(authUser.SessionId);
|
||
|
if(res.Success && res.Account !=null)
|
||
|
{
|
||
|
UserManagement.Humans.Add(res.Account.Id,this);
|
||
|
account=res.Account;
|
||
|
}else{
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if(chattrMsg.IsType(PacketType.AuthenticateBot,out packet))
|
||
|
{
|
||
|
var authUser=(AuthenticateBotPacket)packet;
|
||
|
//authenticate this as a user
|
||
|
var res=UserManagement.AuthenticateApiKey(authUser.ApiKey);
|
||
|
if(res.Success && res.Bot !=null)
|
||
|
{
|
||
|
UserManagement.Bots.Add(res.Bot.Id,this);
|
||
|
bot=res.Bot;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if(chattrMsg.IsType(PacketType.Message,out packet))
|
||
|
{
|
||
|
var msg = (MessagePacket)packet;
|
||
|
|
||
|
if(!string.IsNullOrWhiteSpace(msg.UserStr)){
|
||
|
var usrs=msg.UserStr.Split(new char[]{'-'},2);
|
||
|
if(usrs.Length >= 1)
|
||
|
{
|
||
|
string user = usrs[0];
|
||
|
string bot=null;
|
||
|
if(usrs.Length == 2)
|
||
|
{
|
||
|
bot = usrs[1];
|
||
|
}
|
||
|
Message msg0=new Message();
|
||
|
if(msg0.CreationTime.Year == 1970) msg0.CreationTime=DateTime.Now;
|
||
|
if(!string.IsNullOrWhiteSpace(msg.Content))
|
||
|
msg0.Content = msg.Content;
|
||
|
else
|
||
|
msg0.Content = "[No Body]";
|
||
|
if(this.bot != null)
|
||
|
{
|
||
|
|
||
|
msg0.IsFromBot=true;
|
||
|
msg0.SourceBotId = this.bot.Id;
|
||
|
msg0.SourceUserId = this.bot.UserId;
|
||
|
|
||
|
if(!string.IsNullOrWhiteSpace(bot))
|
||
|
{
|
||
|
msg0.IsToBot=true;
|
||
|
if(!this.bot.Permissions.OthersCanReceiveMessages) return;
|
||
|
if(user == "me")
|
||
|
{
|
||
|
msg0.DestinationUserId = msg0.SourceUserId;
|
||
|
msg0.DestinationBotId = UserManagement.GetBotId(msg0.SourceUserId,bot);
|
||
|
}else{
|
||
|
msg0.DestinationUserId= UserManagement.GetUserId(user);
|
||
|
msg0.DestinationBotId= UserManagement.GetBotId(user,bot);
|
||
|
}
|
||
|
UserManagement.SendMessage(msg0);
|
||
|
}else{
|
||
|
msg0.IsToBot=false;
|
||
|
|
||
|
if(user == "me")
|
||
|
{
|
||
|
|
||
|
msg0.DestinationUserId=msg0.SourceUserId;
|
||
|
}else{
|
||
|
|
||
|
if(!this.bot.Permissions.CanSendMessagesToOtherPeople) return;
|
||
|
msg0.DestinationUserId= UserManagement.GetUserId(user);
|
||
|
}
|
||
|
UserManagement.SendMessage(msg0);
|
||
|
}
|
||
|
}
|
||
|
if(this.account != null)
|
||
|
{
|
||
|
|
||
|
msg0.IsFromBot=false;
|
||
|
msg0.SourceUserId = this.account.Id;
|
||
|
|
||
|
if(!string.IsNullOrWhiteSpace(bot))
|
||
|
{
|
||
|
|
||
|
msg0.IsToBot=true;
|
||
|
|
||
|
if(user == "me")
|
||
|
{
|
||
|
msg0.DestinationUserId = msg0.SourceUserId;
|
||
|
msg0.DestinationBotId= UserManagement.GetBotId(msg0.DestinationUserId,bot);
|
||
|
|
||
|
}else{
|
||
|
|
||
|
msg0.DestinationUserId= UserManagement.GetUserId(user);
|
||
|
msg0.DestinationBotId= UserManagement.GetBotId(user,bot);
|
||
|
|
||
|
}
|
||
|
Bot bt;
|
||
|
if(DataBase.Bots != null && (bt=DataBase.Bots.FindById(msg0.DestinationBotId)) != null)
|
||
|
{
|
||
|
if(!bt.Permissions.CanGetMessages)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
UserManagement.SendMessage(msg0);
|
||
|
}else{
|
||
|
msg0.IsToBot=false;
|
||
|
if(user == "me")
|
||
|
{
|
||
|
msg0.DestinationUserId=msg0.SourceUserId;
|
||
|
}else{
|
||
|
msg0.DestinationUserId= UserManagement.GetUserId(user);
|
||
|
}
|
||
|
UserManagement.SendMessage(msg0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public void Push(ClearAllPacket pkt)
|
||
|
{
|
||
|
Send(new ChatrWSMsg(pkt));
|
||
|
}
|
||
|
public void Push(Message msg)
|
||
|
{
|
||
|
var userStr = UserManagement.GetHashTextFromMessage(msg,true);
|
||
|
var nameStr = UserManagement.GetNameTextFromMessage(msg,true);
|
||
|
var msgData = msg.Content;
|
||
|
var creationTime = msg.CreationTime.ToString("R");
|
||
|
ChatrWSMsg packet=new ChatrWSMsg();
|
||
|
|
||
|
var mpd=new MessagePacket();
|
||
|
|
||
|
mpd.Content=msgData;
|
||
|
mpd.CreationTime=creationTime;
|
||
|
mpd.UserStr=userStr;
|
||
|
mpd.Name=nameStr;
|
||
|
|
||
|
//mpd.Name
|
||
|
|
||
|
packet.SetPacketData(mpd);
|
||
|
//the json packet
|
||
|
Send(packet);
|
||
|
}
|
||
|
public void Push(NotificationEventFirePacket packet)
|
||
|
{
|
||
|
var ppacket=new ChatrWSMsg();
|
||
|
ppacket.SetPacketData(packet);
|
||
|
Send(ppacket);
|
||
|
}
|
||
|
public void Push(Notification notification)
|
||
|
{
|
||
|
if(DataBase.Bots==null || DataBase.Accounts == null) return;
|
||
|
/*
|
||
|
object packet=new{
|
||
|
PacketType="Notification",
|
||
|
Data=new{
|
||
|
BotName = notification.BotName,
|
||
|
Title=notification.Title,
|
||
|
Body=notification.Body,
|
||
|
OnClick=notification.OnClick.ToObject(notification.Id),
|
||
|
}
|
||
|
};
|
||
|
//the json packet
|
||
|
Send(packet);
|
||
|
*/
|
||
|
|
||
|
NotificationPacket packet=new NotificationPacket();
|
||
|
packet.Body=notification.Body;
|
||
|
var bot = DataBase.Bots.FindOne(e=>e.Id==notification.SourceBotId);
|
||
|
var usr = DataBase.Accounts.FindOne(e=>e.Id ==notification.SourceUserId);
|
||
|
if(bot != null && usr != null)
|
||
|
{
|
||
|
packet.BotName = bot.BotName;
|
||
|
packet.BotOwnerName = usr.Name;
|
||
|
packet.BotOwnerUserName =usr.Username;
|
||
|
packet.BotNotificationId=notification.BotNotificationId;
|
||
|
packet.Id=notification.Id;
|
||
|
packet.NotificationButtons=notification.NotificationButtons;
|
||
|
packet.OnClick=notification.OnClick;
|
||
|
packet.Title =notification.Title;
|
||
|
packet.BotUserString = notification.BotUserString;
|
||
|
var ppacket=new ChatrWSMsg();
|
||
|
ppacket.SetPacketData(packet);
|
||
|
Send(ppacket);
|
||
|
}
|
||
|
//packet.BotName=notification.SourceBotId
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class UserManagement
|
||
|
{
|
||
|
internal static Dictionary<long,List<WSConnection>> Humans=new Dictionary<long, List<WSConnection>>();
|
||
|
internal static Dictionary<long,List<WSConnection>> Bots=new Dictionary<long, List<WSConnection>>();
|
||
|
internal static HttpClient clt=new HttpClient();
|
||
|
|
||
|
internal static Dictionary<string,OTA> _otaCodes=new Dictionary<string, OTA>();
|
||
|
private static void SendHttpRequest(Dictionary<string,string> dict)
|
||
|
{
|
||
|
//MET
|
||
|
//HDR
|
||
|
//URL
|
||
|
//BDY
|
||
|
Dictionary<string,List<string>> headers=new Dictionary<string, List<string>>();
|
||
|
string method="GET";
|
||
|
string url="http://example.com/";
|
||
|
byte[] body=new byte[0];
|
||
|
|
||
|
foreach(var d in dict)
|
||
|
{
|
||
|
if(d.Key == "MET")
|
||
|
{
|
||
|
|
||
|
method=d.Value;
|
||
|
|
||
|
}else if(d.Key == "URL")
|
||
|
{
|
||
|
url = d.Value;
|
||
|
}else if(d.Key == "BDY")
|
||
|
{
|
||
|
body = Convert.FromBase64String(d.Value);
|
||
|
}else if(d.Key.StartsWith("HDR"))
|
||
|
{
|
||
|
string[] key= d.Key.Substring(3).Split(new char[]{':'},2);
|
||
|
headers.Add(key[0],d.Value);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
HttpRequestMessage msg=new HttpRequestMessage(new HttpMethod(method),url);
|
||
|
foreach(var h in headers)
|
||
|
{
|
||
|
msg.Headers.Add(h.Key,h.Value);
|
||
|
}
|
||
|
if(body.Length > 0)
|
||
|
{
|
||
|
msg.Content=new ByteArrayContent(body);
|
||
|
}
|
||
|
|
||
|
clt.SendAsync(msg).GetAwaiter().GetResult().Dispose();
|
||
|
|
||
|
}
|
||
|
public static void HandleNotificationEventFirePacket(NotificationEventFirePacket packet)
|
||
|
{
|
||
|
if(DataBase.Notifications != null)
|
||
|
{
|
||
|
var p=DataBase.Notifications.FindOne(e=>e.BotUserString ==packet.BotUserString && e.BotNotificationId == packet.BotNotificationId);
|
||
|
if(p != null)
|
||
|
{
|
||
|
if(string.IsNullOrWhiteSpace(packet.Button))
|
||
|
{
|
||
|
//onclick
|
||
|
switch(p.OnClick.Type)
|
||
|
{
|
||
|
case NotificationEventType.CallApiFromServer:
|
||
|
SendHttpRequest(p.OnClick.Data);
|
||
|
break;
|
||
|
case NotificationEventType.SendCallbackToBot:
|
||
|
SendNotificationEvent(packet);
|
||
|
break;
|
||
|
}
|
||
|
}else{
|
||
|
try{
|
||
|
var p0 = p.NotificationButtons.Find(e=>{
|
||
|
return e.Text == packet.Button;
|
||
|
});
|
||
|
if(p0==null) return;
|
||
|
switch(p0.Event.Type)
|
||
|
{
|
||
|
case NotificationEventType.CallApiFromServer:
|
||
|
SendHttpRequest(p0.Event.Data);
|
||
|
break;
|
||
|
case NotificationEventType.SendCallbackToBot:
|
||
|
SendNotificationEvent(packet);
|
||
|
break;
|
||
|
}
|
||
|
}catch(Exception ex)
|
||
|
{
|
||
|
_=ex;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public static bool DefaultVerificationStatus { get; set; }
|
||
|
public static bool AllowLoginAsAnnonymous { get; set; }
|
||
|
|
||
|
public static RegistrationResult RegisterAccount(string name,string username,string email,string password)
|
||
|
{
|
||
|
if(username.Equals("_anonymous") || email.Equals("anonymous@example.com"))
|
||
|
{
|
||
|
return new RegistrationResult("Can't Register Anonymous");
|
||
|
}
|
||
|
if(IsValidPassword(password))
|
||
|
{
|
||
|
var users=DataBase.Accounts;
|
||
|
|
||
|
if(users != null){
|
||
|
var user =users.FindOne(e=>e.Username == username);
|
||
|
if(user != null)
|
||
|
{
|
||
|
var res=new RegistrationResult("Username Exists");
|
||
|
return res;
|
||
|
}
|
||
|
user = users.FindOne(e=>e.Email == email);
|
||
|
if(user != null)
|
||
|
{
|
||
|
var res=new RegistrationResult("Email Exists");
|
||
|
return res;
|
||
|
}
|
||
|
bool oobe=users.LongCount() == 0;
|
||
|
|
||
|
Account a =new Account();
|
||
|
a.Username = username;
|
||
|
a.SetPassword(password,true);
|
||
|
a.Name = name;
|
||
|
a.Email=email;
|
||
|
a.Verified=UserManagement.DefaultVerificationStatus;
|
||
|
a.IsAdmin = oobe;
|
||
|
a.ShowUserNameToAnyBody=oobe;
|
||
|
if(a.IsValid())
|
||
|
{
|
||
|
users.Insert(a);
|
||
|
if(oobe)
|
||
|
{
|
||
|
//Register Anonymous
|
||
|
Account a2=new Account();
|
||
|
a2.IsAnonymous=true;
|
||
|
a2.IsAdmin=false;
|
||
|
a2.Verified=true;
|
||
|
a2.Username="_anonymous";
|
||
|
a2.Email = "anonymous@example.com";
|
||
|
a2.ShowUserNameToAnyBody=true;
|
||
|
a2.Name="Chatr Anonymous User";
|
||
|
a2.SetPassword("4209enabled",true); //dummy password would be 4209disabled when disabled
|
||
|
users.Insert(a2);
|
||
|
}
|
||
|
return new RegistrationResult(a);
|
||
|
}
|
||
|
return new RegistrationResult("Invalid sign up details");
|
||
|
}
|
||
|
return new RegistrationResult("Database Error: Accounts is null");
|
||
|
}
|
||
|
return new RegistrationResult("Invalid Password");
|
||
|
}
|
||
|
|
||
|
internal static void Logout(string session_id)
|
||
|
{
|
||
|
var sessions=DataBase.Sessions;
|
||
|
if(!string.IsNullOrWhiteSpace(session_id) && sessions!=null)
|
||
|
{
|
||
|
var session=sessions.FindOne(e=>e.SessionId==session_id);
|
||
|
if(session != null)
|
||
|
{
|
||
|
sessions.Delete(session.Id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
static Dictionary<long,UserOptions> _opt=new Dictionary<long, UserOptions>();
|
||
|
public static UserOptions GetUserOptions(Account account)
|
||
|
{
|
||
|
if(_opt.ContainsKey(account.Id))
|
||
|
{
|
||
|
return _opt[account.Id];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return new UserOptions(account);
|
||
|
}
|
||
|
public static void SetUserOptions(UserOptions options,ServerContext ctx)
|
||
|
{
|
||
|
options.Set(ctx);
|
||
|
}
|
||
|
|
||
|
public static AuthenticationResult Authenticate(string session_id)
|
||
|
{
|
||
|
var sessions=DataBase.Sessions;
|
||
|
if(sessions == null) return new AuthenticationResult("Database Error: Sessions is null");
|
||
|
var users=DataBase.Accounts;
|
||
|
if(users == null) return new AuthenticationResult("Database Error: Accounts is null");
|
||
|
|
||
|
foreach(var session in sessions.FindAll())
|
||
|
{
|
||
|
|
||
|
if(session.SessionId.Equals(session_id) && DateTime.Now < session.Expires)
|
||
|
{
|
||
|
var user=users.FindById(session.UserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
return new AuthenticationResult(user,session);
|
||
|
}
|
||
|
return new AuthenticationResult("User Removed");
|
||
|
}
|
||
|
}
|
||
|
return new AuthenticationResult("No valid session");
|
||
|
}
|
||
|
|
||
|
public static string CreateAnotherSession(string session_id,DateTime expires)
|
||
|
{
|
||
|
var sessions=DataBase.Sessions;
|
||
|
if(sessions == null) return null;
|
||
|
var users=DataBase.Accounts;
|
||
|
if(users == null) return null;
|
||
|
var session=sessions.FindOne(e=>e.SessionId==session_id);
|
||
|
if(session != null && DateTime.Now < session.Expires)
|
||
|
{
|
||
|
var user=users.FindById(session.UserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
Session session2=new Session();
|
||
|
session2.Expires=expires;
|
||
|
session2.RememberMe=true;
|
||
|
session2.Created=DateTime.Now;
|
||
|
session2.SessionId = Session.GetNewId();
|
||
|
session2.UserId=session.UserId;
|
||
|
sessions.Insert(session2);
|
||
|
return session2.SessionId;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
private static string CreateSession(Account user,DateTime expire,bool rememberMe)
|
||
|
{
|
||
|
var sessions=DataBase.Sessions;
|
||
|
if(sessions == null) return null;
|
||
|
|
||
|
string id= Session.GetNewId();
|
||
|
Session s=new Session();
|
||
|
s.Expires=expire;
|
||
|
s.SessionId=id;
|
||
|
s.UserId=user.Id;
|
||
|
s.RememberMe=rememberMe;
|
||
|
s.Created=DateTime.Now;
|
||
|
|
||
|
sessions.Insert(s);
|
||
|
|
||
|
return id;
|
||
|
}
|
||
|
|
||
|
public static Account GetAnonymous()
|
||
|
{
|
||
|
if(DataBase.Accounts != null)
|
||
|
{
|
||
|
var res=DataBase.Accounts.FindOne(e=>e.IsAnonymous);
|
||
|
if(res!=null) return res;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
public static LoginResult Login(string username,string password,bool rememberMe)
|
||
|
{
|
||
|
LoginResult res=new LoginResult();
|
||
|
res.Success=false;
|
||
|
var users=DataBase.Accounts;
|
||
|
if(users == null || username == "_anonymous" /*prevent logging in as lovely _anonymous account*/) return res;
|
||
|
|
||
|
|
||
|
var user=users.FindOne(e=>e.Username == username);
|
||
|
|
||
|
if(user != null && user.IsCorrectPassword(password))
|
||
|
{
|
||
|
DateTime expire=rememberMe ? DateTime.Now.AddYears(1) : DateTime.Now.AddHours(2);
|
||
|
res.Success=true;
|
||
|
res.Account=user;
|
||
|
res.Expires=expire;
|
||
|
res.SessionId = CreateSession(user,expire,rememberMe);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
public static string GetNameTextFromMessage(Message msg,bool fromMe)
|
||
|
{
|
||
|
if(!msg.IsFromBot && !msg.IsToBot)
|
||
|
{
|
||
|
//person to person
|
||
|
if(msg.DestinationUserId == msg.SourceUserId) return "me";
|
||
|
if(DataBase.Accounts != null){
|
||
|
if(!fromMe)
|
||
|
{
|
||
|
//to me from username
|
||
|
var user = DataBase.Accounts.FindById(msg.DestinationUserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
return user.Name;
|
||
|
}
|
||
|
|
||
|
}else{
|
||
|
var user = DataBase.Accounts.FindById(msg.SourceUserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
return user.Name;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}else{
|
||
|
if(DataBase.Bots != null)
|
||
|
{
|
||
|
|
||
|
if(msg.DestinationUserId == msg.SourceUserId)
|
||
|
{
|
||
|
//me-botname
|
||
|
if(msg.IsFromBot ^ msg.IsToBot)
|
||
|
{
|
||
|
if(msg.IsFromBot)
|
||
|
{
|
||
|
//get bot for from
|
||
|
var bot=DataBase.Bots.FindById(msg.SourceBotId);
|
||
|
if(bot != null)
|
||
|
return $"{bot.BotName} (My Bot)";
|
||
|
}else{
|
||
|
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
|
||
|
if(bot != null)
|
||
|
return $"{bot.BotName} (My Bot)";
|
||
|
|
||
|
|
||
|
}
|
||
|
} // bot to bot communication not supported in ui if at all
|
||
|
|
||
|
}else{
|
||
|
if(DataBase.Accounts != null){
|
||
|
//the bot must not be yours
|
||
|
if(msg.IsFromBot ^ !fromMe)
|
||
|
{
|
||
|
var a = DataBase.Accounts.FindById(msg.SourceUserId);
|
||
|
var bot=DataBase.Bots.FindById(msg.SourceBotId);
|
||
|
if(bot != null && a != null)
|
||
|
return $"{bot.BotName} ({a.Name}'s Bot)";
|
||
|
|
||
|
//return $"{a.Username}-{bot.BotUserName}";
|
||
|
|
||
|
// {userName}-{botname}
|
||
|
}else if(msg.IsToBot ^ fromMe)
|
||
|
{
|
||
|
var a = DataBase.Accounts.FindById(msg.DestinationUserId);
|
||
|
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
|
||
|
if(bot != null && a != null)
|
||
|
return $"{bot.BotName} ({a.Name}'s Bot)";
|
||
|
//return $"{a.Username}-{bot.BotUserName}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
public static string GetHashTextFromMessage(Message msg,bool fromMe) //true if you are ws to dest, false if loading my msg from data base
|
||
|
{
|
||
|
//from me = true
|
||
|
//msg.Source will be considered me msg.Destination will be username
|
||
|
//from me = false
|
||
|
//msg.Destination will be considered username, destination will be me
|
||
|
|
||
|
|
||
|
if(!msg.IsFromBot && !msg.IsToBot)
|
||
|
{
|
||
|
//person to person
|
||
|
if(msg.DestinationUserId == msg.SourceUserId) return "me";
|
||
|
if(DataBase.Accounts != null){
|
||
|
if(!fromMe)
|
||
|
{
|
||
|
//to me from username
|
||
|
var user = DataBase.Accounts.FindById(msg.DestinationUserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
return user.Username;
|
||
|
}
|
||
|
|
||
|
}else{
|
||
|
var user = DataBase.Accounts.FindById(msg.SourceUserId);
|
||
|
if(user != null)
|
||
|
{
|
||
|
return user.Username;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}else{
|
||
|
if(DataBase.Bots != null)
|
||
|
{
|
||
|
|
||
|
if(msg.DestinationUserId == msg.SourceUserId)
|
||
|
{
|
||
|
//me-botname
|
||
|
if(msg.IsFromBot ^ msg.IsToBot)
|
||
|
{
|
||
|
if(msg.IsFromBot)
|
||
|
{
|
||
|
//get bot for from
|
||
|
var bot=DataBase.Bots.FindById(msg.SourceBotId);
|
||
|
if(bot != null)
|
||
|
return $"me-{bot.BotUserName}";
|
||
|
}else{
|
||
|
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
|
||
|
if(bot != null)
|
||
|
return $"me-{bot.BotUserName}";
|
||
|
}
|
||
|
} // bot to bot communication not supported in ui if at all
|
||
|
|
||
|
}else{
|
||
|
if(DataBase.Accounts != null){
|
||
|
//the bot must not be yours
|
||
|
if(msg.IsFromBot ^ !fromMe)
|
||
|
{
|
||
|
var a = DataBase.Accounts.FindById(msg.SourceUserId);
|
||
|
var bot=DataBase.Bots.FindById(msg.SourceBotId);
|
||
|
if(bot != null && a != null)
|
||
|
return $"{a.Username}-{bot.BotUserName}";
|
||
|
|
||
|
// {userName}-{botname}
|
||
|
}else if(msg.IsToBot ^ fromMe)
|
||
|
{
|
||
|
var a = DataBase.Accounts.FindById(msg.DestinationUserId);
|
||
|
var bot=DataBase.Bots.FindById(msg.DestinationBotId);
|
||
|
if(bot != null && a != null)
|
||
|
return $"{a.Username}-{bot.BotUserName}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
//this doesn't check whether message is legit, it is done somewhere else
|
||
|
|
||
|
public static void SendMessage(Message msg)
|
||
|
{
|
||
|
msg.CreationTime=DateTime.Now;
|
||
|
|
||
|
if(DataBase.Messages != null)
|
||
|
{
|
||
|
//put msg in database
|
||
|
|
||
|
DataBase.Messages.Insert(msg); //easy as pie
|
||
|
|
||
|
|
||
|
//send to user over ws, somewhat harder
|
||
|
|
||
|
|
||
|
|
||
|
if(msg.IsToBot)
|
||
|
{
|
||
|
if(Bots.ContainsKey(msg.DestinationBotId))
|
||
|
{
|
||
|
foreach(var bot in Bots[msg.DestinationBotId])
|
||
|
{
|
||
|
bot.Push(msg);
|
||
|
}
|
||
|
}
|
||
|
}else{
|
||
|
Account tmpAcc;
|
||
|
if(DataBase.Accounts != null && ( tmpAcc = DataBase.Accounts.FindById(msg.DestinationUserId))!= null && tmpAcc.IsHidden(msg.SourceUserId,msg.IsFromBot ? msg.SourceBotId : -1) ) return;//impl hidden accounts and stuff
|
||
|
|
||
|
|
||
|
if(Humans.ContainsKey(msg.DestinationUserId))
|
||
|
{
|
||
|
foreach(var human in Humans[msg.DestinationUserId])
|
||
|
{
|
||
|
human.Push(msg);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public static void SendNotification(Notification notification)
|
||
|
{
|
||
|
|
||
|
|
||
|
if(DataBase.Notifications != null)
|
||
|
{
|
||
|
|
||
|
|
||
|
if(Humans.ContainsKey(notification.DestinationUserId))
|
||
|
{
|
||
|
foreach(var item in Humans[notification.DestinationUserId])
|
||
|
{
|
||
|
item.Push(notification);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
public static void SendNotificationEvent(NotificationEventFirePacket notification)
|
||
|
{
|
||
|
|
||
|
|
||
|
if(DataBase.Notifications != null && !string.IsNullOrWhiteSpace(notification.BotUserString) && !string.IsNullOrWhiteSpace(notification.SourceUserName))
|
||
|
{
|
||
|
|
||
|
var not=notification.BotUserString.Split(new char[]{'-'},2);
|
||
|
if(not.Length < 2) return;
|
||
|
string user=not[0];
|
||
|
string bot = not[1];
|
||
|
if(user == "me")
|
||
|
{
|
||
|
user = notification.SourceUserName;
|
||
|
}
|
||
|
long botId = GetBotId(user,bot);
|
||
|
|
||
|
if(Bots.ContainsKey(botId))
|
||
|
{
|
||
|
foreach(var item in Bots[botId])
|
||
|
{
|
||
|
item.Push(notification);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
public static long GetUserId(string user)
|
||
|
{
|
||
|
Account a;
|
||
|
if(DataBase.Accounts != null && (a=DataBase.Accounts.FindOne(e=>e.Username == user)) != null )
|
||
|
return a.Id;
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
public static long GetBotId(string user,string bot)
|
||
|
{
|
||
|
Bot b;
|
||
|
if(DataBase.Bots != null && (b=DataBase.Bots.FindOne(e=>e.BotUserName == bot && e.UserId== GetUserId(user))) != null)
|
||
|
return b.Id;
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
public static long GetBotId(long user,string bot)
|
||
|
{
|
||
|
Bot b;
|
||
|
if(DataBase.Bots != null && (b=DataBase.Bots.FindOne(e=>e.BotUserName == bot && e.UserId== user)) != null)
|
||
|
return b.Id;
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
public static IEnumerable<Bot> GetMyBots(Account account,bool censored=true)
|
||
|
{
|
||
|
|
||
|
if(DataBase.Bots != null)
|
||
|
{
|
||
|
foreach(var bot in DataBase.Bots.Find(e=>e.UserId==account.Id))
|
||
|
{
|
||
|
if(censored && account.IsHidden(account.Id,bot.Id)) continue;
|
||
|
yield return bot;
|
||
|
}
|
||
|
}
|
||
|
yield break;
|
||
|
}
|
||
|
public static IEnumerable<Bot> GetBotsWithMe(Account account,Account other,bool censored=true)
|
||
|
{
|
||
|
if(censored && account.IsHidden(other.Id,-1)) yield break;
|
||
|
|
||
|
List<long> ids=new List<long>();
|
||
|
if(DataBase.Messages != null && DataBase.Bots != null)
|
||
|
{
|
||
|
foreach(var msg in DataBase.Messages.FindAll())
|
||
|
{
|
||
|
var e=msg;
|
||
|
if(!((e.DestinationUserId == other.Id && e.SourceUserId ==account.Id && !e.IsFromBot && e.IsToBot ) ^ (e.DestinationUserId == account.Id && e.IsFromBot && !e.IsToBot && e.SourceUserId == other.Id) )) continue;
|
||
|
if(msg.SourceUserId == account.Id)
|
||
|
{
|
||
|
if(!ids.Contains(msg.DestinationBotId)) ids.Add(msg.DestinationBotId);
|
||
|
}else{
|
||
|
if(!ids.Contains(msg.SourceBotId)) ids.Add(msg.SourceBotId);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
foreach(var id in ids)
|
||
|
{
|
||
|
if( censored|| account.IsHidden(other.Id,id)) continue;
|
||
|
var res=DataBase.Bots.FindById(id);
|
||
|
if(res != null)
|
||
|
yield return res;
|
||
|
}
|
||
|
}
|
||
|
yield break;
|
||
|
}
|
||
|
public static IEnumerable<Account> GetUserWithMe(Account account,bool censored=true)
|
||
|
{
|
||
|
List<long> ids=new List<long>();
|
||
|
if(DataBase.Messages != null && DataBase.Accounts != null)
|
||
|
{
|
||
|
foreach(var msg in DataBase.Messages.FindAll())
|
||
|
{
|
||
|
var e=msg;
|
||
|
if(!(e.SourceUserId ==account.Id ^ e.DestinationUserId == account.Id )) continue;
|
||
|
if(msg.SourceUserId == account.Id)
|
||
|
{
|
||
|
if(!ids.Contains(msg.DestinationUserId)) ids.Add(msg.DestinationUserId);
|
||
|
}else{
|
||
|
if(!ids.Contains(msg.SourceUserId)) ids.Add(msg.SourceUserId);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
foreach(var usr in DataBase.Accounts.Find(e=>e.ShowUserNameToAnyBody==true))
|
||
|
{
|
||
|
if(!ids.Contains(usr.Id))
|
||
|
{
|
||
|
ids.Add(usr.Id);
|
||
|
}
|
||
|
}
|
||
|
foreach(var id in ids)
|
||
|
{
|
||
|
if(censored && account.IsHidden(id,-1)) continue;
|
||
|
var res=DataBase.Accounts.FindById(id);
|
||
|
if(res != null)
|
||
|
yield return res;
|
||
|
}
|
||
|
}
|
||
|
yield break;
|
||
|
}
|
||
|
public static IEnumerable<Message> GetMessages(Account account,string user=null,string bot=null,bool censored=true)
|
||
|
{
|
||
|
|
||
|
if(DataBase.Messages != null)
|
||
|
{
|
||
|
|
||
|
if(string.IsNullOrWhiteSpace(user) && string.IsNullOrWhiteSpace(bot))
|
||
|
{
|
||
|
//you
|
||
|
|
||
|
|
||
|
foreach(var msg in DataBase.Messages.Find(e=> e.IsFromBot == false && e.IsToBot == false && e.SourceUserId == account.Id && e.DestinationUserId == account.Id))
|
||
|
{
|
||
|
yield return msg;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if(string.IsNullOrWhiteSpace(bot) && !string.IsNullOrWhiteSpace(user))
|
||
|
{
|
||
|
//a user
|
||
|
var userId=GetUserId(user);
|
||
|
if(censored && account.IsHidden(userId,-1)) yield break;
|
||
|
foreach(var msg in DataBase.Messages.Find(e=>e.IsFromBot == false && e.IsToBot==false && ((e.SourceUserId == userId && e.DestinationUserId == account.Id) || (e.SourceUserId == account.Id && e.DestinationUserId == userId))))
|
||
|
{
|
||
|
yield return msg;
|
||
|
}
|
||
|
}else if(!string.IsNullOrWhiteSpace(bot) && string.IsNullOrWhiteSpace(user))
|
||
|
{
|
||
|
//my bots
|
||
|
|
||
|
var botId = GetBotId(account.Id,bot);
|
||
|
|
||
|
if(censored && account.IsHidden(account.Id,botId)) yield break;
|
||
|
|
||
|
foreach(var msg in DataBase.Messages.Find(e=>(
|
||
|
(e.SourceUserId == account.Id && e.IsFromBot==true && e.IsToBot==false && e.SourceBotId == botId && e.DestinationUserId ==account.Id) ||
|
||
|
(e.DestinationUserId == account.Id && e.IsToBot==true && e.IsFromBot == false && e.SourceUserId == account.Id)
|
||
|
)))
|
||
|
{
|
||
|
yield return msg;
|
||
|
}
|
||
|
}
|
||
|
else if(!string.IsNullOrWhiteSpace(bot) && !string.IsNullOrWhiteSpace(user)){
|
||
|
// a bot
|
||
|
var userId = GetUserId(user);
|
||
|
var botId = GetBotId(userId,bot);
|
||
|
if(account.IsHidden(userId,botId)) yield break;
|
||
|
foreach(var msg in DataBase.Messages.Find(e=>(
|
||
|
(e.SourceUserId == userId && e.IsFromBot==true && e.IsToBot==false && e.SourceBotId == botId && e.DestinationUserId == account.Id) ||
|
||
|
(e.DestinationUserId == userId && e.IsToBot==true && e.IsFromBot == false && e.SourceUserId == account.Id)
|
||
|
)))
|
||
|
{
|
||
|
yield return msg;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
yield break;
|
||
|
}
|
||
|
public static AuthenticationBotResult AuthenticateApiKey(string apiKey)
|
||
|
{
|
||
|
if(DataBase.Bots == null)return new AuthenticationBotResult("Database Error: Bots is null");
|
||
|
|
||
|
//authenticate bot
|
||
|
var bot=DataBase.Bots.FindOne(e=>e.ApiKey == apiKey);
|
||
|
if(bot != null){
|
||
|
return new AuthenticationBotResult(bot);
|
||
|
}
|
||
|
return new AuthenticationBotResult("Bot Not found for apiKey");
|
||
|
|
||
|
}
|
||
|
public static string GenerateApiKey(Account user,Bot bot)
|
||
|
{
|
||
|
|
||
|
if(DataBase.Bots == null)return null;
|
||
|
string apiKey;
|
||
|
do{
|
||
|
apiKey=Account.GetNewSalt();
|
||
|
} while(DataBase.Bots.FindOne(e=>e.ApiKey == apiKey) != null);
|
||
|
bot.ApiKey=apiKey;
|
||
|
bot.UserId=user.Id;
|
||
|
DataBase.Bots.Insert(bot);
|
||
|
return apiKey;
|
||
|
|
||
|
}
|
||
|
|
||
|
public static bool IsValidPassword(string password)
|
||
|
{
|
||
|
if(password.Length < 8) return false; //need a longer password
|
||
|
|
||
|
if(password.StartsWith("password",StringComparison.OrdinalIgnoreCase)) return false; //prevents password password1 etc
|
||
|
|
||
|
int num = 0;
|
||
|
char lastChar='\0';
|
||
|
foreach(var c in password) //prevents 12345678
|
||
|
{
|
||
|
|
||
|
if(c+1 == lastChar)
|
||
|
{num++;}
|
||
|
else if(c-1 == lastChar) {num++;} else {num=0;}
|
||
|
|
||
|
|
||
|
lastChar=c;
|
||
|
if(num > 5) return false;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
internal static bool GetAuthCode(string key, out string session)
|
||
|
{
|
||
|
session="";
|
||
|
if(_otaCodes.ContainsKey(key))
|
||
|
{
|
||
|
if(_otaCodes[key].Expires > DateTime.Now)
|
||
|
{
|
||
|
session=_otaCodes[key].SessionId;
|
||
|
return true;
|
||
|
}
|
||
|
_otaCodes.Remove(key);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
private static string GetRandOta()
|
||
|
{
|
||
|
string id=Session.GetNewId().Replace("=","ee").Replace("+","je").Replace("/","42");
|
||
|
return id;
|
||
|
}
|
||
|
internal static string CreateOTA(string sessionId)
|
||
|
{
|
||
|
string ota=GetRandOta();
|
||
|
while(_otaCodes.ContainsKey(ota))
|
||
|
{
|
||
|
ota=GetRandOta();
|
||
|
}
|
||
|
OTA o=new OTA();
|
||
|
o.Expires=DateTime.Now.AddMinutes(10);
|
||
|
o.SessionId = sessionId;
|
||
|
_otaCodes.Add(ota,o);
|
||
|
return ota;
|
||
|
}
|
||
|
|
||
|
internal static void SendClearAll(ClearAllPacket pkt)
|
||
|
{
|
||
|
var uid= UserManagement.GetUserId(pkt.UserStr);
|
||
|
|
||
|
if(Humans.ContainsKey(uid))
|
||
|
{
|
||
|
foreach(var item in Humans[uid])
|
||
|
{
|
||
|
item.Push(pkt);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
internal class OTA
|
||
|
{
|
||
|
public string SessionId {get;set;}
|
||
|
|
||
|
public DateTime Expires {get;set;}
|
||
|
}
|
||
|
}
|