allow limited service control via the command interface

This commit is contained in:
Madpeter 2024-07-22 20:19:48 +01:00
parent c789e53910
commit 9987d7fcb1
18 changed files with 184 additions and 11 deletions

View file

@ -36,6 +36,7 @@ ENV basic_Username='' \
commands_TimeWindowSecs=35 \ commands_TimeWindowSecs=35 \
commands_Enabled='true' \ commands_Enabled='true' \
commands_ObjectMasterOptout='false' \ commands_ObjectMasterOptout='false' \
commands_AllowServiceControl='false' \
datastore_AutoCleanAvatars='true' \ datastore_AutoCleanAvatars='true' \
datastore_AvatarsCleanAfterMins=10 \ datastore_AvatarsCleanAfterMins=10 \
datastore_LocalChatHistoryLimit=120 \ datastore_LocalChatHistoryLimit=120 \

View file

@ -0,0 +1,138 @@
using Newtonsoft.Json;
using OpenMetaverse;
using SecondBotEvents.Services;
using System.Collections.Generic;
using System.Linq;
namespace SecondBotEvents.Commands
{
[ClassInfo("Control services via commands (Requires the command enable service control flag be set to true)<br/><hr/> controlable services:<br/><hr/>" +
"BotClientService<br/>"+
"RLVService<br/>" +
"HttpService<br/>" +
"DiscordService<br/>" +
"InteractionService<br/>" +
"HomeboundService<br/>" +
"EventsService<br/>" +
"DialogService<br/>" +
"TriggerOnEventService" +
"RelayService")]
public class Services : CommandsAPI
{
public Services(EventsSecondBot setmaster) : base(setmaster)
{
}
protected List<string> controlable = new List<string> { "BotClientService","RLVService",
"HttpService",
"DiscordService",
"InteractionService",
"HomeboundService",
"EventsService",
"DialogService",
"TriggerOnEventService",
"RelayService"};
[About("Marks a service as enabled and starts it")]
[ReturnHints("ok")]
[ReturnHintsFailure("Unknown service")]
[ReturnHintsFailure("Unable to manage selected service")]
[ReturnHintsFailure("Service control is not enabled by config")]
public object EnableAndStartService(string servicename)
{
if(master.CommandsService.GetAllowServiceCommands() == false)
{
return Failure("Service control is not enabled by config");
}
if(controlable.Contains(servicename) == false)
{
return Failure("Unknown service");
}
BotServices service = master.GetService(servicename);
if (service == null)
{
return Failure("Unknown service");
}
service.enableAndStart();
return BasicReply("ok");
}
[About("stops a service if it is running")]
[ReturnHints("ok")]
[ReturnHintsFailure("Unknown service")]
[ReturnHintsFailure("Unable to manage selected service")]
[ReturnHintsFailure("Service control is not enabled by config")]
public object StopService(string servicename)
{
if (master.CommandsService.GetAllowServiceCommands() == false)
{
return Failure("Service control is not enabled by config");
}
if (controlable.Contains(servicename) == false)
{
return Failure("Unknown service");
}
BotServices service = master.GetService(servicename);
if (service == null)
{
return Failure("Unknown service");
}
service.Stop();
return BasicReply("ok");
}
[About("restarts a service if it is running")]
[ReturnHints("ok")]
[ReturnHintsFailure("Unknown service")]
[ReturnHintsFailure("Unable to manage selected service")]
[ReturnHintsFailure("Service control is not enabled by config")]
public object RestartService(string servicename)
{
if (master.CommandsService.GetAllowServiceCommands() == false)
{
return Failure("Service control is not enabled by config");
}
if (controlable.Contains(servicename) == false)
{
return Failure("Unknown service");
}
BotServices service = master.GetService(servicename);
if (service == null)
{
return Failure("Unknown service");
}
service.Restart();
return BasicReply("ok");
}
[About("Change or add a config value to a service")]
[ReturnHints("ok")]
[ReturnHintsFailure("Unknown service")]
[ReturnHintsFailure("Unable to manage selected service")]
[ReturnHintsFailure("Service control is not enabled by config")]
public object ChangeConfigValue(string servicename,string configname,string configvalue)
{
if (master.CommandsService.GetAllowServiceCommands() == false)
{
return Failure("Service control is not enabled by config");
}
if (controlable.Contains(servicename) == false)
{
return Failure("Unknown service");
}
BotServices service = master.GetService(servicename);
if (service == null)
{
return Failure("Unknown service");
}
service.changeConfig(configname, configvalue);
return BasicReply("ok");
}
}
}

