Skip to content

Commit faeb9ea

Browse files
rekhoffbfopsjdetterkazimuth
authored
Update C# server and client quickstart examples to match tutorial document. (#258)
# Description of Changes Update the C# server and client SDK quickstart-chat example to match the code presented in the tutorial, as of clockworklabs/spacetime-docs#170 . Also renamed the directory from `quickstart` to `quickstart-chat` in order to be more specific. # API and ABI breaking changes If this is an API or ABI breaking change, please apply the corresponding GitHub label. # Expected complexity level and risk 1 ## Requires SpacetimeDB PRs SpacetimeDB branch name: master com.clockworklabs.spacetimedbsdk: master # Testing *Describe any testing you've done, and any testing you'd like your reviewers to do, so that you're confident that all the changes work as expected!* - [x] Ran `quickstart-chat` C# server and C# client locally and: - Set my name. - Sent a message. - Restarted and viewed the message backlog. - Sent a few more messages. - Exited, deleted my local token, restarted and connected as a new identity. - Set my new identity's name. - Sent a message as my new identity. --------- Co-authored-by: Zeke Foppa <[email protected]> Co-authored-by: John Detter <[email protected]> Co-authored-by: james gilles <[email protected]>
1 parent a000f8e commit faeb9ea

31 files changed

+703
-533
lines changed

