Skip to content

Commit

Permalink
Merge branch 'master' into bfops/bump-version
Browse files Browse the repository at this point in the history
  • Loading branch information
jdetter authored Mar 3, 2025
2 parents fcdad78 + 7fab03c commit 6b0bbcc
Show file tree
Hide file tree
Showing 19 changed files with 699 additions and 537 deletions.
12 changes: 6 additions & 6 deletions SpacetimeDB.ClientSDK.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33717.318
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "examples~\quickstart\client\client.csproj", "{8F33709C-DEE9-41CC-A477-D6128E3700B1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpacetimeDB.ClientSDK", "SpacetimeDB.ClientSDK.csproj", "{242A8146-A58D-43E9-A2BD-31FFC6851AA6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests~\tests.csproj", "{5CD31104-4719-4CE3-8D39-8BAE0B75C085}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "examples~\quickstart-chat\client\client.csproj", "{FE261832-1594-DE21-C8C8-2D525680CBD7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Release|Any CPU.Build.0 = Release|Any CPU
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -27,6 +23,10 @@ Global
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Release|Any CPU.Build.0 = Release|Any CPU
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,101 @@
using SpacetimeDB;
using SpacetimeDB.Types;

const string HOST = "http://localhost:3000";
const string DBNAME = "chatqs";

// our local client SpacetimeDB identity
Identity? local_identity = null;

// declare a thread safe queue to store commands
var input_queue = new ConcurrentQueue<(string Command, string Args)>();

void Main()
{
// Initialize the `AuthToken` module
AuthToken.Init(".spacetime_csharp_quickstart");

// TODO: just do `var conn = DbConnection...` when OnConnect signature is fixed.
// Builds and connects to the database
DbConnection? conn = null;
conn = ConnectToDB();
// Registers callbacks to run in response to database events.
RegisterCallbacks(conn);
// Declare a threadsafe cancel token to cancel the process loop
var cancellationTokenSource = new CancellationTokenSource();
// Spawn a thread to call process updates and process commands
var thread = new Thread(() => ProcessThread(conn, cancellationTokenSource.Token));
thread.Start();
// Handles CLI input
InputLoop();
// This signals the ProcessThread to stop
cancellationTokenSource.Cancel();
thread.Join();
}

/// The URI of the SpacetimeDB instance hosting our chat module.
const string HOST = "http://localhost:3000";

/// The module name we chose when we published our module.
const string DBNAME = "quickstart-chat";

/// Load credentials from a file and connect to the database.
DbConnection ConnectToDB()
{
DbConnection? conn = null;
conn = DbConnection.Builder()
.WithUri(HOST)
.WithModuleName(DBNAME)
//.WithToken(AuthToken.Token)
.OnConnect(OnConnect)
.WithToken(AuthToken.Token)
.OnConnect(OnConnected)
.OnConnectError(OnConnectError)
.OnDisconnect(OnDisconnect)
.OnDisconnect(OnDisconnected)
.Build();
return conn;
}

/// Our `OnConnect` callback: save our credentials to a file.
void OnConnected(DbConnection conn, Identity identity, string authToken)
{
local_identity = identity;
AuthToken.SaveToken(authToken);

conn.SubscriptionBuilder()
.OnApplied(OnSubscriptionApplied)
.SubscribeToAllTables();
}

/// Our `OnConnectError` callback: print the error, then exit the process.
void OnConnectError(Exception e)
{
Console.Write($"Error while connecting: {e}");
}

/// Our `OnDisconnect` callback: print a note, then exit the process.
void OnDisconnected(DbConnection conn, Exception? e)
{
if (e != null)
{
Console.Write($"Disconnected abnormally: {e}");
}
else
{
Console.Write($"Disconnected normally.");
}
}

/// Register all the callbacks our app will use to respond to database events.
void RegisterCallbacks(DbConnection conn)
{
conn.Db.User.OnInsert += User_OnInsert;
conn.Db.User.OnUpdate += User_OnUpdate;

conn.Db.Message.OnInsert += Message_OnInsert;

conn.Reducers.OnSetName += Reducer_OnSetNameEvent;
conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;

// declare a threadsafe cancel token to cancel the process loop
var cancellationTokenSource = new CancellationTokenSource();

// spawn a thread to call process updates and process commands
var thread = new Thread(() => ProcessThread(conn, cancellationTokenSource.Token));
thread.Start();

InputLoop();

// this signals the ProcessThread to stop
cancellationTokenSource.Cancel();
thread.Join();
}

/// If the user has no set name, use the first 8 characters from their identity.
string UserNameOrIdentity(User user) => user.Name ?? user.Identity.ToString()[..8];

/// Our `User.OnInsert` callback: if the user is online, print a notification.
void User_OnInsert(EventContext ctx, User insertedValue)
{
if (insertedValue.Online)
Expand All @@ -61,6 +108,8 @@ void User_OnInsert(EventContext ctx, User insertedValue)
}
}

