Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions api/src/main/kotlin/net/devslash/BodyProviders.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package net.devslash


class BasicBodyProvider(private val body: String, val data: RequestData) : BodyProvider {
class BasicBodyProvider<T>(private val body: String, val data: RequestData<T>) : BodyProvider {
fun get(): String {
var copy = "" + body
data.getReplacements().forEach { (key, value) -> copy = copy.replace(key, value) }
return copy
}
}

class FormBody(private val body: Map<String, List<String>>,
private val data: RequestData) : BodyProvider {
class FormBody<T>(
private val body: Map<String, List<String>>,
private val data: RequestData<T>
) : BodyProvider {
fun get(): Map<String, List<String>> {
return body.map {
val entries = it.value.map { it.asReplaceableValue().get(data) }
val entries = it.value.map { v -> data.accept(v) }
it.key to entries
}.toMap()
}
Expand All @@ -25,7 +27,7 @@ class JsonBody(private val any: Any) : BodyProvider {
}
}

fun getBodyProvider(call: Call, data: RequestData): BodyProvider {
fun <T> getBodyProvider(call: Call<T>, data: RequestData<T>): BodyProvider {
if (call.body == null) {
return EmptyBodyProvider
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/main/kotlin/net/devslash/CookieJar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import java.util.concurrent.ConcurrentHashMap
class CookieJar : SimpleBeforeHook, SimpleAfterHook {
private val cookies = ConcurrentHashMap(mutableMapOf<String, MutableMap<String, String>>())

override fun accept(req: HttpRequest, data: RequestData) {
override fun <T> accept(req: HttpRequest, data: RequestData<T>) {
val basicURl = URL(req.url)
val filteredUrl = "${basicURl.protocol}://${basicURl.host}"

Expand Down
48 changes: 26 additions & 22 deletions api/src/main/kotlin/net/devslash/Definitions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import kotlinx.coroutines.channels.Channel

sealed class Value
data class StrValue(val value: String) : Value()
data class ProvidedValue(val lambda: (RequestData) -> String) : Value()
data class ProvidedValue<T>(val lambda: (RequestData<T>) -> String) : Value()

interface BodyProvider
data class Session(val calls: List<Call>, val concurrency: Int = 100, val delay: Long?, val rateOptions: RateLimitOptions)
data class Session(val calls: List<Call<*>>, val concurrency: Int = 100, val delay: Long?, val rateOptions: RateLimitOptions)

data class Call(val url: String,
data class Call<T>(val url: String,
val headers: Map<String, List<Value>>?,
val cookieJar: String?,
val type: HttpMethod,
val dataSupplier: RequestDataSupplier?,
val body: HttpBody?,
val dataSupplier: RequestDataSupplier<T>?,
val body: HttpBody<T>?,
val onError: OnError?,
val beforeHooks: List<BeforeHook>,
val afterHooks: List<AfterHook>)

interface RequestDataSupplier {
interface RequestDataSupplier<T> {
/**
* Request data should be a closure that is safe to call on a per-request basis
*/
suspend fun getDataForRequest(): RequestData?
suspend fun getDataForRequest(): RequestData<T>?

fun init() {
// By default this is empty, but implementors can be assured that on a per-call basis, this
Expand All @@ -32,54 +32,58 @@ interface RequestDataSupplier {
}

interface OutputFormat {
fun accept(resp: HttpResponse, rep: RequestData): ByteArray?
fun <T> accept(resp: HttpResponse, rep: RequestData<T>): ByteArray?
}

interface RequestData {
interface RequestData<T> {
@Deprecated("Instead, please migrate to utilising Get")
fun getReplacements(): Map<String, String>
fun get(): T
fun accept(v: String): String
}

interface BasicOutput : FullDataAfterHook

data class HttpBody(val value: String?,
data class HttpBody<T>(val value: String?,
val formData: Map<String, List<String>>?,
val jsonObject: Any?,
val lazyJsonObject: ((RequestData) -> Any)?)
val lazyJsonObject: ((RequestData<T>) -> Any)?)

interface ReplaceableValue<T, V> {
fun get(data: V): T
}

fun String.asReplaceableValue() = object : ReplaceableValue<String, RequestData> {
override fun get(data: RequestData): String {
@Deprecated("Please use accept in request data")
fun String.asReplaceableValue() = object : ReplaceableValue<String, RequestData<List<String>>> {
override fun get(data: RequestData<List<String>>): String {
val replacements = data.getReplacements()
var copy = "" + this@asReplaceableValue
replacements.forEach { key, value -> copy = copy.replace(key, value) }
replacements.forEach { (key, value) -> copy = copy.replace(key, value) }
return copy
}
}

interface BeforeHook

fun (() -> Unit).toPreHook() = object : SimpleBeforeHook {
override fun accept(req: HttpRequest, data: RequestData) {
override fun <T> accept(req: HttpRequest, data: RequestData<T>) {
this@toPreHook()
}
}

interface SessionPersistingBeforeHook : BeforeHook {
suspend fun accept(sessionManager: SessionManager,
suspend fun <T> accept(sessionManager: SessionManager,
cookieJar: CookieJar,
req: HttpRequest,
data: RequestData)
data: RequestData<T>)
}

interface SkipBeforeHook : BeforeHook {
fun skip(requestData: RequestData): Boolean
interface SkipBeforeHook<T> : BeforeHook {
fun skip(requestData: RequestData<T>): Boolean
}

interface SimpleBeforeHook : BeforeHook {
fun accept(req: HttpRequest, data: RequestData)
fun <T> accept(req: HttpRequest, data: RequestData<T>)
}

class Envelope<T>(private val message: T, private val maxRetries: Int = 3) {
Expand Down Expand Up @@ -115,8 +119,8 @@ interface ChainReceivingResponseHook : AfterHook {
fun accept(resp: HttpResponse)
}

interface FullDataAfterHook : AfterHook {
fun accept(req: HttpRequest, resp: HttpResponse, data: RequestData)
interface FullDataAfterHook: AfterHook {
fun <T> accept(req: HttpRequest, resp: HttpResponse, data: RequestData<T>)
}

sealed class HttpResult<out T, out E>
Expand Down
53 changes: 26 additions & 27 deletions api/src/main/kotlin/net/devslash/FetchDsl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ class UnaryAddBuilder<T> {
data class RateLimitOptions(val enabled: Boolean, val count: Int, val duration: Duration)

@FetchDSL
open class CallBuilder(private val url: String) {
open class CallBuilder<T>(private val url: String) {

private var cookieJar: String? = null
var data: RequestDataSupplier? = null
var body: HttpBody? = null
var data: RequestDataSupplier<T>? = null
var body: HttpBody<T>? = null
var type: HttpMethod = HttpMethod.GET
var headers: Map<String, List<Any>>? = null
var onError: OnError? = RetryOnTransitiveError()
var onError: OnError? = RetryOnTransitiveError<T>()

private var preHooksList = mutableListOf<BeforeHook>()
private var postHooksList = mutableListOf<AfterHook>()
Expand All @@ -44,8 +45,8 @@ open class CallBuilder(private val url: String) {
postHooksList.addAll(UnaryAddBuilder<AfterHook>().apply(block).build())
}

fun body(block: BodyBuilder.() -> Unit) {
body = BodyBuilder().apply(block).build()
fun body(block: BodyBuilder<T>.() -> Unit) {
body = BodyBuilder<T>().apply(block).build()
}

private fun mapHeaders(m: Map<String, List<Any>>?): Map<String, List<Value>>? {
Expand All @@ -62,7 +63,7 @@ open class CallBuilder(private val url: String) {
}
}

fun build(): Call {
fun build(): Call<T> {
val localHeaders = headers
if (localHeaders == null || !localHeaders.contains("User-Agent")) {
val set = mutableMapOf<String, List<Any>>()
Expand All @@ -72,36 +73,38 @@ open class CallBuilder(private val url: String) {
set["User-Agent"] = listOf("FetchDSL (Apache-HttpAsyncClient + Kotlin, version not set)")
headers = set
}
return Call(url, mapHeaders(headers), cookieJar, type, data, body,
onError, preHooksList, postHooksList)
return Call(
url, mapHeaders(headers), cookieJar, type, data, body,
onError, preHooksList, postHooksList
)
}
}

@FetchDSL
class BodyBuilder {
class BodyBuilder<T> {
var value: String? = null
var formParams: Map<String, List<String>>? = null
var jsonObject: Any? = null
var lazyJsonObject: ((RequestData) -> Any)? = null
var lazyJsonObject: ((RequestData<T>) -> Any)? = null

fun build(): HttpBody = HttpBody(value, formParams, jsonObject, lazyJsonObject)
fun build(): HttpBody<T> = HttpBody(value, formParams, jsonObject, lazyJsonObject)
}

@FetchDSL
class MultiCallBuilder {
private var calls = mutableListOf<Call>()
private var calls = mutableListOf<Call<*>>()

fun call(url: String, block: CallBuilder.() -> Unit = {}) {
calls.add(CallBuilder(url).apply(block).build())
fun call(url: String, block: CallBuilder<*>.() -> Unit = {}) {
calls.add(CallBuilder<Any>(url).apply(block).build())
}

fun calls() = calls
}

@FetchDSL
class SessionBuilder {
private var calls = mutableListOf<Call>()
private val chained = mutableListOf<List<Call>>()
private var calls = mutableListOf<Call<*>>()
private val chained = mutableListOf<List<Call<*>>>()

var concurrency = 20
var delay: Long? = null
Expand All @@ -113,18 +116,14 @@ class SessionBuilder {
rateOptions = RateLimitOptions(true, count, duration)
}

fun call(url: String, block: CallBuilder.() -> Unit = {}) {
calls.add(CallBuilder(url).apply(block).build())
@JvmName("nonStringCall")
fun <T> call(url: String, block: CallBuilder<T>.() -> Unit = {}) {
calls.add(CallBuilder<T>(url).apply(block).build())
}

// TODO: Re-enable when chaining is stable
// fun chained(block: MultiCallBuilder.(prev: Previous?) -> Unit = {}) {
// if (chained.isNotEmpty()) {
// val line = chained.last().line
//
// }
// chained.add(MultiCallBuilder().apply(block).calls())
// }
fun call(url: String, block: CallBuilder<List<String>>.() -> Unit = {}) {
calls.add(CallBuilder<List<String>>(url).apply(block).build())
}

fun build(): Session = Session(calls, concurrency, delay, rateOptions)
}
Expand Down
4 changes: 2 additions & 2 deletions api/src/main/kotlin/net/devslash/SessionManager.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.devslash

interface SessionManager {
fun call(call: Call, jar: CookieJar)
fun call(call: Call)
fun <T> call(call: Call<T>, jar: CookieJar)
fun <T> call(call: Call<T>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import net.devslash.HttpRequest
import net.devslash.RequestData
import java.net.SocketTimeoutException

class RetryOnTransitiveError : ChannelReceiving<Pair<HttpRequest, RequestData>> {
override suspend fun accept(channel: Channel<Envelope<Pair<HttpRequest, RequestData>>>,
envelope: Envelope<Pair<HttpRequest, RequestData>>,
class RetryOnTransitiveError<T> : ChannelReceiving<Pair<HttpRequest, RequestData<T>>> {
override suspend fun accept(channel: Channel<Envelope<Pair<HttpRequest, RequestData<T>>>>,
envelope: Envelope<Pair<HttpRequest, RequestData<T>>>,
e: Exception) {
if (!envelope.shouldProceed()) {
// fail after a few failures
Expand Down
1 change: 0 additions & 1 deletion benchmarks/src/jmh/kotlin/net/devslash/Bencho.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.devslash

import net.devslash.data.ListDataSupplier
import org.openjdk.jmh.annotations.*
import java.util.concurrent.TimeUnit

Expand Down
9 changes: 1 addition & 8 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ buildscript {
plugins {
base
`maven-publish`
kotlin("jvm") version "1.3.50" apply false
kotlin("jvm") version "1.4.20" apply false
id("com.jfrog.bintray") version "1.8.4" apply false }

repositories {
Expand Down Expand Up @@ -51,13 +51,6 @@ subprojects {
}
}

// tasks.withType(Test::class).configureEach {
// useJUnitPlatform()
// testLogging {
// events("passed", "skipped", "failed")
// }
// }

configure<BintrayExtension> {
user = project.findProperty("bintrayUser") as String? ?: System.getenv("BINTRAY_USER")
key = project.findProperty("bintrayApiKey") as String? ?: System.getenv("BINTRAY_API_KEY")
Expand Down
21 changes: 10 additions & 11 deletions examples/src/main/kotlin/net/devslash/examples/PipeExample.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package net.devslash.examples

import io.ktor.application.call
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import net.devslash.data.FileDataSupplier
import net.devslash.outputs.WriteFile
import io.ktor.application.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import net.devslash.data.ListDataSupplier
import net.devslash.pipes.ResettablePipe
import net.devslash.runHttp
import java.net.ServerSocket
import java.util.concurrent.TimeUnit

fun main() {
val pipe = ResettablePipe({ r, _ -> listOf(String(r.body)) })
val pipe = ResettablePipe<String> { r, _ -> listOf(String(r.body)) }
val port = ServerSocket(0).use { it.localPort }
val server = embeddedServer(Netty, port) {
routing {
Expand All @@ -27,10 +25,11 @@ fun main() {
val address = "http://localhost:$port"
runHttp {
call(address) {
data = FileDataSupplier(this.javaClass.getResource("/in.log").path)
// Ok this asserting that it passesa round List types as its big object. therefore this should
data = ListDataSupplier(listOf("1"))
after {
+pipe
+WriteFile("!1!")
// +WriteFileeFile<Int>("!1!")
}
}
call(address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import net.devslash.RequestDataSupplier
import java.io.File
import java.util.concurrent.atomic.AtomicInteger

class FileDataSupplier(val name: String, private val split: String = " ") : RequestDataSupplier {
class FileDataSupplier(val name: String, private val split: String = " ") : RequestDataSupplier<List<String>> {
private val sourceFile = File(name).readLines()
private val line = AtomicInteger(0)

override suspend fun getDataForRequest(): RequestData? {
override suspend fun getDataForRequest(): RequestData<List<String>>? {
val ourLine = sourceFile.getOrNull(line.getAndIncrement())?.split(split)
return if (ourLine == null) null else ListBasedRequestData(ourLine)
}
Expand Down
Loading