Skip to content

Commit

Permalink
Implemented Database.add(Document)ChangeListener
Browse files Browse the repository at this point in the history
  • Loading branch information
Kin Mak committed Jul 14, 2020
1 parent 3be54eb commit c79fc36
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 2.7.1+4

* Added Database addDocumentChangeListener
* Added Database addChangeListener
* Added Database removeChangeListener

## 2.7.1+3

* Setting up plugin CI/CD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class CBManager {
private HashMap<String, ListenerToken> mQueryListenerTokens = new HashMap<>();
private HashMap<String, Replicator> mReplicators = new HashMap<>();
private HashMap<String, ListenerToken[]> mReplicatorListenerTokens = new HashMap<>();
private HashMap<String, ListenerToken> mDatabaseListenerTokens = new HashMap<>();
private DatabaseConfiguration mDBConfig;
private CBManagerDelegate mDelegate;

Expand Down Expand Up @@ -219,12 +220,29 @@ void deleteDatabaseWithName(String _name) throws CouchbaseLiteException {
}

void closeDatabaseWithName(String _name) throws CouchbaseLiteException {
removeDatabaseListenerToken(_name);
Database _db = mDatabase.remove(_name);
if (_db != null) {
_db.close();
}
}

ListenerToken getDatabaseListenerToken(String dbname) {
return mDatabaseListenerTokens.get(dbname);
}

void addDatabaseListenerToken(String dbname, ListenerToken token) {
mDatabaseListenerTokens.put(dbname, token);
}

void removeDatabaseListenerToken(String dbname) {
Database _db = mDatabase.get(dbname);
ListenerToken token = mDatabaseListenerTokens.remove(dbname);
if (_db != null && token != null) {
_db.removeChangeListener(token);
}
}

void addQuery(String queryId, Query query, ListenerToken token) {
mQueries.put(queryId,query);
mQueryListenerTokens.put(queryId,token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.couchbase.lite.CouchbaseLite;
import com.couchbase.lite.CouchbaseLiteException;
import com.couchbase.lite.Database;
import com.couchbase.lite.DatabaseChange;
import com.couchbase.lite.DatabaseChangeListener;
import com.couchbase.lite.Document;
import com.couchbase.lite.DocumentFlag;
import com.couchbase.lite.DocumentReplication;
Expand Down Expand Up @@ -55,6 +57,7 @@ public class CouchbaseLitePlugin implements CBManagerDelegate {
private final Registrar mRegistrar;
private final QueryEventListener mQueryEventListener = new QueryEventListener();
private final ReplicationEventListener mReplicationEventListener = new ReplicationEventListener();
private final DatabaseEventListener mDatabaseEventListener = new DatabaseEventListener();
private final CBManager mCBManager;
private DatabaseCallHander databaseCallHander = new DatabaseCallHander();
private ReplicatorCallHander replicatorCallHander = new ReplicatorCallHander();
Expand All @@ -80,6 +83,10 @@ public static void registerWith(Registrar registrar) {

final EventChannel queryEventChannel = new EventChannel(registrar.messenger(), "com.saltechsystems.couchbase_lite/queryEventChannel", JSONMethodCodec.INSTANCE);
queryEventChannel.setStreamHandler(instance.mQueryEventListener);

final EventChannel databaseEventChannel = new EventChannel(registrar.messenger(),
"com.saltechsystems.couchbase_lite/databaseEventChannel");
databaseEventChannel.setStreamHandler(instance.mDatabaseEventListener);
}

public CouchbaseLitePlugin(Registrar registrar) {
Expand Down Expand Up @@ -378,6 +385,46 @@ public void run() {
}

break;
case ("addChangeListener"):
if (database == null) {
result.error("errDatabase", "Database with name " + dbname + "not found", null);
return;
}

if (mCBManager.getDatabaseListenerToken(dbname) == null) {
ListenerToken token = database.addChangeListener(AsyncTask.THREAD_POOL_EXECUTOR,
new DatabaseChangeListener() {
@Override
public void changed(DatabaseChange change) {

final HashMap<String, Object> map = new HashMap<String, Object>();
map.put("type", "DatabaseChange");
map.put("database", change.getDatabase().getName());
map.put("documentIDs", change.getDocumentIDs());

new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
final EventChannel.EventSink eventSink = mDatabaseEventListener.mEventSink;
if (eventSink != null) {
eventSink.success(map);
}
}
});
}
});

mCBManager.addDatabaseListenerToken(dbname, token);
result.success(null);
}


break;

case ("removeChangeListener"):
mCBManager.removeDatabaseListenerToken(dbname);
result.success(null);
break;
default:
result.notImplemented();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.saltechsystems.couchbase_lite;

import io.flutter.plugin.common.EventChannel;

public class DatabaseEventListener implements EventChannel.StreamHandler {
public EventChannel.EventSink mEventSink;

/*
* IMPLEMENTATION OF EVENTCHANNEL.STREAMHANDLER
*/

@Override
public void onListen(Object args, final EventChannel.EventSink eventSink) {
mEventSink = eventSink;
}

@Override
public void onCancel(Object args) {
mEventSink = null;
}
}
21 changes: 21 additions & 0 deletions example/lib/data/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class AppDatabase {
ListenerToken _replicatorListenerToken;
Database database;
Replicator replicator;
ListenerToken _docListenerToken;
ListenerToken _dbListenerToken;

Future<bool> login(String username, String password) async {
try {
Expand Down Expand Up @@ -68,9 +70,22 @@ class AppDatabase {
await database.createIndex(index, withName: indexName);
} else {
var query = _buildBeerQuery(100, 0, false);
print('explanation:');
print(await query.explain());
}

var pref =
await createDocumentIfNotExists("MyPreference", {"theme": "dark"});
_docListenerToken = database.addDocumentChangeListener(pref.id, (change) {
print("Document change ${change.documentID}");
});

_dbListenerToken = database.addChangeListener((dbChange) {
for (var change in dbChange.documentIDs) {
print("change in id: $change");
}
});

return true;
} on PlatformException {
return false;
Expand All @@ -79,6 +94,12 @@ class AppDatabase {

Future<void> logout() async {
await Future.wait(pendingListeners);

await database.removeChangeListener(_docListenerToken);
await database.removeChangeListener(_dbListenerToken);
_docListenerToken = null;
_dbListenerToken = null;

await replicator.removeChangeListener(_replicatorListenerToken);
_replicatorListenerToken =
replicator.addChangeListener((ReplicatorChange event) async {
Expand Down
28 changes: 28 additions & 0 deletions ios/Classes/CBManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CBManager {
private var mQueryListenerTokens : Dictionary<String,ListenerToken> = Dictionary();
private var mReplicators : Dictionary<String,Replicator> = Dictionary();
private var mReplicatorListenerTokens : Dictionary<String,[ListenerToken]> = Dictionary();
private var mDatabaseListenerTokens : Dictionary<String, ListenerToken> = Dictionary();
private var mDBConfig = DatabaseConfiguration();
private weak var mDelegate: CBManagerDelegate?

Expand Down Expand Up @@ -183,10 +184,37 @@ class CBManager {

func closeDatabaseWithName(name: String) throws {
if let _db = mDatabase.removeValue(forKey: name) {

if let token = mDatabaseListenerTokens[name] {
_db.removeChangeListener(withToken: token)
mDatabaseListenerTokens.removeValue(forKey: name)
}

try _db.close()
}
}

func getDatabaseListenerToken(dbname: String) -> ListenerToken? {
return mDatabaseListenerTokens[dbname]
}

func addDatabaseListenerToken(dbname: String, token: ListenerToken) {
mDatabaseListenerTokens[dbname] = token
}

func removeDatabaseListenerToken(dbname: String) throws {

guard let database = getDatabase(name: dbname) else {
throw CBManagerError.DatabaseNotFound
}

if let token = mDatabaseListenerTokens[dbname] {
database.removeChangeListener(withToken: token)
mDatabaseListenerTokens.removeValue(forKey: dbname)
}
}


func addQuery(queryId: String, query: Query, listenerToken: ListenerToken) {
mQueries[queryId] = query;
mQueryListenerTokens[queryId] = listenerToken;
Expand Down
25 changes: 25 additions & 0 deletions ios/Classes/DatabaseEventListener.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// DatabaseEventListener.swift
// couchbase_lite
//
// Created by Kin Mak on 8/7/2020.
//

import Foundation
import CouchbaseLiteSwift

class DatabaseEventListener: FlutterStreamHandler {
var mEventSink: FlutterEventSink?

func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
mEventSink = events

return nil
}

func onCancel(withArguments arguments: Any?) -> FlutterError? {


return nil
}
}
42 changes: 42 additions & 0 deletions ios/Classes/SwiftCouchbaseLitePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import CouchbaseLiteSwift

public class SwiftCouchbaseLitePlugin: NSObject, FlutterPlugin, CBManagerDelegate {
weak var mRegistrar: FlutterPluginRegistrar?
let mDatabaseEventListener = DatabaseEventListener()
let mQueryEventListener = QueryEventListener();
let mReplicatorEventListener = ReplicatorEventListener();
let databaseDispatchQueue = DispatchQueue(label: "DatabaseDispatchQueue", qos: .background)
Expand All @@ -20,6 +21,9 @@ public class SwiftCouchbaseLitePlugin: NSObject, FlutterPlugin, CBManagerDelegat
let databaseChannel = FlutterMethodChannel(name: "com.saltechsystems.couchbase_lite/database", binaryMessenger: registrar.messenger())
databaseChannel.setMethodCallHandler(instance.handleDatabase(_:result:))

let databaseEventChannel = FlutterEventChannel(name: "com.saltechsystems.couchbase_lite/databaseEventChannel", binaryMessenger: registrar.messenger())
databaseEventChannel.setStreamHandler(instance.mDatabaseEventListener as? FlutterStreamHandler & NSObjectProtocol)

let replicatorChannel = FlutterMethodChannel(name: "com.saltechsystems.couchbase_lite/replicator", binaryMessenger: registrar.messenger())
replicatorChannel.setMethodCallHandler(instance.handleReplicator(_:result:))

Expand Down Expand Up @@ -265,6 +269,44 @@ public class SwiftCouchbaseLitePlugin: NSObject, FlutterPlugin, CBManagerDelegat
}

result(database.indexes)

case "addChangeListener":
guard let database = mCBManager.getDatabase(name: dbname) else {
result(FlutterError.init(code: "errDatabase", message: "Database with name \(dbname) not found", details: nil))
return
}

guard let _ = mCBManager.getDatabaseListenerToken(dbname: dbname) else {
let token = database.addChangeListener(withQueue: databaseDispatchQueue, listener: { [weak self] change in
var map = Dictionary<String,Any?>()
map["type"] = "DatabaseChange"
map["database"] = change.database.name
map["documentIDs"] = change.documentIDs

DispatchQueue.main.async {
// Will only send events when there is something listening
self?.mDatabaseEventListener.mEventSink?(map)
}
})

mCBManager.addDatabaseListenerToken(dbname: dbname, token: token)
result(true)
return
}


result(true)

case "removeChangeListener":

do {
try mCBManager.removeDatabaseListenerToken(dbname: dbname)
result(nil)
} catch {
result(FlutterError(code: "errDatabase", message: "Error removing database listener token", details: nil))
}


default:
result(FlutterMethodNotImplemented)
}
Expand Down

0 comments on commit c79fc36

Please sign in to comment.