Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
d9d218c
modern `program.cs` (top-level statements)
AoshiW Apr 11, 2024
f0f4e51
Channel VIP Events
Hampo Apr 15, 2024
7c7ebdf
Casing corrections
Hampo Apr 17, 2024
307c7dd
More casing corrections
Hampo Apr 17, 2024
d09b926
Deleting duplicate directory
Hampo Apr 17, 2024
01792f9
Update README.md
AoshiW Apr 17, 2024
c5a0a14
Merge pull request #26 from Hampo/dev
swiftyspiffy Apr 22, 2024
f21c26a
fix build error
AoshiW Apr 22, 2024
fed1002
Merge pull request #28 from AoshiW/fix-build-error
swiftyspiffy Apr 22, 2024
62c1aa4
Merge pull request #25 from AoshiW/modern-program.cs
swiftyspiffy May 3, 2024
2a42632
Merge pull request #27 from AoshiW/update-readme
swiftyspiffy May 3, 2024
400b11c
add ty/catch block in `RaiseEvent`
AoshiW May 10, 2024
7b34981
feat: ChannelSuspiciousUserMessage, ChannelSuspiciousUserUpdate
swiftyspiffy May 12, 2024
e734699
Change reference to latest to core package
Mahsaap May 16, 2024
bcfc70a
Merge pull request #33 from TwitchLib/Mahsaap-patch-1
swiftyspiffy May 20, 2024
673019f
Bringing The ChannelPoint Automatic Reward Redemption to Websocket in…
djinnet May 20, 2024
6d062be
Add handler and add the missing newline
djinnet May 20, 2024
bdf3943
Update the summary in ChannelPointsAutomaticRewardRedemptionAddHandle…
djinnet May 20, 2024
5158299
feat: ChannelSuspiciousUserMessage, ChannelSuspiciousUserUpdate
Mahsaap Jun 12, 2024
941cab0
update core version
Mahsaap Jun 12, 2024
ff1356d
Fix build error
Mahsaap Jun 12, 2024
84aeaa0
fix reconnect issues #37
AoshiW Jun 17, 2024
bcc5801
Merge pull request #38 from AoshiW/reconnect-issue
Mahsaap Jun 17, 2024
10a6910
Merge pull request #30 from AoshiW/catch-exception
Mahsaap Jun 17, 2024
abba5e7
Merge pull request #34 from djinnet/ChannelPointAutomaticRewards
Mahsaap Jun 25, 2024
7fa6c6b
Updated dependency System.Text.Json for vulnerability
Psychoboy Jul 25, 2024
ffc3181
Merge pull request #41 from Psychoboy/dev
Mahsaap Jul 31, 2024
9231e00
add `Whisper Received`
AoshiW Sep 7, 2024
036ab23
Update to latest dev core commit.
Mahsaap Nov 5, 2024
fe1656a
Merge pull request #45 from TwitchLib/Mahsaap-update-core-d80beed
Mahsaap Nov 5, 2024
59ea2c9
Update to 0.6.0
Mahsaap Nov 5, 2024
b24c685
Update preview-release action to use newer actions
Syzuna Nov 5, 2024
cde682a
Update preview-release.yml
Syzuna Nov 5, 2024
59d6a73
Merge branch 'dev' into WhisperReceived
AoshiW Nov 5, 2024
8942f6c
Update `TwitchLib.EventSub.Core`
AoshiW Nov 5, 2024
129f195
Merge pull request #43 from AoshiW/WhisperReceived
Mahsaap Nov 5, 2024
e78808b
Add `Channel Warning` related handlers
Hampo Nov 5, 2024
dbc970c
Merge pull request #46 from Hampo/dev
Mahsaap Nov 6, 2024
03dbc64
Updates System.Text.Json
PhoenixICE Nov 16, 2024
2416495
Merge pull request #1 from PhoenixICE/hotfix/update-system.text.json-…
PhoenixICE Nov 16, 2024
6f4cd77
Merge pull request #49 from PhoenixICE/dev
Syzuna Nov 16, 2024
3a46616
Add support for channel.chat.message_delete
MrLawbreaker Nov 21, 2024
80caf60
Add Chat Notificiation and Shared Chat handlers
iryis Dec 10, 2024
4adde38
Add channel unban request events
Bregann Feb 22, 2025
c3c2f75
Remove chat notification (see 51)
iryis Feb 26, 2025
e9f84e7
Add support for channel.chat.notification
MrLawbreaker Nov 21, 2024
3c5fac1
Merge pull request #51 from MrLawbreaker/dev
AoshiW May 14, 2025
7f9f259
[skip-ci] Update `TwitchLib.EventSub.Core`
AoshiW May 14, 2025
532b5cd
Merge pull request #52 from iryis/dev
AoshiW May 14, 2025
8dbcfb5
Merge pull request #54 from Bregann/dev
AoshiW May 14, 2025
c160d95
added `channel.chat.clear` and `channel.chat.clear_user_messages`, mo…
AoshiW May 14, 2025
f14064f
Merge pull request #57 from AoshiW/chat-clear-(user-messages)
AoshiW May 20, 2025
279d4e8
added some XML doc, nullabe->enable
AoshiW May 20, 2025
9e27637
Merge pull request #58 from AoshiW/dev
AoshiW May 22, 2025
a22465b
rewrite ProcessDataAsync, replace DataReceivedArgs.Message(string) wi…
AoshiW May 27, 2025
911f608
[spik-ci] updated readme to v0.6 & PackageReleaseNotes
AoshiW May 30, 2025
534d542
added github.run_number to preview-release.ym
AoshiW May 30, 2025
1c2d411
Merge branch 'main' into dev
AoshiW May 30, 2025
181ed86
[skip-ci] fix build errors in expample projects
AoshiW May 30, 2025
3b6a29d
[skip-ci] fix preview-release.yml
AoshiW May 30, 2025
3e5313f
Merge pull request #59 from AoshiW/rewrite-ProcessDataAsync
AoshiW May 31, 2025
4401bf1
update TwitchLib.EventSub.Core to v2.6
AoshiW Jun 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/preview-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

