mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-03 20:15:02 +02:00
Refactors Relay class to remove the Synchronized block
This commit is contained in:
@@ -112,7 +112,7 @@ object Client : RelayPool.Listener {
|
|||||||
val relay = Relay(url, true, true, feedTypes ?: emptySet(), HttpClient.getProxy())
|
val relay = Relay(url, true, true, feedTypes ?: emptySet(), HttpClient.getProxy())
|
||||||
RelayPool.addRelay(relay)
|
RelayPool.addRelay(relay)
|
||||||
|
|
||||||
relay.requestAndWatch {
|
relay.connectAndRun {
|
||||||
allSubscriptions().forEach {
|
allSubscriptions().forEach {
|
||||||
relay.sendFilter(requestId = it)
|
relay.sendFilter(requestId = it)
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ import okhttp3.WebSocket
|
|||||||
import okhttp3.WebSocketListener
|
import okhttp3.WebSocketListener
|
||||||
import java.net.Proxy
|
import java.net.Proxy
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
enum class FeedType {
|
enum class FeedType {
|
||||||
FOLLOWS, PUBLIC_CHATS, PRIVATE_DMS, GLOBAL, SEARCH, WALLET_CONNECT
|
FOLLOWS, PUBLIC_CHATS, PRIVATE_DMS, GLOBAL, SEARCH, WALLET_CONNECT
|
||||||
@@ -29,14 +30,16 @@ class Relay(
|
|||||||
var activeTypes: Set<FeedType> = FeedType.values().toSet(),
|
var activeTypes: Set<FeedType> = FeedType.values().toSet(),
|
||||||
proxy: Proxy?
|
proxy: Proxy?
|
||||||
) {
|
) {
|
||||||
val seconds = if (proxy != null) 20L else 10L
|
companion object {
|
||||||
val duration = Duration.ofSeconds(seconds)
|
// waits 3 minutes to reconnect once things fail
|
||||||
|
const val RECONNECTING_IN_SECONDS = 60 * 3
|
||||||
|
}
|
||||||
|
|
||||||
private val httpClient = OkHttpClient.Builder()
|
private val httpClient = OkHttpClient.Builder()
|
||||||
.proxy(proxy)
|
.proxy(proxy)
|
||||||
.readTimeout(duration)
|
.readTimeout(Duration.ofSeconds(if (proxy != null) 20L else 10L))
|
||||||
.connectTimeout(duration)
|
.connectTimeout(Duration.ofSeconds(if (proxy != null) 20L else 10L))
|
||||||
.writeTimeout(duration)
|
.writeTimeout(Duration.ofSeconds(if (proxy != null) 20L else 10L))
|
||||||
.followRedirects(true)
|
.followRedirects(true)
|
||||||
.followSslRedirects(true)
|
.followSslRedirects(true)
|
||||||
.build()
|
.build()
|
||||||
@@ -50,9 +53,9 @@ class Relay(
|
|||||||
|
|
||||||
var spamCounter = 0
|
var spamCounter = 0
|
||||||
var errorCounter = 0
|
var errorCounter = 0
|
||||||
var ping: Long? = null
|
var pingInMs: Long? = null
|
||||||
|
|
||||||
var closingTime = 0L
|
var closingTimeInSeconds = 0L
|
||||||
|
|
||||||
var afterEOSE = false
|
var afterEOSE = false
|
||||||
|
|
||||||
@@ -68,10 +71,8 @@ class Relay(
|
|||||||
return socket != null
|
return socket != null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
fun connect() {
|
||||||
fun requestAndWatch() {
|
connectAndRun {
|
||||||
checkNotInMainThread()
|
|
||||||
requestAndWatch {
|
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
// Sends everything.
|
// Sends everything.
|
||||||
@@ -81,9 +82,16 @@ class Relay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
private var connectingBlock = AtomicBoolean()
|
||||||
fun requestAndWatch(onConnected: (Relay) -> Unit) {
|
|
||||||
|
fun connectAndRun(onConnected: (Relay) -> Unit) {
|
||||||
|
// If there is a connection, don't wait.
|
||||||
|
if (connectingBlock.getAndSet(true)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
if (socket != null) return
|
if (socket != null) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -91,14 +99,24 @@ class Relay(
|
|||||||
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
||||||
.url(url.trim())
|
.url(url.trim())
|
||||||
.build()
|
.build()
|
||||||
val listener = object : WebSocketListener() {
|
|
||||||
|
|
||||||
|
socket = httpClient.newWebSocket(request, RelayListener(onConnected))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
errorCounter++
|
||||||
|
markConnectionAsClosed()
|
||||||
|
Log.e("Relay", "Relay Invalid $url")
|
||||||
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
connectingBlock.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class RelayListener(val onConnected: (Relay) -> Unit) : WebSocketListener() {
|
||||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
afterEOSE = false
|
markConnectionAsReady(response.receivedResponseAtMillis - response.sentRequestAtMillis)
|
||||||
isReady = true
|
|
||||||
ping = response.receivedResponseAtMillis - response.sentRequestAtMillis
|
|
||||||
// Log.w("Relay", "Relay OnOpen, Loading All subscriptions $url")
|
// Log.w("Relay", "Relay OnOpen, Loading All subscriptions $url")
|
||||||
onConnected(this@Relay)
|
onConnected(this@Relay)
|
||||||
|
|
||||||
@@ -111,48 +129,7 @@ class Relay(
|
|||||||
eventDownloadCounterInBytes += text.bytesUsedInMemory()
|
eventDownloadCounterInBytes += text.bytesUsedInMemory()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val msg = Event.gson.fromJson(text, JsonElement::class.java).asJsonArray
|
processNewRelayMessage(text)
|
||||||
val type = msg[0].asString
|
|
||||||
val channel = msg[1].asString
|
|
||||||
|
|
||||||
when (type) {
|
|
||||||
"EVENT" -> {
|
|
||||||
val event = Event.fromJson(msg[2], Client.lenient)
|
|
||||||
|
|
||||||
// Log.w("Relay", "Relay onEVENT $url, $channel")
|
|
||||||
listeners.forEach {
|
|
||||||
it.onEvent(this@Relay, channel, event)
|
|
||||||
if (afterEOSE) {
|
|
||||||
it.onRelayStateChange(this@Relay, Type.EOSE, channel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"EOSE" -> listeners.forEach {
|
|
||||||
afterEOSE = true
|
|
||||||
// Log.w("Relay", "Relay onEOSE $url, $channel")
|
|
||||||
it.onRelayStateChange(this@Relay, Type.EOSE, channel)
|
|
||||||
}
|
|
||||||
"NOTICE" -> listeners.forEach {
|
|
||||||
Log.w("Relay", "Relay onNotice $url, $channel")
|
|
||||||
it.onError(this@Relay, channel, Error("Relay sent notice: " + channel))
|
|
||||||
}
|
|
||||||
"OK" -> listeners.forEach {
|
|
||||||
Log.w("Relay", "Relay on OK $url, ${msg[1].asString}, ${msg[2].asBoolean}, ${msg[3].asString}")
|
|
||||||
it.onSendResponse(this@Relay, msg[1].asString, msg[2].asBoolean, msg[3].asString)
|
|
||||||
}
|
|
||||||
"AUTH" -> listeners.forEach {
|
|
||||||
// Log.w("Relay", "Relay$url, ${msg[1].asString}")
|
|
||||||
it.onAuth(this@Relay, msg[1].asString)
|
|
||||||
}
|
|
||||||
else -> listeners.forEach {
|
|
||||||
// Log.w("Relay", "Relay something else $url, $channel")
|
|
||||||
it.onError(
|
|
||||||
this@Relay,
|
|
||||||
channel,
|
|
||||||
Error("Unknown type $type on channel $channel. Msg was $text")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
t.printStackTrace()
|
t.printStackTrace()
|
||||||
text.chunked(2000) { chunked ->
|
text.chunked(2000) { chunked ->
|
||||||
@@ -176,10 +153,8 @@ class Relay(
|
|||||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
socket = null
|
markConnectionAsClosed()
|
||||||
isReady = false
|
|
||||||
afterEOSE = false
|
|
||||||
closingTime = TimeUtils.now()
|
|
||||||
listeners.forEach { it.onRelayStateChange(this@Relay, Type.DISCONNECT, null) }
|
listeners.forEach { it.onRelayStateChange(this@Relay, Type.DISCONNECT, null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,10 +165,7 @@ class Relay(
|
|||||||
|
|
||||||
socket?.close(1000, "Normal close")
|
socket?.close(1000, "Normal close")
|
||||||
// Failures disconnect the relay.
|
// Failures disconnect the relay.
|
||||||
socket = null
|
markConnectionAsClosed()
|
||||||
isReady = false
|
|
||||||
afterEOSE = false
|
|
||||||
closingTime = TimeUtils.now()
|
|
||||||
|
|
||||||
Log.w("Relay", "Relay onFailure $url, ${response?.message} $response")
|
Log.w("Relay", "Relay onFailure $url, ${response?.message} $response")
|
||||||
t.printStackTrace()
|
t.printStackTrace()
|
||||||
@@ -203,20 +175,67 @@ class Relay(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
socket = httpClient.newWebSocket(request, listener)
|
fun markConnectionAsReady(pingInMs: Long) {
|
||||||
} catch (e: Exception) {
|
this.afterEOSE = false
|
||||||
errorCounter++
|
this.isReady = true
|
||||||
isReady = false
|
this.pingInMs = pingInMs
|
||||||
afterEOSE = false
|
}
|
||||||
closingTime = TimeUtils.now()
|
|
||||||
Log.e("Relay", "Relay Invalid $url")
|
fun markConnectionAsClosed() {
|
||||||
e.printStackTrace()
|
this.socket = null
|
||||||
|
this.isReady = false
|
||||||
|
this.afterEOSE = false
|
||||||
|
this.closingTimeInSeconds = TimeUtils.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processNewRelayMessage(newMessage: String) {
|
||||||
|
val msgArray = Event.gson.fromJson(newMessage, JsonElement::class.java).asJsonArray
|
||||||
|
val type = msgArray[0].asString
|
||||||
|
val channel = msgArray[1].asString
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
"EVENT" -> {
|
||||||
|
val event = Event.fromJson(msgArray[2], Client.lenient)
|
||||||
|
|
||||||
|
// Log.w("Relay", "Relay onEVENT $url, $channel")
|
||||||
|
listeners.forEach {
|
||||||
|
it.onEvent(this@Relay, channel, event)
|
||||||
|
if (afterEOSE) {
|
||||||
|
it.onRelayStateChange(this@Relay, Type.EOSE, channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"EOSE" -> listeners.forEach {
|
||||||
|
afterEOSE = true
|
||||||
|
// Log.w("Relay", "Relay onEOSE $url, $channel")
|
||||||
|
it.onRelayStateChange(this@Relay, Type.EOSE, channel)
|
||||||
|
}
|
||||||
|
"NOTICE" -> listeners.forEach {
|
||||||
|
Log.w("Relay", "Relay onNotice $url, $channel")
|
||||||
|
it.onError(this@Relay, channel, Error("Relay sent notice: " + channel))
|
||||||
|
}
|
||||||
|
"OK" -> listeners.forEach {
|
||||||
|
Log.w("Relay", "Relay on OK $url, ${msgArray[1].asString}, ${msgArray[2].asBoolean}, ${msgArray[3].asString}")
|
||||||
|
it.onSendResponse(this@Relay, msgArray[1].asString, msgArray[2].asBoolean, msgArray[3].asString)
|
||||||
|
}
|
||||||
|
"AUTH" -> listeners.forEach {
|
||||||
|
// Log.w("Relay", "Relay$url, ${msg[1].asString}")
|
||||||
|
it.onAuth(this@Relay, msgArray[1].asString)
|
||||||
|
}
|
||||||
|
else -> listeners.forEach {
|
||||||
|
// Log.w("Relay", "Relay something else $url, $channel")
|
||||||
|
it.onError(
|
||||||
|
this@Relay,
|
||||||
|
channel,
|
||||||
|
Error("Unknown type $type on channel $channel. Msg was $newMessage")
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disconnect() {
|
fun disconnect() {
|
||||||
// httpClient.dispatcher.executorService.shutdown()
|
// httpClient.dispatcher.executorService.shutdown()
|
||||||
closingTime = TimeUtils.now()
|
closingTimeInSeconds = TimeUtils.now()
|
||||||
socket?.close(1000, "Normal close")
|
socket?.close(1000, "Normal close")
|
||||||
socket = null
|
socket = null
|
||||||
isReady = false
|
isReady = false
|
||||||
@@ -241,9 +260,9 @@ class Relay(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// waits 60 seconds to reconnect after disconnected.
|
// waits 60 seconds to reconnect after disconnected.
|
||||||
if (TimeUtils.now() > closingTime + 60) {
|
if (TimeUtils.now() > closingTimeInSeconds + RECONNECTING_IN_SECONDS) {
|
||||||
// sends all filters after connection is successful.
|
// sends all filters after connection is successful.
|
||||||
requestAndWatch()
|
connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,9 +273,9 @@ class Relay(
|
|||||||
|
|
||||||
if (socket == null) {
|
if (socket == null) {
|
||||||
// waits 60 seconds to reconnect after disconnected.
|
// waits 60 seconds to reconnect after disconnected.
|
||||||
if (TimeUtils.now() > closingTime + 60) {
|
if (TimeUtils.now() > closingTimeInSeconds + RECONNECTING_IN_SECONDS) {
|
||||||
// println("sendfilter Only if Disconnected ${url} ")
|
// println("sendfilter Only if Disconnected ${url} ")
|
||||||
requestAndWatch()
|
connect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -51,7 +51,7 @@ object RelayPool : Relay.Listener {
|
|||||||
fun requestAndWatch() {
|
fun requestAndWatch() {
|
||||||
checkNotInMainThread()
|
checkNotInMainThread()
|
||||||
|
|
||||||
relays.forEach { it.requestAndWatch() }
|
relays.forEach { it.connect() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendFilter(subscriptionId: String) {
|
fun sendFilter(subscriptionId: String) {
|
||||||
|
Reference in New Issue
Block a user