/// Our `User.OnUpdate` callback:
/// print a notification about name and status changes.
void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
{
if (oldValue.Name != newValue.Name)
Expand All @@ -80,6 +129,18 @@ void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
}
}

/// Our `Message.OnInsert` callback: print new messages.
void Message_OnInsert(EventContext ctx, Message insertedValue)
{
// We are filtering out messages inserted during the subscription being applied,
// since we will be printing those in the OnSubscriptionApplied callback,
// where we will be able to first sort the messages before printing.
if (ctx.Event is not Event<Reducer>.SubscribeApplied)
{
PrintMessage(ctx.Db, insertedValue);
}
}

void PrintMessage(RemoteTables tables, Message message)
{
var sender = tables.User.Identity.Find(message.Sender);
Expand All @@ -92,15 +153,7 @@ void PrintMessage(RemoteTables tables, Message message)
Console.WriteLine($"{senderName}: {message.Text}");
}

void Message_OnInsert(EventContext ctx, Message insertedValue)
{

if (ctx.Event is not Event<Reducer>.SubscribeApplied)
{
PrintMessage(ctx.Db, insertedValue);
}
}

/// Our `OnSetNameEvent` callback: print a warning if the reducer failed.
void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name)
{
var e = ctx.Event;
Expand All @@ -110,6 +163,7 @@ void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name)
}
}

/// Our `OnSendMessageEvent` callback: print a warning if the reducer failed.
void Reducer_OnSendMessageEvent(ReducerEventContext ctx, string text)
{
var e = ctx.Event;
Expand All @@ -119,34 +173,12 @@ void Reducer_OnSendMessageEvent(ReducerEventContext ctx, string text)
}
}

void OnConnect(DbConnection conn, Identity identity, string authToken)
{
local_identity = identity;
AuthToken.SaveToken(authToken);

var subscription = conn.SubscriptionBuilder()
.OnApplied(OnSubscriptionApplied)
.Subscribe(new string[] {
"SELECT * FROM user",
"SELECT * FROM message",
// It is legal to have redundant subscriptions.
// However, keep in mind that data will be sent over the wire multiple times,
// once for each subscriptions. This can cause slowdowns if you aren't careful.
"SELECT * FROM message" });

// You can also use SubscribeToAllTables, but it should be avoided if you have any large tables:
// conn.SubscriptionBuilder().OnApplied(OnSubscriptionApplied).SubscribeToAllTables();

}

void OnConnectError(Exception e)
{

}

void OnDisconnect(DbConnection conn, Exception? e)
/// Our `OnSubscriptionApplied` callback:
/// sort all past messages and print them in timestamp order.
void OnSubscriptionApplied(SubscriptionEventContext ctx)
{

Console.WriteLine("Connected");
PrintMessagesInOrder(ctx.Db);
}

void PrintMessagesInOrder(RemoteTables tables)
Expand All @@ -157,12 +189,7 @@ void PrintMessagesInOrder(RemoteTables tables)
}
}

void OnSubscriptionApplied(SubscriptionEventContext ctx)
{
Console.WriteLine("Connected");
PrintMessagesInOrder(ctx.Db);
}

/// Our separate thread from main, where we can call process updates and process commands without blocking the main thread.
void ProcessThread(DbConnection conn, CancellationToken ct)
{
try
Expand All @@ -183,6 +210,7 @@ void ProcessThread(DbConnection conn, CancellationToken ct)
}
}

/// Read each line of standard input, and either set our name or send a message as appropriate.
void InputLoop()
{
while (true)
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 6b0bbcc

Please sign in to comment.