Skip to content

Commit

Permalink
[format] Introduce scalafmt file (#115)
Browse files Browse the repository at this point in the history
Close #107
  • Loading branch information
ex0ns authored Apr 28, 2021
1 parent e5df2fc commit 0e30d39
Show file tree
Hide file tree
Showing 206 changed files with 5,838 additions and 4,724 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Check code format
uses: jrouly/scalafmt-native-action@v1
with:
version: '2.7.5'
arguments: "-c .scalafmt.conf --test core akka examples"
- uses: jodersky/[email protected]
with:
mill-version: 0.9.5
Expand Down
31 changes: 31 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version = "2.7.5"
maxColumn = 120

align.preset = most
align.multiline = false

continuationIndent.defnSite = 2
assumeStandardLibraryStripMargin = true

docstrings = JavaDoc
lineEndings = preserve

includeCurlyBraceInSelectChains = false
danglingParentheses.preset = true

spaces {
inImportCurlyBraces = true
}

optIn.annotationNewlines = true
newlines.alwaysBeforeMultilineDef = false

rewrite.rules = [SortImports, RedundantBraces]

rewrite.redundantBraces.generalExpressions = false
rewriteTokens = {
"⇒": "=>"
"→": "->"
"←": "<-"
}

8 changes: 4 additions & 4 deletions akka/src/com/bot4s/telegram/api/ActorBroker.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.bot4s.telegram.api

import akka.actor.ActorRef
import com.bot4s.telegram.models.{Update, User}
import com.bot4s.telegram.models.{ Update, User }

import scala.concurrent.Future

/**
* Provides bare-bones harness for actors.
* Redirects all Updates to a broker actor.
*/
* Provides bare-bones harness for actors.
* Redirects all Updates to a broker actor.
*/
trait ActorBroker extends BotBase[Future] {

def broker: Option[ActorRef]
Expand Down
100 changes: 50 additions & 50 deletions akka/src/com/bot4s/telegram/api/GameManager.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,65 @@ import java.util.Base64

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.{Directive1, Route}
import akka.http.scaladsl.server.{ Directive1, Route }
import com.bot4s.telegram.marshalling
import com.bot4s.telegram.methods.{GetGameHighScores, SetGameScore}
import com.bot4s.telegram.models.{CallbackQuery, ChatId, User}
import com.bot4s.telegram.methods.{ GetGameHighScores, SetGameScore }
import com.bot4s.telegram.models.{ CallbackQuery, ChatId, User }
import com.bot4s.telegram.future.BotExecutionContext
import io.circe.generic.extras.semiauto._
import io.circe.generic.semiauto.deriveDecoder
import io.circe.{Decoder, Encoder}
import io.circe.{ Decoder, Encoder }

import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.util.{ Failure, Success }

/**
* Provides basic endpoints to manage game's scoring.
* setScore
* getScore
*
* Game data is shared with the game, base64-encoded in the URL.
* This offer NO security at all, all data is passed au-clair.
* Altering the scores is trivial.
*
* The "secure" implementations I've seen so far are based on security
* though obscurity, all of them can be reverse-engineered to alter the scores.
*
* If you happen to have an idea of how to make it secure, please open an issue,
* or even better, submit a PR with your approach.
*/
* Provides basic endpoints to manage game's scoring.
* setScore
* getScore
*
* Game data is shared with the game, base64-encoded in the URL.
* This offer NO security at all, all data is passed au-clair.
* Altering the scores is trivial.
*
* The "secure" implementations I've seen so far are based on security
* though obscurity, all of them can be reverse-engineered to alter the scores.
*
* If you happen to have an idea of how to make it secure, please open an issue,
* or even better, submit a PR with your approach.
*/
trait GameManager extends WebRoutes {
this: BotBase[Future] with BotExecutionContext with AkkaImplicits =>

import com.bot4s.telegram.marshalling._

private def extractPayload: Directive1[Payload] = {
private def extractPayload: Directive1[Payload] =
headerValueByName("Referer").map { referer: String =>
val parts = referer.split("\\?payload=")
val parts = referer.split("\\?payload=")
val encodedPayload = URLDecoder.decode(parts(1), "UTF-8")
Payload.base64Decode(encodedPayload)
}
}

val gameManagerRoute: Route = {
(post &
path("games" / "api" / "setScore") &
parameter("score".as[Long]) &
extractPayload) { (score, payload) =>

onComplete(request(
SetGameScore(payload.user.id,
score,
chatId = payload.chatId,
messageId = payload.messageId,
inlineMessageId = payload.inlineMessageId))) {
onComplete(
request(
SetGameScore(
payload.user.id,
score,
chatId = payload.chatId,
messageId = payload.messageId,
inlineMessageId = payload.inlineMessageId
)
)
) {

case Success(value) => complete(StatusCodes.OK)
case Failure(ex) =>
complete((StatusCodes.InternalServerError,
s"An error occurred: ${ex.getMessage}"))
complete((StatusCodes.InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
} ~
(get &
Expand All @@ -71,30 +73,29 @@ trait GameManager extends WebRoutes {
onComplete(request(payload.toGetGameHighScores)) {
case Success(scores) => complete(marshalling.toJson(scores))
case Failure(ex) =>
complete((StatusCodes.InternalServerError,
s"An error occurred: ${ex.getMessage}"))
complete((StatusCodes.InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
}
}
}

/**
* Data shared with the game.
*/
* Data shared with the game.
*/
case class Payload(
user : User,
chatId : Option[ChatId] = None,
messageId : Option[Int] = None,
inlineMessageId : Option[String] = None,
gameManagerHost : String,
gameShortName : String) {
user: User,
chatId: Option[ChatId] = None,
messageId: Option[Int] = None,
inlineMessageId: Option[String] = None,
gameManagerHost: String,
gameShortName: String
) {

def toGetGameHighScores = GetGameHighScores(user.id, chatId, messageId, inlineMessageId)

def base64Encode: String = {
val payloadJson = marshalling.toJson[Payload](this)
val encodedPayload = Base64.getEncoder.encodeToString(
payloadJson.getBytes(StandardCharsets.UTF_8))
val payloadJson = marshalling.toJson[Payload](this)
val encodedPayload = Base64.getEncoder.encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8))

encodedPayload
}
Expand All @@ -104,22 +105,21 @@ object Payload {

def base64Decode(encodedPayload: String): Payload = {
val base64payload = URLDecoder.decode(encodedPayload, "UTF-8")
val jsonPayload = new String(Base64.getDecoder.decode(base64payload),
StandardCharsets.UTF_8)
val payload = marshalling.fromJson[Payload](jsonPayload)
val jsonPayload = new String(Base64.getDecoder.decode(base64payload), StandardCharsets.UTF_8)
val payload = marshalling.fromJson[Payload](jsonPayload)

payload
}

def forCallbackQuery(gameManagerHost: String)(implicit cbq: CallbackQuery): Payload = {
def forCallbackQuery(gameManagerHost: String)(implicit cbq: CallbackQuery): Payload =
Payload(
cbq.from,
cbq.message.map(_.source),
cbq.message.map(_.messageId),
cbq.inlineMessageId,
gameManagerHost,
cbq.gameShortName.get) // throws if not a game callback
}
cbq.gameShortName.get
) // throws if not a game callback

import marshalling._
implicit val payloadEncoder: Encoder[Payload] = deriveConfiguredEncoder[Payload]
Expand Down
8 changes: 4 additions & 4 deletions akka/src/com/bot4s/telegram/api/WebRoutes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import akka.http.scaladsl.server.Route
import com.bot4s.telegram.future.BotExecutionContext
import com.typesafe.scalalogging.StrictLogging

import scala.concurrent.{Future, Promise}
import scala.concurrent.{ Future, Promise }

trait WebRoutes extends BotBase[Future] with StrictLogging {
this: BotExecutionContext with AkkaImplicits =>
Expand Down Expand Up @@ -45,9 +45,9 @@ trait WebRoutes extends BotBase[Future] with StrictLogging {
}
super.shutdown()
for {
b <- bindingFuture
_ <- b.unbind()
t <- system.terminate()
b <- bindingFuture
_ <- b.unbind()
t <- system.terminate()
} /* do */ {
eol.success(())
eol = null
Expand Down
54 changes: 25 additions & 29 deletions akka/src/com/bot4s/telegram/api/Webhook.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,48 @@ import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import com.bot4s.telegram.future.BotExecutionContext
import com.bot4s.telegram.methods.SetWebhook
import com.bot4s.telegram.models.{InputFile, Update}
import com.bot4s.telegram.models.{ InputFile, Update }
import com.typesafe.scalalogging.StrictLogging

import scala.concurrent.Future
import scala.util.control.NonFatal

/** Uses a webhook, as an alternative to polling, to receive updates.
*
* Automatically registers the webhook on run().
*/
/**
* Uses a webhook, as an alternative to polling, to receive updates.
*
* Automatically registers the webhook on run().
*/
trait Webhook extends WebRoutes with StrictLogging {
this: BotBase[Future] with BotExecutionContext with AkkaImplicits =>

import com.bot4s.telegram.marshalling._
import com.bot4s.telegram.marshalling.AkkaHttpMarshalling._

/** URL for the webhook.
*
* 'webhookUrl' must be consistent with 'webhookRoute' (by default '/').
*/
/**
* URL for the webhook.
*
* 'webhookUrl' must be consistent with 'webhookRoute' (by default '/').
*/
val webhookUrl: String

/**
* Webhook route.
*
* 'webhookUrl/' by default.
*
* @return Route handler to process updates.
*/
* Webhook route.
*
* 'webhookUrl/' by default.
*
* @return Route handler to process updates.
*/
def webhookRoute: Route = pathEndOrSingleSlash(webhookReceiver)

/**
* Specify self-signed certificate file.
* Check instructions at [[https://core.telegram.org/bots/self-signed Using self-signed certificates]].
*
* @return
*/
* Specify self-signed certificate file.
* Check instructions at [[https://core.telegram.org/bots/self-signed Using self-signed certificates]].
*
* @return
*/
def certificate: Option[InputFile] = None

def webhookReceiver: Route = {
def webhookReceiver: Route =
entity(as[Update]) { update =>
try {
receiveUpdate(update, None)
Expand All @@ -54,20 +56,14 @@ trait Webhook extends WebRoutes with StrictLogging {
}
complete(StatusCodes.OK)
}
}

abstract override def routes: Route = webhookRoute ~ super.routes

abstract override def run(): Future[Unit] = {
request(
SetWebhook(
url = webhookUrl,
certificate = certificate,
allowedUpdates = allowedUpdates)).flatMap {
abstract override def run(): Future[Unit] =
request(SetWebhook(url = webhookUrl, certificate = certificate, allowedUpdates = allowedUpdates)).flatMap {
case true => super.run() // spawn WebRoutes
case false =>
logger.error("Failed to set webhook")
throw new RuntimeException("Failed to set webhook")
}
}
}
Loading

0 comments on commit 0e30d39

Please sign in to comment.