aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRequest.kt
blob: 428043a06ca6a1779c25c54c4212d547df900679 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.pitchedapps.frost.facebook

import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.utils.L
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import org.apache.commons.text.StringEscapeUtils

/**
 * Created by Allan Wang on 21/12/17.
 */
data class RequestAuth(val userId: Long = -1, val cookie: String = "", val fb_dtsg: String = "")

private val client: OkHttpClient by lazy {
    val builder = OkHttpClient.Builder()
    if (BuildConfig.DEBUG)
        builder.addInterceptor(HttpLoggingInterceptor()
                .setLevel(HttpLoggingInterceptor.Level.BASIC))
    builder.build()
}

private fun List<Pair<String, Any?>>.toForm(): RequestBody {
    val builder = FormBody.Builder()
    forEach { (key, value) ->
        val v = value?.toString() ?: ""
        builder.add(key, v)
    }
    return builder.build()
}

private fun String.requestBuilder() = Request.Builder()
        .header("Cookie", this)
        .header("User-Agent", USER_AGENT_BASIC)
        .cacheControl(CacheControl.FORCE_NETWORK)

private fun Request.Builder.call() = client.newCall(build())


fun Pair<Long, String>.getAuth(): RequestAuth? {
    val (userId, cookie) = this
    val call = cookie.requestBuilder()
            .url(FB_URL_BASE)
            .get()
            .call()
    call.execute().body()?.charStream()?.useLines {
        it.forEach {
            val text = StringEscapeUtils.unescapeEcmaScript(it)
            val result = FB_DTSG_MATCHER.find(text)
            val fb_dtsg = result?.groupValues?.get(1)
            if (fb_dtsg != null) {
                L.d(null, "fb_dtsg for $userId: $fb_dtsg")
                return RequestAuth(userId, cookie, fb_dtsg)
            }
        }
    }

    return null
}

fun RequestAuth.markNotificationRead(notifId: Long): Call {

    val body = listOf(
            "click_type" to "notification_click",
            "id" to notifId,
            "target_id" to "null",
            "m_sess" to null,
            "fb_dtsg" to fb_dtsg,
            "__dyn" to null,
            "__req" to null,
            "__ajax__" to null,
            "__user" to userId
    )

    return cookie.requestBuilder()
            .url("${FB_URL_BASE}a/jewel_notifications_log.php")
            .post(body.toForm())
            .call()
}

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()) }
    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")
}