diff --git a/client/.editorconfig b/client/.editorconfig deleted file mode 100644 index 0b3779e..0000000 --- a/client/.editorconfig +++ /dev/null @@ -1,5 +0,0 @@ -root = true - -[*] -end_of_line = lf -insert_final_newline = true diff --git a/client/chat/ChatInput.cs b/client/chat/ChatInput.cs deleted file mode 100644 index 652a055..0000000 --- a/client/chat/ChatInput.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Godot; -using SpacetimeDB; -using SpacetimeDB.Types; - -public partial class ChatInput : LineEdit -{ - public override void _EnterTree() - { - TextSubmitted += OnMessageInput; - } - - // Called when the node enters the scene tree for the first time. - public override void _Ready() - { - DbConnection conn = Spacetime.Instance.Connection; - RegisterSubscriptions(conn); - } - - void OnMessageInput(string text) - { - Spacetime.Instance.Connection.Reducers.SendMessage(text); - Text = ""; - } - - void RegisterSubscriptions(DbConnection conn) - { - conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent; - } - - /// Our `OnSendMessageEvent` callback: print a warning if the reducer failed. - void Reducer_OnSendMessageEvent(ReducerEventContext ctx, string text) - { - var e = ctx.Event; - if (e.CallerIdentity == Spacetime.Instance.Identity && e.Status is Status.Failed(var error)) - { - GD.PrintErr($"Failed to send message {text}: {error}"); - } - } -} diff --git a/client/chat/ChatInput.cs.uid b/client/chat/ChatInput.cs.uid deleted file mode 100644 index 1eaa0c5..0000000 --- a/client/chat/ChatInput.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://115ssbk8epio diff --git a/client/chat/ChatLog.cs b/client/chat/ChatLog.cs index 4f55792..83a2bd7 100644 --- a/client/chat/ChatLog.cs +++ b/client/chat/ChatLog.cs @@ -1,87 +1,20 @@ using Godot; -using SpacetimeDB; -using SpacetimeDB.Types; public partial class ChatLog : RichTextLabel { - const string SystemColor = "#747474"; + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + } - public override void _EnterTree() - { - ClearLog(); - } + // Called every frame. 'delta' is the elapsed time since the previous frame. + public override void _Process(double delta) + { + } - public override void _Ready() - { - DbConnection conn = Spacetime.Instance.Connection; - RegisterSubscriptions(conn); - } - - string UserNameOrIdentity(User user) - { - return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown"; - } - - void PushMessage(string name, string message, string color) - { - string entry = $"[color={color}]{name}:[/color] {message}"; - this.Text += $"{entry}\n"; - } - - void ClearLog() - { - Text = ""; - } - - void RegisterSubscriptions(DbConnection conn) - { - conn.Db.User.OnInsert += User_OnInsert; - conn.Db.User.OnUpdate += User_OnUpdate; - - conn.Db.Message.OnInsert += Message_OnInsert; - } - - void User_OnInsert(EventContext ctx, User insertedValue) - { - if (ctx.Event is Event.SubscribeApplied) - { - return; - } - PushMessage("System", $"{UserNameOrIdentity(insertedValue)} connected", SystemColor); - } - - void User_OnUpdate(EventContext ctx, User oldValue, User newValue) - { - if (oldValue.Name != newValue.Name) - { - PushMessage( - "System", - $"{UserNameOrIdentity(oldValue)} renamed to {UserNameOrIdentity(newValue)}", - SystemColor - ); - } - if (oldValue.Online != newValue.Online) - { - if (newValue.Online) - { - PushMessage("System", $"{UserNameOrIdentity(newValue)} connected", SystemColor); - } - else - { - PushMessage("System", $"{UserNameOrIdentity(newValue)} disconnected", SystemColor); - } - } - } - - void Message_OnInsert(EventContext ctx, Message insertedValue) - { - User sender = ctx.Db.User.Identity.Find(insertedValue.Sender); - string color = sender.Identity.Equals(Spacetime.Instance.Identity) ? "blue" : "red"; - if (ctx.Event is Event.SubscribeApplied) - { - PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); - return; - } - PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); - } + public void PushMessage(string name, string message, string color) + { + string entry = $"[color={color}]{name}:[/color] {message}"; + this.Text += $"{entry}\n"; + } } diff --git a/client/chat/ChatOptions.cs b/client/chat/ChatOptions.cs deleted file mode 100644 index 041dd75..0000000 --- a/client/chat/ChatOptions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Godot; -using SpacetimeDB; -using SpacetimeDB.Types; - -public partial class ChatOptions : HBoxContainer -{ - public LineEdit Username { get; private set; } - public ColorPickerButton ColorPicker { get; private set; } - - public override void _EnterTree() - { - Username = GetNode("Username"); - ColorPicker = GetNode("ColorPicker"); - - Username.TextSubmitted += OnUsernameInput; - Username.FocusExited += ResetUsername; - } - - public override void _Ready() - { - DbConnection conn = Spacetime.Instance.Connection; - RegisterSubscriptions(conn); - } - - string UserNameOrIdentity(User user) - { - return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown"; - } - - void ResetUsername() - { - Username.Text = UserNameOrIdentity(Spacetime.Instance.Me); - } - - void OnUsernameInput(string text) - { - Spacetime.Instance.Connection.Reducers.SetName(text); - } - - void RegisterSubscriptions(DbConnection conn) - { - conn.Reducers.OnSetName += Reducer_OnSetNameEvent; - } - - /// Our `OnSetNameEvent` callback: print a warning if the reducer failed. - void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name) - { - var e = ctx.Event; - if (e.CallerIdentity != Spacetime.Instance.Identity) - { - // Not me - return; - } - if (e.Status is Status.Failed(var error)) - { - GD.PrintErr($"Failed to change name to {name}: {error}"); - return; - } - } -} diff --git a/client/chat/ChatOptions.cs.uid b/client/chat/ChatOptions.cs.uid deleted file mode 100644 index e04a848..0000000 --- a/client/chat/ChatOptions.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://tff5u6blrc1d diff --git a/client/chat/ChatWindow.cs b/client/chat/ChatWindow.cs index 6f387c7..0b58d20 100644 --- a/client/chat/ChatWindow.cs +++ b/client/chat/ChatWindow.cs @@ -1,16 +1,136 @@ using Godot; +using SpacetimeDB; +using SpacetimeDB.Types; public partial class ChatWindow : VBoxContainer { - private ChatOptions _options; - private ChatLog _log; - private LineEdit _input; + const string SystemColor = "#747474"; - // Called when the node enters the scene tree for the first time. - public override void _EnterTree() + private LineEdit _userNameInput; + private ChatLog _log; + private LineEdit _input; + + // Called when the node enters the scene tree for the first time. + public override void _EnterTree() + { + _userNameInput = GetNode("Options/Username"); + _log = GetNode("ChatLog"); + _input = GetNode("ChatInput"); + + _log.Text = ""; + } + + string UserNameOrIdentity(User user) + { + return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown"; + } + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + DbConnection conn = Spacetime.Instance.Connection; + + _userNameInput.TextSubmitted += OnUsernameInput; + _userNameInput.FocusExited += ResetUsername; + _input.TextSubmitted += OnMessageInput; + + 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; + } + + void ResetUsername() + { + _userNameInput.Text = UserNameOrIdentity(Spacetime.Instance.Me); + } + + // Called every frame. 'delta' is the elapsed time since the previous frame. + public override void _Process(double delta) + { + } + + private void OnUsernameInput(string text) + { + Spacetime.Instance.Connection.Reducers.SetName(text); + } + + private void OnMessageInput(string text) + { + Spacetime.Instance.Connection.Reducers.SendMessage(text); + _input.Text = ""; + } + + void User_OnInsert(EventContext ctx, User insertedValue) + { + if (ctx.Event is Event.SubscribeApplied) { - _options = GetNode("Options"); - _log = GetNode("ChatLog"); - _input = GetNode("ChatInput"); + if (insertedValue.Identity == Spacetime.Instance.Identity) + { + ResetUsername(); + } + return; } + _log.PushMessage("System", $"{UserNameOrIdentity(insertedValue)} connected", SystemColor); + } + + void User_OnUpdate(EventContext ctx, User oldValue, User newValue) + { + if (oldValue.Name != newValue.Name) + { + _log.PushMessage("System", $"{UserNameOrIdentity(oldValue)} renamed to {UserNameOrIdentity(newValue)}", SystemColor); + } + if (oldValue.Online != newValue.Online) + { + if (newValue.Online) + { + _log.PushMessage("System", $"{UserNameOrIdentity(newValue)} connected", SystemColor); + } + else + { + _log.PushMessage("System", $"{UserNameOrIdentity(newValue)} disconnected", SystemColor); + } + } + } + + void Message_OnInsert(EventContext ctx, Message insertedValue) + { + User sender = ctx.Db.User.Identity.Find(insertedValue.Sender); + string color = sender.Identity.Equals(Spacetime.Instance.Identity) ? "blue" : "red"; + if (ctx.Event is Event.SubscribeApplied) + { + _log.PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); + return; + } + _log.PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color); + } + + /// Our `OnSetNameEvent` callback: print a warning if the reducer failed. + void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name) + { + var e = ctx.Event; + if (e.CallerIdentity != Spacetime.Instance.Identity) + { + // Not me + return; + } + if (e.Status is Status.Failed(var error)) + { + GD.PrintErr($"Failed to change name to {name}: {error}"); + return; + } + } + + /// Our `OnSendMessageEvent` callback: print a warning if the reducer failed. + void Reducer_OnSendMessageEvent(ReducerEventContext ctx, string text) + { + var e = ctx.Event; + if (e.CallerIdentity == Spacetime.Instance.Identity && e.Status is Status.Failed(var error)) + { + GD.PrintErr($"Failed to send message {text}: {error}"); + } + } } diff --git a/client/chat/ChatWindow.tscn b/client/chat/ChatWindow.tscn index 05f7b26..be31869 100644 --- a/client/chat/ChatWindow.tscn +++ b/client/chat/ChatWindow.tscn @@ -1,9 +1,7 @@ -[gd_scene load_steps=5 format=3 uid="uid://cqmy41vtnqd6f"] +[gd_scene load_steps=3 format=3 uid="uid://cqmy41vtnqd6f"] [ext_resource type="Script" uid="uid://c3s41dv7hv4md" path="res://chat/ChatWindow.cs" id="1_d8jvm"] [ext_resource type="Script" uid="uid://cgn6wa7td0ekp" path="res://chat/ChatLog.cs" id="2_fkxbv"] -[ext_resource type="Script" uid="uid://tff5u6blrc1d" path="res://chat/ChatOptions.cs" id="2_lvlsn"] -[ext_resource type="Script" uid="uid://115ssbk8epio" path="res://chat/ChatInput.cs" id="4_yd183"] [node name="Chat Window" type="VBoxContainer"] anchors_preset = 15 @@ -16,7 +14,6 @@ script = ExtResource("1_d8jvm") [node name="Options" type="HBoxContainer" parent="."] layout_mode = 2 alignment = 2 -script = ExtResource("2_lvlsn") [node name="Label" type="Label" parent="Options"] layout_mode = 2 @@ -26,7 +23,7 @@ text = "Username:" custom_minimum_size = Vector2(120, 0) layout_mode = 2 -[node name="ColorPicker" type="ColorPickerButton" parent="Options"] +[node name="ColorPickerButton" type="ColorPickerButton" parent="Options"] layout_mode = 2 text = "Color" @@ -41,4 +38,3 @@ script = ExtResource("2_fkxbv") [node name="ChatInput" type="LineEdit" parent="."] layout_mode = 2 -script = ExtResource("4_yd183") diff --git a/client/spacetime/Program.cs b/client/spacetime/Program.cs new file mode 100644 index 0000000..71c9efd --- /dev/null +++ b/client/spacetime/Program.cs @@ -0,0 +1,123 @@ +// using SpacetimeDB; +// using SpacetimeDB.Types; +// using System; +// using System.Collections.Concurrent; +// +// // 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"); +// // Builds and connects to the database +// DbConnection? conn = null; +// conn = ConnectToDB(); +// // Registers 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 database and module. +// const string HOST = "http://localhost:3000"; +// +// /// The database name we chose when we published our module. +// const string DB_NAME = "quickstart-chat"; +// +// /// Load credentials from a file and connect to the database. +// DbConnection ConnectToDB() +// { +// DbConnection? conn = null; +// conn = DbConnection.Builder() +// .WithUri(HOST) +// .WithModuleName(DB_NAME) +// .WithToken(AuthToken.Token) +// .OnConnect(OnConnected) +// .OnConnectError(OnConnectError) +// .OnDisconnect(OnDisconnected) +// .Build(); +// return conn; +// } +// +// /// Our `OnConnected` callback: save our credentials to a file. +// void OnConnected(DbConnection conn, Identity identity, string authToken) +// { +// local_identity = identity; +// AuthToken.SaveToken(authToken); +// } +// +// /// 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; +// } +// +// /// 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) +// { +// Console.WriteLine($"{UserNameOrIdentity(insertedValue)} is online"); +// } +// } +// +// /// 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) +// { +// 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."); +// } +// } +// } diff --git a/client/spacetime/Program.cs.uid b/client/spacetime/Program.cs.uid new file mode 100644 index 0000000..700ee94 --- /dev/null +++ b/client/spacetime/Program.cs.uid @@ -0,0 +1 @@ +uid://dtnd8t4orjlip