Skip to content

Commit 53e99a1

Browse files
committed
Stabilize and enhance some minor bits
This adds some improvements and changes to make the bot more stable. Some were mistakes I stumbled upon when doing some random testing. - Widgets now can be in an "unloaded" state. WidgetUserModule holds references to all IWidget instances that are assigned to given user, while IWidget provides two new abstracts that derivatives have to implement: OnLoad() and OnUnload(). This allows to allocate a widget and attempt a load, and when it fails keep the widget unloaded. Failures can happen for many different reasons, ex. widget can be created when module that produces its events is not yet enabled. - Widgets can be manually reloaded by using `widget reload` command. No ID added will reload all widgets assigned to current user. - EventSystem now throws dedicated Event/Dispatcher not found exceptions. This is for more clarity, as it used to return "key not present in dictionary" generic error. - Some parts of LukeBot now rely on https_domain prop instead of server_ip. This is to ensure IP is not visible in ex. OAuth callbacks (although it does not matter much, since anyone can DNS lookup the domain...)
1 parent b0186ed commit 53e99a1

26 files changed

+350
-108
lines changed

LukeBot.API/SpotifyToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public SpotifyToken(AuthFlow flow, string lbUser)
1313
"https://accounts.spotify.com/authorize",
1414
"https://accounts.spotify.com/api/token",
1515
"https://accounts.spotify.com/api/revoke",
16-
"http://" + Conf.Get<string>(Common.Constants.PROP_STORE_SERVER_IP_PROP) + "/callback/spotify"
16+
"http://" + Conf.Get<string>(Common.Constants.PROP_STORE_HTTPS_DOMAIN_PROP) + "/callback/spotify"
1717
)
1818
{
1919
}

LukeBot.API/TwitchToken.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public TwitchToken(AuthFlow flow, string lbUser)
1313
"https://id.twitch.tv/oauth2/authorize",
1414
"https://id.twitch.tv/oauth2/token",
1515
"https://id.twitch.tv/oauth2/revoke",
16-
"https://" + Conf.Get<string>(Common.Constants.PROP_STORE_SERVER_IP_PROP) + "/callback/twitch"
16+
"https://" + Conf.Get<string>(Common.Constants.PROP_STORE_HTTPS_DOMAIN_PROP) + "/callback/twitch"
1717
)
1818
{
1919
}

LukeBot.Common/Constants.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ public class Constants
2121
public static readonly Path PROP_STORE_USERS_PROP = Path.Form(LUKEBOT_USER_ID, PROP_STORE_USERS_PROP_NAME);
2222
public static readonly Path PROP_STORE_RECONNECT_COUNT_PROP = Path.Form(LUKEBOT_USER_ID, PROP_STORE_RECONNECT_COUNT_PROP_NAME);
2323

24-
public const string DEFAULT_SERVER_IP = "localhost:5000";
24+
public const string DEFAULT_SERVER_IP = "127.0.0.1";
25+
public const string DEFAULT_SERVER_HTTPS_DOMAIN = "localhost";
2526
public const string PROPERTY_STORE_FILE = "Data/props.lukebot";
2627
public const string DEFAULT_LOGIN_NAME = "SET_BOT_LOGIN_HERE";
2728
public const string DEFAULT_CLIENT_ID_NAME = "SET_YOUR_CLIENT_ID_HERE";
2829
public const string DEFAULT_CLIENT_SECRET_NAME = "SET_YOUR_CLIENT_SECRET_HERE";
2930

31+
public const int SERVERCLI_DEFAULT_PORT = 55268; // in T9: LKBOT
32+
3033
public const string SPOTIFY_MODULE_NAME = "spotify";
3134
public const string TWITCH_MODULE_NAME = "twitch";
3235
public const string WIDGET_MODULE_NAME = "widget";

LukeBot.Common/Utils.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.Net;
5+
using System.Net.Sockets;
56
using System.Runtime.InteropServices;
67

78

LukeBot.Communication/EventSystem.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ internal EventCollection(string lbUser)
7171
*/
7272
public Event Event(string name)
7373
{
74+
if (!mEvents.ContainsKey(name))
75+
throw new EventNotFoundException(name);
76+
7477
return mEvents[name];
7578
}
7679

