Skip to content

Commit

Permalink
Make OptionFactory a object
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Nov 29, 2017
1 parent 1def851 commit a99134c
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 161 deletions.
103 changes: 16 additions & 87 deletions src/CoAPNet/CoapMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,92 +39,9 @@ public enum CoapMessageType
public enum CoapMessageCodeClass
{
Request = 0,
Success = 200,
ClientError = 400,
ServerError = 500
}

/// <summary>
/// Response Codes
/// <para>See section 5.9 of [RFC7252] and section 12.1 of [RFC7252]</para>
/// </summary>
public enum CoapMessageCode
{
/// <summary>
/// Placeholder and will throw <see cref="InvalidOperationException"/> when used.
/// </summary>
None = 0,
// 0.xx Request
/// <summary>
/// GET request from a client to a server used for retreiving resources
/// </summary>
Get = 1,
/// <summary>
/// Post request from a client to a server used for creating or updating resources
/// </summary>
Post = 2,
/// <summary>
/// Put request from a client to a server used for updating resources
/// </summary>
Put = 3,
/// <summary>
/// DELETE request from a client to a server used to delete resources
/// </summary>
Delete = 4,
// 2.xx Success
Created = 201,
Deleted = 202,
Valid = 203,
Changed = 204,
Content = 205,
// 4.xx Client Error
BadRequest = 400,
Unauthorized = 401,
BadOption = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
PreconditionFailed = 412,
RequestEntityTooLarge = 413,
UnsupportedContentFormat = 415,
// 5.xx Server Error
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
ProxyingNotSupported = 505
}

/// <summary>
/// Extension methods for quickly deciding which logic to apply to CoAP messages.
/// </summary>
public static class CoapMessageCodeExtensions
{
/// <summary>
/// indicates if the CoAP message is a Request from a client.
/// </summary>
public static bool IsRequest(this CoapMessageCode code)
=> ((int) code / 100) == 0 && code != CoapMessageCode.None;

/// <summary>
/// indicates if the CoAP message is a successful response from a server.
/// </summary>
public static bool IsSuccess(this CoapMessageCode code)
=> ((int)code / 100) == 2;

/// <summary>
/// indicates if the CoAP message is a error due to a client's request.
/// </summary>
public static bool IsClientError(this CoapMessageCode code)
=> ((int)code / 100) == 4;

/// <summary>
/// indicates if the CoAP message is a error due to internal server issues.
/// </summary>
public static bool IsServerError(this CoapMessageCode code)
=> ((int)code / 100) == 5;
Success = 2,
ClientError = 4,
ServerError = 5
}

/// <summary>
Expand Down Expand Up @@ -209,6 +126,7 @@ public byte[] Token
public int Id { get; set; }

private List<CoapOption> _options = new List<CoapOption>();

/// <summary>
/// Gets or sets the list of options to be encoded into the message header. The order of these options are Critical and spcial care is needed when adding new items.
/// <para>Todo: Sort items based on <see cref="CoapOption.OptionNumber"/> and preserve options with identical Optionnumbers</para>
Expand All @@ -224,6 +142,17 @@ public List<CoapOption> Options
}
}

private OptionFactory _optionFactory;

/// <summary>
/// Gets or Sets the OptionFactory used when decoding options in a CoAP message header
/// </summary>
public OptionFactory OptionFactory
{
get => _optionFactory ?? (_optionFactory = OptionFactory.Default);
set => _optionFactory = value;
}

/// <summary>
/// Gets or Sets The paylaod of the message.
/// </summary>
Expand Down Expand Up @@ -411,7 +340,7 @@ public void Deserialise(byte[] data)

try
{
var option = CoAPNet.Options.Factory.Create(optCode + optionDelta,
var option = OptionFactory.Create(optCode + optionDelta,
data.Skip(i + 1).Take(dataLen).ToArray());
if (option != null)
Options.Add(option);
Expand Down
74 changes: 0 additions & 74 deletions src/CoAPNet/Options/Factory.cs

This file was deleted.

104 changes: 104 additions & 0 deletions src/CoAPNet/Options/OptionFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Reflection;
using System.Collections.Generic;

namespace CoAPNet.Options
{
public class OptionFactory
{
private Dictionary<int, Type> _options = new Dictionary<int, Type>();

private static OptionFactory _instance;

/// <summary>
/// A <see cref="OptionFactory"/> with all the supported options registered.
/// </summary>
public static OptionFactory Default => _instance ?? (_instance = new OptionFactory());

/// <summary>
/// Creates a new Options Factory with all the suported options registered.
/// </summary>
public OptionFactory()
{
Register<UriHost>();
Register<UriPort>();
Register<UriPath>();
Register<UriQuery>();

Register<ProxyUri>();
Register<ProxyScheme>();

Register<LocationPath>();
Register<LocationQuery>();

Register<ContentFormat>();
Register<Accept>();
Register<MaxAge>();
Register<ETag>();
Register<Size1>();

Register<IfMatch>();
Register<IfNoneMatch>();
}

/// <summary>
/// Creates a new Options Factory with all the suported options registered and registers addional <see cref="CoapOption"/>.
/// </summary>
/// <param name="addtionalOptions"></param>
public OptionFactory(params Type[] addtionalOptions)
: this()
{
Register(addtionalOptions);
}

/// <summary>
/// Register an additional <see cref="CoapOption"/>
/// </summary>
/// <typeparam name="T">Must subclass <see cref="CoapOption"/></typeparam>
public void Register<T>() where T : CoapOption
{
Register(typeof(T));
}

/// <summary>
/// Regisrers additional <see cref="CoapOption"/>s
/// </summary>
/// <param name="addtionalOptions"></param>
public void Register(params Type[] addtionalOptions)
{
foreach (var type in addtionalOptions)
{
if (!type.GetTypeInfo().IsSubclassOf(typeof(CoapOption)))
throw new ArgumentException($"Type must be a subclass of {nameof(CoapOption)}");

var option = (CoapOption)Activator.CreateInstance(type);
_options.Add(option.OptionNumber, type);
}
}

/// <summary>
/// Try to create an <see cref="CoapOption"/> from the option number and data.
/// </summary>
/// <param name="number"></param>
/// <param name="data"></param>
/// <returns><value>null</value> if the option is unsupported.</returns>
/// <exception cref="CoapOptionException">If the option number is unsuppported and is critical (See RFC 7252 Section 5.4.1)</exception>
public CoapOption Create(int number, byte[] data = null)
{
// Let the exception get thrown if index is out of range
Type type = null;
if (!_options.TryGetValue(number, out type))
{
if (number % 2 == 1)
throw new CoapOptionException($"Unsupported critical option ({number})", new ArgumentOutOfRangeException(nameof(number)));
return null;
}

var option = (CoapOption)Activator.CreateInstance(type);
if (data != null)
option.FromBytes(data);

return option;
}
}
}

0 comments on commit a99134c

Please sign in to comment.