From ad101705ae1a16036404092848789472cd70e006 Mon Sep 17 00:00:00 2001 From: drebs Date: Tue, 19 Mar 2013 11:23:58 -0300 Subject: Add notification .proto file. --- src/leap/common/ipc/Makefile | 30 +++++++ src/leap/common/ipc/notification.proto | 23 ++++++ src/leap/common/ipc/notification_pb2.py | 135 ++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 src/leap/common/ipc/Makefile create mode 100644 src/leap/common/ipc/notification.proto create mode 100644 src/leap/common/ipc/notification_pb2.py diff --git a/src/leap/common/ipc/Makefile b/src/leap/common/ipc/Makefile new file mode 100644 index 0000000..7c01fc6 --- /dev/null +++ b/src/leap/common/ipc/Makefile @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Makefile +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is used to generate protobuf python files that are used for IPC: +# +# https://developers.google.com/protocol-buffers/docs/pythontutorial + +PROTOC = protoc + +all: notification_pb2.py + +%_pb2.py: %.proto + $(PROTOC) --python_out=./ $< + +clean: + rm -f *_pb2.py diff --git a/src/leap/common/ipc/notification.proto b/src/leap/common/ipc/notification.proto new file mode 100644 index 0000000..4ae0406 --- /dev/null +++ b/src/leap/common/ipc/notification.proto @@ -0,0 +1,23 @@ +// https://developers.google.com/protocol-buffers/docs/pythontutorial +// https://developers.google.com/protocol-buffers/docs/reference/python-generated + +package leap.common; + +message Notification { + + enum Component { + client = 0; + soledad = 1; + eip = 2; + smtp_relay = 3; + mx = 4; + } + + required int32 id = 1; + required Component component = 2; + required string content = 3; + required string mac_method = 4; + required bytes mac = 5; + optional string enc_method = 6; + optional bool error_occurred = 7; +} diff --git a/src/leap/common/ipc/notification_pb2.py b/src/leap/common/ipc/notification_pb2.py new file mode 100644 index 0000000..a1c285f --- /dev/null +++ b/src/leap/common/ipc/notification_pb2.py @@ -0,0 +1,135 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: notification.proto + +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='notification.proto', + package='leap.common', + serialized_pb='\n\x12notification.proto\x12\x0bleap.common\"\xf7\x01\n\x0cNotification\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x36\n\tcomponent\x18\x02 \x02(\x0e\x32#.leap.common.Notification.Component\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\t\x12\x12\n\nmac_method\x18\x04 \x02(\t\x12\x0b\n\x03mac\x18\x05 \x02(\x0c\x12\x12\n\nenc_method\x18\x06 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x07 \x01(\x08\"E\n\tComponent\x12\n\n\x06\x63lient\x10\x00\x12\x0b\n\x07soledad\x10\x01\x12\x07\n\x03\x65ip\x10\x02\x12\x0e\n\nsmtp_relay\x10\x03\x12\x06\n\x02mx\x10\x04') + + + +_NOTIFICATION_COMPONENT = _descriptor.EnumDescriptor( + name='Component', + full_name='leap.common.Notification.Component', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='client', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='soledad', index=1, number=1, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='eip', index=2, number=2, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='smtp_relay', index=3, number=3, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='mx', index=4, number=4, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=214, + serialized_end=283, +) + + +_NOTIFICATION = _descriptor.Descriptor( + name='Notification', + full_name='leap.common.Notification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='leap.common.Notification.id', index=0, + number=1, type=5, cpp_type=1, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='component', full_name='leap.common.Notification.component', index=1, + number=2, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content', full_name='leap.common.Notification.content', index=2, + number=3, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac_method', full_name='leap.common.Notification.mac_method', index=3, + number=4, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac', full_name='leap.common.Notification.mac', index=4, + number=5, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='enc_method', full_name='leap.common.Notification.enc_method', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='error_occurred', full_name='leap.common.Notification.error_occurred', index=6, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _NOTIFICATION_COMPONENT, + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=36, + serialized_end=283, +) + +_NOTIFICATION.fields_by_name['component'].enum_type = _NOTIFICATION_COMPONENT +_NOTIFICATION_COMPONENT.containing_type = _NOTIFICATION; +DESCRIPTOR.message_types_by_name['Notification'] = _NOTIFICATION + +class Notification(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType + DESCRIPTOR = _NOTIFICATION + + # @@protoc_insertion_point(class_scope:leap.common.Notification) + + +# @@protoc_insertion_point(module_scope) -- cgit v1.2.3 From a16d533125d4fc1c40ee85ad2e626d7373e7719a Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 20 Mar 2013 13:12:00 -0300 Subject: Change protobuf message name. --- src/leap/common/events/Makefile | 30 ++++ src/leap/common/events/signal.proto | 57 ++++++++ src/leap/common/events/signal_pb2.py | 250 ++++++++++++++++++++++++++++++++ src/leap/common/ipc/Makefile | 30 ---- src/leap/common/ipc/notification.proto | 23 --- src/leap/common/ipc/notification_pb2.py | 135 ----------------- 6 files changed, 337 insertions(+), 188 deletions(-) create mode 100644 src/leap/common/events/Makefile create mode 100644 src/leap/common/events/signal.proto create mode 100644 src/leap/common/events/signal_pb2.py delete mode 100644 src/leap/common/ipc/Makefile delete mode 100644 src/leap/common/ipc/notification.proto delete mode 100644 src/leap/common/ipc/notification_pb2.py diff --git a/src/leap/common/events/Makefile b/src/leap/common/events/Makefile new file mode 100644 index 0000000..4f99f35 --- /dev/null +++ b/src/leap/common/events/Makefile @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Makefile +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is used to generate protobuf python files that are used for IPC: +# +# https://developers.google.com/protocol-buffers/docs/pythontutorial + +PROTOC = protoc + +all: signal_pb2.py + +%_pb2.py: %.proto + $(PROTOC) --python_out=./ $< + +clean: + rm -f *_pb2.py diff --git a/src/leap/common/events/signal.proto b/src/leap/common/events/signal.proto new file mode 100644 index 0000000..336471c --- /dev/null +++ b/src/leap/common/events/signal.proto @@ -0,0 +1,57 @@ +// signal.proto +// Copyright (C) 2013 LEA +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package leap.common.events; + +message SignalRequest { + + enum Signal { + CLIENT_SESSION_ID = 1; + CLIENT_UID = 2; + SOLEDAD_CREATING_KEYS = 3; + SOLEDAD_DONE_CREATING_KEYS = 4; + SOLEDAD_UPLOADING_KEYS = 5; + SOLEDAD_DONE_UPLOADING_KEYS = 6; + SOLEDAD_DOWNLOADING_KEYS = 7; + SOLEDAD_DONE_DOWNLOADING_KEYS = 8; + SOLEDAD_NEW_DATA_TO_SYNC = 9; + SOLEDAD_DONE_DATA_SYNC = 10; + } + + required int32 id = 1; + required Signal signal = 2; + required string content = 3; + required string mac_method = 4; + required bytes mac = 5; + optional string enc_method = 6; + optional bool error_occurred = 7; +} + +message SignalResponse { + + enum Status { + OK = 1; + UNAUTH = 2; + ERROR = 3; + } + + required int32 id = 1; + required Status status = 2; +} + +service SignalService { + rpc signal(SignalRequest) returns (SignalResponse); +} diff --git a/src/leap/common/events/signal_pb2.py b/src/leap/common/events/signal_pb2.py new file mode 100644 index 0000000..b21676f --- /dev/null +++ b/src/leap/common/events/signal_pb2.py @@ -0,0 +1,250 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! + +from google.protobuf import descriptor +from google.protobuf import message +from google.protobuf import reflection +from google.protobuf import service +from google.protobuf import service_reflection +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + + +DESCRIPTOR = descriptor.FileDescriptor( + name='signal.proto', + package='leap.common.events', + serialized_pb='\n\x0csignal.proto\x12\x12leap.common.events\"\xd8\x03\n\rSignalRequest\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x38\n\x06signal\x18\x02 \x02(\x0e\x32(.leap.common.events.SignalRequest.Signal\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\t\x12\x12\n\nmac_method\x18\x04 \x02(\t\x12\x0b\n\x03mac\x18\x05 \x02(\x0c\x12\x12\n\nenc_method\x18\x06 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x07 \x01(\x08\"\xa2\x02\n\x06Signal\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\"\x80\x01\n\x0eSignalResponse\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x39\n\x06status\x18\x02 \x02(\x0e\x32).leap.common.events.SignalResponse.Status\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03\x32`\n\rSignalService\x12O\n\x06signal\x12!.leap.common.events.SignalRequest\x1a\".leap.common.events.SignalResponse') + + + +_SIGNALREQUEST_SIGNAL = descriptor.EnumDescriptor( + name='Signal', + full_name='leap.common.events.SignalRequest.Signal', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='CLIENT_SESSION_ID', index=0, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='CLIENT_UID', index=1, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_CREATING_KEYS', index=2, number=3, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_DONE_CREATING_KEYS', index=3, number=4, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_UPLOADING_KEYS', index=4, number=5, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_DONE_UPLOADING_KEYS', index=5, number=6, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_DOWNLOADING_KEYS', index=6, number=7, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_DONE_DOWNLOADING_KEYS', index=7, number=8, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_NEW_DATA_TO_SYNC', index=8, number=9, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='SOLEDAD_DONE_DATA_SYNC', index=9, number=10, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=219, + serialized_end=509, +) + +_SIGNALRESPONSE_STATUS = descriptor.EnumDescriptor( + name='Status', + full_name='leap.common.events.SignalResponse.Status', + filename=None, + file=DESCRIPTOR, + values=[ + descriptor.EnumValueDescriptor( + name='OK', index=0, number=1, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='UNAUTH', index=1, number=2, + options=None, + type=None), + descriptor.EnumValueDescriptor( + name='ERROR', index=2, number=3, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=601, + serialized_end=640, +) + + +_SIGNALREQUEST = descriptor.Descriptor( + name='SignalRequest', + full_name='leap.common.events.SignalRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + descriptor.FieldDescriptor( + name='id', full_name='leap.common.events.SignalRequest.id', index=0, + number=1, type=5, cpp_type=1, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='signal', full_name='leap.common.events.SignalRequest.signal', index=1, + number=2, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='content', full_name='leap.common.events.SignalRequest.content', index=2, + number=3, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='mac_method', full_name='leap.common.events.SignalRequest.mac_method', index=3, + number=4, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='mac', full_name='leap.common.events.SignalRequest.mac', index=4, + number=5, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='enc_method', full_name='leap.common.events.SignalRequest.enc_method', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='error_occurred', full_name='leap.common.events.SignalRequest.error_occurred', index=6, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNALREQUEST_SIGNAL, + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=37, + serialized_end=509, +) + + +_SIGNALRESPONSE = descriptor.Descriptor( + name='SignalResponse', + full_name='leap.common.events.SignalResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + descriptor.FieldDescriptor( + name='id', full_name='leap.common.events.SignalResponse.id', index=0, + number=1, type=5, cpp_type=1, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + descriptor.FieldDescriptor( + name='status', full_name='leap.common.events.SignalResponse.status', index=1, + number=2, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _SIGNALRESPONSE_STATUS, + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=512, + serialized_end=640, +) + + +_SIGNALREQUEST.fields_by_name['signal'].enum_type = _SIGNALREQUEST_SIGNAL +_SIGNALREQUEST_SIGNAL.containing_type = _SIGNALREQUEST; +_SIGNALRESPONSE.fields_by_name['status'].enum_type = _SIGNALRESPONSE_STATUS +_SIGNALRESPONSE_STATUS.containing_type = _SIGNALRESPONSE; + +class SignalRequest(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _SIGNALREQUEST + + # @@protoc_insertion_point(class_scope:leap.common.events.SignalRequest) + +class SignalResponse(message.Message): + __metaclass__ = reflection.GeneratedProtocolMessageType + DESCRIPTOR = _SIGNALRESPONSE + + # @@protoc_insertion_point(class_scope:leap.common.events.SignalResponse) + + +_SIGNALSERVICE = descriptor.ServiceDescriptor( + name='SignalService', + full_name='leap.common.events.SignalService', + file=DESCRIPTOR, + index=0, + options=None, + serialized_start=642, + serialized_end=738, + methods=[ + descriptor.MethodDescriptor( + name='signal', + full_name='leap.common.events.SignalService.signal', + index=0, + containing_service=None, + input_type=_SIGNALREQUEST, + output_type=_SIGNALRESPONSE, + options=None, + ), +]) + +class SignalService(service.Service): + __metaclass__ = service_reflection.GeneratedServiceType + DESCRIPTOR = _SIGNALSERVICE +class SignalService_Stub(SignalService): + __metaclass__ = service_reflection.GeneratedServiceStubType + DESCRIPTOR = _SIGNALSERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/src/leap/common/ipc/Makefile b/src/leap/common/ipc/Makefile deleted file mode 100644 index 7c01fc6..0000000 --- a/src/leap/common/ipc/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# Makefile -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# This file is used to generate protobuf python files that are used for IPC: -# -# https://developers.google.com/protocol-buffers/docs/pythontutorial - -PROTOC = protoc - -all: notification_pb2.py - -%_pb2.py: %.proto - $(PROTOC) --python_out=./ $< - -clean: - rm -f *_pb2.py diff --git a/src/leap/common/ipc/notification.proto b/src/leap/common/ipc/notification.proto deleted file mode 100644 index 4ae0406..0000000 --- a/src/leap/common/ipc/notification.proto +++ /dev/null @@ -1,23 +0,0 @@ -// https://developers.google.com/protocol-buffers/docs/pythontutorial -// https://developers.google.com/protocol-buffers/docs/reference/python-generated - -package leap.common; - -message Notification { - - enum Component { - client = 0; - soledad = 1; - eip = 2; - smtp_relay = 3; - mx = 4; - } - - required int32 id = 1; - required Component component = 2; - required string content = 3; - required string mac_method = 4; - required bytes mac = 5; - optional string enc_method = 6; - optional bool error_occurred = 7; -} diff --git a/src/leap/common/ipc/notification_pb2.py b/src/leap/common/ipc/notification_pb2.py deleted file mode 100644 index a1c285f..0000000 --- a/src/leap/common/ipc/notification_pb2.py +++ /dev/null @@ -1,135 +0,0 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: notification.proto - -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection -from google.protobuf import descriptor_pb2 -# @@protoc_insertion_point(imports) - - - - -DESCRIPTOR = _descriptor.FileDescriptor( - name='notification.proto', - package='leap.common', - serialized_pb='\n\x12notification.proto\x12\x0bleap.common\"\xf7\x01\n\x0cNotification\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x36\n\tcomponent\x18\x02 \x02(\x0e\x32#.leap.common.Notification.Component\x12\x0f\n\x07\x63ontent\x18\x03 \x02(\t\x12\x12\n\nmac_method\x18\x04 \x02(\t\x12\x0b\n\x03mac\x18\x05 \x02(\x0c\x12\x12\n\nenc_method\x18\x06 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x07 \x01(\x08\"E\n\tComponent\x12\n\n\x06\x63lient\x10\x00\x12\x0b\n\x07soledad\x10\x01\x12\x07\n\x03\x65ip\x10\x02\x12\x0e\n\nsmtp_relay\x10\x03\x12\x06\n\x02mx\x10\x04') - - - -_NOTIFICATION_COMPONENT = _descriptor.EnumDescriptor( - name='Component', - full_name='leap.common.Notification.Component', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='client', index=0, number=0, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='soledad', index=1, number=1, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='eip', index=2, number=2, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='smtp_relay', index=3, number=3, - options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='mx', index=4, number=4, - options=None, - type=None), - ], - containing_type=None, - options=None, - serialized_start=214, - serialized_end=283, -) - - -_NOTIFICATION = _descriptor.Descriptor( - name='Notification', - full_name='leap.common.Notification', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='leap.common.Notification.id', index=0, - number=1, type=5, cpp_type=1, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='component', full_name='leap.common.Notification.component', index=1, - number=2, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='content', full_name='leap.common.Notification.content', index=2, - number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='mac_method', full_name='leap.common.Notification.mac_method', index=3, - number=4, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='mac', full_name='leap.common.Notification.mac', index=4, - number=5, type=12, cpp_type=9, label=2, - has_default_value=False, default_value="", - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='enc_method', full_name='leap.common.Notification.enc_method', index=5, - number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='error_occurred', full_name='leap.common.Notification.error_occurred', index=6, - number=7, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _NOTIFICATION_COMPONENT, - ], - options=None, - is_extendable=False, - extension_ranges=[], - serialized_start=36, - serialized_end=283, -) - -_NOTIFICATION.fields_by_name['component'].enum_type = _NOTIFICATION_COMPONENT -_NOTIFICATION_COMPONENT.containing_type = _NOTIFICATION; -DESCRIPTOR.message_types_by_name['Notification'] = _NOTIFICATION - -class Notification(_message.Message): - __metaclass__ = _reflection.GeneratedProtocolMessageType - DESCRIPTOR = _NOTIFICATION - - # @@protoc_insertion_point(class_scope:leap.common.Notification) - - -# @@protoc_insertion_point(module_scope) -- cgit v1.2.3 From 0e6d6850d3c3df67eba054398fa84cd8b9977ecd Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 20 Mar 2013 13:12:50 -0300 Subject: Add callback registering. --- src/leap/common/events/__init__.py | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/leap/common/events/__init__.py diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py new file mode 100644 index 0000000..27542a9 --- /dev/null +++ b/src/leap/common/events/__init__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# __init__.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from leap.common.events import ( + signal_pb2, +) + + +# the `registered_callbacks` dictionary below should have the following +# format: +# +# { component: [ (uid, callback), ... ], ... } +# +registered_callbacks = {} + + +def register(signal, callback, uid=None, replace=False): + """ + Registers `callback` to be called when `signal` is signaled. + """ + if not registered_callbacks.has_key(signal): + registered_callbacks[signal] = [] + cbklist = registered_callbacks[signal] + if uid and filter(lambda (x,y): x == uid, cbklist): + # TODO: create appropriate exception + if not replace: + raise Exception("Callback already registered.") + else: + registered_callbacks[signal] = filter(lambda(x,y): x != uid, + cbklist) + registered_callbacks[signal].append((uid, callback)) + return uid + +#def get_registered_callbacks(): +# return registered_callbacks + +#__all__ = ['signal_pb2', 'service', 'register', 'registered_callbacks'] -- cgit v1.2.3 From 687b2a8aaa3f1aec29a0d8e41e08cc9fda04d46b Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 20 Mar 2013 13:13:23 -0300 Subject: Add service for receiving signal. --- src/leap/common/events/service.py | 114 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/leap/common/events/service.py diff --git a/src/leap/common/events/service.py b/src/leap/common/events/service.py new file mode 100644 index 0000000..fda45b2 --- /dev/null +++ b/src/leap/common/events/service.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# service.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import logging +import threading +from protobuf.socketrpc.server import ( + SocketRpcServer, + ThreadedTCPServer, + SocketHandler, +) +from leap.common.events import ( + signal_pb2 as proto, + registered_callbacks, +) + + +logger = logging.getLogger(__name__) + + +class SignalRpcServer(SocketRpcServer): + + def __init__(self, port, host='localhost'): + '''port - Port this server is started on''' + self.port = port + self.host = host + self.serviceMap = {} + self.server = None + + def run(self): + '''Activate the server.''' + logger.info('Running server on port %d' % self.port) + self.server = ThreadedTCPServer((self.host, self.port), + SocketHandler, self) + self.server.serve_forever() + + def stop(self): + self.server.shutdown() + + +class SignalService(proto.SignalService): + ''' + Handles signaling for LEAP components. + ''' + + def signal(self, controller, request, done): + logger.info('Received signal.') + + # Run registered callbacks + if registered_callbacks.has_key(request.signal): + for (_, cbk) in registered_callbacks[request.signal]: + cbk(request) + + # Create response message + response = proto.SignalResponse() + # TODO: change id for something meaningful + response.id = 1 + response.status = proto.SignalResponse.OK + + # Call provided callback with response message + done.run(response) + + +class SignalServiceThread(threading.Thread): + """ + Singleton class for starting a server thread + """ + + # Singleton instance + _instance = None + + def __init__(self, port): + super(SignalServiceThread, self).__init__() + self._service = SignalService() + self._port = port + self._server = SignalRpcServer(self._port) + self._server.registerService(self._service) + self.setDaemon(True) + + @staticmethod + def start_service(port): + """ + Start the singleton instance if not already running + Will not exit until the process ends + """ + if SignalServiceThread._instance == None: + SignalServiceThread._instance = SignalServiceThread(port) + SignalServiceThread._instance.start() + elif port != SignalServiceThread._instance._port: + # TODO: make this exception more self-explanatory + raise Exception() + return SignalServiceThread._instance + + def get_instance(self): + return self._instance + + def run(self): + self._server.run() + + def stop(self): + self._server.stop() -- cgit v1.2.3 From b966eec96fd3621908baab8697de8e2ed61ba136 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 20 Mar 2013 13:14:10 -0300 Subject: Add tests for registering signals. --- src/leap/common/events/test_events.py | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/leap/common/events/test_events.py diff --git a/src/leap/common/events/test_events.py b/src/leap/common/events/test_events.py new file mode 100644 index 0000000..ae55319 --- /dev/null +++ b/src/leap/common/events/test_events.py @@ -0,0 +1,88 @@ +import unittest +from protobuf.socketrpc import RpcService +from leap.common import events +from leap.common.events import service +from leap.common.events.signal_pb2 import ( + SignalRequest, + SignalService, + SignalService_Stub, +) + + +port = 8090 + +class EventsTestCase(unittest.TestCase): + + def _start_service(self): + return service.SignalServiceThread.start_service(port) + + def setUp(self): + super(EventsTestCase, self).setUp() + self._service = self._start_service() + + def tearDown(self): + events.registered_callbacks = {} + super(EventsTestCase, self).tearDown() + + def test_service_singleton(self): + self.assertTrue(self._service.get_instance() == self._service, + "Can't get singleton class for service.") + + def test_register_signal(self): + key = SignalRequest.SOLEDAD_CREATING_KEYS + self.assertEqual({}, events.registered_callbacks, + 'There should be no registered_callbacks events when ' + 'service has just started.') + events.register(key, lambda x: True) + self.assertEqual(1, len(events.registered_callbacks), + 'Wrong number of registered callbacks.') + self.assertEqual(events.registered_callbacks.keys(), [key], + 'Couldn\'t locate registered signal.') + events.register(key, lambda x: True) + self.assertEqual(1, len(events.registered_callbacks), + 'Wrong number of registered callbacks.') + self.assertEqual(events.registered_callbacks.keys(), [key], + 'Couldn\'t locate registered signal.') + self.assertEqual( + 2, + len(events.registered_callbacks[SignalRequest.SOLEDAD_CREATING_KEYS]), + 'Wrong number of registered callbacks.') + key2 = SignalRequest.CLIENT_UID + events.register(key2, lambda x: True) + self.assertEqual(2, len(events.registered_callbacks), + 'Wrong number of registered callbacks.') + self.assertEqual( + sorted(events.registered_callbacks.keys()), + sorted([key2, key]), + 'Wrong keys in `registered_keys`.') + + def test_register_signal_replace(self): + key = SignalRequest.SOLEDAD_CREATING_KEYS + cbk = lambda x: True + self.assertEqual({}, events.registered_callbacks, + 'There should be no registered_callbacks events when ' + 'service has just started.') + events.register(key, cbk, uid=1) + self.assertRaises(Exception, events.register, key, lambda x: True, uid=1) + self.assertEquals(1, + events.register(key, lambda x: True, uid=1, replace=True), + "Could not replace callback.") + self.assertEqual(1, len(events.registered_callbacks), + 'Wrong number of registered callbacks.') + self.assertEqual(events.registered_callbacks.keys(), [key], + 'Couldn\'t locate registered signal.') + + def test_signal_response_status(self): + sig = SignalRequest.SOLEDAD_CREATING_KEYS + cbk = lambda x: True + events.register(sig, cbk) + request = SignalRequest() + request.id = 1 + request.signal = sig + request.content = 'my signal contents' + request.mac_method = 'nomac' + request.mac = "" + service = RpcService(SignalService_Stub, port, 'localhost') + response = service.signal(request, timeout=1000) + self.assertEqual(response.OK, response.status, + 'Wrong response status.') -- cgit v1.2.3 From 04e3a6e65bfea724dec8de47a7d8195ca3c3674c Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 5 Jun 2013 12:48:41 -0300 Subject: Move symmetric encryption code to leap.soledad. --- src/leap/common/crypto.py | 114 ----------------------------------- src/leap/common/tests/test_crypto.py | 88 --------------------------- 2 files changed, 202 deletions(-) delete mode 100644 src/leap/common/crypto.py delete mode 100644 src/leap/common/tests/test_crypto.py diff --git a/src/leap/common/crypto.py b/src/leap/common/crypto.py deleted file mode 100644 index 7f80a8a..0000000 --- a/src/leap/common/crypto.py +++ /dev/null @@ -1,114 +0,0 @@ -# -*- coding: utf-8 -*- -# crypto.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import binascii - -from Crypto.Cipher import AES -from Crypto.Util import Counter -from leap.common.check import leap_assert, leap_assert_type - -# -# encryption methods -# - -class EncryptionMethods(object): - """ - Representation of encryption methods that can be used. - """ - - AES_256_CTR = 'aes-256-ctr' - - -class UnknownEncryptionMethod(Exception): - """ - Raised when trying to encrypt/decrypt with unknown method. - """ - pass - - -# -# encrypt/decrypt functions -# - -# In the future, we might want to implement other encryption schemes and -# possibly factor out the actual encryption/decryption routines of the -# following functions to specific classes, while not changing the API. - -def encrypt_sym(data, key, method=EncryptionMethods.AES_256_CTR): - """ - Encrypt C{data} with C{key}, using C{method} encryption method. - - :param data: The data to be encrypted. - :type data: str - :param key: The key used to encrypt C{data} (must be 256 bits long). - :type key: str - :param method: The encryption method to use. - :type method: str - - :return: A tuple with the initial value and the encrypted data. - :rtype: (long, str) - """ - leap_assert_type(key, str) - - # AES-256 in CTR mode - if method == EncryptionMethods.AES_256_CTR: - leap_assert( - len(key) == 32, # 32 x 8 = 256 bits. - 'Wrong key size: %s bits (must be 256 bits long).' % (len(key)*8)) - iv = os.urandom(8) - ctr = Counter.new(64, prefix=iv) - cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr) - return binascii.b2a_base64(iv), cipher.encrypt(data) - - # raise if method is unknown - raise UnknownEncryptionMethod('Unkwnown method: %s' % method) - - -def decrypt_sym(data, key, method=EncryptionMethods.AES_256_CTR, **kwargs): - """ - Decrypt C{data} with C{key} using C{method} encryption method. - - :param data: The data to be decrypted. - :type data: str - :param key: The key used to decrypt C{data} (must be 256 bits long). - :type key: str - :param method: The encryption method to use. - :type method: str - :param kwargs: Other parameters specific to each encryption method. - :type kwargs: dict - - :return: The decrypted data. - :rtype: str - """ - leap_assert_type(key, str) - - # AES-256 in CTR mode - if method == EncryptionMethods.AES_256_CTR: - # assert params - leap_assert( - len(key) == 32, # 32 x 8 = 256 bits. - 'Wrong key size: %s (must be 256 bits long).' % len(key)) - leap_assert( - 'iv' in kwargs, - 'AES-256-CTR needs an initial value given as.') - ctr = Counter.new(64, prefix=binascii.a2b_base64(kwargs['iv'])) - cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr) - return cipher.decrypt(data) - - # raise if method is unknown - raise UnknownEncryptionMethod('Unkwnown method: %s' % method) diff --git a/src/leap/common/tests/test_crypto.py b/src/leap/common/tests/test_crypto.py deleted file mode 100644 index ae7dc71..0000000 --- a/src/leap/common/tests/test_crypto.py +++ /dev/null @@ -1,88 +0,0 @@ -## -*- coding: utf-8 -*- -# test_crypto.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - - -""" -Tests for the crypto submodule. -""" - - -import os -import binascii - - -from leap.common.testing.basetest import BaseLeapTest -from leap.common import crypto -from Crypto import Random - - -class CryptoTestCase(BaseLeapTest): - - def setUp(self): - pass - - def tearDown(self): - pass - - def test_encrypt_decrypt_sym(self): - # generate 256-bit key - key = Random.new().read(32) - iv, cyphertext = crypto.encrypt_sym( - 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertTrue(cyphertext is not None) - self.assertTrue(cyphertext != '') - self.assertTrue(cyphertext != 'data') - plaintext = crypto.decrypt_sym( - cyphertext, key, iv=iv, - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertEqual('data', plaintext) - - def test_decrypt_with_wrong_iv_fails(self): - key = Random.new().read(32) - iv, cyphertext = crypto.encrypt_sym( - 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertTrue(cyphertext is not None) - self.assertTrue(cyphertext != '') - self.assertTrue(cyphertext != 'data') - # get a different iv by changing the first byte - rawiv = binascii.a2b_base64(iv) - wrongiv = rawiv - while wrongiv == rawiv: - wrongiv = os.urandom(1) + rawiv[1:] - plaintext = crypto.decrypt_sym( - cyphertext, key, iv=binascii.b2a_base64(wrongiv), - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertNotEqual('data', plaintext) - - def test_decrypt_with_wrong_key_fails(self): - key = Random.new().read(32) - iv, cyphertext = crypto.encrypt_sym( - 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertTrue(cyphertext is not None) - self.assertTrue(cyphertext != '') - self.assertTrue(cyphertext != 'data') - wrongkey = Random.new().read(32) # 256-bits key - # ensure keys are different in case we are extremely lucky - while wrongkey == key: - wrongkey = Random.new().read(32) - plaintext = crypto.decrypt_sym( - cyphertext, wrongkey, iv=iv, - method=crypto.EncryptionMethods.AES_256_CTR) - self.assertNotEqual('data', plaintext) -- cgit v1.2.3 From 7a60675f20c03a0afba931dcae6b48fa737efd57 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 5 Jun 2013 23:26:08 -0300 Subject: Add changes file. --- changes/feature_move-symmetric-encryption-code-to-leap.soledad | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/feature_move-symmetric-encryption-code-to-leap.soledad diff --git a/changes/feature_move-symmetric-encryption-code-to-leap.soledad b/changes/feature_move-symmetric-encryption-code-to-leap.soledad new file mode 100644 index 0000000..1541362 --- /dev/null +++ b/changes/feature_move-symmetric-encryption-code-to-leap.soledad @@ -0,0 +1 @@ + o Move symmetric encryption code to leap.soledad. -- cgit v1.2.3 From a08b198d889396d25182bb9716817311bcc3be47 Mon Sep 17 00:00:00 2001 From: drebs Date: Sun, 9 Jun 2013 14:16:33 -0300 Subject: Add possibility of unregistering in events mechanism. --- changes/feature_add-events-ungerister | 1 + src/leap/common/events/__init__.py | 31 ++- src/leap/common/events/component.py | 55 +++- src/leap/common/events/events.proto | 8 + src/leap/common/events/events_pb2.py | 497 +++++++++++++++++++--------------- src/leap/common/events/server.py | 27 ++ src/leap/common/tests/test_events.py | 33 +++ 7 files changed, 435 insertions(+), 217 deletions(-) create mode 100644 changes/feature_add-events-ungerister diff --git a/changes/feature_add-events-ungerister b/changes/feature_add-events-ungerister new file mode 100644 index 0000000..0f17626 --- /dev/null +++ b/changes/feature_add-events-ungerister @@ -0,0 +1 @@ + o Add possibility of unregistering callbacks for a signal. diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py index 9fc93ee..12416e4 100644 --- a/src/leap/common/events/__init__.py +++ b/src/leap/common/events/__init__.py @@ -24,7 +24,7 @@ import socket from leap.common.events import ( - events_pb2, + events_pb2 as proto, server, component, daemon, @@ -61,12 +61,37 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ return component.register(signal, callback, uid, replace, reqcbk, timeout) +def unregister(signal, uid=None, reqcbk=None, timeout=1000): + """ + Unregister a callback. + + If C{uid} is specified, unregisters only the callback identified by that + unique id. Otherwise, unregisters all callbacks registered for C{signal}. + + :param signal: the signal that causes the callback to be launched + :type signal: int (see the `events.proto` file) + :param uid: a unique id for the callback + :type uid: int + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + + :return: the response from server for synch calls or nothing for asynch + calls. + :rtype: leap.common.events.events_pb2.EventsResponse or None + """ + return component.unregister(signal, uid, reqcbk, timeout) + + def signal(signal, content="", mac_method="", mac="", reqcbk=None, timeout=1000): """ @@ -94,7 +119,7 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ return component.signal(signal, content, mac_method, mac, reqcbk, timeout) diff --git a/src/leap/common/events/component.py b/src/leap/common/events/component.py index 9932190..029d1ac 100644 --- a/src/leap/common/events/component.py +++ b/src/leap/common/events/component.py @@ -56,6 +56,7 @@ class CallbackAlreadyRegistered(Exception): """ Raised when trying to register an already registered callback. """ + pass def ensure_component_daemon(): @@ -111,7 +112,7 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, callback identified by the given uid and replace is False. :return: the response from server for synch calls or nothing for asynch - calls + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ ensure_component_daemon() # so we can receive registered signals @@ -140,6 +141,56 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, str(request)[:40]) return service.register(request, callback=reqcbk, timeout=timeout) +def unregister(signal, uid=None, reqcbk=None, timeout=1000): + """ + Unregister a callback. + + If C{uid} is specified, unregisters only the callback identified by that + unique id. Otherwise, unregisters all callbacks + + :param signal: the signal that causes the callback to be launched + :type signal: int (see the `events.proto` file) + :param uid: a unique id for the callback + :type uid: int + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + + :return: the response from server for synch calls or nothing for asynch + calls or None if no callback is registered for that signal or uid. + :rtype: leap.common.events.events_pb2.EventsResponse or None + """ + if signal not in registered_callbacks or not registered_callbacks[signal]: + logger.warning("No callback registered for signal %d." % signal) + return None + # unregister callback locally + cbklist = registered_callbacks[signal] + if uid is not None: + if filter(lambda (cbkuid, _): cbkuid == uid, cbklist) == []: + logger.warning("No callback registered for uid %d." % st) + return None + registered_callbacks[signal] = filter(lambda(x, y): x != uid, cbklist) + else: + # exclude all callbacks for given signal + registered_callbacks[signal] = [] + # unregister port in server if there are no more callbacks for this signal + if not registered_callbacks[signal]: + request = proto.UnregisterRequest() + request.event = signal + request.port = EventsComponentDaemon.get_instance().get_port() + request.mac_method = mac_auth.MacMethod.MAC_NONE + request.mac = "" + service = RpcService(proto.EventsServerService_Stub, + server.SERVER_PORT, 'localhost') + logger.info( + "Sending unregistration request to server on port %s: %s", + server.SERVER_PORT, + str(request)[:40]) + return service.unregister(request, callback=reqcbk, timeout=timeout) + def signal(signal, content="", mac_method="", mac="", reqcbk=None, timeout=1000): @@ -168,7 +219,7 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ request = proto.SignalRequest() diff --git a/src/leap/common/events/events.proto b/src/leap/common/events/events.proto index 447b038..a813ed1 100644 --- a/src/leap/common/events/events.proto +++ b/src/leap/common/events/events.proto @@ -49,6 +49,13 @@ message RegisterRequest { required bytes mac = 4; } +message UnregisterRequest { + required Event event = 1; + required int32 port = 2; + required string mac_method = 3; + required bytes mac = 4; +} + message EventResponse { enum Status { @@ -63,6 +70,7 @@ message EventResponse { service EventsServerService { rpc register(RegisterRequest) returns (EventResponse); + rpc unregister(UnregisterRequest) returns (EventResponse); rpc signal(SignalRequest) returns (EventResponse); } diff --git a/src/leap/common/events/events_pb2.py b/src/leap/common/events/events_pb2.py index a4f1df4..5b1c118 100644 --- a/src/leap/common/events/events_pb2.py +++ b/src/leap/common/events/events_pb2.py @@ -1,85 +1,87 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! +# source: events.proto -from google.protobuf import descriptor -from google.protobuf import message -from google.protobuf import reflection -from google.protobuf import service +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import service as _service from google.protobuf import service_reflection from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) -DESCRIPTOR = descriptor.FileDescriptor( +DESCRIPTOR = _descriptor.FileDescriptor( name='events.proto', package='leap.common.events', - serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\xb9\x01\n\x13\x45ventsServerService\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2h\n\x16\x45ventsComponentService\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') + serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"l\n\x11UnregisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\x91\x02\n\x13\x45ventsServerService\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12V\n\nunregister\x12%.leap.common.events.UnregisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2h\n\x16\x45ventsComponentService\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') -_EVENT = descriptor.EnumDescriptor( +_EVENT = _descriptor.EnumDescriptor( name='Event', full_name='leap.common.events.Event', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CLIENT_SESSION_ID', index=0, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='CLIENT_UID', index=1, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_CREATING_KEYS', index=2, number=3, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_DONE_CREATING_KEYS', index=3, number=4, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_UPLOADING_KEYS', index=4, number=5, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_DONE_UPLOADING_KEYS', index=5, number=6, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_DOWNLOADING_KEYS', index=6, number=7, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_DONE_DOWNLOADING_KEYS', index=7, number=8, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_NEW_DATA_TO_SYNC', index=8, number=9, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='SOLEDAD_DONE_DATA_SYNC', index=9, number=10, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='UPDATER_NEW_UPDATES', index=10, number=11, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='UPDATER_DONE_UPDATING', index=11, number=12, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='RAISE_WINDOW', index=12, number=13, options=None, type=None), ], containing_type=None, options=None, - serialized_start=432, - serialized_end=791, + serialized_start=542, + serialized_end=901, ) - +Event = enum_type_wrapper.EnumTypeWrapper(_EVENT) CLIENT_SESSION_ID = 1 CLIENT_UID = 2 SOLEDAD_CREATING_KEYS = 3 @@ -95,240 +97,311 @@ UPDATER_DONE_UPDATING = 12 RAISE_WINDOW = 13 -_EVENTRESPONSE_STATUS = descriptor.EnumDescriptor( +_EVENTRESPONSE_STATUS = _descriptor.EnumDescriptor( name='Status', full_name='leap.common.events.EventResponse.Status', filename=None, file=DESCRIPTOR, values=[ - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='OK', index=0, number=1, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='UNAUTH', index=1, number=2, options=None, type=None), - descriptor.EnumValueDescriptor( + _descriptor.EnumValueDescriptor( name='ERROR', index=2, number=3, options=None, type=None), ], containing_type=None, options=None, - serialized_start=390, - serialized_end=429, + serialized_start=500, + serialized_end=539, ) -_SIGNALREQUEST = descriptor.Descriptor( +_SIGNALREQUEST = _descriptor.Descriptor( name='SignalRequest', full_name='leap.common.events.SignalRequest', filename=None, file=DESCRIPTOR, containing_type=None, fields=[ - descriptor.FieldDescriptor( + _descriptor.FieldDescriptor( name='event', full_name='leap.common.events.SignalRequest.event', index=0, number=1, type=14, cpp_type=8, label=2, has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='content', full_name='leap.common.events.SignalRequest.content', index=1, - number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='mac_method', full_name='leap.common.events.SignalRequest.mac_method', index=2, - number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='mac', full_name='leap.common.events.SignalRequest.mac', index=3, - number=4, type=12, cpp_type=9, label=2, - has_default_value=False, default_value="", - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='enc_method', full_name='leap.common.events.SignalRequest.enc_method', index=4, - number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='error_occurred', full_name='leap.common.events.SignalRequest.error_occurred', index=5, - number=6, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - extension_ranges=[], - serialized_start=37, - serialized_end=188, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='content', full_name='leap.common.events.SignalRequest.content', index=1, + number=2, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac_method', full_name='leap.common.events.SignalRequest.mac_method', index=2, + number=3, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac', full_name='leap.common.events.SignalRequest.mac', index=3, + number=4, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='enc_method', full_name='leap.common.events.SignalRequest.enc_method', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='error_occurred', full_name='leap.common.events.SignalRequest.error_occurred', index=5, + number=6, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=37, + serialized_end=188, +) + + +_REGISTERREQUEST = _descriptor.Descriptor( + name='RegisterRequest', + full_name='leap.common.events.RegisterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='event', full_name='leap.common.events.RegisterRequest.event', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='port', full_name='leap.common.events.RegisterRequest.port', index=1, + number=2, type=5, cpp_type=1, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac_method', full_name='leap.common.events.RegisterRequest.mac_method', index=2, + number=3, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac', full_name='leap.common.events.RegisterRequest.mac', index=3, + number=4, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=190, + serialized_end=296, ) -_REGISTERREQUEST = descriptor.Descriptor( - name='RegisterRequest', - full_name='leap.common.events.RegisterRequest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - descriptor.FieldDescriptor( - name='event', full_name='leap.common.events.RegisterRequest.event', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='port', full_name='leap.common.events.RegisterRequest.port', index=1, - number=2, type=5, cpp_type=1, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='mac_method', full_name='leap.common.events.RegisterRequest.mac_method', index=2, - number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='mac', full_name='leap.common.events.RegisterRequest.mac', index=3, - number=4, type=12, cpp_type=9, label=2, - has_default_value=False, default_value="", - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - extension_ranges=[], - serialized_start=190, - serialized_end=296, +_UNREGISTERREQUEST = _descriptor.Descriptor( + name='UnregisterRequest', + full_name='leap.common.events.UnregisterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='event', full_name='leap.common.events.UnregisterRequest.event', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='port', full_name='leap.common.events.UnregisterRequest.port', index=1, + number=2, type=5, cpp_type=1, label=2, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac_method', full_name='leap.common.events.UnregisterRequest.mac_method', index=2, + number=3, type=9, cpp_type=9, label=2, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='mac', full_name='leap.common.events.UnregisterRequest.mac', index=3, + number=4, type=12, cpp_type=9, label=2, + has_default_value=False, default_value="", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=298, + serialized_end=406, ) -_EVENTRESPONSE = descriptor.Descriptor( - name='EventResponse', - full_name='leap.common.events.EventResponse', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - descriptor.FieldDescriptor( - name='status', full_name='leap.common.events.EventResponse.status', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - descriptor.FieldDescriptor( - name='result', full_name='leap.common.events.EventResponse.result', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=unicode("", "utf-8"), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _EVENTRESPONSE_STATUS, - ], - options=None, - is_extendable=False, - extension_ranges=[], - serialized_start=299, - serialized_end=429, +_EVENTRESPONSE = _descriptor.Descriptor( + name='EventResponse', + full_name='leap.common.events.EventResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='status', full_name='leap.common.events.EventResponse.status', index=0, + number=1, type=14, cpp_type=8, label=2, + has_default_value=False, default_value=1, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='result', full_name='leap.common.events.EventResponse.result', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=unicode("", "utf-8"), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _EVENTRESPONSE_STATUS, + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=409, + serialized_end=539, ) _SIGNALREQUEST.fields_by_name['event'].enum_type = _EVENT _REGISTERREQUEST.fields_by_name['event'].enum_type = _EVENT +_UNREGISTERREQUEST.fields_by_name['event'].enum_type = _EVENT _EVENTRESPONSE.fields_by_name['status'].enum_type = _EVENTRESPONSE_STATUS -_EVENTRESPONSE_STATUS.containing_type = _EVENTRESPONSE; +_EVENTRESPONSE_STATUS.containing_type = _EVENTRESPONSE DESCRIPTOR.message_types_by_name['SignalRequest'] = _SIGNALREQUEST DESCRIPTOR.message_types_by_name['RegisterRequest'] = _REGISTERREQUEST +DESCRIPTOR.message_types_by_name['UnregisterRequest'] = _UNREGISTERREQUEST DESCRIPTOR.message_types_by_name['EventResponse'] = _EVENTRESPONSE -class SignalRequest(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType +class SignalRequest(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType DESCRIPTOR = _SIGNALREQUEST # @@protoc_insertion_point(class_scope:leap.common.events.SignalRequest) -class RegisterRequest(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType +class RegisterRequest(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType DESCRIPTOR = _REGISTERREQUEST # @@protoc_insertion_point(class_scope:leap.common.events.RegisterRequest) -class EventResponse(message.Message): - __metaclass__ = reflection.GeneratedProtocolMessageType +class UnregisterRequest(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType + DESCRIPTOR = _UNREGISTERREQUEST + + # @@protoc_insertion_point(class_scope:leap.common.events.UnregisterRequest) + + +class EventResponse(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType DESCRIPTOR = _EVENTRESPONSE # @@protoc_insertion_point(class_scope:leap.common.events.EventResponse) -_EVENTSSERVERSERVICE = descriptor.ServiceDescriptor( - name='EventsServerService', - full_name='leap.common.events.EventsServerService', - file=DESCRIPTOR, - index=0, - options=None, - serialized_start=794, - serialized_end=979, - methods=[ - descriptor.MethodDescriptor( - name='register', - full_name='leap.common.events.EventsServerService.register', +DESCRIPTOR.has_options = True +DESCRIPTOR._options = _descriptor._ParseOptions( + descriptor_pb2.FileOptions(), '\220\001\001') + +_EVENTSSERVERSERVICE = _descriptor.ServiceDescriptor( + name='EventsServerService', + full_name='leap.common.events.EventsServerService', + file=DESCRIPTOR, index=0, - containing_service=None, - input_type=_REGISTERREQUEST, - output_type=_EVENTRESPONSE, options=None, - ), - descriptor.MethodDescriptor( - name='signal', - full_name='leap.common.events.EventsServerService.signal', - index=1, - containing_service=None, - input_type=_SIGNALREQUEST, - output_type=_EVENTRESPONSE, - options=None, - ), -]) + serialized_start=904, + serialized_end=1177, + methods=[ + _descriptor.MethodDescriptor( + name='register', + full_name='leap.common.events.EventsServerService.register', + index=0, + containing_service=None, + input_type=_REGISTERREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), + _descriptor.MethodDescriptor( + name='unregister', + full_name='leap.common.events.EventsServerService.unregister', + index=1, + containing_service=None, + input_type=_UNREGISTERREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), + _descriptor.MethodDescriptor( + name='signal', + full_name='leap.common.events.EventsServerService.signal', + index=2, + containing_service=None, + input_type=_SIGNALREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), + ]) -class EventsServerService(service.Service): +class EventsServerService(_service.Service): __metaclass__ = service_reflection.GeneratedServiceType DESCRIPTOR = _EVENTSSERVERSERVICE @@ -338,28 +411,28 @@ class EventsServerService_Stub(EventsServerService): DESCRIPTOR = _EVENTSSERVERSERVICE -_EVENTSCOMPONENTSERVICE = descriptor.ServiceDescriptor( - name='EventsComponentService', - full_name='leap.common.events.EventsComponentService', - file=DESCRIPTOR, - index=1, - options=None, - serialized_start=981, - serialized_end=1085, - methods=[ - descriptor.MethodDescriptor( - name='signal', - full_name='leap.common.events.EventsComponentService.signal', - index=0, - containing_service=None, - input_type=_SIGNALREQUEST, - output_type=_EVENTRESPONSE, +_EVENTSCOMPONENTSERVICE = _descriptor.ServiceDescriptor( + name='EventsComponentService', + full_name='leap.common.events.EventsComponentService', + file=DESCRIPTOR, + index=1, options=None, - ), -]) + serialized_start=1179, + serialized_end=1283, + methods=[ + _descriptor.MethodDescriptor( + name='signal', + full_name='leap.common.events.EventsComponentService.signal', + index=0, + containing_service=None, + input_type=_SIGNALREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), + ]) -class EventsComponentService(service.Service): +class EventsComponentService(_service.Service): __metaclass__ = service_reflection.GeneratedServiceType DESCRIPTOR = _EVENTSCOMPONENTSERVICE diff --git a/src/leap/common/events/server.py b/src/leap/common/events/server.py index 1f3a874..d53c218 100644 --- a/src/leap/common/events/server.py +++ b/src/leap/common/events/server.py @@ -100,6 +100,33 @@ class EventsServerService(proto.EventsServerService): response.status = proto.EventResponse.OK done.run(response) + def unregister(self, controller, request, done): + """ + Unregister a component port so it will not be signaled when specific + events come in. + + :param controller: used to mediate a single method call + :type controller: protobuf.socketrpc.controller.SocketRpcController + :param request: the request received from the component + :type request: leap.common.events.events_pb2.RegisterRequest + :param done: callback to be called when done + :type done: protobuf.socketrpc.server.Callback + """ + logger.info( + "Received unregistration request: %s..." % str(request)[:40]) + # remove component port from signal list + response = proto.EventResponse() + if request.event in registered_components: + try: + registered_components[request.event].remove(request.port) + response.status = proto.EventResponse.OK + except KeyError: + response.status = proto.EventsResponse.ERROR + response.result = 'Port %d not registered.' % request.port + # send response back to component + logger.debug('sending response back') + done.run(response) + def signal(self, controller, request, done): """ Perform an RPC call to signal all components registered to receive a diff --git a/src/leap/common/tests/test_events.py b/src/leap/common/tests/test_events.py index 8c0bd36..7286bdc 100644 --- a/src/leap/common/tests/test_events.py +++ b/src/leap/common/tests/test_events.py @@ -198,3 +198,36 @@ class EventsTestCase(unittest.TestCase): response = events.signal(sig) self.assertTrue(response.status == response.OK, 'Received wrong response status when signaling.') + + def test_component_unregister_all(self): + """ + Test that the component can unregister all events for one signal. + """ + sig = CLIENT_UID + complist = server.registered_components + events.register(sig, lambda x: True) + events.register(sig, lambda x: True) + time.sleep(0.1) + events.unregister(sig) + time.sleep(0.1) + port = component.EventsComponentDaemon.get_instance().get_port() + self.assertFalse(bool(complist[sig])) + self.assertTrue(port not in complist[sig]) + + def test_component_unregister_by_uid(self): + """ + Test that the component can unregister an event by uid. + """ + sig = CLIENT_UID + complist = server.registered_components + events.register(sig, lambda x: True, uid='cbkuid') + events.register(sig, lambda x: True, uid='cbkuid2') + time.sleep(0.1) + events.unregister(sig, uid='cbkuid') + time.sleep(0.1) + port = component.EventsComponentDaemon.get_instance().get_port() + self.assertTrue(sig in complist) + self.assertTrue(len(complist[sig]) == 1) + self.assertTrue( + component.registered_callbacks[sig].pop()[0] == 'cbkuid2') + self.assertTrue(port in complist[sig]) -- cgit v1.2.3 From 3a4906638909729236b693fb21a4b1b7194344b5 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 27 Jun 2013 15:33:57 -0300 Subject: Bugfix: use the provider's default language as default string Also take care (and note) a possible case with a problematic provider misconfiguration. --- changes/bug-3029_default-localization-language | 2 ++ src/leap/common/config/baseconfig.py | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 changes/bug-3029_default-localization-language diff --git a/changes/bug-3029_default-localization-language b/changes/bug-3029_default-localization-language new file mode 100644 index 0000000..1fbb464 --- /dev/null +++ b/changes/bug-3029_default-localization-language @@ -0,0 +1,2 @@ + o Bugfix: use the provider's default language as default string. Also take care (and note) a possible case with a problematic provider +misconfiguration. Closes #3029. diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index e6bd9c4..699d734 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -155,26 +155,39 @@ class LocalizedKey(object): def __init__(self, func, **kwargs): self._func = func - def __call__(self, instance, lang="en"): + def __call__(self, instance, lang=None): """ Tries to return the string for the specified language, otherwise - informs the problem and returns an empty string. + returns the default language string. :param lang: language code :type lang: str :return: localized value from the possible values returned by self._func + It returns None in case that the provider does not provides + a matching pair of default_language and string for + that language. + e.g.: + 'default_language': 'es', + 'description': {'en': 'test description'} + Note that the json schema can't check that. """ descriptions = self._func(instance) - description_lang = "" - config_lang = "en" + config_lang = instance.get_default_language() + if lang is None: + lang = config_lang + for key in descriptions.keys(): if lang.startswith(key): config_lang = key break - description_lang = descriptions[config_lang] + description_lang = descriptions.get(config_lang) + if description_lang is None: + logger.error("There is a misconfiguration in the " + "provider's language strings.") + return description_lang def __get__(self, instance, instancetype): -- cgit v1.2.3 From 396de6ae9ec3c05c9ce8c48f0d74021773b22102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 28 Jun 2013 14:50:28 -0300 Subject: Fold in changes for 0.2.2 --- CHANGELOG | 21 +++++++++++++++++++++ changes/bug-3029_default-localization-language | 2 -- changes/bug_add-data-files | 1 - changes/bug_allow-absolute-paths | 1 - changes/bug_fix-deprecation-warning | 1 - ...fix-do-not-attempt-to-fetch-privkeys-from-server | 1 - changes/bug_fix-imports | 1 - changes/feature_add-events-ungerister | 1 - changes/feature_events_signals | 1 - changes/feature_improve_which | 2 -- changes/feature_key-manager | 1 - ...e_move-symmetric-encryption-code-to-leap.soledad | 1 - changes/feature_openpgp-context-manager | 1 - changes/feature_openpgp-sign-verify | 1 - changes/feature_raise-window-event | 1 - .../feature_use-pycrypto-for-symmetric-encryption | 1 - 16 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 CHANGELOG delete mode 100644 changes/bug-3029_default-localization-language delete mode 100644 changes/bug_add-data-files delete mode 100644 changes/bug_allow-absolute-paths delete mode 100644 changes/bug_fix-deprecation-warning delete mode 100644 changes/bug_fix-do-not-attempt-to-fetch-privkeys-from-server delete mode 100644 changes/bug_fix-imports delete mode 100644 changes/feature_add-events-ungerister delete mode 100644 changes/feature_events_signals delete mode 100644 changes/feature_improve_which delete mode 100644 changes/feature_key-manager delete mode 100644 changes/feature_move-symmetric-encryption-code-to-leap.soledad delete mode 100644 changes/feature_openpgp-context-manager delete mode 100644 changes/feature_openpgp-sign-verify delete mode 100644 changes/feature_raise-window-event delete mode 100644 changes/feature_use-pycrypto-for-symmetric-encryption diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..5f9cb69 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,21 @@ +0.2.2 Jun 28: + o Bugfix: use the provider's default language as default + string. Also take care (and note) a possible case with a + problematic provider misconfiguration. Closes #3029. + o Add data files to setup and manifest (certificates for tests) + o Allow absolute paths in baseconfig.load + o Fix deprecation warnings + o Fix attempt to fetch private keys from server. + o Fix missing imports + o Add possibility of unregistering callbacks for a signal. + o Add a mechanism for events signaling between components. + o Prioritize the path_extension in the which method so it finds our + bundled app before the system one, if any. + o Move the Key Manager to leap client repository. + o Move symmetric encryption code to leap.soledad. + o Refactor opengpg utility functions implementation so it uses a + context manager. + o Add OpenPGP sign/verify + o Add RAISE_WINDOW event + o Add AES-256 (CTR mode) encrypting/decrypting functions using + PyCrypto. diff --git a/changes/bug-3029_default-localization-language b/changes/bug-3029_default-localization-language deleted file mode 100644 index 1fbb464..0000000 --- a/changes/bug-3029_default-localization-language +++ /dev/null @@ -1,2 +0,0 @@ - o Bugfix: use the provider's default language as default string. Also take care (and note) a possible case with a problematic provider -misconfiguration. Closes #3029. diff --git a/changes/bug_add-data-files b/changes/bug_add-data-files deleted file mode 100644 index 5231fb8..0000000 --- a/changes/bug_add-data-files +++ /dev/null @@ -1 +0,0 @@ - o Add data files to setup and manifest (certificates for tests) diff --git a/changes/bug_allow-absolute-paths b/changes/bug_allow-absolute-paths deleted file mode 100644 index deaff1f..0000000 --- a/changes/bug_allow-absolute-paths +++ /dev/null @@ -1 +0,0 @@ - o Allow absolute paths in baseconfig.load diff --git a/changes/bug_fix-deprecation-warning b/changes/bug_fix-deprecation-warning deleted file mode 100644 index ac58117..0000000 --- a/changes/bug_fix-deprecation-warning +++ /dev/null @@ -1 +0,0 @@ - o Fix deprecation warnings diff --git a/changes/bug_fix-do-not-attempt-to-fetch-privkeys-from-server b/changes/bug_fix-do-not-attempt-to-fetch-privkeys-from-server deleted file mode 100644 index 4c8c0eb..0000000 --- a/changes/bug_fix-do-not-attempt-to-fetch-privkeys-from-server +++ /dev/null @@ -1 +0,0 @@ - o Fix attempt to fetch private keys from server. diff --git a/changes/bug_fix-imports b/changes/bug_fix-imports deleted file mode 100644 index 509f2f4..0000000 --- a/changes/bug_fix-imports +++ /dev/null @@ -1 +0,0 @@ - o Fix missing imports diff --git a/changes/feature_add-events-ungerister b/changes/feature_add-events-ungerister deleted file mode 100644 index 0f17626..0000000 --- a/changes/feature_add-events-ungerister +++ /dev/null @@ -1 +0,0 @@ - o Add possibility of unregistering callbacks for a signal. diff --git a/changes/feature_events_signals b/changes/feature_events_signals deleted file mode 100644 index ae0b7b0..0000000 --- a/changes/feature_events_signals +++ /dev/null @@ -1 +0,0 @@ - o Add a mechanism for events signaling between components. diff --git a/changes/feature_improve_which b/changes/feature_improve_which deleted file mode 100644 index d1d1fb5..0000000 --- a/changes/feature_improve_which +++ /dev/null @@ -1,2 +0,0 @@ - o Prioritize the path_extension in the which method so it finds our bundled - app before the system one, if any. diff --git a/changes/feature_key-manager b/changes/feature_key-manager deleted file mode 100644 index 47a62ed..0000000 --- a/changes/feature_key-manager +++ /dev/null @@ -1 +0,0 @@ - o Move the Key Manager to leap client repository. diff --git a/changes/feature_move-symmetric-encryption-code-to-leap.soledad b/changes/feature_move-symmetric-encryption-code-to-leap.soledad deleted file mode 100644 index 1541362..0000000 --- a/changes/feature_move-symmetric-encryption-code-to-leap.soledad +++ /dev/null @@ -1 +0,0 @@ - o Move symmetric encryption code to leap.soledad. diff --git a/changes/feature_openpgp-context-manager b/changes/feature_openpgp-context-manager deleted file mode 100644 index 4dbf759..0000000 --- a/changes/feature_openpgp-context-manager +++ /dev/null @@ -1 +0,0 @@ - o Refactor opengpg utility functions implementation so it uses a context manager. diff --git a/changes/feature_openpgp-sign-verify b/changes/feature_openpgp-sign-verify deleted file mode 100644 index 9422edc..0000000 --- a/changes/feature_openpgp-sign-verify +++ /dev/null @@ -1 +0,0 @@ - o Add OpenPGP sign/verify diff --git a/changes/feature_raise-window-event b/changes/feature_raise-window-event deleted file mode 100644 index 382ff3f..0000000 --- a/changes/feature_raise-window-event +++ /dev/null @@ -1 +0,0 @@ - o Add RAISE_WINDOW event diff --git a/changes/feature_use-pycrypto-for-symmetric-encryption b/changes/feature_use-pycrypto-for-symmetric-encryption deleted file mode 100644 index 5448483..0000000 --- a/changes/feature_use-pycrypto-for-symmetric-encryption +++ /dev/null @@ -1 +0,0 @@ - o Add AES-256 (CTR mode) encrypting/decrypting functions using PyCrypto. -- cgit v1.2.3 From ee9155c478630d08cc8314fd13f8bc1be4e42130 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 2 Jul 2013 15:08:39 -0300 Subject: Add tests for the BaseConfig class. --- src/leap/common/config/tests/test_baseconfig.py | 268 ++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 src/leap/common/config/tests/test_baseconfig.py diff --git a/src/leap/common/config/tests/test_baseconfig.py b/src/leap/common/config/tests/test_baseconfig.py new file mode 100644 index 0000000..8a2915e --- /dev/null +++ b/src/leap/common/config/tests/test_baseconfig.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +# test_baseconfig.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Tests for baseconfig +""" +import json +import unittest +import copy + +from leap.common.config.baseconfig import BaseConfig, LocalizedKey +from leap.common.testing.basetest import BaseLeapTest + +from mock import Mock + +# reduced eipconfig sample config +sample_config = { + "gateways": [ + { + "capabilities": { + "adblock": False, + "transport": ["openvpn"], + "user_ips": False + }, + "host": "host.dev.example.org", + }, { + "capabilities": { + "adblock": False, + "transport": ["openvpn"], + "user_ips": False + }, + "host": "host2.dev.example.org", + } + ], + "default_language": "en", + "languages": [ + "en", + "es" + ], + "name": { + "en": "Baseconfig testing environment", + "es": "Entorno de pruebas de Baseconfig" + }, + "serial": 1, + "version": 1 +} + +# reduced eipconfig.spec version +sample_spec = { + 'description': 'sample eip service config', + 'type': 'object', + 'properties': { + 'serial': { + 'type': int, + 'default': 1, + 'required': ["True"] + }, + 'version': { + 'type': int, + 'default': 1, + 'required': ["True"] + }, + "default_language": { + 'type': unicode, + 'default': 'en' + }, + 'languages': { + 'type': list, + 'default': ['en'] + }, + 'name': { + 'type': dict, + 'format': 'translatable', + 'default': {u'en': u'Test Provider'} + }, + 'gateways': { + 'type': list, + 'default': [ + {"capabilities": { + "adblock": True, + "transport": ["openvpn"], + "user_ips": False}, + "host": "location.example.org", + }] + }, + } +} + + +class TestConfig(BaseConfig): + """ + BaseConfig implementation for testing purposes only. + """ + def get_gateways(self): + return self._safe_get_value("gateways") + + def get_serial(self): + return self._safe_get_value("serial") + + def get_version(self): + return self._safe_get_value("version") + + def _get_spec(self): + return sample_spec + + def get_default_language(self): + return self._safe_get_value("default_language") + + @LocalizedKey + def get_name(self): + return self._safe_get_value("name") + + +class BaseConfigTest(BaseLeapTest): + + def setUp(self): + pass + + def tearDown(self): + pass + + def _write_config(self, data): + """ + Helper to write some data to a temp config file. + + :param data: data to be used to save in the config file. + :data type: dict (valid json) + """ + self.config_file = self.get_tempfile("config.json") + conf = open(self.config_file, "w") + conf.write(json.dumps(data)) + conf.close() + + def _get_config(self, fromfile=False, data=sample_config): + """ + Helper that returns a TestConfig object using the data parameter + or a sample data. + + :param fromfile: sets if we should use a file or a string + :fromfile type: bool + :param data: sets the data to be used to load in the TestConfig object + :data type: dict (valid json) + :rtype: TestConfig + """ + config = TestConfig() + + loaded = False + if fromfile: + self._write_config(data) + loaded = config.load(self.config_file, relative=False) + else: + json_string = json.dumps(data) + loaded = config.load(data=json_string) + + if not loaded: + return None + + return config + + def test_loads_from_file(self): + config = self._get_config(fromfile=True) + self.assertIsNotNone(config) + + def test_loads_from_data(self): + config = self._get_config() + self.assertIsNotNone(config) + + def test_load_valid_config_from_file(self): + config = self._get_config(fromfile=True) + self.assertIsNotNone(config) + + self.assertEqual(config.get_version(), sample_config["version"]) + self.assertEqual(config.get_serial(), sample_config["serial"]) + self.assertEqual(config.get_gateways(), sample_config["gateways"]) + + def test_load_valid_config_from_data(self): + config = self._get_config() + self.assertIsNotNone(config) + + self.assertEqual(config.get_version(), sample_config["version"]) + self.assertEqual(config.get_serial(), sample_config["serial"]) + self.assertEqual(config.get_gateways(), sample_config["gateways"]) + + def test_safe_get_value_no_config(self): + config = TestConfig() + + with self.assertRaises(AssertionError): + config.get_version() + + def test_safe_get_value_non_existent_value(self): + config = self._get_config() + + self.assertIsNone(config._safe_get_value('non-existent-value')) + + def test_loaded(self): + config = self._get_config() + self.assertTrue(config.loaded()) + + def test_not_loaded(self): + config = TestConfig() + self.assertFalse(config.loaded()) + + def test_save_and_load(self): + config = self._get_config() + config.get_path_prefix = Mock(return_value=self.tempdir) + config_file = 'test_config.json' + self.assertTrue(config.save([config_file])) + + config_saved = TestConfig() + config_file_path = self.get_tempfile(config_file) + self.assertTrue(config_saved.load(config_file_path, relative=False)) + + self.assertEqual(config.get_version(), config_saved.get_version()) + self.assertEqual(config.get_serial(), config_saved.get_serial()) + self.assertEqual(config.get_gateways(), config_saved.get_gateways()) + + def test_localizations(self): + conf = self._get_config() + + self.assertEqual(conf.get_name(lang='en'), sample_config['name']['en']) + self.assertEqual(conf.get_name(lang='es'), sample_config['name']['es']) + + def _localized_config(self, lang): + """ + Helper to change default language of the provider config. + """ + conf = copy.deepcopy(sample_config) + conf['default_language'] = lang + json_string = json.dumps(conf) + config = TestConfig() + config.load(data=json_string) + + return config + + def test_default_localization1(self): + default_language = sample_config['languages'][0] + config = self._localized_config(default_language) + + default_name = sample_config['name'][default_language] + + self.assertEqual(config.get_name(lang='xx'), default_name) + self.assertEqual(config.get_name(), default_name) + + def test_default_localization2(self): + default_language = sample_config['languages'][1] + config = self._localized_config(default_language) + + default_name = sample_config['name'][default_language] + + self.assertEqual(config.get_name(lang='xx'), default_name) + self.assertEqual(config.get_name(), default_name) + + +if __name__ == "__main__": + unittest.main(verbosity=2) -- cgit v1.2.3 From 198aebc32340b961cbcafbcff61e0610a6d6b1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 5 Jul 2013 14:06:02 -0300 Subject: Improve leap_assert traceback logging --- changes/bug2895_improve_leap_assert | 2 ++ src/leap/common/check.py | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 changes/bug2895_improve_leap_assert diff --git a/changes/bug2895_improve_leap_assert b/changes/bug2895_improve_leap_assert new file mode 100644 index 0000000..8caea7e --- /dev/null +++ b/changes/bug2895_improve_leap_assert @@ -0,0 +1,2 @@ + o Improve leap_assert so that it only prints the traceback from the + leap_assert call up. Closes #2895 \ No newline at end of file diff --git a/src/leap/common/check.py b/src/leap/common/check.py index a2d39a6..e6b0b52 100644 --- a/src/leap/common/check.py +++ b/src/leap/common/check.py @@ -18,7 +18,6 @@ Set of functions to help checking situations """ -import inspect import logging import traceback @@ -39,9 +38,11 @@ def leap_assert(condition, message=""): if not condition: logger.error("Bug: %s" % (message,)) try: - frame = inspect.currentframe() - stack_trace = traceback.format_stack(frame) - logger.error(''.join(stack_trace)) + for formatted_line in traceback.format_list( + traceback.extract_stack()[:-1]): + for line in formatted_line.split("\n"): + if len(line.strip()) > 0: + logger.error(line) except Exception as e: logger.error("Bug in leap_assert: %r" % (e,)) assert condition, message -- cgit v1.2.3 From 29053ecc6c3cb7b5b74f7cb7118a7ba7f287e3b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 5 Jul 2013 14:19:06 -0300 Subject: Add osx temp dir prefix --- changes/consider_osx_tempdirs | 1 + src/leap/common/testing/basetest.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changes/consider_osx_tempdirs diff --git a/changes/consider_osx_tempdirs b/changes/consider_osx_tempdirs new file mode 100644 index 0000000..5cc20fb --- /dev/null +++ b/changes/consider_osx_tempdirs @@ -0,0 +1 @@ + o Add OSX temp directories to the basetests class. \ No newline at end of file diff --git a/src/leap/common/testing/basetest.py b/src/leap/common/testing/basetest.py index 8890bf9..54826d5 100644 --- a/src/leap/common/testing/basetest.py +++ b/src/leap/common/testing/basetest.py @@ -68,7 +68,8 @@ class BaseLeapTest(unittest.TestCase): # safety check! please do not wipe my home... # XXX needs to adapt to non-linuces leap_assert( - cls.tempdir.startswith('/tmp/leap_tests-'), + cls.tempdir.startswith('/tmp/leap_tests-') or + cls.tempdir.startswith('/var/folder'), "beware! tried to remove a dir which does not " "live in temporal folder!") shutil.rmtree(cls.tempdir) -- cgit v1.2.3 From 258634d07d1304760c70122af0cc0d58fd0305ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Mon, 8 Jul 2013 17:32:34 -0300 Subject: Add tests for leap_assert* --- src/leap/common/tests/test_check.py | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/leap/common/tests/test_check.py diff --git a/src/leap/common/tests/test_check.py b/src/leap/common/tests/test_check.py new file mode 100644 index 0000000..6ce8493 --- /dev/null +++ b/src/leap/common/tests/test_check.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# test_check.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Tests for: + * leap/common/check.py +""" +try: + import unittest2 as unittest +except ImportError: + import unittest + +import mock + +from leap.common import check + +class CheckTests(unittest.TestCase): + def test_raises_on_false_condition(self): + with self.assertRaises(AssertionError): + check.leap_assert(False, "Condition") + + def test_raises_on_none_condition(self): + with self.assertRaises(AssertionError): + check.leap_assert(None, "Condition") + + def test_suceeds_with_good_condition(self): + check.leap_assert(True, "") + + def test_raises_on_bad_type(self): + with self.assertRaises(AssertionError): + check.leap_assert_type(42, str) + + def test_succeeds_on_good_type(self): + check.leap_assert_type(42, int) + + @mock.patch("traceback.extract_stack", mock.MagicMock(return_value=None)) + def test_does_not_raise_on_bug(self): + with self.assertRaises(AssertionError): + check.leap_assert(False, "") -- cgit v1.2.3 From 936e7a94cb6eb6fec5aeeb2438af525981e68794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 12 Jul 2013 14:46:19 -0300 Subject: Fold in changes --- CHANGELOG | 7 ++++++- changes/bug2895_improve_leap_assert | 2 -- changes/consider_osx_tempdirs | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 changes/bug2895_improve_leap_assert delete mode 100644 changes/consider_osx_tempdirs diff --git a/CHANGELOG b/CHANGELOG index 5f9cb69..a6918b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,9 @@ -0.2.2 Jun 28: +0.2.6 Jul 12: + o Improve leap_assert so that it only prints the traceback from the + leap_assert call up. Closes #2895 + o Add OSX temp directories to the basetests class. + +0.2.5 Jun 28: o Bugfix: use the provider's default language as default string. Also take care (and note) a possible case with a problematic provider misconfiguration. Closes #3029. diff --git a/changes/bug2895_improve_leap_assert b/changes/bug2895_improve_leap_assert deleted file mode 100644 index 8caea7e..0000000 --- a/changes/bug2895_improve_leap_assert +++ /dev/null @@ -1,2 +0,0 @@ - o Improve leap_assert so that it only prints the traceback from the - leap_assert call up. Closes #2895 \ No newline at end of file diff --git a/changes/consider_osx_tempdirs b/changes/consider_osx_tempdirs deleted file mode 100644 index 5cc20fb..0000000 --- a/changes/consider_osx_tempdirs +++ /dev/null @@ -1 +0,0 @@ - o Add OSX temp directories to the basetests class. \ No newline at end of file -- cgit v1.2.3 From 9bd0262664a5cc50957646908af8fe7c92b00cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 12 Jul 2013 14:47:17 -0300 Subject: Bump version to 0.2.6 --- setup.py | 2 +- src/leap/common/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index bdf97c5..9b57aa7 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ setup( name='leap.common', # If you change version, do it also in # src/leap/common/__init__.py - version='0.2.5', + version='0.2.6', url='https://leap.se/', license='GPLv3+', author='The LEAP Encryption Access Project', diff --git a/src/leap/common/__init__.py b/src/leap/common/__init__.py index 2b30715..abeff0f 100644 --- a/src/leap/common/__init__.py +++ b/src/leap/common/__init__.py @@ -16,4 +16,4 @@ except ImportError: __all__ = ["certs", "check", "files", "events"] -__version__ = "0.2.5" +__version__ = "0.2.6" -- cgit v1.2.3 From 1f1412f3c31dfba10135ceae4641313ee48318c8 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 24 Jul 2013 14:01:30 -0300 Subject: Refactor events so components become clients. --- ...46-refactor-events-so-components-become-clients | 1 + src/leap/common/events/README.rst | 12 +- src/leap/common/events/__init__.py | 10 +- src/leap/common/events/client.py | 290 +++++++++++++++++++++ src/leap/common/events/component.py | 290 --------------------- src/leap/common/events/daemon.py | 2 +- src/leap/common/events/events.proto | 2 +- src/leap/common/events/events_pb2.py | 20 +- src/leap/common/events/server.py | 54 ++-- src/leap/common/tests/test_events.py | 66 ++--- 10 files changed, 374 insertions(+), 373 deletions(-) create mode 100644 changes/feature_3246-refactor-events-so-components-become-clients create mode 100644 src/leap/common/events/client.py delete mode 100644 src/leap/common/events/component.py diff --git a/changes/feature_3246-refactor-events-so-components-become-clients b/changes/feature_3246-refactor-events-so-components-become-clients new file mode 100644 index 0000000..c8589c0 --- /dev/null +++ b/changes/feature_3246-refactor-events-so-components-become-clients @@ -0,0 +1 @@ + o Refactor events so components are now called clients. Closes #3246. diff --git a/src/leap/common/events/README.rst b/src/leap/common/events/README.rst index 813be8b..2e7f254 100644 --- a/src/leap/common/events/README.rst +++ b/src/leap/common/events/README.rst @@ -1,19 +1,19 @@ Events mechanism ================ -The events mechanism allows for "components" to send signal events to each -other by means of a centralized server. Components can register with the +The events mechanism allows for clients to send signal events to each +other by means of a centralized server. Clients can register with the server to receive signals of certain types, and they can also send signals to -the server that will then redistribute these signals to registered components. +the server that will then redistribute these signals to registered clients. Listening daemons ----------------- -Both components and the server listen for incoming messages by using a +Both clients and the server listen for incoming messages by using a listening daemon that runs in its own thread. The server daemon has to be -started explicitly, while components daemon will be started whenever a -component registers with the server to receive messages. +started explicitly, while clients daemon will be started whenever a +client registers with the server to receive messages. How to use it diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py index 12416e4..d498340 100644 --- a/src/leap/common/events/__init__.py +++ b/src/leap/common/events/__init__.py @@ -16,7 +16,7 @@ # along with this program. If not, see . """ -An events mechanism that allows for signaling of events between components. +An events mechanism that allows for signaling of events between clients. """ import logging @@ -26,7 +26,7 @@ import socket from leap.common.events import ( events_pb2 as proto, server, - component, + client, daemon, ) @@ -64,7 +64,7 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ - return component.register(signal, callback, uid, replace, reqcbk, timeout) + return client.register(signal, callback, uid, replace, reqcbk, timeout) def unregister(signal, uid=None, reqcbk=None, timeout=1000): @@ -89,7 +89,7 @@ def unregister(signal, uid=None, reqcbk=None, timeout=1000): calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ - return component.unregister(signal, uid, reqcbk, timeout) + return client.unregister(signal, uid, reqcbk, timeout) def signal(signal, content="", mac_method="", mac="", reqcbk=None, @@ -122,4 +122,4 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ - return component.signal(signal, content, mac_method, mac, reqcbk, timeout) + return client.signal(signal, content, mac_method, mac, reqcbk, timeout) diff --git a/src/leap/common/events/client.py b/src/leap/common/events/client.py new file mode 100644 index 0000000..17fc326 --- /dev/null +++ b/src/leap/common/events/client.py @@ -0,0 +1,290 @@ +# -*- coding: utf-8 -*- +# client.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The client end point of the events mechanism. + +Clients are the communicating parties of the events mechanism. They +communicate by sending messages to a server, which in turn redistributes +messages to other clients. + +When a client registers a callback for a given signal, it also tells the +server that it wants to be notified whenever signals of that type are sent by +some other client. +""" + + +import logging +import threading + + +from protobuf.socketrpc import RpcService +from leap.common.events import ( + events_pb2 as proto, + server, + daemon, + mac_auth, +) + + +logger = logging.getLogger(__name__) + + +# the `registered_callbacks` dictionary below should have the following +# format: +# +# { event_signal: [ (uid, callback), ... ], ... } +# +registered_callbacks = {} + + +class CallbackAlreadyRegistered(Exception): + """ + Raised when trying to register an already registered callback. + """ + pass + + +def ensure_client_daemon(): + """ + Ensure the client daemon is running and listening for incoming + messages. + + :return: the daemon instance + :rtype: EventsClientDaemon + """ + import time + daemon = EventsClientDaemon.ensure(0) + logger.debug('ensure client daemon') + + # Because we use a random port we want to wait until a port is assigned to + # local client daemon. + + while not (EventsClientDaemon.get_instance() and + EventsClientDaemon.get_instance().get_port()): + time.sleep(0.1) + return daemon + + +def register(signal, callback, uid=None, replace=False, reqcbk=None, + timeout=1000): + """ + Registers a callback to be called when a specific signal event is + received. + + Will timeout after timeout ms if response has not been received. The + timeout arg is only used for asynch requests. If a reqcbk callback has + been supplied the timeout arg is not used. The response value will be + returned for a synch request but nothing will be returned for an asynch + request. + + :param signal: the signal that causes the callback to be launched + :type signal: int (see the `events.proto` file) + :param callback: the callback to be called when the signal is received + :type callback: function + callback(leap.common.events.events_pb2.SignalRequest) + :param uid: a unique id for the callback + :type uid: int + :param replace: should an existent callback with same uid be replaced? + :type replace: bool + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + + Might raise a CallbackAlreadyRegistered exception if there's already a + callback identified by the given uid and replace is False. + + :return: the response from server for synch calls or nothing for asynch + calls. + :rtype: leap.common.events.events_pb2.EventsResponse or None + """ + ensure_client_daemon() # so we can receive registered signals + # register callback locally + if signal not in registered_callbacks: + registered_callbacks[signal] = [] + cbklist = registered_callbacks[signal] + if uid and filter(lambda (x, y): x == uid, cbklist): + if not replace: + raise CallbackAlreadyRegisteredException() + else: + registered_callbacks[signal] = filter(lambda(x, y): x != uid, + cbklist) + registered_callbacks[signal].append((uid, callback)) + # register callback on server + request = proto.RegisterRequest() + request.event = signal + request.port = EventsClientDaemon.get_instance().get_port() + request.mac_method = mac_auth.MacMethod.MAC_NONE + request.mac = "" + service = RpcService(proto.EventsServerService_Stub, + server.SERVER_PORT, 'localhost') + logger.info( + "Sending registration request to server on port %s: %s", + server.SERVER_PORT, + str(request)[:40]) + return service.register(request, callback=reqcbk, timeout=timeout) + +def unregister(signal, uid=None, reqcbk=None, timeout=1000): + """ + Unregister a callback. + + If C{uid} is specified, unregisters only the callback identified by that + unique id. Otherwise, unregisters all callbacks + + :param signal: the signal that causes the callback to be launched + :type signal: int (see the `events.proto` file) + :param uid: a unique id for the callback + :type uid: int + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + + :return: the response from server for synch calls or nothing for asynch + calls or None if no callback is registered for that signal or uid. + :rtype: leap.common.events.events_pb2.EventsResponse or None + """ + if signal not in registered_callbacks or not registered_callbacks[signal]: + logger.warning("No callback registered for signal %d." % signal) + return None + # unregister callback locally + cbklist = registered_callbacks[signal] + if uid is not None: + if filter(lambda (cbkuid, _): cbkuid == uid, cbklist) == []: + logger.warning("No callback registered for uid %d." % st) + return None + registered_callbacks[signal] = filter(lambda(x, y): x != uid, cbklist) + else: + # exclude all callbacks for given signal + registered_callbacks[signal] = [] + # unregister port in server if there are no more callbacks for this signal + if not registered_callbacks[signal]: + request = proto.UnregisterRequest() + request.event = signal + request.port = EventsClientDaemon.get_instance().get_port() + request.mac_method = mac_auth.MacMethod.MAC_NONE + request.mac = "" + service = RpcService(proto.EventsServerService_Stub, + server.SERVER_PORT, 'localhost') + logger.info( + "Sending unregistration request to server on port %s: %s", + server.SERVER_PORT, + str(request)[:40]) + return service.unregister(request, callback=reqcbk, timeout=timeout) + + +def signal(signal, content="", mac_method="", mac="", reqcbk=None, + timeout=1000): + """ + Send `signal` event to events server. + + Will timeout after timeout ms if response has not been received. The + timeout arg is only used for asynch requests. If a reqcbk callback has + been supplied the timeout arg is not used. The response value will be + returned for a synch request but nothing will be returned for an asynch + request. + + :param signal: the signal that causes the callback to be launched + :type signal: int (see the `events.proto` file) + :param content: the contents of the event signal + :type content: str + :param mac_method: the method used for auth mac + :type mac_method: str + :param mac: the content of the auth mac + :type mac: str + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + + :return: the response from server for synch calls or nothing for asynch + calls. + :rtype: leap.common.events.events_pb2.EventsResponse or None + """ + request = proto.SignalRequest() + request.event = signal + request.content = content + request.mac_method = mac_method + request.mac = mac + service = RpcService(proto.EventsServerService_Stub, server.SERVER_PORT, + 'localhost') + logger.info("Sending signal to server: %s", str(request)[:40]) + return service.signal(request, callback=reqcbk, timeout=timeout) + + +class EventsClientService(proto.EventsClientService): + """ + Service for receiving signal events in clients. + """ + + def __init__(self): + proto.EventsClientService.__init__(self) + + def signal(self, controller, request, done): + """ + Receive a signal and run callbacks registered for that signal. + + This method is called whenever a signal request is received from + server. + + :param controller: used to mediate a single method call + :type controller: protobuf.socketrpc.controller.SocketRpcController + :param request: the request received from the client + :type request: leap.common.events.events_pb2.SignalRequest + :param done: callback to be called when done + :type done: protobuf.socketrpc.server.Callback + """ + logger.info('Received signal from server: %s...' % str(request)[:40]) + + # run registered callbacks + # TODO: verify authentication using mac in incoming message + if request.event in registered_callbacks: + for (_, cbk) in registered_callbacks[request.event]: + # callbacks should be prepared to receive a + # events_pb2.SignalRequest. + cbk(request) + + # send response back to server + response = proto.EventResponse() + response.status = proto.EventResponse.OK + done.run(response) + + +class EventsClientDaemon(daemon.EventsSingletonDaemon): + """ + A daemon that listens for incoming events from server. + """ + + @classmethod + def ensure(cls, port): + """ + Make sure the daemon is running on the given port. + + :param port: the port in which the daemon should listen + :type port: int + + :return: a daemon instance + :rtype: EventsClientDaemon + """ + return cls.ensure_service(port, EventsClientService()) diff --git a/src/leap/common/events/component.py b/src/leap/common/events/component.py deleted file mode 100644 index 029d1ac..0000000 --- a/src/leap/common/events/component.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf-8 -*- -# component.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -The component end point of the events mechanism. - -Components are the communicating parties of the events mechanism. They -communicate by sending messages to a server, which in turn redistributes -messages to other components. - -When a component registers a callback for a given signal, it also tells the -server that it wants to be notified whenever signals of that type are sent by -some other component. -""" - - -import logging -import threading - - -from protobuf.socketrpc import RpcService -from leap.common.events import ( - events_pb2 as proto, - server, - daemon, - mac_auth, -) - - -logger = logging.getLogger(__name__) - - -# the `registered_callbacks` dictionary below should have the following -# format: -# -# { event_signal: [ (uid, callback), ... ], ... } -# -registered_callbacks = {} - - -class CallbackAlreadyRegistered(Exception): - """ - Raised when trying to register an already registered callback. - """ - pass - - -def ensure_component_daemon(): - """ - Ensure the component daemon is running and listening for incoming - messages. - - :return: the daemon instance - :rtype: EventsComponentDaemon - """ - import time - daemon = EventsComponentDaemon.ensure(0) - logger.debug('ensure component daemon') - - # Because we use a random port we want to wait until a port is assigned to - # local component daemon. - - while not (EventsComponentDaemon.get_instance() and - EventsComponentDaemon.get_instance().get_port()): - time.sleep(0.1) - return daemon - - -def register(signal, callback, uid=None, replace=False, reqcbk=None, - timeout=1000): - """ - Registers a callback to be called when a specific signal event is - received. - - Will timeout after timeout ms if response has not been received. The - timeout arg is only used for asynch requests. If a reqcbk callback has - been supplied the timeout arg is not used. The response value will be - returned for a synch request but nothing will be returned for an asynch - request. - - :param signal: the signal that causes the callback to be launched - :type signal: int (see the `events.proto` file) - :param callback: the callback to be called when the signal is received - :type callback: function - callback(leap.common.events.events_pb2.SignalRequest) - :param uid: a unique id for the callback - :type uid: int - :param replace: should an existent callback with same uid be replaced? - :type replace: bool - :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) - :param timeout: the timeout for synch calls - :type timeout: int - - Might raise a CallbackAlreadyRegistered exception if there's already a - callback identified by the given uid and replace is False. - - :return: the response from server for synch calls or nothing for asynch - calls. - :rtype: leap.common.events.events_pb2.EventsResponse or None - """ - ensure_component_daemon() # so we can receive registered signals - # register callback locally - if signal not in registered_callbacks: - registered_callbacks[signal] = [] - cbklist = registered_callbacks[signal] - if uid and filter(lambda (x, y): x == uid, cbklist): - if not replace: - raise CallbackAlreadyRegisteredException() - else: - registered_callbacks[signal] = filter(lambda(x, y): x != uid, - cbklist) - registered_callbacks[signal].append((uid, callback)) - # register callback on server - request = proto.RegisterRequest() - request.event = signal - request.port = EventsComponentDaemon.get_instance().get_port() - request.mac_method = mac_auth.MacMethod.MAC_NONE - request.mac = "" - service = RpcService(proto.EventsServerService_Stub, - server.SERVER_PORT, 'localhost') - logger.info( - "Sending registration request to server on port %s: %s", - server.SERVER_PORT, - str(request)[:40]) - return service.register(request, callback=reqcbk, timeout=timeout) - -def unregister(signal, uid=None, reqcbk=None, timeout=1000): - """ - Unregister a callback. - - If C{uid} is specified, unregisters only the callback identified by that - unique id. Otherwise, unregisters all callbacks - - :param signal: the signal that causes the callback to be launched - :type signal: int (see the `events.proto` file) - :param uid: a unique id for the callback - :type uid: int - :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) - :param timeout: the timeout for synch calls - :type timeout: int - - :return: the response from server for synch calls or nothing for asynch - calls or None if no callback is registered for that signal or uid. - :rtype: leap.common.events.events_pb2.EventsResponse or None - """ - if signal not in registered_callbacks or not registered_callbacks[signal]: - logger.warning("No callback registered for signal %d." % signal) - return None - # unregister callback locally - cbklist = registered_callbacks[signal] - if uid is not None: - if filter(lambda (cbkuid, _): cbkuid == uid, cbklist) == []: - logger.warning("No callback registered for uid %d." % st) - return None - registered_callbacks[signal] = filter(lambda(x, y): x != uid, cbklist) - else: - # exclude all callbacks for given signal - registered_callbacks[signal] = [] - # unregister port in server if there are no more callbacks for this signal - if not registered_callbacks[signal]: - request = proto.UnregisterRequest() - request.event = signal - request.port = EventsComponentDaemon.get_instance().get_port() - request.mac_method = mac_auth.MacMethod.MAC_NONE - request.mac = "" - service = RpcService(proto.EventsServerService_Stub, - server.SERVER_PORT, 'localhost') - logger.info( - "Sending unregistration request to server on port %s: %s", - server.SERVER_PORT, - str(request)[:40]) - return service.unregister(request, callback=reqcbk, timeout=timeout) - - -def signal(signal, content="", mac_method="", mac="", reqcbk=None, - timeout=1000): - """ - Send `signal` event to events server. - - Will timeout after timeout ms if response has not been received. The - timeout arg is only used for asynch requests. If a reqcbk callback has - been supplied the timeout arg is not used. The response value will be - returned for a synch request but nothing will be returned for an asynch - request. - - :param signal: the signal that causes the callback to be launched - :type signal: int (see the `events.proto` file) - :param content: the contents of the event signal - :type content: str - :param mac_method: the method used for auth mac - :type mac_method: str - :param mac: the content of the auth mac - :type mac: str - :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) - :param timeout: the timeout for synch calls - :type timeout: int - - :return: the response from server for synch calls or nothing for asynch - calls. - :rtype: leap.common.events.events_pb2.EventsResponse or None - """ - request = proto.SignalRequest() - request.event = signal - request.content = content - request.mac_method = mac_method - request.mac = mac - service = RpcService(proto.EventsServerService_Stub, server.SERVER_PORT, - 'localhost') - logger.info("Sending signal to server: %s", str(request)[:40]) - return service.signal(request, callback=reqcbk, timeout=timeout) - - -class EventsComponentService(proto.EventsComponentService): - """ - Service for receiving signal events in components. - """ - - def __init__(self): - proto.EventsComponentService.__init__(self) - - def signal(self, controller, request, done): - """ - Receive a signal and run callbacks registered for that signal. - - This method is called whenever a signal request is received from - server. - - :param controller: used to mediate a single method call - :type controller: protobuf.socketrpc.controller.SocketRpcController - :param request: the request received from the component - :type request: leap.common.events.events_pb2.SignalRequest - :param done: callback to be called when done - :type done: protobuf.socketrpc.server.Callback - """ - logger.info('Received signal from server: %s...' % str(request)[:40]) - - # run registered callbacks - # TODO: verify authentication using mac in incoming message - if request.event in registered_callbacks: - for (_, cbk) in registered_callbacks[request.event]: - # callbacks should be prepared to receive a - # events_pb2.SignalRequest. - cbk(request) - - # send response back to server - response = proto.EventResponse() - response.status = proto.EventResponse.OK - done.run(response) - - -class EventsComponentDaemon(daemon.EventsSingletonDaemon): - """ - A daemon that listens for incoming events from server. - """ - - @classmethod - def ensure(cls, port): - """ - Make sure the daemon is running on the given port. - - :param port: the port in which the daemon should listen - :type port: int - - :return: a daemon instance - :rtype: EventsComponentDaemon - """ - return cls.ensure_service(port, EventsComponentService()) diff --git a/src/leap/common/events/daemon.py b/src/leap/common/events/daemon.py index c253948..c4a4189 100644 --- a/src/leap/common/events/daemon.py +++ b/src/leap/common/events/daemon.py @@ -43,7 +43,7 @@ class ServiceAlreadyRunningException(Exception): class EventsRpcServer(SocketRpcServer): """ - RPC server used in server and component interfaces to receive messages. + RPC server used in server and client interfaces to receive messages. """ def __init__(self, port, host='localhost'): diff --git a/src/leap/common/events/events.proto b/src/leap/common/events/events.proto index a813ed1..79a5564 100644 --- a/src/leap/common/events/events.proto +++ b/src/leap/common/events/events.proto @@ -74,6 +74,6 @@ service EventsServerService { rpc signal(SignalRequest) returns (EventResponse); } -service EventsComponentService { +service EventsClientService { rpc signal(SignalRequest) returns (EventResponse); } diff --git a/src/leap/common/events/events_pb2.py b/src/leap/common/events/events_pb2.py index 5b1c118..3b39950 100644 --- a/src/leap/common/events/events_pb2.py +++ b/src/leap/common/events/events_pb2.py @@ -14,7 +14,7 @@ from google.protobuf import descriptor_pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='events.proto', package='leap.common.events', - serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"l\n\x11UnregisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\x91\x02\n\x13\x45ventsServerService\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12V\n\nunregister\x12%.leap.common.events.UnregisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2h\n\x16\x45ventsComponentService\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') + serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"l\n\x11UnregisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\x91\x02\n\x13\x45ventsServerService\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12V\n\nunregister\x12%.leap.common.events.UnregisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2e\n\x13\x45ventsClientService\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') _EVENT = _descriptor.EnumDescriptor( name='Event', @@ -411,18 +411,18 @@ class EventsServerService_Stub(EventsServerService): DESCRIPTOR = _EVENTSSERVERSERVICE -_EVENTSCOMPONENTSERVICE = _descriptor.ServiceDescriptor( - name='EventsComponentService', - full_name='leap.common.events.EventsComponentService', +_EVENTSCLIENTSERVICE = _descriptor.ServiceDescriptor( + name='EventsClientService', + full_name='leap.common.events.EventsClientService', file=DESCRIPTOR, index=1, options=None, serialized_start=1179, - serialized_end=1283, + serialized_end=1280, methods=[ _descriptor.MethodDescriptor( name='signal', - full_name='leap.common.events.EventsComponentService.signal', + full_name='leap.common.events.EventsClientService.signal', index=0, containing_service=None, input_type=_SIGNALREQUEST, @@ -432,13 +432,13 @@ _EVENTSCOMPONENTSERVICE = _descriptor.ServiceDescriptor( ]) -class EventsComponentService(_service.Service): +class EventsClientService(_service.Service): __metaclass__ = service_reflection.GeneratedServiceType - DESCRIPTOR = _EVENTSCOMPONENTSERVICE + DESCRIPTOR = _EVENTSCLIENTSERVICE -class EventsComponentService_Stub(EventsComponentService): +class EventsClientService_Stub(EventsClientService): __metaclass__ = service_reflection.GeneratedServiceStubType - DESCRIPTOR = _EVENTSCOMPONENTSERVICE + DESCRIPTOR = _EVENTSCLIENTSERVICE # @@protoc_insertion_point(module_scope) diff --git a/src/leap/common/events/server.py b/src/leap/common/events/server.py index d53c218..8a0d4e5 100644 --- a/src/leap/common/events/server.py +++ b/src/leap/common/events/server.py @@ -17,12 +17,12 @@ """ A server for the events mechanism. -A server can receive different kinds of requests from components: +A server can receive different kinds of requests from clients: - 1. Registration request: store component port number to be notified when + 1. Registration request: store client port number to be notified when a specific signal arrives. - 2. Signal request: redistribute the signal to registered components. + 2. Signal request: redistribute the signal to registered clients. """ import logging import socket @@ -40,12 +40,12 @@ logger = logging.getLogger(__name__) SERVER_PORT = 8090 -# the `registered_components` dictionary below should have the following +# the `registered_clients` dictionary below should have the following # format: # # { event_signal: [ port, ... ], ... } # -registered_components = {} +registered_clients = {} def ensure_server(port=SERVER_PORT): @@ -74,26 +74,26 @@ def ensure_server(port=SERVER_PORT): class EventsServerService(proto.EventsServerService): """ - Service for receiving events in components. + Service for receiving events in clients. """ def register(self, controller, request, done): """ - Register a component port to be signaled when specific events come in. + Register a client port to be signaled when specific events come in. :param controller: used to mediate a single method call :type controller: protobuf.socketrpc.controller.SocketRpcController - :param request: the request received from the component + :param request: the request received from the client :type request: leap.common.events.events_pb2.RegisterRequest :param done: callback to be called when done :type done: protobuf.socketrpc.server.Callback """ logger.info("Received registration request: %s..." % str(request)[:40]) - # add component port to signal list - if request.event not in registered_components: - registered_components[request.event] = set([]) - registered_components[request.event].add(request.port) - # send response back to component + # add client port to signal list + if request.event not in registered_clients: + registered_clients[request.event] = set([]) + registered_clients[request.event].add(request.port) + # send response back to client logger.debug('sending response back') response = proto.EventResponse() @@ -102,56 +102,56 @@ class EventsServerService(proto.EventsServerService): def unregister(self, controller, request, done): """ - Unregister a component port so it will not be signaled when specific + Unregister a client port so it will not be signaled when specific events come in. :param controller: used to mediate a single method call :type controller: protobuf.socketrpc.controller.SocketRpcController - :param request: the request received from the component + :param request: the request received from the client :type request: leap.common.events.events_pb2.RegisterRequest :param done: callback to be called when done :type done: protobuf.socketrpc.server.Callback """ logger.info( "Received unregistration request: %s..." % str(request)[:40]) - # remove component port from signal list + # remove client port from signal list response = proto.EventResponse() - if request.event in registered_components: + if request.event in registered_clients: try: - registered_components[request.event].remove(request.port) + registered_clients[request.event].remove(request.port) response.status = proto.EventResponse.OK except KeyError: response.status = proto.EventsResponse.ERROR response.result = 'Port %d not registered.' % request.port - # send response back to component + # send response back to client logger.debug('sending response back') done.run(response) def signal(self, controller, request, done): """ - Perform an RPC call to signal all components registered to receive a + Perform an RPC call to signal all clients registered to receive a specific signal. :param controller: used to mediate a single method call :type controller: protobuf.socketrpc.controller.SocketRpcController - :param request: the request received from the component + :param request: the request received from the client :type request: leap.common.events.events_pb2.SignalRequest :param done: callback to be called when done :type done: protobuf.socketrpc.server.Callback """ - logger.info('Received signal from component: %s...', str(request)[:40]) - # send signal to all registered components + logger.info('Received signal from client: %s...', str(request)[:40]) + # send signal to all registered clients # TODO: verify signal auth - if request.event in registered_components: - for port in registered_components[request.event]: + if request.event in registered_clients: + for port in registered_clients[request.event]: def callback(req, resp): logger.info("Signal received by " + str(port)) - service = RpcService(proto.EventsComponentService_Stub, + service = RpcService(proto.EventsClientService_Stub, port, 'localhost') service.signal(request, callback=callback) - # send response back to component + # send response back to client response = proto.EventResponse() response.status = proto.EventResponse.OK done.run(response) diff --git a/src/leap/common/tests/test_events.py b/src/leap/common/tests/test_events.py index 7286bdc..687195f 100644 --- a/src/leap/common/tests/test_events.py +++ b/src/leap/common/tests/test_events.py @@ -22,7 +22,7 @@ from protobuf.socketrpc import RpcService from leap.common import events from leap.common.events import ( server, - component, + client, mac_auth, ) from leap.common.events.events_pb2 import ( @@ -51,7 +51,7 @@ class EventsTestCase(unittest.TestCase): @classmethod def setUpClass(cls): server.EventsServerDaemon.ensure(8090) - cls.callbacks = events.component.registered_callbacks + cls.callbacks = events.client.registered_callbacks @classmethod def tearDownClass(cls): @@ -62,8 +62,8 @@ class EventsTestCase(unittest.TestCase): super(EventsTestCase, self).setUp() def tearDown(self): - #events.component.registered_callbacks = {} - server.registered_components = {} + #events.client.registered_callbacks = {} + server.registered_clients = {} super(EventsTestCase, self).tearDown() def test_service_singleton(self): @@ -76,24 +76,24 @@ class EventsTestCase(unittest.TestCase): self.assertEqual(service1, service2, "Can't get singleton class for service.") - def test_component_register(self): + def test_client_register(self): """ - Ensure components can register callbacks. + Ensure clients can register callbacks. """ self.assertTrue(1 not in self.callbacks, 'There should should be no callback for this signal.') events.register(1, lambda x: True) self.assertTrue(1 in self.callbacks, - 'Could not register signal in local component.') + 'Could not register signal in local client.') events.register(2, lambda x: True) self.assertTrue(1 in self.callbacks, - 'Could not register signal in local component.') + 'Could not register signal in local client.') self.assertTrue(2 in self.callbacks, - 'Could not register signal in local component.') + 'Could not register signal in local client.') def test_register_signal_replace(self): """ - Make sure components can replace already registered callbacks. + Make sure clients can replace already registered callbacks. """ sig = 3 cbk = lambda x: True @@ -134,7 +134,7 @@ class EventsTestCase(unittest.TestCase): def test_events_server_service_register(self): """ - Ensure the server can register components to be signaled. + Ensure the server can register clients to be signaled. """ sig = 5 request = RegisterRequest() @@ -143,34 +143,34 @@ class EventsTestCase(unittest.TestCase): request.mac_method = mac_auth.MacMethod.MAC_NONE request.mac = "" service = RpcService(EventsServerService_Stub, port, 'localhost') - complist = server.registered_components + complist = server.registered_clients self.assertEqual({}, complist, 'There should be no registered_ports when ' 'server has just been created.') response = service.register(request, timeout=1000) self.assertTrue(sig in complist, "Signal not registered succesfully.") self.assertTrue(8091 in complist[sig], - 'Failed registering component port.') + 'Failed registering client port.') - def test_component_request_register(self): + def test_client_request_register(self): """ - Ensure components can register themselves with server. + Ensure clients can register themselves with server. """ sig = 6 - complist = server.registered_components + complist = server.registered_clients self.assertTrue(sig not in complist, - 'There should be no registered components for this ' + 'There should be no registered clients for this ' 'signal.') events.register(sig, lambda x: True) time.sleep(0.1) - port = component.EventsComponentDaemon.get_instance().get_port() - self.assertTrue(sig in complist, 'Failed registering component.') + port = client.EventsClientDaemon.get_instance().get_port() + self.assertTrue(sig in complist, 'Failed registering client.') self.assertTrue(port in complist[sig], - 'Failed registering component port.') + 'Failed registering client port.') - def test_component_receives_signal(self): + def test_client_receives_signal(self): """ - Ensure components can receive signals. + Ensure clients can receive signals. """ sig = 7 @@ -190,44 +190,44 @@ class EventsTestCase(unittest.TestCase): time.sleep(0.5) self.assertTrue(received, 'Did not receive signal back.') - def test_component_send_signal(self): + def test_client_send_signal(self): """ - Ensure components can send signals. + Ensure clients can send signals. """ sig = 8 response = events.signal(sig) self.assertTrue(response.status == response.OK, 'Received wrong response status when signaling.') - def test_component_unregister_all(self): + def test_client_unregister_all(self): """ - Test that the component can unregister all events for one signal. + Test that the client can unregister all events for one signal. """ sig = CLIENT_UID - complist = server.registered_components + complist = server.registered_clients events.register(sig, lambda x: True) events.register(sig, lambda x: True) time.sleep(0.1) events.unregister(sig) time.sleep(0.1) - port = component.EventsComponentDaemon.get_instance().get_port() + port = client.EventsClientDaemon.get_instance().get_port() self.assertFalse(bool(complist[sig])) self.assertTrue(port not in complist[sig]) - def test_component_unregister_by_uid(self): + def test_client_unregister_by_uid(self): """ - Test that the component can unregister an event by uid. + Test that the client can unregister an event by uid. """ sig = CLIENT_UID - complist = server.registered_components + complist = server.registered_clients events.register(sig, lambda x: True, uid='cbkuid') events.register(sig, lambda x: True, uid='cbkuid2') time.sleep(0.1) events.unregister(sig, uid='cbkuid') time.sleep(0.1) - port = component.EventsComponentDaemon.get_instance().get_port() + port = client.EventsClientDaemon.get_instance().get_port() self.assertTrue(sig in complist) self.assertTrue(len(complist[sig]) == 1) self.assertTrue( - component.registered_callbacks[sig].pop()[0] == 'cbkuid2') + client.registered_callbacks[sig].pop()[0] == 'cbkuid2') self.assertTrue(port in complist[sig]) -- cgit v1.2.3 From b7c74e4f293d0e611ea038e04022fbe700a8cb42 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 24 Jul 2013 16:26:52 -0300 Subject: Trying to init events server raises when given port is not free. * Also fix and improve some tests. --- src/leap/common/events/__init__.py | 31 ++++++++ src/leap/common/events/client.py | 38 +++++++++ src/leap/common/events/events.proto | 34 ++++++++ src/leap/common/events/events_pb2.py | 77 ++++++++++++++---- src/leap/common/events/server.py | 60 +++++++++++++- src/leap/common/tests/test_events.py | 146 ++++++++++++++++++++++++++++++----- 6 files changed, 349 insertions(+), 37 deletions(-) diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py index d498340..388ee17 100644 --- a/src/leap/common/events/__init__.py +++ b/src/leap/common/events/__init__.py @@ -123,3 +123,34 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :rtype: leap.common.events.events_pb2.EventsResponse or None """ return client.signal(signal, content, mac_method, mac, reqcbk, timeout) + +def ping_client(port, reqcbk=None, timeout=1000): + """ + Ping a client running in C{port}. + + :param port: the port in which the client should be listening + :type port: int + :param reqcbk: a callback to be called when a response from client is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + """ + return client.ping(port, reqcbk=reqcbk, timeout=timeout) + + +def ping_server(port=server.SERVER_PORT, reqcbk=None, timeout=1000): + """ + Ping the server. + + :param port: the port in which server should be listening + :type port: int + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + """ + return server.ping(port, reqcbk=reqcbk, timeout=timeout) diff --git a/src/leap/common/events/client.py b/src/leap/common/events/client.py index 17fc326..587b02a 100644 --- a/src/leap/common/events/client.py +++ b/src/leap/common/events/client.py @@ -233,6 +233,28 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, return service.signal(request, callback=reqcbk, timeout=timeout) +def ping(port, reqcbk=None, timeout=1000): + """ + Ping a client running in C{port}. + + :param port: the port in which the client should be listening + :type port: int + :param reqcbk: a callback to be called when a response from client is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + """ + request = proto.PingRequest() + service = RpcService( + proto.EventsClientService_Stub, + port, + 'localhost') + logger.info("Pinging a client in port %d..." % port) + return service.ping(request, callback=reqcbk, timeout=timeout) + + class EventsClientService(proto.EventsClientService): """ Service for receiving signal events in clients. @@ -270,6 +292,22 @@ class EventsClientService(proto.EventsClientService): response.status = proto.EventResponse.OK done.run(response) + def ping(self, controller, request, done): + """ + Reply to a ping request. + + :param controller: used to mediate a single method call + :type controller: protobuf.socketrpc.controller.SocketRpcController + :param request: the request received from the client + :type request: leap.common.events.events_pb2.RegisterRequest + :param done: callback to be called when done + :type done: protobuf.socketrpc.server.Callback + """ + logger.info("Received ping request, sending response.") + response = proto.EventResponse() + response.status = proto.EventResponse.OK + done.run(response) + class EventsClientDaemon(daemon.EventsSingletonDaemon): """ diff --git a/src/leap/common/events/events.proto b/src/leap/common/events/events.proto index 79a5564..b844f42 100644 --- a/src/leap/common/events/events.proto +++ b/src/leap/common/events/events.proto @@ -17,6 +17,9 @@ package leap.common.events; option py_generic_services = true; + +// These are the events that can be signaled using the events mechanism. + enum Event { CLIENT_SESSION_ID = 1; CLIENT_UID = 2; @@ -33,6 +36,10 @@ enum Event { RAISE_WINDOW = 13; } + +// A SignalRequest is the type of the message sent from one component to request +// that a signal be sent to every registered component. + message SignalRequest { required Event event = 1; required string content = 2; @@ -42,6 +49,10 @@ message SignalRequest { optional bool error_occurred = 6; } + +// A RegisterRequest message tells the server that a component wants to +// be signaled whenever a specific event occurs. + message RegisterRequest { required Event event = 1; required int32 port = 2; @@ -49,6 +60,10 @@ message RegisterRequest { required bytes mac = 4; } + +// An UnregisterRequest message tells the server that a component does not +// want to be signaled when a specific event occurs. + message UnregisterRequest { required Event event = 1; required int32 port = 2; @@ -56,6 +71,17 @@ message UnregisterRequest { required bytes mac = 4; } + +// A PingRequest message is used to find out if a server or component is +// alive. + +message PingRequest { +} + + +// The EventResponse is the message sent back by server and components after +// they receive other kinds of requests. + message EventResponse { enum Status { @@ -68,12 +94,20 @@ message EventResponse { optional string result = 2; } + +// The EventsServerService is the service provided by the server. + service EventsServerService { + rpc ping(PingRequest) returns (EventResponse); rpc register(RegisterRequest) returns (EventResponse); rpc unregister(UnregisterRequest) returns (EventResponse); rpc signal(SignalRequest) returns (EventResponse); } + +// EventsComponentService is the service provided by components (clients). + service EventsClientService { + rpc ping(PingRequest) returns (EventResponse); rpc signal(SignalRequest) returns (EventResponse); } diff --git a/src/leap/common/events/events_pb2.py b/src/leap/common/events/events_pb2.py index 3b39950..274514c 100644 --- a/src/leap/common/events/events_pb2.py +++ b/src/leap/common/events/events_pb2.py @@ -14,7 +14,7 @@ from google.protobuf import descriptor_pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='events.proto', package='leap.common.events', - serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"l\n\x11UnregisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\x91\x02\n\x13\x45ventsServerService\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12V\n\nunregister\x12%.leap.common.events.UnregisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2e\n\x13\x45ventsClientService\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') + serialized_pb='\n\x0c\x65vents.proto\x12\x12leap.common.events\"\x97\x01\n\rSignalRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0f\n\x07\x63ontent\x18\x02 \x02(\t\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\x12\x12\n\nenc_method\x18\x05 \x01(\t\x12\x16\n\x0e\x65rror_occurred\x18\x06 \x01(\x08\"j\n\x0fRegisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"l\n\x11UnregisterRequest\x12(\n\x05\x65vent\x18\x01 \x02(\x0e\x32\x19.leap.common.events.Event\x12\x0c\n\x04port\x18\x02 \x02(\x05\x12\x12\n\nmac_method\x18\x03 \x02(\t\x12\x0b\n\x03mac\x18\x04 \x02(\x0c\"\r\n\x0bPingRequest\"\x82\x01\n\rEventResponse\x12\x38\n\x06status\x18\x01 \x02(\x0e\x32(.leap.common.events.EventResponse.Status\x12\x0e\n\x06result\x18\x02 \x01(\t\"\'\n\x06Status\x12\x06\n\x02OK\x10\x01\x12\n\n\x06UNAUTH\x10\x02\x12\t\n\x05\x45RROR\x10\x03*\xe7\x02\n\x05\x45vent\x12\x15\n\x11\x43LIENT_SESSION_ID\x10\x01\x12\x0e\n\nCLIENT_UID\x10\x02\x12\x19\n\x15SOLEDAD_CREATING_KEYS\x10\x03\x12\x1e\n\x1aSOLEDAD_DONE_CREATING_KEYS\x10\x04\x12\x1a\n\x16SOLEDAD_UPLOADING_KEYS\x10\x05\x12\x1f\n\x1bSOLEDAD_DONE_UPLOADING_KEYS\x10\x06\x12\x1c\n\x18SOLEDAD_DOWNLOADING_KEYS\x10\x07\x12!\n\x1dSOLEDAD_DONE_DOWNLOADING_KEYS\x10\x08\x12\x1c\n\x18SOLEDAD_NEW_DATA_TO_SYNC\x10\t\x12\x1a\n\x16SOLEDAD_DONE_DATA_SYNC\x10\n\x12\x17\n\x13UPDATER_NEW_UPDATES\x10\x0b\x12\x19\n\x15UPDATER_DONE_UPDATING\x10\x0c\x12\x10\n\x0cRAISE_WINDOW\x10\r2\xdd\x02\n\x13\x45ventsServerService\x12J\n\x04ping\x12\x1f.leap.common.events.PingRequest\x1a!.leap.common.events.EventResponse\x12R\n\x08register\x12#.leap.common.events.RegisterRequest\x1a!.leap.common.events.EventResponse\x12V\n\nunregister\x12%.leap.common.events.UnregisterRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponse2\xb1\x01\n\x13\x45ventsClientService\x12J\n\x04ping\x12\x1f.leap.common.events.PingRequest\x1a!.leap.common.events.EventResponse\x12N\n\x06signal\x12!.leap.common.events.SignalRequest\x1a!.leap.common.events.EventResponseB\x03\x90\x01\x01') _EVENT = _descriptor.EnumDescriptor( name='Event', @@ -77,8 +77,8 @@ _EVENT = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=542, - serialized_end=901, + serialized_start=557, + serialized_end=916, ) Event = enum_type_wrapper.EnumTypeWrapper(_EVENT) @@ -118,8 +118,8 @@ _EVENTRESPONSE_STATUS = _descriptor.EnumDescriptor( ], containing_type=None, options=None, - serialized_start=500, - serialized_end=539, + serialized_start=515, + serialized_end=554, ) @@ -284,6 +284,27 @@ _UNREGISTERREQUEST = _descriptor.Descriptor( ) +_PINGREQUEST = _descriptor.Descriptor( + name='PingRequest', + full_name='leap.common.events.PingRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + serialized_start=408, + serialized_end=421, +) + + _EVENTRESPONSE = _descriptor.Descriptor( name='EventResponse', full_name='leap.common.events.EventResponse', @@ -315,8 +336,8 @@ _EVENTRESPONSE = _descriptor.Descriptor( options=None, is_extendable=False, extension_ranges=[], - serialized_start=409, - serialized_end=539, + serialized_start=424, + serialized_end=554, ) _SIGNALREQUEST.fields_by_name['event'].enum_type = _EVENT @@ -327,6 +348,7 @@ _EVENTRESPONSE_STATUS.containing_type = _EVENTRESPONSE DESCRIPTOR.message_types_by_name['SignalRequest'] = _SIGNALREQUEST DESCRIPTOR.message_types_by_name['RegisterRequest'] = _REGISTERREQUEST DESCRIPTOR.message_types_by_name['UnregisterRequest'] = _UNREGISTERREQUEST +DESCRIPTOR.message_types_by_name['PingRequest'] = _PINGREQUEST DESCRIPTOR.message_types_by_name['EventResponse'] = _EVENTRESPONSE @@ -351,6 +373,13 @@ class UnregisterRequest(_message.Message): # @@protoc_insertion_point(class_scope:leap.common.events.UnregisterRequest) +class PingRequest(_message.Message): + __metaclass__ = _reflection.GeneratedProtocolMessageType + DESCRIPTOR = _PINGREQUEST + + # @@protoc_insertion_point(class_scope:leap.common.events.PingRequest) + + class EventResponse(_message.Message): __metaclass__ = _reflection.GeneratedProtocolMessageType DESCRIPTOR = _EVENTRESPONSE @@ -368,13 +397,22 @@ _EVENTSSERVERSERVICE = _descriptor.ServiceDescriptor( file=DESCRIPTOR, index=0, options=None, - serialized_start=904, - serialized_end=1177, + serialized_start=919, + serialized_end=1268, methods=[ + _descriptor.MethodDescriptor( + name='ping', + full_name='leap.common.events.EventsServerService.ping', + index=0, + containing_service=None, + input_type=_PINGREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), _descriptor.MethodDescriptor( name='register', full_name='leap.common.events.EventsServerService.register', - index=0, + index=1, containing_service=None, input_type=_REGISTERREQUEST, output_type=_EVENTRESPONSE, @@ -383,7 +421,7 @@ _EVENTSSERVERSERVICE = _descriptor.ServiceDescriptor( _descriptor.MethodDescriptor( name='unregister', full_name='leap.common.events.EventsServerService.unregister', - index=1, + index=2, containing_service=None, input_type=_UNREGISTERREQUEST, output_type=_EVENTRESPONSE, @@ -392,7 +430,7 @@ _EVENTSSERVERSERVICE = _descriptor.ServiceDescriptor( _descriptor.MethodDescriptor( name='signal', full_name='leap.common.events.EventsServerService.signal', - index=2, + index=3, containing_service=None, input_type=_SIGNALREQUEST, output_type=_EVENTRESPONSE, @@ -417,13 +455,22 @@ _EVENTSCLIENTSERVICE = _descriptor.ServiceDescriptor( file=DESCRIPTOR, index=1, options=None, - serialized_start=1179, - serialized_end=1280, + serialized_start=1271, + serialized_end=1448, methods=[ + _descriptor.MethodDescriptor( + name='ping', + full_name='leap.common.events.EventsClientService.ping', + index=0, + containing_service=None, + input_type=_PINGREQUEST, + output_type=_EVENTRESPONSE, + options=None, + ), _descriptor.MethodDescriptor( name='signal', full_name='leap.common.events.EventsClientService.signal', - index=0, + index=1, containing_service=None, input_type=_SIGNALREQUEST, output_type=_EVENTRESPONSE, diff --git a/src/leap/common/events/server.py b/src/leap/common/events/server.py index 8a0d4e5..daccc61 100644 --- a/src/leap/common/events/server.py +++ b/src/leap/common/events/server.py @@ -48,6 +48,13 @@ SERVER_PORT = 8090 registered_clients = {} +class PortAlreadyTaken(Exception): + """ + Raised when trying to open a server in a port that is already taken. + """ + pass + + def ensure_server(port=SERVER_PORT): """ Make sure the server is running on the given port. @@ -60,18 +67,51 @@ def ensure_server(port=SERVER_PORT): :return: the daemon instance or nothing :rtype: EventsServerDaemon or None + + :raise PortAlreadyTaken: Raised if C{port} is already taken by something + that is not an events server. """ try: + # check if port is available s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', port)) s.close() - logger.info('Server is already running on port %d.', port) - return None + # port is taken, check if there's a server running there + response = ping(port) + if response is not None and response.status == proto.EventResponse.OK: + logger.info('A server is already running on port %d.', port) + return None + # port is taken, and not by an events server + logger.info('Port %d is taken by something not an events server.', port) + raise PortAlreadyTaken(port) except socket.error: + # port is available, run a server logger.info('Launching server on port %d.', port) return EventsServerDaemon.ensure(port) +def ping(port=SERVER_PORT, reqcbk=None, timeout=1000): + """ + Ping the server. + + :param port: the port in which server should be listening + :type port: int + :param reqcbk: a callback to be called when a response from server is + received + :type reqcbk: function + callback(leap.common.events.events_pb2.EventResponse) + :param timeout: the timeout for synch calls + :type timeout: int + """ + request = proto.PingRequest() + service = RpcService( + proto.EventsServerService_Stub, + port, + 'localhost') + logger.info("Pinging server in port %d..." % port) + return service.ping(request, callback=reqcbk, timeout=timeout) + + class EventsServerService(proto.EventsServerService): """ Service for receiving events in clients. @@ -156,6 +196,22 @@ class EventsServerService(proto.EventsServerService): response.status = proto.EventResponse.OK done.run(response) + def ping(self, controller, request, done): + """ + Reply to a ping request. + + :param controller: used to mediate a single method call + :type controller: protobuf.socketrpc.controller.SocketRpcController + :param request: the request received from the client + :type request: leap.common.events.events_pb2.RegisterRequest + :param done: callback to be called when done + :type done: protobuf.socketrpc.server.Callback + """ + logger.info("Received ping request, sending response.") + response = proto.EventResponse() + response.status = proto.EventResponse.OK + done.run(response) + class EventsServerDaemon(daemon.EventsSingletonDaemon): """ diff --git a/src/leap/common/tests/test_events.py b/src/leap/common/tests/test_events.py index 687195f..90124b4 100644 --- a/src/leap/common/tests/test_events.py +++ b/src/leap/common/tests/test_events.py @@ -18,6 +18,12 @@ import unittest import sets import time +import socket +import threading +import random + + +from mock import Mock from protobuf.socketrpc import RpcService from leap.common import events from leap.common.events import ( @@ -28,9 +34,11 @@ from leap.common.events import ( from leap.common.events.events_pb2 import ( EventsServerService, EventsServerService_Stub, + EventsClientService_Stub, EventResponse, SignalRequest, RegisterRequest, + PingRequest, SOLEDAD_CREATING_KEYS, CLIENT_UID, ) @@ -39,11 +47,6 @@ from leap.common.events.events_pb2 import ( port = 8090 received = False -local_callback_executed = False - - -def callback(request, reponse): - return True class EventsTestCase(unittest.TestCase): @@ -120,17 +123,28 @@ class EventsTestCase(unittest.TestCase): response = service.signal(request, timeout=1000) self.assertEqual(EventResponse.OK, response.status, 'Wrong response status.') - # test asynch - def local_callback(request, response): - global local_callback_executed - local_callback_executed = True + def test_signal_executes_callback(self): + """ + Ensure callback is executed upon receiving signal. + """ + sig = CLIENT_UID + request = SignalRequest() + request.event = sig + request.content = 'my signal contents' + request.mac_method = mac_auth.MacMethod.MAC_NONE + request.mac = "" + service = RpcService(EventsServerService_Stub, port, 'localhost') - events.register(sig, local_callback) - service.signal(request, callback=local_callback) - time.sleep(0.1) - self.assertTrue(local_callback_executed, - 'Local callback did not execute.') + # register a callback + flag = Mock() + events.register(sig, lambda req: flag(req.event)) + # signal + response = service.signal(request) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + time.sleep(1) # wait for signal to arrive + flag.assert_called_once_with(sig) def test_events_server_service_register(self): """ @@ -173,12 +187,9 @@ class EventsTestCase(unittest.TestCase): Ensure clients can receive signals. """ sig = 7 + flag = Mock() - def getsig(param=None): - global received - received = True - - events.register(sig, getsig) + events.register(sig, lambda req: flag(req.event)) request = SignalRequest() request.event = sig request.content = "" @@ -188,7 +199,7 @@ class EventsTestCase(unittest.TestCase): response = service.signal(request, timeout=1000) self.assertTrue(response is not None, 'Did not receive response.') time.sleep(0.5) - self.assertTrue(received, 'Did not receive signal back.') + flag.assert_called_once_with(sig) def test_client_send_signal(self): """ @@ -231,3 +242,98 @@ class EventsTestCase(unittest.TestCase): self.assertTrue( client.registered_callbacks[sig].pop()[0] == 'cbkuid2') self.assertTrue(port in complist[sig]) + + def test_server_replies_ping(self): + """ + Ensure server replies to a ping. + """ + request = PingRequest() + service = RpcService(EventsServerService_Stub, port, 'localhost') + response = service.ping(request, timeout=1000) + self.assertIsNotNone(response) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_client_replies_ping(self): + """ + Ensure clients reply to a ping. + """ + daemon = client.ensure_client_daemon() + port = daemon.get_port() + request = PingRequest() + service = RpcService(EventsClientService_Stub, port, 'localhost') + response = service.ping(request, timeout=1000) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_server_ping(self): + """ + Ensure the function from server module pings correctly. + """ + response = server.ping() + self.assertIsNotNone(response) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_client_ping(self): + """ + Ensure the function from client module pings correctly. + """ + daemon = client.ensure_client_daemon() + response = client.ping(daemon.get_port()) + self.assertIsNotNone(response) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_module_ping_server(self): + """ + Ensure the function from main module pings server correctly. + """ + response = events.ping_server() + self.assertIsNotNone(response) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_module_ping_client(self): + """ + Ensure the function from main module pings clients correctly. + """ + daemon = client.ensure_client_daemon() + response = events.ping_client(daemon.get_port()) + self.assertIsNotNone(response) + self.assertEqual(EventResponse.OK, response.status, + 'Wrong response status.') + + def test_ensure_server_raises_if_port_taken(self): + """ + Verify that server raises an exception if port is already taken. + """ + # get a random free port + while True: + port = random.randint(1024, 65535) + try: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('localhost', port)) + s.close() + except: + break + + class PortBlocker(threading.Thread): + + def run(self): + conns = 0 + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind(('localhost', port)) + s.setblocking(1) + s.listen(1) + while conns < 2: # blocks until rece + conns += 1 + s.accept() + s.close() + + # block the port + taker = PortBlocker() + taker.start() + time.sleep(1) # wait for thread to start. + self.assertRaises( + server.PortAlreadyTaken, server.ensure_server, port) -- cgit v1.2.3 From e7fa419f13e0afbb3f2653a4b0d8330dd45bbfd0 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 24 Jul 2013 17:51:03 -0300 Subject: Add doc and tests about events sync/async behaviour. * Also fix docstrings identation so sphynx doesn't complain. --- src/leap/common/events/__init__.py | 82 +++++++++++++++++++++++++-------- src/leap/common/events/client.py | 34 +++++++------- src/leap/common/events/server.py | 11 +++-- src/leap/common/tests/test_events.py | 89 ++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 39 deletions(-) diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py index 388ee17..a6fe7c3 100644 --- a/src/leap/common/events/__init__.py +++ b/src/leap/common/events/__init__.py @@ -16,7 +16,58 @@ # along with this program. If not, see . """ -An events mechanism that allows for signaling of events between clients. +This is an events mechanism that uses a server to allow for signaling of +events between clients. + +Application components should use the interface available in this file to +register callbacks to be executed upon receiving specific signals, and to send +signals to other components. + +To register a callback to be executed when a specific event is signaled, use +leap.common.events.register(): + +>>> from leap.common.events import register +>>> from leap.common.events.proto import CLIENT_UID +>>> register(CLIENT_UID, lambda req: do_something(req)) + +To signal an event, use leap.common.events.signal(): + +>>> from leap.common.events import signal +>>> from leap.common.events.proto import CLIENT_UID +>>> signal(CLIENT_UID) + + +NOTE ABOUT SYNC/ASYNC REQUESTS: + +Clients always communicate with the server, and never between themselves. +When a client registers a callback for an event, the callback is saved locally +in the client and the server stores the client socket port in a list +associated with that event. When a client signals an event, the server +forwards the signal to all registered client ports, and then each client +executes its callbacks associated with that event locally. + +Each RPC call from a client to the server is followed by a response from the +server to the client. Calls to register() and signal() (and all other RPC +calls) can be synchronous or asynchronous meaning if they will or not wait for +the server's response before returning. + +This mechanism was built on top of protobuf.socketrpc, and because of this RPC +calls are made synchronous or asynchronous in the following way: + + * If RPC calls receive a parameter called `reqcbk`, then the call is made + asynchronous. That means that: + + - an eventual `timeout` parameter is not used, + - the call returns immediatelly with value None, and + - the `reqcbk` callback is executed asynchronously upon the arrival of + a response from the server. + + * Otherwise, if the `reqcbk` parameter is None, then the call is made in a + synchronous manner: + + - if a response from server arrives within `timeout` milliseconds, the + RPC call returns it; + - otherwise, the call returns None. """ import logging @@ -54,9 +105,8 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, :param replace: should an existent callback with same uid be replaced? :type replace: bool :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -79,14 +129,13 @@ def unregister(signal, uid=None, reqcbk=None, timeout=1000): :param uid: a unique id for the callback :type uid: int :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls. + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ return client.unregister(signal, uid, reqcbk, timeout) @@ -112,14 +161,13 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :param mac: the content of the auth mac :type mac: str :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls. + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ return client.signal(signal, content, mac_method, mac, reqcbk, timeout) @@ -131,9 +179,8 @@ def ping_client(port, reqcbk=None, timeout=1000): :param port: the port in which the client should be listening :type port: int :param reqcbk: a callback to be called when a response from client is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int """ @@ -147,9 +194,8 @@ def ping_server(port=server.SERVER_PORT, reqcbk=None, timeout=1000): :param port: the port in which server should be listening :type port: int :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int """ diff --git a/src/leap/common/events/client.py b/src/leap/common/events/client.py index 587b02a..55f14ab 100644 --- a/src/leap/common/events/client.py +++ b/src/leap/common/events/client.py @@ -95,16 +95,14 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, :param signal: the signal that causes the callback to be launched :type signal: int (see the `events.proto` file) :param callback: the callback to be called when the signal is received - :type callback: function - callback(leap.common.events.events_pb2.SignalRequest) + :type callback: function(leap.common.events.events_pb2.SignalRequest) :param uid: a unique id for the callback :type uid: int :param replace: should an existent callback with same uid be replaced? :type replace: bool :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -112,7 +110,7 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, callback identified by the given uid and replace is False. :return: the response from server for synch calls or nothing for asynch - calls. + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ ensure_client_daemon() # so we can receive registered signals @@ -153,14 +151,14 @@ def unregister(signal, uid=None, reqcbk=None, timeout=1000): :param uid: a unique id for the callback :type uid: int :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls or None if no callback is registered for that signal or uid. + calls or None if no callback is registered for that signal or + uid. :rtype: leap.common.events.events_pb2.EventsResponse or None """ if signal not in registered_callbacks or not registered_callbacks[signal]: @@ -212,14 +210,13 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :param mac: the content of the auth mac :type mac: str :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int :return: the response from server for synch calls or nothing for asynch - calls. + calls. :rtype: leap.common.events.events_pb2.EventsResponse or None """ request = proto.SignalRequest() @@ -240,11 +237,14 @@ def ping(port, reqcbk=None, timeout=1000): :param port: the port in which the client should be listening :type port: int :param reqcbk: a callback to be called when a response from client is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int + + :return: the response from client for synch calls or nothing for asynch + calls. + :rtype: leap.common.events.events_pb2.EventsResponse or None """ request = proto.PingRequest() service = RpcService( diff --git a/src/leap/common/events/server.py b/src/leap/common/events/server.py index daccc61..a7d4da9 100644 --- a/src/leap/common/events/server.py +++ b/src/leap/common/events/server.py @@ -69,7 +69,7 @@ def ensure_server(port=SERVER_PORT): :rtype: EventsServerDaemon or None :raise PortAlreadyTaken: Raised if C{port} is already taken by something - that is not an events server. + that is not an events server. """ try: # check if port is available @@ -97,11 +97,14 @@ def ping(port=SERVER_PORT, reqcbk=None, timeout=1000): :param port: the port in which server should be listening :type port: int :param reqcbk: a callback to be called when a response from server is - received - :type reqcbk: function - callback(leap.common.events.events_pb2.EventResponse) + received + :type reqcbk: function(leap.common.events.events_pb2.EventResponse) :param timeout: the timeout for synch calls :type timeout: int + + :return: the response from server for synch calls or nothing for asynch + calls. + :rtype: leap.common.events.events_pb2.EventsResponse or None """ request = proto.PingRequest() service = RpcService( diff --git a/src/leap/common/tests/test_events.py b/src/leap/common/tests/test_events.py index 90124b4..bc04dd6 100644 --- a/src/leap/common/tests/test_events.py +++ b/src/leap/common/tests/test_events.py @@ -337,3 +337,92 @@ class EventsTestCase(unittest.TestCase): time.sleep(1) # wait for thread to start. self.assertRaises( server.PortAlreadyTaken, server.ensure_server, port) + + def test_async_register(self): + """ + Test asynchronous registering of callbacks. + """ + flag = Mock() + + # executed after async register, when response is received from server + def reqcbk(request, response): + flag(request.event) + + # callback registered by application + def callback(request): + pass + + # passing a callback as reqcbk param makes the call asynchronous + result = events.register(CLIENT_UID, callback, reqcbk=reqcbk) + self.assertIsNone(result) + events.signal(CLIENT_UID) + time.sleep(1) # wait for signal to arrive from server + flag.assert_called_once_with(CLIENT_UID) + + def test_async_signal(self): + """ + Test asynchronous registering of callbacks. + """ + flag = Mock() + + # executed after async signal, when response is received from server + def reqcbk(request, response): + flag(request.event) + + # passing a callback as reqcbk param makes the call asynchronous + result = events.signal(CLIENT_UID, reqcbk=reqcbk) + self.assertIsNone(result) + time.sleep(1) # wait for signal to arrive from server + flag.assert_called_once_with(CLIENT_UID) + + def test_async_unregister(self): + """ + Test asynchronous unregistering of callbacks. + """ + flag = Mock() + + # executed after async signal, when response is received from server + def reqcbk(request, response): + flag(request.event) + + # callback registered by application + def callback(request): + pass + + # passing a callback as reqcbk param makes the call asynchronous + events.register(CLIENT_UID, callback) + result = events.unregister(CLIENT_UID, reqcbk=reqcbk) + self.assertIsNone(result) + time.sleep(1) # wait for signal to arrive from server + flag.assert_called_once_with(CLIENT_UID) + + def test_async_ping_server(self): + """ + Test asynchronous pinging of server. + """ + flag = Mock() + + # executed after async signal, when response is received from server + def reqcbk(request, response): + flag() + + result = events.ping_server(reqcbk=reqcbk) + self.assertIsNone(result) + time.sleep(1) # wait for response to arrive from server. + flag.assert_called_once_with() + + def test_async_ping_client(self): + """ + Test asynchronous pinging of client. + """ + flag = Mock() + + # executed after async signal, when response is received from server + def reqcbk(request, response): + flag() + + daemon = client.ensure_client_daemon() + result = events.ping_client(daemon.get_port(), reqcbk=reqcbk) + self.assertIsNone(result) + time.sleep(1) # wait for response to arrive from server. + flag.assert_called_once_with() -- cgit v1.2.3 From 7747b4c28c4d9ed596e72061f34261d6158efe17 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 25 Jul 2013 11:02:18 -0300 Subject: Add leap_check helper method, #3007 related issue. --- changes/feature_add-leap-check | 1 + src/leap/common/check.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 changes/feature_add-leap-check diff --git a/changes/feature_add-leap-check b/changes/feature_add-leap-check new file mode 100644 index 0000000..5906c03 --- /dev/null +++ b/changes/feature_add-leap-check @@ -0,0 +1 @@ + o Add leap_check helper method, to use whenever leap_assert does not apply. Related to #3007. diff --git a/src/leap/common/check.py b/src/leap/common/check.py index e6b0b52..82da5ff 100644 --- a/src/leap/common/check.py +++ b/src/leap/common/check.py @@ -60,3 +60,20 @@ def leap_assert_type(var, expectedType): leap_assert(isinstance(var, expectedType), "Expected type %r instead of %r" % (expectedType, type(var))) + + +def leap_check(condition, message="", exception=Exception): + """ + Asserts the condition and displays the message if that's not + met. It also logs the error and its backtrace. + + :param condition: condition to check + :type condition: bool + :param message: message to display if the condition isn't met + :type message: str + :param exception: the exception to raise in case of condition being false. + :type exception: Exception + """ + if not condition: + logger.error(message) + raise exception(message) -- cgit v1.2.3 From dcb71ea078a7f56f76bf84b352656cdfa252d677 Mon Sep 17 00:00:00 2001 From: drebs Date: Thu, 25 Jul 2013 15:20:33 -0300 Subject: Fix events doc about reqcbk signature. Closes #3261 --- src/leap/common/events/__init__.py | 8 ++++---- src/leap/common/events/client.py | 8 ++++---- src/leap/common/events/server.py | 2 +- src/leap/common/tests/test_events.py | 20 ++++++++++---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/leap/common/events/__init__.py b/src/leap/common/events/__init__.py index a6fe7c3..6eaf3d4 100644 --- a/src/leap/common/events/__init__.py +++ b/src/leap/common/events/__init__.py @@ -130,7 +130,7 @@ def unregister(signal, uid=None, reqcbk=None, timeout=1000): :type uid: int :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.UnregisterRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -162,7 +162,7 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :type mac: str :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.SignalRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -180,7 +180,7 @@ def ping_client(port, reqcbk=None, timeout=1000): :type port: int :param reqcbk: a callback to be called when a response from client is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.PingRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int """ @@ -195,7 +195,7 @@ def ping_server(port=server.SERVER_PORT, reqcbk=None, timeout=1000): :type port: int :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.PingRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int """ diff --git a/src/leap/common/events/client.py b/src/leap/common/events/client.py index 55f14ab..4ae9bff 100644 --- a/src/leap/common/events/client.py +++ b/src/leap/common/events/client.py @@ -102,7 +102,7 @@ def register(signal, callback, uid=None, replace=False, reqcbk=None, :type replace: bool :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.RegisterRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -152,7 +152,7 @@ def unregister(signal, uid=None, reqcbk=None, timeout=1000): :type uid: int :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.UnregisterRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -211,7 +211,7 @@ def signal(signal, content="", mac_method="", mac="", reqcbk=None, :type mac: str :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.SignalRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int @@ -238,7 +238,7 @@ def ping(port, reqcbk=None, timeout=1000): :type port: int :param reqcbk: a callback to be called when a response from client is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.PingRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int diff --git a/src/leap/common/events/server.py b/src/leap/common/events/server.py index a7d4da9..59f3454 100644 --- a/src/leap/common/events/server.py +++ b/src/leap/common/events/server.py @@ -98,7 +98,7 @@ def ping(port=SERVER_PORT, reqcbk=None, timeout=1000): :type port: int :param reqcbk: a callback to be called when a response from server is received - :type reqcbk: function(leap.common.events.events_pb2.EventResponse) + :type reqcbk: function(proto.PingRequest, proto.EventResponse) :param timeout: the timeout for synch calls :type timeout: int diff --git a/src/leap/common/tests/test_events.py b/src/leap/common/tests/test_events.py index bc04dd6..0779b2e 100644 --- a/src/leap/common/tests/test_events.py +++ b/src/leap/common/tests/test_events.py @@ -346,7 +346,7 @@ class EventsTestCase(unittest.TestCase): # executed after async register, when response is received from server def reqcbk(request, response): - flag(request.event) + flag(request.event, response.status) # callback registered by application def callback(request): @@ -357,7 +357,7 @@ class EventsTestCase(unittest.TestCase): self.assertIsNone(result) events.signal(CLIENT_UID) time.sleep(1) # wait for signal to arrive from server - flag.assert_called_once_with(CLIENT_UID) + flag.assert_called_once_with(CLIENT_UID, EventResponse.OK) def test_async_signal(self): """ @@ -367,13 +367,13 @@ class EventsTestCase(unittest.TestCase): # executed after async signal, when response is received from server def reqcbk(request, response): - flag(request.event) + flag(request.event, response.status) # passing a callback as reqcbk param makes the call asynchronous result = events.signal(CLIENT_UID, reqcbk=reqcbk) self.assertIsNone(result) time.sleep(1) # wait for signal to arrive from server - flag.assert_called_once_with(CLIENT_UID) + flag.assert_called_once_with(CLIENT_UID, EventResponse.OK) def test_async_unregister(self): """ @@ -383,7 +383,7 @@ class EventsTestCase(unittest.TestCase): # executed after async signal, when response is received from server def reqcbk(request, response): - flag(request.event) + flag(request.event, response.status) # callback registered by application def callback(request): @@ -394,7 +394,7 @@ class EventsTestCase(unittest.TestCase): result = events.unregister(CLIENT_UID, reqcbk=reqcbk) self.assertIsNone(result) time.sleep(1) # wait for signal to arrive from server - flag.assert_called_once_with(CLIENT_UID) + flag.assert_called_once_with(CLIENT_UID, EventResponse.OK) def test_async_ping_server(self): """ @@ -404,12 +404,12 @@ class EventsTestCase(unittest.TestCase): # executed after async signal, when response is received from server def reqcbk(request, response): - flag() + flag(response.status) result = events.ping_server(reqcbk=reqcbk) self.assertIsNone(result) time.sleep(1) # wait for response to arrive from server. - flag.assert_called_once_with() + flag.assert_called_once_with(EventResponse.OK) def test_async_ping_client(self): """ @@ -419,10 +419,10 @@ class EventsTestCase(unittest.TestCase): # executed after async signal, when response is received from server def reqcbk(request, response): - flag() + flag(response.status) daemon = client.ensure_client_daemon() result = events.ping_client(daemon.get_port(), reqcbk=reqcbk) self.assertIsNone(result) time.sleep(1) # wait for response to arrive from server. - flag.assert_called_once_with() + flag.assert_called_once_with(EventResponse.OK) -- cgit v1.2.3 From f6478550641fdd46eeef417e8c9b438a86b68511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 26 Jul 2013 10:42:32 -0300 Subject: Fold in changes --- CHANGELOG | 5 +++++ changes/feature_3246-refactor-events-so-components-become-clients | 1 - changes/feature_add-leap-check | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 changes/feature_3246-refactor-events-so-components-become-clients delete mode 100644 changes/feature_add-leap-check diff --git a/CHANGELOG b/CHANGELOG index a6918b9..a66674b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +0.2.7 Jul 26: + o Refactor events so components are now called clients. Closes #3246 + o Add leap_check helper method, to use whenever leap_assert does not + apply. Related to #3007. + 0.2.6 Jul 12: o Improve leap_assert so that it only prints the traceback from the leap_assert call up. Closes #2895 diff --git a/changes/feature_3246-refactor-events-so-components-become-clients b/changes/feature_3246-refactor-events-so-components-become-clients deleted file mode 100644 index c8589c0..0000000 --- a/changes/feature_3246-refactor-events-so-components-become-clients +++ /dev/null @@ -1 +0,0 @@ - o Refactor events so components are now called clients. Closes #3246. diff --git a/changes/feature_add-leap-check b/changes/feature_add-leap-check deleted file mode 100644 index 5906c03..0000000 --- a/changes/feature_add-leap-check +++ /dev/null @@ -1 +0,0 @@ - o Add leap_check helper method, to use whenever leap_assert does not apply. Related to #3007. -- cgit v1.2.3 From b006c2c56fe0b83a3baf6a10a1e7dbe196051b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 26 Jul 2013 10:43:19 -0300 Subject: Bump version to 0.2.7 --- setup.py | 2 +- src/leap/common/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 9b57aa7..43848d0 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ setup( name='leap.common', # If you change version, do it also in # src/leap/common/__init__.py - version='0.2.6', + version='0.2.7', url='https://leap.se/', license='GPLv3+', author='The LEAP Encryption Access Project', diff --git a/src/leap/common/__init__.py b/src/leap/common/__init__.py index abeff0f..b378d5e 100644 --- a/src/leap/common/__init__.py +++ b/src/leap/common/__init__.py @@ -16,4 +16,4 @@ except ImportError: __all__ = ["certs", "check", "files", "events"] -__version__ = "0.2.6" +__version__ = "0.2.7" -- cgit v1.2.3 From f4ad8fe84e96d355c46cd94a0e30330b83861dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Tue, 30 Jul 2013 11:41:08 -0300 Subject: Fix path prefix for OSX --- changes/bug-path_prefix | 2 ++ src/leap/common/config/prefixers.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changes/bug-path_prefix diff --git a/changes/bug-path_prefix b/changes/bug-path_prefix new file mode 100644 index 0000000..f112eba --- /dev/null +++ b/changes/bug-path_prefix @@ -0,0 +1,2 @@ + o OSX: Fix problem with path prefix not returning the correct + value. Fixes #3273. \ No newline at end of file diff --git a/src/leap/common/config/prefixers.py b/src/leap/common/config/prefixers.py index 050d4cd..9a5b043 100644 --- a/src/leap/common/config/prefixers.py +++ b/src/leap/common/config/prefixers.py @@ -95,7 +95,7 @@ class DarwinPrefixer(Prefixer): config_dir = BaseDirectory.xdg_config_home if not standalone: return config_dir - return os.getenv(os.getcwd(), "config") + return os.path.join(os.getcwd(), "config") class WindowsPrefixer(Prefixer): -- cgit v1.2.3 From e169ed03967fc8552c9300467bd99013ad7391df Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 6 Aug 2013 11:55:44 -0300 Subject: Check if schema exists before load a config. Related to #3310. --- changes/check-if-schema-exists | 1 + src/leap/common/config/baseconfig.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 changes/check-if-schema-exists diff --git a/changes/check-if-schema-exists b/changes/check-if-schema-exists new file mode 100644 index 0000000..1459112 --- /dev/null +++ b/changes/check-if-schema-exists @@ -0,0 +1 @@ + o Check if schema exists before load a config. Related to #3310. diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index 699d734..7bf08dd 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -26,7 +26,7 @@ import os from abc import ABCMeta, abstractmethod -from leap.common.check import leap_assert +from leap.common.check import leap_assert, leap_check from leap.common.files import mkdir_p from leap.common.config.pluggableconfig import PluggableConfig from leap.common.config.prefixers import get_platform_prefixer @@ -34,6 +34,12 @@ from leap.common.config.prefixers import get_platform_prefixer logger = logging.getLogger(__name__) +class NonExistingSchema(Exception): + """ + Raised if the schema needed to verify the config is None. + """ + + class BaseConfig: """ Abstract base class for any JSON based configuration. @@ -112,6 +118,7 @@ class BaseConfig: def load(self, path="", data=None, mtime=None, relative=True): """ Loads the configuration from disk. + It may raise NonExistingSchema exception. :param path: if relative=True, this is a relative path to configuration. The absolute path @@ -131,8 +138,12 @@ class BaseConfig: else: config_path = path + schema = self._get_spec() + leap_check(schema is not None, + "There is no schema to use.", NonExistingSchema) + self._config_checker = PluggableConfig(format="json") - self._config_checker.options = copy.deepcopy(self._get_spec()) + self._config_checker.options = copy.deepcopy(schema) try: if data is None: -- cgit v1.2.3 From 011e8802b248ffa39fa40d4931d2577256d01bd7 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 6 Aug 2013 18:20:59 -0300 Subject: Handle schemas and api versions in base class. --- changes/common-code-to-base-config | 1 + src/leap/common/config/baseconfig.py | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 changes/common-code-to-base-config diff --git a/changes/common-code-to-base-config b/changes/common-code-to-base-config new file mode 100644 index 0000000..d4e7fc1 --- /dev/null +++ b/changes/common-code-to-base-config @@ -0,0 +1 @@ + o Handle schemas and api versions in base class. Related to #3310. diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index 7bf08dd..ba87df9 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -61,13 +61,25 @@ class BaseConfig: def __init__(self): self._data = {} self._config_checker = None + self._api_version = None @abstractmethod + def _get_schema(self): + """ + Returns the schema corresponding to the version given. + + :rtype: dict or None if the version is not supported. + """ + pass + def _get_spec(self): """ Returns the spec object for the specific configuration. """ - return None + leap_assert(self._api_version is not None, + "You should set the API version.") + + return self._get_schema() def _safe_get_value(self, key): """ @@ -79,6 +91,17 @@ class BaseConfig: leap_assert(self._config_checker, "Load the config first") return self._config_checker.config.get(key, None) + def set_api_version(self, version): + """ + Sets the supported api version. + + :param api_version: the version of the api supported by the provider. + :type api_version: str + """ + self._api_version = version + leap_assert(self._get_schema(self._api_version) is not None, + "Version %s is not supported." % (version, )) + def get_path_prefix(self): """ Returns the platform dependant path prefixer -- cgit v1.2.3 From 335d73ee94976300aae156084e8e275e98ee5ea5 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 7 Aug 2013 15:23:42 -0300 Subject: Fix old parameter error. --- src/leap/common/config/baseconfig.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/leap/common/config/baseconfig.py b/src/leap/common/config/baseconfig.py index ba87df9..e310bc0 100644 --- a/src/leap/common/config/baseconfig.py +++ b/src/leap/common/config/baseconfig.py @@ -75,6 +75,8 @@ class BaseConfig: def _get_spec(self): """ Returns the spec object for the specific configuration. + + :rtype: dict or None if the version is not supported. """ leap_assert(self._api_version is not None, "You should set the API version.") @@ -99,7 +101,7 @@ class BaseConfig: :type api_version: str """ self._api_version = version - leap_assert(self._get_schema(self._api_version) is not None, + leap_assert(self._get_schema() is not None, "Version %s is not supported." % (version, )) def get_path_prefix(self): -- cgit v1.2.3 From 2ee356cd9acbb76a697a738a7d320570c78caf9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 9 Aug 2013 14:32:20 -0300 Subject: Fold in changes --- CHANGELOG | 6 ++++++ changes/bug-path_prefix | 2 -- changes/check-if-schema-exists | 1 - changes/common-code-to-base-config | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 changes/bug-path_prefix delete mode 100644 changes/check-if-schema-exists delete mode 100644 changes/common-code-to-base-config diff --git a/CHANGELOG b/CHANGELOG index a66674b..81c5f96 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +0.3.0 Aug 9: + o OSX: Fix problem with path prefix not returning the correct + value. Fixes #3273. + o Check if schema exists before load a config. Related to #3310. + o Handle schemas and api versions in base class. Related to #3310. + 0.2.7 Jul 26: o Refactor events so components are now called clients. Closes #3246 o Add leap_check helper method, to use whenever leap_assert does not diff --git a/changes/bug-path_prefix b/changes/bug-path_prefix deleted file mode 100644 index f112eba..0000000 --- a/changes/bug-path_prefix +++ /dev/null @@ -1,2 +0,0 @@ - o OSX: Fix problem with path prefix not returning the correct - value. Fixes #3273. \ No newline at end of file diff --git a/changes/check-if-schema-exists b/changes/check-if-schema-exists deleted file mode 100644 index 1459112..0000000 --- a/changes/check-if-schema-exists +++ /dev/null @@ -1 +0,0 @@ - o Check if schema exists before load a config. Related to #3310. diff --git a/changes/common-code-to-base-config b/changes/common-code-to-base-config deleted file mode 100644 index d4e7fc1..0000000 --- a/changes/common-code-to-base-config +++ /dev/null @@ -1 +0,0 @@ - o Handle schemas and api versions in base class. Related to #3310. -- cgit v1.2.3 From 0e721b1b47c3b94f6d4d6709e34b6b816f9fd810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Fri, 9 Aug 2013 14:33:10 -0300 Subject: Bump version to 0.3.0 --- setup.py | 2 +- src/leap/common/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 43848d0..0db731e 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ setup( name='leap.common', # If you change version, do it also in # src/leap/common/__init__.py - version='0.2.7', + version='0.3.0', url='https://leap.se/', license='GPLv3+', author='The LEAP Encryption Access Project', diff --git a/src/leap/common/__init__.py b/src/leap/common/__init__.py index b378d5e..3946fe8 100644 --- a/src/leap/common/__init__.py +++ b/src/leap/common/__init__.py @@ -16,4 +16,4 @@ except ImportError: __all__ = ["certs", "check", "files", "events"] -__version__ = "0.2.7" +__version__ = "0.3.0" -- cgit v1.2.3