| // 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); |
| } |
| } |
| } |
| } |