48b6cf1bbf520f73ef677c7055ae3accf7486b13
[platform/core/csapi/tizenfx.git] / Tizen.Applications / Tizen.Applications.Messages / MessagePort.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Runtime.InteropServices;
6 using System.Text;
7 using System.Threading.Tasks;
8 using Tizen.Internals;
9
10 namespace Tizen.Applications.Messages
11 {
12     /// <summary>
13     /// The Message Port API provides functions to send and receive messages between applications.
14     /// </summary>
15     /// <remarks>
16     /// The Message Port API provides functions for passing messages between applications. An application should register its own local port to receive messages from remote applications.
17     /// If a remote application sends a message, the registered callback function of the local port is called.
18     /// The trusted message-port API allows communications between applications that are signed by the same developer(author) certificate.
19     /// </remarks>
20     public class MessagePort : IDisposable
21     {
22         private static readonly object s_lock = new object();
23         private static readonly HashSet<string> s_portMap = new HashSet<string>();
24
25         /// <summary>
26         /// Initializes the instance of the MessagePort class.
27         /// </summary>
28         /// <param name="portName">The name of the local message port</param>
29         /// <param name="trusted">If true is the trusted message port of application, otherwise false</param>
30         public MessagePort(string portName, bool trusted)
31         {
32             if (String.IsNullOrEmpty(portName))
33             {
34                 MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "Invalid PortName", "PortName");
35             }
36             _portName = portName;
37             _trusted = trusted;
38         }
39
40         /// <summary>
41         /// Destructor of the MessagePort class.
42         /// </summary>
43         ~MessagePort()
44         {
45             Dispose(false);
46         }
47
48         /// <summary>
49         /// Called when a message is received.
50         /// </summary>
51         public event EventHandler<MessageReceivedEventArgs> MessageReceived;
52
53         /// <summary>
54         /// The name of the local message port
55         /// </summary>
56         public string PortName
57         {
58             get
59             {
60                 return _portName;
61             }
62         }
63         /// <summary>
64         /// If true the message port is a trusted port, otherwise false it is not
65         /// </summary>
66         public bool Trusted
67         {
68             get
69             {
70                 return _trusted;
71             }
72         }
73
74         /// <summary>
75         /// If true the message port is listening, otherwise false it is not
76         /// </summary>
77         public bool Listening
78         {
79             get
80             {
81                 return _listening;
82             }
83         }
84
85         /// <summary>
86         /// The local message port ID
87         /// </summary>
88         private int _portId = 0;
89
90         /// <summary>
91         /// The name of the local message port
92         /// </summary>
93         private readonly string _portName = null;
94
95         /// <summary>
96         /// If true the message port is a trusted port, otherwise false it is not
97         /// </summary>
98         private readonly bool _trusted = false;
99
100         /// <summary>
101         /// If true the message port is listening, otherwise false it is not
102         /// </summary>
103         private bool _listening = false;
104
105         private Interop.MessagePort.message_port_message_cb _messageCallBack;
106
107         /// <summary>
108         /// Register the local message port.
109         /// </summary>
110         public void Listen()
111         {
112             lock (s_lock)
113             {
114                 if (s_portMap.Contains(_portName))
115                 {
116                     throw new InvalidOperationException(_portName + " is already used");
117                 }
118                 _messageCallBack = (int localPortId, string remoteAppId, string remotePortName, bool trusted, IntPtr message, IntPtr userData) =>
119                 {
120                     MessageReceivedEventArgs args = new MessageReceivedEventArgs()
121                     {
122                         Message = Bundle.MakeRetainedBundle(message)
123                     };
124
125                     if (!String.IsNullOrEmpty(remotePortName) && !String.IsNullOrEmpty(remoteAppId))
126                     {
127                         args.Remote = new RemoteValues()
128                         {
129                             AppId = remoteAppId,
130                             PortName = remotePortName,
131                             Trusted = trusted
132                         };
133                     }
134                     RaiseMessageReceivedEvent(MessageReceived, args);
135                 };
136
137                 _portId = _trusted ?
138                             Interop.MessagePort.RegisterTrustedPort(_portName, _messageCallBack, IntPtr.Zero) :
139                             Interop.MessagePort.RegisterPort(_portName, _messageCallBack, IntPtr.Zero);
140
141                 if (_portId <= 0)
142                     throw new InvalidOperationException("Can't Listening with " + _portName);
143
144                 s_portMap.Add(_portName);
145                 _listening = true;
146             }
147         }
148
149         /// <summary>
150         /// Unregisters the local message port.
151         /// </summary>
152         public void StopListening()
153         {
154             if (!_listening)
155             {
156                 throw new InvalidOperationException("Already stopped");
157             }
158
159             int ret = _trusted ?
160                         Interop.MessagePort.UnregisterTrustedPort(_portId) :
161                         Interop.MessagePort.UnregisterPort(_portId);
162
163             if (ret != (int)MessagePortError.None)
164             {
165                 MessagePortErrorFactory.ThrowException(ret);
166             }
167
168             lock (s_lock)
169             {
170                 s_portMap.Remove(_portName);
171             }
172             _portId = 0;
173             _listening = false;
174         }
175
176         /// <summary>
177         /// Sends a untrusted message to the message port of a remote application.
178         /// </summary>
179         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB</param>
180         /// <param name="remoteAppId">The ID of the remote application</param>
181         /// <param name="remotePortName">The name of the remote message port</param>
182         public void Send(Bundle message, string remoteAppId, string remotePortName)
183         {
184             Send(message, remoteAppId, remotePortName, false);
185         }
186
187         /// <summary>
188         /// Sends a message to the message port of a remote application.
189         /// </summary>
190         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB</param>
191         /// <param name="remoteAppId">The ID of the remote application</param>
192         /// <param name="remotePortName">The name of the remote message port</param>
193         /// <param name="trusted">If true the trusted message port of remote application otherwise false</param>
194         public void Send(Bundle message, string remoteAppId, string remotePortName, bool trusted)
195         {
196             if (!_listening)
197             {
198                 throw new InvalidOperationException("Should start listen before send");
199             }
200             if (message == null)
201             {
202                 throw new ArgumentNullException("message");
203             }
204             int ret = trusted ?
205                         Interop.MessagePort.SendTrustedMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId) :
206                         Interop.MessagePort.SendMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId);
207
208             if (ret != (int)MessagePortError.None)
209             {
210                 if (ret == (int)MessagePortError.MaxExceeded)
211                 {
212                     MessagePortErrorFactory.ThrowException(ret, "Message has exceeded the maximum limit(4KB)", "Message");
213                 }
214                 MessagePortErrorFactory.ThrowException(ret, "Can't send message");
215             }
216         }
217
218         private void RaiseMessageReceivedEvent(EventHandler<MessageReceivedEventArgs> evt, MessageReceivedEventArgs args)
219         {
220             if (evt != null)
221             {
222                 evt(this, args);
223             }
224         }
225
226         /// <summary>
227         /// Releases the unmanaged resourced used by the MessagePort class specifying whether to perform a normal dispose operation.
228         /// </summary>
229         /// <param name="disposing">true for a normal dispose operation; false to finalize the handle.</param>
230         protected virtual void Dispose(bool disposing)
231         {
232             if (_listening)
233             {
234                 try
235                 {
236                     StopListening();
237                 }
238                 catch (Exception e)
239                 {
240                     Tizen.Log.Warn(GetType().Namespace, "Exception in Dispose :" + e.Message);
241                 }
242             }
243         }
244
245         /// <summary>
246         /// Releases all resources used by the MessagePort class.
247         /// </summary>
248         public void Dispose()
249         {
250             Dispose(true);
251             GC.SuppressFinalize(this);
252         }
253     }
254 }