@@ -139,6 +142,8 @@ public List<EventCallback> RegisterPublisher(IEventPublisher p)
139142
{
140143
string pubName = p.GetName();
141144

145+
Logger.Log().Debug("Registering publisher {0}", pubName);
146+
142147
if (mPublishers.ContainsKey(pubName))
143148
throw new PublisherAlreadyRegisteredException(pubName);
144149

@@ -170,6 +175,8 @@ public void UnregisterPublisher(IEventPublisher p)
170175
{
171176
string pubName = p.GetName();
172177

178+
Logger.Log().Debug("Unregistering publisher {0}", pubName);
179+
173180
if (!mPublishers.ContainsKey(pubName))
174181
return;
175182

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using LukeBot.Communication.Common;
2+
3+
4+
namespace LukeBot.Communication
5+
{
6+
public class DispatcherNotFoundException: LukeBot.Common.Exception
7+
{
8+
public DispatcherNotFoundException(string dispatcherName)
9+
: base(string.Format("Not found dispatcher: {0}", dispatcherName))
10+
{}
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using LukeBot.Communication.Common;
2+
3+
4+
namespace LukeBot.Communication
5+
{
6+
public class EventNotFoundException: LukeBot.Common.Exception
7+
{
8+
public EventNotFoundException(string eventName)
9+
: base(string.Format("Not found event: {0}", eventName))
10+
{}
11+
}
12+
}

LukeBot.Endpoint/Endpoint.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,32 +61,37 @@ public IWebHostBuilder CreateHostBuilder()
6161
logging.AddProvider(new LBLoggingProvider());
6262
});
6363

64-
string IP = Conf.Get<string>(Common.Constants.PROP_STORE_SERVER_IP_PROP);
64+
string domain;
6565
string[] URLs;
6666

67-
if (IP.Contains("localhost"))
67+
if (!Conf.TryGet<string>(Common.Constants.PROP_STORE_HTTPS_DOMAIN_PROP, out domain))
68+
{
69+
domain = "localhost";
70+
}
71+
72+
if (domain.Contains("localhost"))
6873
{
6974
// manually set only localhost
7075
// we do this path just in case someone prefers to use different-than-default port 5000
7176
URLs = new string[]
7277
{
73-
"https://" + IP + "/",
78+
"https://" + domain + "/",
7479
};
7580
}
7681
else
7782
{
7883
// add defined address + localhost:5000
7984
URLs = new string[]
8085
{
81-
"https://" + IP + "/",
86+
"https://" + domain + "/",
8287
"https://localhost:5000/"
8388
};
8489
}
8590

86-
Logger.Log().Debug("Endpoint using host addresses:");
91+
Logger.Log().Info("Endpoint using host addresses:");
8792
foreach (string addr in URLs)
8893
{
89-
Logger.Log().Debug(" - https://" + IP + "/");
94+
Logger.Log().Info(" - https://" + addr + "/");
9095
}
9196

9297
builder.UseUrls(URLs);

LukeBot.Module/IUserModule.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
public interface IUserModule
44
{
55
public void Run();
6-
public void RequestShutdown();
7-
public void WaitForShutdown();
6+
public void RequestShutdown(); // TODO replace with single call Shutdown()
7+
public void WaitForShutdown(); // TODO ^
88
public ModuleType GetModuleType();
99
}
1010
}

LukeBot.Twitch/IRCChannel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace LukeBot.Twitch
1313
{
14-
class IRCChannel: IEventPublisher
14+
class IRCChannel: IEventPublisher, IDisposable
1515
{
1616
private string mLBUser;
1717
private string mChannelName;
@@ -109,6 +109,11 @@ public List<EventDescriptor> GetEvents()
109109
return events;
110110
}
111111

112+
public void Dispose()
113+
{
114+
Comms.Event.User(mLBUser).UnregisterPublisher(this);
115+
}
116+
112117
public IRCChannel(string lbUser, API.Twitch.GetUserData userData, Token userToken, BadgeCollection globalBadges)
113118
{
114119
mLBUser = lbUser;

LukeBot.Twitch/TwitchIRC.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,6 @@ public TwitchIRC(string username, Token token)
355355
Logger.Log().Info("Twitch IRC module initialized");
356356
}
357357

358-
~TwitchIRC()
359-
{
360-
Disconnect();
361-
WaitForShutdown();
362-
}
363-
364358
public void JoinChannel(string lbUser, API.Twitch.GetUserData user, Token token)
365359
{
366360
mChannelsMutex.WaitOne();
@@ -390,6 +384,7 @@ public void PartChannel(API.Twitch.GetUserData user)
390384

391385
mIRCClient.Send(IRCMessage.PART(user.login));
392386

387+
mChannels[user.login].Dispose();
393388
mChannels.Remove(user.login);
394389

395390
mChannelsMutex.ReleaseMutex();

LukeBot.Widget/Alerts.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,7 @@ protected override void OnConfigurationUpdate()
148148
AwaitEventCompletion();
149149
}
150150

151-
public Alerts(string lbUser, string id, string name)
152-
: base(lbUser, "LukeBot.Widget/Widgets/Alerts.html", id, name, new AlertWidgetConfig())
151+
protected override void OnLoad()
153152
{
154153
EventCollection collection = Comms.Event.User(mLBUser);
155154

@@ -163,6 +162,25 @@ public Alerts(string lbUser, string id, string name)
163162
collection.Event(Events.TWITCH_SUBSCRIPTION).InterruptEndpoint += OnEventInterrupt;
164163
}
165164

165+
protected override void OnUnload()
166+
{
167+
EventCollection collection = Comms.Event.User(mLBUser);
168+
169+
collection.Event(Events.TWITCH_CHANNEL_POINTS_REDEMPTION).Endpoint -= OnSimpleEvent<TwitchChannelPointsRedemptionArgs>;
170+
collection.Event(Events.TWITCH_CHANNEL_POINTS_REDEMPTION).InterruptEndpoint -= OnEventInterrupt;
171+
172+
collection.Event(Events.TWITCH_CHEER).Endpoint -= OnSimpleEvent<TwitchCheerArgs>;
173+
collection.Event(Events.TWITCH_CHEER).InterruptEndpoint -= OnEventInterrupt;
174+
175+
collection.Event(Events.TWITCH_SUBSCRIPTION).Endpoint -= OnSubscriptionEvent;
176+
collection.Event(Events.TWITCH_SUBSCRIPTION).InterruptEndpoint -= OnEventInterrupt;
177+
}
178+
179+
public Alerts(string lbUser, string id, string name)
180+
: base(lbUser, "LukeBot.Widget/Widgets/Alerts.html", id, name, new AlertWidgetConfig())
181+
{
182+
}
183+
166184
public override WidgetType GetWidgetType()
167185
{
168186
return WidgetType.alerts;

LukeBot.Widget/Chat.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,25 @@ protected override void OnConnected()
3636
// noop
3737
}
3838

39-
public Chat(string lbUser, string id, string name)
40-
: base(lbUser, "LukeBot.Widget/Widgets/Chat.html", id, name)
39+
protected override void OnLoad()
4140
{
4241
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_MESSAGE).Endpoint += OnMessage;
4342
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_CLEAR_USER).Endpoint += OnClearChat;
4443
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_CLEAR_MESSAGE).Endpoint += OnClearMsg;
4544
}
4645

