Cleanup of services and new homebound service [replaces at home]

This commit is contained in:
Madpeter 2022-06-02 07:24:35 +01:00
parent b089591fcb
commit 745977b1b4
15 changed files with 857 additions and 199 deletions

View file

@ -197,6 +197,7 @@ namespace SecondBotEvents.Commands
{
return Failure("Error Unable to Teleport to location", new [] { region, x, y, z });
}
master.HomeboundService.markTeleport();
return BasicReply("Accepted", new [] { region, x, y, z });
}

View file

@ -26,8 +26,8 @@ namespace SecondBotEvents.Commands
{
return Failure("Content value is empty", new [] { collection, content });
}
return Failure("@todo notecard temp stroage");
//return BasicReply("ok", "NotecardAdd", new [] { collection, content });
master.DataStoreService.AppendKeyValue("notecard_"+collection, content);
return BasicReply("ok", new [] { collection, master.DataStoreService.GetKeyValue("notecard_"+collection).Length.ToString() });
}
[About("Clears the contents of a collection")]
@ -40,7 +40,8 @@ namespace SecondBotEvents.Commands
{
return Failure("Collection value is empty", new [] { collection });
}
return Failure("@todo notecard storage");
master.DataStoreService.ClearKeyValue("notecard_" + collection);
return BasicReply("ok");
}
[About("Sends a notecard to a avatar using the text in the prebuilt collection [see NotecardAdd] and also clears the collection just before sending [see NotecardClear]")]
@ -67,7 +68,18 @@ namespace SecondBotEvents.Commands
{
return Failure("Invaild avatar uuid", new [] { avatar, collection, notecardname });
}
return Failure("@todo notecard storage");
string content = master.DataStoreService.GetKeyValue("notecard_" + collection);
if(content.Length <= 3)
{
return Failure("No content in notecard storage ?", new[] { avatar, collection, notecardname });
}
bool result = master.botClient.SendNotecard(notecardname, content, avataruuid);
if (result == false)
{
return Failure("Failed to create/send notecard", new[] { avatar, content, notecardname });
}
master.DataStoreService.ClearKeyValue("notecard_" + collection);
return BasicReply("ok");
}
[About("Creates and sends a notecard in one command good if you are using HTTP otherwise see [NotecardSend]")]
@ -93,7 +105,12 @@ namespace SecondBotEvents.Commands
{
return Failure("Invaild avatar uuid", new[] { avatar, content, notecardname });
}
return Failure("@todo notecard sending");
bool result = master.botClient.SendNotecard(notecardname, content, avataruuid);
if(result == false)
{
return Failure("Failed to create/send notecard", new[] { avatar, content, notecardname });
}
return BasicReply("ok");
}
}
}

View file

@ -60,7 +60,17 @@ namespace SecondBotEvents.Commands
{
return Failure("Notecard title is to short", new [] { endpoint, endpointcode });
}
return Failure("@todo notecard sending");
ProcessAvatar(server_reply.AvatarUUID);
if(avataruuid == UUID.Zero)
{
return Failure("Unable to unpack avatar", new[] { endpoint, endpointcode });
}
bool result = master.botClient.SendNotecard(server_reply.NotecardTitle, server_reply.NotecardContent, avataruuid);
if (result == false)
{
return Failure("Failed to create/send notecard", new[] { endpoint, endpointcode });
}
return BasicReply("ok");
}
catch (Exception e)
{

View file

@ -14,7 +14,6 @@ namespace SecondBotEvents.Config
settings.Add("LocalChatHistoryLimit");
settings.Add("GroupChatHistoryLimitPerGroup");
settings.Add("ImChatHistoryLimit");
settings.Add("NotecardStoragePurgeAfterMins");
settings.Add("PrefetchGroupMembers");
settings.Add("PrefetchGroupRoles");
settings.Add("PrefetchEstateBanlist");
@ -73,10 +72,5 @@ namespace SecondBotEvents.Config
{
return ReadSettingAsInt("ImChatHistoryLimit", 50);
}
public int GetNotecardStoragePurgeAfterMins()
{
return ReadSettingAsInt("NotecardStoragePurgeAfterMins", 10);
}
}
}

View file

@ -0,0 +1,53 @@
using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Text;
namespace SecondBotEvents.Config
{
public class HomeboundConfig : Config
{
public HomeboundConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { }
protected override void MakeSettings()
{
filename = "homebound";
settings.Add("Enabled");
settings.Add("HomeSimSlUrl");
settings.Add("BackupSimSLUrl");
settings.Add("AtHomeSeekLocation");
settings.Add("AtBackupSeekLocation");
settings.Add("AtHomeAutoSitUuid");
}
public string GetAtHomeAutoSitUuid()
{
return ReadSettingAsString("AtHomeAutoSitUuid", UUID.Zero.ToString());
}
public bool GetAtHomeSeekLocation()
{
return ReadSettingAsBool("AtHomeSeekLocation", true);
}
public bool GetAtBackupSeekLocation()
{
return ReadSettingAsBool("AtBackupSeekLocation", false);
}
public string GetBackupSimSLUrl()
{
return ReadSettingAsString("BackupSimSLUrl", "Sandbox%20Decorus/128/128/27");
}
public string GetHomeSimSlUrl()
{
return ReadSettingAsString("HomeSimSlUrl", "Viserion/46/163/23");
}
public bool GetEnabled()
{
return ReadSettingAsBool("Enabled", false);
}
}
}

View file