SpacetimeDB.ClientSDK.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717
<PackageReadmeFile>README.md</PackageReadmeFile>
1818
<RepositoryUrl>https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk</RepositoryUrl>
1919
<AssemblyVersion>1.0.0</AssemblyVersion>
20-
<Version>1.0.0-rc4</Version>
20+
<Version>1.0.0</Version>
2121
<DefaultItemExcludes>$(DefaultItemExcludes);*~/**</DefaultItemExcludes>
2222
<!-- We want to save DLLs for Unity which doesn't support NuGet. -->
2323
<RestorePackagesPath>packages</RestorePackagesPath>
2424
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
2525
</PropertyGroup>
2626

2727
<ItemGroup>
28-
<PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="1.0.0-rc4" />
28+
<PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="1.0.0" />
2929

3030
<InternalsVisibleTo Include="SpacetimeDB.Tests" />
3131
</ItemGroup>

SpacetimeDB.ClientSDK.sln

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.6.33717.318
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "examples~\quickstart\client\client.csproj", "{8F33709C-DEE9-41CC-A477-D6128E3700B1}"
7-
EndProject
86
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpacetimeDB.ClientSDK", "SpacetimeDB.ClientSDK.csproj", "{242A8146-A58D-43E9-A2BD-31FFC6851AA6}"
97
EndProject
108
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests~\tests.csproj", "{5CD31104-4719-4CE3-8D39-8BAE0B75C085}"
119
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "examples~\quickstart-chat\client\client.csproj", "{FE261832-1594-DE21-C8C8-2D525680CBD7}"
11+
EndProject
1212
Global
1313
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1414
Debug|Any CPU = Debug|Any CPU
1515
Release|Any CPU = Release|Any CPU
1616
EndGlobalSection
1717
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18-
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19-
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
20-
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
21-
{8F33709C-DEE9-41CC-A477-D6128E3700B1}.Release|Any CPU.Build.0 = Release|Any CPU
2218
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2319
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
2420
{242A8146-A58D-43E9-A2BD-31FFC6851AA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -27,6 +23,10 @@ Global
2723
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Debug|Any CPU.Build.0 = Debug|Any CPU
2824
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Release|Any CPU.ActiveCfg = Release|Any CPU
2925
{5CD31104-4719-4CE3-8D39-8BAE0B75C085}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{FE261832-1594-DE21-C8C8-2D525680CBD7}.Release|Any CPU.Build.0 = Release|Any CPU
3030
EndGlobalSection
3131
GlobalSection(SolutionProperties) = preSolution
3232
HideSolutionNode = FALSE

examples~/quickstart/client/Program.cs renamed to examples~/quickstart-chat/client/Program.cs

Lines changed: 90 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,54 +5,101 @@
55
using SpacetimeDB;
66
using SpacetimeDB.Types;
77

8-
const string HOST = "http://localhost:3000";
9-
const string DBNAME = "chatqs";
108

119
// our local client SpacetimeDB identity
1210
Identity? local_identity = null;
11+
1312
// declare a thread safe queue to store commands
1413
var input_queue = new ConcurrentQueue<(string Command, string Args)>();
1514

1615
void Main()
1716
{
17+
// Initialize the `AuthToken` module
1818
AuthToken.Init(".spacetime_csharp_quickstart");
19-
20-
// TODO: just do `var conn = DbConnection...` when OnConnect signature is fixed.
19+
// Builds and connects to the database
2120
DbConnection? conn = null;
21+
conn = ConnectToDB();
22+
// Registers callbacks to run in response to database events.
23+
RegisterCallbacks(conn);
24+
// Declare a threadsafe cancel token to cancel the process loop
25+
var cancellationTokenSource = new CancellationTokenSource();
26+
// Spawn a thread to call process updates and process commands
27+
var thread = new Thread(() => ProcessThread(conn, cancellationTokenSource.Token));
28+
thread.Start();
29+
// Handles CLI input
30+
InputLoop();
31+
// This signals the ProcessThread to stop
32+
cancellationTokenSource.Cancel();
33+
thread.Join();
34+
}
35+
36+
/// The URI of the SpacetimeDB instance hosting our chat module.
37+
const string HOST = "http://localhost:3000";
38+
39+
/// The module name we chose when we published our module.
40+
const string DBNAME = "quickstart-chat";
2241

42+
/// Load credentials from a file and connect to the database.
43+
DbConnection ConnectToDB()
44+
{
45+
DbConnection? conn = null;
2346
conn = DbConnection.Builder()
2447
.WithUri(HOST)
2548
.WithModuleName(DBNAME)
26-
//.WithToken(AuthToken.Token)
27-
.OnConnect(OnConnect)
49+
.WithToken(AuthToken.Token)
50+
.OnConnect(OnConnected)
2851
.OnConnectError(OnConnectError)
29-
.OnDisconnect(OnDisconnect)
52+
.OnDisconnect(OnDisconnected)
3053
.Build();
54+
return conn;
55+
}
3156

57+
/// Our `OnConnect` callback: save our credentials to a file.
58+
void OnConnected(DbConnection conn, Identity identity, string authToken)
59+
{
60+
local_identity = identity;
61+
AuthToken.SaveToken(authToken);
62+
63+
conn.SubscriptionBuilder()
64+
.OnApplied(OnSubscriptionApplied)
65+
.SubscribeToAllTables();
66+
}
67+
68+
/// Our `OnConnectError` callback: print the error, then exit the process.
69+
void OnConnectError(Exception e)
70+
{
71+
Console.Write($"Error while connecting: {e}");
72+
}
73+
74+
/// Our `OnDisconnect` callback: print a note, then exit the process.
75+
void OnDisconnected(DbConnection conn, Exception? e)
76+
{
77+
if (e != null)
78+
{
79+
Console.Write($"Disconnected abnormally: {e}");
80+
}
81+
else
82+
{
83+
Console.Write($"Disconnected normally.");
84+
}
85+
}
86+
87+
/// Register all the callbacks our app will use to respond to database events.
88+
void RegisterCallbacks(DbConnection conn)
89+
{
3290
conn.Db.User.OnInsert += User_OnInsert;
3391
conn.Db.User.OnUpdate += User_OnUpdate;
3492

3593
conn.Db.Message.OnInsert += Message_OnInsert;
3694

3795
conn.Reducers.OnSetName += Reducer_OnSetNameEvent;
3896
conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;
39-
40-
// declare a threadsafe cancel token to cancel the process loop
41-
var cancellationTokenSource = new CancellationTokenSource();
42-
43-
// spawn a thread to call process updates and process commands
44-
var thread = new Thread(() => ProcessThread(conn, cancellationTokenSource.Token));
45-
thread.Start();
46-
47-
InputLoop();
48-
49-
// this signals the ProcessThread to stop
50-
cancellationTokenSource.Cancel();
51-
thread.Join();
5297
}
5398

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

102+
/// Our `User.OnInsert` callback: if the user is online, print a notification.
56103
void User_OnInsert(EventContext ctx, User insertedValue)
57104
{
58105
if (insertedValue.Online)
@@ -61,6 +108,8 @@ void User_OnInsert(EventContext ctx, User insertedValue)
61108
}
62109
}
63110

111+
/// Our `User.OnUpdate` callback:
112+
/// print a notification about name and status changes.
64113
void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
65114
{
66115
if (oldValue.Name != newValue.Name)
@@ -80,6 +129,18 @@ void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
80129
}
81130
}
82131

132+
/// Our `Message.OnInsert` callback: print new messages.
133+
void Message_OnInsert(EventContext ctx, Message insertedValue)
134+
{
135+
// We are filtering out messages inserted during the subscription being applied,
136+
// since we will be printing those in the OnSubscriptionApplied callback,
137+
// where we will be able to first sort the messages before printing.
138+
if (ctx.Event is not Event<Reducer>.SubscribeApplied)
139+
{
140+
PrintMessage(ctx.Db, insertedValue);
141+
}
142+
}
143+
83144
void PrintMessage(RemoteTables tables, Message message)
84145
{
85146
var sender = tables.User.Identity.Find(message.Sender);
@@ -92,15 +153,7 @@ void PrintMessage(RemoteTables tables, Message message)
92153
Console.WriteLine($"{senderName}: {message.Text}");
93154
}
94155

95-
void Message_OnInsert(EventContext ctx, Message insertedValue)
96-
{
97-
98-
if (ctx.Event is not Event<Reducer>.SubscribeApplied)
99-
{
100-
PrintMessage(ctx.Db, insertedValue);
101-
}
102-
}
103-
156+
/// Our `OnSetNameEvent` callback: print a warning if the reducer failed.
104157
void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name)
105158
{
106159
var e = ctx.Event;
@@ -110,6 +163,7 @@ void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name)
110163
}
111164
}
112165

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

122-
void OnConnect(DbConnection conn, Identity identity, string authToken)
123-
{
124-
local_identity = identity;
125-
AuthToken.SaveToken(authToken);
126-
127-
var subscription = conn.SubscriptionBuilder()
128-
.OnApplied(OnSubscriptionApplied)
129-
.Subscribe(new string[] {
130-
"SELECT * FROM user",
131-
"SELECT * FROM message",
132-
// It is legal to have redundant subscriptions.
133-
// However, keep in mind that data will be sent over the wire multiple times,
134-
// once for each subscriptions. This can cause slowdowns if you aren't careful.
135-
"SELECT * FROM message" });
136-
137-
// You can also use SubscribeToAllTables, but it should be avoided if you have any large tables:
138-
// conn.SubscriptionBuilder().OnApplied(OnSubscriptionApplied).SubscribeToAllTables();
139-
140-
}
141-
142-
void OnConnectError(Exception e)
143-
{
144-
145-
}
146-
147-
void OnDisconnect(DbConnection conn, Exception? e)
176+
/// Our `OnSubscriptionApplied` callback:
177+
/// sort all past messages and print them in timestamp order.
178+
void OnSubscriptionApplied(SubscriptionEventContext ctx)
148179
{
149-
180+
Console.WriteLine("Connected");
181+
PrintMessagesInOrder(ctx.Db);
150182
}
151183

152184
void PrintMessagesInOrder(RemoteTables tables)
@@ -157,12 +189,7 @@ void PrintMessagesInOrder(RemoteTables tables)
157189
}
158190
}
159191

160-
void OnSubscriptionApplied(SubscriptionEventContext ctx)
161-
{
162-
Console.WriteLine("Connected");
163-
PrintMessagesInOrder(ctx.Db);
164-
}
165-
192+
/// Our separate thread from main, where we can call process updates and process commands without blocking the main thread.
166193
void ProcessThread(DbConnection conn, CancellationToken ct)
167194
{
168195
try
@@ -183,6 +210,7 @@ void ProcessThread(DbConnection conn, CancellationToken ct)
183210
}
184211
}
185212

213+
/// Read each line of standard input, and either set our name or send a message as appropriate.
186214
void InputLoop()
187215
{
188216
while (true)
File renamed without changes.

0 commit comments

Comments
 (0)