Commit e466af1c authored by Grisha Kruglov's avatar Grisha Kruglov
Browse files

Part 1: Add SyncEngine to account manager's public API

Preparatory work for allowing users to choose what to sync. We are about to
tie SyncConfig with FxA's "capabilities" webchannel API, which takes a set of
"engines" as strings. To simplify our integration work, this patch replaces an
untyped set of "stores" with a typed set of "engines" at the API level.
parent 9299f035
......@@ -33,11 +33,20 @@ data class DeviceConfig(
/**
* Configuration for sync.
*
* @property syncableStores A set of store names to sync, exposed via [GlobalSyncableStoreProvider].
* @property supportedEngines A set of supported sync engines, exposed via [GlobalSyncableStoreProvider].
* @property syncPeriodInMinutes Optional, how frequently periodic sync should happen. If this is `null`,
* periodic syncing will be disabled.
*/
data class SyncConfig(
val syncableStores: Set<String>,
val supportedEngines: Set<SyncEngine>,
val syncPeriodInMinutes: Long? = null
)
/**
* Describes possible sync engines that device can support.
*/
enum class SyncEngine {
History,
Bookmarks,
Passwords,
}
......@@ -65,3 +65,20 @@ fun handleFxaExceptions(logger: Logger, operation: String, block: () -> Unit): B
true
})
}
/**
* Internally, Rust SyncManager represents engines as strings. Forward-compatibility with new engines
* is one of the reasons for this. E.g. during any sync, an engine may appear that we do not know about.
* At the public API level, we expose a concrete [SyncEngine] type to allow for more robust integrations.
* We do not expose "unknown" engines via our public API, but do handle them internally (by persisting
* their enabled/disabled status). Since unknown engines are not exposed to the application, this
* conversion only needs to go one-way.
*/
fun SyncEngine.toNativeString(): String {
return when (this) {
SyncEngine.History -> "history"
SyncEngine.Bookmarks -> "bookmarks"
SyncEngine.Passwords -> "passwords"
}
}
......@@ -291,8 +291,8 @@ open class FxaAccountManager(
val result = CompletableDeferred<Unit>()
// Initialize a new sync manager with the passed-in config.
if (config.syncableStores.isEmpty()) {
throw IllegalArgumentException("Set of stores can't be empty")
if (config.supportedEngines.isEmpty()) {
throw IllegalArgumentException("Set of supported engines can't be empty")
}
syncManager = createSyncManager(config).also { manager ->
......
......@@ -6,6 +6,7 @@ package mozilla.components.service.fxa.sync
import mozilla.components.concept.sync.SyncableStore
import mozilla.components.service.fxa.SyncConfig
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.base.observer.Observable
import mozilla.components.support.base.observer.ObserverRegistry
......@@ -136,7 +137,7 @@ abstract class SyncManager(
*/
internal fun start() = synchronized(this) {
logger.debug("Enabling...")
syncDispatcher = initDispatcher(newDispatcher(syncDispatcher, syncConfig.syncableStores))
syncDispatcher = initDispatcher(newDispatcher(syncDispatcher, syncConfig.supportedEngines))
logger.debug("set and initialized new dispatcher: $syncDispatcher")
}
......@@ -151,13 +152,13 @@ abstract class SyncManager(
syncDispatcher = null
}
internal abstract fun createDispatcher(stores: Set<String>): SyncDispatcher
internal abstract fun createDispatcher(supportedEngines: Set<SyncEngine>): SyncDispatcher
internal abstract fun dispatcherUpdated(dispatcher: SyncDispatcher)
private fun newDispatcher(
currentDispatcher: SyncDispatcher?,
stores: Set<String>
supportedEngines: Set<SyncEngine>
): SyncDispatcher {
// Let the existing dispatcher, if present, cleanup.
currentDispatcher?.close()
......@@ -166,7 +167,7 @@ abstract class SyncManager(
currentDispatcher?.unregister(dispatcherStatusObserver)
// Create a new dispatcher bound to current stores and account.
return createDispatcher(stores)
return createDispatcher(supportedEngines)
}
private fun initDispatcher(dispatcher: SyncDispatcher): SyncDispatcher {
......
......@@ -23,7 +23,9 @@ import mozilla.components.concept.sync.AuthException
import mozilla.components.concept.sync.SyncStatus
import mozilla.components.service.fxa.SyncAuthInfoCache
import mozilla.components.service.fxa.SyncConfig
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.authErrorRegistry
import mozilla.components.service.fxa.toNativeString
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.base.observer.Observable
import mozilla.components.support.base.observer.ObserverRegistry
......@@ -61,8 +63,8 @@ internal class WorkManagerSyncManager(syncConfig: SyncConfig) : SyncManager(sync
}
}
override fun createDispatcher(stores: Set<String>): SyncDispatcher {
return WorkManagerSyncDispatcher(stores)
override fun createDispatcher(supportedEngines: Set<SyncEngine>): SyncDispatcher {
return WorkManagerSyncDispatcher(supportedEngines)
}
override fun dispatcherUpdated(dispatcher: SyncDispatcher) {
......@@ -108,7 +110,7 @@ object WorkersLiveDataObserver {
}
class WorkManagerSyncDispatcher(
private val stores: Set<String>
private val supportedEngines: Set<SyncEngine>
) : SyncDispatcher, Observable<SyncStatusObserver> by ObserverRegistry(), Closeable {
private val logger = Logger("WMSyncDispatcher")
......@@ -215,7 +217,9 @@ class WorkManagerSyncDispatcher(
}
private fun getWorkerData(): Data {
val dataBuilder = Data.Builder().putStringArray(KEY_DATA_STORES, stores.toTypedArray())
val dataBuilder = Data.Builder().putStringArray(
KEY_DATA_STORES, supportedEngines.map { it.toNativeString() }.toTypedArray()
)
return dataBuilder.build()
}
......@@ -264,8 +268,7 @@ class WorkManagerSyncWorker(
val resultBuilder = Data.Builder()
syncResult.forEach {
val status = it.value.status
when (status) {
when (val status = it.value.status) {
SyncStatus.Ok -> {
logger.info("Synchronized store ${it.key}")
resultBuilder.putBoolean(it.key, true)
......
......@@ -211,7 +211,7 @@ class FxaAccountManagerTest {
val dispatcher: TestSyncDispatcher = TestSyncDispatcher(dispatcherRegistry)
private var dispatcherUpdatedCount = 0
override fun createDispatcher(stores: Set<String>): SyncDispatcher {
override fun createDispatcher(supportedEngines: Set<SyncEngine>): SyncDispatcher {
return dispatcher
}
......@@ -299,7 +299,7 @@ class FxaAccountManagerTest {
assertEquals(0, syncStatusObserver.onErrorCount)
// No periodic sync.
manager.setSyncConfigAsync(SyncConfig(setOf("history"))).await()
manager.setSyncConfigAsync(SyncConfig(setOf(SyncEngine.History))).await()
assertNotNull(latestSyncManager)
assertNotNull(latestSyncManager?.dispatcher)
......@@ -309,7 +309,7 @@ class FxaAccountManagerTest {
verify(latestSyncManager!!.dispatcher.inner, times(1)).syncNow(anyBoolean(), anyBoolean())
// With periodic sync.
manager.setSyncConfigAsync(SyncConfig(setOf("history"), 60 * 1000L)).await()
manager.setSyncConfigAsync(SyncConfig(setOf(SyncEngine.History), 60 * 1000L)).await()
verify(latestSyncManager!!.dispatcher.inner, times(1)).startPeriodicSync(any(), anyLong())
verify(latestSyncManager!!.dispatcher.inner, never()).stopPeriodicSync()
......@@ -354,7 +354,7 @@ class FxaAccountManagerTest {
// With a sync config this time.
var latestSyncManager: TestSyncManager? = null
val syncConfig = SyncConfig(setOf("history"), syncPeriodInMinutes = 120L)
val syncConfig = SyncConfig(setOf(SyncEngine.History), syncPeriodInMinutes = 120L)
val manager = object : TestableFxaAccountManager(
context = testContext,
config = ServerConfig.release("dummyId", "http://auth-url/redirect"),
......@@ -423,7 +423,7 @@ class FxaAccountManagerTest {
// assertEquals(1, syncStatusObserver.onErrorCount)
// Turn off periodic syncing.
manager.setSyncConfigAsync(SyncConfig(setOf("history"))).await()
manager.setSyncConfigAsync(SyncConfig(setOf(SyncEngine.History))).await()
verify(latestSyncManager!!.dispatcher.inner, never()).startPeriodicSync(any(), anyLong())
verify(latestSyncManager!!.dispatcher.inner, never()).stopPeriodicSync()
......
......@@ -188,4 +188,11 @@ class UtilsKtTest {
throw FxaPanicException("dunno")
}
}
@Test
fun `sync engine native name conversions`() {
assertEquals("passwords", SyncEngine.Passwords.toNativeString())
assertEquals("history", SyncEngine.History.toNativeString())
assertEquals("bookmarks", SyncEngine.Bookmarks.toNativeString())
}
}
\ No newline at end of file
......@@ -44,6 +44,9 @@ permalink: /changelog/
* **browser-engine-servo**
* ❌ We removed the `browser-engine-servo` component since it was not being maintained, updated and used.
* **service-firefox-accounts**
* ⚠️ **This is a breaking change**: `SyncConfig`'s `syncableStores` has been renamed to `supportedEngines`, expressed via new enum type `SyncEngine`.
# 11.0.0
* [Commits](https://github.com/mozilla-mobile/android-components/compare/v10.0.0...v11.0.0)
......
......@@ -26,6 +26,7 @@ import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.DeviceConfig
import mozilla.components.service.fxa.ServerConfig
import mozilla.components.service.fxa.SyncConfig
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider
import mozilla.components.service.fxa.sync.SyncStatusObserver
import mozilla.components.service.sync.logins.AsyncLoginsStorageAdapter
......@@ -62,7 +63,7 @@ class MainActivity : AppCompatActivity(), LoginFragment.OnLoginCompleteListener,
applicationContext,
ServerConfig.release(CLIENT_ID, REDIRECT_URL),
DeviceConfig("A-C Logins Sync Sample", DeviceType.MOBILE, setOf()),
SyncConfig(setOf("logins"))
SyncConfig(setOf(SyncEngine.Passwords))
)
}
......
......@@ -37,6 +37,7 @@ import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider
import mozilla.components.service.fxa.sync.SyncStatusObserver
import mozilla.components.support.base.log.Log
import mozilla.components.lib.fetch.httpurlconnection.HttpURLConnectionClient
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.support.base.log.sink.AndroidLogSink
import mozilla.components.support.rusthttp.RustHttpConfig
import mozilla.components.support.rustlog.RustLog
......@@ -70,7 +71,7 @@ class MainActivity :
type = DeviceType.MOBILE,
capabilities = setOf(DeviceCapability.SEND_TAB)
),
SyncConfig(setOf("history", "bookmarks"), syncPeriodInMinutes = 15L)
SyncConfig(setOf(SyncEngine.History, SyncEngine.Bookmarks), syncPeriodInMinutes = 15L)
)
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment