mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-26 01:28:05 +01:00
Split Account into Device and Account definitions.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (C) 2013 Open WhisperSystems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.whispersystems.textsecuregcm.storage;
|
||||
|
||||
|
||||
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Account implements Serializable {
|
||||
private String number;
|
||||
private boolean supportsSms;
|
||||
private Map<Long, Device> devices = new HashMap<>();
|
||||
|
||||
private Account(String number, boolean supportsSms) {
|
||||
this.number = number;
|
||||
this.supportsSms = supportsSms;
|
||||
}
|
||||
|
||||
public Account(String number, boolean supportsSms, Device onlyDevice) {
|
||||
this(number, supportsSms);
|
||||
this.devices.put(onlyDevice.getDeviceId(), onlyDevice);
|
||||
}
|
||||
|
||||
public Account(String number, boolean supportsSms, List<Device> devices) {
|
||||
this(number, supportsSms);
|
||||
for (Device device : devices)
|
||||
this.devices.put(device.getDeviceId(), device);
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public boolean getSupportsSms() {
|
||||
return supportsSms;
|
||||
}
|
||||
|
||||
public void setSupportsSms(boolean supportsSms) {
|
||||
this.supportsSms = supportsSms;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
Device masterDevice = devices.get((long) 1);
|
||||
return masterDevice != null && masterDevice.isActive();
|
||||
}
|
||||
|
||||
public Collection<Device> getDevices() {
|
||||
return devices.values();
|
||||
}
|
||||
|
||||
public Device getDevice(long destinationDeviceId) {
|
||||
return devices.get(destinationDeviceId);
|
||||
}
|
||||
|
||||
public boolean hasAllDeviceIds(Set<Long> deviceIds) {
|
||||
if (devices.size() != deviceIds.size())
|
||||
return false;
|
||||
for (long deviceId : devices.keySet()) {
|
||||
if (!deviceIds.contains(deviceId))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,8 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -78,22 +80,22 @@ public abstract class Accounts {
|
||||
"WHERE " + NUMBER + " = :number AND " + DEVICE_ID + " = :device_id")
|
||||
abstract void update(@AccountBinder Device device);
|
||||
|
||||
@Mapper(AccountMapper.class)
|
||||
@Mapper(DeviceMapper.class)
|
||||
@SqlQuery("SELECT * FROM accounts WHERE " + NUMBER + " = :number AND " + DEVICE_ID + " = :device_id")
|
||||
abstract Device get(@Bind("number") String number, @Bind("device_id") long deviceId);
|
||||
|
||||
@SqlQuery("SELECT COUNT(DISTINCT " + NUMBER + ") from accounts")
|
||||
abstract long getNumberCount();
|
||||
|
||||
@Mapper(AccountMapper.class)
|
||||
@Mapper(DeviceMapper.class)
|
||||
@SqlQuery("SELECT * FROM accounts WHERE " + DEVICE_ID + " = 1 OFFSET :offset LIMIT :limit")
|
||||
abstract List<Device> getAllFirstAccounts(@Bind("offset") int offset, @Bind("limit") int length);
|
||||
abstract List<Device> getAllMasterDevices(@Bind("offset") int offset, @Bind("limit") int length);
|
||||
|
||||
@Mapper(AccountMapper.class)
|
||||
@Mapper(DeviceMapper.class)
|
||||
@SqlQuery("SELECT * FROM accounts WHERE " + DEVICE_ID + " = 1")
|
||||
public abstract Iterator<Device> getAllFirstAccounts();
|
||||
public abstract Iterator<Device> getAllMasterDevices();
|
||||
|
||||
@Mapper(AccountMapper.class)
|
||||
@Mapper(DeviceMapper.class)
|
||||
@SqlQuery("SELECT * FROM accounts WHERE " + NUMBER + " = :number")
|
||||
public abstract List<Device> getAllByNumber(@Bind("number") String number);
|
||||
|
||||
@@ -104,8 +106,7 @@ public abstract class Accounts {
|
||||
return insertStep(device);
|
||||
}
|
||||
|
||||
public static class AccountMapper implements ResultSetMapper<Device> {
|
||||
|
||||
public static class DeviceMapper implements ResultSetMapper<Device> {
|
||||
@Override
|
||||
public Device map(int i, ResultSet resultSet, StatementContext statementContext)
|
||||
throws SQLException
|
||||
|
||||
@@ -20,10 +20,17 @@ package org.whispersystems.textsecuregcm.storage;
|
||||
import com.google.common.base.Optional;
|
||||
import net.spy.memcached.MemcachedClient;
|
||||
import org.whispersystems.textsecuregcm.entities.ClientContact;
|
||||
import org.whispersystems.textsecuregcm.util.Pair;
|
||||
import org.whispersystems.textsecuregcm.util.Util;
|
||||
import sun.util.logging.resources.logging_zh_CN;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class AccountsManager {
|
||||
|
||||
@@ -44,16 +51,17 @@ public class AccountsManager {
|
||||
return accounts.getNumberCount();
|
||||
}
|
||||
|
||||
public List<Device> getAllMasterAccounts(int offset, int length) {
|
||||
return accounts.getAllFirstAccounts(offset, length);
|
||||
public List<Device> getAllMasterDevices(int offset, int length) {
|
||||
return accounts.getAllMasterDevices(offset, length);
|
||||
}
|
||||
|
||||
public Iterator<Device> getAllMasterAccounts() {
|
||||
return accounts.getAllFirstAccounts();
|
||||
public Iterator<Device> getAllMasterDevices() {
|
||||
return accounts.getAllMasterDevices();
|
||||
}
|
||||
|
||||
/** Creates a new Device and NumberData, clearing all existing accounts/data on the given number */
|
||||
public void createResetNumber(Device device) {
|
||||
/** Creates a new Account (WITH ONE DEVICE), clearing all existing devices on the given number */
|
||||
public void create(Account account) {
|
||||
Device device = account.getDevices().iterator().next();
|
||||
long id = accounts.insertClearingNumber(device);
|
||||
device.setId(id);
|
||||
|
||||
@@ -64,8 +72,8 @@ public class AccountsManager {
|
||||
updateDirectory(device);
|
||||
}
|
||||
|
||||
/** Creates a new Device for an existing NumberData (setting the deviceId) */
|
||||
public void createAccountOnExistingNumber(Device device) {
|
||||
/** Creates a new Device for an existing Account */
|
||||
public void provisionDevice(Device device) {
|
||||
long id = accounts.insert(device);
|
||||
device.setId(id);
|
||||
|
||||
@@ -104,8 +112,43 @@ public class AccountsManager {
|
||||
else return Optional.absent();
|
||||
}
|
||||
|
||||
public List<Device> getAllByNumber(String number) {
|
||||
return accounts.getAllByNumber(number);
|
||||
public Optional<Account> getAccount(String number) {
|
||||
List<Device> devices = accounts.getAllByNumber(number);
|
||||
if (devices.isEmpty())
|
||||
return Optional.absent();
|
||||
return Optional.of(new Account(number, devices.get(0).getSupportsSms(), devices));
|
||||
}
|
||||
|
||||
private Map<String, Account> getAllAccounts(Set<String> numbers) {
|
||||
//TODO: ONE QUERY
|
||||
Map<String, Account> result = new HashMap<>();
|
||||
for (String number : numbers) {
|
||||
Optional<Account> account = getAccount(number);
|
||||
if (account.isPresent())
|
||||
result.put(number, account.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Pair<Map<String, Account>, List<String>> getAccountsForDevices(Map<String, Set<Long>> destinations) {
|
||||
List<String> numbersMissingDevices = new LinkedList<>();
|
||||
Map<String, Account> localAccounts = getAllAccounts(destinations.keySet());
|
||||
|
||||
for (String number : destinations.keySet()) {
|
||||
if (localAccounts.get(number) == null)
|
||||
numbersMissingDevices.add(number);
|
||||
}
|
||||
|
||||
Iterator<Account> localAccountIterator = localAccounts.values().iterator();
|
||||
while (localAccountIterator.hasNext()) {
|
||||
Account account = localAccountIterator.next();
|
||||
if (!account.hasAllDeviceIds(destinations.get(account.getNumber()))) {
|
||||
numbersMissingDevices.add(account.getNumber());
|
||||
localAccountIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return new Pair<>(localAccounts, numbersMissingDevices);
|
||||
}
|
||||
|
||||
private void updateDirectory(Device device) {
|
||||
|
||||
@@ -125,15 +125,19 @@ public class Device implements Serializable {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setFetchesMessages(boolean fetchesMessages) {
|
||||
this.fetchesMessages = fetchesMessages;
|
||||
public boolean isActive() {
|
||||
return fetchesMessages || !Util.isEmpty(getApnRegistrationId()) || !Util.isEmpty(getGcmRegistrationId());
|
||||
}
|
||||
|
||||
public boolean getFetchesMessages() {
|
||||
return fetchesMessages;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return getFetchesMessages() || !Util.isEmpty(getApnRegistrationId()) || !Util.isEmpty(getGcmRegistrationId());
|
||||
public void setFetchesMessages(boolean fetchesMessages) {
|
||||
this.fetchesMessages = fetchesMessages;
|
||||
}
|
||||
|
||||
public String getBackwardsCompatibleNumberEncoding() {
|
||||
return deviceId == 1 ? number : (number + "." + deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,9 +79,9 @@ public abstract class Keys {
|
||||
}
|
||||
|
||||
@Transaction(TransactionIsolationLevel.SERIALIZABLE)
|
||||
public UnstructuredPreKeyList get(String number, List<Device> devices) {
|
||||
public UnstructuredPreKeyList get(String number, Account account) {
|
||||
List<PreKey> preKeys = new LinkedList<>();
|
||||
for (Device device : devices) {
|
||||
for (Device device : account.getDevices()) {
|
||||
PreKey preKey = retrieveFirst(number, device.getDeviceId());
|
||||
if (preKey != null)
|
||||
preKeys.add(preKey);
|
||||
|
||||
Reference in New Issue
Block a user