{"id":20770700,"url":"https://github.com/ably/delta-codec-dotnet","last_synced_at":"2025-04-30T14:02:10.175Z","repository":{"id":45892680,"uuid":"222430984","full_name":"ably/delta-codec-dotnet","owner":"ably","description":null,"archived":false,"fork":false,"pushed_at":"2023-06-05T09:15:31.000Z","size":2499,"stargazers_count":3,"open_issues_count":2,"forks_count":4,"subscribers_count":25,"default_branch":"main","last_synced_at":"2025-03-30T16:46:34.434Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ably.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-11-18T11:16:21.000Z","updated_at":"2023-03-13T09:54:04.000Z","dependencies_parsed_at":"2024-11-18T00:04:09.836Z","dependency_job_id":null,"html_url":"https://github.com/ably/delta-codec-dotnet","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/ably%2Fdelta-codec-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ably","download_url":"https://codeload.github.com/ably/delta-codec-dotnet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251716504,"owners_count":21632136,"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":[],"created_at":"2024-11-17T12:11:28.346Z","updated_at":"2025-04-30T14:02:10.102Z","avatar_url":"https://github.com/ably.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dotnet Codec Library for the VCDIFF Delta Format\n\nC# VCDiff decoder library used internally by the Ably client library. The implementation includes the Vcdiff code from \"Miscellaneous Utility Library\" authored by [Jon Skeet and Marc Gravell](https://jonskeet.uk/csharp/miscutil/) and forked by Ably.\n\n## Supported platforms\n\nThe library is targeting netstandard 1.3.\n\n## General Use\n\nThe `DeltaDecoder` class is an entry point to the public API. It provides a stateful way of applying a stream of `vcdiff` deltas.\n\n`DeltaDecoder` can do the necessary bookkeeping in the scenario where a number of successive deltas/patches have to be applied where each of them represents the difference to the previous one (e.g. a sequence of messages each of which represents a set of mutations to a given object; i.e. sending only the mutations of an object instead the full object each time).\n\nIn order to benefit from the bookkeeping provided by the `DeltaDecoder` class, one has to first provide the base payload that the first delta would be generated against. That could be done using the `SetBase` method. `SetBase` method accepts a `byte[]` for the base payload. We have some helper methods you can use `DataHelpers.ConvertToByteArray` and `DataHelpers.TryConvertToDeltaByteArray`. These will convert object which can be either `byte[]`, `utf-8 string` or `base64 encoded string`. Usually the base payload comes from string or binary transport so it can be used easily.\nThe most simple flavor of `setBase` is:\n\n```\nvar decoder = new DeltaDecoder();\nbyte[] basePayload = GetPayload(); // Get the first payload\ndecoder.SetBase(basePayload);\n```\n\nOnce the decoder is initialized like this it can be used to apply a stream of deltas/patches each one resulting in a new full payload.\n\n```\nvar result = decoder.ApplyDelta(vcdiffDelta);\n```\n\n`ApplyDelta` could be called as many times as needed. The `DeltaDecoder` will automatically retain the last delta application result and use it as a base for the next delta application. Thus it allows applying an infinite sequence of deltas.\n\n`result` would be of type `DeltaApplicationResult`. That is a convenience class that allows interpreting the result in various data formats - string, byte[], etc.\n\n`DeltaDecoder` also supports delta streams that have unique Ids. You can call `SetBase` and `ApplyDelta` passing these ids and the decoder will validate whether the supplied Id is the same as what is expected. E.g.\n\n\n```\ndecoder.SetBase(payload, baseId);\n\nvar result = decoder.ApplyDelta(vcdiffDelta,\n                deltaID,/*any unique identifier of the delta there might be*/\n                baseID /*any unique identifier of the object this delta was generated against there might be */);\n```\n\n## Common Use Cases\n\n### MQTT with Binary or String Payload\n\nThe samples are using [MQTTnet](https://www.nuget.org/packages/MQTTnet/) nuget package.\n\n```\nusing System;\nusing System.Text;\nusing System.Threading.Tasks;\nusing MQTTnet;\nusing MQTTnet.Client;\nusing MQTTnet.Client.Options;\n\npublic class ConsumerSample\n{\n    private IMqttClientOptions _options;\n    private IMqttClient _client;\n    private DeltaDecoder _decoder = new DeltaDecoder();\n\n    public ConsumerSample()\n    {\n        var ablyApiKey = \"REPLACE WITH API KEY\";\n        var keyParts = ablyApiKey.Split(\":\");\n        var factory = new MqttFactory();\n        _options = new MqttClientOptionsBuilder()\n            .WithClientId(\"consumer\")\n            .WithTcpServer(\"mqtt.ably.io\", 8883)\n            .WithCredentials(keyParts[0], keyParts[1])\n            .WithTls()\n            .Build();\n        _client = factory.CreateMqttClient();\n        _client.UseApplicationMessageReceivedHandler(OnSubscriberMessageReceived);\n        _client.UseConnectedHandler(e =\u003e\n        {\n            Console.WriteLine(\"### CONNECTED WITH SERVER ###\");\n        });\n    }\n\n    private string ChannelName =\u003e $\"[?delta=vcdiff]{Program.ChannelName}\";\n\n    public async Task Start()\n    {\n        Console.WriteLine(\"Connecting Consumer\");\n        await _client.ConnectAsync(_options);\n        await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic(ChannelName).Build());\n        Console.WriteLine(\"### SUBSCRIBED ###\");\n    }\n\n    private void OnSubscriberMessageReceived(MqttApplicationMessageReceivedEventArgs messageArgs)\n    {\n        var message = DecodeStringMessage();\n        var stats =\n            $\"Payload Size: {messageArgs.ApplicationMessage.Payload.Length}. Decoded Message Size: {message.Length}. Saving: {message.Length - messageArgs.ApplicationMessage.Payload.Length}\";\n        var item = $\"Timestamp: {DateTime.Now:O} | Stats: {stats} | Topic: {messageArgs.ApplicationMessage.Topic} | Payload: {message} | QoS: {messageArgs.ApplicationMessage.QualityOfServiceLevel}\";\n        Console.WriteLine(item);\n\n        string DecodeStringMessage()\n        {\n            try\n            {\n                var payload = messageArgs.ApplicationMessage.Payload;\n                if (DeltaDecoder.IsDelta(payload))\n                {\n                    var result = _decoder.ApplyDelta(payload);\n                    return result.AsUtf8String();\n                }\n\n                _decoder.SetBase(payload);\n\n                return Encoding.UTF8.GetString(payload);\n            }\n            catch (Exception e)\n            {\n                Console.WriteLine(e);\n                return \"\";\n            }\n        }\n    }\n}\n```\n\n## Support, feedback and troubleshooting\n\nPlease visit https://ably.com/support for access to our knowledge base and to ask for any assistance.\n\nYou can also view the [community reported GitHub issues](https://github.com/ably/delta-codec-dotnet/issues).\n\nTo see what has changed in recent versions, see the [CHANGELOG](CHANGELOG.md).\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Ensure you have added suitable tests and the test suite is passing(`dotnet test`)\n5. Push to the branch (`git push origin my-new-feature`)\n6. Create a new Pull Request\n\n## Release Process\n\n- Make sure the tests are passing in ci for the branch you're building\n- Update the CHANGELOG.md with any customer-affecting changes since the last release\n\n## License\n\nCopyright (c) 2020 Ably Real-time Ltd, Licensed under the Apache License, Version 2.0.  Refer to [LICENSE](LICENSE) for the license terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fdelta-codec-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fably%2Fdelta-codec-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fdelta-codec-dotnet/lists"}