@@ -16,7 +16,6 @@ import mil.nga.giat.mage.database.model.observation.Observation
1616import mil.nga.giat.mage.database.model.observation.ObservationFavorite
1717import mil.nga.giat.mage.data.datasource.observation.ObservationLocalDataSource
1818import mil.nga.giat.mage.database.model.observation.State
19- import java.net.HttpURLConnection
2019import java.util.concurrent.TimeUnit
2120
2221@HiltWorker
@@ -28,144 +27,117 @@ class ObservationSyncWorker @AssistedInject constructor(
2827) : CoroutineWorker(context, params) {
2928
3029 override suspend fun doWork (): Result {
31- // Lock to ensure previous running work will complete when cancelled before new work is started.
30+ // Lock to ensure previous running work will complete when cancelled before new work is started.
3231 return mutex.withLock {
33- var result = RESULT_SUCCESS_FLAG
34-
3532 try {
36- result = syncObservations().withFlag(result)
37- result = syncObservationImportant().withFlag(result)
38- result = syncObservationFavorites().withFlag(result)
33+ // submit observations to the server that are marked as "dirty" and track the overall response flag of all transactions
34+ val overallResponseFlag = ResponseFlag .combineResponseFlags(
35+ syncObservations(),
36+ syncObservationImportant(),
37+ syncObservationFavorites()
38+ )
39+
40+ // if any of the transactions returned RetryFlag, then Result.retry() will be returned to retry the work request per back off policy
41+ // this should not result in the successful transactions being resubmitted, as they will no longer be marked as "dirty"
42+ when (overallResponseFlag) {
43+ ResponseFlag .SuccessFlag -> Result .success()
44+ ResponseFlag .FailureFlag -> Result .failure()
45+ ResponseFlag .RetryFlag -> Result .retry()
46+ }
3947 } catch (e: Exception ) {
40- result = RESULT_RETRY_FLAG
4148 Log .e(LOG_NAME , " Error trying to sync observations with server" , e)
49+ // any unhandled exception should result in a retry
50+ Result .retry()
4251 }
43-
44- if (result.containsFlag(RESULT_RETRY_FLAG )) Result .retry() else Result .success()
4552 }
4653 }
4754
48- override suspend fun getForegroundInfo (): ForegroundInfo {
49- val notification = NotificationCompat .Builder (applicationContext, MageApplication .MAGE_NOTIFICATION_CHANNEL_ID )
50- .setSmallIcon(R .drawable.ic_sync_preference_24dp)
51- .setContentTitle(" Sync Observations" )
52- .setContentText(" Pushing observation updates to MAGE." )
53- .setPriority(NotificationCompat .PRIORITY_MAX )
54- .setAutoCancel(true )
55- .build()
56-
57- return ForegroundInfo (OBSERVATION_SYNC_NOTIFICATION_ID , notification)
58- }
59-
60- private suspend fun syncObservations (): Int {
61- var result = RESULT_SUCCESS_FLAG
55+ private suspend fun syncObservations (): ResponseFlag {
56+ var overallResult: ResponseFlag = ResponseFlag .SuccessFlag
6257
6358 for (observation in observationLocalDataSource.dirty) {
64- result = syncObservation(observation).withFlag(result)
59+ val syncResult = syncObservation(observation)
60+ overallResult = ResponseFlag .combineResponseFlags(overallResult, syncResult)
6561 }
6662
67- return result
63+ return overallResult
6864 }
6965
70- private suspend fun syncObservation (observation : Observation ): Int {
71- val result = RESULT_SUCCESS_FLAG
72-
66+ private suspend fun syncObservation (observation : Observation ): ResponseFlag {
7367 return if (observation.state == State .ARCHIVE ) {
74- archive(observation).withFlag(result)
68+ archive(observation)
7569 } else {
76- save(observation).withFlag(result)
70+ save(observation)
7771 }
7872 }
7973
80- private suspend fun syncObservationImportant (): Int {
81- var result = RESULT_SUCCESS_FLAG
74+ private suspend fun syncObservationImportant (): ResponseFlag {
75+ var overallResult : ResponseFlag = ResponseFlag . SuccessFlag
8276
8377 for (observation in observationLocalDataSource.dirtyImportant) {
84- result = updateImportant(observation).withFlag(result)
78+ val updateResult = updateImportant(observation)
79+ overallResult = ResponseFlag .combineResponseFlags(overallResult, updateResult)
8580 }
8681
87- return result
82+ return overallResult
8883 }
8984
90- private suspend fun syncObservationFavorites (): Int {
91- var result = RESULT_SUCCESS_FLAG
85+ private suspend fun syncObservationFavorites (): ResponseFlag {
86+ var overallResult : ResponseFlag = ResponseFlag . SuccessFlag
9287
9388 for (favorite in observationLocalDataSource.dirtyFavorites) {
94- result = updateFavorite(favorite).withFlag(result)
89+ val updateResult = updateFavorite(favorite)
90+ overallResult = ResponseFlag .combineResponseFlags(overallResult, updateResult)
9591 }
9692
97- return result
93+ return overallResult
9894 }
9995
100- private suspend fun save (observation : Observation ): Result {
96+ private suspend fun save (observation : Observation ): ResponseFlag {
10197 return if (observation.remoteId.isNullOrEmpty()) {
98+ // observation doesn't exist on the server, so create it
10299 create(observation)
103100 } else {
101+ // observation should exist on the server, so update it
104102 update(observation)
105103 }
106104 }
107105
108- private suspend fun create (observation : Observation ): Result {
106+ private suspend fun create (observation : Observation ): ResponseFlag {
109107 val response = observationRepository.create(observation)
110- return if (response.isSuccessful) {
111- Result .success()
112- } else {
113- if (response.code() == HttpURLConnection .HTTP_UNAUTHORIZED ) Result .failure() else Result .retry()
114- }
108+ return ResponseFlag .processResponse(response)
115109 }
116110
117- private suspend fun update (observation : Observation ): Result {
111+ private suspend fun update (observation : Observation ): ResponseFlag {
118112 val response = observationRepository.update(observation)
119- return if (response.isSuccessful) {
120- Result .success()
121- } else {
122- if (response.code() == HttpURLConnection .HTTP_UNAUTHORIZED ) Result .failure() else Result .retry()
123- }
113+ return ResponseFlag .processResponse(response)
124114 }
125115
126- private suspend fun archive (observation : Observation ): Result {
127- val response = observationRepository.archive(observation)
128- return when {
129- response.isSuccessful -> Result .success()
130- response.code() == HttpURLConnection .HTTP_NOT_FOUND -> Result .success()
131- response.code() == HttpURLConnection .HTTP_UNAUTHORIZED -> Result .failure()
132- else -> Result .retry()
133- }
134- }
135-
136- private suspend fun updateImportant (observation : Observation ): Result {
116+ private suspend fun updateImportant (observation : Observation ): ResponseFlag {
137117 val response = observationRepository.updateImportant(observation)
138-
139- return if (response.isSuccessful) {
140- Result .success()
141- } else {
142- if (response.code() == HttpURLConnection .HTTP_UNAUTHORIZED ) Result .failure() else Result .retry()
143- }
118+ return ResponseFlag .processResponse(response)
144119 }
145120
146- private suspend fun updateFavorite (favorite : ObservationFavorite ): Result {
121+ private suspend fun updateFavorite (favorite : ObservationFavorite ): ResponseFlag {
147122 val response = observationRepository.updateFavorite(favorite)
148- return if (response.isSuccessful) {
149- Result .success()
150- } else {
151- if (response.code() == HttpURLConnection .HTTP_UNAUTHORIZED ) Result .failure() else Result .retry()
152- }
123+ return ResponseFlag .processResponse(response)
153124 }
154125
155- private fun Result.withFlag (flag : Int ): Int {
156- return when (this ) {
157- is Result .Failure -> RESULT_FAILURE_FLAG or flag
158- is Result .Retry -> RESULT_RETRY_FLAG or flag
159- else -> RESULT_SUCCESS_FLAG or flag
160- }
126+ private suspend fun archive (observation : Observation ): ResponseFlag {
127+ val response = observationRepository.archive(observation)
128+ return ResponseFlag .processArchiveResponse(response)
161129 }
162130
163- private fun Int.containsFlag (flag : Int ): Boolean {
164- return (this or flag) == this
165- }
131+ override suspend fun getForegroundInfo (): ForegroundInfo {
132+ val notification = NotificationCompat .Builder (applicationContext, MageApplication .MAGE_NOTIFICATION_CHANNEL_ID )
133+ .setSmallIcon(R .drawable.ic_sync_preference_24dp)
134+ .setContentTitle(" Sync Observations" )
135+ .setContentText(" Pushing observation updates to MAGE." )
136+ .setPriority(NotificationCompat .PRIORITY_MAX )
137+ .setAutoCancel(true )
138+ .build()
166139
167- private fun Int.withFlag (flag : Int ): Int {
168- return this or flag
140+ return ForegroundInfo (OBSERVATION_SYNC_NOTIFICATION_ID , notification)
169141 }
170142
171143 companion object {
@@ -174,10 +146,6 @@ class ObservationSyncWorker @AssistedInject constructor(
174146 private const val OBSERVATION_SYNC_WORK = " mil.nga.mage.OBSERVATION_SYNC_WORK"
175147 private const val OBSERVATION_SYNC_NOTIFICATION_ID = 100
176148
177- private const val RESULT_SUCCESS_FLAG = 0
178- private const val RESULT_FAILURE_FLAG = 1
179- private const val RESULT_RETRY_FLAG = 2
180-
181149 private val mutex = Mutex ()
182150
183151 fun scheduleWork (context : Context ) {
0 commit comments