diff --git a/app/build.gradle b/app/build.gradle index 0fc5ccb..10ffc89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -158,6 +158,7 @@ dependencies { implementation "androidx.preference:preference-ktx:1.2.1" implementation 'io.nats:jnats:2.11.2' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1' implementation("androidx.work:work-runtime-ktx:2.9.0") diff --git a/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt b/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt index 0b653bb..92d3091 100644 --- a/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt +++ b/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt @@ -7,8 +7,11 @@ import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import okhttp3.MultipartBody +import okhttp3.Response import okhttp3.ResponseBody import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header import retrofit2.http.Multipart import retrofit2.http.POST import retrofit2.http.PUT @@ -31,6 +34,10 @@ interface MolbioResultApi { @Body deviceUpdateRequest: DeviceUpdateRequest ): ResponseBody + @GET("deviceService/device/getClientCertificate") + suspend fun downloadClientCertificate( + ): ResponseBody + @Multipart @POST("deviceService/device/uploadLogs") suspend fun uploadLogs( diff --git a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt index bffe71e..d982014 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt @@ -77,6 +77,9 @@ class DatabaseRepository @Inject constructor( return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) } } + override suspend fun downloadClientCertificate(): Result { + return safeApiCall { molbioResultApi.downloadClientCertificate() } + } override suspend fun uploadLogs(logFile: MultipartBody.Part): Result { return safeApiCall { molbioResultApi.uploadLogs(logFile) } } diff --git a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt index cd3e9b5..f595aeb 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt @@ -45,5 +45,6 @@ interface Repository { suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result + suspend fun downloadClientCertificate(): Result suspend fun uploadLogs(logFile: MultipartBody.Part): Result } \ 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 97d6094..cd62ff2 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 @@ -43,11 +43,19 @@ import com.google.firebase.perf.ktx.performance import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding +import okhttp3.ResponseBody import org.json.JSONObject +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.net.URL import java.text.SimpleDateFormat import java.util.Calendar import java.util.Date import java.util.Locale +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream @AndroidEntryPoint class HomeFragment : Fragment() { @@ -62,7 +70,6 @@ class HomeFragment : Fragment() { private val homeViewModel: HemoCubeViewModel by activityViewModels() private var isTokenAvailable = false - private lateinit var sharedPreference: SharedPreferences override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, @@ -203,6 +210,7 @@ class HomeFragment : Fragment() { hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData()) hemoCubeViewModel.uploadLogs() hemoCubeViewModel.startPeriodicCheckUpdate() + hemoCubeViewModel.downloadClientCertificate() } } } else { @@ -212,6 +220,11 @@ class HomeFragment : Fragment() { Toast.LENGTH_SHORT ).show() } + + + + + hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response -> when (response) { is Result.Success -> { @@ -266,6 +279,41 @@ class HomeFragment : Fragment() { } } + + + hemoCubeViewModel.downloadcertificate.observe(viewLifecycleOwner) { response -> + when (response) { + is Result.Success -> { + val url = response.data + + val fileName = "nats_certificate.zip" + val downloadDirectory = "NATS" + val file = downloadFile(url, requireContext(), fileName, downloadDirectory) + Toast.makeText(requireContext(), "NATS certificate Downloaded", Toast.LENGTH_SHORT).show() + + val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory" + unzip(file.absolutePath, unzipDirectoryPath) + Toast.makeText(requireContext(), "NATS certificate Extracted", Toast.LENGTH_SHORT).show() + } + is Result.Error -> { + response.exception.let { message -> + Toast.makeText( + activity, + "An error occurred in nats download: $message", + Toast.LENGTH_LONG + ) + .show() + } + } + + is Result.Loading -> { + + } + + else -> {} + } + } + hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) { when (it) { is Result.Success -> { @@ -290,8 +338,11 @@ class HomeFragment : Fragment() { else -> {} } } + + } + private fun isTokenExpired(token: String): Boolean { val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT)) @@ -341,6 +392,60 @@ class HomeFragment : Fragment() { ) } + private fun downloadFile(responseBody: ResponseBody, context: Context, fileName: String, downloadDirectory: String): File { + // Ensure the download directory exists + val fileDir = File(context.getExternalFilesDir(null), downloadDirectory) + if (!fileDir.exists()) { + fileDir.mkdirs() + } + val file = File(fileDir, fileName) + Log.d("Download", "Starting download to $file") + responseBody.byteStream().use { inputStream -> + FileOutputStream(file).use { outputStream -> + inputStream.copyTo(outputStream) + } + } + +// After download + Log.d("Download", "Download completed to ${file.absolutePath}") + + return file + } + + + + + private fun unzip(zipFilePath: String, destDirectory: String) { + val destDir = File(destDirectory) + if (!destDir.exists()) { + destDir.mkdir() + } + ZipInputStream(FileInputStream(zipFilePath)).use { zipIn -> + var entry: ZipEntry? = zipIn.nextEntry + while (entry != null) { + val filePath = destDirectory + File.separator + entry.name + if (!entry.isDirectory) { + extractFile(zipIn, filePath) + } else { + val dir = File(filePath) + dir.mkdir() + } + zipIn.closeEntry() + entry = zipIn.nextEntry + } + } + } + + private fun extractFile(zipIn: ZipInputStream, filePath: String) { + BufferedOutputStream(FileOutputStream(filePath)).use { bos -> + val bytesIn = ByteArray(4096) + var read: Int + while (zipIn.read(bytesIn).also { read = it } != -1) { + bos.write(bytesIn, 0, read) + } + } + } + private fun setUserId() { binding.btnSubmit.setOnClickListener { val userId = binding.userId.text.toString() 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 79ad9e0..a56407d 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 @@ -79,6 +79,7 @@ class HemoCubeViewModel @Inject constructor( val checkUpdate = MutableLiveData>() val deviceUpdate = MutableLiveData>() + val downloadcertificate = MutableLiveData>() val uploadLogs = MutableLiveData?>() @@ -141,6 +142,9 @@ class HemoCubeViewModel @Inject constructor( } } + + + fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch { checkUpdate.postValue(Result.Loading()) repository.checkUpdate(checkUpdateRequest).let { @@ -155,6 +159,17 @@ class HemoCubeViewModel @Inject constructor( } } + + fun downloadClientCertificate() = viewModelScope.launch { + downloadcertificate.postValue(Result.Loading()) + repository.downloadClientCertificate().let { + downloadcertificate.postValue(it) + } + } + + + + fun startPeriodicCheckUpdate() { val periodicRequest = PeriodicWorkRequestBuilder( repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES