77package at.bitfire.dav4jvm.exception
88
99import at.bitfire.dav4jvm.HttpUtils
10+ import at.bitfire.dav4jvm.exception.ServiceUnavailableException.Companion.DELAY_UNTIL_DEFAULT
11+ import at.bitfire.dav4jvm.exception.ServiceUnavailableException.Companion.DELAY_UNTIL_MAX
12+ import at.bitfire.dav4jvm.exception.ServiceUnavailableException.Companion.DELAY_UNTIL_MIN
1013import okhttp3.Response
1114import java.net.HttpURLConnection
1215import java.time.Instant
1316import java.util.logging.Level
1417import java.util.logging.Logger
1518
16- class ServiceUnavailableException : HttpException {
19+ class ServiceUnavailableException : HttpException {
1720
1821 private val logger
1922 get() = Logger .getLogger(javaClass.name)
2023
21- var retryAfter: Instant ? = null
24+ val retryAfter: Instant ?
2225
23- constructor (message: String? ): super (HttpURLConnection .HTTP_UNAVAILABLE , message)
26+ constructor (message: String? ) : super (HttpURLConnection .HTTP_UNAVAILABLE , message) {
27+ retryAfter = null
28+ }
2429
25- constructor (response: Response ): super (response) {
30+ constructor (response: Response ) : super (response) {
2631 // Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
2732 // HTTP-date = rfc1123-date | rfc850-date | asctime-date
2833
34+ var retryAfterValue: Instant ? = null
2935 response.header(" Retry-After" )?.let { after ->
30- retryAfter = HttpUtils .parseDate(after) ? :
36+ retryAfterValue = HttpUtils .parseDate(after) ? :
3137 // not a HTTP-date, must be delta-seconds
3238 try {
3339 val seconds = after.toLong()
@@ -37,6 +43,41 @@ class ServiceUnavailableException: HttpException {
3743 null
3844 }
3945 }
46+
47+ retryAfter = retryAfterValue
48+ }
49+
50+
51+ /* *
52+ * Returns appropriate sync retry delay in seconds, considering the servers suggestion
53+ * in [retryAfter] ([DELAY_UNTIL_DEFAULT] if no server suggestion).
54+ *
55+ * Takes current time into account to calculate intervals. Interval
56+ * will be restricted to values between [DELAY_UNTIL_MIN] and [DELAY_UNTIL_MAX].
57+ *
58+ * @param start timestamp to calculate the delay from (default: now)
59+ *
60+ * @return until when to wait before sync can be retried
61+ */
62+ fun getDelayUntil (start : Instant = Instant .now()): Instant {
63+ if (retryAfter == null )
64+ return start.plusSeconds(DELAY_UNTIL_DEFAULT )
65+
66+ // take server suggestion, but restrict to plausible min/max values
67+ return retryAfter.coerceIn(
68+ minimumValue = start.plusSeconds(DELAY_UNTIL_MIN ),
69+ maximumValue = start.plusSeconds(DELAY_UNTIL_MAX )
70+ )
71+ }
72+
73+
74+ companion object {
75+
76+ // default values for getDelayUntil
77+ const val DELAY_UNTIL_DEFAULT = 15 * 60L // 15 min
78+ const val DELAY_UNTIL_MIN = 1 * 60L // 1 min
79+ const val DELAY_UNTIL_MAX = 2 * 60 * 60L // 2 hours
80+
4081 }
4182
42- }
83+ }
0 commit comments