SocketClient.kt 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. package com.example.modifier.service
  2. import android.os.Build
  3. import android.util.Log
  4. import com.example.modifier.BuildConfig
  5. import com.example.modifier.baseTag
  6. import com.example.modifier.enums.ReqState
  7. import com.example.modifier.model.CancelStoreNumberAction
  8. import com.example.modifier.model.CheckPifAction
  9. import com.example.modifier.model.CleanBackupAction
  10. import com.example.modifier.model.InstallApkAction
  11. import com.example.modifier.model.ResumeAction
  12. import com.example.modifier.model.RunScriptAction
  13. import com.example.modifier.model.RunScriptResult
  14. import com.example.modifier.model.SocketCallback
  15. import com.example.modifier.model.StoreNumberAction
  16. import com.example.modifier.model.TaskAction
  17. import com.example.modifier.model.TaskExecutionResult
  18. import com.example.modifier.model.UpdateDeviceAction
  19. import com.example.modifier.repo.AppPrefsRepo
  20. import com.example.modifier.repo.AppStateRepo
  21. import com.example.modifier.repo.SpoofedInfoRepo
  22. import com.example.modifier.serializer.Json
  23. import com.example.modifier.utils.checkPif
  24. import com.example.modifier.utils.getIPAddress
  25. import io.socket.client.IO
  26. import io.socket.client.Socket
  27. import io.socket.emitter.Emitter
  28. import kotlinx.coroutines.CoroutineScope
  29. import kotlinx.coroutines.Dispatchers
  30. import kotlinx.coroutines.delay
  31. import kotlinx.coroutines.launch
  32. import kotlinx.serialization.encodeToString
  33. import org.json.JSONObject
  34. import java.util.Timer
  35. import kotlin.concurrent.schedule
  36. class SocketClient(
  37. private val taskRunner: TaskRunner
  38. ) : Emitter.Listener {
  39. companion object {
  40. private const val TAG = "$baseTag/SocketClient"
  41. }
  42. private val mSocketOpts: IO.Options = IO.Options()
  43. private val mSocket: Socket
  44. init {
  45. val appPrefs = AppPrefsRepo.instance.appPrefs.value
  46. mSocketOpts.query =
  47. "model=${Build.MODEL}&name=${appPrefs.name}&id=${appPrefs.id}&version=${BuildConfig.VERSION_CODE}&ip=${
  48. getIPAddress().joinToString(",")
  49. }}"
  50. mSocketOpts.transports = arrayOf("websocket")
  51. mSocket = IO.socket(appPrefs.server, mSocketOpts)
  52. mSocket.on("message", this)
  53. mSocket.on(Socket.EVENT_CONNECT) { this.onConnected(it) }
  54. mSocket.on(Socket.EVENT_DISCONNECT) { this.onDisconnected(it) }
  55. mSocket.on(Socket.EVENT_CONNECT_ERROR) {
  56. it.forEach {
  57. Log.e(TAG, "Connection error", it as Throwable)
  58. }
  59. }
  60. try {
  61. mSocket.connect()
  62. } catch (e: Exception) {
  63. Log.e(TAG, "connect error", e)
  64. }
  65. val timer = Timer()
  66. timer.schedule(0, 3000) {
  67. reportDeviceStatues()
  68. }
  69. }
  70. fun disconnect() {
  71. mSocket.off()
  72. mSocket.disconnect()
  73. }
  74. private fun throwIfBusy() {
  75. if (AppStateRepo.instance.appState.value.busy) {
  76. throw Exception("Device is busy")
  77. }
  78. }
  79. override fun call(vararg args: Any?) {
  80. if (args.isEmpty()) {
  81. return
  82. }
  83. Log.i(TAG, "Received message: " + args[0])
  84. if (args[0] !is JSONObject) return
  85. val json = args[0] as JSONObject
  86. val action = json.optString("action")
  87. val id = json.optString("id")
  88. val jsonStr = json.toString()
  89. when (action) {
  90. TaskAction.NAME -> {
  91. try {
  92. throwIfBusy()
  93. val taskAction = Json.decodeFromString<TaskAction>(jsonStr)
  94. CoroutineScope(Dispatchers.IO).launch {
  95. taskRunner.runTask(taskAction, onSuccess = { res ->
  96. socketCallback(taskAction.id, res)
  97. }, onError = { error ->
  98. socketCallback(
  99. id = taskAction.id,
  100. status = -1,
  101. error = error.message
  102. )
  103. })
  104. }
  105. } catch (e: Exception) {
  106. Log.e(TAG, "taskAction error", e)
  107. socketCallback(id = id, status = -1, error = e.message)
  108. }
  109. }
  110. InstallApkAction.NAME -> {
  111. try {
  112. val installApkAction = Json.decodeFromString<InstallApkAction>(jsonStr)
  113. if (true != installApkAction.data.interrupt) {
  114. throwIfBusy()
  115. }
  116. CoroutineScope(Dispatchers.IO).launch {
  117. taskRunner.installApk(installApkAction, onSuccess = {
  118. socketCallback(
  119. id = installApkAction.id,
  120. status = 0,
  121. data = "OK"
  122. )
  123. }, onError = { error ->
  124. socketCallback(
  125. id = installApkAction.id,
  126. status = -1,
  127. error = error.message
  128. )
  129. })
  130. }
  131. } catch (e: Exception) {
  132. Log.e(TAG, "installApk error", e)
  133. socketCallback(id = id, status = -1, error = e.message)
  134. }
  135. }
  136. RunScriptAction.NAME -> {
  137. try {
  138. val runScriptAction = Json.decodeFromString<RunScriptAction>(jsonStr)
  139. CoroutineScope(Dispatchers.IO).launch {
  140. taskRunner.runScript(runScriptAction, onSuccess = { out, err ->
  141. socketCallback(runScriptAction.id, RunScriptResult(out, err))
  142. }, onError = { error ->
  143. socketCallback(
  144. id = runScriptAction.id,
  145. status = -1,
  146. error = error.message
  147. )
  148. })
  149. }
  150. } catch (e: Exception) {
  151. Log.e(TAG, "runScript error", e)
  152. socketCallback(id = id, status = -1, error = e.message)
  153. }
  154. }
  155. UpdateDeviceAction.NAME -> {
  156. try {
  157. val updateDeviceAction = Json.decodeFromString<UpdateDeviceAction>(jsonStr)
  158. CoroutineScope(Dispatchers.IO).launch {
  159. taskRunner.updateDevice(updateDeviceAction, onSuccess = {
  160. socketCallback(
  161. id = updateDeviceAction.id,
  162. status = 0,
  163. data = "OK"
  164. )
  165. }, onError = { error ->
  166. socketCallback(
  167. id = updateDeviceAction.id,
  168. status = -1,
  169. error = error.message
  170. )
  171. })
  172. }
  173. } catch (e: Exception) {
  174. Log.e(TAG, "updateDevice error", e)
  175. socketCallback(id = id, status = -1, error = e.message)
  176. }
  177. }
  178. StoreNumberAction.NAME -> {
  179. try {
  180. throwIfBusy()
  181. val storeNumberAction = Json.decodeFromString<StoreNumberAction>(jsonStr)
  182. CoroutineScope(Dispatchers.IO).launch {
  183. taskRunner.storeNumbers(storeNumberAction.data?.num)
  184. socketCallback(id = storeNumberAction.id, status = 0, data = "OK")
  185. }
  186. } catch (e: Exception) {
  187. Log.e(TAG, "storeNumber error", e)
  188. socketCallback(id = id, status = -1, error = e.message)
  189. }
  190. }
  191. CancelStoreNumberAction.NAME -> {
  192. try {
  193. CoroutineScope(Dispatchers.IO).launch {
  194. taskRunner.cancelStoreNumber()
  195. socketCallback(id = id, status = 0, data = "OK")
  196. }
  197. } catch (e: Exception) {
  198. Log.e(TAG, "cancelStoreNumber error", e)
  199. socketCallback(id = id, status = -1, error = e.message)
  200. }
  201. }
  202. ResumeAction.NAME -> {
  203. try {
  204. throwIfBusy()
  205. val resumeAction = Json.decodeFromString<ResumeAction>(jsonStr)
  206. CoroutineScope(Dispatchers.IO).launch {
  207. AppStateRepo.instance.updateRuntimeFlags(suspended = false)
  208. AppStateRepo.instance.updateSend(true)
  209. if (resumeAction.data?.request == true) {
  210. taskRunner.requestNumberOnTask(
  211. reset = resumeAction.data.reset ?: false
  212. )
  213. }
  214. }
  215. socketCallback(id = id, status = 0, data = "OK")
  216. } catch (e: Exception) {
  217. Log.e(TAG, "resume error", e)
  218. socketCallback(id = id, status = -1, error = e.message)
  219. }
  220. }
  221. CheckPifAction.NAME -> {
  222. try {
  223. val checkPifAction = Json.decodeFromString<CheckPifAction>(jsonStr)
  224. CoroutineScope(Dispatchers.IO).launch {
  225. checkPif()
  226. socketCallback(
  227. id = checkPifAction.id,
  228. status = 0,
  229. data = "OK"
  230. )
  231. }
  232. } catch (e: Exception) {
  233. Log.e(TAG, "checkPif error", e)
  234. socketCallback(id = id, status = -1, error = e.message)
  235. }
  236. }
  237. CleanBackupAction.NAME -> {
  238. try {
  239. val cleanBackupAction = Json.decodeFromString<CleanBackupAction>(jsonStr)
  240. CoroutineScope(Dispatchers.IO).launch {
  241. taskRunner.cleanBackup(
  242. cleanBackupAction.data.start,
  243. cleanBackupAction.data.end
  244. )
  245. }
  246. socketCallback(id = id, status = 0, data = "OK")
  247. } catch (e: Exception) {
  248. Log.e(TAG, "checkPif error", e)
  249. socketCallback(id = id, status = -1, error = e.message)
  250. }
  251. }
  252. }
  253. }
  254. private fun onConnected(vararg args: Any) {
  255. Log.i(TAG, "Connected to server")
  256. CoroutineScope(Dispatchers.IO).launch {
  257. delay(500)
  258. reportDeviceStatues()
  259. }
  260. }
  261. private fun onDisconnected(vararg args: Any) {}
  262. fun reportDeviceStatues() {
  263. if (!mSocket.connected()) {
  264. return
  265. }
  266. val data = JSONObject()
  267. runCatching {
  268. data.put("action", "updateDevice")
  269. val dataObj = JSONObject()
  270. dataObj.put("canSend", AppStateRepo.instance.appState.value.send)
  271. dataObj.put("busy", AppStateRepo.instance.appState.value.busy)
  272. dataObj.put("currentCountry", SpoofedInfoRepo.instance.spoofedInfo.value.country)
  273. dataObj.put("ip", getIPAddress().joinToString(","))
  274. dataObj.put(
  275. "requesting",
  276. AppStateRepo.instance.appState.value.reqState == ReqState.REQUEST
  277. )
  278. dataObj.put("suspended", AppStateRepo.instance.appState.value.suspended)
  279. dataObj.put("storing", AppStateRepo.instance.appState.value.storing)
  280. data.put("data", dataObj)
  281. mSocket.emit("message", data)
  282. }.onFailure { e ->
  283. Log.e(TAG, "reportDeviceStatues error", e)
  284. }
  285. }
  286. private fun socketCallback(id: String, data: List<TaskExecutionResult>) {
  287. Log.i(TAG, "socketCallback: ${Json.encodeToString(
  288. SocketCallback(
  289. id = id,
  290. status = 0,
  291. data = data
  292. )
  293. )}")
  294. runCatching {
  295. mSocket.emit(
  296. "callback", JSONObject(
  297. Json.encodeToString(
  298. SocketCallback(
  299. id = id,
  300. status = 0,
  301. data = data
  302. )
  303. )
  304. )
  305. )
  306. }.onFailure { e ->
  307. Log.e(TAG, "emitEvent error", e)
  308. }
  309. }
  310. private fun socketCallback(id: String, data: RunScriptResult) {
  311. runCatching {
  312. mSocket.emit(
  313. "callback", JSONObject(
  314. Json.encodeToString(
  315. SocketCallback(
  316. id = id,
  317. status = 0,
  318. data = data
  319. )
  320. )
  321. )
  322. )
  323. }.onFailure { e ->
  324. Log.e(TAG, "emitEvent error", e)
  325. }
  326. }
  327. private fun socketCallback(
  328. id: String,
  329. status: Int,
  330. data: String? = null,
  331. error: String? = null
  332. ) {
  333. runCatching {
  334. mSocket.emit(
  335. "callback", JSONObject(
  336. Json.encodeToString(
  337. SocketCallback(
  338. id = id,
  339. status = status,
  340. data = data,
  341. error = error
  342. )
  343. )
  344. )
  345. )
  346. }.onFailure { e ->
  347. Log.e(TAG, "emitEvent error", e)
  348. }
  349. }
  350. }