diff --git a/app/build.gradle b/app/build.gradle index 662fc62..2d397c8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -139,4 +139,8 @@ dependencies { implementation "androidx.preference:preference-ktx:1.2.1" implementation 'io.nats:jnats:2.11.2' + + implementation("androidx.work:work-runtime-ktx:2.9.0") + + implementation("io.nats:jnats:2.11.2") } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt index 08d9ac0..c0a3c80 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt @@ -18,6 +18,7 @@ object Constants { const val ACCESS_TOKEN = "accessToken" const val NATS_TOKEN = "natsToken" + const val NATS_TOKEN_EXPIRE_DATE = "natsTokenExpireDate" const val WRITE_TIMEOUT_MILLIS = 30000 // 30 sec const val READ_TIMEOUT_MILLIS = 60000 // 1 min diff --git a/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt index c7cb63d..7ebe1d6 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/HemoCubeDao.kt @@ -23,4 +23,7 @@ interface HemoCubeDao { @Query("UPDATE hemo_cube_test_table SET localFlag = :newValue WHERE _id = :id") suspend fun updateFieldById(id: String, newValue: Boolean) + + @Query("UPDATE hemo_cube_test_table SET molbioFlag = :newValue WHERE _id = :id") + suspend fun updateMolbioFlag(id: String, newValue: Boolean) } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt b/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt index 23d19b8..3e3c698 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt @@ -3,27 +3,27 @@ package com.example.hpostesting.data.model.molbioresult import com.example.hpostesting.data.model.patient.HemoCubeTestData data class MolbioV2Result( - val age: Int? = 0, + val age: Int? = 31, val analysisDate: String? = "", val analysisId: String? = "", val analysisStatus: String? = "", - val analysisType: String? = "", + val analysisType: String? = "HPOS", val analysisTypeMethod: String? = "", val bloodGroup: String? = "", - val coefficients: List? = listOf(), + val coefficients: List? = listOf(22, 22), val collectionLocation: List? = listOf(), val collectionTime: String? = "", val collector: String? = "", - val curveFitting: String? = "", - val deviceName: String? = "", + val curveFitting: String? = "Linear", + val deviceName: String? = "HPOS", val expiryTime: String? = "", val gender: String? = "", val interpretation: String? = "", val `operator`: String? = "", - val patientId: Int? = 0, + val patientId: Int? = 4545, val pregnancy: Boolean? = false, val rawData: HemoCubeTestData? = HemoCubeTestData(), - val recommendation: String? = "", + val recommendation: String? = "NA", val sampleId: String? = "", val sampleType: String? = "", val sickleCellHistory: Boolean? = false, @@ -34,5 +34,5 @@ data class MolbioV2Result( val testType: String? = "", val thresholds: String? = "", val underMedication: Boolean? = false, - val volume: Int? = 0 + val volume: Int? = 2 ) \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/domain/CheckUpdateWorker.kt b/app/src/main/java/com/example/hpostesting/domain/CheckUpdateWorker.kt new file mode 100644 index 0000000..9a55536 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/domain/CheckUpdateWorker.kt @@ -0,0 +1,28 @@ +package com.example.hpostesting.domain + +import android.content.Context +import android.util.Log +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext + +class CheckUpdateWorker( + context: Context, + workerParams: WorkerParameters +) : CoroutineWorker(context, workerParams) { + + override suspend fun doWork(): Result = withContext(Dispatchers.IO) { + try { + for (i in 1..900){ + delay(1000) + Log.d("Work for every second", "doWork: Running") + } + + Result.success() + } catch (e: Exception) { + Result.failure() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt new file mode 100644 index 0000000..f49091c --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt @@ -0,0 +1,134 @@ +package com.example.hpostesting.presentation + +import android.util.Log +import com.example.hpostesting.presentation.dashboard.DashboardActivity +import io.nats.client.AuthHandler +import io.nats.client.Connection +import io.nats.client.Message +import io.nats.client.NKey +import io.nats.client.Nats +import io.nats.client.Options +import java.io.IOException +import java.nio.charset.StandardCharsets +import java.security.GeneralSecurityException + + +class NatsManager(datacollector: DashboardActivity) { + + val TAG = "Nats Service" + var nc: Connection? = null + val datacollector = datacollector + var connect = false + + fun connect() { + Log.d(TAG, "TRY TO CONNECT") + Thread { + + val seedString = "SUAK5IDCMHY4T2WA2LHNXGICGHKR3TPJFNSP6AUQP523RLANO4PSR6IEYA" + val seedBytes = seedString.toCharArray() + + val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere + + val options = Options.Builder() + .server("nats://192.168.10.117:4222") + .authHandler(object : AuthHandler { + override fun getID(): CharArray? { + return try { + theNKey?.publicKey + } catch (ex: GeneralSecurityException) { + null + } catch (ex: IOException) { + null + } catch (ex: NullPointerException) { + null + } + } + + override fun sign(nonce: ByteArray): ByteArray? { + return try { + theNKey?.sign(nonce) + } catch (ex: GeneralSecurityException) { + null + } catch (ex: IOException) { + null + } catch (ex: NullPointerException) { + null + } + } + + override fun getJWT(): CharArray? { + return null + } + }) + .build() + + try { + nc = Nats.connect(options) + Log.d(TAG, "Connected to Nats server ${options.servers.first()}") + connect = true + datacollector.setConnect(true) + + + nc?.publish( + "server.hpos.HCV-000-3001.ping", + "ALIVE".toByteArray(StandardCharsets.UTF_8) + ) + nc?.publish( + "server.hpos.HCV-000-3001.health", + "ALIVE".toByteArray(StandardCharsets.UTF_8) + ) + Log.d(TAG, "Published msg server.hpos.HCV-000-3001.ping on topic Testing") + val d = nc?.createDispatcher { msg: Message? -> + println("PRITIMOI SARKAR $msg") + } + + d?.subscribe("device.hpos.HCV-000-3001.update") { msg -> + val response = String(msg.data, StandardCharsets.UTF_8) + datacollector. setResponse(response) + println("Message received (up to 100 times): $response") + } + + d?.subscribe("device.hpos.HCV-000-3001.uploadlogs") { msg -> + val response = String(msg.data, StandardCharsets.UTF_8) + datacollector.setResponse(response + "uPLOAD") + println("Message received (up to 100 times): $response") + } + + d?.subscribe("device.hpos.HCV-000-3001.disable") { msg -> + val response = String(msg.data, StandardCharsets.UTF_8) + datacollector.setResponse(response) + println("Message received (up to 100 times): $response") + } + + d?.subscribe("device.hpos.HCV-000-3001.updatecustomer") { msg -> + val response = String(msg.data, StandardCharsets.UTF_8) + datacollector.setResponse(response) + println("Message received (up to 100 times): $response") + } + + d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg -> + val response = String(msg.data, StandardCharsets.UTF_8) + datacollector.setResponse(response) + println("Message received (up to 100 times): $response") + } + + } catch (exp: Exception) { + println(exp.printStackTrace()) + connect = false + datacollector.setConnect(true) + } + }.start() + + } + + fun pub(topic: String, msg: String) { + nc?.publish(topic, msg.toByteArray(StandardCharsets.UTF_8)) + Log.d(TAG, "Published msg ${msg} on topic ${topic}") + } + + fun close() { + nc?.close() + Log.d(TAG, "Nats connection close") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt index 9bf5207..22de1f1 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt @@ -2,6 +2,7 @@ package com.example.hpostesting.presentation.dashboard import android.content.Context import android.os.Bundle +import android.util.Log import android.view.Menu import android.widget.Toast import androidx.appcompat.app.AppCompatActivity @@ -12,7 +13,9 @@ import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.example.hpostesting.data.constant.LanguageManager +import com.example.hpostesting.presentation.NatsManager import com.google.android.material.navigation.NavigationView +import com.google.android.material.progressindicator.LinearProgressIndicator import com.google.android.play.core.appupdate.AppUpdateManager import com.google.android.play.core.appupdate.AppUpdateManagerFactory import com.google.firebase.appdistribution.FirebaseAppDistribution @@ -22,11 +25,17 @@ import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding +open interface IDataCollector { + fun setConnect(connect: Boolean) + fun setResponse(response: String) +} @AndroidEntryPoint -class DashboardActivity : AppCompatActivity() { +class DashboardActivity : AppCompatActivity(), IDataCollector { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityDashboardBinding + var responses: String = "" + lateinit var nats: NatsManager override fun attachBaseContext(newBase: Context?) { val languageCode = LanguageManager.getSavedLanguage(newBase!!) LanguageManager.setLocale(newBase, languageCode) @@ -39,6 +48,9 @@ class DashboardActivity : AppCompatActivity() { binding = ActivityDashboardBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarDashboard.toolbar) + nats = NatsManager(this) +// nats.connect() +// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG") val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView @@ -104,4 +116,16 @@ class DashboardActivity : AppCompatActivity() { // Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show() } } + + override fun setConnect(connect: Boolean) { + if(connect){ + Log.i("NATS Connection", connect.toString()) + } + } + + override fun setResponse(response: String) { + + responses = responses+response+"\n" + println(responses) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 13a46ab..9702cca 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -142,6 +142,7 @@ class HomeFragment : Fragment() { private fun checkForTokenAndUpdate() { val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString() val natsToken = sharedPreference.getString(Constants.NATS_TOKEN, "").toString() + val natsTokenExpireDate = sharedPreference.getString(Constants.NATS_TOKEN_EXPIRE_DATE, "").toString() if (accessToken.isEmpty() && natsToken.isEmpty()) { hemoCubeViewModel.login(createLoginRequestData()) } else { @@ -150,6 +151,7 @@ class HomeFragment : Fragment() { } else { hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData()) hemoCubeViewModel.uploadLogs() + hemoCubeViewModel.startPeriodicCheckUpdate() } } hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response -> @@ -238,6 +240,7 @@ class HomeFragment : Fragment() { with(sharedPreference.edit()) { putString(Constants.ACCESS_TOKEN, response.data.data?.accessToken) putString(Constants.NATS_TOKEN, response.data.data?.deviceUser?.natsToken) + putString(Constants.NATS_TOKEN_EXPIRE_DATE, response.data.data?.deviceUser?.natsTokenExpiry) apply() } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index fa0e9d8..5e6e34b 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -138,20 +138,20 @@ class HemoCubeFragment : Fragment() { hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> if (result == "Success") { showToast(R.string.test_upload) - activity?.runOnUiThread { - binding.btnSubmit.visibility = View.GONE - val i = Intent( - requireContext().applicationContext, - DashboardActivity::class.java - ) - startActivity(i) - } hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) { when (it) { is Result.Success -> { it.data.data?.get(0)?.rawData?.let { it1 -> hemoCubeViewModel.updateMolbioFlag( it1._id) + activity?.runOnUiThread { + binding.btnSubmit.visibility = View.GONE + val i = Intent( + requireContext().applicationContext, + DashboardActivity::class.java + ) + startActivity(i) + } } } is Result.Error -> { diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index 4deb30f..6d7fc92 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -10,6 +10,9 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.work.ExistingPeriodicWorkPolicy +import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkManager import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.NetworkStatusLiveData import com.example.hpostesting.data.Result @@ -34,6 +37,7 @@ import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.repository.DatabaseRepository import com.example.hpostesting.data.repository.Repository +import com.example.hpostesting.domain.CheckUpdateWorker import com.example.hpostesting.domain.LogFileManager import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.launch @@ -44,6 +48,7 @@ import okhttp3.ResponseBody import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale +import java.util.concurrent.TimeUnit import javax.inject.Inject @HiltViewModel @@ -62,6 +67,12 @@ class HemoCubeViewModel @Inject constructor( private val sharedPreference: SharedPreferences = context.getSharedPreferences("PREFERENCE_NAME", Context.MODE_PRIVATE) + private val workManager = WorkManager.getInstance(context) + +// init { +// startPeriodicCheckUpdate() +// } + val deviceProvisionResponse = MutableLiveData>() val loginResponse = MutableLiveData>() @@ -165,6 +176,16 @@ class HemoCubeViewModel @Inject constructor( } } + fun startPeriodicCheckUpdate() { + val periodicRequest = PeriodicWorkRequestBuilder( + repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES + ).build() + + workManager.enqueueUniquePeriodicWork( + "checkUpdateWorker", ExistingPeriodicWorkPolicy.KEEP, periodicRequest + ) + } + fun uploadLogs() = viewModelScope.launch { uploadLogs.postValue(Result.Loading()) val logFile = logFileManager.createLogFile().let { file -> @@ -402,7 +423,24 @@ class HemoCubeViewModel @Inject constructor( Log.i("Testdb", "Data uploaded to Firestore successfully") fireBaseUpload.postValue("Success") testDetails.localFlag = true - uploadResult(MolbioV2ResultRequest(listOf(MolbioV2Result(rawData = testDetails)))) + uploadResult( + MolbioV2ResultRequest( + listOf( + MolbioV2Result( + rawData = testDetails, + analysisId = testDetails._id, + analysisDate = testDetails.testTime, + analysisStatus = testDetails.classificationResult, + thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(), + interpretation = testDetails.classificationResult, + testId = testDetails._id, + testTime = testDetails.testTime, + collectionTime = testDetails.testTime, + expiryTime = testDetails.testTime, + ) + ) + ) + ) hemoCubeDao.insertAll(testDetails) } @@ -468,7 +506,7 @@ class HemoCubeViewModel @Inject constructor( } fun updateMolbioFlag(userId: String) = viewModelScope.launch { - hemoCubeDao.updateFieldById(id = userId, true) + hemoCubeDao.updateMolbioFlag(id = userId, true) } fun addUser(userData: HemoCubeTestData) = viewModelScope.launch {