[IoTConnectvity] Fix native callback management (#1047)
authorsemun-lee <35090067+semun-lee@users.noreply.github.com>
Tue, 1 Oct 2019 12:32:42 +0000 (21:32 +0900)
committerGitHub <noreply@github.com>
Tue, 1 Oct 2019 12:32:42 +0000 (21:32 +0900)
* [IoTConnectivity] Fix native callback management

Use one callback for each type of request.
Use map for multiplexing task completion.

Change-Id: I779d388a6695a405d33264459df7acb75beed806
Signed-off-by: Semun Lee <semun.lee@samsung.com>
* [IoTConnectivity] Fix to use static native callbacks

Change-Id: I8075218091bdfd3978ca66537e5475e57d5f796f
Signed-off-by: Semun Lee <semun.lee@samsung.com>
src/Tizen.Network.IoTConnectivity/Tizen.Network.IoTConnectivity/RemoteResource.cs

index d8101b1..ccc7ec5 100755 (executable)
@@ -38,8 +38,13 @@ namespace Tizen.Network.IoTConnectivity
         private bool _cacheEnabled = false;
         private ResourceOptions _options;
 
-        private static int _responseCallbackId = 1;
-        private static IDictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback> _responseCallbacksMap = new ConcurrentDictionary<IntPtr, Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback>();
+        private static int _responseCompletionId = 1;
+        private static IDictionary<IntPtr, TaskCompletionSource<RemoteResponse>> _taskCompletionMap = new ConcurrentDictionary<IntPtr, TaskCompletionSource<RemoteResponse>>();
+
+        private static Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback _getResultCallback = NativeGetResultCallbackHandler;
+        private static Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback _putResultCallback = NativePutResultCallbackHandler;
+        private static Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback _postResultCallback = NativePostResultCallbackHandler;
+        private static Interop.IoTConnectivity.Client.RemoteResource.ResponseCallback _deleteResultCallback = NativeDeleteResultCallbackHandler;
 
         private Interop.IoTConnectivity.Client.RemoteResource.CachedRepresentationChangedCallback _cacheUpdatedCallback;
         private Interop.IoTConnectivity.Client.RemoteResource.StateChangedCallback _stateChangedCallback;
@@ -398,36 +403,15 @@ namespace Tizen.Network.IoTConnectivity
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
 
             IntPtr id = IntPtr.Zero;
-            lock (_responseCallbacksMap)
+            lock (_taskCompletionMap)
             {
-                id = (IntPtr)_responseCallbackId++;
+                id = (IntPtr)_responseCompletionId++;
             }
-            _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
-            {
-                IntPtr responseCallbackId = userData;
 
-                _responseCallbacksMap.Remove(responseCallbackId);
-
-                if (responseHandle != IntPtr.Zero)
-                {
-                    try
-                    {
-                        tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
-                    }
-                    catch(Exception exp)
-                    {
-                        Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
-                        tcsRemoteResponse.TrySetException(exp);
-                    }
-                }
-                else
-                {
-                    tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
-                }
-            };
+            _taskCompletionMap[id] = tcsRemoteResponse;
 
             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
-            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _responseCallbacksMap[id], id);
+            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Get(_remoteResourceHandle, queryHandle, _getResultCallback, id);
             if (errCode != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get resource attributes");
@@ -436,6 +420,30 @@ namespace Tizen.Network.IoTConnectivity
             return await tcsRemoteResponse.Task;
         }
 
+        private static void NativeGetResultCallbackHandler(IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData)
+        {
+            IntPtr responseCompletionId = userData;
+            TaskCompletionSource<RemoteResponse> responseCompletionSource = _taskCompletionMap[responseCompletionId];
+            _taskCompletionMap.Remove(responseCompletionId);
+
+            if (responseHandle != IntPtr.Zero)
+            {
+                try
+                {
+                    responseCompletionSource.TrySetResult(GetRemoteResponse(responseHandle));
+                }
+                catch(Exception exp)
+                {
+                    Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
+                    responseCompletionSource.TrySetException(exp);
+                }
+            }
+            else
+            {
+                responseCompletionSource.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
+            }
+        }
+
         /// <summary>
         /// Puts the representation of a resource asynchronously.
         /// </summary>
@@ -451,42 +459,15 @@ namespace Tizen.Network.IoTConnectivity
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
 
             IntPtr id = IntPtr.Zero;
-            lock (_responseCallbacksMap)
+            lock (_taskCompletionMap)
             {
-                id = (IntPtr)_responseCallbackId++;
+                id = (IntPtr)_responseCompletionId++;
             }
-            _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
-            {
-                IntPtr responseCallbackId = userData;
 
-                _responseCallbacksMap.Remove(responseCallbackId);
+            _taskCompletionMap[id] = tcsRemoteResponse;
 
-                if (err == (int)(IoTConnectivityError.Iotivity))
-                {
-                    RemoteResponse response = new RemoteResponse();
-                    response.Result = ResponseCode.Forbidden;
-                    response.Representation = null;
-                    tcsRemoteResponse.TrySetResult(response);
-                }
-                else if (responseHandle != IntPtr.Zero)
-                {
-                    try
-                    {
-                        tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
-                    }
-                    catch (Exception exp)
-                    {
-                        Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
-                        tcsRemoteResponse.TrySetException(exp);
-                    }
-                }
-                else
-                {
-                    tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
-                }
-            };
             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
-            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
+            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Put(_remoteResourceHandle, representation._representationHandle, queryHandle, _putResultCallback, id);
             if (errCode != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to put resource representation");
@@ -495,6 +476,37 @@ namespace Tizen.Network.IoTConnectivity
             return await tcsRemoteResponse.Task;
         }
 
+        private static void NativePutResultCallbackHandler(IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData)
+        {
+            IntPtr responseCompletionId = userData;
+            TaskCompletionSource<RemoteResponse> responseCompletionSource = _taskCompletionMap[responseCompletionId];
+            _taskCompletionMap.Remove(responseCompletionId);
+
+            if (err == (int)(IoTConnectivityError.Iotivity))
+            {
+                RemoteResponse response = new RemoteResponse();
+                response.Result = ResponseCode.Forbidden;
+                response.Representation = null;
+                responseCompletionSource.TrySetResult(response);
+            }
+            else if (responseHandle != IntPtr.Zero)
+            {
+                try
+                {
+                    responseCompletionSource.TrySetResult(GetRemoteResponse(responseHandle));
+                }
+                catch (Exception exp)
+                {
+                    Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
+                    responseCompletionSource.TrySetException(exp);
+                }
+            }
+            else
+            {
+                responseCompletionSource.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
+            }
+        }
+
         /// <summary>
         /// Posts request on a resource asynchronously.
         /// </summary>
@@ -510,35 +522,15 @@ namespace Tizen.Network.IoTConnectivity
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
 
             IntPtr id = IntPtr.Zero;
-            lock (_responseCallbacksMap)
+            lock (_taskCompletionMap)
             {
-                id = (IntPtr)_responseCallbackId++;
+                id = (IntPtr)_responseCompletionId++;
             }
-            _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
-            {
-                IntPtr responseCallbackId = userData;
 
-                _responseCallbacksMap.Remove(responseCallbackId);
+            _taskCompletionMap[id] = tcsRemoteResponse;
 
-                if (responseHandle != IntPtr.Zero)
-                {
-                    try
-                    {
-                        tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
-                    }
-                    catch (Exception exp)
-                    {
-                        Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
-                        tcsRemoteResponse.TrySetException(exp);
-                    }
-                }
-                else
-                {
-                    tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
-                }
-            };
             IntPtr queryHandle = (query == null) ? IntPtr.Zero : query._resourceQueryHandle;
-            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _responseCallbacksMap[id], id);
+            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Post(_remoteResourceHandle, representation._representationHandle, queryHandle, _postResultCallback, id);
             if (errCode != (int)IoTConnectivityError.None)
             {
                 Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to post request");
@@ -547,6 +539,30 @@ namespace Tizen.Network.IoTConnectivity
             return await tcsRemoteResponse.Task;
         }
 