steps:
- uses: actions/checkout@v4
- uses: benjlevesque/short-sha@v2.2
- uses: benjlevesque/short-sha@v3.0
id: short-sha
- name: Setup .NET
uses: actions/setup-dotnet@v3
Expand All @@ -22,6 +22,6 @@ jobs:
- name: Build TwitchLib.EventSub.Websockets
run: dotnet build -c Release --no-restore
- name: Pack TwitchLib.EventSub.Websockets
run: dotnet pack ./TwitchLib.EventSub.Websockets/TwitchLib.EventSub.Websockets.csproj -v normal -c Release -o nugets --no-build --version-suffix "preview-${{ steps.short-sha.outputs.sha }}"
run: dotnet pack ./TwitchLib.EventSub.Websockets/TwitchLib.EventSub.Websockets.csproj -v normal -c Release -o nugets --no-build --version-suffix "preview.${{ github.run_number }}.${{ steps.short-sha.outputs.sha }}"
- name: Push to Nuget
run: dotnet nuget push "./nugets/*.nupkg" -k ${{ secrets.API_NUGET_TOKEN }} -s https://api.nuget.org/v3/index.json
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ You can also find a console app example for .NET 8 and for .NET Framework 4.8 in

| NuGet | | [![TwitchLib.EventSub.Websockets][1]][2] |
| :--------------- | ----: | :--------------------------------------------------------------------------- |
| Package Manager | `PM>` | `Install-Package TwitchLib.EventSub.Websockets -Version 0.5.0` |
| .NET CLI | `>` | `dotnet add package TwitchLib.EventSub.Websockets --version 0.5.0` |
| PackageReference | | `<PackageReference Include="TwitchLib.EventSub.Websockets" Version="0.5.0" />` |
| Paket CLI | `>` | `paket add TwitchLib.EventSub.Websockets --version 0.5.0` |
| Package Manager | `PM>` | `Install-Package TwitchLib.EventSub.Websockets -Version 0.6.0` |
| .NET CLI | `>` | `dotnet add package TwitchLib.EventSub.Websockets --version 0.6.0` |
| PackageReference | | `<PackageReference Include="TwitchLib.EventSub.Websockets" Version="0.6.0" />` |
| Paket CLI | `>` | `paket add TwitchLib.EventSub.Websockets --version 0.6.0` |

[1]: https://img.shields.io/nuget/v/TwitchLib.EventSub.Websockets.svg?label=TwitchLib.EventSub.Websockets
[2]: https://www.nuget.org/packages/TwitchLib.EventSub.Websockets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
<TargetFramework>netframework4.8</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="TwitchLib.Api" Version="3.10.0-preview-4e0146c" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Threading;
using System.Threading.Tasks;
using TwitchLib.Api;
using TwitchLib.Api.Core.Enums;
using TwitchLib.EventSub.Websockets.Core.EventArgs;
using TwitchLib.EventSub.Websockets.Core.EventArgs.Channel;

