{"id":25908166,"url":"https://github.com/bonnyad9/ipk24-chat-client","last_synced_at":"2025-08-25T12:29:28.248Z","repository":{"id":237299948,"uuid":"763593022","full_name":"BonnyAD9/ipk24-chat-client","owner":"BonnyAD9","description":"First project to the subject IPK.","archived":false,"fork":false,"pushed_at":"2024-03-29T16:01:54.000Z","size":149,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-03T07:17:09.649Z","etag":null,"topics":["chat","chat-client","csharp","tcp","tcp-client","udp","udp-client"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BonnyAD9.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-26T15:28:01.000Z","updated_at":"2024-04-30T17:13:35.000Z","dependencies_parsed_at":"2024-04-30T19:42:33.778Z","dependency_job_id":null,"html_url":"https://github.com/BonnyAD9/ipk24-chat-client","commit_stats":null,"previous_names":["bonnyad9/ipk24-chat-client"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/BonnyAD9/ipk24-chat-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BonnyAD9%2Fipk24-chat-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BonnyAD9%2Fipk24-chat-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BonnyAD9%2Fipk24-chat-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BonnyAD9%2Fipk24-chat-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BonnyAD9","download_url":"https://codeload.github.com/BonnyAD9/ipk24-chat-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BonnyAD9%2Fipk24-chat-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272064200,"owners_count":24866897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","chat-client","csharp","tcp","tcp-client","udp","udp-client"],"created_at":"2025-03-03T07:17:11.569Z","updated_at":"2025-08-25T12:29:28.200Z","avatar_url":"https://github.com/BonnyAD9.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ipk24chat-client\n**Documentation**\n\nAuthor: **xstigl00**\n\n## Contents\n- [About](#about)\n- [Code structure](#code-structure)\n    - [`Ipk24ChatClient`](#ipk24chatclient)\n        - [Program entry point](#program-entry-point)\n        - [`ChatClient`](#chatclient)\n        - [Message records](#message-records)\n        - [User input in interactive terminal](#user-input-in-interactive-terminal)\n    - [`IpkChatClient.Udp`](#ipkchatclientudp)\n        - [`UdpChatClient`](#udpchatclient)\n            - [Sending](#sending)\n            - [Receiving](#receiving)\n    - [`IpkChatClient.Tcp`](#ipk24chatclienttcp)\n    - [`IpkChatClient.Cli`](#ipk24chatclientcli)\n- [Testing](#testing)\n- [Extra functionality](#extra-functionality)\n\n\n## About\nThe project is chat client using the `IPK24-CHAT` protocol in both its `UDP`\nand `TCP` variant.\n\nI decided to implement this project in C# because I know the language well and\nits standard library has lots of features that I can just use without the need\nto implement them.\n\nThe implementation uses only single thread. In order to achieve that, all\noperations are non-blocking. Reading from console is done by setting terminal\nto raw mode (C# does this by default) and than reading one key at a time only\nwhen there are any available keys. Non-blocking receiving is achieved by\nchecking whether there are any new data before calling the function that\nreceives.\n\n## Code structure\nThe code is divided into 4 namespaces:\n- `Ipk24ChatClient`: the main namespace, contains the `Main` function, class\n  `ConsoleReader` for non-blocking reading and writing to console and classes\n  that are common for both the TCP and UDP variant of the protocol.\n- `Ipk24ChatClient.Cli`: Contains structures and logic for parsing command line\n  arguments.\n- `Ipk24ChatClient.Udp`: Logic for the UDP variant.\n- `Ipk24ChatClient.Tcp`: Logic for the TCP variant.\n\nAll errors are propagated using exceptions.\n\n### `Ipk24ChatClient`\nThis namespace is the base of the project. It contains the `Main` function,\nlogic for the interactive console and structures common for UDP and TCP variant\nof the protocol.\n\n#### Program entry point\nThe main function is located in the file *Program.cs*. The `Main` function\nitself is just a wrapper around the function `Start`. Configuration useful for\nthe man loop is stored in static fields and properties of the class `Program`.\n\nThe main loop of the program is in the static method `Program.RunClient`. In\neach iteration of the loop, it checks for the user input and than for new data\nfrom the server. These operations are non-blocking. To prevent the CPU from\ndoing a lot of work for nothing, the loop also contains `Thread.sleep` that\nby default sleeps for 10 ms.\n\nColored printing is achieved by setting static fields that represent color\nmodes either as empty strings when colors are disabled, or with their\nrespective ansi codes when colored printing is enabled. This is implemented in\nthe static function `Program.InitANSI`.\n\n#### `ChatClient`\nThis is abstract class that represents chat client. It is independent of the\nprtocol variant. Its main purpose is to track and transition between the client\nstates and to check whether operation requested by user is valid in the current\nstate.\n\nIt also decides when it is apropriate to send error messages to the server.\n\nUser input is validated using static methods in the static class `Validators`.\n\n#### Message records\nMessages received by the server are represented by record classes. They are\ndeclared in `Message.cs`\n\n#### User input in interactive terminal\nUser input and output is handled by the class `ConsoleReader`. It provides\nmethod for non-blocking variant of `Console.ReadLine` and methods that can\nprint to console at the same time that user types to the console.\n\nUser input is readed one key at a time from the terminal that is set raw mode.\nThe standard C# library provides basic logic for manipulating the raw terminal,\nbut it has only few features and some of them are slow, so I decided to use the\nnuget package `Bny.Console` for aditional functionality.\n\nApart from reading from the standard input, `ConsoleReader` also handles\nspecial input from the user (such as moving the cursor and editing what was\nalready typed) and ensures that the text and cursor position in the console is\nproperly displayed to the user.\n\n### `IpkChatClient.Udp`\nThis namespace is located in the folder `Udp` and contains logic specific to\nthe UDP variant of the protocol. The logic is more complicated compared to the\nTCP variant so it is split into several units.\n\nParsing of messages from binary is done by static class `MessageParser`.\n\nSerializing of messages to binary is done by static methods on the record\n`SentMessage`.\n\n#### `UdpChatClient`\nThis class contains the main logic of the UDP client and implements the\nabstract class `ChatClient`.\n\nIt handles the lower level details of the protocol that are specific to the UDP\nvariant such as confirmations (sending/receiving) and retransmition of messages\nfor which there was no confirmation in the specified timeout.\n\nThe logic is achieved by using two buffers for both received and sent messages\n(4 total). One queue and one list for each direction.\n\n##### Sending\nWhen sending message it is first stored in a queue where it waits to be sent.\nIt is not sent imidietely because the specification doesn't say how many\nunconfirmed messages may be sent at a time and so I decided that this is\nimplicitly supposed to be only one message (Next message is sent only after\nthe previous has been confirmed.). This can be changed using one of the\nextensions.\n\nWhen message is sent to the server it is stored in the list where it waits to\nbe confirmed or potentially retransmitted if timeout is reached.\n\n##### Receiving\nAll received messages are stored in the list. Every time new messages are\nreceived, the client checks their *id*. If the *id* matches *id* of the next\nexpected message, it is moved to the queue where it waits to be readed trough\nthe `ChatClient` abstract method implementation.\n\nIn the reference server, there is a bug that it sends its *id* in wrong byte\norder. To make the client compatible with the reference server and also comply\nwith the specification, there is a method `CheckEndianness` that swaps the\nendianness of the *id* if the other endianness seems more likely to be correct.\n\n### `Ipk24ChatClient.Tcp`\nCompared to UDP the TCP variant is much simpler. The main logic is in the class\n`TcpChatClient` that implements the abstract class `ChatClient`.\n\nBecause TCP is reliable, there is no special logic for confirmations or\nreordering of the messages, so the serialization of the messages to binary is\ndone directly in the implementation of the abstract methods.\n\nOn the other hand, there are no boundaries between data so there is special\nclass for parsing the messages: `MessageParser`. The parser reads from the TCP\nstream and parses the data. It also handles situations where whole message may\nnot be received at once and it is necesary to wait for new data.\n\n### `Ipk24ChatClient.Cli`\nThis namespace contains the logic for parsing the command line argumens. The\nparsing logic is implemented in methods of the class `Args`. The class itself\nthan holds the information about the configuration from the command line.\n\n## Testing\nCore networking functionality is tested using unit tests in the folder `tests`.\n\nI also checked functionality of the app as whole manually with the reference\nserver.\n\n## Extra functionality\n- **Useful extra prints**\n    - enabled with flag `-e` or by setting environment variable `IPK_EXTEND` to\n      `YES`\n- **Colored printing**\n    - enabled automatically when *extra prints* are enabled and the standard\n    output is terminal.\n    - can be also forced by `--color=always`\n- **Setting how many unconfirmend UDP messages may be sent**\n    - can be set with the flag `-w`.\n    - This is by default `1`.\n+ Command `/clear` and `/claer` (I often mistype *clear* in this way)\n\nAll of the extensions are also documented in the help commands.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbonnyad9%2Fipk24-chat-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbonnyad9%2Fipk24-chat-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbonnyad9%2Fipk24-chat-client/lists"}