Skip to content

Commit

Permalink
Spider client (#6)
Browse files Browse the repository at this point in the history
Add in some HttpClient helpers, mainly.
  • Loading branch information
alterationx10 authored Nov 13, 2024
1 parent c7455d9 commit 4652416
Show file tree
Hide file tree
Showing 21 changed files with 208 additions and 38 deletions.
14 changes: 0 additions & 14 deletions example/src/main/scala/app/wishingtree/HttpAppExample.scala

This file was deleted.

55 changes: 55 additions & 0 deletions example/src/main/scala/app/wishingtree/SpiderAppExample.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package app.wishingtree

import com.sun.net.httpserver.Filter
import dev.wishingtree.branch.friday.JsonEncoder
import dev.wishingtree.branch.friday.http.JsonBodyHandler
import dev.wishingtree.branch.spider.*
import dev.wishingtree.branch.spider.client.ClientRequest.uri
import dev.wishingtree.branch.spider.client.{Client, ClientRequest}
import dev.wishingtree.branch.spider.server.*
import dev.wishingtree.branch.spider.server.OpaqueSegments.*

import java.net.http.HttpResponse

object SpiderAppExample extends SpiderApp {

import RequestHandler.given

val staticFilesPath = Segments.wd / "site" / "book"
val files = FileContext(staticFilesPath)

case class Person(name: String)

given Conversion[Person, Array[Byte]] = { person =>
summon[JsonEncoder[Person]].encode(person).toJsonString.getBytes
}

val personHandler = new ContextHandler("/") {
override val contextRouter: PartialFunction[
(HttpVerb, Segments),
RequestHandler[Unit, Person]
] = { case HttpVerb.GET -> >> / "person" =>
new RequestHandler[Unit, Person] {
override def handle(request: Request[Unit]): Response[Person] =
Response(Person("Mark"))
}
}
}

val handlers: ContextHandler = files |+| personHandler
ContextHandler.registerHandler(handlers)

val client = Client.build()

val request = ClientRequest
.build(uri"http://localhost:9000/person")

val response =
client.sendAsync(request, JsonBodyHandler.of[Person])

response
.thenApply { resp =>
println(resp.body())
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dev.wishingtree.branch.friday.http

import dev.wishingtree.branch.friday.JsonDecoder

import java.net.http.HttpResponse
import java.net.http.HttpResponse.{BodyHandler, BodySubscribers}
import java.nio.charset.Charset
import scala.util.Try

trait JsonBodyHandler[I] extends BodyHandler[I] {}

object JsonBodyHandler {

inline def of[I](using JsonDecoder[I]): JsonBodyHandler[Try[I]] =
summon[JsonBodyHandler[Try[I]]]

inline given derived[I](using
decoder: JsonDecoder[I]
): JsonBodyHandler[Try[I]] = {
new JsonBodyHandler[Try[I]] {
override def apply(
responseInfo: HttpResponse.ResponseInfo
): HttpResponse.BodySubscriber[Try[I]] = {
BodySubscribers.mapping(
BodySubscribers.ofString(Charset.defaultCharset()),
str => decoder.decode(str)
)
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.wishingtree.branch.friday.http

import dev.wishingtree.branch.friday.JsonEncoder

import java.net.http.HttpRequest
import java.net.http.HttpRequest.BodyPublishers

object JsonBodyPublisher {

inline def of[I](
i: I
)(using jsonEncoder: JsonEncoder[I]): HttpRequest.BodyPublisher = {
BodyPublishers.ofString(jsonEncoder.encode(i).toJsonString)
}

}
4 changes: 3 additions & 1 deletion site/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
- [Spider](./spider/index.md)
- [Piggy](./piggy/index.md)
- [Friday](./friday/index.md)
- [Macaroni](./macaroni/index.md)
- [Macaroni](./macaroni/index.md)
- [Veil](./veil/index.md)
- [Blammo](./blammo/index.md)
4 changes: 4 additions & 0 deletions site/src/blammo/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Blammo

This module contains some helpers around `java.util.logging`. So far, the main thing it has going for it is a
`JsonFormatter` for some structured logging.
9 changes: 5 additions & 4 deletions site/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ things done quickly! Think of it as the framework for your side-project, not you
*Branch* is made up of a collection of modules, each focusing on different parts:

- **Lzy** - Lazy Futures or Tiny Effects?
- **Spider** - A wrapper/framework around the Java HttpServer (I bet you didn't even know there was one!)
- **Spider** - A wrapper/framework around the Java HttpServer (I bet you didn't even know there was one!), as well as
HttpClient helpers.
- **Piggy** - A SQL framework, probably focused on PostgreSQL.
- **Friday** - A Json library, because Scala doesn't already have enough.
- **Macaroni** - Some re-usable helpers and meta-programming utilities.
- **Veil** - `.env` / (Json based) Config utilities.
- **Blammo** - It's better than bad, it's (Json) logging!

... and *more to come*!

A list of other things important to this framework's goals are (but not limited to):

- HTTP Client
- Configuration
- Web Sockets
- Event Bus
- Forms/Validations
- Actors, even if it kills me.
- (HTML) Templating
11 changes: 11 additions & 0 deletions site/src/veil/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Veil

Veil is a small layer to help with configs and environment variables.

Veil can load a `.env`, `.env.test`, or `.env.prod` file based on the environment variable `SCALA_ENV` being set to
`DEV`, `TEST`, or `PROD`. Values in this file are loaded into an in-memory map, and you can look up an env variable with
`Veil.get(key: String): Option[String]`. If it's not present in the in-memory map, it will then search Java's
`System.getenv()`.

There is also a `Config` type-class that helps with loading json from files/resources, and mapping them to a case
class (which presumably is used for configuration).
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.wishingtree.branch.spider.client

import java.net.http.HttpClient

object Client {

def builder: HttpClient.Builder =
HttpClient.newBuilder()

def build(settings: HttpClient.Builder => HttpClient.Builder*): HttpClient =
settings
.foldLeft(builder)((b, s) => s(b))
.build()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dev.wishingtree.branch.spider.client

import dev.wishingtree.branch.spider.ContentType
import java.net.URI
import java.net.http.HttpRequest

object ClientRequest {

extension (sc: StringContext) {
def uri(args: Any*): URI = URI.create(sc.s(args*))
}

extension (rb: HttpRequest.Builder) {
def withContentType(contentType: ContentType): HttpRequest.Builder =
rb.setHeader("Content-Type", contentType.content)
}

def builder(uri: URI): HttpRequest.Builder =
HttpRequest.newBuilder(uri)

def build(
uri: URI,
settings: HttpRequest.Builder => HttpRequest.Builder*
): HttpRequest = {
settings
.foldLeft(
builder(uri)
)((b, s) => s(b))
.build()
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import com.sun.net.httpserver.*
import dev.wishingtree.branch.lzy.Lazy
import dev.wishingtree.branch.lzy.abstractions.Semigroup
import dev.wishingtree.branch.spider.OpaqueSegments.*
import dev.wishingtree.branch.spider.HttpVerb
import dev.wishingtree.branch.spider.server.OpaqueSegments.*

import java.time.{Duration, Instant}
import scala.jdk.CollectionConverters.*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.wishingtree.branch.spider
import dev.wishingtree.branch.spider.OpaqueSegments.*
package dev.wishingtree.branch.spider.server

import OpaqueSegments.*
import dev.wishingtree.branch.spider.*

import java.io.File

Expand All @@ -23,7 +25,7 @@ case class FileContext(rootFilePath: Segments, rootPath: String = "/")
private def defaultExists(path: Segments): Boolean = {
!path.toSeq.lastOption.exists(_.contains("\\.")) &&
FileContext.defaultFiles.foldLeft(false) { (b, d) =>
val file = new File((rootFilePath / d).toPathString)
val file = new File((rootFilePath / path / d).toPathString)
b || (file.exists() && file.isFile)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import OpaqueSegments.*
import FileHandler.given
import RequestHandler.given
import dev.wishingtree.branch.spider.server.FileHandler.given
import dev.wishingtree.branch.spider.server.OpaqueSegments.*
import dev.wishingtree.branch.spider.server.RequestHandler.given
import dev.wishingtree.branch.spider.server.{Request, RequestHandler, Response}

import java.io.{File, FileInputStream}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import java.net.URLEncoder
import java.nio.file.Path
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import dev.wishingtree.branch.spider.server.Request

import java.net.URI

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import com.sun.net.httpserver.HttpExchange
import dev.wishingtree.branch.lzy.Lazy
import dev.wishingtree.branch.spider.server.{RequestHandler, Response}

import scala.jdk.CollectionConverters.*

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import dev.wishingtree.branch.spider.ContentType

case class Response[A](
body: A,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package dev.wishingtree.branch.spider
package dev.wishingtree.branch.spider.server

import com.sun.net.httpserver.{HttpHandler, HttpServer}
import dev.wishingtree.branch.lzy.LazyRuntime

import java.net.InetSocketAddress

trait HttpApp {
trait SpiderApp {

val port: Int =
9000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package dev.wishingtree.branch.spider

import com.sun.net.httpserver.HttpServer
import dev.wishingtree.branch.lzy.LazyRuntime
import dev.wishingtree.branch.spider.server.OpaqueSegments.*
import dev.wishingtree.branch.spider.server.{ContextHandler, RequestHandler}
import munit.FunSuite
import OpaqueSegments.*

import java.net.InetSocketAddress

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.wishingtree.branch.spider

import dev.wishingtree.branch.spider.OpaqueSegments.*
import dev.wishingtree.branch.spider.server.OpaqueSegments.*
import munit.FunSuite

class PathsSpec extends FunSuite {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package dev.wishingtree.branch.spider
import dev.wishingtree.branch.spider.OpaqueSegments.*
import dev.wishingtree.branch.spider.RequestHandler.given
import dev.wishingtree.branch.spider.server.OpaqueSegments.*
import dev.wishingtree.branch.spider.server.{
ContextHandler,
Request,
RequestHandler,
Response
}
import dev.wishingtree.branch.spider.server.RequestHandler.given

import java.net.URI
import java.net.http.HttpClient.Version
Expand Down

0 comments on commit 4652416

Please sign in to comment.