@ -11,12 +11,12 @@ namespace SecondBotEvents.Config
{
filename = "http";
settings.Add("Enabled");
settings.Add("Host");
settings.Add("Port");
}
public string GetHost()
public int GetPort()
{
return ReadSettingAsString("Host", "http://*:80");
return ReadSettingAsInt("Port", 80);
}
public bool GetEnabled()

View file

@ -3,6 +3,7 @@ using System;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Collections.Generic;
namespace SecondBotEvents
{
@ -10,24 +11,31 @@ namespace SecondBotEvents
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to Secondbot [Events build] version: " + AssemblyInfo.GetGitHash());
LogFormater.Info("Welcome to Secondbot [Events build] version: " + AssemblyInfo.GetGitHash());
EventsSecondBot worker = new EventsSecondBot(args);
while(worker.Exit() == false)
{
if(worker.Ready == true)
{
worker.Status();
}
Thread.Sleep(1000);
}
LogFormater.Warn("Shutdown in 5 secs");
Thread.Sleep(5000);
}
}
public class EventsSecondBot
{
public HttpService HttpService = null;
public CommandsService CommandsService = null;
public BotClientService botClient = null;
public DiscordService DiscordService = null;
public InteractionService InteractionService = null;
public DataStoreService DataStoreService = null;
public HttpService HttpService { get { return (HttpService) getService("HttpService"); } }
public CommandsService CommandsService { get { return (CommandsService)getService("CommandsService"); } }
public BotClientService botClient { get { return (BotClientService)getService("BotClientService"); } }
public DiscordService DiscordService { get { return (DiscordService)getService("DiscordService"); } }
public InteractionService InteractionService { get { return (InteractionService)getService("InteractionService"); } }
public DataStoreService DataStoreService { get { return (DataStoreService)getService("DataStoreService"); } }
public HomeboundService HomeboundService { get { return (HomeboundService)getService("HomeboundService"); } }
private EventHandler<BotClientNotice> botclient_eventNotices;
@ -45,6 +53,8 @@ namespace SecondBotEvents
handler?.Invoke(this, new BotClientNotice(asRestart));
}
public string GetVersion()
{
return AssemblyInfo.GetGitHash();
@ -67,61 +77,120 @@ namespace SecondBotEvents
StartServices();
}
public bool Ready = false;
public void RestartServices()
{
StopServices();
StartServices();
}
protected Dictionary<string, BotServices> services = new Dictionary<string, BotServices>();
public BotServices getService(string classname)
{
if(services.ContainsKey(classname) == false)
{
return null;
}
return services[classname];
}
protected BotServices RegisterService(string classname, bool autoStart = true)
{
BotServices instance = (BotServices)GetInstance("SecondBotEvents.Services." + classname);
services.Add(classname, instance);
lastStatus.Add(classname, "?");
if (autoStart == true)
{
instance.Start();
}
return instance;
}
protected object GetInstance(string strFullyQualifiedName)
{
Type type = Type.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type, this);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(strFullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type, this);
}
return null;
}
protected void StartServices()
{
DataStoreService = new DataStoreService(this);
DataStoreService.Start();
botClient = new BotClientService(this);
HttpService = new HttpService(this);
CommandsService = new CommandsService(this);
DiscordService = new DiscordService(this);
InteractionService = new InteractionService(this);
services = new Dictionary<string, BotServices>();
lastStatus = new Dictionary<string, string>();
RegisterService("BotClientService", false);
RegisterService("DataStoreService");
RegisterService("HttpService");
RegisterService("CommandsService");
RegisterService("DiscordService");
RegisterService("InteractionService");
RegisterService("HomeboundService");
if (botClient.IsLoaded() == false)
{
Console.WriteLine("Config is not loaded :(");
exitNow = true;
return;
}
HttpService.Start();
CommandsService.Start();
DiscordService.Start();
InteractionService.Start();
botClient.Start();
Ready = true;
}
Dictionary<string, string> lastStatus = new Dictionary<string, string>();
long lastChange = 0;
public void Status()
{
string Output = "";
string addon = "";
foreach(KeyValuePair<string, BotServices> A in services)
{
string StatusMessage = A.Value.Status();
if(StatusMessage != lastStatus[A.Key])
{
Output = Output + addon + " [" + A.Key + "] ~ " + StatusMessage;
lastStatus[A.Key] = StatusMessage;
addon = " | ";
}
}
if(Output != "")
{
LogFormater.Info(Output);
lastChange = SecondbotHelpers.UnixTimeNow();
return;
}
long dif = SecondbotHelpers.UnixTimeNow() - lastChange;
if(dif > 60)
{
string[] bits = lastStatus.Keys.ToArray();
foreach (string A in bits)
{
lastStatus[A] = "";
}
}
}
protected void StopServices()
{
if(DataStoreService != null)
Ready = false;
Dictionary<string, BotServices> copy = services;
foreach (KeyValuePair<string, BotServices> A in copy)
{
DataStoreService.Stop();
if(A.Key == "BotClientService")
{
continue;
}
A.Value.Stop();
services.Remove(A.Key);
}
if (HttpService != null)
{
HttpService.Stop();
}
if (CommandsService != null)
{
CommandsService.Stop();
}
if (DiscordService != null)
{
DiscordService.Stop();
}
if(InteractionService != null)
{
InteractionService.Stop();
}
if(botClient != null)
{
botClient.Stop();
}
HttpService = null;
botClient = null;
services["BotClientService"].Stop();
services.Remove("BotClientService");
}
public bool Exit()

