blob: c0b8a453558663b2dc75dcc9da47137278ba8475 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.mojo.discovery;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.v.v23.InputChannelCallback;
import org.chromium.mojo.system.MojoException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import io.v.v23.InputChannels;
import io.v.v23.context.VContext;
import io.v.v23.discovery.Attachments;
import io.v.v23.discovery.Attributes;
import io.v.v23.discovery.VDiscovery;
import io.v.v23.rpc.Callback;
import io.v.v23.security.BlessingPattern;
import io.v.v23.verror.VException;
class DiscoveryImpl implements Discovery {
private final VDiscovery discovery;
private final VContext rootCtx;
private final Map<Integer, VContext> contextMap = new HashMap<>();
private final Map<String, VContext> advertiserContextMap = new HashMap<>();
private final AtomicInteger nextScanner = new AtomicInteger(0);
public DiscoveryImpl(VDiscovery discovery, VContext rootCtx) {
this.discovery = discovery;
this.rootCtx = rootCtx;
}
@Override
public void startScan(String query, final ScanHandler scanHandler, StartScanResponse callback) {
synchronized (this) {
System.out.println("Got a scan call");
int handle = nextScanner.getAndAdd(1);
VContext ctx = rootCtx.withCancel();
contextMap.put(handle, ctx);
ListenableFuture<Void> done = InputChannels.withCallback(discovery.scan(ctx, query),
new InputChannelCallback<io.v.v23.discovery.Update>() {
@Override
public ListenableFuture<Void> onNext(io.v.v23.discovery.Update update) {
if (update instanceof io.v.v23.discovery.Update.Found) {
io.v.v23.discovery.Update.Found found = (io.v.v23.discovery.Update.Found) update;
Service mService = toMojoService(found.getElem().getService());
ScanUpdate mUpdate = new ScanUpdate();
mUpdate.service = mService;
mUpdate.updateType = UpdateType.FOUND;
scanHandler.update(mUpdate);
} else {
io.v.v23.discovery.Update.Lost lost = (io.v.v23.discovery.Update.Lost) update;
Service mService = toMojoService(lost.getElem().getService());
ScanUpdate mUpdate = new ScanUpdate();
mUpdate.service = mService;
mUpdate.updateType = UpdateType.LOST;
scanHandler.update(mUpdate);
}
return Futures.immediateFuture(null);
}
});
System.out.println("Returning a scan call");
callback.call(handle, null);
}
}
@Override
public void stopScan(int h, StopScanResponse response) {
synchronized (this) {
VContext ctx = contextMap.get(h);
if (ctx != null) {
contextMap.remove(h);
ctx.cancel();
}
response.call(null);
}
}
private static Service toMojoService(io.v.v23.discovery.Service vService) {
Service mService = new Service();
mService.instanceId = vService.getInstanceId();
mService.instanceName = vService.getInstanceName();
mService.interfaceName = vService.getInterfaceName();
mService.addrs = new String[vService.getAddrs().size()];
mService.addrs = vService.getAddrs().toArray(mService.addrs);
mService.attrs = vService.getAttrs();
return mService;
}
@Override
public void startAdvertising(Service service, String[] visibility, final StartAdvertisingResponse callback) {
synchronized (this) {
final VContext ctx = rootCtx.withCancel();
Attributes attrs = null;
final io.v.v23.discovery.Service vService = new io.v.v23.discovery.Service(
service.instanceId, service.instanceName, service.interfaceName,
new Attributes(service.attrs), Arrays.asList(service.addrs), new Attachments());
if (service.attrs == null) {
vService.setAttrs(new Attributes(new HashMap<String, String>()));
}
List<BlessingPattern> patterns;
if (visibility != null) {
patterns = new ArrayList<>(visibility.length);
for (String pattern : visibility) {
patterns.add(new BlessingPattern(pattern));
}
} else {
patterns = new ArrayList<>(0);
}
ListenableFuture<ListenableFuture<Void>> done = discovery.advertise(ctx, vService, patterns);
Futures.addCallback(done, new FutureCallback<ListenableFuture<Void>>() {
@Override
public void onSuccess(ListenableFuture<Void> result) {
String instanceId = vService.getInstanceId();
callback.call(instanceId, null);
advertiserContextMap.put(instanceId, ctx);
}
@Override
public void onFailure(Throwable t) {
System.out.println("Failed with " + t.toString());
Error e = new Error();
e.msg = t.toString();
e.id = "unknown";
callback.call("", e);
}
});
}
}
@Override
public void stopAdvertising(String instanceId, StopAdvertisingResponse response) {
synchronized (this) {
VContext ctx = advertiserContextMap.get(instanceId);
if (ctx != null) {
advertiserContextMap.remove(instanceId);
ctx.cancel();
}
response.call(null);
}
}
@Override
public void close() {}
@Override
public void onConnectionError(MojoException e) {}
}