Merge lp:~mandel/ubuntuone-windows-installer/implement_dotnet_ipc_events into lp:ubuntuone-windows-installer/beta

Proposed by Manuel de la Peña
Status: Merged
Approved by: Rick McBride
Approved revision: 48
Merged at revision: 64
Proposed branch: lp:~mandel/ubuntuone-windows-installer/implement_dotnet_ipc_events
Merge into: lp:ubuntuone-windows-installer/beta
Prerequisite: lp:~mandel/ubuntuone-windows-installer/implement_port_manager
Diff against target: 981 lines (+790/-32)
16 files modified
main.build (+1/-1)
src/Canonical.UbuntuOne.Common/Canonical.UbuntuOne.Common.csproj (+1/-0)
src/Canonical.UbuntuOne.Common/OperationContracts/IEventNotifier.cs (+59/-0)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncConfiguration.cs (+2/-6)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemon.cs (+1/-5)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemonClient.cs (+2/-2)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFileManager.cs (+2/-6)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFolders.cs (+2/-6)
src/Canonical.UbuntuOne.Common/OperationContracts/ISyncShares.cs (+2/-6)
src/Canonical.UbuntuOne.ProcessDispatcher.Tests/Canonical.UbuntuOne.ProcessDispatcher.Tests.csproj (+1/-0)
src/Canonical.UbuntuOne.ProcessDispatcher.Tests/EventNotifierFixture.cs (+239/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/CallerContext.cs (+43/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/Canonical.UbuntuOne.ProcessDispatcher.csproj (+4/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/EventNotifier.cs (+357/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/ICallerContext.cs (+34/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/IEventDispatcher.cs (+40/-0)
To merge this branch: bzr merge lp:~mandel/ubuntuone-windows-installer/implement_dotnet_ipc_events
Reviewer Review Type Date Requested Status
Rick McBride (community) Approve
Stuart Colville (community) Approve
Review via email: mp+32759@code.launchpad.net

Description of the change

Provides the technique used to communicate the different windows client the firing of events from the python code.

To post a comment you must log in.
Revision history for this message
Stuart Colville (muffinresearch) wrote :

tests pass, looks good.

review: Approve
Revision history for this message
Rick McBride (rmcbride) wrote :

Looks good, however 'NAnt.exe tests' hangs after

'Executng Canonical.UbuntuOne.ProcessDispatcher.Tests' and the exec block after it. (Note that Executing is misspelled in the echo string).

At that point nunit-console.exe spikes at 50% processor utilization and about 30,048K. The first time I tried this I left it running like this for two hours and it never came back.

Once the script is broken w/ CTRL-C, nunit-console.exe has to be killed at the task manager before anything further can be run in this context.

review: Needs Fixing
47. By Manuel de la Peña

Modify the tests to beignored until RhinoMocks has multithreading support.

48. By Manuel de la Peña

Fix echo typo.

Revision history for this message
Manuel de la Peña (mandel) wrote :

Rick,

This issue is again due to RhinoMocks not having support with multithreading (major PITA in this area of the code).

As we did with the other test that had this same issue I have added an ignore message. Right now I do not have the time to look at RhinoMocks to add the support or to use a completely diff lib in the project for mocking (I doubt there is any better than Rhino and open sourced).

Revision history for this message
Rick McBride (rmcbride) wrote :

Works now with that test disabled.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'main.build'
--- main.build 2010-08-10 10:04:31 +0000
+++ main.build 2010-08-18 09:45:53 +0000
@@ -176,7 +176,7 @@
176 program="nunit-console.exe"176 program="nunit-console.exe"
177 commandline="Canonical.UbuntuOne.Common.Tests.dll /xml=../../../../test-results/Canonical.UbuntuOne.Common.Tests-Result.xml" /> 177 commandline="Canonical.UbuntuOne.Common.Tests.dll /xml=../../../../test-results/Canonical.UbuntuOne.Common.Tests-Result.xml" />
178 178
179 <echo>Executng Canonical.UbuntuOne.ProcessDispatcher.Tests</echo>179 <echo>Executing Canonical.UbuntuOne.ProcessDispatcher.Tests</echo>
180 <exec basedir="tools/NUnit"180 <exec basedir="tools/NUnit"
181 managed="true"181 managed="true"
182 workingdir="src/Canonical.UbuntuOne.ProcessDispatcher.Tests/bin/${enviroment}"182 workingdir="src/Canonical.UbuntuOne.ProcessDispatcher.Tests/bin/${enviroment}"
183183
=== modified file 'src/Canonical.UbuntuOne.Common/Canonical.UbuntuOne.Common.csproj'
--- src/Canonical.UbuntuOne.Common/Canonical.UbuntuOne.Common.csproj 2010-08-04 14:36:09 +0000
+++ src/Canonical.UbuntuOne.Common/Canonical.UbuntuOne.Common.csproj 2010-08-18 09:45:53 +0000
@@ -58,6 +58,7 @@
58 <Compile Include="Container\SpringContainer.cs" />58 <Compile Include="Container\SpringContainer.cs" />
59 <Compile Include="Container\UnsatisfiedDependencyException.cs" />59 <Compile Include="Container\UnsatisfiedDependencyException.cs" />
60 <Compile Include="IAuthentication.cs" />60 <Compile Include="IAuthentication.cs" />
61 <Compile Include="OperationContracts\IEventNotifier.cs" />
61 <Compile Include="Utils\ApplicationWrapper.cs" />62 <Compile Include="Utils\ApplicationWrapper.cs" />
62 <Compile Include="Utils\Explorer.cs" />63 <Compile Include="Utils\Explorer.cs" />
63 <Compile Include="Utils\ExplorerException.cs" />64 <Compile Include="Utils\ExplorerException.cs" />
6465
=== added file 'src/Canonical.UbuntuOne.Common/OperationContracts/IEventNotifier.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/IEventNotifier.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/IEventNotifier.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.ServiceModel;
21
22namespace Canonical.UbuntuOne.Common.OperationContracts
23{
24 /// <summary>
25 /// Interface to be implemented by those objects that will allow to
26 /// </summary>
27 [ServiceContract( CallbackContract = typeof(ISyncDaemonClient),
28 SessionMode = SessionMode.Required)]
29 public interface IEventNotifier
30 {
31 /// <summary>
32 /// Method that allows to register a client that will be reciving notitications
33 /// from than point until it unregisters
34 /// </summary>
35 [OperationContract(IsOneWay = true)]
36 void RegisterClient();
37
38 /// <summary>
39 /// Method that allows to unregister a client from receiving notification.
40 /// </summary>
41 [OperationContract(IsOneWay = true)]
42 void UnregisterClient();
43
44 /// <summary>
45 /// Method that tells the notifier to start listening for other events using a separate thread.
46 /// </summary>
47 void StartListening();
48
49 /// <summary>
50 /// Method that tells the notifier to stop listning for events.
51 /// </summary>
52 void StopListening();
53
54 /// <summary>
55 /// Gets if the notifier is listening.
56 /// </summary>
57 bool IsListening { get; }
58 }
59}
060
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncConfiguration.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncConfiguration.cs 2010-08-10 08:50:26 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncConfiguration.cs 2010-08-18 09:45:53 +0000
@@ -1,4 +1,4 @@
1/**1/*
2 * Copyright 2010 Canonical Ltd.2 * Copyright 2010 Canonical Ltd.
3 * 3 *
4 * This file is part of UbuntuOne on Windows.4 * This file is part of UbuntuOne on Windows.
@@ -25,11 +25,7 @@
25 /// Interface to be implemented by those object that allows to interact with the 25 /// Interface to be implemented by those object that allows to interact with the
26 /// different setting of the sync daemon.26 /// different setting of the sync daemon.
27 /// </summary>27 /// </summary>
28 [ServiceContract(28 [ServiceContract]
29 Name = "SyncConfiguration",
30 Namespace = "http://one.ubuntu.com/syncconfiguration",
31 CallbackContract = typeof(ISyncDaemonClient),
32 SessionMode = SessionMode.Required)]
33 public interface ISyncConfiguration29 public interface ISyncConfiguration
34 {30 {
35 /// <summary>31 /// <summary>
3632
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemon.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemon.cs 2010-08-10 08:50:26 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemon.cs 2010-08-18 09:45:53 +0000
@@ -26,11 +26,7 @@
26 /// The implementators of this interface should allow the callng clients to perform a number of applications on 26 /// The implementators of this interface should allow the callng clients to perform a number of applications on
27 /// the sync daemon from windows. This will allow users to interact with the daemon through .Net.27 /// the sync daemon from windows. This will allow users to interact with the daemon through .Net.
28 /// </summary>28 /// </summary>
29 [ServiceContract(29 [ServiceContract]
30 Name = "SyncDaemon",
31 Namespace = "http://one.ubuntu.com/syncdaemon",
32 CallbackContract = typeof(ISyncDaemonClient),
33 SessionMode = SessionMode.Required)]
34 public interface ISyncDaemon30 public interface ISyncDaemon
35 {31 {
3632
3733
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemonClient.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemonClient.cs 2010-08-05 07:13:28 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncDaemonClient.cs 2010-08-18 09:45:53 +0000
@@ -1,4 +1,4 @@
1/**1/*
2 * Copyright 2010 Canonical Ltd.2 * Copyright 2010 Canonical Ltd.
3 * 3 *
4 * This file is part of UbuntuOne on Windows.4 * This file is part of UbuntuOne on Windows.
@@ -25,7 +25,7 @@
25 /// Interface to be implementedby a sync daemon client that wants to interact with the 25 /// Interface to be implementedby a sync daemon client that wants to interact with the
26 /// daemon that manages the Ubuntu One storage in a machine.26 /// daemon that manages the Ubuntu One storage in a machine.
27 /// </summary>27 /// </summary>
28 [ServiceContract(Namespace = "http://one.ubuntu.com/client")]28 [ServiceContract]
29 public interface ISyncDaemonClient29 public interface ISyncDaemonClient
30 {30 {
31 /// <summary>31 /// <summary>
3232
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFileManager.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFileManager.cs 2010-08-10 08:50:26 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFileManager.cs 2010-08-18 09:45:53 +0000
@@ -1,4 +1,4 @@
1/**1/*
2 * Copyright 2010 Canonical Ltd.2 * Copyright 2010 Canonical Ltd.
3 * 3 *
4 * This file is part of UbuntuOne on Windows.4 * This file is part of UbuntuOne on Windows.
@@ -25,11 +25,7 @@
25 /// <summary>25 /// <summary>
26 /// Service that provides method to interact with the FileManager used by the sync daemon.26 /// Service that provides method to interact with the FileManager used by the sync daemon.
27 /// </summary>27 /// </summary>
28 [ServiceContract(28 [ServiceContract]
29 Name = "SyncFileManager",
30 Namespace = "http://one.ubuntu.com/syncfilemanager",
31 CallbackContract = typeof(ISyncDaemonClient),
32 SessionMode = SessionMode.Required)]
33 public interface ISyncFileManager29 public interface ISyncFileManager
34 {30 {
3531
3632
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFolders.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFolders.cs 2010-08-10 08:50:26 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncFolders.cs 2010-08-18 09:45:53 +0000
@@ -1,4 +1,4 @@
1/**1/*
2 * Copyright 2010 Canonical Ltd.2 * Copyright 2010 Canonical Ltd.
3 * 3 *
4 * This file is part of UbuntuOne on Windows.4 * This file is part of UbuntuOne on Windows.
@@ -26,11 +26,7 @@
26 /// Interface to be implemented by those objects that allow to interact with the data related to 26 /// Interface to be implemented by those objects that allow to interact with the data related to
27 /// the sync folders by the Ubuntu One sync daemon.27 /// the sync folders by the Ubuntu One sync daemon.
28 /// </summary>28 /// </summary>
29 [ServiceContract(29 [ServiceContract]
30 Name = "SyncFolders",
31 Namespace = "http://one.ubuntu.com/syncfolders",
32 CallbackContract = typeof(ISyncDaemonClient),
33 SessionMode = SessionMode.Required)]
34 public interface ISyncFolders30 public interface ISyncFolders
35 {31 {
3632
3733
=== modified file 'src/Canonical.UbuntuOne.Common/OperationContracts/ISyncShares.cs'
--- src/Canonical.UbuntuOne.Common/OperationContracts/ISyncShares.cs 2010-08-10 08:50:26 +0000
+++ src/Canonical.UbuntuOne.Common/OperationContracts/ISyncShares.cs 2010-08-18 09:45:53 +0000
@@ -1,4 +1,4 @@
1/**1/*
2 * Copyright 2010 Canonical Ltd.2 * Copyright 2010 Canonical Ltd.
3 * 3 *
4 * This file is part of UbuntuOne on Windows.4 * This file is part of UbuntuOne on Windows.
@@ -26,11 +26,7 @@
26 /// Contract to be implemented by a object that allows to interact with the different shares26 /// Contract to be implemented by a object that allows to interact with the different shares
27 /// that a user has in the Ubuntu One storage infrastructure.27 /// that a user has in the Ubuntu One storage infrastructure.
28 /// </summary>28 /// </summary>
29 [ServiceContract(29 [ServiceContract]
30 Name = "SyncShares",
31 Namespace = "http://one.ubuntu.com/shares",
32 CallbackContract = typeof(ISyncDaemonClient),
33 SessionMode = SessionMode.Required)]
34 public interface ISyncShares30 public interface ISyncShares
35 {31 {
3632
3733
=== modified file 'src/Canonical.UbuntuOne.ProcessDispatcher.Tests/Canonical.UbuntuOne.ProcessDispatcher.Tests.csproj'
--- src/Canonical.UbuntuOne.ProcessDispatcher.Tests/Canonical.UbuntuOne.ProcessDispatcher.Tests.csproj 2010-08-12 07:59:15 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher.Tests/Canonical.UbuntuOne.ProcessDispatcher.Tests.csproj 2010-08-18 09:45:53 +0000
@@ -55,6 +55,7 @@
55 <Compile Include="..\Version.cs">55 <Compile Include="..\Version.cs">
56 <Link>Properties\Version.cs</Link>56 <Link>Properties\Version.cs</Link>
57 </Compile>57 </Compile>
58 <Compile Include="EventNotifierFixture.cs" />
58 <Compile Include="Net\PortManagerFixture.cs" />59 <Compile Include="Net\PortManagerFixture.cs" />
59 <Compile Include="Net\TcpClientCommunicatorFixture.cs" />60 <Compile Include="Net\TcpClientCommunicatorFixture.cs" />
60 <Compile Include="Net\TcpClientFactoryFixture.cs" />61 <Compile Include="Net\TcpClientFactoryFixture.cs" />
6162
=== added file 'src/Canonical.UbuntuOne.ProcessDispatcher.Tests/EventNotifierFixture.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher.Tests/EventNotifierFixture.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher.Tests/EventNotifierFixture.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,239 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System;
21using System.Net.Sockets;
22using Canonical.UbuntuOne.Common;
23using Canonical.UbuntuOne.ProcessDispatcher.Net;
24using NUnit.Framework;
25using Rhino.Mocks;
26
27namespace Canonical.UbuntuOne.ProcessDispatcher.Tests
28{
29 [TestFixture]
30 public class EventNotifierFixture
31 {
32 #region Vars
33
34 private MockRepository _mocks;
35 private IEventDispatcher _eventDispatcher;
36 private ISyncDaemonClient _notifyIconClient;
37 private ICallerContext<ISyncDaemonClient> _callerContext;
38 private IPortManager _portManager;
39 private IProtobufSerializer _serilizer;
40 private TcpClient _client;
41 private EventNotifier _notifier;
42 private int _freePort;
43
44 #endregion
45
46 #region Setup
47
48 [SetUp]
49 public void Setup()
50 {
51 _mocks = new MockRepository();
52 _eventDispatcher = _mocks.DynamicMock<IEventDispatcher>();
53 _notifyIconClient = _mocks.StrictMock<ISyncDaemonClient>();
54 _mocks.StrictMock<ISyncDaemonClient>();
55 _callerContext = _mocks.StrictMock<ICallerContext<ISyncDaemonClient>>();
56 _portManager = _mocks.StrictMock<IPortManager>();
57 _serilizer = _mocks.DynamicMock<IProtobufSerializer>();
58 _freePort = 50128;
59 _notifier = new EventNotifier
60 {
61 CallerContext = _callerContext,
62 EventDispatcher = _eventDispatcher,
63 PortManager = _portManager,
64 ProtobufSerializer = _serilizer
65 };
66 }
67
68 [TearDown]
69 public void TearDown()
70 {
71 _notifier.KillListeningThread();
72 }
73
74 #endregion
75
76 #region Tests
77
78 [Test]
79 public void RegisterClientTest()
80 {
81 using (_mocks.Record())
82 {
83 Expect.Call(_callerContext.GetCaller())
84 .Return(_notifyIconClient)
85 .Repeat.Once();
86 }
87 using(_mocks.Playback())
88 {
89 _notifier.RegisterClient();
90 }
91 }
92
93 [Test]
94 public void UnregisterClientRegisteredTest()
95 {
96 using (_mocks.Record())
97 {
98 Expect.Call(_callerContext.GetCaller())
99 .Return(_notifyIconClient)
100 .Repeat.Once();
101 }
102 using (_mocks.Playback())
103 {
104 _notifier.UnregisterClient();
105 }
106 }
107
108 [Test]
109 public void UnregisterClientNotRegisteredTest()
110 {
111 using (_mocks.Record())
112 {
113 Expect.Call(_callerContext.GetCaller())
114 .Return(_notifyIconClient)
115 .Repeat.Once();
116 }
117 using (_mocks.Playback())
118 {
119 _notifier.UnregisterClient();
120 }
121 }
122
123 [Test]
124 public void StartListeningTest()
125 {
126 try
127 {
128 Assert.Ignore("This test is not reliable until RhinoMocks has multithread support.");
129 //using (_mocks.Record())
130 //{
131 // Expect.Call(_portManager.GetDotNetClientPort())
132 // .Return(_freePort)
133 // .Repeat.Any();
134 //}
135 //using (_mocks.Playback())
136 //{
137 // _notifier.StartListening();
138 // // create a client that will connect to the port
139 // while (!_notifier.IsListening)
140 // {
141 // // wait doing nothing :(
142 // }
143 // _client = new TcpClient("localhost", _freePort);
144 // // write data in the buffer to tell the the event notifier
145 // var stream = _client.GetStream();
146 // var data = System.Text.Encoding.ASCII.GetBytes("Test");
147 // stream.Write(data, 0, data.Length);
148 // stream.Flush();
149 // stream.Close();
150 //}
151 }
152 catch (SocketException)
153 {
154 Assert.Inconclusive(
155 "The test could not be performed due to a socket exception. You firewall is probably blocking connections to {0}",
156 _freePort);
157 }
158 }
159
160 [Test]
161 [ExpectedException(typeof(InvalidOperationException))]
162 public void StartListeningAlreadyListeningTest()
163 {
164 try
165 {
166 using (_mocks.Record())
167 {
168 Expect.Call(_portManager.GetDotNetClientPort())
169 .Return(_freePort)
170 .Repeat.Once();
171 }
172 using (_mocks.Playback())
173 {
174 _notifier.StartListening();
175 _notifier.StartListening();
176 }
177 }
178 catch (SocketException)
179 {
180 Assert.Inconclusive(
181 "The test could not be performed due to a socket exception. You firewall is probably blocking connections to {0}",
182 _freePort);
183 }
184 }
185
186 [Test]
187 public void StopListeningTest()
188 {
189 try
190 {
191 using (_mocks.Record())
192 {
193 Expect.Call(_portManager.GetDotNetClientPort())
194 .Return(_freePort)
195 .Repeat.Any();
196 }
197 using (_mocks.Playback())
198 {
199 _notifier.StartListening();
200 _notifier.StopListening();
201 }
202 }
203 catch (SocketException)
204 {
205 Assert.Inconclusive(
206 "The test could not be performed due to a socket exception. You firewall is probably blocking connections to {0}",
207 _freePort);
208 }
209 }
210
211 [Test]
212 [ExpectedException(typeof(InvalidOperationException))]
213 public void StopListeningExceptionTest()
214 {
215 try
216 {
217 using (_mocks.Record())
218 {
219 Expect.Call(_portManager.GetDotNetClientPort())
220 .Return(_freePort)
221 .Repeat.Once();
222 }
223 using (_mocks.Playback())
224 {
225 _notifier.StopListening();
226 }
227 }
228 catch(SocketException)
229 {
230 Assert.Inconclusive(
231 "The test could not be performed due to a socket exception. You firewall is probably blocking connections to {0}",
232 _freePort);
233 }
234 }
235
236 #endregion
237
238 }
239}
0240
=== added file 'src/Canonical.UbuntuOne.ProcessDispatcher/CallerContext.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher/CallerContext.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/CallerContext.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.ServiceModel;
21
22namespace Canonical.UbuntuOne.ProcessDispatcher
23{
24 /// <summary>
25 /// Implementation of the ICallerContext that realies in WCF the retrive the caller of a
26 /// WCF Operation contract.
27 /// </summary>
28 internal class CallerContext<TCaller> : ICallerContext<TCaller>
29 {
30 #region Implementation of ICallerContext<TCaller>
31
32 /// <summary>
33 /// Returns the object that has called the method,
34 /// </summary>
35 /// <returns>The object that performed the call.</returns>
36 public TCaller GetCaller()
37 {
38 return OperationContext.Current.GetCallbackChannel<TCaller>();
39 }
40
41 #endregion
42 }
43}
044
=== modified file 'src/Canonical.UbuntuOne.ProcessDispatcher/Canonical.UbuntuOne.ProcessDispatcher.csproj'
--- src/Canonical.UbuntuOne.ProcessDispatcher/Canonical.UbuntuOne.ProcessDispatcher.csproj 2010-08-12 07:59:15 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/Canonical.UbuntuOne.ProcessDispatcher.csproj 2010-08-18 09:45:53 +0000
@@ -71,6 +71,10 @@
71 <Compile Include="..\Version.cs">71 <Compile Include="..\Version.cs">
72 <Link>Properties\Version.cs</Link>72 <Link>Properties\Version.cs</Link>
73 </Compile>73 </Compile>
74 <Compile Include="CallerContext.cs" />
75 <Compile Include="EventNotifier.cs" />
76 <Compile Include="ICallerContext.cs" />
77 <Compile Include="IEventDispatcher.cs" />
74 <Compile Include="Net\IPortFinder.cs" />78 <Compile Include="Net\IPortFinder.cs" />
75 <Compile Include="Net\IPortManager.cs" />79 <Compile Include="Net\IPortManager.cs" />
76 <Compile Include="Net\ITcpClient.cs" />80 <Compile Include="Net\ITcpClient.cs" />
7781
=== added file 'src/Canonical.UbuntuOne.ProcessDispatcher/EventNotifier.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher/EventNotifier.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/EventNotifier.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,357 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System;
21using System.Collections.Generic;
22using System.IO;
23using System.Net;
24using System.Net.Sockets;
25using System.Threading;
26using Canonical.UbuntuOne.Common;
27using Canonical.UbuntuOne.Common.OperationContracts;
28using Canonical.UbuntuOne.ProcessDispatcher.Net;
29using log4net;
30using PortManagerImpl = Canonical.UbuntuOne.ProcessDispatcher.Net.PortManager;
31
32namespace Canonical.UbuntuOne.ProcessDispatcher
33{
34 /// <summary>
35 /// Implementation of the IEventNotifier that receives messages from the python code through sockets and
36 /// broadcasts those messages to the .net clients that have registered to receive them.
37 /// </summary>
38 internal class EventNotifier : IEventNotifier
39 {
40 #region Helper class
41
42 /// <summary>
43 /// This class is used to allows to keep the state of the async reading operation of the
44 /// socket.
45 /// </summary>
46 private class StateObject
47 {
48 /// <summary>
49 /// The socket we are working with.
50 /// </summary>
51 public Socket WorkSocket;
52
53 /// <summary>
54 /// The size of the buffer that will be used to read.
55 /// </summary>
56 public const int BufferSize = 1024;
57
58 /// <summary>
59 /// The buffer wich will be used to place the read information.
60 /// </summary>
61 public readonly byte[] Buffer = new byte[BufferSize];
62
63 /// <summary>
64 /// Stream that is used to concatenated the data that has been processed
65 /// so far.
66 /// </summary>
67 public readonly MemoryStream ResultBuilder = new MemoryStream();
68 }
69
70 #endregion
71
72 #region Vars
73
74 private IPortManager _portManager;
75 private ILog _logger;
76 private readonly object _loggerLock = new object();
77 private readonly object _clientsLock = new object();
78 private readonly object _portManagerLock = new object();
79 private readonly object _isListeningLock = new object();
80 private static readonly ManualResetEvent _allDone = new ManualResetEvent(false);
81 private static readonly HashSet<ISyncDaemonClient> _registeredClients = new HashSet<ISyncDaemonClient>();
82 private bool _hasToListen;
83 private bool _isListening;
84 private Thread _listeningThread;
85
86 #endregion
87
88 #region DI properties
89
90 /// <summary>
91 /// Gets and sets the protobuf serializer that is used to deserialize the messages comming from python.
92 /// </summary>
93 internal IProtobufSerializer ProtobufSerializer { get; set; }
94
95 /// <summary>
96 /// Gets and sets the event dispatcher that is used to notify the different clients about
97 /// an event.
98 /// </summary>
99 internal IEventDispatcher EventDispatcher { get; set; }
100
101 /// <summary>
102 /// Gets and sets the object that is used to retrieve the information of the object
103 /// that performs the different WCF calls.
104 /// </summary>
105 internal ICallerContext<ISyncDaemonClient> CallerContext { get; set; }
106
107 /// <summary>
108 /// Gets and sets the logger that is used to log the different activities.
109 /// </summary>
110 internal ILog Logger
111 {
112 get
113 {
114 if(_logger == null)
115 {
116 lock (_loggerLock)
117 {
118 _logger = LogManager.GetLogger(typeof (EventNotifier));
119 }
120 }
121 return _logger;
122 }
123 set { _logger = value; }
124 }
125 /// <summary>
126 /// Gets and sets the port manager that is used to ensure that the ports are correctly used
127 /// for the application per user.
128 /// </summary>
129 internal IPortManager PortManager
130 {
131 get
132 {
133 if(_portManager == null)
134 {
135 lock (_portManagerLock)
136 {
137 _portManager = PortManagerImpl.Instance;
138 }
139 }
140 return _portManager;
141 }
142 set { _portManager = value; }
143 }
144
145 #endregion
146
147 #region HelperMethods
148
149 /// <summary>
150 /// This method listens to the port that has been set for this service to be listening for
151 /// </summary>
152 private void Listen()
153 {
154
155 var localEndPoint = new IPEndPoint(IPAddress.Any, PortManager.GetDotNetClientPort());
156 var listener = new Socket(localEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
157 try
158 {
159 listener.Bind(localEndPoint);
160 listener.Listen(1000);
161 lock (_isListeningLock)
162 {
163 _isListening = true;
164 }
165 while (_hasToListen)
166 {
167 _allDone.Reset();
168
169 Logger.Info("Waiting for a connection...");
170 listener.BeginAccept(
171 new AsyncCallback(AcceptCallback),
172 listener);
173
174 _allDone.WaitOne();
175 }
176 }
177 catch (Exception e)
178 {
179 var message = string.Format("An exception was thrown when listening to port {0}",
180 PortManager.GetDotNetClientPort());
181 Logger.Error(message, e);
182 }
183 }
184
185 /// <summary>
186 /// Callback that will be used to accept connections in an async manner. The method
187 /// will be ran in a separate thread and will take care of dispathinch the work to other threads.
188 /// </summary>
189 /// <param name="asyncResult">The async result that will be passed to the call back with the
190 /// connect information.</param>
191 private void AcceptCallback(IAsyncResult asyncResult)
192 {
193 var listener = (Socket)asyncResult.AsyncState;
194 var handler = listener.EndAccept(asyncResult);
195 // Signal the main thread to continue.
196 _allDone.Set();
197
198 // Create the state object.
199 var state = new StateObject
200 {
201 WorkSocket = handler
202 };
203 handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
204 new AsyncCallback(ReadCallback), state);
205 }
206
207 /// <summary>
208 /// Callback that will be used after a read operation has been performed once the data from
209 /// the python client has arrived.
210 /// </summary>
211 /// <param name="ar">The async result that will be passed to the callback with the read information
212 /// that has been collected so far.</param>
213 private void ReadCallback(IAsyncResult ar)
214 {
215 var state = (StateObject)ar.AsyncState;
216 var handler = state.WorkSocket;
217
218 // Read data from the client socket.
219 var read = handler.EndReceive(ar);
220
221 // Data was read from the client socket.
222 if (read > 0)
223 {
224 // create a binary writer that will be used to append the data to the stream.
225 var writer = new BinaryWriter(state.ResultBuilder);
226 writer.Write(state.Buffer, 0, read);
227 writer.Flush();
228 // start another callback to see if we have more info to read.
229 handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
230 new AsyncCallback(ReadCallback), state);
231 }
232 else
233 {
234 if (state.ResultBuilder.Length > 1)
235 {
236 // All the data has been read from the client;
237 // display it on the console.
238 var workThread = new Thread(ProcessMessage);
239 workThread.Start(state.ResultBuilder);
240
241 }
242 handler.Close();
243 }
244 }
245
246 /// <summary>
247 /// Method that will be executed in a thread that will process the message comming from python and
248 /// will notify the different clients.
249 /// </summary>
250 /// <param name="o">An object that should be castable to a MemoryStream that contains the data of the
251 /// protobuf message.</param>
252 private void ProcessMessage(object o)
253 {
254 // cast the object to the data that we actually have,
255 var data = (MemoryStream) o;
256 var protobufMessage = ProtobufSerializer.Deserialize<SyncDaemonClientMessage>(data);
257 EventDispatcher.Dispatch(protobufMessage, _registeredClients);
258 }
259
260 #endregion
261
262 /// <summary>
263 /// Helper method that can be used internally to kill the listening thread to allow the event listener to stop. This
264 /// method is very useful when running tests to be sure that not too many threads are kept alive.
265 /// </summary>
266 internal void KillListeningThread()
267 {
268 if (_listeningThread != null)
269 {
270 _hasToListen = false;
271 _listeningThread.Abort();
272 }
273 }
274
275 #region Implementation of IEventNotifier
276
277 /// <summary>
278 /// Method that allows to register a client that will be reciving notitications
279 /// from than point until it unregisters
280 /// </summary>
281 public void RegisterClient()
282 {
283 lock (_clientsLock)
284 {
285 // we get the client that will be used for the callbacks
286 var client = CallerContext.GetCaller();
287 if(!_registeredClients.Contains(client))
288 {
289 _registeredClients.Add(client);
290 }
291 }
292 }
293
294 /// <summary>
295 /// Method that allows to unregister a client from receiving notification.
296 /// </summary>
297 public void UnregisterClient()
298 {
299 lock (_clientsLock)
300 {
301 var client = CallerContext.GetCaller();
302 if(_registeredClients.Contains(client))
303 {
304 _registeredClients.Remove(client);
305 }
306 }
307 }
308
309 /// <summary>
310 /// Method that tells the notifier to start listening for other events using a separate thread.
311 /// </summary>
312 public void StartListening()
313 {
314 if (!_hasToListen)
315 {
316 _hasToListen = true;
317 // Once created, start listening to the port used by python to talk with us
318 _listeningThread = new Thread(Listen) {Name = "EventNotifierSocketServer"};
319 _listeningThread.Start();
320 }
321 else
322 {
323 throw new InvalidOperationException("EventNotifier cannot start listning because it already is.");
324 }
325 }
326
327 /// <summary>
328 /// Method that tells the notifier to stop listning for events.
329 /// </summary>
330 public void StopListening()
331 {
332 if (_hasToListen)
333 {
334 _hasToListen = false;
335 lock (_isListeningLock)
336 {
337 _isListening = false;
338 }
339 _listeningThread.Join();
340 }
341 else
342 {
343 throw new InvalidOperationException("Cannot stop listening because EventNotifier never started to listen.");
344 }
345 }
346
347 /// <summary>
348 /// Gets if the notifier is listening.
349 /// </summary>
350 public bool IsListening
351 {
352 get { return _isListening; }
353 }
354
355 #endregion
356 }
357}
0358
=== added file 'src/Canonical.UbuntuOne.ProcessDispatcher/ICallerContext.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher/ICallerContext.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/ICallerContext.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,34 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20namespace Canonical.UbuntuOne.ProcessDispatcher
21{
22 /// <summary>
23 /// Interface to be implemented by those objects that can retrieve information regarding the
24 /// context of a method call.
25 /// </summary>
26 internal interface ICallerContext<TCaller>
27 {
28 /// <summary>
29 /// Returns the object that has called the method,
30 /// </summary>
31 /// <returns>The object that performed the call.</returns>
32 TCaller GetCaller();
33 }
34}
035
=== added file 'src/Canonical.UbuntuOne.ProcessDispatcher/IEventDispatcher.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher/IEventDispatcher.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/IEventDispatcher.cs 2010-08-18 09:45:53 +0000
@@ -0,0 +1,40 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.Collections.Generic;
21using Canonical.UbuntuOne.Common;
22
23namespace Canonical.UbuntuOne.ProcessDispatcher
24{
25 /// <summary>
26 /// Interface to be implemented by an object that knows how to dispatch events froma protobuf message
27 /// to a collection of ISyncDaemonClients.
28 /// </summary>
29 internal interface IEventDispatcher
30 {
31 /// <summary>
32 /// Method that ensures that an event that is given in a particular protobuf message
33 /// is notified to all the different clients.
34 /// </summary>
35 /// <param name="clientMessage">The client message that was sent by the python code.</param>
36 /// <param name="clients">An enumerable that contains all those clients that have to be notified about the
37 /// particular event.</param>
38 void Dispatch(SyncDaemonClientMessage clientMessage, IEnumerable<ISyncDaemonClient> clients);
39 }
40}

Subscribers

People subscribed via source and target branches

to all changes: