chore(release): v1.5.11 - #62
Merged
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
Reviewer's GuideIntroduces a new cross-profile metrics system and a unified, timestamped event bus in GiveawayBot, wires them into core giveaway flows (entries, draws, lifecycle), replaces the old event/metrics implementations, and bumps the version and release metadata to v1.5.11 while tightening a version-updating script and fixing a config sync concurrency issue. Sequence diagram for entry handling with metrics and event bussequenceDiagram
actor Viewer
participant GiveawayManager
participant MetricsService as Metrics
participant CPHAdapter as CPH
participant EventBus as Bus
participant Messenger
Viewer->>GiveawayManager: HandleEntry(CPH, config, platform, userId, userName, tickets)
GiveawayManager->>CPH: Validate entry and state
CPH-->>GiveawayManager: Validation result
alt entry accepted
GiveawayManager->>Metrics: RecordEntry(profileName, userId, CPH)
Metrics->>CPH: GetGlobalVar EntriesTotal
CPH-->>Metrics: currentEntries
Metrics->>CPH: SetGlobalVar EntriesTotal + 1
Metrics->>CPH: GetGlobalVar profile entries
CPH-->>Metrics: profileEntries
Metrics->>CPH: SetGlobalVar profile entries + 1
Metrics->>CPH: GetUserVar user entries
CPH-->>Metrics: userEntries
Metrics->>CPH: SetUserVar user entries + 1
GiveawayManager->>Bus: Publish EntryAcceptedEvent(CPH, profileName, userId, userName, tickets)
Bus->>Messenger: Invoke OnEntryAccepted(evt)
Messenger->>CPH: Loc.Get EntryAccepted message
Messenger->>CPH: SendBroadcast acceptedMsg, profileName
opt toast enabled
Messenger->>CPH: ShowToastNotification New Entry userName
end
else entry rejected
GiveawayManager->>Bus: Publish EntryRejectedEvent(...)
Bus->>Messenger: Invoke OnEntryRejected(evt)
end
Sequence diagram for winner draw with metrics, event bus, and notificationssequenceDiagram
actor Moderator
participant GiveawayManager
participant MetricsService as Metrics
participant CPHAdapter as CPH
participant EventBus as Bus
participant Messenger
participant ObsController as Obs
Moderator->>GiveawayManager: HandleDraw(CPH, config, platform)
GiveawayManager->>CPH: Permission and state checks
CPH-->>GiveawayManager: Checks ok
GiveawayManager->>Metrics: RecordDraw(profileName, CPH)
Metrics->>CPH: GetGlobalVar DrawsTotal
CPH-->>Metrics: draws
Metrics->>CPH: SetGlobalVar DrawsTotal + 1
GiveawayManager->>GiveawayManager: Select winner
alt winner selected
GiveawayManager->>GiveawayManager: _cachedMetrics.WinnerDrawAttempts++
GiveawayManager->>GiveawayManager: _cachedMetrics.WinnerDrawSuccesses++
GiveawayManager->>Metrics: RecordWin(profileName, winnerId, CPH)
Metrics->>CPH: GetGlobalVar WinsTotal
CPH-->>Metrics: wins
Metrics->>CPH: SetGlobalVar WinsTotal + 1
Metrics->>CPH: GetGlobalVar profile wins
CPH-->>Metrics: profileWins
Metrics->>CPH: SetGlobalVar profile wins + 1
Metrics->>CPH: GetUserVar user wins
CPH-->>Metrics: userWins
Metrics->>CPH: SetUserVar user wins + 1
GiveawayManager->>Bus: Publish WinnerDrawnEvent(CPH, profileName, state, winnerName, winnerId)
Bus->>Messenger: Invoke OnWinnerDrawn(evt)
Messenger->>CPH: ShowToastNotification Giveaway Winner
Messenger->>CPH: SendBroadcast winner message, profileName
opt discord configured
Messenger->>CPH: SendDiscordMessage winnerName
end
else no entries
GiveawayManager->>CPH: Log no entries
end
opt wheel of names integration
GiveawayManager->>Bus: Publish WheelReadyEvent(CPH, profileName, state, wheelUrl, platform)
Bus->>Messenger: Invoke OnWheelReady(evt)
Messenger->>CPH: SendBroadcast Wheel Ready wheelUrl, platform
Bus->>Obs: Invoke OnWheelReady(evt)
Obs->>CPH: SetBrowserSource scene, source, wheelUrl
end
Class diagram for the new metrics systemclassDiagram
direction LR
class MetricsContainer {
+long EntriesTotal
+long WinsTotal
+long DrawsTotal
+Dictionary~string, ProfileMetrics~ Profiles
+Dictionary~string, long~ GlobalMetrics
+Dictionary~string, UserMetricSet~ UserMetrics
+DateTime LastUpdated
+int MessageIdCacheSize
+int MessageIdCleanupCount
+int LoopDetectedCount
+int LoopDetectedByMsgId
+int LoopDetectedByToken
+int LoopDetectedByBotFlag
+int ConfigReloadCount
+int FileIOErrors
+long TotalEntryProcessingMs
+int EntriesProcessedCount
+int WinnerDrawAttempts
+int WinnerDrawSuccesses
+long WheelApiTotalMs
+int WheelApiCalls
+int ApiErrors
+int WheelApiErrors
+int WheelApiInvalidKeys
+int WheelApiTimeouts
+int WheelApiNetworkErrors
+MetricsContainer()
+string ToJson()
+static MetricsContainer FromGlobalVars(CPHAdapter adapter)
}
class ProfileMetrics {
+string ProfileName
+long Entries
+long Wins
+long Draws
}
class UserMetrics {
+string UserId
+long EntriesTotal
+long WinsTotal
}
class UserMetricSet {
+Dictionary~string, long~ Metrics
}
class MetricsService {
-string _path
+MetricsService()
+MetricsContainer GetGlobalMetrics(CPHAdapter adapter)
+ProfileMetrics GetProfileMetrics(string profileName, CPHAdapter adapter)
+UserMetrics GetUserMetrics(string userId, CPHAdapter adapter)
+void RecordEntry(string profileName, string userId, CPHAdapter adapter)
+void RecordWin(string profileName, string userId, CPHAdapter adapter)
+void RecordDraw(string profileName, CPHAdapter adapter)
+void SaveMetrics(CPHAdapter adapter, MetricsContainer metrics)
+MetricsContainer LoadMetrics(CPHAdapter adapter)
}
class GiveawayManager {
+const string Version
+Dictionary~string, GiveawayState~ States
+MetricsService Metrics
+MetricsContainer _cachedMetrics
+void SyncAllVariables(CPHAdapter adapter)
+Task~bool~ HandleEntry(CPHAdapter adapter, GiveawayProfileConfig config, string platform, string userId, string userName, int tickets)
+Task~bool~ HandleDraw(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
+Task~bool~ HandleStart(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
+Task~bool~ HandleEnd(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
}
class CPHAdapter {
+T GetGlobalVar~T~(string name, bool persisted)
+void SetGlobalVar(string name, object value, bool persisted)
+T GetUserVar~T~(string userId, string name, bool persisted)
+void SetUserVar(string userId, string name, object value, bool persisted)
+void LogDebug(string message)
+void LogTrace(string message)
+void LogError(string message)
}
MetricsContainer "1" o-- "*" ProfileMetrics : profiles
MetricsContainer "1" o-- "*" UserMetricSet : userMetrics
MetricsService --> MetricsContainer : uses
MetricsService --> ProfileMetrics : returns
MetricsService --> UserMetrics : returns
MetricsContainer --> CPHAdapter : FromGlobalVars
MetricsService --> CPHAdapter : persistence
GiveawayManager "1" o-- "1" MetricsService : Metrics
GiveawayManager "1" o-- "1" MetricsContainer : cachedMetrics
Class diagram for the unified event bus and giveaway eventsclassDiagram
direction LR
class IEventBus {
<<interface>>
+void Subscribe~T~(Action~T~ handler)
+void Unsubscribe~T~(Action~T~ handler)
+void Publish~T~(T evt)
}
class IGiveawayEvent {
<<interface>>
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
}
class EventBus {
-Dictionary~Type, List~Delegate~~ _subscribers
-object _lock
+EventBus()
+void Subscribe~T~(Action~T~ handler)
+void Unsubscribe~T~(Action~T~ handler)
+void Publish~T~(T evt)
}
class GiveawayStartedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+GiveawayState State
+GiveawayStartedEvent(CPHAdapter adapter, string profileName, GiveawayState state)
}
class GiveawayEndedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+GiveawayState State
+GiveawayEndedEvent(CPHAdapter adapter, string profileName, GiveawayState state)
}
class WinnerDrawnEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+GiveawayState State
+string WinnerName
+string WinnerId
+WinnerDrawnEvent(CPHAdapter adapter, string profileName, GiveawayState state, string winnerName, string winnerId)
}
class WheelReadyEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+GiveawayState State
+string WheelUrl
+string Platform
+WheelReadyEvent(CPHAdapter adapter, string profileName, GiveawayState state, string wheelUrl, string platform)
}
class EntryAcceptedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string UserId
+string UserName
+int TicketCount
+EntryAcceptedEvent(CPHAdapter adapter, string profileName, string userId, string userName, int ticketCount)
}
class EntryRejectedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string UserId
+string UserName
+string Reason
+EntryRejectedEvent(CPHAdapter adapter, string profileName, string userId, string userName, string reason)
}
class ToastNotificationEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string Title
+string Message
+ToastNotificationEvent(CPHAdapter adapter, string profileName, string title, string message)
}
class ChatMessageEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string Message
+string Platform
+ChatMessageEvent(CPHAdapter adapter, string profileName, string message, string platform)
}
class ObsUpdateEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string Scene
+string Source
+string Url
+ObsUpdateEvent(CPHAdapter adapter, string profileName, string scene, string source, string url)
}
class MetricsUpdatedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+string MetricName
+long Value
+MetricsUpdatedEvent(CPHAdapter adapter, string profileName, string metricName, long value)
}
class ConfigReloadedEvent {
+CPHAdapter Adapter
+string ProfileName
+DateTime Timestamp
+ConfigReloadedEvent(CPHAdapter adapter, string profileName)
}
class GiveawayManager {
+IEventBus Bus
+void Initialize(CPHAdapter adapter)
+Task~bool~ HandleStart(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
+Task~bool~ HandleEnd(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
+Task~bool~ HandleEntry(CPHAdapter adapter, GiveawayProfileConfig config, string platform, string userId, string userName, int tickets)
+Task~bool~ HandleDraw(CPHAdapter adapter, GiveawayProfileConfig config, string platform)
}
class Messenger {
+MessengerConfig Config
+void Register(IEventBus bus)
-void OnWinnerDrawn(WinnerDrawnEvent evt)
-void OnWheelReady(WheelReadyEvent evt)
-void OnGiveawayStarted(GiveawayStartedEvent evt)
-void OnGiveawayEnded(GiveawayEndedEvent evt)
-void OnEntryAccepted(EntryAcceptedEvent evt)
}
class ObsController {
+void Register(IEventBus bus)
-void OnWheelReady(WheelReadyEvent evt)
}
IEventBus <|.. EventBus
IGiveawayEvent <|.. GiveawayStartedEvent
IGiveawayEvent <|.. GiveawayEndedEvent
IGiveawayEvent <|.. WinnerDrawnEvent
IGiveawayEvent <|.. WheelReadyEvent
IGiveawayEvent <|.. EntryAcceptedEvent
IGiveawayEvent <|.. EntryRejectedEvent
IGiveawayEvent <|.. ToastNotificationEvent
IGiveawayEvent <|.. ChatMessageEvent
IGiveawayEvent <|.. ObsUpdateEvent
IGiveawayEvent <|.. MetricsUpdatedEvent
IGiveawayEvent <|.. ConfigReloadedEvent
EventBus "1" o-- "*" IGiveawayEvent : publishes
GiveawayManager "1" o-- "1" IEventBus : Bus
Messenger ..> IEventBus : subscribes
ObsController ..> IEventBus : subscribes
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The new
UserMetricSet/MetricsServicedefinitions appear duplicated and partially inlined into theMetricsServiceclass (note the stray// ADD THESE METHODS TO MetricsService CLASScomment and_pathfield), which will likely cause type/brace/structure issues—please consolidate these into a single, clean definition in one region. - The refactor of
EntryAcceptedEvent/WinnerDrawnEventdrops theSource/platform and message/threading data and then reusesProfileNameas the broadcast target (e.g.,SendBroadcast(..., evt.ProfileName)), which changes behavior from the previous platform-aware implementation—consider explicitly carrying the platform and any needed message metadata in the new events instead of overloading profile name. - Files
TEST_STARTED.txtandtest_debug.loglook like temporary/debug artifacts and probably should not be committed; consider removing them from the repository.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `UserMetricSet`/`MetricsService` definitions appear duplicated and partially inlined into the `MetricsService` class (note the stray `// ADD THESE METHODS TO MetricsService CLASS` comment and `_path` field), which will likely cause type/brace/structure issues—please consolidate these into a single, clean definition in one region.
- The refactor of `EntryAcceptedEvent`/`WinnerDrawnEvent` drops the `Source`/platform and message/threading data and then reuses `ProfileName` as the broadcast target (e.g., `SendBroadcast(..., evt.ProfileName)`), which changes behavior from the previous platform-aware implementation—consider explicitly carrying the platform and any needed message metadata in the new events instead of overloading profile name.
- Files `TEST_STARTED.txt` and `test_debug.log` look like temporary/debug artifacts and probably should not be committed; consider removing them from the repository.
## Individual Comments
### Comment 1
<location> `GiveawayBot.cs:482-491` </location>
<code_context>
+ adapter.SetGlobalVar(profileKey, profileDraws + 1, true);
+ }
+
+ /// <summary>
+/// Legacy diagnostic metric set for a user (backward compatibility).
+/// </summary>
+public class UserMetricSet
+{
+ public Dictionary<string, long> Metrics { get; set; } = new Dictionary<string, long>();
</code_context>
<issue_to_address>
**issue (bug_risk):** UserMetricSet is now nested inside MetricsService but still referenced as a top-level type, which will not compile.
Earlier in the file, `MetricsContainer` exposes `Dictionary<string, UserMetricSet> UserMetrics`, assuming `UserMetricSet` is a top-level type. If `UserMetricSet` is nested inside `MetricsService`, it must be referenced as `MetricsService.UserMetricSet`, and it won’t be in scope at the `MetricsContainer` declaration. This will not compile. Either keep `UserMetricSet` as a top-level class or update all references (and type ordering) to use the nested type correctly.
</issue_to_address>
### Comment 2
<location> `GiveawayBot.cs:9050` </location>
<code_context>
if (!string.IsNullOrEmpty(msg))
{
- SendBroadcast(evt.Adapter, msg, evt.Source);
+ SendBroadcast(evt.Adapter, msg, evt.ProfileName);
}
</code_context>
<issue_to_address>
**issue (bug_risk):** Using ProfileName as the broadcast "platform" alters the semantics from the previous implementation and is likely incorrect.
In the old flow, `OnWinnerSelected` passed `evt.Source` (the platform/trigger) into `SendBroadcast`, but the refactor now passes `evt.ProfileName`. Unless `SendBroadcast` has been updated to treat this argument as a profile name, this risks misrouting broadcasts or breaking multi‑platform behavior. Please add a platform field to `WinnerDrawnEvent` (analogous to `Source`) and pass that through instead.
</issue_to_address>
### Comment 3
<location> `GiveawayBot.cs:9123` </location>
<code_context>
- // Reply directly to the user with platform-specific threading
- SendReply(evt.Adapter, acceptedMsg, evt.Source, evt.Entry.UserName, evt.MessageId);
+ // Broadcast confirmation
+ SendBroadcast(evt.Adapter, acceptedMsg, evt.ProfileName);
// Handle Toast notification
</code_context>
<issue_to_address>
**question (bug_risk):** EntryAccepted handling switched from a targeted reply to a profile-based broadcast and dropped platform information.
Previously, replying via `SendReply` used the platform and message ID to keep responses scoped and threaded; the new `SendBroadcast` call will send this to all listeners and loses that context. If this broader visibility isn’t explicitly desired, consider restoring `Platform` (and optionally `MessageId`) on `EntryAcceptedEvent` and continuing to call `SendReply`. If the broadcast is intentional, please double‑check that `ProfileName` is the correct third parameter for `SendBroadcast`, as this may not match its expected API.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Signed-off-by: Sythsaz <53737244+Sythsaz@users.noreply.github.com>
Signed-off-by: Sythsaz <53737244+Sythsaz@users.noreply.github.com>
…metrics persistence into `MetricsService`
…veaway-Bot into chore/release-v1.5.11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated release for v1.5.11.
Updates version files and changelog.
Summary by Sourcery
Introduce a cross-profile metrics system and a unified event bus, and bump the bot to version 1.5.11.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation: