Initial commit with weather data fetcher and parser

This commit is contained in:
Guntis Smaukstelis
2023-04-13 16:58:56 +03:00
commit 40156d6283
15 changed files with 746 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
package fetch
import cats.effect._
import cats.implicits._
import org.http4s._
import org.http4s.blaze.client.BlazeClientBuilder
import org.http4s.client.Client
import org.http4s.headers.Authorization
import com.typesafe.config.ConfigFactory
import java.nio.file.{Files, Paths}
import scala.concurrent.ExecutionContext.global
object FetchData extends IOApp.Simple {
private val config = ConfigFactory.load()
private val basicCredentials = BasicCredentials(config.getString("username"), config.getString("password"))
private val baseUrl = Uri.unsafeFromString(config.getString("url")) // 20220831_1330.csv
// private val baseUrl = Uri.unsafeFromString("https://jsonplaceholder.typicode.com/") // todos/1
def saveToFile(fileName: String, content: String): IO[Unit] = {
val path = Paths.get(s"data/$fileName")
IO(Files.writeString(path, content)).attempt.flatMap {
case Right(_) => IO(println(s"write: $fileName"))
case Left(error) => IO(println(s"Write file '$fileName' failed with error: ${error.getMessage}"))
}
}
def makeRequest(client: Client[IO], url: Uri): IO[Unit] = {
val fileName = url.path.toString()
for {
request <- Request[IO](Method.GET, url)
.withHeaders(Authorization(basicCredentials))
.pure[IO]
responseOrError <- client.expect[String](request).attempt
_ <- responseOrError match {
case Right(response) => saveToFile(fileName, response)
case Left(error) => IO(println(s"Request failed to url: $url with error: ${error.getMessage}"))
}
} yield ()
}
def run: IO[Unit] = {
val fileNames = FileName.generateLast5Hours()
// fileNames.foreach(println)
val urls = fileNames.map(baseUrl / _)
BlazeClientBuilder[IO](global).resource.use { client =>
urls.traverse(url => makeRequest(client, url)) // urls.map(...).sequence
}
}.as(ExitCode.Success)
}
+40
View File
@@ -0,0 +1,40 @@
package fetch
import java.time.format.DateTimeFormatter
import java.time.{LocalDateTime, Duration}
object FileName {
private val interval = Duration.ofMinutes(30)
private val formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm")s
def generateLastHour(): List[String] = {
val now = LocalDateTime.now
generate(now.minusHours(1), now)
}
def generateLast5Hours(): List[String] = {
val now = roundToInterval(LocalDateTime.now, false)
generate(now.minusHours(5), now)
}
private def roundToInterval(time: LocalDateTime, roundUp: Boolean): LocalDateTime = {
val minutes = time.getMinute
val adjustment = if (roundUp) (interval.toMinutes - minutes % interval.toMinutes) % interval.toMinutes
else -minutes % interval.toMinutes
time.plusMinutes(adjustment)
}
// not sure either data are each 10 minutes or each 30 mins of hour
def generate(startTime: LocalDateTime, endTime: LocalDateTime): List[String] = {
val roundStartTime = roundToInterval(startTime, true)
val roundEndTime = roundToInterval(endTime, false)
Iterator.iterate(roundStartTime) { time =>
time.plus(interval)
}.takeWhile(!_.isAfter(roundEndTime))
.filter(_.getMinute == 30)
.map(time => s"${formatter.format(time)}.csv")
.toList
}
}