Convert device linking apis to use websockets.

This commit is contained in:
Cody Henthorne
2025-03-06 16:17:55 -05:00
committed by Michelle Tang
parent 451d12ed53
commit c38342e2fb
21 changed files with 334 additions and 200 deletions

View File

@@ -47,8 +47,8 @@ import androidx.transition.TransitionManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.concurrent.JvmRxExtensions;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.signal.core.util.concurrent.RxExtensions;
import org.signal.core.util.concurrent.SimpleTask;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
@@ -722,7 +722,7 @@ public final class ContactSelectionListFragment extends LoggingFragment {
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
try {
return RxExtensions.safeBlockingGet(UsernameRepository.fetchAciForUsername(UsernameUtil.sanitizeUsernameFromSearch(username)));
return JvmRxExtensions.safeBlockingGet(UsernameRepository.fetchAciForUsername(UsernameUtil.sanitizeUsernameFromSearch(username)));
} catch (InterruptedException e) {
Log.w(TAG, "Interrupted?", e);
return UsernameAciFetchResult.NetworkError.INSTANCE;

View File

@@ -377,7 +377,7 @@ object AppDependencies {
fun provideArchiveApi(pushServiceSocket: PushServiceSocket): ArchiveApi
fun provideKeysApi(pushServiceSocket: PushServiceSocket): KeysApi
fun provideAttachmentApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket, pushServiceSocket: PushServiceSocket): AttachmentApi
fun provideLinkDeviceApi(pushServiceSocket: PushServiceSocket): LinkDeviceApi
fun provideLinkDeviceApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): LinkDeviceApi
fun provideRegistrationApi(pushServiceSocket: PushServiceSocket): RegistrationApi
fun provideStorageServiceApi(pushServiceSocket: PushServiceSocket): StorageServiceApi
fun provideAuthWebSocket(signalServiceConfigurationSupplier: Supplier<SignalServiceConfiguration>, libSignalNetworkSupplier: Supplier<Network>): SignalWebSocket.AuthenticatedWebSocket

View File

@@ -478,8 +478,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
}
@Override
public @NonNull LinkDeviceApi provideLinkDeviceApi(@NonNull PushServiceSocket pushServiceSocket) {
return new LinkDeviceApi(pushServiceSocket);
public @NonNull LinkDeviceApi provideLinkDeviceApi(@NonNull SignalWebSocket.AuthenticatedWebSocket authWebSocket) {
return new LinkDeviceApi(authWebSocket);
}
@Override

View File

@@ -146,7 +146,7 @@ class NetworkDependenciesModule(
}
val linkDeviceApi: LinkDeviceApi by lazy {
provider.provideLinkDeviceApi(pushServiceSocket)
provider.provideLinkDeviceApi(authWebSocket)
}
val registrationApi: RegistrationApi by lazy {

View File

@@ -68,7 +68,10 @@ class LinkedDeviceInactiveCheckJob private constructor(
}
val devices = try {
AppDependencies.signalServiceAccountManager.devices
AppDependencies
.linkDeviceApi
.getDevices()
.successOrThrow()
.filter { it.id != SignalServiceAddress.DEFAULT_DEVICE_ID }
} catch (e: IOException) {
return Result.retry(defaultBackoff())

View File

@@ -45,29 +45,32 @@ object LinkDeviceRepository {
private val TAG = Log.tag(LinkDeviceRepository::class)
fun removeDevice(deviceId: Int): Boolean {
return try {
val accountManager = AppDependencies.signalServiceAccountManager
accountManager.removeDevice(deviceId)
LinkedDeviceInactiveCheckJob.enqueue()
true
} catch (e: IOException) {
Log.w(TAG, e)
false
return when (val result = AppDependencies.linkDeviceApi.removeDevice(deviceId)) {
is NetworkResult.Success -> {
LinkedDeviceInactiveCheckJob.enqueue()
true
}
else -> {
Log.w(TAG, "Unable to remove device", result.getCause())
false
}
}
}
fun loadDevices(): List<Device>? {
val accountManager = AppDependencies.signalServiceAccountManager
return try {
val devices: List<Device> = accountManager.getDevices()
.filter { d: DeviceInfo -> d.getId() != SignalServiceAddress.DEFAULT_DEVICE_ID }
.map { deviceInfo: DeviceInfo -> deviceInfo.toDevice() }
.sortedBy { it.createdMillis }
.toList()
devices
} catch (e: IOException) {
Log.w(TAG, e)
null
return when (val result = AppDependencies.linkDeviceApi.getDevices()) {
is NetworkResult.Success -> {
result
.result
.filter { d: DeviceInfo -> d.getId() != SignalServiceAddress.DEFAULT_DEVICE_ID }
.map { deviceInfo: DeviceInfo -> deviceInfo.toDevice() }
.sortedBy { it.createdMillis }
.toList()
}
else -> {
Log.w(TAG, "Unable to load device", result.getCause())
null
}
}
}
@@ -132,12 +135,12 @@ object LinkDeviceRepository {
val verificationCodeResult: LinkedDeviceVerificationCodeResponse = when (val result = SignalNetwork.linkDevice.getDeviceVerificationCode()) {
is NetworkResult.Success -> result.result
is NetworkResult.ApplicationError -> throw result.throwable
is NetworkResult.NetworkError -> return LinkDeviceResult.NetworkError
is NetworkResult.NetworkError -> return LinkDeviceResult.NetworkError(result.exception)
is NetworkResult.StatusCodeError -> {
return when (result.code) {
411 -> LinkDeviceResult.LimitExceeded
429 -> LinkDeviceResult.NetworkError
else -> LinkDeviceResult.NetworkError
429 -> LinkDeviceResult.NetworkError(result.exception)
else -> LinkDeviceResult.NetworkError(result.exception)
}
}
}
@@ -171,15 +174,15 @@ object LinkDeviceRepository {
LinkDeviceResult.Success(verificationCodeResult.tokenIdentifier)
}
is NetworkResult.ApplicationError -> throw deviceLinkResult.throwable
is NetworkResult.NetworkError -> LinkDeviceResult.NetworkError
is NetworkResult.NetworkError -> LinkDeviceResult.NetworkError(deviceLinkResult.exception)
is NetworkResult.StatusCodeError -> {
when (deviceLinkResult.code) {
403 -> LinkDeviceResult.NoDevice
409 -> LinkDeviceResult.NoDevice
411 -> LinkDeviceResult.LimitExceeded
422 -> LinkDeviceResult.NetworkError
429 -> LinkDeviceResult.NetworkError
else -> LinkDeviceResult.NetworkError
422 -> LinkDeviceResult.NetworkError(deviceLinkResult.exception)
429 -> LinkDeviceResult.NetworkError(deviceLinkResult.exception)
else -> LinkDeviceResult.NetworkError(deviceLinkResult.exception)
}
}
}
@@ -200,7 +203,7 @@ object LinkDeviceRepository {
Log.d(TAG, "[waitForDeviceToBeLinked] Willing to wait for $timeRemaining ms...")
val result = SignalNetwork.linkDevice.waitForLinkedDevice(
token = token,
timeoutSeconds = timeRemaining.milliseconds.inWholeSeconds.toInt()
timeout = timeRemaining.milliseconds
)
when (result) {
@@ -422,7 +425,7 @@ object LinkDeviceRepository {
data object None : LinkDeviceResult
data class Success(val token: String) : LinkDeviceResult
data object NoDevice : LinkDeviceResult
data object NetworkError : LinkDeviceResult
data class NetworkError(val error: Throwable) : LinkDeviceResult
data object KeyError : LinkDeviceResult
data object LimitExceeded : LinkDeviceResult
data object BadCode : LinkDeviceResult

View File

@@ -288,7 +288,7 @@ class LinkDeviceViewModel : ViewModel() {
Log.d(TAG, "[addDeviceWithSync] Got result: $result")
if (result !is LinkDeviceResult.Success) {
Log.w(TAG, "[addDeviceWithSync] Unable to link device $result")
Log.w(TAG, "[addDeviceWithSync] Unable to link device $result", if (result is LinkDeviceResult.NetworkError) result.error else null)
_state.update {
it.copy(
dialogState = DialogState.None
@@ -377,7 +377,7 @@ class LinkDeviceViewModel : ViewModel() {
}
if (result !is LinkDeviceResult.Success) {
Log.w(TAG, "Unable to link device $result")
Log.w(TAG, "Unable to link device $result", if (result is LinkDeviceResult.NetworkError) result.error else null)
_state.update {
it.copy(
dialogState = DialogState.None

View File

@@ -23,7 +23,7 @@ import androidx.fragment.app.FragmentManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.concurrent.RxExtensions;
import org.signal.core.util.concurrent.JvmRxExtensions;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.concurrent.SimpleTask;
import org.signal.core.util.logging.Log;
@@ -460,7 +460,7 @@ public class CommunicationActions {
SimpleTask.run(() -> {
try {
UsernameLinkConversionResult result = RxExtensions.safeBlockingGet(UsernameRepository.fetchUsernameAndAciFromLink(link));
UsernameLinkConversionResult result = JvmRxExtensions.safeBlockingGet(UsernameRepository.fetchUsernameAndAciFromLink(link));
// TODO we could be better here and report different types of errors to the UI
if (result instanceof UsernameLinkConversionResult.Success success) {