Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dhpiggott committed Aug 7, 2023
1 parent e1c8cd0 commit f02a235
Show file tree
Hide file tree
Showing 13 changed files with 518 additions and 15 deletions.
60 changes: 54 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ lazy val allModules = Seq(
decline,
codegenPlugin,
benchmark,
sandbox,
`aws-sandbox`,
`oauth-sandbox`,
protocol,
protocolTests,
`aws-kernel`,
Expand Down Expand Up @@ -885,9 +886,9 @@ lazy val benchmark = projectMatrix
.jvmPlatform(List(Scala213), jvmDimSettings)
.settings(Smithy4sBuildPlugin.doNotPublishArtifact)

lazy val sandbox = projectMatrix
.in(file("modules/sandbox"))
.dependsOn(`aws-http4s`, http4s)
lazy val `aws-sandbox` = projectMatrix
.in(file("modules/aws-sandbox"))
.dependsOn(`aws-http4s`)
.settings(
Compile / allowedNamespaces := Seq(
"com.amazonaws.cloudwatch",
Expand All @@ -897,20 +898,67 @@ lazy val sandbox = projectMatrix
// Ignore deprecation warnings here - it's all generated code, anyway.
scalacOptions ++= Seq(
"-Wconf:cat=deprecation:silent"
) ++ scala3MigrationOption(scalaVersion.value),
),
smithy4sDependencies ++= Seq(
"com.disneystreaming.smithy" % "aws-cloudwatch-spec" % "2023.02.10",
"com.disneystreaming.smithy" % "aws-ec2-spec" % "2023.02.10"
),
libraryDependencies ++= Seq(
Dependencies.Http4s.emberClient.value,
Dependencies.slf4jNop
Dependencies.slf4jSimple % Runtime
),
run / fork := true
)
.jvmPlatform(List(Scala213), jvmDimSettings)
.settings(Smithy4sBuildPlugin.doNotPublishArtifact)

lazy val `oauth-sandbox` = projectMatrix
.in(file("modules/oauth-sandbox"))
// TODO: Nope
.dependsOn(`aws-http4s`, http4s)
.settings(
Compile / allowedNamespaces := Seq(
"smithy4s.sandbox.oauth"
),
smithySpecs := IO.listFiles(
(ThisBuild / baseDirectory).value / "modules" / "oauth-sandbox" / "smithy"
),
genSmithy(Compile),
// Ignore deprecation warnings here - it's all generated code, anyway.
scalacOptions ++= Seq(
"-Wconf:cat=deprecation:silent"
),
libraryDependencies ++= Seq(
// TODO: DRY
// TODO: Replace with cats-effect and jsoniter?
"dev.zio" %% "zio" % "2.0.6",
"dev.zio" %% "zio-interop-cats" % "23.0.0.1",
"dev.zio" %% "zio-stacktracer" % "2.0.6",
"dev.zio" %% "zio-nio" % "2.0.1",
"io.circe" %% "circe-core" % "0.14.5",
"io.circe" %% "circe-parser" % "0.14.5",
"org.gnieh" %% "fs2-data-xml" % "1.5.1",
"org.http4s" %% "http4s-circe" % "0.23.18",
"org.http4s" %% "http4s-client" % "0.23.18",
"org.http4s" %% "http4s-core" % "0.23.18",
"org.http4s" %% "http4s-dsl" % "0.23.18",
"org.http4s" %% "http4s-ember-client" % "0.23.18",
"org.http4s" %% "http4s-ember-server" % "0.23.18",
"org.typelevel" %% "case-insensitive" % "1.3.0",
"org.typelevel" %% "cats-effect" % "3.4.5",
"org.typelevel" %% "cats-effect-kernel" % "3.4.5",
Dependencies.Http4s.emberClient.value,
Dependencies.Http4s.emberServer.value,
// TODO: Can this be replaced?
Dependencies.slf4jSimple % Runtime
),
run / fork := true,
run / connectInput := true,
run / outputStrategy := Some(OutputStrategy.StdoutOutput)
)
.jvmPlatform(List(Scala3), jvmDimSettings)
.settings(Smithy4sBuildPlugin.doNotPublishArtifact)

def genSmithy(config: Configuration) = Def.settings(
Seq(
config / sourceGenerators := Seq(genSmithyScala(config).taskValue),
Expand Down
Empty file added errors
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
* limitations under the License.
*/

package smithy4s
package sandbox
package aws

import cats.effect._
import com.amazonaws.cloudwatch
import com.amazonaws.ec2
Expand Down
77 changes: 77 additions & 0 deletions modules/oauth-sandbox/smithy/token_api.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
$version: "2"

namespace smithy4s.sandbox.oauth

@tokenExchange
service TokenApi {
operations: [
CreateAccessToken
]
errors: [
BadRequest
]
}

@http(method: "POST", uri: "/token")
operation CreateAccessToken {
input := {
@required
@xmlName("client_id")
clientId: ClientId
@required
@xmlName("client_secret")
clientSecret: ClientSecret
@required
@xmlName("grant_type")
grantType: GrantType
@required
@xmlName("refresh_token")
refreshToken: RefreshToken
}
output := {
@required
@jsonName("access_token")
accessToken: AccessToken
@required
@jsonName("expires_in")
expiresIn: ExpiresIn
@required
@jsonName("refresh_token")
refreshToken: RefreshToken
@required
@jsonName("token_type")
tokenType: TokenType
}
}

enum GrantType {
REFRESH_TOKEN = "refresh_token"
}

string ClientId

string ClientSecret

long ExpiresIn

string AccessToken

string RefreshToken

enum TokenType {
BEARER = "Bearer"
}

@error("client")
@httpError(400)
structure BadRequest {
@required
error: Error
}

enum Error {
INVALID_CLIENT = "invalid_client"
INVALID_GRANT = "invalid_grant"
UNAUTHORIZED_CLIENT = "unauthorized_client"
UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type"
}
29 changes: 29 additions & 0 deletions modules/oauth-sandbox/smithy/token_exchange.smithy
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
$version: "2"

namespace smithy4s.sandbox.oauth

// TODO: Move out of sandbox.

@protocolDefinition
@trait(selector: "service")
structure tokenExchange {}

// TODO: Make UrlFormSchemaVisitors work with this.

/// Unwraps the values of a list, set, or map into the containing /
//structure/union.
@trait(
selector: ":is(structure, union) > :test(member > :test(list, map))",
breakingChanges: [{change: "any"}]
)
structure queryFlattened {}

// TODO: Make UrlFormSchemaVisitors work with this.

/// The queryName trait allows a serialized form key to differ from a structure
/// member name used in the model.
@trait(
selector: ":is(structure, union) > member",
breakingChanges: [{change: "any"}]
)
string queryName
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ import smithy4s.json.Json
import smithy4s.kinds.PolyFunction
import smithy4s.schema.CachedSchemaCompiler

private[http4s] class OAuthCodecs(
// TODO
// private[http4s]
class OAuthCodecs(
val maxArity: Int,
val explicitDefaultsEncoding: Boolean
) extends SimpleProtocolCodecs {

private val jsonHintMask =
alloy.SimpleRestJson.protocol.hintMask
private val jsonHintMask = alloy.SimpleRestJson.protocol.hintMask

private val jsonUnderlyingCodecs = Json.payloadCodecs
.withJsoniterCodecCompiler(
Expand All @@ -55,8 +56,8 @@ private[http4s] class OAuthCodecs(
EntityEncoders.fromPayloadCodecK[F](jsonMediaType)
)

// scalafmt: {maxColumn = 120}
def jsonEntityDecoders[F[_]: Concurrent]: CachedSchemaCompiler[EntityDecoder[F, *]] = jsonUnderlyingCodecs.mapK(
def jsonEntityDecoders[F[_]: Concurrent]
: CachedSchemaCompiler[EntityDecoder[F, *]] = jsonUnderlyingCodecs.mapK(
EntityDecoders.fromPayloadCodecK[F](jsonMediaType)
)

Expand Down Expand Up @@ -104,7 +105,8 @@ private[http4s] class OAuthCodecs(
)
}

private def urlFormRequestDecoderCompilers[F[_]: Concurrent]: CachedSchemaCompiler[RequestDecoder[F, *]] =
private def urlFormRequestDecoderCompilers[F[_]: Concurrent]
: CachedSchemaCompiler[RequestDecoder[F, *]] =
RequestDecoder.restSchemaCompiler[F](
metadataDecoderCompiler = Metadata.AwsDecoder,
entityDecoderCompiler = UrlForm
Expand Down Expand Up @@ -134,7 +136,8 @@ private[http4s] class OAuthCodecs(
)

// TODO: Use fromPayloadCodec, here and elsewhere?
private def urlFormEntityDecoder[F[_]: Concurrent]: EntityDecoder[F, UrlForm] =
private def urlFormEntityDecoder[F[_]: Concurrent]
: EntityDecoder[F, UrlForm] =
EntityDecoders.fromHttpMediaReader(
HttpMediaTyped(
HttpMediaType("application/x-www-form-urlencoded"),
Expand All @@ -153,7 +156,8 @@ private[http4s] class OAuthCodecs(
)
)

private def urlFormRequestEncoderCompilers[F[_]: Concurrent]: CachedSchemaCompiler[RequestEncoder[F, *]] =
private def urlFormRequestEncoderCompilers[F[_]: Concurrent]
: CachedSchemaCompiler[RequestEncoder[F, *]] =
RequestEncoder.restSchemaCompiler[F](
metadataEncoderCompiler = Metadata.AwsEncoder,
entityEncoderCompiler = UrlForm
Expand Down
72 changes: 72 additions & 0 deletions modules/oauth-sandbox/src-3/ReferenceClient.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2021-2022 Disney Streaming
*
* Licensed under the Tomorrow Open Source Technology License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://disneystreaming.github.io/TOST-1.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package smithy4s
package sandbox
package oauth

import io.circe.Json
import org.http4s.*
import org.http4s.client.middleware.Logger
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.client.dsl.Http4sClientDsl
import org.http4s.dsl.io._
import org.http4s.ember.client.EmberClientBuilder
import zio.*
import zio.interop.catz.*

object ReferenceClient extends ZIOAppDefault with Http4sClientDsl[Task]:

override def run: RIO[Scope, Unit] = for
portString <- Console.readLine("Enter port: ")
port <- ZIO
.fromOption(portString.toIntOption)
.mapError(_ => Exception(s"$portString is not a valid port."))
client <- EmberClientBuilder
.default[Task]
.build
.map(
Logger.colored(
logHeaders = true,
logBody = true,
logAction = Some(Console.printLine(_))
)
)
.toScopedZIO
oauthSandboxApiUri = Uri(
scheme = Some(Uri.Scheme.http),
authority = Some(Uri.Authority(port = Some(port)))
)
_ <- (for
createAccessTokenOutput <- client
.run(
POST(
UrlForm(
"client_id" -> expectedClientId.value,
"client_secret" -> expectedClientSecret.value,
"grant_type" -> "refresh_token",
"refresh_token" -> expectedRefreshToken.value
),
oauthSandboxApiUri / "token"
)
)
.use(_.as[Json])
accessToken <- ZIO.fromEither(
createAccessTokenOutput.hcursor.get[String]("access_token")
)
_ <- Console.printLine(s"Access token: $accessToken")
yield ()).repeat(Schedule.spaced(1.second))
yield ()
Loading

0 comments on commit f02a235

Please sign in to comment.