View file

@ -1,4 +1,5 @@
using OpenMetaverse;
using OpenMetaverse.Assets;
using SecondBotEvents.Config;
using System;
using System.Collections.Generic;
@ -6,10 +7,19 @@ using System.Text;
namespace SecondBotEvents.Services
{
public class BotClientService : Services
public class BotClientService : BotServices
{
public GridClient client = null;
protected BasicConfig basicCfg = null;
public bool _ExitBot
{
get { return ExitBot; } // get method
set { } // set method
}
protected bool ExitBot = false;
public BotClientService(EventsSecondBot setMaster) : base(setMaster)
{
basicCfg = new BasicConfig(master.fromEnv, master.fromFolder);
@ -52,7 +62,14 @@ namespace SecondBotEvents.Services
}
protected void BotLoginStatus(object o, LoginProgressEventArgs e)
{
{
if(e.FailReason != "")
{
Console.WriteLine("Client service ~ {FAILED} Login status: " + e.FailReason.ToString());
client.Network.Logout();
ResetClient();
return;
}
Console.WriteLine("Client service ~ Login status: " + e.Status.ToString());
}
public void SendIM(UUID avatar, string message)
@ -61,6 +78,64 @@ namespace SecondBotEvents.Services
client.Self.InstantMessage(avatar, message);
}
public bool SendNotecard(string name, string content, UUID sendToUUID)
{
bool returnstatus = true;
name = name + " " + DateTime.Now;
client.Inventory.RequestCreateItem(
client.Inventory.FindFolderForType(AssetType.Notecard),
name,
name + " Created via SecondBot notecard API",
AssetType.Notecard,
UUID.Random(),
InventoryType.Notecard,
PermissionMask.All,
(bool Success, InventoryItem item) =>
{
if (Success)
{
AssetNotecard empty = new AssetNotecard { BodyText = "\n" };
empty.Encode();
client.Inventory.RequestUploadNotecardAsset(empty.AssetData, item.UUID,
(bool emptySuccess, string emptyStatus, UUID emptyItemID, UUID emptyAssetID) =>
{
if (emptySuccess)
{
empty.BodyText = content;
empty.Encode();
client.Inventory.RequestUploadNotecardAsset(empty.AssetData, emptyItemID,
(bool finalSuccess, string finalStatus, UUID finalItemID, UUID finalID) =>
{
if (finalSuccess)
{
LogFormater.Info("Sending notecard now");
client.Inventory.GiveItem(finalItemID, name, AssetType.Notecard, sendToUUID, false);
}
else
{
returnstatus = false;
LogFormater.Warn("Unable to request notecard upload");
}
});
}
else
{
LogFormater.Warn("The fuck empty success notecard create");
returnstatus = false;
}
});
}
else
{
LogFormater.Warn("Unable to find default notecards folder");
returnstatus = false;
}
}
);
return returnstatus;
}
protected void ResetClient()
{
bool isRestart = false;
@ -96,6 +171,25 @@ namespace SecondBotEvents.Services
client.Network.BeginLogin(loginParams);
}
public override string Status()
{
if (client == null)
{
return "No Client [Restart needed]";
}
else if (client.Network == null)
{
return "No network - [Starting / Shutting down]";
}
else if (client.Network.Connected == false)
{
return "Not connected";
}
else if (client.Network.CurrentSim == null)
{
return "No sim";
}
return client.Network.CurrentSim.Name + " " + client.Self.SimPosition.ToString();
}
}
}

View file

@ -11,7 +11,7 @@ using System.Net.Http;
namespace SecondBotEvents.Services
{
public class CommandsService : Services
public class CommandsService : BotServices
{
public CommandsConfig myConfig = null;
public bool acceptNewCommands = false;
@ -120,6 +120,15 @@ namespace SecondBotEvents.Services
acceptNewCommands = false;
}
public override string Status()
{
if (acceptNewCommands == false)
{
return "Disabled";
}
return "Enabled";
}
protected void BotImMessage(object o, InstantMessageEventArgs e)
{
if(acceptNewCommands == false)
@ -346,7 +355,7 @@ namespace SecondBotEvents.Services
public string command;
public string signingCode;
public string[] args;
public string replyTarget;
public string replyTarget = null;
public bool accepted = false;
public long unixtimeOfCommand = 0;
public SignedCommand(string input, bool requireSigning, bool requireTimewindow, int windowSize, string secret)
@ -357,12 +366,27 @@ namespace SecondBotEvents.Services
accepted = true; // just accept the command
return;
}
vaildate(requireTimewindow, windowSize, secret);
}
public SignedCommand(string setCommand, string setSigningCode, string[] setArgs, int setUnixtime, string setReplyTarget, bool requireTimewindow, int windowSize, string secret)
{
command = setCommand;
signingCode = setSigningCode;
args = setArgs;
unixtimeOfCommand = setUnixtime;
replyTarget = setReplyTarget;
vaildate(requireTimewindow, windowSize, secret);
}
protected void vaildate(bool requireTimewindow, int windowSize, string secret)
{
accepted = false;
long dif = SecondbotHelpers.UnixTimeNow() - unixtimeOfCommand;
if ((requireTimewindow == true) && ((unixtimeOfCommand == 0) || (dif > windowSize))) // bad time window
{
return;
}
if ((signingCode == null) ) // no signing code
if ((signingCode == null)) // no signing code
{
return;
}
@ -379,9 +403,8 @@ namespace SecondBotEvents.Services
return; // invaild signing code
}
accepted = true;
}
protected void unpackInput(string input)
{
if (IsValidJson(input) == false)

View file

@ -9,7 +9,7 @@ using System.Threading;
namespace SecondBotEvents.Services
{
public class DataStoreService : Services
public class DataStoreService : BotServices
{
protected DataStoreConfig myConfig;
protected bool botConnected = false;
@ -18,15 +18,6 @@ namespace SecondBotEvents.Services
myConfig = new DataStoreConfig(master.fromEnv,master.fromFolder);
}
public override string Status()
{
if(myConfig == null)
{
return "DataStore Service [Config status broken]";
}
return "DataStore Service [Waiting for bot]";
}
protected Dictionary<string, UUID> avatarsName2Key = new Dictionary<string, UUID>();
protected Dictionary<UUID, string> groupsKey2Name = new Dictionary<UUID, string>();
@ -44,12 +35,24 @@ namespace SecondBotEvents.Services
protected Dictionary<string, string> KeyValueStore = new Dictionary<string, string>();
protected Dictionary<string, long> KeyValueStoreLastUsed = new Dictionary<string, long>();
protected List<CommandHistory> commandHistories = new List<CommandHistory>();
public void addCommandToHistory(UUID Source, string command, string[] args)
public override string Status()
{
CommandHistory A = new CommandHistory(Source, command, args, SecondbotHelpers.UnixTimeNow());
if (myConfig == null)
{
return "DataStore Service [Config broken]";
}
int sum = commandHistories.Count() + KeyValueStoreLastUsed.Count() + KeyValueStore.Count() +
chatWindowsOwner.Count() + chatWindowsIsGroup.Count() + chatWindowsUnread.Count() +
chatWindows.Count() + localChatHistory.Count() + groupRoles.Count() +
groupMembers.Count() + groupsKey2Name.Count() + avatarsName2Key.Count();
return sum.ToString();
}
public void addCommandToHistory(bool status, string command, string[] args)
{
CommandHistory A = new CommandHistory(status, command, args, SecondbotHelpers.UnixTimeNow());
commandHistories.Add(A);
int c = commandHistories.Count;
while (c > myConfig.GetCommandHistoryLimit())
@ -257,83 +260,92 @@ namespace SecondBotEvents.Services
protected void recordChat(UUID sessionID, string fromname, string message)
{
if(chatWindows.ContainsKey(sessionID) == false)
lock (chatWindows)
{
return; // chat window not open unable to record message
}
chatWindows[sessionID].Add(fromname + ": " + message);
chatWindowsUnread[sessionID] = true;
int purgeLen = myConfig.GetImChatHistoryLimit();
if(chatWindowsIsGroup[sessionID] == true)
{
purgeLen = myConfig.GetGroupChatHistoryLimitPerGroup();
}
int counter = chatWindows[sessionID].Count();
while (counter > purgeLen)
{
chatWindows[sessionID].RemoveAt(0);
counter--;
if (chatWindows.ContainsKey(sessionID) == false)
{
return; // chat window not open unable to record message
}
chatWindows[sessionID].Add(fromname + ": " + message);
chatWindowsUnread[sessionID] = true;
int purgeLen = myConfig.GetImChatHistoryLimit();
if (chatWindowsIsGroup[sessionID] == true)
{
purgeLen = myConfig.GetGroupChatHistoryLimitPerGroup();
}
int counter = chatWindows[sessionID].Count();
while (counter > purgeLen)
{
chatWindows[sessionID].RemoveAt(0);
counter--;
}
}
}
protected void closeChat(UUID owner)
{
UUID sessionID = UUID.Zero;
if(chatWindowsOwner.ContainsValue(owner) == false)
lock (chatWindows)
{
return;
}
foreach(KeyValuePair<UUID,UUID> ownermap in chatWindowsOwner)
{
if(ownermap.Value != owner)
UUID sessionID = UUID.Zero;
if (chatWindowsOwner.ContainsValue(owner) == false)
{
continue;
return;
}
sessionID = ownermap.Key;
foreach (KeyValuePair<UUID, UUID> ownermap in chatWindowsOwner)
{
if (ownermap.Value != owner)
{
continue;
}
sessionID = ownermap.Key;
}
if (sessionID == UUID.Zero)
{
return;
}
chatWindowsOwner.Remove(sessionID);
chatWindowsIsGroup.Remove(sessionID);
chatWindowsUnread.Remove(sessionID);
chatWindows.Remove(sessionID);
}
if(sessionID == UUID.Zero)
{
return;
}
chatWindowsOwner.Remove(sessionID);
chatWindowsIsGroup.Remove(sessionID);
chatWindowsUnread.Remove(sessionID);
chatWindows.Remove(sessionID);
}
protected void openChatWindow(bool group, UUID sessionID, UUID ownerID)
{
if (chatWindows.ContainsKey(sessionID) == true)
lock (chatWindows)
{
return; // window already open
}
if (chatWindowsOwner.ContainsValue(ownerID) == true)
{
// new session find the old one and update to this session
Dictionary<UUID, UUID> oldOwners = chatWindowsOwner;
foreach (KeyValuePair<UUID,UUID> kvp in oldOwners)
if (chatWindows.ContainsKey(sessionID) == true)
{
if(kvp.Value == ownerID)
{
chatWindows.Add(sessionID, chatWindows[kvp.Key]);
chatWindowsUnread.Add(sessionID, chatWindowsUnread[kvp.Key]);
chatWindowsIsGroup.Add(sessionID, chatWindowsIsGroup[kvp.Key]);
chatWindowsOwner.Add(sessionID, ownerID);
chatWindows.Remove(kvp.Key);
chatWindowsUnread.Remove(kvp.Key);
chatWindowsIsGroup.Remove(kvp.Key);
chatWindowsOwner.Remove(kvp.Key);
break;
}
return; // window already open
}
return; // chat recovered
if (chatWindowsOwner.ContainsValue(ownerID) == true)
{
// new session find the old one and update to this session
Dictionary<UUID, UUID> oldOwners = chatWindowsOwner;
foreach (KeyValuePair<UUID, UUID> kvp in oldOwners)
{
if (kvp.Value == ownerID)
{
chatWindows.Add(sessionID, chatWindows[kvp.Key]);
chatWindowsUnread.Add(sessionID, chatWindowsUnread[kvp.Key]);
chatWindowsIsGroup.Add(sessionID, chatWindowsIsGroup[kvp.Key]);
chatWindowsOwner.Add(sessionID, ownerID);
chatWindows.Remove(kvp.Key);
chatWindowsUnread.Remove(kvp.Key);
chatWindowsIsGroup.Remove(kvp.Key);
chatWindowsOwner.Remove(kvp.Key);
break;
}
}
return; // chat recovered
}
chatWindows.Add(sessionID, new List<string>());
chatWindowsUnread.Add(sessionID, false);
chatWindowsIsGroup.Add(sessionID, group);
chatWindowsOwner.Add(sessionID, ownerID);
// new window now open
}
chatWindows.Add(sessionID, new List<string>());
chatWindowsUnread.Add(sessionID, false);
chatWindowsIsGroup.Add(sessionID, group);
chatWindowsOwner.Add(sessionID, ownerID);
// new window now open
}
@ -632,23 +644,29 @@ namespace SecondBotEvents.Services
protected void GroupRoles(object o, GroupRolesDataReplyEventArgs e)
{
if(groupRoles.ContainsKey(e.GroupID) == false)
lock (groupRoles)
{
groupRoles.Add(e.GroupID, new Dictionary<UUID, GroupRole>());
if (groupRoles.ContainsKey(e.GroupID) == false)
{
groupRoles.Add(e.GroupID, new Dictionary<UUID, GroupRole>());
}
groupRoles[e.GroupID] = e.Roles;
}
groupRoles[e.GroupID] = e.Roles;
}
protected void GroupMembers(object o, GroupMembersReplyEventArgs e)
{
if(groupMembers.ContainsKey(e.GroupID) == true)
lock (groupMembers)
{
groupMembers.Remove(e.GroupID);
}
groupMembers.Add(e.GroupID, new List<UUID>());
foreach (KeyValuePair<UUID,GroupMember> a in e.Members)
{
groupMembers[e.GroupID].Add(a.Value.ID);
if (groupMembers.ContainsKey(e.GroupID) == true)
{
groupMembers.Remove(e.GroupID);
}
groupMembers.Add(e.GroupID, new List<UUID>());
foreach (KeyValuePair<UUID, GroupMember> a in e.Members)
{
groupMembers[e.GroupID].Add(a.Value.ID);
}
}
}
@ -678,7 +696,10 @@ namespace SecondBotEvents.Services
protected void EstateBans(object o, EstateBansReplyEventArgs e)
{
estateBanlist = e.Banned;
lock (estateBanlist)
{
estateBanlist = e.Banned;
}
}
protected void BotLoggedIn(object o, SimConnectedEventArgs e)
@ -733,35 +754,38 @@ namespace SecondBotEvents.Services
protected void GroupCurrent(object o, CurrentGroupsEventArgs e)
{
List<UUID> missingGroups = groupsKey2Name.Keys.ToList();
foreach(Group G in e.Groups.Values)
lock (groupsKey2Name)
{
missingGroups.Remove(G.ID);
if (groupsKey2Name.ContainsKey(G.ID) == true)
List<UUID> missingGroups = groupsKey2Name.Keys.ToList();
foreach (Group G in e.Groups.Values)
{
continue;
missingGroups.Remove(G.ID);
if (groupsKey2Name.ContainsKey(G.ID) == true)
{
continue;
}
groupsKey2Name.Add(G.ID, G.Name);
getClient().Self.RequestJoinGroupChat(G.ID);
if (myConfig.GetPrefetchGroupMembers() == true)
{
getClient().Groups.RequestGroupMembers(G.ID);
}
if (myConfig.GetPrefetchGroupRoles() == true)
{
getClient().Groups.RequestGroupRoles(G.ID);
}
}
groupsKey2Name.Add(G.ID, G.Name);
getClient().Self.RequestJoinGroupChat(G.ID);
if (myConfig.GetPrefetchGroupMembers() == true)
{
getClient().Groups.RequestGroupMembers(G.ID);
}
if(myConfig.GetPrefetchGroupRoles() == true)
{
getClient().Groups.RequestGroupRoles(G.ID);
}
}
foreach(UUID G in missingGroups)
{
if (groupsKey2Name.ContainsKey(G) == false)
foreach (UUID G in missingGroups)
{
continue;
if (groupsKey2Name.ContainsKey(G) == false)
{
continue;
}
string name = groupsKey2Name[G];
groupsKey2Name.Remove(G);
closeChat(G);
}
string name = groupsKey2Name[G];
groupsKey2Name.Remove(G);
closeChat(G);
}
}
@ -777,11 +801,14 @@ namespace SecondBotEvents.Services
protected void addAvatar(UUID id, string name)
{
if (avatarsName2Key.ContainsValue(id) == true)
lock (avatarsName2Key)
{
return;
if (avatarsName2Key.ContainsValue(id) == true)
{
return;
}
avatarsName2Key.Add(name, id);
}
avatarsName2Key.Add(name, id);
}
protected void AvatarUUIDName(object o, UUIDNameReplyEventArgs e)
@ -878,14 +905,14 @@ namespace SecondBotEvents.Services
public class CommandHistory
{
public UUID Source = UUID.Zero;
public string Command = "";
public string[] Args = new string[] { };
public long Unixtime = 0;
public bool status = false;
public CommandHistory(UUID setSource, string setCommand, string[] setArgs, long setUnixtime)
public CommandHistory(bool setStatus, string setCommand, string[] setArgs, long setUnixtime)
{
Source = setSource;
status = setStatus;
Command = setCommand;
Args = setArgs;
Unixtime = setUnixtime;

View file

@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace SecondBotEvents.Services
{
public class DiscordService : Services
public class DiscordService : BotServices
{
public Config.DiscordConfig myConfig = null;
public bool acceptChat = false;

View file

@ -0,0 +1,308 @@
using OpenMetaverse;
using SecondBotEvents.Config;
using System;
namespace SecondBotEvents.Services
{
public class HomeboundService : BotServices
{
protected HomeboundConfig myConfig;
protected bool botConnected = false;
protected SimSlURL home = null;
protected SimSlURL backup = null;
protected UUID sitTarget = UUID.Zero;
protected long lastAlertTeleport = 0;
protected bool evacWanted = false;
protected bool gotoPosAttemptedTp = false;
protected bool gotoPosAttemptedWalk = false;
protected long lastGotoAction = 0;
protected bool softDisable = false;
protected bool closeToHome = false;
public void markTeleport()
{
softDisable = true;
}
public HomeboundService(EventsSecondBot setMaster) : base(setMaster)
{
myConfig = new HomeboundConfig(master.fromEnv, master.fromFolder);
if (myConfig.GetEnabled() == false)
{
return;
}
home = new SimSlURL(myConfig.GetHomeSimSlUrl());
backup = new SimSlURL(myConfig.GetBackupSimSLUrl());
if(UUID.TryParse(myConfig.GetAtHomeAutoSitUuid(), out sitTarget) == false)
{
sitTarget = UUID.Zero;
}
}
protected string simNickname = "";
protected bool attemptedTeleportHome = false;
protected bool attemptedTeleportBackup = false;
protected long teleportActionLockout = 0;
protected void Tick()
{
if (evacWanted == true)
{
BotAlertMessage(null, new AlertMessageEventArgs("restart", "999", new OpenMetaverse.StructuredData.OSDMap()));
}
if (getClient().Network.CurrentSim.Name == home.name)
{
simNickname = "Home # ";
if (sitTarget != UUID.Zero)
{
if (getClient().Self.SittingOn == 0)
{
getClient().Self.RequestSit(sitTarget, Vector3.Zero);
}
}
if (myConfig.GetAtHomeSeekLocation() == true)
{
GetToPos(home);
}
return;
}
else if (getClient().Network.CurrentSim.Name == backup.name)
{
simNickname = "Backup # ";
if (myConfig.GetAtBackupSeekLocation() == true)
{
GetToPos(backup);
}
return;
}
if (simNickname == "")
{
simNickname = "Someplace # ";
return;
}
long dif = SecondbotHelpers.UnixTimeNow() - teleportActionLockout;
if(dif < 30)
{
return;
}
teleportActionLockout = SecondbotHelpers.UnixTimeNow();
if (attemptedTeleportHome == false)
{
attemptedTeleportHome = true;
LogFormater.Info("Teleporting to home sim");
getClient().Self.Teleport(home.name, new Vector3(home.x, home.y, home.z), new Vector3(0, 0, 0));
return;
}
else if(attemptedTeleportBackup == false)
{
attemptedTeleportBackup = true;
LogFormater.Info("Teleporting to backup sim");
teleportActionLockout = SecondbotHelpers.UnixTimeNow();
getClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0));
return;
}
attemptedTeleportHome = false;
attemptedTeleportBackup = false;
LogFormater.Warn("Both home and backup sims failed clearing and trying again");
}
public override string Status()
{
if(myConfig == null)
{
return simNickname + "Config broken";
}
if(botConnected == false)
{
return simNickname + "No bot";
}
if(softDisable == false)
{
Tick();
if(evacWanted == true)
{
return simNickname + "Waiting to evac";
}
else if(getClient().Self.SittingOn != 0)
{
return simNickname + "Sitting on a thing";
}
else if(closeToHome == true)
{
return simNickname + "In a safe space";
}
else if(gotoPosAttemptedWalk == true)
{
return simNickname + "Trying to auto pilot";
}
else if(gotoPosAttemptedTp == true)
{
return simNickname + "Trying to TP to location";
}
return simNickname + "Waiting";
}
return simNickname + "Standby - teleported by master / script";
}
protected void GetToPos(SimSlURL location)
{
if (getClient().Self.SittingOn != 0)
{
return;
}
long dif = SecondbotHelpers.UnixTimeNow() - lastGotoAction;
if (dif < 30)
{
return;
}
lastGotoAction = SecondbotHelpers.UnixTimeNow();
float dist = Vector3.Distance(new Vector3(location.x, location.y, location.z), getClient().Self.SimPosition);
if(dist < 1)
{
closeToHome = true;
if (gotoPosAttemptedWalk == true)
{
getClient().Self.AutoPilotCancel();
}
gotoPosAttemptedWalk = false;
gotoPosAttemptedTp = false;
return;
}
if (gotoPosAttemptedTp == false)
{
gotoPosAttemptedTp = true;
getClient().Self.Teleport(location.name, new Vector3(location.x, location.y, location.z), new Vector3(0, 0, 0));
return;
}
if(gotoPosAttemptedWalk == false)
{
gotoPosAttemptedWalk = true;
getClient().Self.AutoPilotLocal(location.x, location.y, location.z);
return;
}
getClient().Self.AutoPilotCancel();
gotoPosAttemptedWalk = false;
}
protected void BotChangedSim(object o, SimChangedEventArgs e)
{
gotoPosAttemptedTp = false;
evacWanted = false;
gotoPosAttemptedWalk = false;
closeToHome = false;
simNickname = "";
attemptedTeleportHome = false;
attemptedTeleportBackup = false;
lastGotoAction = SecondbotHelpers.UnixTimeNow();
teleportActionLockout = SecondbotHelpers.UnixTimeNow() + 30;
}
protected void BotAlertMessage(object o, AlertMessageEventArgs e)
{
if (e.Message.ToLower().Contains("restart") == false)
{
return;
}
long dif = SecondbotHelpers.UnixTimeNow() - lastAlertTeleport;
if (dif < 60)
{
if (evacWanted == false)
{
LogFormater.Warn("Evac wanted due to restart");
evacWanted = true;
}
return;
}
evacWanted = false;
if (getClient().Network.CurrentSim.Name == home.name)
{
LogFormater.Info("Teleporting to backup sim to avoid restart");
getClient().Self.Teleport(backup.name, new Vector3(backup.x, backup.y, backup.z), new Vector3(0, 0, 0));
return;
}
LogFormater.Info("Teleporting to home sim to avoid restart");
getClient().Self.Teleport(home.name, new Vector3(home.x, home.y, home.z), new Vector3(0, 0, 0));
}
protected void BotClientRestart(object o, BotClientNotice e)
{
botConnected = false;
Console.WriteLine("Homebound Service [Attached to new client]");
getClient().Network.LoggedOut += BotLoggedOut;
getClient().Network.SimConnected += BotLoggedIn;
getClient().Self.AlertMessage += BotAlertMessage;
getClient().Network.SimChanged += BotChangedSim;
}
protected void BotLoggedOut(object o, LoggedOutEventArgs e)
{
lastAlertTeleport = 0;
evacWanted = false;
botConnected = false;
gotoPosAttemptedTp = false;
evacWanted = false;
gotoPosAttemptedWalk = false;
softDisable = false;
closeToHome = false;
lastGotoAction = SecondbotHelpers.UnixTimeNow();
Console.WriteLine("Homebound Service [Standby]");
}
protected void BotLoggedIn(object o, SimConnectedEventArgs e)
{
botConnected = true;
Console.WriteLine("Homebound Service [Active]");
}
public override void Start()
{
if(myConfig.GetEnabled() == false)
{
return;
}
Stop();
master.BotClientNoticeEvent += BotClientRestart;
Console.WriteLine("Homebound Service [Starting]");
}
public override void Stop()
{
master.BotClientNoticeEvent -= BotClientRestart;
if (master.botClient != null)
{
if (getClient() != null)
{
getClient().Network.SimConnected -= BotLoggedIn;
getClient().Self.AlertMessage -= BotAlertMessage;
getClient().Network.SimChanged -= BotChangedSim;
}
}
Console.WriteLine("Homebound Service [Stopping]");
}
}
public class SimSlURL
{
public string name;
public int x = 0;
public int y = 0;
public int z = 0;
public SimSlURL(string url)
{
// http://maps.secondlife.com/secondlife/Viserion/66/166/23
url = url.Replace("maps.secondlife.com/secondlife/", "");
url = url.Replace("http://", "");
url = url.Replace("https://", "");
// Viserion/66/166/23
string[] bits = url.Split("/");
name = System.Net.WebUtility.UrlDecode(bits[0]);
x = int.Parse(bits[1]);
y = int.Parse(bits[2]);
z = int.Parse(bits[3]);
}
}
}

View file

@ -1,18 +1,18 @@
using EmbedIO;
using EmbedIO.Actions;
using EmbedIO.Routing;
using EmbedIO.WebApi;
using Newtonsoft.Json;
using OpenMetaverse;
using SecondBotEvents.Commands;
using SecondBotEvents.Config;
using Swan.Logging;
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
namespace SecondBotEvents.Services
{
public class HttpService : Services
public class HttpService : BotServices
{
protected WebServer HTTPendpoint = null;
protected HttpConfig myConfig;
@ -27,26 +27,31 @@ namespace SecondBotEvents.Services
}
}
public bool GetAcceptBotCommands()
{
return acceptBotCommands;
}
public override string Status()
{
if (myConfig == null)
{
return "HTTP service [Config status broken]";
return "Config broken";
}
if (myConfig.GetEnabled() == false)
{
return "HTTP service [- Not requested -]";
return "- Not requested -";
}
// @todo HTTP server check here
if (HTTPendpoint == null)
{
return "HTTP endpoint not online";
return "not online";
}
if (acceptBotCommands == false)
{
return "Active [Service]";
return "Active ~ Service";
}
return "Active [Commands]";
return "Active ~ Commands";
}
protected void BotClientRestart(object o, BotClientNotice e)
@ -68,7 +73,7 @@ namespace SecondBotEvents.Services
{
getClient().Network.SimConnected -= BotLoggedIn;
acceptBotCommands = true;
Console.WriteLine("HTTP service [Bot commands enabled]");
CreateWebServer();
}
public override void Start()
@ -80,8 +85,6 @@ namespace SecondBotEvents.Services
}
Stop();
master.BotClientNoticeEvent += BotClientRestart;
Console.WriteLine("HTTP service [Enabled]");
CreateWebServer();
}
public override void Stop()
@ -103,12 +106,14 @@ namespace SecondBotEvents.Services
{
Swan.Logging.Logger.UnregisterLogger<ConsoleLogger>();
HTTPendpoint = new WebServer(o => o
.WithUrlPrefix(myConfig.GetHost())
.WithMode(HttpListenerMode.EmbedIO))
.WithUrlPrefix("http://*:" + myConfig.GetPort().ToString())
.WithMode(HttpListenerMode.EmbedIO))
.WithCors()
.WithWebApi("/api", m => m.WithController(() => new HttpWebBot(master)))
.WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Error" }))
);
HTTPendpoint.RunAsync();
Console.WriteLine("HTTP service [Enabled] on port "+ myConfig.GetPort().ToString());
}
}
@ -170,13 +175,13 @@ namespace SecondBotEvents.Services
protected object BasicReply(string input, string[] args, string command)
{
// @todo Command history storage system
master.DataStoreService.addCommandToHistory(true, command, args);
return new { reply = input, status = false };
}
protected object Failure(string input, string command, string[] args, string whyfailed)
{
// @todo Command history storage system
master.DataStoreService.addCommandToHistory(false, command, args);
return new { reply = input, status = false };
}
@ -240,4 +245,51 @@ namespace SecondBotEvents.Services
this.about = about;
}
}
public class SecondbotWebApi : WebApiController
{
protected EventsSecondBot master;
public SecondbotWebApi(EventsSecondBot setmaster)
{
master = setmaster;
}
}
public class HttpWebBot : SecondbotWebApi
{
public HttpWebBot(EventsSecondBot setmaster) : base(setmaster) { }
[About("Runs a command on the bot")]
[ReturnHints("command reply")]
[ReturnHintsFailure("Bad token signing")]
[ArgHints("commandName", "the name of the command to run")]
[ArgHints("args", "a list of args formated with ~#~ as the split points")]
[ArgHints("signing", "a sha1 hash that meets level 3 API signing spec [see github wiki]")]
[ArgHints("unixtime", "the time you signed the command")]
[Route(HttpVerbs.Post, "/Run")]
public string Run([FormField] string commandName, [FormField] string? args, [FormField] string signing, [FormField] string unixtime)
{
string input = commandName;
string[] myArgs = new string[] { };
if(args != null)
{
myArgs = args.Split("~#~", StringSplitOptions.RemoveEmptyEntries);
}
if(int.TryParse(unixtime, out int cmdUnixtime) == false)
{
return "Invaild unixtime was sent";
}
if (master.HttpService.GetAcceptBotCommands() == false)
{
return "No bot connected yet";
}
SignedCommand C = new SignedCommand(commandName, signing, myArgs, cmdUnixtime, null, true, 5, master.CommandsService.myConfig.GetSharedSecret());
if(C.accepted == false)
{
return "Command request rejected";
}
return JsonConvert.SerializeObject(master.CommandsService.runCommand(C));
}
}
}

