Created
September 30, 2023 19:19
-
-
Save TomTriple/3fb5b67781383eea681cd713a1d71fd9 to your computer and use it in GitHub Desktop.
Flash.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package zio.http | |
import zio.schema.Schema | |
import zio.schema.codec.JsonCodec | |
import java.net.URLDecoder | |
sealed trait Flash[+A] { self => | |
def flatMap[B](f: A => Flash[B]):Flash[B] = Flash.FlatMap(self, f) | |
def map[B](f: A => B):Flash[B] = self.flatMap(a => Flash.succeed(f(a))) | |
def run(request: Request):Either[Throwable, A] = Flash.run(self, request) | |
def orElse[B >: A](that: => Flash[B]):Flash[B] = Flash.OrElse(self, that) | |
def |[B >: A](that: => Flash[B]):Flash[B] = self.orElse(that) | |
def zip[B](that: => Flash[B]):Flash[(A, B)] = self.zipWith(that)((a, b) => a -> b) | |
def zipWith[B, C](that: => Flash[B])(f: (A, B) => C):Flash[C] = | |
self.flatMap(a => that.map(b => f(a, b))) | |
def optional:Flash[Option[A]] = self.map(Option(_)) | Flash.succeed(None) | |
} | |
object Flash { | |
private[zio] val COOKIE_NAME = "zio-http-flash" | |
private case class Get[A](schema: Schema[A], key: String) extends Flash[A] | |
private case class FlatMap[A, B](self: Flash[A], f: A => Flash[B]) extends Flash[B] | |
private case class OrElse[A, B >: A](self: Flash[A], that:Flash[B]) extends Flash[B] | |
private case class WithInput[A](f:Map[String, String] => Flash[A]) extends Flash[A] | |
private case class Succeed[A](a: A) extends Flash[A] | |
private def succeed[A](a:A):Flash[A] = Succeed(a) | |
private def withInput[A](f: Map[String, String] => Flash[A]):Flash[A] = WithInput(f) | |
def get[A](key: String)(implicit ev: Schema[A]): Flash[A] = Flash.Get(ev, key) | |
def getString(key:String):Flash[String] = get[String](key) | |
def getFloat(key:String):Flash[Float] = get[Float](key) | |
def getDouble(key:String):Flash[Double] = get[Double](key) | |
def getInt(key:String):Flash[Int] = get[Int](key) | |
def getLong(key:String):Flash[Long] = get[Long](key) | |
def getBoolean(key:String):Flash[Boolean] = get[Boolean](key) | |
def getType[A : Schema]:Flash[A] = withInput { map => | |
map.keys.map(a => Flash.get(a)(Schema[A])).reduce(_ | _) | |
} | |
private def loop[A](flash: Flash[A], map: Map[String, String]): Either[Throwable, A] = | |
flash match { | |
case Get(schema, key) => | |
map.get(key).toRight(new Throwable(s"no key: $key")).flatMap { value => | |
JsonCodec.jsonDecoder(schema).decodeJson(value).left.map(e => new Throwable(e)) | |
} | |
case WithInput(f) => | |
loop(f(map), map) | |
case OrElse(self, that) => | |
loop(self, map).orElse(loop(that, map)).asInstanceOf[Either[Throwable, A]] | |
case FlatMap(self, f) => | |
loop(self, map) match { | |
case Right(value) => loop(f(value), map) | |
case Left(e) => Left(e) | |
} | |
case Succeed(a) => Right(a) | |
} | |
def run[A](flash: Flash[A], request: Request):Either[Throwable, A] = { | |
request | |
.cookie(COOKIE_NAME) | |
.toRight(new Throwable("flash cookie doesn't exist")) | |
.flatMap { cookie => | |
try Right(URLDecoder.decode(cookie.content, java.nio.charset.Charset.defaultCharset)) | |
catch { | |
case e:Exception => Left(e) | |
} | |
} | |
.flatMap { cookieContent => | |
JsonCodec.jsonDecoder(Schema.map[String,String]).decodeJson(cookieContent).left.map(e => new Throwable(e)) | |
}.flatMap(loop(flash, _)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment