From e24f374a9cef82f04d8b2ad11fa321d747c04cf8 Mon Sep 17 00:00:00 2001 From: Collin Jackson Date: Fri, 15 Jan 2016 13:36:52 -0800 Subject: [PATCH] Support for value and child events on Firebase iOS --- sky/services/firebase/ios/firebase_impl.h | 6 ++ sky/services/firebase/ios/firebase_impl.mm | 92 +++++++++++++++++++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/sky/services/firebase/ios/firebase_impl.h b/sky/services/firebase/ios/firebase_impl.h index 0651537b484..f96dd1d6e40 100644 --- a/sky/services/firebase/ios/firebase_impl.h +++ b/sky/services/firebase/ios/firebase_impl.h @@ -30,6 +30,10 @@ class FirebaseImpl : public ::firebase::Firebase { void GetChild( const mojo::String& path, mojo::InterfaceRequest child) override; + void AddValueEventListener( + ::firebase::ValueEventListenerPtr listener) override; + void AddChildEventListener( + ::firebase::ChildEventListenerPtr listener) override; void ObserveSingleEventOfType( ::firebase::EventType eventType, const ObserveSingleEventOfTypeCallback& callback) override; @@ -41,6 +45,8 @@ class FirebaseImpl : public ::firebase::Firebase { private: mojo::StrongBinding<::firebase::Firebase> binding_; ::Firebase* client_; + std::vector<::firebase::ValueEventListenerPtr> value_event_listeners_; + std::vector<::firebase::ChildEventListenerPtr> child_event_listeners_; DISALLOW_COPY_AND_ASSIGN(FirebaseImpl); }; diff --git a/sky/services/firebase/ios/firebase_impl.mm b/sky/services/firebase/ios/firebase_impl.mm index c98c4dea261..239fc9043b2 100644 --- a/sky/services/firebase/ios/firebase_impl.mm +++ b/sky/services/firebase/ios/firebase_impl.mm @@ -12,6 +12,20 @@ namespace sky { namespace services { namespace firebase { +::firebase::DataSnapshotPtr toMojoSnapshot(FDataSnapshot* snapshot) { + ::firebase::DataSnapshotPtr mojoSnapshot(::firebase::DataSnapshot::New()); + mojoSnapshot->key = base::SysNSStringToUTF8(snapshot.key); + mojoSnapshot->value = base::SysNSStringToUTF8(snapshot.value); + return mojoSnapshot.Pass(); +} + +::firebase::ErrorPtr toMojoError(NSError* error) { + ::firebase::ErrorPtr mojoError(::firebase::Error::New()); + mojoError->code = error.code; + mojoError->message = base::SysNSStringToUTF8(error.description); + return mojoError.Pass(); +} + FirebaseImpl::FirebaseImpl(mojo::InterfaceRequest<::firebase::Firebase> request) : binding_(this, request.Pass()) {} @@ -35,6 +49,79 @@ void FirebaseImpl::GetChild( child->client_ = [[client_ childByAppendingPath:@(path.data())] retain]; } +void FirebaseImpl::AddValueEventListener(::firebase::ValueEventListenerPtr ptr) { + ::firebase::ValueEventListener *listener = ptr.get(); + FirebaseHandle handle = [client_ observeEventType:FEventTypeValue + withBlock:^(FDataSnapshot *snapshot) { + listener->OnDataChange(toMojoSnapshot(snapshot)); + } withCancelBlock:^(NSError *error) { + listener->OnCancelled(toMojoError(error)); + }]; + ptr.set_connection_error_handler([this, handle, listener]() { + [client_ removeObserverWithHandle:handle]; + auto it = std::find_if(value_event_listeners_.begin(), + value_event_listeners_.end(), + [listener](const ::firebase::ValueEventListenerPtr& p) { + return (p.get() == listener); + }); + DCHECK(it != value_event_listeners_.end()); + value_event_listeners_.erase(it); + }); + value_event_listeners_.emplace_back(ptr.Pass()); +} + +void FirebaseImpl::AddChildEventListener(::firebase::ChildEventListenerPtr ptr) { + ::firebase::ChildEventListener *listener = ptr.get(); + void (^cancelBlock)(NSError *) = ^(NSError *error) { + listener->OnCancelled(toMojoError(error)); + }; + + void (^addedBlock)(FDataSnapshot *, NSString *) = ^(FDataSnapshot *snapshot, NSString *prevKey) { + listener->OnChildAdded(toMojoSnapshot(snapshot), base::SysNSStringToUTF8(prevKey)); + }; + FirebaseHandle addedHandle = [client_ observeEventType:FEventTypeChildAdded + andPreviousSiblingKeyWithBlock:addedBlock + withCancelBlock:cancelBlock]; + + void (^changedBlock)(FDataSnapshot *, NSString *) = ^(FDataSnapshot *snapshot, NSString *prevKey) { + listener->OnChildChanged(toMojoSnapshot(snapshot), base::SysNSStringToUTF8(prevKey)); + }; + FirebaseHandle changedHandle = [client_ observeEventType:FEventTypeChildChanged + andPreviousSiblingKeyWithBlock:changedBlock + withCancelBlock:cancelBlock]; + + void (^movedBlock)(FDataSnapshot *, NSString *) = ^(FDataSnapshot *snapshot, NSString *prevKey) { + listener->OnChildMoved(toMojoSnapshot(snapshot), base::SysNSStringToUTF8(prevKey)); + }; + FirebaseHandle movedHandle = [client_ observeEventType:FEventTypeChildMoved + andPreviousSiblingKeyWithBlock:movedBlock + withCancelBlock:cancelBlock]; + + void (^removedBlock)(FDataSnapshot *snapshot) = ^(FDataSnapshot *snapshot) { + listener->OnChildRemoved(toMojoSnapshot(snapshot)); + }; + FirebaseHandle removedHandle = [client_ observeEventType:FEventTypeChildRemoved + withBlock:removedBlock + withCancelBlock:cancelBlock]; + + ptr.set_connection_error_handler( + [this, addedHandle, changedHandle, movedHandle, removedHandle, listener]() { + [client_ removeObserverWithHandle:addedHandle]; + [client_ removeObserverWithHandle:changedHandle]; + [client_ removeObserverWithHandle:movedHandle]; + [client_ removeObserverWithHandle:removedHandle]; + auto it = std::find_if(child_event_listeners_.begin(), + child_event_listeners_.end(), + [listener](const ::firebase::ChildEventListenerPtr& p) { + return (p.get() == listener); + }); + DCHECK(it != child_event_listeners_.end()); + child_event_listeners_.erase(it); + } + ); + child_event_listeners_.emplace_back(ptr.Pass()); +} + void FirebaseImpl::ObserveSingleEventOfType( ::firebase::EventType eventType, const ObserveSingleEventOfTypeCallback& callback) { @@ -42,10 +129,7 @@ void FirebaseImpl::ObserveSingleEventOfType( new ObserveSingleEventOfTypeCallback(callback); [client_ observeSingleEventOfType:static_cast(eventType) withBlock:^(FDataSnapshot *snapshot) { - ::firebase::DataSnapshotPtr mojoSnapshot(::firebase::DataSnapshot::New()); - mojoSnapshot->key = base::SysNSStringToUTF8(snapshot.key); - mojoSnapshot->value = base::SysNSStringToUTF8(snapshot.value); - copyCallback->Run(mojoSnapshot.Pass()); + copyCallback->Run(toMojoSnapshot(snapshot)); delete copyCallback; }]; }