View file

@ -20,9 +20,13 @@ namespace SecondBotEvents.Config
settings.Add("TimeWindowSecs"); settings.Add("TimeWindowSecs");
settings.Add("Enabled"); settings.Add("Enabled");
settings.Add("ObjectMasterOptout"); settings.Add("ObjectMasterOptout");
settings.Add("AllowServiceControl");
settings.Add("HideStatusOutput"); settings.Add("HideStatusOutput");
} }
public bool GetAllowServiceControl()
{
return ReadSettingAsBool("AllowServiceControl", false);
}
public bool GetEnabled() public bool GetEnabled()
{ {
return ReadSettingAsBool("Enabled", true); return ReadSettingAsBool("Enabled", true);

View file

@ -23,6 +23,16 @@ namespace SecondBotEvents.Config
MakeSettings(); MakeSettings();
LoadSettings(fromENV, fromFolder); LoadSettings(fromENV, fromFolder);
} }
public void updateKey(string key, string value)
{
if(mysettings.ContainsKey(key))
{
mysettings[key] = value;
return;
}
mysettings.Add(key, value);
}
public void setEnabled(bool enabled) public void setEnabled(bool enabled)
{ {
mysettings["Enabled"] = enabled.ToString(); mysettings["Enabled"] = enabled.ToString();

View file

@ -164,6 +164,7 @@ namespace SecondBotEvents
RegisterService("DialogService"); RegisterService("DialogService");
RegisterService("CustomCommandsService"); RegisterService("CustomCommandsService");
RegisterService("TriggerOnEventService"); RegisterService("TriggerOnEventService");
RegisterService("RelayService");
if (BotClient.IsLoaded() == false) if (BotClient.IsLoaded() == false)
{ {
LogFormater.Info("Config is not loaded :("); LogFormater.Info("Config is not loaded :(");

View file

@ -49,6 +49,11 @@ namespace SecondBotEvents.Services
LoadCommands(); LoadCommands();
} }
public bool GetAllowServiceCommands()
{
return myConfig.GetAllowServiceControl();
}
protected void LoadCommands() protected void LoadCommands()
{ {
Dictionary<string, Type> commandmodules = http_commands_helper.getCommandModules(); Dictionary<string, Type> commandmodules = http_commands_helper.getCommandModules();

View file

@ -11,7 +11,7 @@ namespace SecondBotEvents.Services
{ {
public class CustomCommandsService: BotServices public class CustomCommandsService: BotServices
{ {
protected CustomCommandsConfig myConfig; protected new CustomCommandsConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
protected Dictionary<string, CustomCommand> commands = new Dictionary<string, CustomCommand>(); protected Dictionary<string, CustomCommand> commands = new Dictionary<string, CustomCommand>();
public bool HasCommand(string C) public bool HasCommand(string C)

View file

@ -14,7 +14,7 @@ namespace SecondBotEvents.Services
{ {
public class DataStoreService : BotServices public class DataStoreService : BotServices
{ {
protected DataStoreConfig myConfig; protected new DataStoreConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
public DataStoreService(EventsSecondBot setMaster) : base(setMaster) public DataStoreService(EventsSecondBot setMaster) : base(setMaster)
{ {

View file

@ -17,7 +17,7 @@ namespace SecondBotEvents.Services
public class DialogService : BotServices public class DialogService : BotServices
{ {
protected bool botConnected = false; protected bool botConnected = false;
protected DialogRelayConfig myConfig; protected new DialogRelayConfig myConfig;
public DialogService(EventsSecondBot setMaster) : base(setMaster) public DialogService(EventsSecondBot setMaster) : base(setMaster)
{ {
myConfig = new DialogRelayConfig(master.fromEnv, master.fromFolder); myConfig = new DialogRelayConfig(master.fromEnv, master.fromFolder);

View file

@ -15,7 +15,7 @@ namespace SecondBotEvents.Services
{ {
public class DiscordService : BotServices public class DiscordService : BotServices
{ {
protected Config.DiscordConfig myConfig = null; protected new Config.DiscordConfig myConfig = null;
protected bool AcceptEventsFromSL = false; protected bool AcceptEventsFromSL = false;
protected bool DiscordIsReady = false; protected bool DiscordIsReady = false;
protected bool DiscordDisconnectExpected = false; protected bool DiscordDisconnectExpected = false;

View file

@ -13,7 +13,7 @@ namespace SecondBotEvents.Services
{ {
public class EventsService : BotServices public class EventsService : BotServices
{ {
protected EventsConfig myConfig; protected new EventsConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
protected string lastSimName = ""; protected string lastSimName = "";
protected UUID TrackGroupUUID = UUID.Zero; protected UUID TrackGroupUUID = UUID.Zero;

View file

@ -8,7 +8,7 @@ namespace SecondBotEvents.Services
{ {
public class HomeboundService : BotServices public class HomeboundService : BotServices
{ {
protected HomeboundConfig myConfig; protected new HomeboundConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;

View file

@ -20,7 +20,7 @@ namespace SecondBotEvents.Services
public class HttpService : BotServices public class HttpService : BotServices
{ {
protected WebServer HTTPendpoint = null; protected WebServer HTTPendpoint = null;
protected HttpConfig myConfig; protected new HttpConfig myConfig;
protected bool acceptBotCommands = false; protected bool acceptBotCommands = false;
public HttpService(EventsSecondBot setMaster) : base(setMaster) public HttpService(EventsSecondBot setMaster) : base(setMaster)
{ {

View file

@ -11,7 +11,7 @@ namespace SecondBotEvents.Services
{ {
public class InteractionService : BotServices public class InteractionService : BotServices
{ {
protected InteractionConfig myConfig; protected new InteractionConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
public InteractionService(EventsSecondBot setMaster) : base(setMaster) public InteractionService(EventsSecondBot setMaster) : base(setMaster)
{ {

View file

@ -16,7 +16,7 @@ namespace SecondBotEvents.Services
{ {
public class RelayService : BotServices public class RelayService : BotServices
{ {
protected RelayConfig myConfig; protected new RelayConfig myConfig;
protected bool botConnected = false; protected bool botConnected = false;
public RelayService(EventsSecondBot setMaster) : base(setMaster) public RelayService(EventsSecondBot setMaster) : base(setMaster)
{ {

View file

@ -2,18 +2,31 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using SecondBotEvents.Config;
namespace SecondBotEvents.Services namespace SecondBotEvents.Services
{ {
public abstract class BotServices public abstract class BotServices
{ {
public EventsSecondBot master; public EventsSecondBot master;
protected Config.Config myConfig;
protected bool running = false; protected bool running = false;
public BotServices(EventsSecondBot setMaster) public BotServices(EventsSecondBot setMaster)
{ {
master = setMaster; master = setMaster;
} }
public void enableAndStart()
{
myConfig.setEnabled(true);
Restart();
}
public void changeConfig(string configKey, string configValue)
{
myConfig.updateKey(configKey, configValue);
}
public bool isRunning() { return running; } public bool isRunning() { return running; }
public GridClient GetClient() public GridClient GetClient()

View file

@ -27,6 +27,7 @@ namespace SecondBotEvents
reply.Add("parcel", typeof(ParcelCommands)); reply.Add("parcel", typeof(ParcelCommands));
reply.Add("self", typeof(Self)); reply.Add("self", typeof(Self));
reply.Add("streamadmin", typeof(StreamAdmin)); reply.Add("streamadmin", typeof(StreamAdmin));
reply.Add("services", typeof(SecondBotEvents.Commands.Services));
return reply; return reply;
} }
} }

View file

@ -55,7 +55,7 @@ namespace SecondBotEvents
string card = "<div class=\"card mt-2 mx-2\" style=\"width: 18rem;\">" string card = "<div class=\"card mt-2 mx-2\" style=\"width: 18rem;\">"
+ "<div class=\"card-body\">" + "<div class=\"card-body\">"
+ "<h5 class=\"card-title\">" + namespaceworker.FirstCharToUpper() + "</h5>" + "<h5 class=\"card-title\">" + namespaceworker.FirstCharToUpper() + "</h5>"
+ "<p class=\"card-text\">" + about + "</p>" + "<p class=\"card-text\">" + about.Split("<br")[0] + "</p>"
+ "<a href = \"" + url + "\" class=\"btn btn-primary\">View " + commandcount.ToString() + " commands</a>" + "<a href = \"" + url + "\" class=\"btn btn-primary\">View " + commandcount.ToString() + " commands</a>"
+ "</div>" + "</div>"
+ "</div>"; + "</div>";