2

J'essaye de convertir ce code, qui utilise la version 2.4 de Play à la version actuelle (2.6) et j'ai quelques problèmes parce que je suis toujours un noob dans Scala.Conversion de WebSockets dans le framework Play depuis la version 2.4 vers la version 2.6

def wsWeatherIntervals = WebSocket.using[String] { 
    request => 
    val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl" 
    val outEnumerator = Enumerator.repeatM[String]({ 
     Thread.sleep(3000) 
     ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}") 
    }) 
    (Iteratee.ignore[String], outEnumerator) 
} 

J'ai suivi this guide, mais maintenant je suis coincé sur les choses que je revenir sur la méthode. Ce est le code que je suis en train de courir en utilisant la version 2.6:

import play.api.mvc._ 
    import scala.concurrent.Future 
    import akka.stream.scaladsl._ 
    def wsWeatherIntervals = WebSocket.accept[String, Future[String]] { res => 
    val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl" 
    val source = Source.repeat({ 
     Thread.sleep(3000) 
     ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}") 
    }) 
    Flow.fromSinkAndSource(Sink.ignore, source) 
    } 

Mais j'obtiens cette erreur lors de l'exécution du serveur, qui pointe vers la première ligne de la méthode:

could not find implicit value for parameter transformer: play.api.mvc.WebSocket.MessageFlowTransformer[String,scala.concurrent.Future[String]] 

Note: J'ai également essayé d'appeler WebSocket.apply au lieu de WebSocket.accept et j'ai fait quelques recherches sur les différences entre les deux mais je n'ai rien trouvé d'utile. Quelqu'un peut-il expliquer la différence entre les deux? Merci.

Répondre

2

L'erreur superficielle est que Play ne sait pas comment transformer un Future[String] en un message Websocket, pour lequel vous utiliseriez normalement un transformateur implicite. Cependant, dans ce cas, vous ne voulez pas retourner un Future[String] de toute façon, mais juste une chaîne de caractères qui peut être automatiquement rangea (en utilisant la condition stringMessageFlowTransformer comme il arrive.) Voici quelque chose qui devrait fonctionner:

def wsWeatherIntervals = WebSocket.accept[String, String] { res => 
    val url = "http://api.openweathermap.org/data/2.5/weather?q=Amsterdam,nl" 
    def f = ws.url(url).get().map(r => s"${new java.util.Date()}\n ${r.body}") 

    val source = Source.unfoldAsync(f)(last => { 
    Thread.sleep(3000) 
    f.map(next => Some((last, next))) 
    }) 
    Flow.fromSinkAndSource(Sink.ignore, source) 
} 

Le unfoldAsync source nous permet de répéter une fonction renvoyant un futur de l'élément suivant dans le flux. (Puisque nous voulons que le flux d'aller à l'infini, nous retournons la valeur emballée Some.)

La méthode Websocket.apply est essentiellement une version plus complexe de accept qui vous permet de rejeter une connexion websocket pour une raison en retournant une réponse, mais si vous avez besoin de faire cela, il est préférable d'utiliser acceptOrResult, qui gère la transformation de tout ce que votre flux émet en messages websocket.