SocketClient.kt 14 KB

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