{"id":13723528,"url":"https://github.com/Mazyod/PhoenixSharp","last_synced_at":"2025-05-07T17:30:32.801Z","repository":{"id":13536792,"uuid":"74701066","full_name":"Mazyod/PhoenixSharp","owner":"Mazyod","description":"C# Phoenix Channels client. Unity Compatible.","archived":false,"fork":false,"pushed_at":"2023-07-24T18:31:59.000Z","size":692,"stargazers_count":168,"open_issues_count":7,"forks_count":27,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-05-04T04:53:57.162Z","etag":null,"topics":["csharp","networking","phoenix","phoenix-framework","presence","realtime","unity","unity3d","websockets"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mazyod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-24T19:47:16.000Z","updated_at":"2025-04-16T01:24:25.000Z","dependencies_parsed_at":"2022-07-29T12:49:37.186Z","dependency_job_id":null,"html_url":"https://github.com/Mazyod/PhoenixSharp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mazyod%2FPhoenixSharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mazyod%2FPhoenixSharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mazyod%2FPhoenixSharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mazyod%2FPhoenixSharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mazyod","download_url":"https://codeload.github.com/Mazyod/PhoenixSharp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252926477,"owners_count":21826320,"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","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":["csharp","networking","phoenix","phoenix-framework","presence","realtime","unity","unity3d","websockets"],"created_at":"2024-08-03T01:01:42.592Z","updated_at":"2025-05-07T17:30:32.527Z","avatar_url":"https://github.com/Mazyod.png","language":"C#","readme":"\n![Imgur](http://i.imgur.com/B8ClrWe.png)\n\n[![.NET](https://github.com/Mazyod/PhoenixSharp/actions/workflows/dotnet.yml/badge.svg)](https://github.com/Mazyod/PhoenixSharp/actions/workflows/dotnet.yml) \u0026nbsp; ![net](https://img.shields.io/badge/version-netstandard%202.0-blue)\n\nA C# Phoenix Channels client. Unity Compatible. Proudly powering [Dama King][level3-website].\n\n\u003e Graphic is a shameless mix between unity, phoenix logos. Please don't sue me. Thanks.\n\n+ [**Overview**](#overview): What this library is about.\n+ [**Getting Started**](#getting-started): A quicky guide on how to use this library.\n+ [**PhoenixJS**](#phoenixjs): How this library differs from PhoenixJs.\n+ [**Tests**](#tests): How to run the tests to make sure we're golden.\n+ [**Dependencies**](#dependencies): A rant about dependencies.\n+ [**Unity**](#unity): Important remarks for Unity developers.\n\n## Overview\n\nPhoenixSharp has the following main goals:\n- Aspires to be the defacto Phoenix C# client.\n- Portable enough to work out of the box in Unity and other C# environments.\n\nIn order to achieve the goals stated, it is necessary to:\n- Maintain a close resemblance to the Phoenix.js implementation.\n- Engage the community to accommodate different requirements based on various environments.\n\n## Getting Started\n\n**Migrating from older versions? [See our migration guide][migration-guide]**\n\nFor now, you can use git submodules or simply download the sources and drop them in your project.\n\nOnce you grab the source, you can look at `IntegrationTests.cs` for a full example. Otherwise, keep reading to learn more.\n\n### Required Interfaces\n\n#### Implementing `IWebsocketFactory` and `IWebsocket`\n\nThe library requires you to implement `IWebsocketFactory` and `IWebsocket` in order to provide a websocket implementation of your choosing.\n\nUnder the PhoenixTests/WebSocketImpl folder, you'll find a few sample implementations of these interfaces which you could simply copy to your project as needed.\n\n\u003e [!WARNING]\\\n\u003e DotNetWebSocket may be unstable. Please consider using BestHTTP, WebSocketSharp, or contributing fixes, or adding new implementations 🤌\n\n#### Implementing `IMessageSerializer` and `IJsonBox`\n\n`IMessageSerializer` is the interface that allows you to customize the serialization of your Phoenix messages.\n\n`IJsonBox` wraps the underlying mutable JSON object, such as JToken in NewtonSoft.Json and JsonElement/JsonObject in System.Text.Json/System.Text.Json.Nodes.\n\nThe library ships with a default implementation: `JsonMessageSerializer`. It relies on [Newtonsoft.Json][newtonsoft-website] to provide JSON serialization based on [Phoenix V2 format][phoenix-v2-serialization-format]. The implementation is self-contained in a single file. This means, by removing that one file, you can decouple your code from Newtonsoft.Json if you like.\n\n### Establishing a Connection\n\n#### Creating a Socket\n\nOnce you have your websocket and serializer implementation ready, you can proceed to create a socket object. A `Phoenix.Socket` instance represents a connection to a Phoenix server.\n\nIn order to ensure that socket connections are self-contained, we pass the socket parameters on initialization. Trying to connect with different parameters requires a new socket instance.\n\n```cs\nvar socketOptions = new Socket.Options(new JsonMessageSerializer());\nvar socketAddress = \"ws://my-awesome-app.com/socket\";\nvar socketFactory = new WebsocketSharpFactory();\nvar socket = new Socket(socketAddress, null, socketFactory, socketOptions);\n\nsocket.OnOpen += onOpenCallback;\nsocket.OnMessage += onMessageCallback;\n\nsocket.Connect();\n```\n\n#### Joining a Channel\n\nOnce the socket is created, you can now join a channel. The API is so simple, you could explore it yourself with auto-complete, but here's a quick example:\n\n```cs\n// initialize a channel with topic and parameters\nvar roomChannel = socket.Channel(\n  \"tester:phoenix-sharp\",\n  channelParams\n);\n\n// prepare any event callbacks\n// e.g. listen to phx_error inbound event\nroomChannel.On(\n  Message.InBoundEvent.Error,\n  message =\u003e errorMessage = message\n);\n// ... listen to a custom event\nroomChannel.On(\n  \"after_join\",\n  message =\u003e afterJoinMessage = message\n);\n// ... you can also use a generic event callback\n// this will parse the message payload automatically\nroomChannel.On(\n  \"custom_event\",\n  (CustomPayload payload) =\u003e Handle(payload)\n);\n\n// join the channel, handling the reply response as needed\n// here, we assume JoinResponse and ChannelError are defined\nroomChannel.Join()\n  .Receive(\n    ReplyStatus.Ok, \n    reply =\u003e okResponse = reply.Response.Unbox\u003cJoinResponse\u003e()\n  )\n  .Receive(\n    ReplyStatus.Error,\n    reply =\u003e errorResponse = reply.Response.Unbox\u003cChannelError\u003e()\n  );\n\n// push a message to the channel\nroomChannel\n  .Push(\"reply_test\", payload)\n  .Receive(\n    ReplyStatus.Ok, \n    reply =\u003e testOkReply = reply\n  );\n```\n\n#### Presence Tracking\n\nPresence is also supported by the library.\n\n```cs\nvar presence = new Presence(channel);\npresence.OnJoin += onJoinCallback;\npresence.OnLeave += onLeaveCallback;\n```\n\n## PhoenixJS\n\nThe difference between PhoenixJS and PhoenixSharp can be observed in the following areas:\n- The static typing nature of C#, and in contrast, the dynamic nature of JavaScript.\n  + Defining types for various constructs.\n  + Adding generic callbacks to automatically extract and parse payloads.\n  + Using delegates, instead of callbacks, to handle events.\n- The flexibility required to allow PhoenixSharp to be adapted to different environments.\n  + Abstracting away the websocket implementation.\n  + Pluggable \"Delayed Executor\", useful for Unity developers.\n  + Ability to disable socket reconnect / channel rejoin.\n- The lack of features in PhoenixSharp due to lesser popularity and contributions.\n\n## Tests\n\nIn order to run the integration tests specifically, you need to make sure you have a phoenix server running and point the `host` in the integration tests to it.\n\nI've published [the code for the phoenix server I'm using to run the tests against here][phoenix-integration-tests-repo]. However, if for any reason you don't want to run the phoenix server locally, you can use the following host:\n\n```\nphoenix-integration-tester.herokuapp.com\n```\n\n## Dependencies\n\n### Production Dependencies\n\n1. (Optional) Newtonsoft.Json\n\n### Development/Test Dependencies\n\n1. NUnit\n2. WebSocketSharp\n3. Newtonsoft.Json\n\n#### Details about the Dependencies\n\n`Newtonsoft.Json` is marked as optional because it can easily be replaced with another implementation as needed. However, this flexibility when it comes to the serialization process comes at a cost.\n\nDue to the decoupling of the serializer from the rest of the implementation, it left use with an unfortunate side-effect. The use of `object` as the type of `payload` and `response` properties on the `Message` and `Reply` classes, respectively.\n\nWe try to mitigate the effects of this \"type loss\" issue by providing higher-level APIs that abstract away the need to handle the `object` types directly.\n\n## Unity\n\nFirst off, it would very much be worth your while to read [Microsoft's documentation on Unity's scripting upgrade][microsoft-docs-unity]. It highlights the main opportunities and challenges, which is also an inspiration for this library to take things further with the new scripting upgrade.\n\n#### Main Thread Callbacks\n\nOne of the core components of the library is a mechanism that mimics javascipt's `setTimeout` and `setInterval` functions. It is used to trigger timeout event in case we don't get a response back in time.\n\nBy default, the library uses the `System.Threading.Task` class to schedule the callbacks. Based on our tests, this works well in Unity out-of-the-box thanks to the `SynchronizationContext`.\n\nIf you'd rather not use the `Task` based executor, you can easily replace it with a custom implementation by implementing the `IDelayedExecutor` interface. For example, you can use the `CoroutineDelayedExecutor` available in the Reference directory of this repo. Another option is to provide a custom implementation based on [UniTask][unitask-repo] if you see it more performant and beneficial to your project.\n\n#### Useful Libraries\n\nI'm personally shipping this library with my Unity game, so you can rest assured it will always support Unity. Here are some important notes I learned from integrating PhoenixSharp with Unity:\n\n- **BestHTTP websockets** instead of Websocket-sharp. It's much better maintained and doesn't require synchronizing callbacks from the socket to the main thread. Websocket-sharp does need that.\n- **Json.NET** instead of Newtonsoft.Json, that's what I'm using. I've experienced weird issues in the past with the opensource Newtonsoft.Json on mobile platforms.\n\n**NOTE:**\n- Many people are using BestHTTP, so I figured it would be useful to add that integration separately in the repo, for people to use. See the directory, `Reference/Unity/BestHTTP`.\n- Under `Reference/Unity` directory as well, you will find a sample implementation for `IDelayedExecutor` that can be used in Unity projects.\n\n## Contributions\n\nWhether you open new issues or send in some PRs .. It's all welcome here!\n\n## Author\n\nMaz (Mazyad Alabduljaleel)\n\n[level3-website]: http://level3.io\n[newtonsoft-website]: https://www.newtonsoft.com/json\n[microsoft-docs-unity]: https://docs.microsoft.com/en-us/visualstudio/gamedev/unity/unity-scripting-upgrade\n[unitask-repo]: https://github.com/Cysharp/UniTask\n[migration-guide]: https://github.com/Mazyod/PhoenixSharp/blob/master/Migration.md\n[phoenix-integration-tests-repo]: https://github.com/Mazyod/phoenix-integration-tester\n[phoenix-v2-serialization-format]: https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/socket/serializers/v2_json_serializer.ex\n","funding_links":[],"categories":["Languages Integration","Multiplayer","Unity","Open Source Repositories"],"sub_categories":["Networking"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMazyod%2FPhoenixSharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMazyod%2FPhoenixSharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMazyod%2FPhoenixSharp/lists"}