Cannot broadcast to all clients in play2 - scala

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)
}

Related

Scala akka SSE future support

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 .

paypal-checkout-sdk Capture function is captured once only how to fixed fatal error when it is occuring second time

I am using paypal-checkout-sdk for server side configuration.
I have used custom button. On submission of that i am creating order
with below code
$environment = new SandboxEnvironment($clientId, $clientSecret);
$client = new PayPalHttpClient($environment);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
"intent" => "CAPTURE",
"purchase_units" => [[
"reference_id" => "test_ref_id1",
"amount" => [
"value" => "100.00",
"currency_code" => "USD"
]
]],
"application_context" => [
"cancel_url" => "https://example.com/cancel",
"return_url" => "https://example.com/return"
]
];
try {
// Call API with your client and get a response for your call
$response = $client->execute($request);
echo "<pre>";
print_r($response);
echo "</pre>";
//exit();
// If call returns body in response, you can get the deserialized version from the result attribute of the response
if(isset($response->result->links[1]->href) && !empty($response->result->links[1]->href)){
//echo $response->result->links[1]->href;
//header('Location:'.$response->result->links[1]->href);
//die();
}
}catch (HttpException $ex) {
//echo $ex->statusCode;
//print_r($ex->getMessage());
}
Then redirect it to paypal with approved url. After coming from that if i am using capture class to
capture data.In that i am receiving response properly.
$request = new OrdersCaptureRequest("6UD13042B02825225");
$request->prefer('return=representation');
try {
// Call API with your client and get a response for your call
$response = $client->execute($request);
print_r($response);
// If call returns body in response, you can get the deserialized version from the result attribute of the response
if ($response->statusCode == 201)
{
print_r($response);
}
}catch (HttpException $ex) {
$message = json_decode($ex->getMessage(), true);
//echo json_encode($response->result, JSON_PRETTY_PRINT), "\n";
print_r($message);
print "Status Code: {$ex->statusCode}\n";
}
Response sample.
PayPalHttp\HttpResponse Object ( [statusCode] => 201 [result] => stdClass Object ( [id] => 6UD13042B02825225 [intent] => CAPTURE [status] => COMPLETED [purchase_units] => Array ( [0] => stdClass Object ( [reference_id] => test_ref_id1 [amount] => stdClass Object ( [currency_code] => USD [value] => 100.00 ) [
If I am trying to run this above code for OrderCapture for the same order it is showing an error like this
Fatal error: Uncaught PayPalHttp\HttpException: {"name":"UNPROCESSABLE_ENTITY","details":[{"issue":"ORDER_ALREADY_CAPTURED","description":"Order already captured.If 'intent=CAPTURE' only one capture per order is allowed."}],"message":"The requested action could not be performed, semantically incorrect, or failed business validation.","debug_id":"cfdc8ac1d115b","links":[{"href":"https://developer.paypal.com/docs/api/orders/v2/#error-ORDER_ALREADY_CAPTURED","rel":"information_link","method":"GET"}]} in
I am not sure how to fix this error. I want to capture it multiple times.
When using intent:capture, only one capture can be made for an order, for the full amount. This is what the payer approved when they went through the checkout approval flow.
You cannot capture multiple times in this situation, since that was not approved by the payer.
You need a new order (and to get it approved) for a new capture.

How to send then receive packet from Client-Server in Ada

I want to create a server-client connection where a client send a request packet to the server then return a value back to the user. I can get the server to read the incoming packet from the client, but when it write back to the client, the client is not receiving the packet.
I have the size of string in Client and Server matches to ensure the read is not waiting for more incoming packet.
Server
Buffer : Ada.Streams.Stream_Element_Array (1 .. 10);
Offset : Ada.Streams.Stream_Element_Offset;
...
GNAT.Sockets.Create_Socket (Socket => Receiver);
GNAT.Sockets.Set_Socket_Option
(Socket => Receiver,
Option => (Name => GNAT.Sockets.Reuse_Address, Enabled => True));
GNAT.Sockets.Bind_Socket
(Socket => Receiver,
Address => (Family => GNAT.Sockets.Family_Inet,
Addr => GNAT.Sockets.Inet_Addr ("127.0.0.1"),
Port => 12321));
GNAT.Sockets.Listen_Socket (Socket => Receiver);
GNAT.Sockets.Accept_Socket
(Server => Receiver,
Socket => Connection,
Address => Client);
Channel := GNAT.Sockets.Stream (Connection);
Ada.Streams.Read(Stream => Channel.all,
Item => Buffer,
Last => Offset);
for J in 1..Offset loop
Ada.Text_IO.Put_Line(Character'Val(Integer (Buffer (J)))'Img);
end loop;
String'Write(GNAT.Sockets.Stream (Connection), "1234567890");
GNAT.Sockets.Close_Socket (Connection);
Client
input : String(1..10);
output : String(1..10);
...
Initialize;
Create_Socket (Socket => Client);
Connect_Socket (Socket => Client,
Server => (Family => Family_Inet,
Addr => Inet_Addr ("127.0.0.1"),
Port => 12321));
String'Write (Stream (Client), Input);
String'Read (Stream (Client), output); --hanging right here
Close_Socket (Client);
For some reason, the client is getting the message now. The code above works as intended

Don't show 's3.amazon.com' when posting images to LinkedIn API

I am posting images to LinkedIn through the public api with my app that pulls the images from our S3 bucket. When the update appears on LinkedIn it shows 's3.amazon.com' next to the image. Is there any way that I can keep this from happening?
Ruby Code from app:
def post(message_body, attachment, post)
options = { :visibility => { :code => 'anyone' } }
if attachment.present?
options.merge!(:content => { :title => 'titles',
:description => 'descriptions',
:submitted_url => 'http://s3.amazonaws.com/...'
}, :comment => message_body)
else
options.merge!(:comment => message_body)
end
response = client.add_share(options)
post.posted!
JSON.parse(response.body)['updateUrl']
rescue LinkedIn::Errors::UnauthorizedError => e
raise SocialProfile::UnauthorizedError, e.message
rescue LinkedIn::Errors::AccessDeniedError => e
raise SocialProfile::UnauthorizedError, e.message
## Heading ##end

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 {
}