-
-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
451 additions
and
203 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License. | ||
// See the LICENSE file in the repository root for full license text. | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
|
||
namespace VRCOSC.Game.Modules.Bases.Heartrate; | ||
|
||
/// <summary> | ||
/// The base class for anything looking to gather heartrate data from a source | ||
/// </summary> | ||
public abstract class HeartrateProvider | ||
{ | ||
private DateTimeOffset lastHeartrateDateTime; | ||
|
||
/// <summary> | ||
/// Used to decide the connection state of this <see cref="HeartrateProvider"/> | ||
/// </summary> | ||
public virtual bool IsConnected => false; | ||
|
||
/// <summary> | ||
/// Used decide if this <see cref="HeartrateProvider"/> is receiving heartrate values. | ||
/// For example, <see cref="IsConnected"/> could be true but values may not be being received | ||
/// </summary> | ||
public virtual bool IsReceiving => IsConnected && lastHeartrateDateTime + IsReceivingTimeout >= DateTimeOffset.Now; | ||
|
||
/// <summary> | ||
/// Called when this <see cref="HeartrateProvider"/> is broadcasting information. | ||
/// By default, <see cref="HeartrateModule{T}"/> captures this and automatically logs the message | ||
/// </summary> | ||
public Action<string>? OnLog; | ||
|
||
/// <summary> | ||
/// Called when this <see cref="HeartrateProvider"/> is connected and ready to send data to <see cref="OnHeartrateUpdate"/> | ||
/// </summary> | ||
public Action? OnConnected; | ||
|
||
/// <summary> | ||
/// Called when this <see cref="HeartrateProvider"/> is disconnected and will no longer send data to <see cref="OnHeartrateUpdate"/> | ||
/// </summary> | ||
public Action? OnDisconnected; | ||
|
||
/// <summary> | ||
/// Called when this <see cref="HeartrateProvider"/> receives a new heartrate value. | ||
/// This is listened on internally so DO NOT set directly. Use the +=/-= syntax instead if you want to bind/unbind | ||
/// </summary> | ||
public Action<int>? OnHeartrateUpdate; | ||
|
||
/// <summary> | ||
/// How long should we wait after the last <see cref="OnHeartrateUpdate"/> call until <see cref="IsReceiving"/> resolves to false | ||
/// </summary> | ||
protected virtual TimeSpan IsReceivingTimeout => TimeSpan.FromSeconds(30); | ||
|
||
/// <summary> | ||
/// A stub method that forwards <paramref name="message"/> to <see cref="OnLog"/> | ||
/// </summary> | ||
/// <param name="message">The message to forward to <see cref="OnLog"/></param> | ||
protected void Log(string message) => OnLog?.Invoke(message); | ||
|
||
protected HeartrateProvider() | ||
{ | ||
OnHeartrateUpdate += _ => lastHeartrateDateTime = DateTimeOffset.Now; | ||
} | ||
|
||
/// <summary> | ||
/// Initialises this <see cref="HeartrateProvider"/> | ||
/// </summary> | ||
public virtual void Initialise() | ||
{ | ||
lastHeartrateDateTime = DateTimeOffset.MinValue; | ||
} | ||
|
||
/// <summary> | ||
/// Tears down this <see cref="HeartrateProvider"/> | ||
/// </summary> | ||
public abstract Task Teardown(); | ||
} |
84 changes: 84 additions & 0 deletions
84
VRCOSC.Game/Modules/Bases/Heartrate/WebSocketHeartrateProvider.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License. | ||
// See the LICENSE file in the repository root for full license text. | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using Newtonsoft.Json; | ||
|
||
namespace VRCOSC.Game.Modules.Bases.Heartrate; | ||
|
||
/// <inheritdoc /> | ||
/// <summary> | ||
/// Stub class that provides handling for a <see cref="WebSocketClient"/> and adds virtual methods for <see cref="WebSocketClient"/> management | ||
/// </summary> | ||
public abstract class WebSocketHeartrateProvider : HeartrateProvider | ||
{ | ||
public override bool IsConnected => client?.IsConnected ?? false; | ||
|
||
private WebSocketClient? client; | ||
|
||
protected virtual Uri? WebsocketUri => null; | ||
|
||
/// <inheritdoc /> | ||
/// <summary> | ||
/// Initialises this <see cref="WebSocketHeartrateProvider"/> and connects to the websocket | ||
/// <exception cref="InvalidOperationException">If <see cref="Initialise"/> is called while this <see cref="WebSocketHeartrateProvider"/> is already initialised, or if <see cref="WebsocketUri"/> is null</exception> | ||
/// </summary> | ||
public override void Initialise() | ||
{ | ||
if (client is not null) throw new InvalidOperationException("Call Teardown before re-initialising"); | ||
if (WebsocketUri is null) throw new InvalidOperationException("WebsocketUri is null"); | ||
|
||
client = new WebSocketClient(WebsocketUri.ToString()); | ||
|
||
client.OnWsConnected += () => | ||
{ | ||
OnWebSocketConnected(); | ||
OnConnected?.Invoke(); | ||
}; | ||
|
||
client.OnWsDisconnected += () => | ||
{ | ||
OnWebSocketDisconnected(); | ||
OnDisconnected?.Invoke(); | ||
}; | ||
|
||
client.OnWsMessage += OnWebSocketMessage; | ||
|
||
client.Connect(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
/// <summary> | ||
/// Tears this <see cref="WebSocketHeartrateProvider"/> down and disconnects the <see cref="WebSocketClient"/> if it's connected | ||
/// </summary> | ||
public override async Task Teardown() | ||
{ | ||
if (client is null) return; | ||
|
||
if (IsConnected) await client.Disconnect(); | ||
|
||
client = null; | ||
} | ||
|
||
/// <summary> | ||
/// Sends an object by first serialising it using <see cref="JsonConvert"/> | ||
/// </summary> | ||
/// <param name="data">The data to serialise and then send</param> | ||
protected void SendDataAsJson(object data) => SendData(JsonConvert.SerializeObject(data)); | ||
|
||
/// <summary> | ||
/// Sends a raw string | ||
/// </summary> | ||
/// <param name="data">The data to send</param> | ||
protected void SendData(string data) | ||
{ | ||
if (!IsConnected) return; | ||
|
||
client?.Send(data); | ||
} | ||
|
||
protected virtual void OnWebSocketConnected() { } | ||
protected virtual void OnWebSocketDisconnected() { } | ||
protected virtual void OnWebSocketMessage(string message) { } | ||
} |
This file contains 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
Oops, something went wrong.