diff --git a/BrazChat.sln b/BrazChat.sln new file mode 100644 index 0000000..d34e957 --- /dev/null +++ b/BrazChat.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32616.157 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrazChatServer", "BrazChat\BrazChatServer.csproj", "{4C021E19-57F4-490E-ADE7-13064329DE7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrazChatClient", "BrazChatClient\BrazChatClient.csproj", "{B21A1847-29C5-4AD2-BE79-ADBA5FA89578}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4C021E19-57F4-490E-ADE7-13064329DE7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C021E19-57F4-490E-ADE7-13064329DE7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C021E19-57F4-490E-ADE7-13064329DE7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C021E19-57F4-490E-ADE7-13064329DE7D}.Release|Any CPU.Build.0 = Release|Any CPU + {B21A1847-29C5-4AD2-BE79-ADBA5FA89578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B21A1847-29C5-4AD2-BE79-ADBA5FA89578}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B21A1847-29C5-4AD2-BE79-ADBA5FA89578}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B21A1847-29C5-4AD2-BE79-ADBA5FA89578}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0FB81DD0-9A62-4AEA-A1B1-B165821EB7BA} + EndGlobalSection +EndGlobal diff --git a/BrazChat/BrazChat.proto b/BrazChat/BrazChat.proto new file mode 100644 index 0000000..38c941e --- /dev/null +++ b/BrazChat/BrazChat.proto @@ -0,0 +1,73 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.brazchat"; +option java_outer_classname = "BrazChatProto"; +option objc_class_prefix = "BCH"; + +package brazchat; + + +service Messaging { + rpc Greeting (GreetingRequest) returns (GreetingReply) {} //Just a handshake to test connection + rpc GetMessages (GetMessagesRequest) returns (GetMessagesReply) {} + rpc GetMessageLogs (GetMessageLogsRequest) returns (GetMessageLogsReply) {} + rpc SendMessage (SendMessageRequest) returns (SendMessageReply) {} + rpc WelcomeMessage (WelcomeMessageRequest) returns (WelcomeMessageReply) {} +} + +message GreetingRequest{ +} + +message GreetingReply{ +} + +message GetMessagesRequest { + string clientUsername = 1; +} + + +message GetMessagesReply { + string confirmation = 1; + string messages = 2; +} + +message GetMessageLogsRequest{ + +} + +message GetMessageLogsReply{ + string log = 1; +} + +message SendMessageRequest { + string clientUsername = 1; + string message = 2; + string color = 3; +} + +message SendMessageReply{ + string confirmation = 1; +} + +message WelcomeMessageRequest{ //Feels redundant to have this here lol. +} + +message WelcomeMessageReply{ + string WelcomeLogo = 1; + string MOTD = 2; +} \ No newline at end of file diff --git a/BrazChat/BrazChatServer.csproj b/BrazChat/BrazChatServer.csproj new file mode 100644 index 0000000..a149ec2 --- /dev/null +++ b/BrazChat/BrazChatServer.csproj @@ -0,0 +1,29 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + Always + + + + diff --git a/BrazChat/Program.cs b/BrazChat/Program.cs new file mode 100644 index 0000000..34e97ea --- /dev/null +++ b/BrazChat/Program.cs @@ -0,0 +1,103 @@ +using System; +using System.IO; +using Grpc; +using Grpc.Core; +using Brazchat; +using Google.Protobuf; +using Newtonsoft.Json; + +namespace BrazChatServer +{ + class MessagingImpl : Messaging.MessagingBase + { + + public override Task SendMessage(SendMessageRequest request, ServerCallContext context) + { + string username = request.ClientUsername; + if(request.ClientUsername == null) + { + username = "Guest"; + } + Console.WriteLine($"Message received: '{request.Message}' from {username}"); + Utilities.LogNewMessage(request.Message, username); + return Task.FromResult(new SendMessageReply { Confirmation = "Successfully sent message to target!" }); + } + public override Task GetMessageLogs(GetMessageLogsRequest request, ServerCallContext context) + { + return Task.FromResult(new GetMessageLogsReply { Log = File.ReadAllText(@$"{Program.brazChatPath}\log\ChatLog.txt")}); + } + public override Task GetMessages(GetMessagesRequest request, ServerCallContext context) + { + List text = File.ReadLines(@$"{Program.brazChatPath}\log\ChatLog.txt").Reverse().Take(20).Reverse().ToList(); + string messages = string.Join("\n", text); + return Task.FromResult(new GetMessagesReply { Confirmation = "Successful!", Messages = messages}); + } + public override Task WelcomeMessage(WelcomeMessageRequest request, ServerCallContext context) + { + return Task.FromResult(new WelcomeMessageReply {WelcomeLogo = Figgle.FiggleFonts.Banner3D.Render("BrazChat") , MOTD = File.ReadAllText(@$"{Program.brazChatPath}\config\MOTD.txt") }); //Make this read the logo from a file in the future. + } + public override Task Greeting(GreetingRequest request, ServerCallContext context) + { + return Task.FromResult(new GreetingReply { }); + } + + } + class Program + { + public static string brazChatPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + const int Port = 50051; + public static void Main(string[] args) + { + CheckNecessaryFiles(); + List configItems = new List(); + using (StreamReader r = new StreamReader(@$"{Program.brazChatPath}\config\config.json")) + { + string json = r.ReadToEnd(); + configItems = JsonConvert.DeserializeObject>(json); + } + Server server = new Server + { + Services = { Messaging.BindService(new MessagingImpl()) }, + Ports = { new ServerPort(configItems[0].Host, configItems[0].Port, ServerCredentials.Insecure)} + }; + server.Start(); + Console.WriteLine("Server running. Press any key to stop server."); + Console.ReadKey(); + } + public static void CheckNecessaryFiles() + { + if (File.Exists(@$"{Program.brazChatPath}\config\MOTD.txt") == false) + { + Directory.CreateDirectory($@"{Program.brazChatPath}\config"); + File.WriteAllText(@$"{Program.brazChatPath}\config\MOTD.txt", "Default MOTD"); + } + if (File.Exists(@$"{Program.brazChatPath}\config\config.json") == false) + { + Console.WriteLine("No config file found! Exiting."); + Environment.Exit(2); + } + if (File.Exists(@$"{Program.brazChatPath}\log\ChatLog.txt") == false) + { + Directory.CreateDirectory($@"{Program.brazChatPath}\log"); + File.WriteAllText(@$"{Program.brazChatPath}\log\ChatLog.txt", "Say something!\n"); + } + } + } + class Utilities + { + public static void LogNewMessage(string message, string username) + { + string path = @$"{Program.brazChatPath}\log\ChatLog.txt"; + + File.AppendAllText(path, $"{username}: {message}\n"); + } + } + + public class Config + { + public string Host; + public int Port; + } +} + + diff --git a/BrazChat/config/MOTD.txt b/BrazChat/config/MOTD.txt new file mode 100644 index 0000000..a847678 --- /dev/null +++ b/BrazChat/config/MOTD.txt @@ -0,0 +1,2 @@ +This is a test motd! +New linerino!! \ No newline at end of file diff --git a/BrazChat/config/config.json b/BrazChat/config/config.json new file mode 100644 index 0000000..ebebdf2 --- /dev/null +++ b/BrazChat/config/config.json @@ -0,0 +1,6 @@ +[ + { + "host": "localhost", + "port": 50051 + } +] \ No newline at end of file diff --git a/BrazChatClient/BrazChat.proto b/BrazChatClient/BrazChat.proto new file mode 100644 index 0000000..38c941e --- /dev/null +++ b/BrazChatClient/BrazChat.proto @@ -0,0 +1,73 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.brazchat"; +option java_outer_classname = "BrazChatProto"; +option objc_class_prefix = "BCH"; + +package brazchat; + + +service Messaging { + rpc Greeting (GreetingRequest) returns (GreetingReply) {} //Just a handshake to test connection + rpc GetMessages (GetMessagesRequest) returns (GetMessagesReply) {} + rpc GetMessageLogs (GetMessageLogsRequest) returns (GetMessageLogsReply) {} + rpc SendMessage (SendMessageRequest) returns (SendMessageReply) {} + rpc WelcomeMessage (WelcomeMessageRequest) returns (WelcomeMessageReply) {} +} + +message GreetingRequest{ +} + +message GreetingReply{ +} + +message GetMessagesRequest { + string clientUsername = 1; +} + + +message GetMessagesReply { + string confirmation = 1; + string messages = 2; +} + +message GetMessageLogsRequest{ + +} + +message GetMessageLogsReply{ + string log = 1; +} + +message SendMessageRequest { + string clientUsername = 1; + string message = 2; + string color = 3; +} + +message SendMessageReply{ + string confirmation = 1; +} + +message WelcomeMessageRequest{ //Feels redundant to have this here lol. +} + +message WelcomeMessageReply{ + string WelcomeLogo = 1; + string MOTD = 2; +} \ No newline at end of file diff --git a/BrazChatClient/BrazChatClient.csproj b/BrazChatClient/BrazChatClient.csproj new file mode 100644 index 0000000..12dee1a --- /dev/null +++ b/BrazChatClient/BrazChatClient.csproj @@ -0,0 +1,22 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/BrazChatClient/Program.cs b/BrazChatClient/Program.cs new file mode 100644 index 0000000..4f3d88e --- /dev/null +++ b/BrazChatClient/Program.cs @@ -0,0 +1,213 @@ +using Brazchat; +using Grpc.Core; + +namespace BrazChatClient +{ + class Program + { + public static string username = ""; + public static string host = ""; + public static void Main(string[] args) + { + StartScreen(); + } + + public static void StartScreen() + { + Console.Clear(); + Console.WriteLine("Please enter a hostname (ip:port)"); + host = Console.ReadLine(); + Console.WriteLine(host); + try + { + Channel channel = new Channel(host, ChannelCredentials.Insecure); + + var client = new Messaging.MessagingClient(channel); + + var reply = client.Greeting(new GreetingRequest { }); + + channel.ShutdownAsync().Wait(); + WelcomeScreen(); + } + catch (RpcException) + { + Console.WriteLine("Invalid host! Press any key to try again."); + Console.ReadKey(); + Console.Clear(); + StartScreen(); + } + } + public static void WelcomeScreen() + { + Console.ForegroundColor = ConsoleColor.Green; + Console.Clear(); + string[] WelcomeMessage = GetWelcomeMessage(); + Console.WriteLine(WelcomeMessage[0]); + Console.WriteLine(WelcomeMessage[1]); + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine("Type in a username please!"); + username = Console.ReadLine(); + Console.WriteLine("Press any key to start sending messages!"); + Console.ReadKey(); + ChatScreen(); + } + public static void ChatScreen() + { + Console.Clear(); + while (!Console.KeyAvailable) + { + Console.CursorVisible = false; + CustomClear(); + Console.SetCursorPosition(0, 0); + var Messages = GetMessages(); + if (Messages.Confirmation == "Nope!") + { + ConnectionFailureScreen(); + } + else + { + Console.WriteLine($"{Messages.Messages}\n"); + //Console.WriteLine("----------------------"); + Console.WriteLine("T - Type message \nL - View logs"); + Thread.Sleep(100); + } + } + ConsoleKey input = Console.ReadKey(true).Key; + switch (input) + { + case ConsoleKey.T: + TypeScreen(); + break; + case ConsoleKey.L: + ChatLogScreen(); + break; + default: + ChatScreen(); + break; + } + } + + public static void TypeScreen() + { + Console.Clear(); + var Messages = GetMessages(); + if (Messages.Confirmation == "Nope!") + { + ConnectionFailureScreen(); + } + else + { + Console.WriteLine(Messages.Messages); + Console.WriteLine("Type your message!"); + string? message = Console.ReadLine(); + SendMessage(message); + ChatScreen(); + } + } + + public static void ChatLogScreen() + { + Console.Clear(); + var Messages = GetMessages(); + if(GetMessages().Confirmation == "Nope!") + { + Console.WriteLine("Connection to server lost! Press any key to return to connection menu!"); + ConnectionFailureScreen(); + }else{ + Console.WriteLine("--------------------------"); + Console.WriteLine(GetMessageLogs().Log); + Console.WriteLine("--------------------------"); + Console.ReadKey(); + Console.Clear(); + ChatScreen(); + } + } + + public static void ConnectionFailureScreen() + { + Console.Clear(); + Console.WriteLine("Connection to server lost! Press any key to return to connection menu!"); + Console.ReadKey(); + StartScreen(); + } + public static string[] GetWelcomeMessage() + { + try + { + Channel channel = new Channel(host, ChannelCredentials.Insecure); + + var client = new Messaging.MessagingClient(channel); + + var reply = client.WelcomeMessage(new WelcomeMessageRequest { }); + + string[] WelcomeMessage = { reply.WelcomeLogo, reply.MOTD }; + + channel.ShutdownAsync().Wait(); + return WelcomeMessage; + } + catch (RpcException) + { + string[] Fallback = { "Brazchat", "ERRORNOCONNECTION" }; //0 = Logo, 1 = MOTD + return Fallback; + } + } + public static void SendMessage(string? message) + { + try + { + Channel channel = new Channel(host, ChannelCredentials.Insecure); + + var client = new Messaging.MessagingClient(channel); + + var reply = client.SendMessage(new SendMessageRequest { ClientUsername = username, Message = message, Color = "Red" }); + Console.WriteLine("Message sent. Result:" + reply.Confirmation); + + channel.ShutdownAsync().Wait(); + } + catch (Grpc.Core.RpcException) + { + ConnectionFailureScreen(); + } + } + + public static GetMessagesReply GetMessages() + { + try + { + Channel channel = new Channel(host, ChannelCredentials.Insecure); + + var client = new Messaging.MessagingClient(channel); + String clientUsername = "Brazman"; + + var reply = client.GetMessages(new GetMessagesRequest { ClientUsername = clientUsername }); + channel.ShutdownAsync().Wait(); + return reply; + } + catch (Grpc.Core.RpcException) + { + //lord forgive me + var Fallback = new GetMessagesReply { Confirmation = "Nope!", Messages = "No connection! Retrying!\n" }; + return Fallback; + } + } + public static GetMessageLogsReply GetMessageLogs() + { + Channel channel = new Channel(host, ChannelCredentials.Insecure); + + var client = new Messaging.MessagingClient(channel); + + var reply = client.GetMessageLogs(new GetMessageLogsRequest { }); + channel.ShutdownAsync().Wait(); + return reply; + } + + public static void CustomClear() + { + Console.SetCursorPosition(0, 0); + for (int y = 0; y < Console.WindowHeight; y++) + Console.Write(new String(' ', Console.WindowWidth)); + Console.SetCursorPosition(0, 0); + } + + } +} \ No newline at end of file