Scala akka SSE future support - scala

I am following this article https://doc.akka.io/docs/akka-http/current/common/sse-support.html.
Now I have a function some_def(key:String) that returns Future[Either[Throwable,T]] the payload for my SSE data
Below codebase I tried
(path("events") & get) {
complete {
Source fromFuture (some_def(key:String)) flatMapConcat {
case Right(s: T) =>
Source.tick(2.seconds, 2.second, NotUsed) map { _ =>
s
}
case _ => Source.empty
} map { s =>
ServerSentEvent(
s.message
)
} keepAlive (1.second, () => ServerSentEvent.heartbeat)
}
}
Now even though some_def(key:String) returns different payload post start SSE doesn't render that.
Is there a way we can refresh the akka - source .

Related

pg_search_scope: chaining scopes seems impossible

I have a search form for searching "documents", that have a small dozen of search criterions, including "entire_text", "keywords" and "description".
I'm using pg_search_scope, but I have 2 different scopes.
This is in my document.rb:
pg_search_scope :search_entire_text,
:against => :entire_text,
:using => {
:tsearch => {
:prefix => true,
:dictionary => "french"
}
}
pg_search_scope :search_keywords,
:associated_against => {
:keywords => [:keyword]
},
:using => {
:tsearch => {
:any_word => true
}
}
Each separately works fine. But I can't do this:
#resultats = Document.search_keywords(params[:ch_document][:keywords]).search_entire_text(params[:ch_document][:entire_text])
Is there any way to work around this?
Thanks
I've never used pg_search_scope but it looks like you indeed can't combine two pg_search_scope's.
What you could do is use :search_entire_text with a pg_search_scope and use the resulting id's in a Document.where([1,2,3]) that way you can use standard rails scope's for the remaining keyword searches.
Example:
# If pluck doesn't work you can also use map(&:id)
txt_res_ids = Document.search_entire_text(params[:ch_document][:entire_text]).pluck(:id)
final_results = Document.where(id: txt_res_ids).some_keyword_scope.all
It works. Here's the entire code ... if ever this could help someone :
Acte.rb (I didn't translate to english, the explanations are commented to correspond to the question above)
pg_search_scope :cherche_texte_complet, #i.e. find entire text
:against => :texte_complet,
:using => {
:tsearch => {
:prefix => true,
:dictionary => "french"
}
}
pg_search_scope :cherche_mots_clefs, #find keywords
:associated_against => {
:motclefs => [:motcle]
},
:using => {
:tsearch => {
:any_word => true
}
}
def self.cherche_date(debut, fin) #find date between
where("acte_date BETWEEN :date_debut AND :date_fin", {date_debut: debut, date_fin: fin})
end
def self.cherche_mots(mots)
if mots.present? #the if ... else is necessary, see controller.rb
cherche_mots_clefs(mots)
else
order("id DESC")
end
end
def self.ids_texte_compl(ids)
if ids.any?
where("id = any (array #{ids})")
else
where("id IS NOT NULL")
end
end
and actes_controller.rb
ids = Acte.cherche_texte_complet(params[:ch_acte][:texte_complet]).pluck(:id)
#resultats = Acte.cherche_date(params[:ch_acte][:date_debut],params[:ch_acte][:date_fin])
.ids_texte_compl(ids)
.cherche_mots(params[:ch_acte][:mots])
Thanks !
chaining works in pg_search 2.3.2 at least
SomeModel.pg_search_based_scope("abc").pg_search_based_scope("xyz")

doIf not working with session

I´m trying to use Gatling, where I just want to execute some steps in the first scenario iteration, here my code
def create(): ScenarioBuilder = {
scenario(name)
.exec(session => session.set("DEBUG", debug_set))
.exec(session => session.set("client_id", session.userId))
.doIf(session => session("initialized").asOption[String].isEmpty) {
exec(Identity.getIdentityToken)
exec(session => session.set("initialized", "true"))
}
.exitHereIfFailed
.during(Duration(15, MINUTES)) {
exec(X.setupVars)
.exec(X.create)
.pause(Duration(1, SECONDS))
.exec(X.get)
}
}
}
Somehow first iteration where initialized it´s not defined it´s not getting there, since I dont see the logs the execution of the one of the steps.
Any idea what I´m doing wrong?
One dot is missing for the second exec in your doIf:
.doIf(session => session("initialized").asOption[String].isEmpty) {
exec(Identity.getIdentityToken)
.exec(session => session.set("initialized", "true"))
}
Cheers,
Paul as well :)
Gatling Team

Add a field if match

