Skip to content

Commit

Permalink
Implement better exception handling in CoapHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Aug 23, 2017
1 parent 330ade3 commit 8e547da
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 23 deletions.
5 changes: 3 additions & 2 deletions CoAPNet.Tests/CoapResourceHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public void TestResourceMethodNotImplemented()
{
// Arrange
var expectedMessage = CoapMessageUtility
.CreateMessage(CoapMessageCode.NotImplemented, new NotImplementedException().Message).Serialise();
.FromException(new NotImplementedException()).Serialise();
_endpoint
.Setup(c => c.SendAsync(It.Is<CoapPacket>(p => p.Payload.SequenceEqual(expectedMessage)), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(0))
Expand Down Expand Up @@ -180,7 +180,8 @@ public void TestResourceMethodNotImplemented()
public void TestResourceNotFound()
{
// Arrange
var expectedMessage = CoapMessageUtility.CreateMessage(CoapMessageCode.NotFound, $"Resouce {new Uri(_baseUri, "/test")} was not found").Serialise();
var expectedMessage = CoapMessageUtility.CreateMessage(CoapMessageCode.NotFound, $"Resouce {new Uri(_baseUri, "/test")} was not found", CoapMessageType.Acknowledgement).Serialise();

_endpoint
.Setup(e => e.SendAsync(It.Is<CoapPacket>(p => p.Payload.SequenceEqual(expectedMessage)), It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(0))
Expand Down
68 changes: 50 additions & 18 deletions CoAPNet/CoapHander.cs → CoAPNet/CoapHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace CoAPNet
{
public class CoapResourceHandler : CoapHander
public class CoapResourceHandler : CoapHandler
{
public readonly IList<CoapResource> Resources = new List<CoapResource>();

Expand All @@ -35,7 +35,7 @@ public CoapResourceHandler(Uri baseUri)
}
}

public class CoapHander : ICoapHandler
public class CoapHandler : ICoapHandler
{
public virtual CoapResource GetResource(Uri requesstUri)
{
Expand All @@ -46,23 +46,36 @@ public virtual CoapResource GetResource(Uri requesstUri)

public virtual Uri BaseUri { get; } = new Uri("coap://localhost/");

public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byte[] payload)
{
var message = new CoapMessage();
message.Deserialise(payload);
private int _messageId;

//TODO: check if message is multicast, ignore Confirmable requests and delay response
public CoapHandler()
{
_messageId = new Random().Next() & 0xFFFF;
}

if (!message.Code.IsRequest())
{
// TODO: send CoapMessageCode.Reset or ignore them, i dunno
throw new NotImplementedException("TODO: Send CoapMessageCode.Reset or ignore them");
}
private int GetNextMessageId()
{
return Interlocked.Increment(ref _messageId) & ushort.MaxValue;
}

var resource = GetResource(new Uri(BaseUri, message.GetUri()));
public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byte[] payload)
{
CoapMessage result = null;
var message = new CoapMessage();
try
{
message.Deserialise(payload);

//TODO: check if message is multicast, ignore Confirmable requests and delay response

if (!message.Code.IsRequest())
{
// TODO: send CoapMessageCode.Reset or ignore them, i dunno
throw new NotImplementedException("TODO: Send CoapMessageCode.Reset or ignore them");
}

var resource = GetResource(new Uri(BaseUri, message.GetUri()));

if (resource == null)
{
result = CoapMessageUtility.CreateMessage(CoapMessageCode.NotFound,
Expand Down Expand Up @@ -90,20 +103,39 @@ public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byt
}
}
}
catch (NotImplementedException ex)
catch (CoapException ex)
{
result = CoapMessageUtility.CreateMessage(CoapMessageCode.NotImplemented, ex.Message);
//Debug.Fail(ex.Message);
result = CoapMessageUtility.FromException(ex);
}
catch (Exception ex)
catch (NotImplementedException ex)
{
result = CoapMessageUtility.FromException(ex);
//Debug.Fail(ex.Message);
}
catch (Exception)
{
result = CoapMessageUtility.CreateMessage(CoapMessageCode.InternalServerError,
"An unexpected error occured", CoapMessageType.Reset);
throw;
}
finally
{
Debug.Assert(result != null);

if (message.Type == CoapMessageType.Confirmable)
{
if (result.Type != CoapMessageType.Reset)
result.Type = CoapMessageType.Acknowledgement;

// TODO: create unit tests to ensure message.Id and message.Token are set when exceptions are thrown
result.Id = message.Id;
}
else
{
result.Id = GetNextMessageId();
}

result.Token = message.Token;

await connection.LocalEndpoint.SendAsync(
new CoapPacket
{
Expand Down
19 changes: 16 additions & 3 deletions CoAPNet/Utils/CoapMessageUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,37 @@ namespace CoAPNet.Utils
{
public static class CoapMessageUtility
{
public static CoapMessage CreateMessage(CoapMessageCode code, string message)
public static CoapMessage CreateMessage(CoapMessageCode code, string message, CoapMessageType type = CoapMessageType.Confirmable)
{
return new CoapMessage
{
Code = code,
Type = type,
Options = {new ContentFormat(ContentFormatType.TextPlain)},
Payload = Encoding.UTF8.GetBytes(message)
};
}

public static CoapMessage FromException(Exception exception)
{
return new CoapMessage
var result = new CoapMessage
{
Type = CoapMessageType.Reset,
Code = CoapMessageCode.InternalServerError,
Options = { new ContentFormat(ContentFormatType.TextPlain) },
Options = {new ContentFormat(ContentFormatType.TextPlain)},
Payload = Encoding.UTF8.GetBytes(exception.Message)
};

switch (exception)
{
case CoapOptionException _:
result.Code = CoapMessageCode.BadOption;
break;
case NotImplementedException _:
result.Code = CoapMessageCode.NotImplemented;
break;
}
return result;
}
}
}

0 comments on commit 8e547da

Please sign in to comment.