Files
SpacetimeDB/examples/quickstart/client/Program.cs
T
Ingvar Stepanyan 596c4a5e5c Make logger a separate SDK setting from client instance (#79)
This allows to:

1. Have a preset logger that is already correctly matching the environment (console vs Unity).
2. Removes the need for explicit `SpacetimeDBClient.CreateInstance(...)` which is particularly awkward to use and easy to forget with singleton as it doesn't return a result as a factory method name could suggest. Instead, `SpacetimeDBClient.instance` is available on first use.
3. Slightly simplifies dependencies between classes, e.g. `ClientCache` doesn't need a circular dependency on `SpacetimeDBClient`, making future maintenance and changes a bit easier.
2024-04-24 17:51:53 +01:00

194 lines
4.6 KiB
C#

using SpacetimeDB;
using SpacetimeDB.Types;
using System.Collections.Concurrent;
// our local client SpacetimeDB identity
Identity? local_identity = null;
// declare a thread safe queue to store commands in format (command, args)
ConcurrentQueue<(string,string)> input_queue = new ConcurrentQueue<(string, string)>();
// declare a threadsafe cancel token to cancel the process loop
CancellationTokenSource cancel_token = new CancellationTokenSource();
void Main()
{
AuthToken.Init(".spacetime_csharp_quickstart");
RegisterCallbacks();
// spawn a thread to call process updates and process commands
var thread = new Thread(ProcessThread);
thread.Start();
InputLoop();
// this signals the ProcessThread to stop
cancel_token.Cancel();
thread.Join();
}
void RegisterCallbacks()
{
SpacetimeDBClient.instance.onConnect += OnConnect;
SpacetimeDBClient.instance.onIdentityReceived += OnIdentityReceived;
SpacetimeDBClient.instance.onSubscriptionApplied += OnSubscriptionApplied;
User.OnInsert += User_OnInsert;
User.OnUpdate += User_OnUpdate;
Message.OnInsert += Message_OnInsert;
Reducer.OnSetNameEvent += Reducer_OnSetNameEvent;
Reducer.OnSendMessageEvent += Reducer_OnSendMessageEvent;
}
string UserNameOrIdentity(User user) => user.Name ?? user.Identity.ToString()!.Substring(0, 8);
void User_OnInsert(User insertedValue, ReducerEvent? dbEvent)
{
if(insertedValue.Online)
{
Console.WriteLine($"{UserNameOrIdentity(insertedValue)} is online");
}
}
void User_OnUpdate(User oldValue, User newValue, ReducerEvent? dbEvent)
{
if(oldValue.Name != newValue.Name)
{
Console.WriteLine($"{UserNameOrIdentity(oldValue)} renamed to {newValue.Name}");
}
if(oldValue.Online != newValue.Online)
{
if(newValue.Online)
{
Console.WriteLine($"{UserNameOrIdentity(newValue)} connected.");
}
else
{
Console.WriteLine($"{UserNameOrIdentity(newValue)} disconnected.");
}
}
}
void PrintMessage(Message message)
{
var sender = User.FilterByIdentity(message.Sender);
var senderName = "unknown";
if(sender != null)
{
senderName = UserNameOrIdentity(sender);
}
Console.WriteLine($"{senderName}: {message.Text}");
}
void Message_OnInsert(Message insertedValue, ReducerEvent? dbEvent)
{
if(dbEvent != null)
{
PrintMessage(insertedValue);
}
}
void Reducer_OnSetNameEvent(ReducerEvent reducerEvent, string name)
{
if(reducerEvent.Identity == local_identity && reducerEvent.Status == ClientApi.Event.Types.Status.Failed)
{
Console.Write($"Failed to change name to {name}");
}
}
void Reducer_OnSendMessageEvent(ReducerEvent reducerEvent, string text)
{
if (reducerEvent.Identity == local_identity && reducerEvent.Status == ClientApi.Event.Types.Status.Failed)
{
Console.Write($"Failed to send message {text}");
}
}
void OnConnect()
{
SpacetimeDBClient.instance.Subscribe(new List<string> { "SELECT * FROM User", "SELECT * FROM Message" });
}
void OnIdentityReceived(string authToken, Identity identity, Address _address)
{
local_identity = identity;
AuthToken.SaveToken(authToken);
}
void PrintMessagesInOrder()
{
foreach (Message message in Message.Iter().OrderBy(item => item.Sent))
{
PrintMessage(message);
}
}
void OnSubscriptionApplied()
{
Console.WriteLine("Connected");
PrintMessagesInOrder();
}
const string HOST = "http://localhost:3000";
const string DBNAME = "chatqs";
void ProcessThread()
{
SpacetimeDBClient.instance.Connect(AuthToken.Token, HOST, DBNAME);
// loop until cancellation token
while (!cancel_token.IsCancellationRequested)
{
SpacetimeDBClient.instance.Update();
ProcessCommands();
Thread.Sleep(100);
}
SpacetimeDBClient.instance.Close();
}
void InputLoop()
{
while (true)
{
var input = Console.ReadLine();
if(input == null)
{
break;
}
if(input.StartsWith("/name "))
{
input_queue.Enqueue(("name", input.Substring(6)));
continue;
}
else
{
input_queue.Enqueue(("message", input));
}
}
}
void ProcessCommands()
{
// process input queue commands
while (input_queue.TryDequeue(out var command))
{
switch (command.Item1)
{
case "message":
Reducer.SendMessage(command.Item2);
break;
case "name":
Reducer.SetName(command.Item2);
break;
}
}
}
Main();