diff options
author | Allan Wang <me@allanwang.ca> | 2018-01-10 22:13:28 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-10 22:13:28 -0500 |
commit | fd5f2a82eb968b5d50f586925ebb705249062446 (patch) | |
tree | 7e2cb3edad1e2398d74eb2780a912ed05188db41 /app/src/main/kotlin/com/pitchedapps/frost/facebook/requests | |
parent | ad97b4ff946b4ba3a3f7ac880575eed9de810166 (diff) | |
download | frost-fd5f2a82eb968b5d50f586925ebb705249062446.tar.gz frost-fd5f2a82eb968b5d50f586925ebb705249062446.tar.bz2 frost-fd5f2a82eb968b5d50f586925ebb705249062446.zip |
Misc (#614)
* Add locale log
* Add flyweight design for authenticator
* Add option to have instant messages only
* Update interceptor
* Add hd image model loader (#613)
* Launch image view for view full image
* Update changelog
* Greatly improve ImageActivity loading
* Update hashes
* Add back keyword filter
* Clean up
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/facebook/requests')
3 files changed, 113 insertions, 17 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt index ae8652e6..3ca37bb4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt @@ -2,6 +2,7 @@ package com.pitchedapps.frost.facebook.requests import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.rx.RxFlyweight import com.pitchedapps.frost.utils.L import io.reactivex.Single import io.reactivex.schedulers.Schedulers @@ -12,7 +13,17 @@ import org.apache.commons.text.StringEscapeUtils /** * Created by Allan Wang on 21/12/17. */ -private val authMap: MutableMap<String, RequestAuth> = mutableMapOf() +private class RxAuth : RxFlyweight<String, Long, RequestAuth>() { + + override fun call(input: String) = input.getAuth() + + override fun validate(input: String, cond: Long) = + System.currentTimeMillis() - cond < 3600000 // valid for an hour + + override fun cache(input: String) = System.currentTimeMillis() +} + +private val auth = RxAuth() /** * Synchronously fetch [RequestAuth] from cookie @@ -21,18 +32,13 @@ private val authMap: MutableMap<String, RequestAuth> = mutableMapOf() */ fun String?.fbRequest(fail: () -> Unit = {}, action: RequestAuth.() -> Unit) { if (this == null) return fail() - val savedAuth = authMap[this] - if (savedAuth != null) { - savedAuth.action() - } else { - val auth = getAuth() - if (!auth.isValid) { - L.e { "Attempted fbrequest with invalid auth" } - return fail() + auth(this).subscribe { a: RequestAuth?, _ -> + if (a?.isValid == true) + a.action() + else { + L.e { "Failed auth for ${hashCode()}" } + fail() } - authMap.put(this, auth) - L._i { "Found auth $auth" } - auth.action() } } @@ -94,6 +100,7 @@ private fun String.requestBuilder() = Request.Builder() fun Request.Builder.call() = client.newCall(build())!! fun String.getAuth(): RequestAuth { + L.v { "Getting auth for ${hashCode()}" } var auth = RequestAuth(cookie = this) val id = FB_USER_MATCHER.find(this)[1]?.toLong() ?: return auth auth = auth.copy(userId = id) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt index 61a94ac5..fa78bbfa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt @@ -1,9 +1,19 @@ package com.pitchedapps.frost.facebook.requests import com.bumptech.glide.Priority +import com.bumptech.glide.RequestBuilder import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.Options import com.bumptech.glide.load.data.DataFetcher +import com.bumptech.glide.load.model.ModelLoader +import com.bumptech.glide.load.model.ModelLoaderFactory +import com.bumptech.glide.load.model.MultiModelLoaderFactory +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.Target +import com.bumptech.glide.signature.ObjectKey +import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER import com.pitchedapps.frost.facebook.FB_URL_BASE +import com.pitchedapps.frost.facebook.get import okhttp3.Call import okhttp3.Request import java.io.IOException @@ -17,8 +27,54 @@ fun RequestAuth.getFullSizedImage(fbid: Long) = frostRequest(::getJsonUrl) { get() } -class ImageFbidFetcher(private val fbid: Long, - private val cookie: String) : DataFetcher<InputStream> { +/** + * Request loader for a potentially hd version of a url + * In this case, each url may potentially return an id, + * which may potentially be used to fetch a higher res image url + * The following aims to allow such loading while adhering to Glide's lifecycle + */ +data class HdImageMaybe(val url: String, val cookie: String) { + + val id: Long by lazy { FB_IMAGE_ID_MATCHER.find(url)[1]?.toLongOrNull() ?: -1 } + + val isValid: Boolean by lazy { + id != -1L && cookie.isNotBlank() + } + +} + +/* + * The following was a test to see if hd image loading would work + * + * It's working and tested, though the improvements aren't really worth the extra data use + * and reload + */ + +class HdImageLoadingFactory : ModelLoaderFactory<HdImageMaybe, InputStream> { + + override fun build(multiFactory: MultiModelLoaderFactory) = HdImageLoading() + + override fun teardown() = Unit +} + +fun <T> RequestBuilder<T>.loadWithPotentialHd(model: HdImageMaybe) = + thumbnail(clone().load(model.url)) + .load(model) + .apply(RequestOptions().override(Target.SIZE_ORIGINAL)) + +class HdImageLoading : ModelLoader<HdImageMaybe, InputStream> { + + override fun buildLoadData(model: HdImageMaybe, + width: Int, + height: Int, + options: Options?): ModelLoader.LoadData<InputStream>? = + if (!model.isValid) null + else ModelLoader.LoadData(ObjectKey(model), HdImageFetcher(model)) + + override fun handles(model: HdImageMaybe) = model.isValid +} + +class HdImageFetcher(private val model: HdImageMaybe) : DataFetcher<InputStream> { @Volatile private var cancelled: Boolean = false private var urlCall: Call? = null @@ -33,10 +89,12 @@ class ImageFbidFetcher(private val fbid: Long, override fun getDataSource(): DataSource = DataSource.REMOTE override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) { - cookie.fbRequest(fail = { callback.fail("Invalid auth") }) { + if (!model.isValid) return callback.fail("Model is invalid") + model.cookie.fbRequest(fail = { callback.fail("Invalid auth") }) { if (cancelled) return@fbRequest callback.fail("Cancelled") - val url = getFullSizedImage(fbid).invoke() ?: return@fbRequest callback.fail("Null url") + val url = getFullSizedImage(model.id).invoke() ?: return@fbRequest callback.fail("Null url") if (cancelled) return@fbRequest callback.fail("Cancelled") + if (!url.contains("png") && !url.contains("jpg")) return@fbRequest callback.fail("Invalid format") urlCall = Request.Builder().url(url).get().call() inputStream = try { @@ -44,7 +102,6 @@ class ImageFbidFetcher(private val fbid: Long, } catch (e: IOException) { null } - callback.onDataReady(inputStream) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt new file mode 100644 index 00000000..0e37a61e --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt @@ -0,0 +1,32 @@ +package com.pitchedapps.frost.facebook.requests + +import com.pitchedapps.frost.facebook.FB_URL_BASE +import okhttp3.Call + +/** + * Created by Allan Wang on 07/01/18. + */ +fun RequestAuth.sendMessage(group: String, content: String): FrostRequest<Boolean> { + + // todo test more; only tested against tids=cid... + val body = listOf( + "tids" to group, + "body" to content, + "fb_dtsg" to fb_dtsg, + "__user" to userId + ).withEmptyData("m_sess", "__dyn", "__req", "__ajax__") + + return frostRequest(::validateMessage) { + url("${FB_URL_BASE}messages/send") + post(body.toForm()) + } +} + +/** + * Messages are a bit weird with their responses + */ +private fun validateMessage(call: Call): Boolean { + val body = call.execute().body() ?: return false + // todo + return true +}
\ No newline at end of file |