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.Runtime.InteropServices;
13 using System.Threading.Tasks;
15 namespace Tizen.Network.IoTConnectivity
18 /// RemoteResource class
20 public class RemoteResource : IDisposable
22 internal const int TimeOutMax = 3600;
23 internal IntPtr _remoteResourceHandle = IntPtr.Zero;
25 private bool _disposed = false;
26 private bool _cacheEnabled = false;
27 private ResourceOptions _options;
29 private int _responseCallbackId = 1;
30 private static Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback> _responseCallbacksMap = new Dictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback>();
32 private Interop.IoTConnectivity.Client.RemoteResource.CachedRepresentationChangedCallback _cacheUpdatedCallback;
33 private Interop.IoTConnectivity.Client.RemoteResource.StateChangedCallback _stateChangedCallback;
34 private Interop.IoTConnectivity.Client.RemoteResource.ObserveCallback _observeCallback;
36 private EventHandler<StateChangedEventArgs> _stateChangedEventHandler;
41 public RemoteResource(string hostAddress, string uriPath, ResourcePolicy policy, ResourceTypes resourceTypes, ResourceInterfaces resourceInterfaces)
43 if (hostAddress == null || uriPath == null || resourceTypes == null || resourceInterfaces == null)
45 Log.Error(IoTConnectivityErrorFactory.LogTag, "Invalid parameters");
46 throw new ArgumentException("Invalid parameter");
49 HostAddress = hostAddress;
52 Types = new List<string>(resourceTypes);
53 Interfaces = new List<string>(resourceInterfaces);
56 CreateRemoteResource(resourceTypes._resourceTypeHandle, resourceInterfaces.ResourceInterfacesHandle);
59 internal RemoteResource(IntPtr handleToClone)
61 int ret = Interop.IoTConnectivity.Client.RemoteResource.Clone(handleToClone, out _remoteResourceHandle);
62 if (ret != (int)IoTConnectivityError.None)
64 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to clone");
65 throw IoTConnectivityErrorFactory.GetException(ret);
76 /// Event that is called to cache resource attribute's
78 public event EventHandler<CacheUpdatedEventArgs> CacheUpdated;
81 /// Observe event on the resource
83 public event EventHandler<ObserverNotifiedEventArgs> ObserverNotified;
86 /// Event that is called when remote resource's state are changed
88 public event EventHandler<StateChangedEventArgs> StateChanged
92 if (_stateChangedEventHandler == null)
94 RegisterStateChangedEvent();
96 _stateChangedEventHandler += value;
100 _stateChangedEventHandler -= value;
101 if (_stateChangedEventHandler == null)
103 UnregisterStateChangedEvent();
109 /// The host address of the resource
111 public string HostAddress { get; private set; }
114 /// The URI path of the resource
116 public string UriPath { get; private set; }
119 /// The resource types of the remote resource
121 public IEnumerable<string> Types { get; private set; }
124 /// The interfaces of the resource
126 public IEnumerable<string> Interfaces { get; private set; }
129 /// The policy of the resource
131 public ResourcePolicy Policy { get; private set; }
134 /// The device name of the remote resource
136 public string DeviceName { get; private set; }
139 /// The header options of the resource
141 public ResourceOptions Options
152 int ret = Interop.IoTConnectivity.Client.RemoteResource.SetOptions(_remoteResourceHandle, value._resourceOptionsHandle);
153 if (ret != (int)IoTConnectivityError.None)
155 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set options");
156 throw IoTConnectivityErrorFactory.GetException(ret);
163 /// Cache enabled property
165 public bool CacheEnabled
169 return _cacheEnabled;
173 if (_cacheEnabled != value)
175 _cacheEnabled = value;
176 HandleCachePolicyChanged();
182 /// Time interval of monitoring and caching API
184 public int TimeInterval
189 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetTimeInterval(out interval);
190 if (ret != (int)IoTConnectivityError.None)
192 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get time interval");
199 int ret = (int)IoTConnectivityError.InvalidParameter;
200 if (value < TimeOutMax && value > 0)
202 ret = Interop.IoTConnectivity.Client.RemoteResource.SetTimeInterval(value);
204 if (ret != (int)IoTConnectivityError.None)
206 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to set time interval");
207 throw IoTConnectivityErrorFactory.GetException(ret);
213 /// The device id of the resource
215 public string DeviceId { get; private set; }
218 /// Gets cached representation of the remote resource
220 public Representation CachedRepresentation()
223 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetCachedRepresentation(_remoteResourceHandle, out handle);
224 if (ret != (int)IoTConnectivityError.None)
226 Log.Warn(IoTConnectivityErrorFactory.LogTag, "Failed to get CachedRepresentation");
230 Representation representation = new Representation(handle);
231 return representation;
235 /// Registers the observe callback on the resource
237 /// <param name="policy">The type to specify how client wants to observe</param>
238 /// <param name="query">The ResourceQuery to send to server</param>
239 public void StartObserving(ObservePolicy policy, ResourceQuery query = null)
241 _observeCallback = (IntPtr resource, int err, int sequenceNumber, IntPtr response, IntPtr userData) =>
244 IntPtr representationHandle;
245 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
246 if (ret != (int)IoTConnectivityError.None)
248 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
252 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
253 if (ret != (int)IoTConnectivityError.None)
255 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
259 Representation repr = null;
262 repr = new Representation(representationHandle);
264 catch (Exception exp)
266 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new representation: " + exp.Message);
270 ObserverNotifiedEventArgs e = new ObserverNotifiedEventArgs()
272 Representation = repr,
273 Result = (ResponseCode)result
275 ObserverNotified?.Invoke(null, e);
278 IntPtr queryHandle = IntPtr.Zero;
281 queryHandle = query._resourceQueryHandle;
284 int errCode = Interop.IoTConnectivity.Client.RemoteResource.RegisterObserve(_remoteResourceHandle, (int)policy, queryHandle, _observeCallback, IntPtr.Zero);
285 if (errCode != (int)IoTConnectivityError.None)
287 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to register observe callbacks");
288 throw IoTConnectivityErrorFactory.GetException(errCode);
293 /// Deregisters the observe callback on the resource
295 public void StopObserving()
297 int ret = Interop.IoTConnectivity.Client.RemoteResource.DeregisterObserve(_remoteResourceHandle);
298 if (ret != (int)IoTConnectivityError.None)
300 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to deregister observe callbacks");
301 throw IoTConnectivityErrorFactory.GetException(ret);
306 /// Gets the attributes of a resource
308 /// <param name="query">The ResourceQuery to send to server</param>
309 /// <returns></returns>
310 public async Task<RemoteResponse> GetAsync(ResourceQuery query = null)
312 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
314 IntPtr id = IntPtr.Zero;
315 lock (_responseCallbacksMap)
317 id = (IntPtr)_responseCallbackId++;
319 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
321 IntPtr responseCallbackId = userData;
322 lock(_responseCallbacksMap)
324 _responseCallbacksMap.Remove(responseCallbackId);
327 if (responseHandle != IntPtr.Zero)
331 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
335 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
336 tcsRemoteResponse.TrySetException(exp);
341 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
345 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
346 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
347 if (errCode != (int)IoTConnectivityError.None)
349 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
350 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
352 return await tcsRemoteResponse.Task;
356 /// Puts the representation of a resource, asynchronously.
358 /// <param name="representation">Resource representation</param>
359 /// <param name="query">The ResourceQuery to send to server</param>
360 /// <returns></returns>
361 public async Task<RemoteResponse> PutAsync(Representation representation, ResourceQuery query = null)
363 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
365 IntPtr id = IntPtr.Zero;
366 lock (_responseCallbacksMap)
368 id = (IntPtr)_responseCallbackId++;
370 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
372 IntPtr responseCallbackId = userData;
373 lock (_responseCallbacksMap)
375 _responseCallbacksMap.Remove(responseCallbackId);
378 if (responseHandle != IntPtr.Zero)
382 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
384 catch (Exception exp)
386 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
387 tcsRemoteResponse.TrySetException(exp);
392 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
396 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
397 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
398 if (errCode != (int)IoTConnectivityError.None)
400 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
401 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
403 return await tcsRemoteResponse.Task;
407 /// Post request on a resource
409 /// <param name="representation">Resource representation</param>
410 /// <param name="query">The ResourceQuery to send to server</param>
411 /// <returns></returns>
412 public async Task<RemoteResponse> PostAsync(Representation representation, ResourceQuery query = null)
414 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
416 IntPtr id = IntPtr.Zero;
417 lock (_responseCallbacksMap)
419 id = (IntPtr)_responseCallbackId++;
421 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
423 IntPtr responseCallbackId = userData;
424 lock (_responseCallbacksMap)
426 _responseCallbacksMap.Remove(responseCallbackId);
429 if (responseHandle != IntPtr.Zero)
433 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
435 catch (Exception exp)
437 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
438 tcsRemoteResponse.TrySetException(exp);
443 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
447 IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
448 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
449 if (errCode != (int)IoTConnectivityError.None)
451 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
452 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
454 return await tcsRemoteResponse.Task;
458 /// Delete the resource
460 /// <returns></returns>
461 public async Task<RemoteResponse> DeleteAsync()
463 TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
465 IntPtr id = IntPtr.Zero;
466 lock (_responseCallbacksMap)
468 id = (IntPtr)_responseCallbackId++;
470 _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
472 IntPtr responseCallbackId = userData;
473 lock (_responseCallbacksMap)
475 _responseCallbacksMap.Remove(responseCallbackId);
478 if (responseHandle != IntPtr.Zero)
482 tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
484 catch (Exception exp)
486 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
487 tcsRemoteResponse.TrySetException(exp);
492 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
496 int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
497 if (errCode != (int)IoTConnectivityError.None)
499 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
500 tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
502 return await tcsRemoteResponse.Task;
505 public void Dispose()
508 GC.SuppressFinalize(this);
511 internal static Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType GetConnectivityType(string hostAddress)
513 Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None;
515 if (hostAddress == IoTConnectivityClientManager.MulticastAddress)
517 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
522 string hostName = hostAddress;
523 if (hostAddress.Contains(":"))
525 string[] hostParts = hostAddress.Split(':');
526 if (hostParts.Length == 2)
528 hostName = hostParts[0];
531 if (IPAddress.TryParse(hostName, out address))
533 switch (address.AddressFamily)
535 case System.Net.Sockets.AddressFamily.InterNetwork:
536 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv4;
538 case System.Net.Sockets.AddressFamily.InterNetworkV6:
539 type = Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.Ipv6;
542 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to parse for Ipv4 or Ipv6");
550 protected virtual void Dispose(bool disposing)
557 // Free managed objects
560 Interop.IoTConnectivity.Client.RemoteResource.Destroy(_remoteResourceHandle);
564 private void HandleCachePolicyChanged()
568 _cacheUpdatedCallback = (IntPtr resource, IntPtr representation, IntPtr userData) =>
572 Representation repr = null;
575 repr = new Representation(representation);
577 catch (Exception exp)
579 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to new Representation: " + exp.Message);
583 CacheUpdatedEventArgs e = new CacheUpdatedEventArgs()
585 Representation = repr
587 CacheUpdated?.Invoke(null, e);
591 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartCaching(_remoteResourceHandle, _cacheUpdatedCallback, IntPtr.Zero);
592 if (ret != (int)IoTConnectivityError.None)
594 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add cache updated event handler");
595 throw IoTConnectivityErrorFactory.GetException(ret);
600 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopCaching(_remoteResourceHandle);
601 if (ret != (int)IoTConnectivityError.None)
603 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove cache updated event handler");
604 throw IoTConnectivityErrorFactory.GetException(ret);
609 private void RegisterStateChangedEvent()
611 _stateChangedCallback = (IntPtr resource, int state, IntPtr userData) =>
613 StateChangedEventArgs e = new StateChangedEventArgs()
615 State = (ResourceState)state
617 _stateChangedEventHandler?.Invoke(null, e);
620 int ret = Interop.IoTConnectivity.Client.RemoteResource.StartMonitoring(_remoteResourceHandle, _stateChangedCallback, IntPtr.Zero);
621 if (ret != (int)IoTConnectivityError.None)
623 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to add state changed event handler");
624 throw IoTConnectivityErrorFactory.GetException(ret);
628 private void UnregisterStateChangedEvent()
630 int ret = Interop.IoTConnectivity.Client.RemoteResource.StopMonitoring(_remoteResourceHandle);
631 if (ret != (int)IoTConnectivityError.None)
633 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to remove state changed event handler");
634 throw IoTConnectivityErrorFactory.GetException(ret);
638 private void CreateRemoteResource(IntPtr resourceTypeHandle, IntPtr resourceInterfaceHandle)
640 Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType connectivityType = GetConnectivityType(HostAddress);
641 if (connectivityType == Interop.IoTConnectivity.Client.RemoteResource.ConnectivityType.None)
643 Log.Error(IoTConnectivityErrorFactory.LogTag, "Unable to parse host address");
644 throw new ArgumentException("Unable to parse host address");
646 int ret = Interop.IoTConnectivity.Client.RemoteResource.Create(HostAddress, (int)connectivityType, UriPath, (int)Policy, resourceTypeHandle, resourceInterfaceHandle, out _remoteResourceHandle);
647 if (ret != (int)IoTConnectivityError.None)
649 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get remote resource");
650 throw IoTConnectivityErrorFactory.GetException(ret);
654 ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceName(_remoteResourceHandle, out deviceName);
655 if (ret != (int)IoTConnectivityError.None)
657 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device name of remote resource");
658 throw IoTConnectivityErrorFactory.GetException(ret);
660 DeviceName = Marshal.PtrToStringAuto(deviceName);*/
663 private void SetRemoteResource()
665 IntPtr hostAddressPtr, uriPathPtr;
666 int ret = Interop.IoTConnectivity.Client.RemoteResource.GetHostAddress(_remoteResourceHandle, out hostAddressPtr);
667 if (ret != (int)IoTConnectivityError.None)
669 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get host address");
670 throw IoTConnectivityErrorFactory.GetException(ret);
673 ret = Interop.IoTConnectivity.Client.RemoteResource.GetUriPath(_remoteResourceHandle, out uriPathPtr);
674 if (ret != (int)IoTConnectivityError.None)
676 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
677 throw IoTConnectivityErrorFactory.GetException(ret);
680 int policy = (int)ResourcePolicy.NoProperty;
681 ret = Interop.IoTConnectivity.Client.RemoteResource.GetPolicies(_remoteResourceHandle, out policy);
682 if (ret != (int)IoTConnectivityError.None)
684 Log.Error(IoTConnectivityErrorFactory.LogTag, "Faled to get uri path");
685 throw IoTConnectivityErrorFactory.GetException(ret);
688 IntPtr typesHandle, interfacesHandle;
689 ret = Interop.IoTConnectivity.Client.RemoteResource.GetTypes(_remoteResourceHandle, out typesHandle);
690 if (ret != (int)IoTConnectivityError.None)
692 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource types");
693 throw IoTConnectivityErrorFactory.GetException(ret);
696 ret = Interop.IoTConnectivity.Client.RemoteResource.GetInterfaces(_remoteResourceHandle, out interfacesHandle);
697 if (ret != (int)IoTConnectivityError.None)
699 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource interfaces");
700 throw IoTConnectivityErrorFactory.GetException(ret);
704 ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceId(_remoteResourceHandle, out deviceIdPtr);
705 if (ret != (int)IoTConnectivityError.None)
707 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device id");
708 throw IoTConnectivityErrorFactory.GetException(ret);
711 ret = Interop.IoTConnectivity.Client.RemoteResource.GetDeviceName(_remoteResourceHandle, out deviceName);
712 if (ret != (int)IoTConnectivityError.None)
714 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get device name of remote resource");
715 throw IoTConnectivityErrorFactory.GetException(ret);
717 DeviceName = Marshal.PtrToStringAuto(deviceName);
718 DeviceId = Marshal.PtrToStringAuto(deviceIdPtr);
719 HostAddress = Marshal.PtrToStringAuto(hostAddressPtr);
720 UriPath = Marshal.PtrToStringAuto(uriPathPtr);
721 Types = new ResourceTypes(typesHandle);
722 Interfaces = new ResourceInterfaces(interfacesHandle);
723 Policy = (ResourcePolicy)policy;
726 private RemoteResponse GetRemoteResponse(IntPtr response)
729 IntPtr representationHandle, optionsHandle;
730 int ret = Interop.IoTConnectivity.Server.Response.GetResult(response, out result);
731 if (ret != (int)IoTConnectivityError.None)
733 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get result");
734 throw IoTConnectivityErrorFactory.GetException(ret);
737 ret = Interop.IoTConnectivity.Server.Response.GetRepresentation(response, out representationHandle);
738 if (ret != (int)IoTConnectivityError.None)
740 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get representation");
741 throw IoTConnectivityErrorFactory.GetException(ret);
744 ret = Interop.IoTConnectivity.Server.Response.GetOptions(response, out optionsHandle);
745 if (ret != (int)IoTConnectivityError.None)
747 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get options");
748 throw IoTConnectivityErrorFactory.GetException(ret);
750 return new RemoteResponse()
752 Result = (ResponseCode)result,
753 Representation = new Representation(representationHandle),
754 Options = (optionsHandle == IntPtr.Zero)? null : new ResourceOptions(optionsHandle)