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

Proposed by Manuel de la Peña
Status: Merged
Approved by: John Lenton
Approved revision: 165
Merged at revision: 127
Proposed branch: lp:~mandel/ubuntuone-windows-installer/improve_u1sync_communication
Merge into: lp:ubuntuone-windows-installer/beta
Prerequisite: lp:~mandel/ubuntuone-windows-installer/remove_recently_modifed_state_spaces
Diff against target: 391 lines (+136/-29)
9 files modified
src/Canonical.UbuntuOne.Client.Views/NotifyIcon.xaml.cs (+26/-1)
src/Canonical.UbuntuOne.Client/Canonical.UbuntuOne.Client.csproj (+1/-0)
src/Canonical.UbuntuOne.Client/Notification/Enums.cs (+40/-0)
src/Canonical.UbuntuOne.Client/Notification/INotificationIconPresenter.cs (+19/-17)
src/Canonical.UbuntuOne.Client/Notification/INotificationIconView.cs (+9/-0)
src/Canonical.UbuntuOne.ProcessDispatcher/JsonMessageProcessor.cs (+7/-1)
src/u1sync/main.py (+9/-1)
src/u1sync/sync.py (+21/-5)
src/u1sync/utils.py (+4/-4)
To merge this branch: bzr merge lp:~mandel/ubuntuone-windows-installer/improve_u1sync_communication
Reviewer Review Type Date Requested Status
John Lenton (community) Approve
Review via email: mp+39906@code.launchpad.net

Description of the change

Improve the u1sync communication.

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Canonical.UbuntuOne.Client.Views/NotifyIcon.xaml.cs'
--- src/Canonical.UbuntuOne.Client.Views/NotifyIcon.xaml.cs 2010-11-02 22:21:27 +0000
+++ src/Canonical.UbuntuOne.Client.Views/NotifyIcon.xaml.cs 2010-11-02 22:21:27 +0000
@@ -86,7 +86,32 @@
86 /// <param name="text">The text of the notification.</param>86 /// <param name="text">The text of the notification.</param>
87 public void ShowNotification(int timeout, string title, string text)87 public void ShowNotification(int timeout, string title, string text)
88 {88 {
89 NotifyIcon.ShowBalloonTip(timeout, title, text, NotifyBalloonIcon.Info);89 ShowNotification(timeout, title, text, NotificationType.INFO);
90 }
91
92 /// <summary>
93 /// Shows a notification to the user.
94 /// </summary>
95 /// <param name="timeout">The amount of time the notification will be shown.</param>
96 /// <param name="title">The title of the notification.</param>
97 /// <param name="text">The text of the actual notification.</param>
98 /// <param name="type">The type of notification sent.</param>
99 public void ShowNotification(int timeout, string title, string text, NotificationType type)
100 {
101 var icon = NotifyBalloonIcon.None;
102 switch (type)
103 {
104 case NotificationType.ERROR:
105 icon = NotifyBalloonIcon.Error;
106 break;
107 case NotificationType.WARNING:
108 icon = NotifyBalloonIcon.Warning;
109 break;
110 default:
111 icon = NotifyBalloonIcon.Info;
112 break;
113 }
114 NotifyIcon.ShowBalloonTip(timeout, title, text, icon);
90 }115 }
91116
92 /// <summary>117 /// <summary>
93118
=== modified file 'src/Canonical.UbuntuOne.Client/Canonical.UbuntuOne.Client.csproj'
--- src/Canonical.UbuntuOne.Client/Canonical.UbuntuOne.Client.csproj 2010-10-19 12:34:50 +0000
+++ src/Canonical.UbuntuOne.Client/Canonical.UbuntuOne.Client.csproj 2010-11-02 22:21:27 +0000
@@ -74,6 +74,7 @@
74 <Compile Include="..\Version.cs">74 <Compile Include="..\Version.cs">
75 <Link>Properties\Version.cs</Link>75 <Link>Properties\Version.cs</Link>
76 </Compile>76 </Compile>
77 <Compile Include="Notification\Enums.cs" />
77 <Compile Include="Notification\INotificationIconView.cs" />78 <Compile Include="Notification\INotificationIconView.cs" />
78 <Compile Include="Notification\IStateMapper.cs" />79 <Compile Include="Notification\IStateMapper.cs" />
79 <Compile Include="Notification\ISyncDaemonClientNotifier.cs" />80 <Compile Include="Notification\ISyncDaemonClientNotifier.cs" />
8081
=== added file 'src/Canonical.UbuntuOne.Client/Notification/Enums.cs'
--- src/Canonical.UbuntuOne.Client/Notification/Enums.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.UbuntuOne.Client/Notification/Enums.cs 2010-11-02 22:21:27 +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 */
20namespace Canonical.UbuntuOne.Client.Notification
21{
22 /// <summary>
23 /// Enum that contains the different types of notifications.
24 /// </summary>
25 public enum NotificationType
26 {
27 ///<summary>
28 /// Enum that states that the notification provides information.
29 ///</summary>
30 INFO,
31 /// <summary>
32 /// Enum that states that the notification provides an error.
33 /// </summary>
34 ERROR,
35 /// <summary>
36 /// Enum that states that the notification provides a warning.
37 /// </summary>
38 WARNING
39 }
40}
041
=== modified file 'src/Canonical.UbuntuOne.Client/Notification/INotificationIconPresenter.cs'
--- src/Canonical.UbuntuOne.Client/Notification/INotificationIconPresenter.cs 2010-08-30 17:30:31 +0000
+++ src/Canonical.UbuntuOne.Client/Notification/INotificationIconPresenter.cs 2010-11-02 22:21:27 +0000
@@ -1,20 +1,22 @@
1// Copyright 2010 Canonical Ltd.1/*
2// 2 * Copyright 2010 Canonical Ltd.
3// This file is part of UbuntuOne on Windows.3 *
4// 4 * This file is part of UbuntuOne on Windows.
5// UbuntuOne on Windows is free software: you can redistribute it and/or modify 5 *
6// it under the terms of the GNU Lesser General Public License version 6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7// as published by the Free Software Foundation. 7 * it under the terms of the GNU Lesser General Public License version
8// 8 * as published by the Free Software Foundation.
9// Ubuntu One on Windows is distributed in the hope that it will be useful,9 *
10// but WITHOUT ANY WARRANTY; without even the implied warranty of10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12// GNU Lesser General Public License for more details. 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13//13 * GNU Lesser General Public License for more details.
14// You should have received a copy of the GNU Lesser General Public License 14 *
15// along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.15 * You should have received a copy of the GNU Lesser General Public License
16// 16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17// Authors: Manuel de la Peña <manuel.delapena@canonical.com>17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
18namespace Canonical.UbuntuOne.Client.Notification20namespace Canonical.UbuntuOne.Client.Notification
19{21{
20 /// <summary>22 /// <summary>
2123
=== modified file 'src/Canonical.UbuntuOne.Client/Notification/INotificationIconView.cs'
--- src/Canonical.UbuntuOne.Client/Notification/INotificationIconView.cs 2010-10-20 23:09:36 +0000
+++ src/Canonical.UbuntuOne.Client/Notification/INotificationIconView.cs 2010-11-02 22:21:27 +0000
@@ -41,6 +41,15 @@
41 void ShowNotification(int timeout, string title, string text);41 void ShowNotification(int timeout, string title, string text);
4242
43 /// <summary>43 /// <summary>
44 /// Shows a notification to the user.
45 /// </summary>
46 /// <param name="timeout">The amount of time the notification will be shown.</param>
47 /// <param name="title">The title of the notification.</param>
48 /// <param name="text">The text of the actual notification.</param>
49 /// <param name="type">The type of notification sent.</param>
50 void ShowNotification(int timeout, string title, string text, NotificationType type);
51
52 /// <summary>
44 /// Gets and sets the list of recently modified files.53 /// Gets and sets the list of recently modified files.
45 /// </summary>54 /// </summary>
46 IList<string> RecentlyModifiedFiles { get; set; }55 IList<string> RecentlyModifiedFiles { get; set; }
4756
=== modified file 'src/Canonical.UbuntuOne.ProcessDispatcher/JsonMessageProcessor.cs'
--- src/Canonical.UbuntuOne.ProcessDispatcher/JsonMessageProcessor.cs 2010-10-19 12:34:50 +0000
+++ src/Canonical.UbuntuOne.ProcessDispatcher/JsonMessageProcessor.cs 2010-11-02 22:21:27 +0000
@@ -47,7 +47,13 @@
47 var messageObject = (JObject) message;47 var messageObject = (JObject) message;
48 if(string.Compare((string)messageObject["type"], "notify", StringComparison.CurrentCultureIgnoreCase) == 0)48 if(string.Compare((string)messageObject["type"], "notify", StringComparison.CurrentCultureIgnoreCase) == 0)
49 {49 {
50 NotificationIconView.ShowNotification(10, (string)messageObject["title"], (string)messageObject["message"]);50 NotificationIconView.ShowNotification(5, (string)messageObject["title"], (string)messageObject["message"],
51 NotificationType.INFO);
52 }
53 if(string.Compare((string)messageObject["type"], "error", StringComparison.CurrentCultureIgnoreCase) == 0)
54 {
55 NotificationIconView.ShowNotification(5, "Error", (string) messageObject["message"],
56 NotificationType.ERROR);
51 }57 }
52 }58 }
53 }59 }
5460
=== modified file 'src/u1sync/main.py'
--- src/u1sync/main.py 2010-10-19 10:35:43 +0000
+++ src/u1sync/main.py 2010-11-02 22:21:27 +0000
@@ -43,7 +43,7 @@
43from u1sync.merge import (43from u1sync.merge import (
44 SyncMerge, ClobberServerMerge, ClobberLocalMerge, merge_trees)44 SyncMerge, ClobberServerMerge, ClobberLocalMerge, merge_trees)
45from u1sync.sync import download_tree, upload_tree45from u1sync.sync import download_tree, upload_tree
46from u1sync.utils import safe_mkdir, send_bus_error, send_notification46from u1sync.utils import safe_mkdir, send_error, send_notification
47from u1sync import metadata47from u1sync import metadata
48from u1sync.constants import METADATA_DIR_NAME48from u1sync.constants import METADATA_DIR_NAME
49from u1sync.ubuntuone_optparse import UbuntuOneOptionsParser49from u1sync.ubuntuone_optparse import UbuntuOneOptionsParser
@@ -335,21 +335,29 @@
335 try:335 try:
336 do_main(argv, UbuntuOneOptionsParser())336 do_main(argv, UbuntuOneOptionsParser())
337 except AuthenticationError, e:337 except AuthenticationError, e:
338 send_error("Authentication failed: %s" % e, e)
338 print "Authentication failed: %s" % e339 print "Authentication failed: %s" % e
339 except ConnectionError, e:340 except ConnectionError, e:
341 send_error("Connection failed: %s" % e, e)
340 print "Connection failed: %s" % e342 print "Connection failed: %s" % e
341 except DirectoryNotInitializedError, e:343 except DirectoryNotInitializedError, e:
344 send_error("Directory not initialized", e)
342 print "Directory not initialized; " \345 print "Directory not initialized; " \
343 "use --init [DIRECTORY] to initialize it."346 "use --init [DIRECTORY] to initialize it."
344 except DirectoryAlreadyInitializedError, e:347 except DirectoryAlreadyInitializedError, e:
348 send_error("Directory already initialized.", e)
345 print "Directory already initialized."349 print "Directory already initialized."
346 except NoSuchShareError, e:350 except NoSuchShareError, e:
351 send_error("No matching share found.", e)
347 print "No matching share found."352 print "No matching share found."
348 except ReadOnlyShareError, e:353 except ReadOnlyShareError, e:
354 send_error("The selected action isn't possible on a read-only share.", e)
349 print "The selected action isn't possible on a read-only share."355 print "The selected action isn't possible on a read-only share."
350 except (ForcedShutdown, KeyboardInterrupt), e:356 except (ForcedShutdown, KeyboardInterrupt), e:
357 send_error("Interrupted!", e)
351 print "Interrupted!"358 print "Interrupted!"
352 except TreesDiffer, e:359 except TreesDiffer, e:
360 send_error("Trees differ.", e)
353 if not e.quiet:361 if not e.quiet:
354 print "Trees differ."362 print "Trees differ."
355 else:363 else:
356364
=== modified file 'src/u1sync/sync.py'
--- src/u1sync/sync.py 2010-10-20 08:42:42 +0000
+++ src/u1sync/sync.py 2010-11-02 22:21:27 +0000
@@ -35,7 +35,7 @@
35 DIRECTORY, SYMLINK)35 DIRECTORY, SYMLINK)
36from u1sync.genericmerge import (36from u1sync.genericmerge import (
37 MergeNode, generic_merge)37 MergeNode, generic_merge)
38from u1sync.utils import safe_mkdir, send_notification38from u1sync.utils import safe_mkdir, send_notification, send_error
39from u1sync.client import UnsupportedOperationError39from u1sync.client import UnsupportedOperationError
4040
41def get_conflict_path(path, conflict_info):41def get_conflict_path(path, conflict_info):
@@ -88,10 +88,6 @@
88 else:88 else:
89 if not quiet:89 if not quiet:
90 print "%s %s" % (sync_mode.symbol, display_path)90 print "%s %s" % (sync_mode.symbol, display_path)
91 if(sync_mode.symbol == DOWNLOAD_SYMBOL):
92 send_notification("Downloading", "Downloading file '%s'" % display_path, "info")
93 elif(sync_mode.symbol == UPLOAD_SYMBOL):
94 send_notification("Uploading", "Uploading file '%s'" % display_path, "info")
95 try:91 try:
96 create_dir = sync_mode.create_directory92 create_dir = sync_mode.create_directory
97 node_uuid = create_dir(parent_uuid=parent_uuid,93 node_uuid = create_dir(parent_uuid=parent_uuid,
@@ -241,6 +237,7 @@
241 safe_mkdir(path)237 safe_mkdir(path)
242 send_notification("New dir", "Creating dir %s" % path, "info")238 send_notification("New dir", "Creating dir %s" % path, "info")
243 except OSError, e:239 except OSError, e:
240 send_error("Error creating local directory %s" % path, e)
244 raise NodeCreateError("Error creating local directory %s: %s" % \241 raise NodeCreateError("Error creating local directory %s: %s" % \
245 (path, e))242 (path, e))
246 return None243 return None
@@ -253,6 +250,7 @@
253 path = get_conflict_path(path, conflict_info)250 path = get_conflict_path(path, conflict_info)
254 content_hash = conflict_info[1]251 content_hash = conflict_info[1]
255 try:252 try:
253 send_notification("Downloading", "Downloading '%s'" % path, "info")
256 if node_type == SYMLINK:254 if node_type == SYMLINK:
257 self.client.download_string(share_uuid=255 self.client.download_string(share_uuid=
258 self.share_uuid,256 self.share_uuid,
@@ -265,24 +263,30 @@
265 filename=path)263 filename=path)
266 except (request.StorageRequestError, UnsupportedOperationError), e:264 except (request.StorageRequestError, UnsupportedOperationError), e:
267 if os.path.exists(path):265 if os.path.exists(path):
266 send_error("Error downloading content for %s" % path, e)
268 raise NodeUpdateError("Error downloading content for %s: %s" %\267 raise NodeUpdateError("Error downloading content for %s: %s" %\
269 (path, e))268 (path, e))
270 else:269 else:
270 send_error("Error locally creating %s" % path, e)
271 raise NodeCreateError("Error locally creating %s: %s" % \271 raise NodeCreateError("Error locally creating %s: %s" % \
272 (path, e))272 (path, e))
273273
274 def delete_directory(self, node_uuid, path):274 def delete_directory(self, node_uuid, path):
275 """Deletes a directory."""275 """Deletes a directory."""
276 send_notification("Removing", "Removing directory '%s'" % path, "info")
276 try:277 try:
277 os.rmdir(path)278 os.rmdir(path)
278 except OSError, e:279 except OSError, e:
280 send_error("Error locally deleting %s" % path, e)
279 raise NodeDeleteError("Error locally deleting %s: %s" % (path, e))281 raise NodeDeleteError("Error locally deleting %s: %s" % (path, e))
280282
281 def delete_file(self, node_uuid, path):283 def delete_file(self, node_uuid, path):
282 """Deletes a file."""284 """Deletes a file."""
285 send_notification("Removing", "Removing file '%s'" % path, "info")
283 try:286 try:
284 os.unlink(path)287 os.unlink(path)
285 except OSError, e:288 except OSError, e:
289 send_error("Error locally deleting %s" % path, e)
286 raise NodeDeleteError("Error locally deleting %s: %s" % (path, e))290 raise NodeDeleteError("Error locally deleting %s: %s" % (path, e))
287291
288292
@@ -298,10 +302,12 @@
298 """Creates a directory on the server."""302 """Creates a directory on the server."""
299 name = name_from_path(path)303 name = name_from_path(path)
300 try:304 try:
305 send_notification("Creating", "Creating directory '%s'" % path, "info")
301 return self.client.create_directory(share_uuid=self.share_uuid,306 return self.client.create_directory(share_uuid=self.share_uuid,
302 parent_uuid=parent_uuid,307 parent_uuid=parent_uuid,
303 name=name)308 name=name)
304 except (request.StorageRequestError, UnsupportedOperationError), e:309 except (request.StorageRequestError, UnsupportedOperationError), e:
310 send_error("Error remotely creating %s" % path, e)
305 raise NodeCreateError("Error remotely creating %s: %s" % \311 raise NodeCreateError("Error remotely creating %s: %s" % \
306 (path, e))312 (path, e))
307313
@@ -319,6 +325,7 @@
319 name=conflict_name,325 name=conflict_name,
320 node_uuid=node_uuid)326 node_uuid=node_uuid)
321 except (request.StorageRequestError, UnsupportedOperationError), e:327 except (request.StorageRequestError, UnsupportedOperationError), e:
328 send_error("Error remotely renaming %s to %s" % (path, conflict_path), e)
322 raise NodeUpdateError("Error remotely renaming %s to %s: %s" %\329 raise NodeUpdateError("Error remotely renaming %s to %s: %s" %\
323 (path, conflict_path, e))330 (path, conflict_path, e))
324 node_uuid = None331 node_uuid = None
@@ -328,6 +335,7 @@
328 try:335 try:
329 target = os.readlink(path)336 target = os.readlink(path)
330 except OSError, e:337 except OSError, e:
338 send_error("Error retrieving link target %s" % path, e)
331 raise NodeCreateError("Error retrieving link target " \339 raise NodeCreateError("Error retrieving link target " \
332 "for %s: %s" % (path, e))340 "for %s: %s" % (path, e))
333 else:341 else:
@@ -336,6 +344,7 @@
336 name = name_from_path(path)344 name = name_from_path(path)
337 if node_uuid is None:345 if node_uuid is None:
338 try:346 try:
347 send_notification("Creating", "Remotely creating '%s'" % path, "info")
339 if node_type == SYMLINK:348 if node_type == SYMLINK:
340 node_uuid = self.client.create_symlink(share_uuid=349 node_uuid = self.client.create_symlink(share_uuid=
341 self.share_uuid,350 self.share_uuid,
@@ -351,11 +360,13 @@
351 parent_uuid,360 parent_uuid,
352 name=name)361 name=name)
353 except (request.StorageRequestError, UnsupportedOperationError), e:362 except (request.StorageRequestError, UnsupportedOperationError), e:
363 send_error("Error remotely creating for %s" % path, e)
354 raise NodeCreateError("Error remotely creating %s: %s" % \364 raise NodeCreateError("Error remotely creating %s: %s" % \
355 (path, e))365 (path, e))
356366
357 if old_content_hash != content_hash:367 if old_content_hash != content_hash:
358 try:368 try:
369 send_notification("Updating", "Uploading '%s'" % path, "info")
359 if node_type == SYMLINK:370 if node_type == SYMLINK:
360 self.client.upload_string(share_uuid=self.share_uuid,371 self.client.upload_string(share_uuid=self.share_uuid,
361 node_uuid=node_uuid,372 node_uuid=node_uuid,
@@ -370,6 +381,7 @@
370 old_content_hash=old_content_hash,381 old_content_hash=old_content_hash,
371 filename=path)382 filename=path)
372 except (request.StorageRequestError, UnsupportedOperationError), e:383 except (request.StorageRequestError, UnsupportedOperationError), e:
384 send_error("Error uploading content for %s" % path, e)
373 raise NodeUpdateError("Error uploading content for %s: %s" % \385 raise NodeUpdateError("Error uploading content for %s: %s" % \
374 (path, e))386 (path, e))
375387
@@ -377,12 +389,16 @@
377 """Deletes a directory."""389 """Deletes a directory."""
378 try:390 try:
379 self.client.unlink(share_uuid=self.share_uuid, node_uuid=node_uuid)391 self.client.unlink(share_uuid=self.share_uuid, node_uuid=node_uuid)
392 send_notification("Deleting", "Remotely deleting directory '%s'" % path, "info")
380 except (request.StorageRequestError, UnsupportedOperationError), e:393 except (request.StorageRequestError, UnsupportedOperationError), e:
394 send_error("Error remotely deleting %s" % path, e)
381 raise NodeDeleteError("Error remotely deleting %s: %s" % (path, e))395 raise NodeDeleteError("Error remotely deleting %s: %s" % (path, e))
382396
383 def delete_file(self, node_uuid, path):397 def delete_file(self, node_uuid, path):
384 """Deletes a file."""398 """Deletes a file."""
385 try:399 try:
386 self.client.unlink(share_uuid=self.share_uuid, node_uuid=node_uuid)400 self.client.unlink(share_uuid=self.share_uuid, node_uuid=node_uuid)
401 send_notification("Deleting", "Remotely deleting file '%s'" % path, "info")
387 except (request.StorageRequestError, UnsupportedOperationError), e:402 except (request.StorageRequestError, UnsupportedOperationError), e:
403 send_error("Error remotely deleting %s" % path, e)
388 raise NodeDeleteError("Error remotely deleting %s: %s" % (path, e))404 raise NodeDeleteError("Error remotely deleting %s: %s" % (path, e))
389405
=== modified file 'src/u1sync/utils.py'
--- src/u1sync/utils.py 2010-10-19 10:35:43 +0000
+++ src/u1sync/utils.py 2010-11-02 22:21:27 +0000
@@ -81,14 +81,14 @@
81 except Exception, e:81 except Exception, e:
82 print "Error: C# client is not listening!! %s" % e.message82 print "Error: C# client is not listening!! %s" % e.message
83 83
84def send_bus_error(error_message, exception):84def send_error(error_message, exception):
85 message = create_error_message(error_message, exception)85 message = create_error_message(error_message, exception)
86 send_bus_message(message)86 send_bus_message(message)
87 87
88def send_notification(title, message, type):88def send_notification(title, message, type):
89 message = {'type':'notify',89 message = {'type':'notify',
90 'title':title,90 'title':title,
91 'message':message,91 'message':message,
92 'notification_type':type}92 'notification_type':type}
93 send_bus_message(message)93 send_bus_message(message)
94 94
95\ No newline at end of file95\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: