Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ The project is a multi-module sbt project with the following key directories:
- **Testing**: Tests are run using `sbt test`.
- **Running Locally**: The `scripts` directory contains `docker-compose.yml` files to run the application stack (backend, frontend, database) locally.
- **CI/CD**: GitHub Actions are configured to build and test the application on push and pull requests.
- **Code style**: Run `scalafixAll` and `scalafmtAll` every time before make a commit to make the style consistently.
- **Code style**: You MUST run `sbt scalafixAll` and `sbt scalafmtAll` before every commit and before creating a Pull Request to ensure code style consistency.

## Repository

Expand Down
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.scalajs.linker.interface.ModuleSplitStyle

import scala.sys.process.*

lazy val projectVersion = "2.4.2"
lazy val projectVersion = "2.4.3"
lazy val organizationName = "ru.trett"
lazy val scala3Version = "3.7.4"
lazy val circeVersion = "0.14.15"
Expand Down Expand Up @@ -120,6 +120,7 @@ lazy val server = project
).map(_ % doobieVersion),
libraryDependencies += "org.jsoup" % "jsoup" % "1.21.2",
libraryDependencies += "com.github.blemale" %% "scaffeine" % "5.3.0",
libraryDependencies += "io.circe" %% "circe-fs2" % "0.14.1",
libraryDependencies += "org.flywaydb" % "flyway-database-postgresql" % "11.17.2" % "runtime",
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.19" % Test,
libraryDependencies += "org.scalamock" %% "scalamock" % "7.5.2" % Test,
Expand Down
18 changes: 18 additions & 0 deletions client/src/main/scala/client/Models.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ object Decoders:
}
given Decoder[SummaryResponse] = deriveDecoder

import SummaryEvent.*
given Decoder[Content] = deriveDecoder
given Decoder[Metadata] = deriveDecoder
given Decoder[FunFact] = deriveDecoder
given Decoder[Error] = deriveDecoder

given Decoder[SummaryEvent] = Decoder.instance { cursor =>
cursor.downField("type").as[String].flatMap {
case "content" => cursor.as[Content]
case "metadata" => cursor.as[Metadata]
case "funFact" => cursor.as[FunFact]
case "error" => cursor.as[Error]
case "done" => Right(Done)
case other =>
Left(io.circe.DecodingFailure(s"Unknown SummaryEvent type: $other", cursor.history))
}
}

final class Model:
val feedVar: Var[FeedItemList] = Var(List())
val channelVar: Var[ChannelList] = Var(List())
Expand Down
30 changes: 30 additions & 0 deletions client/src/main/scala/client/NetworkUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import scala.util.Failure
import scala.util.Success
import scala.util.Try
import ru.trett.rss.models.UserSettings
import ru.trett.rss.models.SummaryEvent

import scala.collection.mutable.ListBuffer

object NetworkUtils {

Expand Down Expand Up @@ -68,4 +71,31 @@ object NetworkUtils {

def logout(): EventStream[Unit] =
FetchStream.post("/api/logout", _.body("")).mapTo(())

def streamSummary(url: String): EventStream[Try[SummaryEvent]] =
val source = ListBuffer.empty[dom.EventSource]
EventStream.fromCustomSource[Try[SummaryEvent]](
shouldStart = _ => true,
start = (fireValue, fireError, getStartIndex, getIsStarted) => {
val s = new dom.EventSource(url)
source += s

s.onmessage = msg =>
if getIsStarted() then
decode[SummaryEvent](msg.data.toString) match
case Right(SummaryEvent.Done) =>
fireValue(Success(SummaryEvent.Done))
s.close()
case Right(event) => fireValue(Success(event))
case Left(err) => fireValue(Failure(err))

s.onerror = _ =>
if getIsStarted() then
fireValue(Failure(new RuntimeException("Stream error")))
s.close()
},
stop = _ =>
source.foreach(_.close())
source.clear()
)
}
Loading