Expand All @@ -16,7 +15,7 @@ public class WebsocketHostedService : IHostedService
private readonly IConfiguration _configuration;
private readonly ILogger<WebsocketHostedService> _logger;
private readonly EventSubWebsocketClient _eventSubWebsocketClient;
private readonly TwitchApi _twitchApi = new();
private readonly TwitchAPI _twitchApi = new();
private string _userId;

public WebsocketHostedService(IConfiguration configuration ,ILogger<WebsocketHostedService> logger, EventSubWebsocketClient eventSubWebsocketClient)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using TwitchLib.Api;
using TwitchLib.EventSub.Websockets.Core.EventArgs;
using TwitchLib.EventSub.Websockets.Core.EventArgs.Channel;

Expand All @@ -12,7 +13,7 @@ public class WebsocketHostedServiceWithoutDI : IHostedService
{
private readonly ILogger<WebsocketHostedService> _logger;
private readonly EventSubWebsocketClient _eventSubWebsocketClient;
private readonly TwitchApi _twitchApi = new();
private readonly TwitchAPI _twitchApi = new();
private string _userId;

public WebsocketHostedServiceWithoutDI(ILogger<WebsocketHostedService> logger, ILoggerFactory loggerFactory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="TwitchLib.Api" Version="3.10.0-preview-4e0146c" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class WebsocketHostedService : IHostedService
{
private readonly ILogger<WebsocketHostedService> _logger;
private readonly EventSubWebsocketClient _eventSubWebsocketClient;
private readonly TwitchApi _twitchApi = new();
private readonly TwitchAPI _twitchApi = new();
private string _userId;

public WebsocketHostedService(ILogger<WebsocketHostedService> logger, EventSubWebsocketClient eventSubWebsocketClient)
Expand Down
132 changes: 31 additions & 101 deletions TwitchLib.EventSub.Websockets/Client/WebsocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ public class WebsocketClient : IDisposable
/// </summary>
public bool IsFaulted => _webSocket.CloseStatus != WebSocketCloseStatus.Empty && _webSocket.CloseStatus != WebSocketCloseStatus.NormalClosure;

internal event AsyncEventHandler<DataReceivedArgs> OnDataReceived;
internal event AsyncEventHandler<ErrorOccuredArgs> OnErrorOccurred;
internal event AsyncEventHandler<DataReceivedArgs>? OnDataReceived;
internal event AsyncEventHandler<ErrorOccuredArgs>? OnErrorOccurred;

private readonly ClientWebSocket _webSocket;
private readonly ILogger<WebsocketClient> _logger;
private ClientWebSocket _webSocket;
private readonly ILogger<WebsocketClient>? _logger;

/// <summary>
/// Constructor to create a new Websocket client with a logger
/// </summary>
/// <param name="logger">Logger used by the websocket client to print various state info</param>
public WebsocketClient(ILogger<WebsocketClient> logger = null)
public WebsocketClient(ILogger<WebsocketClient>? logger = null)
{
_webSocket = new ClientWebSocket();
_logger = logger;
Expand All @@ -56,6 +56,8 @@ public async Task<bool> ConnectAsync(Uri url)
{
if (_webSocket.State is WebSocketState.Open or WebSocketState.Connecting)
return true;
if (_webSocket.State is WebSocketState.Closed) //after a socken is closed it cannot be reopened
_webSocket = new();

await _webSocket.ConnectAsync(url, CancellationToken.None);

Expand Down Expand Up @@ -92,66 +94,63 @@ public async Task<bool> DisconnectAsync()
}
}

#if NET6_0_OR_GREATER
/// <summary>
/// Background operation to process incoming data via the websocket
/// </summary>
/// <returns>Task representing the background operation</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
private async Task ProcessDataAsync()
{
const int minimumBufferSize = 256;
var storeSize = 4096;
var decoder = Encoding.UTF8.GetDecoder();

var store = MemoryPool<byte>.Shared.Rent(storeSize).Memory;
var buffer = MemoryPool<byte>.Shared.Rent(minimumBufferSize).Memory;

const int bufferLength = 4096;
#if NETSTANDARD2_0
var buffer = new ArraySegment<byte>(new byte[bufferLength]);
#else
var buffer = new Memory<byte>(new byte[bufferLength]);
#endif
var store = new byte[4096];
var payloadSize = 0;

while (IsConnected)
{
try
{
#if NETSTANDARD2_0
WebSocketReceiveResult receiveResult;
#else
ValueWebSocketReceiveResult receiveResult;
#endif
do
{
receiveResult = await _webSocket.ReceiveAsync(buffer, CancellationToken.None);
if (payloadSize + receiveResult.Count >= storeSize)

if (payloadSize + receiveResult.Count >= store.Length)
{
storeSize +=
#if NET8_0_OR_GREATER
int.Max(4096, receiveResult.Count);
#else
Math.Max(4096, receiveResult.Count);
#endif
var newStore = MemoryPool<byte>.Shared.Rent(storeSize).Memory;
store.CopyTo(newStore);
var newStoreLength = store.Length + Math.Max(bufferLength, receiveResult.Count);
var newStore = new byte[newStoreLength];
store.AsSpan().CopyTo(newStore);
store = newStore;
}

buffer.CopyTo(store[payloadSize..]);
buffer
#if NETSTANDARD2_0
.Array.AsSpan(0, receiveResult.Count)
#else
.Span.Slice(0, receiveResult.Count)
#endif
.CopyTo(store.AsSpan(payloadSize));

payloadSize += receiveResult.Count;
} while (!receiveResult.EndOfMessage);

switch (receiveResult.MessageType)
{
case WebSocketMessageType.Text:
{
var intermediate = MemoryPool<char>.Shared.Rent(payloadSize).Memory;

if (payloadSize == 0)
continue;

decoder.Convert(store.Span[..payloadSize], intermediate.Span, true, out _, out var charsCount, out _);
var message = intermediate[..charsCount];

OnDataReceived?.Invoke(this, new DataReceivedArgs { Message = message.Span.ToString() });
OnDataReceived?.Invoke(this, new DataReceivedArgs { Bytes = store.AsSpan(0, payloadSize).ToArray() });
payloadSize = 0;
break;
}
case WebSocketMessageType.Binary:
break;
case WebSocketMessageType.Close:
Expand All @@ -168,75 +167,6 @@ private async Task ProcessDataAsync()
}
}
}
#else
/// <summary>
/// Background operation to process incoming data via the websocket
/// </summary>
/// <returns>Task representing the background operation</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
private async Task ProcessDataAsync()
{
const int minimumBufferSize = 8192;

var buffer = new ArraySegment<byte>(new byte[minimumBufferSize]);
var payloadSize = 0;

while (IsConnected)
{
try
{
WebSocketReceiveResult receiveResult;
var memory = new MemoryStream();

do
{
receiveResult = await _webSocket.ReceiveAsync(buffer, CancellationToken.None);

if (buffer.Array == null)
continue;

#pragma warning disable CA1849
memory.Write(buffer.Array, buffer.Offset, receiveResult.Count);
#pragma warning restore CA1849
payloadSize += receiveResult.Count;
} while (!receiveResult.EndOfMessage);

switch (receiveResult.MessageType)
{
case WebSocketMessageType.Text:
{
if (payloadSize == 0)
continue;

memory.Seek(0, SeekOrigin.Begin);

var reader = new StreamReader(memory, Encoding.UTF8);

OnDataReceived?.Invoke(this, new DataReceivedArgs { Message = await reader.ReadToEndAsync() });

memory.Dispose();
reader.Dispose();
break;
}
case WebSocketMessageType.Binary:
break;
case WebSocketMessageType.Close:
if (_webSocket.CloseStatus != null)
_logger?.LogWebsocketClosed((WebSocketCloseStatus)_webSocket.CloseStatus!, _webSocket.CloseStatusDescription!);
break;
default:
throw new ArgumentOutOfRangeException();
}
}

catch (Exception ex)
{
OnErrorOccurred?.Invoke(this, new ErrorOccuredArgs { Exception = ex });
break;
}
}
}
#endif

/// <summary>
/// Cleanup of any unused resources as per IDisposable guidelines
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel;

public class ChannelChatClearArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelChatClear>>
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel;

public class ChannelChatClearUserMessagesArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelChatClearUserMessage>>
{ }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;
namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelChatMessageDeleteArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelChatMessageDelete>>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;
namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelChatNotificationArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelChatNotification>>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel;

public class ChannelPointsAutomaticRewardRedemptionArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelPointsAutomaticRewardRedemption>>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelSharedChatSessionBeginArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelSharedChatSessionBegin>>
{ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelSharedChatSessionEndArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelSharedChatSessionEnd>>
{ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelSharedChatSessionUpdateArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelSharedChatSessionUpdate>>
{ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public class ChannelSuspiciousUserMessageArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelSuspiciousUserMessage>>
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using TwitchLib.EventSub.Core.SubscriptionTypes.Channel;
using TwitchLib.EventSub.Websockets.Core.Models;

namespace TwitchLib.EventSub.Websockets.Core.EventArgs.Channel
{
public sealed class ChannelSuspiciousUserUpdateArgs : TwitchLibEventSubEventArgs<EventSubNotification<ChannelSuspiciousUserUpdate>>
{
}
}
Loading
Loading