i'm triyng to monitor an irc server. And i'm loot for a way to create a new numeral field (example: Alert_level) only if a message match a specific word inside.
Example: Message: ABC | Alert_level: 1 ; Message: ZYX | Alert_level: 3.
Its the running code
input {
irc {
channels => "#xyz"
host => "a.b.c"
nick => "myusername"
catch_all => true
get_stats => true
}
}
output {
stdout { codec => "rubydebug" }
elasticsearch {
hosts => "localhost"
index => "logstash-irc-%{+YYYY.MM.dd}"
}
}
Thank you!
As #Val suggested above you might need to use the grok filter in order match something from the input. For example your filter could look something like this:
filter {
grok {
match => { "message" => "%{GREEDYDATA:somedata}" }
}
if "ZYX" in [message]{ <-- change your condition accordingly
mutate {
add_field => { "%{Alert_level}" => "12345" } <-- somefield is the field name
convert => { "Alert_level" => "integer" } <-- do the conversion
}
}
}
NOTE that you have to do the conversion in order to create a numeric field through logstash, where you can't directly create one. The above is just a sample so that you can reproduce. Do change the grok match in respect to your requirement. Hope it helps!

Not able to set header for content type request in spray

A piece of my code to validate user login is :
val loginRoute = path("login") {
post {
parameter('next ?) {
(next) =>
entity(as[FormData]) {
params =>
implicit ctx => {
var headers = List[HttpHeader]()
val user = params.fields.find(_._1 == "username").get._2
val pass = params.fields.find(_._1 == "password").get._2
val remember = params.fields.find(_._1 == "remember") match {
case Some(rem) => rem._2
case None => "off"
}
LdapAuthenticationProvider.authenticate(user, pass) match {
case false =>
sendResponse(StatusCodes.Forbidden.intValue, "Authentication Failed")
redirect("login", StatusCodes.Found)
case true =>
if ("on".equalsIgnoreCase(remember)) {
val hash = calculateHash(Map(Const.USERNAME -> user))
headers = List(HttpHeaders.`Set-Cookie`(HttpCookie(Const.COOKIE_REMEMBER_ME_KEY, user)),
HttpHeaders.`Set-Cookie`(HttpCookie(Const.COOKIE_AUTH_HASH, hash)))
}
val url = next match {
case Some(path) => path
case None => "/"
}
complete {
HttpResponse(
status = StatusCodes.Found,
headers = Location(url) :: headers,
entity = StatusCodes.Found.htmlTemplate match {
case "" ⇒ HttpEntity.Empty
case template ⇒ HttpEntity(`text/html`, template format url)
}
)
}
}
}
}
}
}
}
However I am not able to set the request content Type. Shouldn't spray do that for me automatically? My request will be of
Content-Type: application/x-www-form-urlencoded
Which I am setting in my POST request header .
However I am still getting :
There was a problem with the requests Content-Type:
Expected 'application/json'
Please help me out here ! Thanks in advance!
The problem as Jrudolf suggested was that my JSON support trait was trying to deserialize the data. The headers were being ignored. Infact it was not even getting there. The solution was as simple as extending the already existing marshallers.
class LoginServlet(context: akka.actor.ActorRefFactory) extends BaseServlet with FormDataUnmarshallers {
}

Cannot broadcast to all clients in play2

Now I'm working on WebSocket using Play2(Scala) and succeessfully communicate with client. However, the broadcast function that play offers seems not to send message to all clients. How can I fix it?
:Controller in server
def ws = WebSocket.using[String] { request =>
val (out, channel) = Concurrent.broadcast[String]
val in = Iteratee.foreach[String] { msg =>
println(msg)
channel push(msg)
}.map{ _ => println("closed") } //when connection close
(in, out)
}
:Client Side
$ ->
ws = new WebSocket("ws://localhost:9000/ws")
ws.onopen = (event) ->
console.log("connected!!")
ws.onmessage = (event) ->
data = event.data.split(",")
infotype = data[0]
if infotype is "noisy"
room = data[1]
alert "noise happen at " + room
else if infotype is "gotIt"
console.log("someone gotIt")
else
console.log(data)
alert("oh arrive")
ws.onerror = (event) ->
console.log("error happned")
$(".rooms").on("click", (event) ->
room = $(this).attr("id")
ws.send("noisy," + room) )
Ideally, when push the button(not button but just rooms class in this case), the client send message to the server(this works correctly) and server should broadcast that message to all clients(it did not work in my code).
As a result, all clients should show the alert message.
However, Only the client which sent message to the server can get the message from server and show the alert.
What is the problem?
It's because you create a new Concurrent.broadcast for every client.
Create it once outside your action, like this:
val (out, channel) = Concurrent.broadcast[String]
def ws = WebSocket.using[String] { request =>
val in = Iteratee.foreach[String] { msg =>
println(msg)
channel push(msg)
}.map{ _ => println("closed") } //when connection close
(in, out)
}