forked from hush/SilentDragonAndroid-old
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
10 KiB
269 lines
10 KiB
// Copyright 2019-2020 The Hush developers
|
|
// Released under the GPLv3
|
|
package org.myhush.silentdragon
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.res.Resources
|
|
import android.util.Log
|
|
import com.beust.klaxon.Json
|
|
import com.beust.klaxon.JsonObject
|
|
import com.beust.klaxon.json
|
|
import okhttp3.*
|
|
import okio.ByteString
|
|
import org.json.JSONObject
|
|
import java.lang.Exception
|
|
import java.net.ConnectException
|
|
import java.util.*
|
|
import java.util.concurrent.TimeUnit
|
|
import kotlin.collections.HashMap
|
|
|
|
|
|
object ConnectionManager {
|
|
|
|
val DATA_SIGNAL: String = "ConnectionManager_NewData_Signal"
|
|
|
|
/**
|
|
* Refresh all data, including attempting a connection if none exists
|
|
*/
|
|
fun refreshAllData() {
|
|
// First, try to make a connection.
|
|
makeConnection()
|
|
initCurrencies()
|
|
}
|
|
|
|
// Attempt a connection to the server. If there is no saved connection, we'll set the connection status
|
|
// to None
|
|
private fun makeConnection(directConn : Boolean = true) {
|
|
val connString =
|
|
DataModel.getConnString(SilentDragonApp.appContext!!)
|
|
if (connString.isNullOrBlank()) {
|
|
// The user might have just disconnected, so make sure we are disconnected
|
|
|
|
DataModel.ws?.close(1000, "disconnected")
|
|
sendUpdateDataSignal(true)
|
|
return
|
|
}
|
|
|
|
println("MakeConnection")
|
|
|
|
// If still connecting, this is a duplicate call, so do nothing but wait.
|
|
if (DataModel.connStatus == DataModel.ConnectionStatus.CONNECTING) {
|
|
return
|
|
}
|
|
|
|
// If already connected, then refresh data
|
|
if (DataModel.connStatus == DataModel.ConnectionStatus.CONNECTED) {
|
|
DataModel.makeAPICalls()
|
|
return
|
|
}
|
|
|
|
println("Attempting new connection ${DataModel.connStatus}")
|
|
sendRefreshSignal(false)
|
|
|
|
// If direct connection, then connect to the URL in connection string
|
|
if (directConn) {
|
|
// Update status to connecting, so we can update the UI
|
|
DataModel.connStatus =
|
|
DataModel.ConnectionStatus.CONNECTING
|
|
println("Connstatus = connecting")
|
|
|
|
val client = OkHttpClient.Builder().connectTimeout(2, TimeUnit.SECONDS).build()
|
|
val request = Request.Builder().url(connString).build()
|
|
val listener = WebsocketClient(true)
|
|
|
|
DataModel.ws = client.newWebSocket(request, listener)
|
|
} else {
|
|
// Connect to the wormhole
|
|
DataModel.connStatus =
|
|
DataModel.ConnectionStatus.CONNECTING
|
|
|
|
println("Connstatus = connecting")
|
|
|
|
val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).build()
|
|
val request = Request.Builder().url("wss://wormhole.myhush.org:443").build()
|
|
//val request = Request.Builder().url("ws://192.168.5.187:7070").build()
|
|
val listener = WebsocketClient(false)
|
|
|
|
DataModel.ws = client.newWebSocket(request, listener)
|
|
}
|
|
}
|
|
|
|
fun closeConnection() {
|
|
DataModel.ws?.close(1000, "Close requested")
|
|
}
|
|
|
|
fun sendRefreshSignal(finished: Boolean) {
|
|
val i = Intent(DATA_SIGNAL)
|
|
i.putExtra("action", "refresh")
|
|
i.putExtra("finished", finished)
|
|
SilentDragonApp.appContext?.sendBroadcast(i)
|
|
}
|
|
|
|
fun sendUpdateDataSignal(updateTxns: Boolean = false) {
|
|
val i = Intent(DATA_SIGNAL)
|
|
i.putExtra("action", "newdata")
|
|
i.putExtra("updateTxns", updateTxns)
|
|
SilentDragonApp.appContext?.sendBroadcast(i)
|
|
}
|
|
|
|
fun sendErrorSignal(msg: String? = null, doDisconnect: Boolean = false) {
|
|
val i = Intent(DATA_SIGNAL)
|
|
i.putExtra("action", "error")
|
|
i.putExtra("msg", msg)
|
|
i.putExtra("doDisconnect", doDisconnect)
|
|
SilentDragonApp.appContext?.sendBroadcast(i)
|
|
}
|
|
fun initCurrencies(){
|
|
try {
|
|
DataModel.currencySymbols["AUD"] = "$"
|
|
DataModel.currencySymbols["BTC"] = "BTC"
|
|
DataModel.currencySymbols["CAD"] = "$"
|
|
DataModel.currencySymbols["CNY"] = "¥"
|
|
DataModel.currencySymbols["EUR"] = "€"
|
|
DataModel.currencySymbols["GBP"] = "£"
|
|
DataModel.currencySymbols["JPY"] = "¥"
|
|
DataModel.currencySymbols["KRW"] = "₩"
|
|
DataModel.currencySymbols["MXN"] = "$"
|
|
DataModel.currencySymbols["MYR"] = "RM"
|
|
DataModel.currencySymbols["PHP"] = "₱"
|
|
DataModel.currencySymbols["PKR"] = "₨"
|
|
DataModel.currencySymbols["RUB"] = "₽"
|
|
DataModel.currencySymbols["SGD"] = "$"
|
|
DataModel.currencySymbols["THB"] = "฿"
|
|
DataModel.currencySymbols["USD"] = "$"
|
|
DataModel.currencySymbols["VEF"] = "Bs"
|
|
DataModel.currencySymbols["VND"] = "₫"
|
|
DataModel.currencySymbols["XAG"] = "XAG"
|
|
DataModel.currencySymbols["XAU"] = "XAU"
|
|
DataModel.currencySymbols["ZAR"] = "R"
|
|
|
|
Thread {
|
|
val client = OkHttpClient()
|
|
val currencies = "usd,eur,jpy,btc,cny,rub,cad,sgd,chf,inr,gbp,aud,pkr,mxn,php,vnd,thb,zar,krw,myr,vef,xau,xag"
|
|
val request: Request = Request.Builder()
|
|
.url("https://api.coingecko.com/api/v3/simple/price?ids=hush&vs_currencies=${currencies}")
|
|
.build()
|
|
val response: Response = client.newCall(request).execute()
|
|
val json: JSONObject = JSONObject(response.body()?.string() as @NonNull String)["hush"] as JSONObject
|
|
|
|
if (json.length() > 0){
|
|
for (cur: String in json.keys()){
|
|
DataModel.currencyValues[cur.toUpperCase()] = json.getDouble(cur)
|
|
if(!DataModel.currencySymbols.containsKey(cur.toUpperCase()))
|
|
DataModel.currencySymbols[cur.toUpperCase()] = cur.toUpperCase()
|
|
}
|
|
}
|
|
}.start()
|
|
|
|
|
|
|
|
}catch (e: Exception){
|
|
e.printStackTrace()
|
|
}
|
|
}
|
|
|
|
private class WebsocketClient (directConn: Boolean) : WebSocketListener() {
|
|
val m_directConn = directConn
|
|
val TAG = "WebsocketClient"
|
|
|
|
override fun onOpen(webSocket: WebSocket, response: Response) {
|
|
Log.d(TAG, "Opened Websocket")
|
|
DataModel.connStatus =
|
|
DataModel.ConnectionStatus.CONNECTED
|
|
println("Connstatus = connected")
|
|
|
|
// If direct connection, start making API calls to get data.
|
|
if (m_directConn) {
|
|
DataModel.makeAPICalls()
|
|
} else {
|
|
// If this is a connection to wormhole, we have to register ourselves before we make any API calls
|
|
if (!DataModel.getWormholeCode().isNullOrBlank()) {
|
|
webSocket.send( json { obj( "register" to DataModel.getWormholeCode()) }.toJsonString())
|
|
|
|
// Delay sending the API calls a bit to let the register call finish
|
|
Timer().schedule(object : TimerTask() {
|
|
override fun run() {
|
|
DataModel.makeAPICalls()
|
|
}}, 100)
|
|
}
|
|
}
|
|
|
|
sendUpdateDataSignal()
|
|
}
|
|
|
|
override fun onMessage(webSocket: WebSocket?, text: String?) {
|
|
Log.i(TAG, "Receiving $text")
|
|
|
|
val r = DataModel.parseResponse(text!!)
|
|
|
|
if (r.displayMsg != null) {
|
|
sendErrorSignal(
|
|
r.displayMsg,
|
|
r.doDisconnect
|
|
)
|
|
|
|
if (r.doDisconnect) {
|
|
// We don't pass a reason here, because we already sent the error signal above
|
|
webSocket?.close(1000, null)
|
|
}
|
|
|
|
} else {
|
|
sendUpdateDataSignal(r.updateTxns)
|
|
sendRefreshSignal(r.updateTxns)
|
|
}
|
|
}
|
|
|
|
override fun onMessage(webSocket: WebSocket?, bytes: ByteString) {
|
|
Log.i(TAG, "Receiving bytes : " + bytes.hex())
|
|
}
|
|
|
|
override fun onClosing(webSocket: WebSocket, code: Int, reason: String?) {
|
|
DataModel.connStatus =
|
|
DataModel.ConnectionStatus.DISCONNECTED
|
|
println("Connstatus = disconnected")
|
|
|
|
Log.i(TAG,"Closing : $code / $reason")
|
|
//if (!reason.isNullOrEmpty()) {
|
|
// sendErrorSignal(reason, true)
|
|
//}
|
|
sendRefreshSignal(true)
|
|
}
|
|
|
|
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
|
Log.e(TAG,"Failed $t")
|
|
DataModel.connStatus =
|
|
DataModel.ConnectionStatus.DISCONNECTED
|
|
|
|
val allowInternet = DataModel.getAllowInternet() && DataModel.getGlobalAllowInternet()
|
|
|
|
// If the connection is direct, and there is no need to further connect, so just error out
|
|
if (t is ConnectException && (m_directConn && !allowInternet)) {
|
|
var mesg = t.localizedMessage
|
|
if (!DataModel.getAllowInternet()) {
|
|
mesg += ": " + SilentDragonApp.appContext!!.getString(R.string.Connecting_over_internet_not_enabled_in_desktop_node)
|
|
} else if (!DataModel.getGlobalAllowInternet()) {
|
|
mesg += ": " + SilentDragonApp.appContext!!.getString(R.string.Connecting_over_internet_is_disabled_in_settings)
|
|
}
|
|
|
|
sendErrorSignal(mesg, true)
|
|
sendRefreshSignal(true)
|
|
return
|
|
}
|
|
|
|
// If this was a direct connection and there was a failure to connect, retry connecting
|
|
// without the direct connection (i.e., through wormhole)
|
|
if (m_directConn && allowInternet) {
|
|
makeConnection(false)
|
|
} else {
|
|
// Not a direct connection (or we're not allowed to connect to internet) and there was a failure.
|
|
sendErrorSignal(
|
|
t.localizedMessage,
|
|
true
|
|
)
|
|
sendRefreshSignal(true)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|