blob: 480de8417fdc75cb1f19bedb83f68e4b3be47e1b [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.impl.google.lib.discovery;
import com.google.common.collect.Sets;
import org.joda.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.UUID;
import io.v.x.ref.lib.discovery.Advertisement;
public class DeviceCache {
private Map<Long, CacheEntry> cachedDevices;
private Map<String, CacheEntry> knownIds;
private class CacheEntry {
Set<Advertisement> advertisements;
long hash;
Date lastSeen;
String deviceId;
CacheEntry(Set<Advertisement> advs, long hash, String deviceId) {
advertisements = advs;
this.hash = hash;
lastSeen = new Date();
this.deviceId = deviceId;
}
}
int nextScanner;
private Map<UUID, Set<Advertisement>> knownServices;
private Map<Integer, VScanner> scannersById;
private Map<UUID, Set<VScanner>> scannersByUUID;
private Duration maxAge;
public DeviceCache(Duration maxAge) {
cachedDevices = new HashMap<>();
knownIds = new HashMap<>();
knownServices = new HashMap<>();
scannersById = new HashMap<>();
scannersByUUID = new HashMap<>();
this.maxAge = maxAge;
nextScanner = 0;
}
public boolean haveSeenHash(long hash, String deviceId) {
synchronized (this) {
CacheEntry entry = cachedDevices.get(hash);
if (entry != null) {
entry.lastSeen = new Date();
if (!entry.deviceId.equals(deviceId)) {
// This probably happened becuase a device has changed it's ble mac address.
// We need to update the mac address for this entry.
knownIds.remove(entry.deviceId);
entry.deviceId = deviceId;
knownIds.put(deviceId, entry);
}
}
return entry != null;
}
}
public void saveDevice(long hash, Set<Advertisement> advs, String deviceId) {
CacheEntry entry = new CacheEntry(advs, hash, deviceId);
synchronized (this) {
CacheEntry oldEntry = knownIds.get(deviceId);
Set<Advertisement> oldValues = null;
if (oldEntry != null) {
cachedDevices.remove(oldEntry.hash);
knownIds.remove(oldEntry.deviceId);
oldValues = oldEntry.advertisements;
} else {
oldValues = new HashSet<>();
}
Sets.SetView<Advertisement> removed = Sets.difference(oldValues, advs);
for (Advertisement adv : removed) {
UUID uuid = UUIDUtil.UuidtUUID(adv.getServiceUuid());
Set<Advertisement> set = knownServices.get(uuid);
if (set != null) {
set.remove(adv);
adv.setLost(true);
handleUpdate(adv);
if (set.size() == 0) {
knownServices.remove(uuid);
}
}
}
Sets.SetView<Advertisement> added = Sets.difference(advs, oldValues);
for (Advertisement adv: added) {
UUID uuid = UUIDUtil.UuidtUUID(adv.getServiceUuid());
Set<Advertisement> set = knownServices.get(uuid);
if (set == null) {
set = new HashSet<>();
knownServices.put(uuid, set);
}
set.add(adv);
handleUpdate(adv);
}
cachedDevices.put(hash, entry);
CacheEntry oldDeviceEntry = knownIds.get(deviceId);
if (oldDeviceEntry != null) {
// Delete the old hash value.
cachedDevices.remove(hash);
}
knownIds.put(deviceId, entry);
}
}
private void handleUpdate(Advertisement adv) {
UUID uuid = UUIDUtil.UuidtUUID(adv.getServiceUuid());
Set<VScanner> scanners = scannersByUUID.get(uuid);
if (scanners == null) {
return;
}
for (VScanner scanner : scanners) {
scanner.getHandler().handleUpdate(adv);
}
}
public int addScanner(VScanner scanner) {
synchronized (this) {
int id = nextScanner++;
scannersById.put(id, scanner);
Set<VScanner> scanners = scannersByUUID.get(scanner.getmServiceUUID());
if (scanners == null) {
scanners = new HashSet<>();
scannersByUUID.put(scanner.getmServiceUUID(), scanners);
}
Set<Advertisement> knownAdvs = knownServices.get(scanner.getmServiceUUID());
if (knownAdvs != null) {
for (Advertisement adv : knownAdvs) {
scanner.getHandler().handleUpdate(adv);
}
}
scanners.add(scanner);
return id;
}
}
public void removeScanner(int id) {
synchronized (this) {
VScanner scanner = scannersById.get(id);
if (scanner != null) {
Set<VScanner> list = scannersByUUID.get(scanner.getmServiceUUID());
if (list != null) {
list.remove(scanner);
if (list.size() == 0) {
scannersByUUID.remove(scanner.getmServiceUUID());
}
}
scannersById.remove(id);
}
}
}
}