| OLD | NEW |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """An implementation of the server side of the Chromium sync protocol. | 5 """An implementation of the server side of the Chromium sync protocol. |
| 6 | 6 |
| 7 The details of the protocol are described mostly by comments in the protocol | 7 The details of the protocol are described mostly by comments in the protocol |
| 8 buffer definition at chrome/browser/sync/protocol/sync.proto. | 8 buffer definition at chrome/browser/sync/protocol/sync.proto. |
| 9 """ | 9 """ |
| 10 | 10 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 import managed_user_shared_setting_specifics_pb2 | 43 import managed_user_shared_setting_specifics_pb2 |
| 44 import nigori_specifics_pb2 | 44 import nigori_specifics_pb2 |
| 45 import password_specifics_pb2 | 45 import password_specifics_pb2 |
| 46 import preference_specifics_pb2 | 46 import preference_specifics_pb2 |
| 47 import priority_preference_specifics_pb2 | 47 import priority_preference_specifics_pb2 |
| 48 import search_engine_specifics_pb2 | 48 import search_engine_specifics_pb2 |
| 49 import session_specifics_pb2 | 49 import session_specifics_pb2 |
| 50 import sync_pb2 | 50 import sync_pb2 |
| 51 import sync_enums_pb2 | 51 import sync_enums_pb2 |
| 52 import synced_notification_app_info_specifics_pb2 | 52 import synced_notification_app_info_specifics_pb2 |
| 53 import synced_notification_data_pb2 | |
| 54 import synced_notification_render_pb2 | |
| 55 import synced_notification_specifics_pb2 | 53 import synced_notification_specifics_pb2 |
| 56 import theme_specifics_pb2 | 54 import theme_specifics_pb2 |
| 57 import typed_url_specifics_pb2 | 55 import typed_url_specifics_pb2 |
| 58 import wifi_credential_specifics_pb2 | 56 import wifi_credential_specifics_pb2 |
| 59 | 57 |
| 60 # An enumeration of the various kinds of data that can be synced. | 58 # An enumeration of the various kinds of data that can be synced. |
| 61 # Over the wire, this enumeration is not used: a sync object's type is | 59 # Over the wire, this enumeration is not used: a sync object's type is |
| 62 # inferred by which EntitySpecifics field it has. But in the context | 60 # inferred by which EntitySpecifics field it has. But in the context |
| 63 # of a program, it is useful to have an enumeration. | 61 # of a program, it is useful to have an enumeration. |
| 64 ALL_TYPES = ( | 62 ALL_TYPES = ( |
| (...skipping 1135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1200 | 1198 |
| 1201 def SetInducedError(self, error, error_frequency, | 1199 def SetInducedError(self, error, error_frequency, |
| 1202 sync_count_before_errors): | 1200 sync_count_before_errors): |
| 1203 self.induced_error = error | 1201 self.induced_error = error |
| 1204 self.induced_error_frequency = error_frequency | 1202 self.induced_error_frequency = error_frequency |
| 1205 self.sync_count_before_errors = sync_count_before_errors | 1203 self.sync_count_before_errors = sync_count_before_errors |
| 1206 | 1204 |
| 1207 def GetInducedError(self): | 1205 def GetInducedError(self): |
| 1208 return self.induced_error | 1206 return self.induced_error |
| 1209 | 1207 |
| 1210 def AddSyncedNotification(self, serialized_notification): | |
| 1211 """Adds a synced notification to the server data. | |
| 1212 | |
| 1213 The notification will be delivered to the client on the next GetUpdates | |
| 1214 call. | |
| 1215 | |
| 1216 Args: | |
| 1217 serialized_notification: A serialized CoalescedSyncedNotification. | |
| 1218 | |
| 1219 Returns: | |
| 1220 The string representation of the added SyncEntity. | |
| 1221 | |
| 1222 Raises: | |
| 1223 ClientNotConnectedError: if the client has not yet connected to this | |
| 1224 server | |
| 1225 """ | |
| 1226 # A unique string used wherever a unique ID for this notification is | |
| 1227 # required. | |
| 1228 unique_notification_id = str(uuid.uuid4()) | |
| 1229 | |
| 1230 specifics = self._CreateSyncedNotificationEntitySpecifics( | |
| 1231 unique_notification_id, serialized_notification) | |
| 1232 | |
| 1233 # Create the root SyncEntity representing a single notification. | |
| 1234 entity = sync_pb2.SyncEntity() | |
| 1235 entity.specifics.CopyFrom(specifics) | |
| 1236 entity.parent_id_string = self._ServerTagToId( | |
| 1237 'google_chrome_synced_notifications') | |
| 1238 entity.name = 'Synced notification added for testing' | |
| 1239 entity.version = self._GetNextVersionNumber() | |
| 1240 | |
| 1241 entity.client_defined_unique_tag = self._CreateSyncedNotificationClientTag( | |
| 1242 specifics.synced_notification.coalesced_notification.key) | |
| 1243 entity.id_string = self._ClientTagToId(GetEntryType(entity), | |
| 1244 entity.client_defined_unique_tag) | |
| 1245 | |
| 1246 self._entries[entity.id_string] = copy.deepcopy(entity) | |
| 1247 | |
| 1248 return google.protobuf.text_format.MessageToString(entity) | |
| 1249 | |
| 1250 def _GetNextVersionNumber(self): | 1208 def _GetNextVersionNumber(self): |
| 1251 """Set the version to one more than the greatest version number seen.""" | 1209 """Set the version to one more than the greatest version number seen.""" |
| 1252 entries = sorted(self._entries.values(), key=operator.attrgetter('version')) | 1210 entries = sorted(self._entries.values(), key=operator.attrgetter('version')) |
| 1253 if len(entries) < 1: | 1211 if len(entries) < 1: |
| 1254 raise ClientNotConnectedError | 1212 raise ClientNotConnectedError |
| 1255 return entries[-1].version + 1 | 1213 return entries[-1].version + 1 |
| 1256 | 1214 |
| 1257 def _CreateSyncedNotificationEntitySpecifics(self, unique_id, | |
| 1258 serialized_notification): | |
| 1259 """Create the EntitySpecifics proto for a synced notification.""" | |
| 1260 coalesced = synced_notification_data_pb2.CoalescedSyncedNotification() | |
| 1261 google.protobuf.text_format.Merge(serialized_notification, coalesced) | |
| 1262 | |
| 1263 # Override the provided key so that we have a unique one. | |
| 1264 coalesced.key = unique_id | |
| 1265 | |
| 1266 specifics = sync_pb2.EntitySpecifics() | |
| 1267 notification_specifics = \ | |
| 1268 synced_notification_specifics_pb2.SyncedNotificationSpecifics() | |
| 1269 notification_specifics.coalesced_notification.CopyFrom(coalesced) | |
| 1270 specifics.synced_notification.CopyFrom(notification_specifics) | |
| 1271 | |
| 1272 return specifics | |
| 1273 | |
| 1274 def _CreateSyncedNotificationClientTag(self, key): | |
| 1275 """Create the client_defined_unique_tag value for a SyncedNotification. | |
| 1276 | |
| 1277 Args: | |
| 1278 key: The entity used to create the client tag. | |
| 1279 | |
| 1280 Returns: | |
| 1281 The string value of the to be used as the client_defined_unique_tag. | |
| 1282 """ | |
| 1283 serialized_type = sync_pb2.EntitySpecifics() | |
| 1284 specifics = synced_notification_specifics_pb2.SyncedNotificationSpecifics() | |
| 1285 serialized_type.synced_notification.CopyFrom(specifics) | |
| 1286 hash_input = serialized_type.SerializeToString() + key | |
| 1287 return base64.b64encode(hashlib.sha1(hash_input).digest()) | |
| 1288 | |
| 1289 def AddSyncedNotificationAppInfo(self, app_info): | |
| 1290 """Adds an app info struct to the server data. | |
| 1291 | |
| 1292 The notification will be delivered to the client on the next GetUpdates | |
| 1293 call. | |
| 1294 | |
| 1295 Args: | |
| 1296 app_info: A serialized AppInfo. | |
| 1297 | |
| 1298 Returns: | |
| 1299 The string representation of the added SyncEntity. | |
| 1300 | |
| 1301 Raises: | |
| 1302 ClientNotConnectedError: if the client has not yet connected to this | |
| 1303 server | |
| 1304 """ | |
| 1305 specifics = self._CreateSyncedNotificationAppInfoEntitySpecifics(app_info) | |
| 1306 | |
| 1307 # Create the root SyncEntity representing a single app info protobuf. | |
| 1308 entity = sync_pb2.SyncEntity() | |
| 1309 entity.specifics.CopyFrom(specifics) | |
| 1310 entity.parent_id_string = self._ServerTagToId( | |
| 1311 'google_chrome_synced_notification_app_info') | |
| 1312 entity.name = 'App info added for testing' | |
| 1313 entity.version = self._GetNextVersionNumber() | |
| 1314 | |
| 1315 # App Infos do not have a strong id, it only needs to be unique. | |
| 1316 entity.client_defined_unique_tag = "foo" | |
| 1317 entity.id_string = "foo" | |
| 1318 | |
| 1319 self._entries[entity.id_string] = copy.deepcopy(entity) | |
| 1320 | |
| 1321 print "entity before exit is ", entity | |
| 1322 | |
| 1323 return google.protobuf.text_format.MessageToString(entity) | |
| 1324 | |
| 1325 def _CreateSyncedNotificationAppInfoEntitySpecifics( | |
| 1326 self, synced_notification_app_info): | |
| 1327 """Create the EntitySpecifics proto for a synced notification app info.""" | |
| 1328 # Create a single, empty app_info object | |
| 1329 app_info = \ | |
| 1330 synced_notification_app_info_specifics_pb2.SyncedNotificationAppInfo() | |
| 1331 # Fill the app_info object from the text format protobuf. | |
| 1332 google.protobuf.text_format.Merge(synced_notification_app_info, app_info) | |
| 1333 | |
| 1334 # Create a new specifics object with a contained app_info | |
| 1335 specifics = sync_pb2.EntitySpecifics() | |
| 1336 app_info_specifics = \ | |
| 1337 synced_notification_app_info_specifics_pb2.\ | |
| 1338 SyncedNotificationAppInfoSpecifics() | |
| 1339 | |
| 1340 # Copy the app info from the text format protobuf | |
| 1341 contained_app_info = app_info_specifics.synced_notification_app_info.add() | |
| 1342 contained_app_info.CopyFrom(app_info) | |
| 1343 | |
| 1344 # And put the new app_info_specifics into the specifics before returning. | |
| 1345 specifics.synced_notification_app_info.CopyFrom(app_info_specifics) | |
| 1346 | |
| 1347 return specifics | |
| 1348 | 1215 |
| 1349 class TestServer(object): | 1216 class TestServer(object): |
| 1350 """An object to handle requests for one (and only one) Chrome Sync account. | 1217 """An object to handle requests for one (and only one) Chrome Sync account. |
| 1351 | 1218 |
| 1352 TestServer consumes the sync command messages that are the outermost | 1219 TestServer consumes the sync command messages that are the outermost |
| 1353 layers of the protocol, performs the corresponding actions on its | 1220 layers of the protocol, performs the corresponding actions on its |
| 1354 SyncDataModel, and constructs an appropriate response message. | 1221 SyncDataModel, and constructs an appropriate response message. |
| 1355 """ | 1222 """ |
| 1356 | 1223 |
| 1357 def __init__(self): | 1224 def __init__(self): |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1733 '<p>request_token: ' + self.request_token + '</p>' | 1600 '<p>request_token: ' + self.request_token + '</p>' |
| 1734 '<p>access_token: ' + self.access_token + '</p>' | 1601 '<p>access_token: ' + self.access_token + '</p>' |
| 1735 '<p>expires_in: ' + str(self.expires_in) + '</p>' | 1602 '<p>expires_in: ' + str(self.expires_in) + '</p>' |
| 1736 '<p>token_type: ' + self.token_type + '</p>' | 1603 '<p>token_type: ' + self.token_type + '</p>' |
| 1737 '</html>') | 1604 '</html>') |
| 1738 | 1605 |
| 1739 def CustomizeClientCommand(self, sessions_commit_delay_seconds): | 1606 def CustomizeClientCommand(self, sessions_commit_delay_seconds): |
| 1740 """Customizes the value of the ClientCommand of ServerToClientResponse. | 1607 """Customizes the value of the ClientCommand of ServerToClientResponse. |
| 1741 | 1608 |
| 1742 Currently, this only allows for changing the sessions_commit_delay_seconds | 1609 Currently, this only allows for changing the sessions_commit_delay_seconds |
| 1743 field. This is useful for testing in conjunction with | 1610 field. |
| 1744 AddSyncedNotification so that synced notifications are seen immediately | |
| 1745 after triggering them with an HTTP call to the test server. | |
| 1746 | 1611 |
| 1747 Args: | 1612 Args: |
| 1748 sessions_commit_delay_seconds: The desired sync delay time for sessions. | 1613 sessions_commit_delay_seconds: The desired sync delay time for sessions. |
| 1749 """ | 1614 """ |
| 1750 if not self._client_command: | 1615 if not self._client_command: |
| 1751 self._client_command = client_commands_pb2.ClientCommand() | 1616 self._client_command = client_commands_pb2.ClientCommand() |
| 1752 | 1617 |
| 1753 self._client_command.sessions_commit_delay_seconds = \ | 1618 self._client_command.sessions_commit_delay_seconds = \ |
| 1754 sessions_commit_delay_seconds | 1619 sessions_commit_delay_seconds |
| 1755 return self._client_command | 1620 return self._client_command |
| OLD | NEW |