Hi everyone!
I’ve been trying my best to figure out how to do this but have hit a brick wall.
I’m able to get the welcome message but I haven’t been able to successfully receive any messages from my twitch channel when someone redeems a channel point reward.
I’ve checked my OAuth token is valid and has the scope for channel:read:redemptions.
Please help, I’ve been at this for months and I bet it’s something really obvious x(
Here is my script and a screenshot of my log messages.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using TMPro;
using System.Text;
using System.Text.Json;
using System.Net.Http;
using System.Net.Http.Headers;
public class WebSocketClientTwitch : MonoBehaviour
{
public TMP_Text chatBoxTMP;
private string lastMessage;
private ClientWebSocket webSocket;
private string clientID = "MY_CLIENT_ID";
private string accessToken = "MY_OAUTH_TOKEN";
private string broadcasterId = "MY_BROADCASTER_ID";
private string sessionIDString;
public async void Start()
{
Uri uri = new Uri("wss://eventsub.wss.twitch.tv/ws");
await ConnectAndReceiveAsync(uri);
}
private async Task ConnectAndReceiveAsync(Uri uri)
{
webSocket = new ClientWebSocket();
try
{
await webSocket.ConnectAsync(uri, CancellationToken.None);
Debug.Log("Connected to WebSocket!");
// Receive data
var receiveBuffer = new byte[1024];
while (webSocket.State == WebSocketState.Open)
{
Debug.Log("WebSocket is open");
WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);
if (result.MessageType == WebSocketMessageType.Text)
{
string receivedMessage = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
lastMessage = receivedMessage;
if (receivedMessage.Contains("pusher:pong"))
{
Debug.Log("Received: Pong");
}
else if (receivedMessage.Contains("ChatMessageEvent"))
{
Debug.Log("Received Chat Message: " + receivedMessage);
}
else if (receivedMessage.Contains("session_welcome"))
{
Debug.Log("We have been Welcomed: " + receivedMessage);
// Get the session ID from receivedMessage
sessionIDString = ExtractSessionID(receivedMessage);
//Debug.Log("Here is the session ID " + sessionIDString);
await SubscribeToChannelPointRedemptions(sessionIDString);
await StartPingLoop();
}
else if (receivedMessage.Contains("custom_reward_redemption"))
{
Debug.Log("Custom channel point redemption received: " + receivedMessage);
}
else
Debug.Log("Received: " + receivedMessage);
}
else
{
Debug.Log("The Message Type is: " + result.MessageType);
Debug.Log("The Message Type is: " + result.EndOfMessage);
Debug.Log("The Message Type is: " + webSocket.State);
}
}
Debug.Log("Websocket is closed...");
}
catch (Exception ex)
{
Debug.LogError("WebSocket connection error: " + ex.Message);
}
}
static string ExtractSessionID(string welcomeMessage)
{
int startIndex = welcomeMessage.IndexOf("\"id\":\"") + 6;
int endIndex = welcomeMessage.IndexOf("\"", startIndex);
return welcomeMessage.Substring(startIndex, endIndex - startIndex);
}
private async Task StartPingLoop()
{
while (webSocket.State == WebSocketState.Open)
{
string pingMessage = "{\"type\":\"ping\"}";
byte[] pingBuffer = Encoding.UTF8.GetBytes(pingMessage);
await webSocket.SendAsync(new ArraySegment<byte>(pingBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
Debug.Log("Sent keep-alive ping to Twitch");
await Task.Delay(10000); // Ping every 10 seconds
if (UnityEditor.EditorApplication.isPlaying == false)
{
// If the app is closed within the Editor, stop the Ping loop
Console.WriteLine("Close loop complete");
break;
}
}
}
private async Task SubscribeToChannelPointRedemptions(string sessionID)
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Client-ID", clientID);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
string subscribeMessage = @$"{{
""type"": ""subscribe"",
""version"": ""1"",
""condition"": {{
""broadcaster_user_id"": ""{broadcasterId}""
}},
""transport"": {{
""method"": ""websocket"",
""session_id"": ""{sessionID}""
}},
""event_type"": ""channel.channel_points_custom_reward_redemption.add""
}}";
byte[] subscribeBuffer = Encoding.UTF8.GetBytes(subscribeMessage);
await webSocket.SendAsync(new ArraySegment<byte>(subscribeBuffer), WebSocketMessageType.Text, true, CancellationToken.None);
Debug.Log("Subscribed to custom channel point redemptions on Twitch EventSub");
}
}
public async void OnApplicationQuit()
{
if (webSocket != null && webSocket.State == WebSocketState.Open)
{
// Close the WebSocket connection gracefully when the application quits
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Application quitting", CancellationToken.None);
Debug.Log("WebSocket connection closed.");
}
else
Debug.Log("WebSocket connection is closed already.");
}
}