View file

@ -8,7 +8,7 @@ using System.Collections.Generic;
namespace SecondBotEvents.Services
{
public class InteractionService : Services
public class InteractionService : BotServices
{
protected InteractionConfig myConfig;
protected bool botConnected = false;
@ -26,13 +26,17 @@ namespace SecondBotEvents.Services
{
if(myConfig == null)
{
return "Interaction Service [Config status broken]";
return "Config broken";
}
if (myConfig.GetEnabled() == false)
{
return "Interaction Service [- Not requested -]";
return "- Not requested -";
}
return "Interaction Service [Waiting for bot]";
if (botConnected == false)
{
return "Waiting for bot";
}
return "Active";
}
protected bool processRequest(bool enabledByConfig, string avatarName, string sourceName)
@ -90,12 +94,18 @@ namespace SecondBotEvents.Services
return;
}
string mode = "Teleport Bot to Av";
bool markTeleport = true;
if (e.IM.Dialog == InstantMessageDialog.RequestLure)
{
mode = "Teleport Av to Bot";
markTeleport = false;
}
if (processRequest(myConfig.GetAcceptTeleports(), e.IM.FromAgentName, mode) == false)
{
if(markTeleport == true)
{
master.HomeboundService.markTeleport();
}
if (e.IM.Dialog != InstantMessageDialog.RequestLure)
{
return;

View file

@ -5,10 +5,10 @@ using System.Text;
namespace SecondBotEvents.Services
{
public abstract class Services
public abstract class BotServices
{
public EventsSecondBot master;
public Services(EventsSecondBot setMaster)
public BotServices(EventsSecondBot setMaster)
{
master = setMaster;
}