Sync disabled by default.

This commit is contained in:
Koen J 2025-05-05 12:00:04 +02:00
commit e12b500144
4 changed files with 200 additions and 123 deletions

View file

@ -926,7 +926,7 @@ class Settings : FragmentedStorageFileJson() {
@Serializable
class Synchronization {
@FormField(R.string.enabled, FieldForm.TOGGLE, R.string.enabled_description, 1)
var enabled: Boolean = true;
var enabled: Boolean = false;
@FormField(R.string.broadcast, FieldForm.TOGGLE, R.string.broadcast_description, 1)
var broadcast: Boolean = false;

View file

@ -89,6 +89,14 @@ class SyncHomeActivity : AppCompatActivity() {
updateEmptyVisibility()
}
}
StateSync.instance.confirmStarted(this, {
StateSync.instance.showFailedToBindDialogIfNecessary(this@SyncHomeActivity)
}, {
finish()
}, {
StateSync.instance.showFailedToBindDialogIfNecessary(this@SyncHomeActivity)
})
}
override fun onDestroy() {

View file

@ -29,6 +29,7 @@ import com.futo.platformplayer.activities.CaptchaActivity
import com.futo.platformplayer.activities.IWithResultLauncher
import com.futo.platformplayer.activities.MainActivity
import com.futo.platformplayer.activities.SettingsActivity
import com.futo.platformplayer.activities.SettingsActivity.Companion.settingsActivityClosed
import com.futo.platformplayer.api.media.platforms.js.DevJSClient
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.background.BackgroundWorker
@ -411,7 +412,27 @@ class StateApp {
}
if (Settings.instance.synchronization.enabled) {
StateSync.instance.start(context)
StateSync.instance.start(context, {
try {
UIDialogs.toast("Failed to start sync, port in use")
} catch (e: Throwable) {
//Ignored
}
})
}
settingsActivityClosed.subscribe {
if (Settings.instance.synchronization.enabled) {
StateSync.instance.start(context, {
try {
UIDialogs.toast("Failed to start sync, port in use")
} catch (e: Throwable) {
//Ignored
}
})
} else {
StateSync.instance.stop()
}
}
Logger.onLogSubmitted.subscribe {
@ -707,6 +728,7 @@ class StateApp {
StatePlayer.instance.closeMediaSession();
StateCasting.instance.stop();
StateSync.instance.stop();
StatePlayer.dispose();
Companion.dispose();
_fileLogConsumer?.close();

View file

@ -7,6 +7,7 @@ import android.os.Build
import android.util.Log
import com.futo.platformplayer.LittleEndianDataInputStream
import com.futo.platformplayer.LittleEndianDataOutputStream
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.activities.MainActivity
@ -77,10 +78,11 @@ class StateSync {
private var _serverSocket: ServerSocket? = null
private var _thread: Thread? = null
private var _connectThread: Thread? = null
private var _started = false
@Volatile private var _started = false
private val _sessions: MutableMap<String, SyncSession> = mutableMapOf()
private val _lastConnectTimesMdns: MutableMap<String, Long> = mutableMapOf()
private val _lastConnectTimesIp: MutableMap<String, Long> = mutableMapOf()
private var _serverStarted = false
//TODO: Should sync mdns and casting mdns be merged?
//TODO: Decrease interval that devices are updated
//TODO: Send less data
@ -91,48 +93,7 @@ class StateSync {
private var _threadRelay: Thread? = null
private val _remotePendingStatusUpdate = mutableMapOf<String, (complete: Boolean?, message: String) -> Unit>()
private var _nsdManager: NsdManager? = null
private val _registrationListener = object : NsdManager.RegistrationListener {
override fun onServiceRegistered(serviceInfo: NsdServiceInfo) {
Log.v(TAG, "onServiceRegistered: ${serviceInfo.serviceName}")
}
override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
Log.v(TAG, "onRegistrationFailed: ${serviceInfo.serviceName} (error code: $errorCode)")
}
override fun onServiceUnregistered(serviceInfo: NsdServiceInfo) {
Log.v(TAG, "onServiceUnregistered: ${serviceInfo.serviceName}")
}
override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
Log.v(TAG, "onUnregistrationFailed: ${serviceInfo.serviceName} (error code: $errorCode)")
}
}
var keyPair: DHState? = null
var publicKey: String? = null
val deviceRemoved: Event1<String> = Event1()
val deviceUpdatedOrAdded: Event2<String, SyncSession> = Event2()
//TODO: Should authorize acknowledge be implemented?
fun hasAuthorizedDevice(): Boolean {
synchronized(_sessions) {
return _sessions.any{ it.value.connected && it.value.isAuthorized };
}
}
fun start(context: Context) {
if (_started) {
Logger.i(TAG, "Already started.")
return
}
_started = true
_nsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager
if (Settings.instance.synchronization.connectDiscovered) {
_nsdManager?.apply {
discoverServices("_gsync._tcp", NsdManager.PROTOCOL_DNS_SD, object : NsdManager.DiscoveryListener {
private var _discoveryListener: NsdManager.DiscoveryListener = object : NsdManager.DiscoveryListener {
override fun onDiscoveryStarted(regType: String) {
Log.d(TAG, "Service discovery started for $regType")
}
@ -241,7 +202,50 @@ class StateSync {
})
}
}
})
}
private val _registrationListener = object : NsdManager.RegistrationListener {
override fun onServiceRegistered(serviceInfo: NsdServiceInfo) {
Log.v(TAG, "onServiceRegistered: ${serviceInfo.serviceName}")
}
override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
Log.v(TAG, "onRegistrationFailed: ${serviceInfo.serviceName} (error code: $errorCode)")
}
override fun onServiceUnregistered(serviceInfo: NsdServiceInfo) {
Log.v(TAG, "onServiceUnregistered: ${serviceInfo.serviceName}")
}
override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {
Log.v(TAG, "onUnregistrationFailed: ${serviceInfo.serviceName} (error code: $errorCode)")
}
}
var keyPair: DHState? = null
var publicKey: String? = null
val deviceRemoved: Event1<String> = Event1()
val deviceUpdatedOrAdded: Event2<String, SyncSession> = Event2()
//TODO: Should authorize acknowledge be implemented?
fun hasAuthorizedDevice(): Boolean {
synchronized(_sessions) {
return _sessions.any{ it.value.connected && it.value.isAuthorized };
}
}
fun start(context: Context, onServerBindFail: () -> Unit) {
if (_started) {
Logger.i(TAG, "Already started.")
return
}
_started = true
_nsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager
if (Settings.instance.synchronization.connectDiscovered) {
_nsdManager?.apply {
discoverServices("_gsync._tcp", NsdManager.PROTOCOL_DNS_SD, _discoveryListener)
}
}
@ -292,6 +296,7 @@ class StateSync {
Logger.i(TAG, "Sync key pair initialized (public key = ${publicKey})")
_serverStarted = true
_thread = Thread {
try {
val serverSocket = ServerSocket(PORT)
@ -305,8 +310,13 @@ class StateSync {
session.startAsResponder()
}
} catch (e: Throwable) {
_serverStarted = false
Logger.e(TAG, "Failed to bind server socket to port ${PORT}", e)
UIDialogs.toast("Failed to start sync, port in use")
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
onServerBindFail.invoke()
}
} finally {
_serverStarted = false
}
}.apply { start() }
@ -479,6 +489,31 @@ class StateSync {
}
}
fun showFailedToBindDialogIfNecessary(context: Context) {
if (!_serverStarted) {
try {
UIDialogs.showDialogOk(context, R.drawable.ic_warning, "Local discovery unavailable, port was in use")
} catch (e: Throwable) {
//Ignored
}
}
}
fun confirmStarted(context: Context, onStarted: () -> Unit, onNotStarted: () -> Unit, onServerBindFail: () -> Unit) {
if (!_started) {
UIDialogs.showConfirmationDialog(context, "Sync has not been enabled yet, would you like to enable sync?", {
Settings.instance.synchronization.enabled = true
StateSync.instance.start(context, onServerBindFail)
Settings.instance.save()
onStarted.invoke()
}, {
onNotStarted.invoke()
})
} else {
onStarted.invoke()
}
}
private fun getDeviceName(): String {
val manufacturer = Build.MANUFACTURER.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
val model = Build.MODEL
@ -1034,19 +1069,31 @@ class StateSync {
fun stop() {
_started = false
_nsdManager?.unregisterService(_registrationListener)
try {
_nsdManager?.stopServiceDiscovery(_discoveryListener)
} catch (e: Throwable) {
Logger.e(TAG, "Failed to stop discovery listener", e)
}
try {
_nsdManager?.unregisterService(_registrationListener)
} catch (e: Throwable) {
Logger.e(TAG, "Failed to unregister service", e)
}
_relaySession?.stop()
_serverSocket?.close()
_serverSocket = null
_thread?.interrupt()
_thread = null
_connectThread?.interrupt()
_connectThread = null
_threadRelay?.interrupt()
_threadRelay = null
synchronized(_sessions) {
_sessions.values.forEach { it.close() }
_sessions.clear()
}
_relaySession?.stop()
_thread = null
_connectThread = null
_threadRelay = null
_relaySession = null
}