Skip to content

Commit

Permalink
Feature/websocket enhancements (#20)
Browse files Browse the repository at this point in the history
* Initial WebSocket re-implementation

* Removed unused models.

* Resolved comments on pull request.

* Replaced .HasValue with != null for deserialized Result check.

* Updated documentation for WebSockets.
  • Loading branch information
brokenprogrammer authored Oct 5, 2020
1 parent 66d80d8 commit d2cf5c3
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 430 deletions.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Fortnox.NET/Fortnox.NET.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageVersion>1.1.0</PackageVersion>
<Version>1.1.0</Version>
<PackageVersion>2.0.0</PackageVersion>
<Version>2.0.0</Version>
<Title>Fortnox API SDK</Title>
<Authors>Zenta AB</Authors>
<Description>.NET bindings for the Fortnox API.</Description>
Expand Down
254 changes: 93 additions & 161 deletions Fortnox.NET/WebSockets/FortnoxWebSocketClient.cs

Large diffs are not rendered by default.

23 changes: 0 additions & 23 deletions Fortnox.NET/WebSockets/Models/WebSocketCommandResponse.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace FortnoxNET.WebSockets
namespace FortnoxNET.WebSockets.Models
{
public static class WebSocketCommands
{
Expand Down
27 changes: 0 additions & 27 deletions Fortnox.NET/WebSockets/Models/WebSocketEvent.cs

This file was deleted.

76 changes: 76 additions & 0 deletions Fortnox.NET/WebSockets/Models/WebSocketEventType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Runtime.Serialization;

namespace Fortnox.NET.WebSockets.Models
{
public enum WebSocketEventType
{
[EnumMember(Value = "invoice-created-v1")]
InvoiceCreated,
[EnumMember(Value = "invoice-updated-v1")]
InvoiceUpdated,
[EnumMember(Value = "invoice-cancelled-v1")]
InvoiceCancelled,
[EnumMember(Value = "invoicepayment-bookkeep-v1")]
InvoicePaymentBookkeep,
[EnumMember(Value = "invoicepayment-deleted-v1")]
InvoicePaymentDeleted,
[EnumMember(Value = "reminder-sent-v1")]
ReminderSentV1,
[EnumMember(Value = "reminder-sent-v2")]
ReminderSent,

[EnumMember(Value = "customer-created-v1")]
CustomerCreated,
[EnumMember(Value = "customer-updated-v1")]
CustomerUpdated,
[EnumMember(Value = "customer-deleted-v1")]
CustomerDeleted,

[EnumMember(Value = "order-created-v1")]
OrderCreated,
[EnumMember(Value = "order-updated-v1")]
OrderUpdated,
[EnumMember(Value = "order-cancelled-v1")]
OrderCancelled,

[EnumMember(Value = "offer-created-v1")]
OfferCreated,
[EnumMember(Value = "offer-updated-v1")]
OfferUpdated,

[EnumMember(Value = "article-created-v1")]
ArticleCreated,
[EnumMember(Value = "article-updated-v1")]
ArticleUpdated,
[EnumMember(Value = "article-deleted-v1")]
ArticleDeleted,

[EnumMember(Value = "currency-created-v1")]
CurrencyCreated,
[EnumMember(Value = "currency-updated-v1")]
CurrencyUpdated,
[EnumMember(Value = "currency-deleted-v1")]
CurrencyDeleted,

[EnumMember(Value = "termofdelivery-created-v1")]
TermOfDeliveryCreated,
[EnumMember(Value = "termofdelivery-updated-v1")]
TermOfDeliveryUpdated,
[EnumMember(Value = "termofdelivery-deleted-v1")]
TermOfDeliveryDeleted,

[EnumMember(Value = "wayofdelivery-created-v1")]
WayOfDeliveryCreated,
[EnumMember(Value = "wayofdelivery-updated-v1")]
WayOfDeliveryUpdated,
[EnumMember(Value = "wayofdelivery-deleted-v1")]
WayOfDeliveryDeleted,

[EnumMember(Value = "termsofpayments-created-v1")]
TermsOfPaymentsCreated,
[EnumMember(Value = "termsofpayments-updated-v1")]
TermsOfPaymentsUpdated,
[EnumMember(Value = "termsofpayments-deleted-v1")]
TermsOfPaymentDeleted,
}
}
54 changes: 54 additions & 0 deletions Fortnox.NET/WebSockets/Models/WebSocketResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

namespace Fortnox.NET.WebSockets.Models
{
public enum WebSocketResponseType
{
CommandResponse = 0,
EventResponse = 1,
}

public class WebSocketResponse
{
[JsonIgnore]
public WebSocketResponseType Type;

[JsonProperty(PropertyName = "response")]
public string Response { get; set; }

[JsonProperty(PropertyName = "result")]
public string Result { get; set; }

[JsonProperty(PropertyName = "tenantIds")]
public Dictionary<string, long> TenantIDs { get; set; }

[JsonProperty(PropertyName = "invalidTokens")]
public List<string> InvalidTokens { get; set; }

[JsonProperty(PropertyName = "invalidTopics")]
public List<string> InvalidTopics { get; set; }

[JsonProperty(PropertyName = "offset")]
public string Offset { get; set; }

[JsonProperty(PropertyName = "tenantId")]
public long? TenantId { get; set; }

[JsonProperty(PropertyName = "topic")]
public string Topic { get; set; }

[JsonProperty(PropertyName = "entityId")]
public string EntityId { get; set; }

[JsonProperty(PropertyName = "type")]
[JsonConverter(typeof(StringEnumConverter))]
public WebSocketEventType EventType { get; set; }

[JsonProperty(PropertyName = "timestamp")]
public DateTime Timestamp { get; set; }
}
}
54 changes: 30 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,41 +44,47 @@ var response = await ArticleService.GetArticleAsync(request, "100370");

### WebSocket

If you want to subscribe to changes instead of having to poll for new information you can use the Fortnox WebSocket API.
You start by creating a FortnoxWebSocketClient with your AccessToken and ClientSecret. You can then add the desired topics to your connection and once you're ready call `Connect` to initiate the connection.
If you want to subscribe to changes instead of having to poll for new information you can use the Fortnox WebSocket API.
You start by creating a FortnoxWebSocketClient with your ClientSecret. Proceed with calling `Connect` to initiate the connection with Fortnox followed by adding the desired topics and tenants to your connection and once you're ready call `Subscribe` to start recieving events.

```CSharp
var client = await new FortnoxWebSocketClient(this.connectionSettings.AccessToken, this.connectionSettings.ClientSecret)
.AddTopic(WebSocketTopic.Articles);
var client = new FortnoxWebSocketClient(this.connectionSettings.ClientSecret);
await client.Connect();
await client.AddTenant(this.connectionSettings.AccessToken);
await client.AddTopic(WebSocketTopic.Articles);
await client.Subscribe();
```

Once you're connected you can call `Listen` and specify your callback function, in order for this to not block your current thread you can run this within a Task like in the following snippet. Inside your listener callback you can make use of the `GetNextEvent` helper method to process messages as they come.
Once you're subscribed you can call `Recieve` to recieve incoming messages. Performing actions such as `AddTenant`, `AddTopic` and `Subscribe` also results in a message being returned, if you wish you can handle those as well. In the following snippet we see an example which stores all action responses in their own variables followed by a while loop listening for incoming events.

```CSharp
var task = new Task(async () =>
var client = new FortnoxWebSocketClient(this.connectionSettings.ClientSecret);
await client.Connect();

await client.AddTenant(this.connectionSettings.AccessToken);
var addTenantResponse = await client.Recieve();

await client.AddTopic(WebSocketTopic.Articles);
var addTopicResponse = await client.Recieve();

await client.Subscribe();
var subscribeResponse = await client.Recieve();

while (ListenToIncomingEvents)
{
try
var response = await client.Recieve();
if (response.Type == WebSocketResponseType.EventResponse)
{
(await client.Connect()).Listen(async (socket) =>
{
// GetNextEvent returns an enumeration and is iterated asyncrounusly as new events are yielded
foreach (var response in client.GetNextEvent(socket))
{
if (response != null)
{
// Process messages here.
return;
}
}
}).GetAwaiter().GetResult();
// Handle events
}
catch (Exception e)

if (response.Type == WebSocketResponseType.CommandResponse)
{
// Handle errors.
throw e;
// Handle commands
}
}, TaskCreationOptions.LongRunning);
task.Start();
}

await client.Close();
```

More examples of how to use the Fortnox WebSocket API exists within the unit tests for the `FortnoxWebSocketClient` class.
Expand Down

0 comments on commit d2cf5c3

Please sign in to comment.