1
+ package controllers
2
+
3
+ import javax .inject ._
4
+
5
+ import models .Location
6
+ import play .api ._
7
+ import play .api .mvc ._
8
+ import play .api .libs .json ._
9
+ import play .api .libs .json .Reads ._
10
+ // import play.api.libs.functional.syntax._
11
+ import play .api .libs .ws ._
12
+
13
+ import scala .concurrent .{ExecutionContext , Future }
14
+ import scala .concurrent .duration ._
15
+ import play .modules .reactivemongo ._
16
+ import reactivemongo .play .json .collection ._
17
+ import akka .actor .ActorSystem
18
+ import akka .stream .ActorMaterializer
19
+ import akka .stream .scaladsl ._
20
+ import akka .util .ByteString
21
+ import reactivemongo .play .json ._
22
+ import reactivemongo .bson ._
23
+ import reactivemongo .bson .{BSONDocument , BSONDocumentReader }
24
+ import reactivemongo .api .collections .bson .BSONCollection
25
+
26
+ import models .Station
27
+ import models .Station ._
28
+
29
+ @ Singleton
30
+ class StationController @ Inject ()(val reactiveMongoApi : ReactiveMongoApi , val ws : WSClient )(implicit exec : ExecutionContext ) extends Controller with MongoController with ReactiveMongoComponents {
31
+ lazy val stations = database.map(_.collection(" stations" ))
32
+
33
+ def geocode (rawAddress : Option [String ] = None , timeout : FiniteDuration = 2 .seconds): Future [Seq [Double ]] = {
34
+ if (rawAddress.isEmpty) return Future (Seq .empty[Double ])
35
+
36
+ val wsRequest = ws.url(s " http://maps.googleapis.com/maps/api/geocode/json " )
37
+ .withHeaders(ACCEPT -> " applicaton/json" )
38
+ .withQueryString(" sensor" -> " false" )
39
+ .withQueryString(" address" -> rawAddress.get)
40
+ .withRequestTimeout(timeout)
41
+
42
+ wsRequest.get().map { wsResponse =>
43
+ (wsResponse.json \ " status" ).as[String ] match {
44
+ case " OK" =>
45
+ val location = (wsResponse.json \ " results" ) (0 ) \ " geometry" \ " location"
46
+ Seq [Double ]((location \ " lng" ).as[Double ], (location \ " lat" ).as[Double ])
47
+ case _ => Seq .empty[Double ]
48
+ }
49
+ }
50
+ }
51
+
52
+ def geocode_it (address : String ) = Action .async {
53
+ for {location <- geocode(Some (address))} yield Ok (Json .toJson(BSONDocument (" coordinates" -> location)))
54
+ }
55
+
56
+ def listStations (at : Seq [Double ] = Seq .empty[Double ], limit : Int , maxDistance : Int ): Future [List [Station ]] = {
57
+ stations.flatMap {
58
+ var query = BSONDocument (" company" -> " petrol" )
59
+
60
+ if (at.nonEmpty) {
61
+ query = query.add(BSONDocument (" loc" -> BSONDocument (" $near" -> BSONDocument (
62
+ " $geometry" -> BSONDocument (" $type" -> " Point" , " coordinates" -> at),
63
+ " $maxDistance" -> maxDistance)
64
+ )))
65
+ }
66
+
67
+ var projection = BSONDocument (" key" -> 1 , " address" -> 1 , " loc" -> 1 , " updated_at" -> 1 , " scraped_url" -> 1 )
68
+
69
+ projection = projection.add(" prices" -> " 1" )
70
+
71
+ _.find(query, projection).cursor[Station ]().collect[List ](limit)
72
+ }
73
+ }
74
+
75
+ def index (near : Option [String ] = None , at : Option [String ], limit : Int , maxDistance : Int ) = Action .async {
76
+ val now = System .nanoTime
77
+ val atLocation = at.fold(Seq .empty[Double ])(_.split(" ," ).map(_.toDouble))
78
+
79
+ val composition : Future [List [Station ]] = if (near.isEmpty && atLocation.nonEmpty) {
80
+ listStations(atLocation, limit, maxDistance)
81
+ } else if (near.nonEmpty) {
82
+ geocode(near).flatMap(listStations(_, limit, maxDistance))
83
+ } else {
84
+ listStations(limit = limit, maxDistance = maxDistance)
85
+ }
86
+
87
+ composition.map { stations =>
88
+ Ok (Json .toJson(BSONDocument (
89
+ " stations" -> stations,
90
+ " status" -> " ok" ,
91
+ " executed_in" -> ((System .nanoTime - now).asInstanceOf [Double ] / 1000000000 )
92
+ )))
93
+ }
94
+ }
95
+ }
0 commit comments