So i got stuck on following problem. So far i can call methods from the client on the red5 server but calling methods on the client from red5 server is not working. I got the following code
public function onCreationComplete(event:FlexEvent) : void {
connection = new NetConnection();
connection.connect("rtmp://localhost/simpleChat");
connection.client = this;
so = SharedObject.getRemote("sharedMessage");
connection.addEventListener(NetStatusEvent.NET_STATUS, onConnectionNetStatus);
connection.call("addOne", ro, 5);
}
public function onConnectionNetStatus(event:NetStatusEvent) : void {
if(event.info.code == "NetConnection.Connect.Success") {
Alert.show("Connection Successful","Information");
} else {
Alert.show("Conection not successful", "Error");
}
}
public function onResult(responder:String): void{
Alert.show(responder);
}
public function onError(e:Object): void{
Alert.show("Got an error: " + e.description);
}
private function onClickSendBtn(event:MouseEvent):void
{
connection.call("broadcastMessageToClients", null, inputTxt.text);
}
public function receiveBroadcastedMessages(msg:String):void
{
outputTxtArea.text += msg + "\n";
}
this is the client side as a flash
and now on the server side the sysout is being called but the method on the client side is not called, what is wrong?
public class Application extends ApplicationAdapter {
/*
* The scope object. A statefull object shared between a group of clients connected to the same context path.
* Scopes are arranged in hierarchical way, so its possible for a scope to have a parent and children scopes.
* If a client connects to a scope then they are also connected to its parent scope. The scope object is used
* to access resources, shared object, streams, etc. That is, scope are general option for grouping things in
* application. The following are all names for scopes: application, room, place, lobby.
*/
private IScope appScope;
/** {#inheritDoc} */
#Override
public boolean connect(IConnection conn, IScope scope, Object[] params) {
// init appScope
appScope = scope;
// create a sharedobject on server and call it "sharedMessage" under the current scope.
createSharedObject(appScope, "sharedMessage", false);
return true;
}
/** {#inheritDoc} */
#Override
public void disconnect(IConnection conn, IScope scope) {
super.disconnect(conn, scope);
}
/* Simple method to illustrate how simple is to access the methods on the server side from the client side.
* if called from the client it adds "1" to the passed argument.
*/
public double addOne(double a) {
return a + 1;
}
/* Simple method to illustrate how simple is to access the methods on the client side from the server side.
* Also this uses the SharedObject to send a unified message to all connected clients
*/
public void broadcastMessageToClients(List<String> params) {
ISharedObject so = getSharedObject(appScope, "sharedMessage");
System.out.println("broadcastMessageToClients...");
// call receiveMessage method on all connected clients
so.sendMessage("receiveBroadcastedMessages", params); // send the received parameter back to all connected clients by calling the "receiveBroadcastedMessages" method on the client side
}
You are invoking the method on the client using a Shared Object but the client SO wasn't connected to the server, the code below demonstrate how to do it
so = SharedObject.getRemote("sharedMessage");
co.client = this; //indicate that this class will have the methods invoked by the server
so.connect(connection); //connect the SO with the server
This code need to be invoked when the connection is successful with the server, so it should be added to onConnectionNetStatus function.
Related
I have a web app that uses a request/response message in Masstransit.
This works on out test environment, no problem.
However on the customer deployment we face a problem. At the customer site we do have two network segments A and B. The component doing the database call is in segment A, the web app and the RabbitMq server in segment B.
Due to security restrictions the component in segment A has to go through a loadbalancer with a given address. The component itself can connect to RabbitMQ with Masstransit. So far so good.
The web component on segment B however uses the direct address for the RabbitMq server. When the web component now is starting the request/response call, I can see that the message arrives at the component in segment A.
However I see that the consumer tries to call the RabbitMQ server on the "wrong" address. It uses the address the web component uses to issue the request. However the component in segment A should reply on the "loadbalancer" address.
Is there a way to configure or tell the RespondAsync call to use the connection address configured for that component?
Of course the easiest would be to have the web component also connect through the loadbalancer, but due to the network segments/security setup the loadbalancer is only reachable from segment A.
Any input/help is appreciated.
I had a similar problem with rabbitmq federation. Here's what I did.
ResponseAddressSendObserver
class ResponseAddressSendObserver : ISendObserver
{
private readonly string _hostUriString;
public ResponseAddressSendObserver(string hostUriString)
{
_hostUriString = hostUriString;
}
public Task PreSend<T>(SendContext<T> context)
where T : class
{
if (context.ResponseAddress != null)
{
// Send relative response address alongside the message
context.Headers.Set("RelativeResponseAddress",
context.ResponseAddress.AbsoluteUri.Substring(_hostUriString.Length));
}
return Task.CompletedTask;
}
...
}
ResponseAddressConsumeFilter
class ResponseAddressConsumeFilter : IFilter<ConsumeContext>
{
private readonly string _hostUriString;
public ResponseAddressConsumeFilter(string hostUriString)
{
_hostUriString = hostUriString;
}
public Task Send(ConsumeContext context, IPipe<ConsumeContext> next)
{
var responseAddressOverride = GetResponseAddress(_hostUriString, context);
return next.Send(new ResponseAddressConsumeContext(responseAddressOverride, context));
}
public void Probe(ProbeContext context){}
private static Uri GetResponseAddress(string host, ConsumeContext context)
{
if (context.ResponseAddress == null)
return context.ResponseAddress;
object relativeResponseAddress;
if (!context.Headers.TryGetHeader("RelativeResponseAddress", out relativeResponseAddress) || !(relativeResponseAddress is string))
throw new InvalidOperationException("Message has ResponseAddress but doen't have RelativeResponseAddress header");
return new Uri(host + relativeResponseAddress);
}
}
ResponseAddressConsumeContext
class ResponseAddressConsumeContext : BaseConsumeContext
{
private readonly ConsumeContext _context;
public ResponseAddressConsumeContext(Uri responseAddressOverride, ConsumeContext context)
: base(context.ReceiveContext)
{
_context = context;
ResponseAddress = responseAddressOverride;
}
public override Uri ResponseAddress { get; }
public override bool TryGetMessage<T>(out ConsumeContext<T> consumeContext)
{
ConsumeContext<T> context;
if (_context.TryGetMessage(out context))
{
// the most hackish part in the whole arrangement
consumeContext = new MessageConsumeContext<T>(this, context.Message);
return true;
}
else
{
consumeContext = null;
return false;
}
}
// all other members just delegate to _context
}
And when configuring the bus
var result = MassTransit.Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri(hostAddress), h =>
{
h.Username(...);
h.Password(...);
});
cfg.UseFilter(new ResponseAddressConsumeFilter(hostAddress));
...
});
result.ConnectSendObserver(new ResponseAddressSendObserver(hostAddress));
So now relative response addresses are sent with the messages and used on the receiving side.
Using observers to modify anything is not recommended by the documentation, but should be fine in this case.
Maybe three is a better solution, but I haven't found one. HTH
I am creating a sample project for learning purpose(later on I will be working on project based on webrtc and kurento), I am using Kurento media server with it, I have modified the tutorial of the kurento server and made one sample out of it.
In all of the samples for Kurento Server they are using a UserRegistry.java where they are storing objects of UserSession as shown below:
public class UserSession {
private static final Logger log = LoggerFactory.getLogger(UserSession.class);
private final String name;
private final WebSocketSession session;
private String sdpOffer;
private String callingTo;
private String callingFrom;
private WebRtcEndpoint webRtcEndpoint;
private WebRtcEndpoint playingWebRtcEndpoint;
private final List<IceCandidate> candidateList = new ArrayList<>();
public UserSession(WebSocketSession session, String name) {
this.session = session;
this.name = name;
}
public void sendMessage(JsonObject message) throws IOException {
log.debug("Sending message from user '{}': {}", name, message);
session.sendMessage(new TextMessage(message.toString()));
}
public String getSessionId() {
return session.getId();
}
public void setWebRtcEndpoint(WebRtcEndpoint webRtcEndpoint) {
this.webRtcEndpoint = webRtcEndpoint;
if (this.webRtcEndpoint != null) {
for (IceCandidate e : candidateList) {
this.webRtcEndpoint.addIceCandidate(e);
}
this.candidateList.clear();
}
}
public void addCandidate(IceCandidate candidate) {
if (this.webRtcEndpoint != null) {
this.webRtcEndpoint.addIceCandidate(candidate);
} else {
candidateList.add(candidate);
}
if (this.playingWebRtcEndpoint != null) {
this.playingWebRtcEndpoint.addIceCandidate(candidate);
}
}
public void clear() {
this.webRtcEndpoint = null;
this.candidateList.clear();
}
}
I have two questions on this:
Why do we need session object?
What are the alternatives(if there are any) to manage session?
Let me give some more background on 2nd question. I found out that I can run the Kurento-JavaScript-Client(I need to convert it to browser version and then I can use it.) on the client side only (That way I won't require a backend server i.e. nodejs or tomcat - this is my assumption). So in this case how would I manage session or I can totally remove the UserRegistry concept and use some other way.
Thanks & Regards
You need to store sessions to implement signalling between the clients and the application server. See for example here. The signalling diagram describes the messages required to start/stop/etc the WebRTC video communication.
If you are planing to get rid of the application server (i.e. move to JavaScript client completely) you can take a look to a publish/subscribe API such as PubNub.
We have two RESTful APIs - one is internal and another one is public, the two being implemented by different jars. The public API sort of wraps the internal one, performing the following steps:
Do some work
Call internal API
Do some work
Return the response to the user
It may happen (though not necessarily) that the two jars run in the same Java process.
We are using Restlet with the JAX-RS extension.
Here is an example of a simple public API implementation, which just forwards to the internal API:
#PUT
#Path("abc")
public MyResult method1(#Context UriInfo uriInfo, InputStream body) throws Exception {
String url = uriInfo.getAbsolutePath().toString().replace("/api/", "/internalapi/");
RestletClientResponse<MyResult> reply = WebClient.put(url, body, MyResult.class);
RestletUtils.addResponseHeaders(reply.responseHeaders);
return reply.returnObject;
}
Where WebClient.put is:
public class WebClient {
public static <T> RestletClientResponse<T> put(String url, Object body, Class<T> returnType) throws Exception {
Response restletResponse = Response.getCurrent();
ClientResource resource = new ClientResource(url);
Representation reply = null;
try {
Client timeoutClient = new Client(Protocol.HTTP);
timeoutClient.setConnectTimeout(30000);
resource.setNext(timeoutClient);
reply = resource.put(body, MediaType.APPLICATION_JSON);
T result = new JacksonConverter().toObject(new JacksonRepresentation<T>(reply, returnType), returnType, resource);
Status status = resource.getStatus();
return new RestletClientResponse<T>(result, (Form)resource.getResponseAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS), status);
} finally {
if (reply != null) {
reply.release();
}
resource.release();
Response.setCurrent(restletResponse);
}
}
}
and RestletClientResponse<T> is:
public class RestletClientResponse<T> {
public T returnObject = null;
public Form responseHeaders = null;
public Status status = null;
public RestletClientResponse(T returnObject, Form responseHeaders, Status status) {
this.returnObject = returnObject;
this.responseHeaders = responseHeaders;
this.status = status;
}
}
and RestletUtils.addResponseHeaders is:
public class RestletUtils {
public static void addResponseHeader(String key, Object value) {
Form responseHeaders = (Form)org.restlet.Response.getCurrent().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
if (responseHeaders == null) {
responseHeaders = new Form();
org.restlet.Response.getCurrent().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
}
responseHeaders.add(key, value.toString());
}
public static void addResponseHeaders(Form responseHeaders) {
for (String headerKey : responseHeaders.getNames()) {
RestletUtils.addResponseHeader(headerKey, responseHeaders.getValues(headerKey));
}
}
}
The problem is that if the two jars run in the same Java process, then an exception thrown from the internal API is not routed to the JAX-RS exception mapper of the internal API - the exception propagates up to the public API and is translated to the Internal Server Error (500).
Which means I am doing it wrong. So, my question is how do I invoke the internal RESTful API from within the public API implementation given the constraint that both the client and the server may run in the same Java process.
Surely, there are other problems, but I have a feeling that fixing the one I have just described is going to fix others as well.
The problem has nothing to do with the fact that both internal and public JARs are in the same JVM. They are perfectly separated by WebResource.put() method, which creates a new HTTP session. So, an exception in the internal API doesn't propagate to the public API.
The internal server error in the public API is caused by the post-processing mechanism, which interprets the output of the internal API and crashes for some reason. Don't blame the internal API, it is perfectly isolated and can't cause any troubles (even though it's in the same JVM).
I read that the best practice for using WCF proxy would be:
YourClientProxy clientProxy = new YourClientProxy();
try
{
.. use your service
clientProxy.Close();
}
catch(FaultException)
{
clientProxy.Abort();
}
catch(CommunicationException)
{
clientProxy.Abort();
}
catch (TimeoutException)
{
clientProxy.Abort();
}
My problem is, after I allocate my proxy, I assign event handlers to it and also initialize other method using the proxy:
public void InitProxy()
{
sdksvc = new SdkServiceClient();
sdksvc.InitClusteringObjectCompleted += new EventHandler<InitClusteringObjectCompletedEventArgs>(sdksvc_InitClusteringObjectCompleted);
sdksvc.InitClusteringObjectAsync(Utils.DSN, Utils.USER,Utils.PASSWORD);
sdksvc.DoClusteringCompleted += new EventHandler<DoClusteringCompletedEventArgs>(sdksvc_DoClusteringCompleted);
sdksvc.CreateTablesCompleted += new EventHandler<CreateTablesCompletedEventArgs>(sdksvc_CreateTablesCompleted);
}
I now need to call the InitProxy() method each Time I use the proxy if I want to use it as best practice suggests.
Any ideas on how to avoid this?
There are several options. One option is to write a helper class as follows:
public class SvcClient : IDisposable {
public SvcClient(ICommunicationObject service) {
if( service == null ) {
throw ArgumentNullException("service");
}
_service = service;
// Add your event handlers here, e.g. using your example:
sdksvc = new SdkServiceClient();
sdksvc.InitClusteringObjectCompleted += new EventHandler<InitClusteringObjectCompletedEventArgs>(sdksvc_InitClusteringObjectCompleted);
sdksvc.InitClusteringObjectAsync(Utils.DSN, Utils.USER,Utils.PASSWORD);
sdksvc.DoClusteringCompleted += new EventHandler<DoClusteringCompletedEventArgs>(sdksvc_DoClusteringCompleted);
sdksvc.CreateTablesCompleted += new EventHandler<CreateTablesCompletedEventArgs>(sdksvc_CreateTablesCompleted);
}
public void Dispose() {
try {
if( _service.State == CommunicationState.Faulted ) {
_service.Abort();
}
}
finally {
_service.Close();
}
}
private readonly ICommunicationObject _service;
}
To use this class write the following:
var clientProxy = new YourClientProxy();
using(new SvcClient(clientProxy)) {
// use clientProxy as usual. No need to call Abort() and/or Close() here.
}
When the constructor for SvcClient is called it then sets up the SdkServiceClient instance as desired. Furthermore the SvcClient class cleans up the service client proxy as well aborting and/or closing the connection as needed regardless of how the control flow leaves the using-block.
I don't see how the ClientProxy and the InitProxy() are linked but if they are linked this strong I'd move the initialization of the ClientProxy to the InitProxy (or make a method that initializes both) so you can control both their lifespans from there.
If you call a web service from Silverlight like this:
MyServiceClient serviceClient = new MyServiceClient();
void MyMethod()
{
serviceClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(serviceClient_GetDataCompleted);
serviceClient.GetDataAsync();
// HOW DO I WAIT/JOIN HERE ON THE ASYNC CALL, RATHER THAN BEING FORCE TO LEAVE THIS METHOD?
}
I would rather wait/join with the asych service thread inside "MyMethod" rather than leaving "MyMethod" after calling "GetDataAsync", what is the best way to do this?
Thanks,
Jeff
No you cannot do this way. You will end up in a deadlock. GetDataCompleted is called by the mainthreed. The same threed thait is waiting in WaitOne.
I have to ask; why? The point is to provide your user with a fluid experience and waiting on a web service call will not necessarily do that. I suppose you want the full block of content to load before the Silverlight control loads. In that case, I would turn to caching the content rather than forcing the client to wait indefinitely.
To do this you would use a ManualResetEvent in your class (class level variable) and then wait on it.
void MyMethod()
{
wait = new ManualResetEvent(false);
// call your service
wait.WaitOne();
// finish working
}
and in your event handler code
void serviceClient_GetDataCompleted(...)
{
// Set values you need from service
wait.Set();
}
You could also use a lambda and closure to get similar behavior:
serviceClient.GetDataCompleted += (s,e) =>
{
// Your code here
};
serviceClient.GetDataAsync();
If you had a base class provide the mechanics of building a WCF channel, it could then be used to build the BeginX / EndX methods for a async call.
public class ServiceFooCoordinator : CoordinatorBase<IServiceFoo>
{
public IAsyncResult BeginMethodFoo ()
{
IAsyncResult ar = null;
IServiceFoo channel = null;
channel = _factory.GetChannel();
Begin( channel, () => ar = channel.BeginMethodFoo( null, channel ) );
return ar;
}
public Bar[] EndMethodFoo ( IAsyncResult ar )
{
IServiceFoo channel = null;
channel = _factory.GetChannel();
return channel.EndMethodFoo( ar );
}
}
Which can then be used in a method:
ServiceFooCoordinator _coordinator;
var asyncResult = _coordinator.BeginMethodFoo();
try
{
var result = _coordinator.EndMethodFoo( asyncResult );
}
catch ( Exception )
{ }
Which gets you your asynchronous call in a sychronous manner.