aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt85
1 files changed, 58 insertions, 27 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt
index 2fa20917..51e14097 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt
@@ -11,6 +11,24 @@ import org.apache.commons.text.StringEscapeUtils
/**
* Created by Allan Wang on 21/12/17.
*/
+private val authMap: MutableMap<String, RequestAuth> = mutableMapOf()
+
+fun String.fbRequest(action: RequestAuth.() -> Unit) {
+ val savedAuth = authMap[this]
+ if (savedAuth != null) {
+ savedAuth.action()
+ } else {
+ val auth = getAuth()
+ if (!auth.isValid) {
+ L.e("Attempted fbrequest with invalid auth")
+ return
+ }
+ authMap.put(this, auth)
+ L.i(null, "Found auth $auth")
+ auth.action()
+ }
+}
+
data class RequestAuth(val userId: Long = -1,
val cookie: String = "",
val fb_dtsg: String = "",
@@ -19,6 +37,22 @@ data class RequestAuth(val userId: Long = -1,
get() = userId > 0 && cookie.isNotEmpty() && fb_dtsg.isNotEmpty() && rev.isNotEmpty()
}
+/**
+ * Request container with the execution call
+ */
+class FrostRequest<out T : Any>(val call: Call, private val invoke: (Call) -> T) {
+ fun invoke() = invoke(call)
+}
+
+private inline fun <T : Any> RequestAuth.frostRequest(
+ noinline invoke: (Call) -> T,
+ builder: Request.Builder.() -> Request.Builder // to ensure we don't do anything extra at the end
+): FrostRequest<T> {
+ val request = cookie.requestBuilder()
+ request.builder()
+ return FrostRequest(request.call(), invoke)
+}
+
private val client: OkHttpClient by lazy {
val builder = OkHttpClient.Builder()
if (BuildConfig.DEBUG)
@@ -49,12 +83,12 @@ private fun String.requestBuilder() = Request.Builder()
private fun Request.Builder.call() = client.newCall(build())
-
-fun Pair<Long, String>.getAuth(): RequestAuth {
- val (userId, cookie) = this
- var auth = RequestAuth(userId, cookie)
- val call = cookie.requestBuilder()
- .url("https://touch.facebook.com")
+fun String.getAuth(): RequestAuth {
+ var auth = RequestAuth(cookie = this)
+ val id = FB_USER_MATCHER.find(this)[1]?.toLong() ?: return auth
+ auth = auth.copy(userId = id)
+ val call = this.requestBuilder()
+ .url(FB_URL_BASE)
.get()
.call()
call.execute().body()?.charStream()?.useLines {
@@ -62,14 +96,14 @@ fun Pair<Long, String>.getAuth(): RequestAuth {
val text = StringEscapeUtils.unescapeEcmaScript(it)
val fb_dtsg = FB_DTSG_MATCHER.find(text)[1]
if (fb_dtsg != null) {
- L.d(null, "fb_dtsg for $userId: $fb_dtsg")
+ L.d(null, "fb_dtsg for ${auth.userId}: $fb_dtsg")
auth = auth.copy(fb_dtsg = fb_dtsg)
if (auth.isValid) return auth
}
val rev = FB_REV_MATCHER.find(text)[1]
if (rev != null) {
- L.d(null, "rev for $userId: $rev")
+ L.d(null, "rev for ${auth.userId}: $rev")
auth = auth.copy(rev = rev)
if (auth.isValid) return auth
}
@@ -79,7 +113,7 @@ fun Pair<Long, String>.getAuth(): RequestAuth {
return auth
}
-fun RequestAuth.markNotificationRead(notifId: Long): Call {
+fun RequestAuth.markNotificationRead(notifId: Long): FrostRequest<Boolean> {
val body = listOf(
"click_type" to "notification_click",
@@ -89,40 +123,37 @@ fun RequestAuth.markNotificationRead(notifId: Long): Call {
"__user" to userId
).withEmptyData("m_sess", "__dyn", "__req", "__ajax__")
- return cookie.requestBuilder()
- .url("${FB_URL_BASE}a/jewel_notifications_log.php")
- .post(body.toForm())
- .call()
+ return frostRequest(::executeForNoError) {
+ url("${FB_URL_BASE}a/jewel_notifications_log.php")
+ post(body.toForm())
+ }
}
-private inline fun <T, reified R : Any, O> zip(data: Array<T>,
- crossinline mapper: (List<R>) -> O,
- crossinline caller: (T) -> R): Single<O> {
- val singles = data.map { Single.fromCallable { caller(it) }.subscribeOn(Schedulers.io()) }
+inline fun <T, reified R : Any, O> Array<T>.zip(crossinline mapper: (List<R>) -> O,
+ crossinline caller: (T) -> R): Single<O> {
+ val singles = map { Single.fromCallable { caller(it) }.subscribeOn(Schedulers.io()) }
return Single.zip(singles) {
val results = it.mapNotNull { it as? R }
mapper(results)
}
}
-fun RequestAuth.markNotificationsRead(vararg notifId: Long) = zip<Long, Boolean, Int>(notifId.toTypedArray(),
- { it.count { it } }) {
- val response = markNotificationRead(it).execute()
- val buffer = CharArray(20)
- response.body()?.charStream()?.read(buffer) ?: return@zip false
- !buffer.toString().contains("error")
-}
+fun RequestAuth.markNotificationsRead(vararg notifId: Long) =
+ notifId.toTypedArray().zip<Long, Boolean, Boolean>(
+ { it.all { it } },
+ { markNotificationRead(it).invoke() })
/**
* Execute the call and attempt to check validity
+ * Valid = not blank & no "error" instance
*/
-fun Call.executeAndCheck(): Boolean {
- val body = execute().body() ?: return false
+fun executeForNoError(call: Call): Boolean {
+ val body = call.execute().body() ?: return false
var empty = true
body.charStream().useLines {
it.forEach {
+ if (it.contains("error")) return false
if (empty && it.isNotEmpty()) empty = false
- if (it.contains("error")) return true
}
}
return !empty