+        private static void NativePostResultCallbackHandler(IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData)
+        {
+            IntPtr responseCompletionId = userData;
+            TaskCompletionSource<RemoteResponse> responseCompletionSource = _taskCompletionMap[responseCompletionId];
+            _taskCompletionMap.Remove(responseCompletionId);
+
+            if (responseHandle != IntPtr.Zero)
+            {
+                try
+                {
+                    responseCompletionSource.TrySetResult(GetRemoteResponse(responseHandle));
+                }
+                catch (Exception exp)
+                {
+                    Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
+                    responseCompletionSource.TrySetException(exp);
+                }
+            }
+            else
+            {
+                responseCompletionSource.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
+            }
+        }
+
         /// <summary>
         /// Deletes the resource asynchronously.
         /// </summary>
@@ -560,48 +576,51 @@ namespace Tizen.Network.IoTConnectivity
             TaskCompletionSource<RemoteResponse> tcsRemoteResponse = new TaskCompletionSource<RemoteResponse>();
 
             IntPtr id = IntPtr.Zero;
-            lock (_responseCallbacksMap)
+            lock (_taskCompletionMap)
             {
-                id = (IntPtr)_responseCallbackId++;
+                id = (IntPtr)_responseCompletionId++;
             }
-            _responseCallbacksMap[id] = (IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData) =>
+
+            _taskCompletionMap[id] = tcsRemoteResponse;
+
+            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _deleteResultCallback, id);
+            if (errCode != (int)IoTConnectivityError.None)
             {
-                IntPtr responseCallbackId = userData;
+                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
+                tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
+            }
+            return await tcsRemoteResponse.Task;
+        }
 
-                _responseCallbacksMap.Remove(responseCallbackId);
+        private static void NativeDeleteResultCallbackHandler(IntPtr resource, int err, int requestType, IntPtr responseHandle, IntPtr userData)
+        {
+            IntPtr responseCompletionId = userData;
+            TaskCompletionSource<RemoteResponse> responseCompletionSource = _taskCompletionMap[responseCompletionId];
+            _taskCompletionMap.Remove(responseCompletionId);
 
-                if (err == (int)(IoTConnectivityError.Iotivity))
-                {
-                    RemoteResponse response = new RemoteResponse();
-                    response.Result = ResponseCode.Forbidden;
-                    response.Representation = null;
-                    tcsRemoteResponse.TrySetResult(response);
-                }
-                else if (responseHandle != IntPtr.Zero)
+            if (err == (int)(IoTConnectivityError.Iotivity))
+            {
+                RemoteResponse response = new RemoteResponse();
+                response.Result = ResponseCode.Forbidden;
+                response.Representation = null;
+                responseCompletionSource.TrySetResult(response);
+            }
+            else if (responseHandle != IntPtr.Zero)
+            {
+                try
                 {
-                    try
-                    {
-                        tcsRemoteResponse.TrySetResult(GetRemoteResponse(responseHandle));
-                    }
-                    catch (Exception exp)
-                    {
-                        Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
-                        tcsRemoteResponse.TrySetException(exp);
-                    }
+                    responseCompletionSource.TrySetResult(GetRemoteResponse(responseHandle));
                 }
-                else
+                catch (Exception exp)
                 {
-                    tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
+                    Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to get RemoteResponse: ", exp.Message);
+                    responseCompletionSource.TrySetException(exp);
                 }
-            };
-
-            int errCode = Interop.IoTConnectivity.Client.RemoteResource.Delete(_remoteResourceHandle, _responseCallbacksMap[id], id);
-            if (errCode != (int)IoTConnectivityError.None)
+            }
+            else
             {
-                Log.Error(IoTConnectivityErrorFactory.LogTag, "Failed to delete");
-                tcsRemoteResponse.TrySetException(IoTConnectivityErrorFactory.GetException(errCode));
+                responseCompletionSource.TrySetException(IoTConnectivityErrorFactory.GetException((int)IoTConnectivityError.System));
             }
-            return await tcsRemoteResponse.Task;
         }
 
         /// <summary>
@@ -842,7 +861,7 @@ namespace Tizen.Network.IoTConnectivity
             Policy = (ResourcePolicy)policy;
         }
 
-        private RemoteResponse GetRemoteResponse(IntPtr response)
+        private static RemoteResponse GetRemoteResponse(IntPtr response)
         {
             int result;
             IntPtr representationHandle, optionsHandle;