1 /// Copyright 2016 by Samsung Electronics, Inc.,
3 /// This software is the confidential and proprietary information
4 /// of Samsung Electronics, Inc. ("Confidential Information"). You
5 /// shall not disclose such Confidential Information and shall use
6 /// it only in accordance with the terms of the license agreement
7 /// you entered into with Samsung.
10 using System.Collections.Generic;
12 using System.Threading.Tasks;
14 namespace Tizen.Network.IoTConnectivity
17 /// RemoteResource class
19 public class RemoteResource : IDisposable
21 internal const int TimeOutMax = 3600;
22 internal IntPtr _remoteResourceHandle = IntPtr.Zero;
24 private bool _disposed = false;
25 private bool _cacheEnabled = false;
26 private ResourceOptions _options;
28 private int _responseCallbackId = 1;
29 private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback> _responseCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback>();
31 private Interop.IoTConnectivity.Client.RemoteResource.CachedRepresentationChangedCallback _cacheUpdatedCallback;
32 private Interop.IoTConnectivity.Client.RemoteResource.StateChangedCallback _stateChangedCallback;
33 private Interop.IoTConnectivity.Client.RemoteResource.ObserveCallback _observeCallback;
35 private EventHandler<StateChangedEventArgs> _stateChangedEventHandler;
40 public RemoteResource(string hostAddress, string uriPath, ResourcePolicy policy, ResourceTypes resourceTypes, ResourceInterfaces resourceInterfaces)
42 if (hostAddress == null || uriPath == null || resourceTypes == null || resourceInterfaces == null)
44 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid parameters");
45 throw new ArgumentException("Invalid parameter");
48 HostAddress = hostAddress;
51 Types = new List<string>(resourceTypes);
52 Interfaces = new List<string>(resourceInterfaces);
55 CreateRemoteResource(resourceTypes._resourceTypeHandle, resourceInterfaces.ResourceInterfacesHandle);
58 internal RemoteResource(IntPtr handleToClone)
60 int ret = Interop.IoTConnectivity.Client.RemoteResource.Clone(handleToClone, out _remoteResourceHandle);
61 if (ret != (int)IoTConnectivityError.None)
63 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to clone");
64 throw IoTConnectivityErrorFactory.GetException(ret);
75 /// Event that is called to cache resource attribute's
77 public event EventHandler<CacheUpdatedEventArgs> CacheUpdated;
80 /// Observe event on the resource
82 public event EventHandler<ObserverNotifiedEventArgs> ObserverNotified;
85 /// Event that is called when remote resource's state are changed
87 public event EventHandler<StateChangedEventArgs> StateChanged
91 if (_stateChangedEventHandler == null)
93 RegisterStateChangedEvent();
95 _stateChangedEventHandler += value;
99 _stateChangedEventHandler -= value;
100 if (_stateChangedEventHandler == null)
102 UnregisterStateChangedEvent();
108 /// The host address of the resource
110 public string HostAddress { get; private set; }
113 /// The URI path of the resource
115 public string UriPath { get; private set; }
118 /// The resource types of the remote resource
120 public IEnumerable<string> Types { get; private set; }
123 /// The interfaces of the resource
125 public IEnumerable<string> Interfaces { get; private set; }
128 /// The policy of the resource
130 public ResourcePolicy Policy { get; private set; }
133 /// The header options of the resource
135 public ResourceOptions Options
146 int ret = Interop.IoTConnectivity.Client.RemoteResource.SetOptions(_remoteResourceHandle, value._resourceOptionsHandle);
147 if (ret != (int)IoTConnectivityError.None)
149 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set options");
150 throw IoTConnectivityErrorFactory.GetException(ret);
157 /// Cache enabled property
159 public bool CacheEnabled
163 return _cacheEnabled;
167 if (_cacheEnabled != value)
169 _cacheEnabled = value;
170 HandleCachePolicyChanged();
176 /// Time interval of monitoring and caching API
178 public int TimeInterval
183 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetTimeInterval(_remoteResourceHandle, out interval);
184 if (ret != (int)IoTConnectivityError.None)
186 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get time interval");
193 int ret = (int)IoTConnectivityError.InvalidParameter;
194 if (value < TimeOutMax && value > 0)
196 ret = Interop.IoTConnectivity.Client.RemoteResource.SetTimeInterval(_remoteResourceHandle, value);
198 if (ret != (int)IoTConnectivityError.None)
200 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set time interval");
201 throw IoTConnectivityErrorFactory.GetException(ret);
207 /// The device id of the resource
209 public string DeviceId { get; private set; }
212 /// Gets cached representation of the remote resource
214 public Representation CachedRepresentation()
217 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetCachedRepresentation(_remoteResourceHandle, out handle);
218 if (ret != (int)IoTConnectivityError.None)
220 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get CachedRepresentation");
224 Representation representation = new Representation(handle);
225 return representation;
229 /// Registers the observe callback on the resource
231 /// <param name="policy">The type to specify how client wants to observe</param>
232 /// <param name="query">The ResourceQuery to send to server</param>
233 public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
235 _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
238 IntPtr representationHandle;
239 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
240 if (ret != (int)IoTConnectivityError.None)
242 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
246 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
247 if (ret != (int)IoTConnectivityError.None)
249 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
253 Representation repr = null;
256 repr = new Representation(representationHandle);
258 catch (Exception exp)
260 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new representation: " + exp.Message);
264 ObserverNotifiedEventArgs e = new ObserverNotifiedEventArgs()
266 Representation = repr,
267 Result = (ResponseCode)result
269 ObserverNotified?.Invoke(null, e);
272 IntPtr queryHandle = IntPtr.Zero;
275 queryHandle = query._resourceQueryHandle;
278 int errCode = Interop.IoTConnectivity.Client.RemoteResource.RegisterObserve(_remoteResourceHandle, (int)policy, queryHandle, _observeCallback, IntPtr.Zero);
279 if (errCode != (int)IoTConnectivityError.None)
281 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register observe callbacks");
282 throw IoTConnectivityErrorFactory.GetException(errCode);
287 /// Deregisters the observe callback on the resource
289 public void StopObserving()
291 int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
292 if (ret != (int)IoTConnectivityError.None)
294 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister observe callbacks");
295 throw IoTConnectivityErrorFactory.GetException(ret);
300 /// Gets the attributes of a resource
302 /// <param name="query">The ResourceQuery to send to server</param>
303 /// <returns></returns>
304 public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
306 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
308 IntPtr id = IntPtr.Zero;
309 lock (_responseCallbacksMap)
311 id = (IntPtr)_responseCallbackId++;
313 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
315 IntPtr responseCallbackId = userData;
316 lock(_responseCallbacksMap)
318 _responseCallbacksMap.Remove(responseCallbackId);
321 if (responseHandle != IntPtr.Zero)
325 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
329 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
330 tcsRemoteResponse.TrySetException(exp);
335 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
339 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
340 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
341 if (errCode != (int)IoTConnectivityError.None)
343 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
344 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
346 return await tcsRemoteResponse.Task;
350 /// Puts the representation of a resource, asynchronously.
352 /// <param name="representation">Resource representation</param>
353 /// <param name="query">The ResourceQuery to send to server</param>
354 /// <returns></returns>
355 public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
357 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
359 IntPtr id = IntPtr.Zero;
360 lock (_responseCallbacksMap)
362 id = (IntPtr)_responseCallbackId++;
364 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
366 IntPtr responseCallbackId = userData;
367 lock (_responseCallbacksMap)
369 _responseCallbacksMap.Remove(responseCallbackId);
372 if (responseHandle != IntPtr.Zero)
376 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
378 catch (Exception exp)
380 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
381 tcsRemoteResponse.TrySetException(exp);
386 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
390 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
391 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
392 if (errCode != (int)IoTConnectivityError.None)
394 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
395 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
397 return await tcsRemoteResponse.Task;
401 /// Post request on a resource
403 /// <param name="representation">Resource representation</param>
404 /// <param name="query">The ResourceQuery to send to server</param>
405 /// <returns></returns>
406 public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
408 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
410 IntPtr id = IntPtr.Zero;
411 lock (_responseCallbacksMap)
413 id = (IntPtr)_responseCallbackId++;
415 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
417 IntPtr responseCallbackId = userData;
418 lock (_responseCallbacksMap)
420 _responseCallbacksMap.Remove(responseCallbackId);
423 if (responseHandle != IntPtr.Zero)
427 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
429 catch (Exception exp)
431 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
432 tcsRemoteResponse.TrySetException(exp);
437 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
441 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
442 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
443 if (errCode != (int)IoTConnectivityError.None)
445 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
446 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
448 return await tcsRemoteResponse.Task;
452 /// Delete the resource
454 /// <returns></returns>
455 public async Task<RemoteResponse> DeleteAsync()
457 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
459 IntPtr id = IntPtr.Zero;
460 lock (_responseCallbacksMap)
462 id = (IntPtr)_responseCallbackId++;
464 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
466 IntPtr responseCallbackId = userData;
467 lock (_responseCallbacksMap)
469 _responseCallbacksMap.Remove(responseCallbackId);
472 if (responseHandle != IntPtr.Zero)
476 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
478 catch (Exception exp)
480 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
481 tcsRemoteResponse.TrySetException(exp);
486 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
490 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
491 if (errCode != (int)IoTConnectivityError.None)
493 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
494 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
496 return await tcsRemoteResponse.Task;
499 public void Dispose()
502 GC.SuppressFinalize(this);
505 internal static Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType GetConnectivityType(string hostAddress)
507 Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
509 if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
511 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
516 if (IPAddress.TryParse(hostAddress, out address))
518 switch (address.AddressFamily)
520 case System.Net.Sockets.AddressFamily.InterNetwork:
521 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
523 case System.Net.Sockets.AddressFamily.InterNetworkV6:
524 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv6;
527 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse for Ipv4 or Ipv6");
535 protected virtual void Dispose(bool disposing)
542 // Free managed objects
545 Interop.IoTConnectivity.Client.RemoteResource.Destroy(_remoteResourceHandle);
549 private void HandleCachePolicyChanged()
553 _cacheUpdatedCallback = (IntPtr resource, IntPtr representation, IntPtr userData) =>
557 Representation repr = null;
560 repr = new Representation(representation);
562 catch (Exception exp)
564 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
568 CacheUpdatedEventArgs e = new CacheUpdatedEventArgs()
570 Representation = repr
572 CacheUpdated?.Invoke(null, e);
576 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartCaching(_remoteResourceHandle, _cacheUpdatedCallback, IntPtr.Zero);
577 if (ret != (int)IoTConnectivityError.None)
579 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add cache updated event handler");
580 throw IoTConnectivityErrorFactory.GetException(ret);
585 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopCaching(_remoteResourceHandle);
586 if (ret != (int)IoTConnectivityError.None)
588 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove cache updated event handler");
589 throw IoTConnectivityErrorFactory.GetException(ret);
594 private void RegisterStateChangedEvent()
596 _stateChangedCallback = (IntPtr resource, int state, IntPtr userData) =>
598 StateChangedEventArgs e = new StateChangedEventArgs()
600 State = (ResourceState)state
602 _stateChangedEventHandler?.Invoke(null, e);
605 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartMonitoring(_remoteResourceHandle, _stateChangedCallback, IntPtr.Zero);
606 if (ret != (int)IoTConnectivityError.None)
608 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add state changed event handler");
609 throw IoTConnectivityErrorFactory.GetException(ret);
613 private void UnregisterStateChangedEvent()
615 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopMonitoring(_remoteResourceHandle);
616 if (ret != (int)IoTConnectivityError.None)
618 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove state changed event handler");
619 throw IoTConnectivityErrorFactory.GetException(ret);
623 private void CreateRemoteResource(IntPtr resourceTypeHandle, IntPtr resourceInterfaceHandle)
625 Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = GetConnectivityType(HostAddress);
626 if (connectivityType == Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None)
628 Log.Error(IoTConnectivityErrorFactory.LogTag, "Unable to parse host address");
629 throw new ArgumentException("Unable to parse host address");
631 int ret = Interop.IoTConnectivity.Client.RemoteResource.Create(HostAddress, (int)connectivityType, UriPath, (int)Policy, resourceTypeHandle, resourceInterfaceHandle, out _remoteResourceHandle);
632 if (ret != (int)IoTConnectivityError.None)
634 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
635 throw IoTConnectivityErrorFactory.GetException(ret);
639 private void SetRemoteResource()
641 string hostAddress, uriPath;
642 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddress);
643 if (ret != (int)IoTConnectivityError.None)
645 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
646 throw IoTConnectivityErrorFactory.GetException(ret);
649 ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPath);
650 if (ret != (int)IoTConnectivityError.None)
652 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
653 throw IoTConnectivityErrorFactory.GetException(ret);
656 int policy = (int)ResourcePolicy.NoProperty;
657 ret = Interop.IoTConnectivity.Client.RemoteResource.GetProperties(_remoteResourceHandle, out policy);
658 if (ret != (int)IoTConnectivityError.None)
660 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
661 throw IoTConnectivityErrorFactory.GetException(ret);
664 IntPtr typesHandle, interfacesHandle;
665 ret = Interop.IoTConnectivity.Client.RemoteResource.GetTypes(_remoteResourceHandle, out typesHandle);
666 if (ret != (int)IoTConnectivityError.None)
668 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource types");
669 throw IoTConnectivityErrorFactory.GetException(ret);
672 ret = Interop.IoTConnectivity.Client.RemoteResource.GetInterfaces(_remoteResourceHandle, out interfacesHandle);
673 if (ret != (int)IoTConnectivityError.None)
675 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource interfaces");
676 throw IoTConnectivityErrorFactory.GetException(ret);
680 ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceId);
681 if (ret != (int)IoTConnectivityError.None)
683 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
684 throw IoTConnectivityErrorFactory.GetException(ret);
688 HostAddress = hostAddress;
690 Types = new ResourceTypes(typesHandle);
691 Interfaces = new ResourceInterfaces(interfacesHandle);
692 Policy = (ResourcePolicy)policy;
695 private RemoteResponse GetRemoteResponse(IntPtr response)
698 IntPtr representationHandle, optionsHandle;
699 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
700 if (ret != (int)IoTConnectivityError.None)
702 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
703 throw IoTConnectivityErrorFactory.GetException(ret);
706 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
707 if (ret != (int)IoTConnectivityError.None)
709 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
710 throw IoTConnectivityErrorFactory.GetException(ret);
713 ret = Interop.IoTConnectivity.Server.Response.GetOptions(response, out optionsHandle);
714 if (ret != (int)IoTConnectivityError.None)
716 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
717 throw IoTConnectivityErrorFactory.GetException(ret);
720 return new RemoteResponse()
722 Result = (ResponseCode)result,
723 Representation = new Representation(representationHandle),
724 Options = new ResourceOptions(optionsHandle)