46+
protected override void OnUnload()
47+
{
48+
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_MESSAGE).Endpoint -= OnMessage;
49+
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_CLEAR_USER).Endpoint -= OnClearChat;
50+
Comms.Event.User(mLBUser).Event(Events.TWITCH_CHAT_CLEAR_MESSAGE).Endpoint -= OnClearMsg;
51+
}
52+
53+
public Chat(string lbUser, string id, string name)
54+
: base(lbUser, "LukeBot.Widget/Widgets/Chat.html", id, name)
55+
{
56+
}
57+
4758
public override WidgetType GetWidgetType()
4859
{
4960
return WidgetType.chat;

LukeBot.Widget/Echo.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ protected override void OnConnected()
6666
}
6767
}
6868

69+
protected override void OnLoad()
70+
{
71+
}
72+
73+
protected override void OnUnload()
74+
{
75+
}
76+
6977
public Echo(string lbUser, string id, string name)
7078
: base(lbUser, "LukeBot.Widget/Widgets/Echo.html", id, name)
7179
{

LukeBot.Widget/IWidget.cs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public WebSocketRecv(WebSocketReceiveResult result, string data)
3636

3737
public string ID { get; private set; }
3838
public string Name { get; private set; }
39+
public bool Loaded { get; private set; }
3940
public string mWidgetFilePath;
4041
protected string mLBUser;
4142
private List<string> mHead;
@@ -50,6 +51,8 @@ public WebSocketRecv(WebSocketReceiveResult result, string data)
5051
private Config.Path mConfigurationPath;
5152

5253
protected bool Connected { get { return mWS != null && mWS.State == WebSocketState.Open; } }
54+
protected abstract void OnLoad(); // called when widget is loaded. Can throw, which will leave widget in unloaded state.
55+
protected abstract void OnUnload(); // called when widget is loaded. Can throw, which will leave widget in unloaded state.
5356
protected abstract void OnConnected();
5457
protected virtual void OnConfigurationUpdate() {}
5558

@@ -67,13 +70,13 @@ private string GetWidgetCode()
6770

6871
internal string GetWidgetAddress()
6972
{
70-
string serverAddress = Conf.Get<string>(LukeBot.Common.Constants.PROP_STORE_SERVER_IP_PROP);
73+
string serverAddress = Conf.Get<string>(LukeBot.Common.Constants.PROP_STORE_HTTPS_DOMAIN_PROP);
7174
return "https://" + serverAddress + "/widget/" + ID;
7275
}
7376

7477
private string GetWidgetWSAddress()
7578
{
76-
string serverAddress = Conf.Get<string>(LukeBot.Common.Constants.PROP_STORE_SERVER_IP_PROP);
79+
string serverAddress = Conf.Get<string>(LukeBot.Common.Constants.PROP_STORE_HTTPS_DOMAIN_PROP);
7780
return "wss://" + serverAddress + "/widgetws/" + ID;
7881
}
7982

@@ -237,6 +240,7 @@ public IWidget(string lbUser, string widgetFilePath, string id, string name, Wid
237240

238241
ID = id;
239242
Name = name;
243+
Loaded = false;
240244
mLBUser = lbUser;
241245
mHead = new List<string>();
242246
mWS = null;
@@ -251,14 +255,40 @@ public IWidget(string lbUser, string widgetFilePath, string id, string name, Wid
251255
.Push(ID)
252256
.Push(Constants.PROP_CONFIG);
253257
mConfiguration = config;
254-
LoadConfiguration();
255258
}
256259

257260
public IWidget(string lbUser, string widgetFilePath, string id, string name)
258261
: this(lbUser, widgetFilePath, id, name, new EmptyWidgetConfiguration())
259262
{
260263
}
261264

265+
public void Load()
266+
{
267+
if (Loaded)
268+
return;
269+
270+
LoadConfiguration();
271+
OnLoad();
272+
Loaded = true;
273+
}
274+
275+
public void Unload()
276+
{
277+
if (!Loaded)
278+
return;
279+
280+
mWSThreadDone = true;
281+
CloseWS(WebSocketCloseStatus.NormalClosure);
282+
283+
if (mWSMessagingThread != null)
284+
mWSMessagingThread.Join();
285+
286+
SaveConfiguration();
287+
288+
OnUnload();
289+
Loaded = false;
290+
}
291+
262292
public string GetPage()
263293
{
264294
string page = "<!DOCTYPE html><html><head>";
@@ -314,19 +344,5 @@ public WidgetDesc GetDesc()
314344
}
315345

316346
public abstract WidgetType GetWidgetType();
317-
318-
public virtual void RequestShutdown()
319-
{
320-
mWSThreadDone = true;
321-
CloseWS(WebSocketCloseStatus.NormalClosure);
322-
}
323-
324-
public virtual void WaitForShutdown()
325-
{
326-
if (mWSMessagingThread != null)
327-
mWSMessagingThread.Join();
328-
329-
SaveConfiguration();
330-
}
331347
}
332348
}

0 commit comments

Comments
 (0)