ZIO client
A ZIO-based ShowdownClient. Each method returns a ZIO
program and is not effectful in itself.
Connecting to the server
You can create a ZIOShowdownClient from a ZIO-HTTP Client then use ZIOShowdownClient#openConnection to connect to the Pokemon Showdown server.
val zHttpClient: Client = ???
val connectionProgram: ZIO[Scope, ProtocolError, ZIOShowdownConnection] = ZIOShowdownClient(zHttpClient).openConnection()
Note that openConnection
only returns a program. It does not perform any effect and need to be run by the ZIO runtime (e.g using a ZIOApp).
Receiving messages
Server-sent messages can be treated as a ZStream using ZIOShowdownConnection#serverMessages.
val connection: ZIOShowdownConnection = ???
val consumeUntilStop: Task[Unit] = connection
.serverMessages
.runForeachWhile:
case Right(GlobalMessage.PrivateMessage(User(sender, _), _, content)) if content.value.equalsIgnoreCase("ping") =>
for
_ <- Console.printLine(s"< $sender: Ping!")
_ <- connection.sendPrivateMessage(sender, ChatContent("Pong!"))
_ <- Console.printLine(s"> $sender: Pong!")
yield
true
case Right(GlobalMessage.PrivateMessage(User(sender, _), _, content)) if content.value.equalsIgnoreCase("stop") =>
for
_ <- Console.printLine(s"< $sender: Received stop command")
_ <- connection.sendPrivateMessage(sender, ChatContent("Goodbye!"))
yield
false
case Left(error) =>
for
_ <- Console.printLine(s"An error occurred: $sender")
yield
true
Using ZIO's service pattern
Both ZIOShowdownClient and ZIOShowdownConnection's companion object provide service accessors to be used with ZIO's service pattern.
Here is the example above rewritten using the service pattern:
val connectionProgram: ZIO[ZIOShowdownConnection, Throwable, Unit] =
ZIOShowdownConnection
.serverMessages
.runForeachWhile:
case Right(GlobalMessage.PrivateMessage(User(sender, _), _, content)) if content.value.equalsIgnoreCase("ping") =>
for
_ <- Console.printLine(s"< $sender: Ping!")
_ <- connection.sendPrivateMessage(sender, ChatContent("Pong!"))
_ <- Console.printLine(s"> $sender: Pong!")
yield
true
case Right(GlobalMessage.PrivateMessage(User(sender, _), _, content)) if content.value.equalsIgnoreCase("stop") =>
for
_ <- Console.printLine(s"< $sender: Received stop command")
_ <- connection.sendPrivateMessage(sender, ChatContent("Goodbye!"))
yield
false
case Left(error) =>
for
_ <- Console.printLine(s"An error occurred: $sender")
yield
true
val clientProgram: ZIO[Scope & ZIOShowdownClient, Throwable, Unit] =
ZIOShowdownClient
.openConnection()
.flatMap(connection => connectionProgram.provideSome[ZIOShowdownClient](ZLayer.succeed(connection)))
//Can be used in a ZIOApp
val program: Task[Unit] =
ZIO.scoped(clientProgram).provide(
Client.default,
ZIOShowdownClient.layer
)
Note: authentication process has been truncated for readability reasons. Check this page instead.