AtmosphereHandler - Chat: I get "undefined" when I send a message - atmosphere

I am having trouble with this example of chat: https://github.com/Atmosphere/atmosphere/wiki/Getting-Started-with-AtmosphereHandler,-WebSocket-and-Long-Polling
In this simple example is used an implemetation of AtmosphereHandler to create a chat application.
How you could see from the pic below, i don't see what i have wrote but only an "undefined" message. Why? Where is the error?
Thank you a lot.
web.xml:
<display-name>AtmoChat</display-name>
<description>Atmosphere Chat</description>
<servlet>
<description>AtmosphereServlet</description>
<servlet-name>AtmosphereServlet</servlet-name>
<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
<!-- limit classpath scanning to speed up starting, not mandatory -->
<init-param>
<param-name>org.atmosphere.cpr.packages</param-name>
<param-value>org.atmosphere.samples</param-value>
</init-param>
<init-param>
<param-name>org.atmosphere.interceptor.HeartbeatInterceptor.clientHeartbeatFrequencyInSeconds</param-name>
<param-value>10</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>AtmosphereServlet</servlet-name>
<url-pattern>/chat/*</url-pattern>
</servlet-mapping>
application.js:
$(function () {
"use strict";
var header = $('#header');
var content = $('#content');
var input = $('#input');
var status = $('#status');
var myName = false;
var author = null;
var logged = false;
var socket = atmosphere;
var subSocket;
var transport = 'websocket';
// We are now ready to cut the request
var request = { url: 'http://myLink/' + 'chat',
contentType : "application/json",
logLevel : 'debug',
transport : transport ,
trackMessageLength : true,
reconnectInterval : 5000 };
request.onOpen = function(response) {
content.html($('<p>', { text: 'Atmosphere connected using ' + response.transport }));
input.removeAttr('disabled').focus();
status.text('Choose name:');
transport = response.transport;
// Carry the UUID. This is required if you want to call subscribe(request) again.
request.uuid = response.request.uuid;
};
request.onClientTimeout = function(r) {
content.html($('<p>', { text: 'Client closed the connection after a timeout. Reconnecting in ' + request.reconnectInterval }));
subSocket.push(atmosphere.util.stringifyJSON({ author: author, message: 'is inactive and closed the connection. Will reconnect in ' + request.reconnectInterval }));
input.attr('disabled', 'disabled');
setTimeout(function (){
subSocket = socket.subscribe(request);
}, request.reconnectInterval);
};
request.onReopen = function(response) {
input.removeAttr('disabled').focus();
content.html($('<p>', { text: 'Atmosphere re-connected using ' + response.transport }));
};
// For demonstration of how you can customize the fallbackTransport using the onTransportFailure function
request.onTransportFailure = function(errorMsg, request) {
atmosphere.util.info(errorMsg);
request.fallbackTransport = "long-polling";
header.html($('<h3>', { text: 'Atmosphere Chat. Default transport is WebSocket, fallback is ' + request.fallbackTransport }));
};
request.onMessage = function (response) {
var message = response.responseBody;
try {
var json = atmosphere.util.parseJSON(message);
} catch (e) {
console.log('This doesn\'t look like a valid JSON: ', message);
return;
}
input.removeAttr('disabled').focus();
if (!logged && myName) {
logged = true;
status.text(myName + ': ').css('color', 'blue');
} else {
var me = json.author == author;
var date = typeof(json.time) == 'string' ? parseInt(json.time) : json.time;
addMessage(json.author, json.message, me ? 'blue' : 'black', new Date(date));
}
};
request.onClose = function(response) {
content.html($('<p>', { text: 'Server closed the connection after a timeout' }));
if (subSocket) {
subSocket.push(atmosphere.util.stringifyJSON({ author: author, message: 'disconnecting' }));
}
input.attr('disabled', 'disabled');
};
request.onError = function(response) {
content.html($('<p>', { text: 'Sorry, but there\'s some problem with your '
+ 'socket or the server is down' }));
logged = false;
};
request.onReconnect = function(request, response) {
content.html($('<p>', { text: 'Connection lost, trying to reconnect. Trying to reconnect ' + request.reconnectInterval}));
input.attr('disabled', 'disabled');
};
subSocket = socket.subscribe(request);
input.keydown(function(e) {
if (e.keyCode === 13) {
var msg = $(this).val();
// First message is always the author's name
if (author == null) {
author = msg;
}
subSocket.push(atmosphere.util.stringifyJSON({ author: author, message: msg }));
$(this).val('');
input.attr('disabled', 'disabled');
if (myName === false) {
myName = msg;
}
}
});
function addMessage(author, message, color, datetime) {
content.append('<p><span style="color:' + color + '">' + author + '</span> # ' +
+ (datetime.getHours() < 10 ? '0' + datetime.getHours() : datetime.getHours()) + ':'
+ (datetime.getMinutes() < 10 ? '0' + datetime.getMinutes() : datetime.getMinutes())
+ ': ' + message + '</p>');
}});

Ok. For now, I don't see any trouble about your "onMessage" method in your javascript code. Your javascript code is based on simple chat room from documentation of atmosphere-js. So, your code is correct.
I need to see your Java code for how you send object message to client app. I need also to see your class Java representing the model object message to send.
Maybe, the value of message attribute from object model class is null or empty. That's why you have "undefined" value in your message field.
Your model java class must be like :
public class ChatMessage {
private String message;
private String author;
private long time = System.currentTimeMillis();
public ChatMessage(){
this("","");
}
public ChatMessage(String author, String message) {
this.author = author;
this.message = message;
this.time = new Date().getTime();
}
public String getMessage(){
return message;
}
public String getAuthor(){
return author;
}
public void setAuthor(String author){
this.author = author;
}
public void setMessage(String message){
this.message = message;
}
public long getTime(){
return time;
}
public void setTime(long time){
this.time = time;
}
}
Here's an class Java to manage a chat application :
import java.io.IOException;
import org.atmosphere.config.service.Disconnect;
import org.atmosphere.config.service.ManagedService;
import org.atmosphere.config.service.Message;
import org.atmosphere.config.service.PathParam;
import org.atmosphere.config.service.Ready;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple annotated class that demonstrate the power of Atmosphere. This class
* supports all transports, support message length guarantee, heart beat,
* message cache thanks to the #ManagedService.
*/
#ManagedService(path = "/chatRoom/{room_id}")
public final class ChatRoom {
private static final Logger logger = LoggerFactory.getLogger(ChatRoom.class);
#PathParam("room_id")
private String chatRoomId;
/**
* Invoked when the connection as been fully established and suspended, e.g
* ready for receiving messages.
*
* #param r
* the atmosphere resource
* #return
*/
#Ready
public final void onReady(final AtmosphereResource r) {
logger.info("Browser {} connected.", r.uuid());
}
/**
* Invoked when the client disconnect or when an unexpected closing of the
* underlying connection happens.
*
* #param event
* the event
* #throws IOException
*/
#Disconnect
public final void onDisconnect(final AtmosphereResourceEvent event) throws IOException {
if (event.isCancelled()) {
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
}
else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
}
/**
* Simple annotated class that demonstrate how
* {#link org.atmosphere.config.managed.Encoder} and {#link org.atmosphere.config.managed.Decoder
* can be used.
*
* #param message an instance of {#link ChatMessage }
* #return the chat message
*/
#Message(encoders = { ChatMessageEncoderDecoder.class }, decoders = { ChatMessageEncoderDecoder.class })
public final ChatMessage onMessage(final ChatMessage message) {
logger.info("{} just send {}", message.getAuthor(), message.getMessage());
return message;
}
}

Related

How to differentiate the data of one topic or another coming from Mercure hub if the client is suscribed to two topics

I have a a dashboard on a Symony app with two ChartJS graphs, one for temperature data, and the other for pressure data. I need update both on realtime; for that purpose I try to use MercureBundle with two topics: ['realtime-notif/temperature/{sensorId}', 'realtime-notif/pressure/{sensorId}']. Although the topics sound similar, the logic to conform datas are differents because the two ChartJS are differents, and for that I have two Messenger messages handlers with AMQP queue, one publish a mercure update in topic 'realtime-notif/temperature/{sensorId}' and the other message handler class publish in 'realtime-notif/pressure/{sensorId}'. I will try to summarize the code to be concise.
#mercure.yaml:
mercure:
hubs:
default:
url: '%env(MERCURE_URL)%'
public_url: '%env(MERCURE_PUBLIC_URL)%'
jwt:
secret: '%env(MERCURE_JWT_SECRET)%'
publish: ['realtime-notif/temperature/{sensorId}', 'realtime-notif/pressure/{sensorId}']
subscribe: ['realtime-notif/temperature/{sensorId}', 'realtime-notif/pressure/{sensorId}']
#The TemperatureMessageHandler class:
class TemperatureMessageHandler implements MessageHandlerInterface
{
private $mercureHub;
private $managerRegistry;
public function __construct(HubInterface $mercureHub, ManagerRegistry $managerRegistry)
{
$this->mercureHub = $mercureHub;
$this->managerRegistry = managerRegistry;
}
public function __invoke(TemperatureMessage $message)
{
try {
$graphId=$message->getGraphId();
$lastElapsedTime=$message->getLastElapsedTime();
$em=$this->managerRegistry->getManager();
$storedData = $em->getRepository(Temperature::class)->findLastRecordsForGraph($graphId, $lastElapsedTime);
/**
Set the data source for the temperature graph to a specific format from $toredData
**/
$formatedChartData = [];
**....**
$update = new Update(
sprintf('realtime-notif/temperature/%s', $graphId),
\json_encode($$formatedChartData),
true
);
$this->mercureHub->publish($update);
} catch (\Exception $exc) {
}
}
}
And,
#The PressureMessageHandler class:
class PressureMessageHandler implements MessageHandlerInterface
{
private $mercureHub;
private $managerRegistry;
public function __construct(HubInterface $mercureHub, ManagerRegistry $managerRegistry)
{
$this->mercureHub = $mercureHub;
$this->managerRegistry = managerRegistry;
}
public function __invoke(PressureMessage $message)
{
try {
$graphId = $message->getGraphId();
$lastElapsedTime = $message->getLastElapsedTime();
$em = $this->managerRegistry->getManager();
$storedData = $em->getRepository(Pressure::class)->findLastRecordsForGraph($graphId, $lastElapsedTime);
/**
Set the data source for the pressure graph to a specific format from $toredData
**/
$formatedChartData = [];
**....**
$update = new Update(
sprintf('realtime-notif/pressure/%s', $graphId),
\json_encode($$formatedChartData),
true
);
$this->mercureHub->publish($update);
} catch (\Exception $exc) {
}
}
}
The problem for me is I don't know how to differentiate on the client side if the data received from the Mercure hub is from temperature topic or pressure topic in the message event of EventSource object.
<script type="text/javascript">
$(document).ready(function () {
/**Create two graph on page ready **/
let temperatureGraphObject = createTemperatureGraph(canvasTemperaturaGraph);
let pressureGRaphObject = createPressureGraph(canvasPressureGraph);
/**
I have two function updateTemperatureGraph(temperatureGraphObject, newTemperaturaData) and updatePressureGraph(pressureGraphObject, newPresureData)
**/
/**Subscribe client to topics for data updates **/
{% set topics = ['realtime-notif/temperature/'~temperatureSensorId, 'realtime-notif/pressure/'~pressureSensorId] %}
const eventSource = new EventSource("{{ mercure(topics, { subscribe:topics})|escape('js')}}", {withCredentials: true});
eventSource.onopen = function () {
console.log('New socket connection!');
};
eventSource.onmessage = function (e) {
console.log('New data received');
var data = JSON.parse(e.data);
/**
The problem is here, how differentiate the topics data to call updateTemperaturaGraph(temperatureGraphObject, data) or updatePressureGraph(pressureGraphObject, data)
**/
};
eventSource.onerror = function () {
console.log('Socket connection lost!');
};
});
</script>
So, how differentiate the topics data to call updateTemperaturaGraph(temperatureGraphObject, data) or updatePressureGraph(pressureGraphObject, data) into onmessage event?
If I subscribe the client to only one topic all data received will be of kind of the topic graph, and of course the graph is updated correctly.
The solution is set de type attribute for Update class constructor that you want to publish in your Mercure hub from the MessageHandler related class. So, for the messages related to temperature notification we will set the type attribute = 'temperatureUpdate', and for the message related to pressure notification we will set the type attribute = 'pressureUpdate'.
The __invoke function on TemperatureMessageHandler:
public function __invoke(TemperatureMessage $message)
{
try {
$graphId=$message->getGraphId();
$lastElapsedTime=$message->getLastElapsedTime();
$em=$this->managerRegistry->getManager();
$storedData = $em->getRepository(Temperature::class)->findLastRecordsForGraph($graphId, $lastElapsedTime);
/**
Set the data source for the temperature graph to a specific format from $toredData
**/
$formatedChartData = [];
**....**
$update = new Update(
sprintf('realtime-notif/temperature/%s', $graphId),
\json_encode($$formatedChartData),
true,
null,
'temperatureUpdate'
);
$this->mercureHub->publish($update);
} catch (\Exception $exc) {
}
}
The __invoke function on PressureMessageHandler:
public function __invoke(PressureMessage $message)
{
try {
$graphId = $message->getGraphId();
$lastElapsedTime = $message->getLastElapsedTime();
$em = $this->managerRegistry->getManager();
$storedData = $em->getRepository(Pressure::class)->findLastRecordsForGraph($graphId, $lastElapsedTime);
/**
Set the data source for the pressure graph to a specific format from $toredData
**/
$formatedChartData = [];
**....**
$update = new Update(
sprintf('realtime-notif/pressure/%s', $graphId),
\json_encode($$formatedChartData),
true,
null,
'pressureUpdate'
);
$this->mercureHub->publish($update);
} catch (\Exception $exc) {
}
}
On the client side, is mandatory to create two new EventListeners for the EventSource object, with the name equals to the new types created. Every one new listener will treat the related messages types published in the Mercure hub:
<script type="text/javascript">
$(document).ready(function () {
/**Create two graph on page ready **/
let temperatureGraphObject = createTemperatureGraph(canvasTemperaturaGraph);
let pressureGRaphObject = createPressureGraph(canvasPressureGraph);
/**
I have two function updateTemperatureGraph(temperatureGraphObject, newTemperaturaData) and updatePressureGraph(pressureGraphObject, newPresureData)
**/
/**Subscribe client to topics for data updates **/
{% set topics = ['realtime-notif/temperature/'~temperatureSensorId, 'realtime-notif/pressure/'~pressureSensorId] %}
const eventSource = new EventSource("{{ mercure(topics, { subscribe:topics})|escape('js')}}", {withCredentials: true});
eventSource.onopen = function () {
console.log('New socket connection!');
};
eventSource.addEventListener("temperaturaUpdate", function (e) {
let parsedData = null;
try {
parsedData = JSON.parse(e.data);
} catch (error) {
console.log(error);
}
if (parsedData) {
updateTemperatureGraph(temperatureGraphObject, parsedData);
}
}, false);
eventSource.addEventListener("pressureUpdate", function (e) {
let parsedData = null;
try {
parsedData = JSON.parse(e.data);
} catch (error) {
console.log(error);
}
if (parsedData) {
updatePressureGraph(pressureGraphObject, parsedData);
}
}, false);
eventSource.onerror = function () {
console.log('Socket connection lost!');
};
});
</script>
In this way, the Mercure hub publishes the classified messages, and each EventListener will be in charge of processing the corresponding message in the order in which it arrives at the subscribed client, regardless of the topics to which it is subscribed.

'Server side events' send with the ASP Web Api do not arrive?

I created a test source which should send a message to the client every x time. This is the ApiController:
public class TestSourceController : ApiController
{
private static readonly ConcurrentQueue<StreamWriter> ConnectedClients = new ConcurrentQueue<StreamWriter>();
[AllowAnonymous]
[Route("api/sources/test")]
public HttpResponseMessage Get()
{
var response = Request.CreateResponse();
response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>) OnStreamAvailable,
"text/event-stream");
return response;
}
private static void OnStreamAvailable(Stream stream, HttpContent headers, TransportContext context)
{
var clientStream = new StreamWriter(stream);
ConnectedClients.Enqueue(clientStream);
}
private static void DoThings()
{
const string outboundMessage = "Test";
foreach (var clientStream in ConnectedClients)
{
clientStream.WriteLine("data:" + JsonConvert.SerializeObject(outboundMessage));
clientStream.Flush();
}
}
}
The clientStream.Flush(); is called like expected and without exceptions.
I handle it in AngularJS like this:
$scope.handleServerCallback = function (data) {
console.log(data);
$scope.$apply(function() {
$scope.serverData = data;
});
};
$scope.listen = function () {
$scope.eventSource = new window.EventSource("http://localhost:18270/api/sources/test");
$scope.eventSource.onmessage = $scope.handleServerCallback;
$scope.eventSource.onopen = function() { console.log("Opened source"); };
$scope.eventSource.onerror = function (e) { console.error(e); };
};
$scope.listen();
My guess is it's a problem with the server since I can see the "EventStream" from the test call is empty in the chrome debugger.
Does anyone know how to make sure the messages arrive at the client?
The solution was quite easy, according to the spec every line has to end with "\n" and the very last line with "\n\n".
So:
clientStream.WriteLine("data:" + JsonConvert.SerializeObject(outboundMessage) + "\n\n");
Solves it.

SignalR 2.0 Hub public method not accecible via Java Script

I'm trying to get list of connected users by using the following server code in SignalR hub. For store in-memory data I'm using following class:
public class UserInfo
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
public string Role { get; set; }
}
When user connected I'm adding user to the list of connected users:
public override Task OnConnected()
{
if (Context.User.Identity.IsAuthenticated)
{
if (Context.User.IsInRole("User"))
{
ui.Add(new UserInfo { ConnectionId = Context.ConnectionId, UserName = Context.User.Identity.Name, Role = "User" });
}
else
{
ui.Add(new UserInfo { ConnectionId = Context.ConnectionId, UserName = Context.User.Identity.Name, Role = "Operator" });
}
}
return base.OnConnected();
}
Here is the way I'm getting list of currently connected users:
public IEnumerable<UserInfo> GetUsers()
{
var x = (from a in ui where a.Role == "User" select new UserInfo { UserName = a.UserName, ConnectionId = a.ConnectionId }).ToList();
return x;
}
public IEnumerable<UserInfo> GetOperators()
{
var y = (from a in ui where a.Role == "Operator" select new UserInfo { UserName = a.UserName, ConnectionId = a.ConnectionId }).ToList();
return y;
}
Unfortinately public method GetOperators/GetUsers not accessible and I did not receive data on client side:
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
//Here I'm calling hub public methods
chat.getOperators = function (data) {
alert(data);
};
chat.getUsers = function (data) {
alert(data);
};
// Create a function that the hub can call to broadcast messages.
chat.client.addChatMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.sendChatMessage($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
Your syntax for the calls to the server is wrong; this here:
chat.getUsers = function (data) {
alert(data);
};
will simply define chat.getUsers to be a function.
You probably want
chat.server.getUsers().done(function(data) {
console.log(data);
}).fail(function(error) {
console.log("failed to get data", error);
});
Take another look at the documentation.
please can you try this
//on your client action do a server call
chat.server.getOperators();
and
//on your client action do a server call
chat.server.getUsers();
instead of
chat.getOperators = function (data) {
alert(data);
};
chat.getUsers = function (data) {
alert(data);
};

crawler4j compile error with class CrawlConfig - VariableDeclaratorId Expected

The code will not compile. I changed the JRE to 1.7. The compiler does not highlight the class in Eclipse and the CrawlConfig appears to fail in the compiler. The class should be run from the command line in Linux.
Any ideas?
Compiler Error -
Description Resource Path Location Type
Syntax error on token "crawlStorageFolder", VariableDeclaratorId expected after this token zeocrawler.java /zeowebcrawler/src/main/java/com/example line 95 Java Problem
import edu.uci.ics.crawler4j.crawler.CrawlConfig;
import edu.uci.ics.crawler4j.crawler.CrawlController;
import edu.uci.ics.crawler4j.crawler.Page;
import edu.uci.ics.crawler4j.crawler.WebCrawler;
import edu.uci.ics.crawler4j.fetcher.PageFetcher;
import edu.uci.ics.crawler4j.parser.HtmlParseData;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtConfig;
import edu.uci.ics.crawler4j.robotstxt.RobotstxtServer;
import edu.uci.ics.crawler4j.url.WebURL;
public class Controller {
String crawlStorageFolder = "/data/crawl/root";
int numberOfCrawlers = 7;
CrawlConfig config = new CrawlConfig();
config.setCrawlStorageFolder(crawlStorageFolder);
PageFetcher pageFetcher = new PageFetcher(config);
RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcher);
CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);
controller.addSeed("http://www.senym.com");
controller.addSeed("http://www.merrows.co.uk");
controller.addSeed("http://www.zeoic.com");
controller.start(MyCrawler.class, numberOfCrawlers);
}
public URLConnection connectURL(String strURL) {
URLConnection conn =null;
try {
URL inputURL = new URL(strURL);
conn = inputURL.openConnection();
int test = 0;
}catch(MalformedURLException e) {
System.out.println("Please input a valid URL");
}catch(IOException ioe) {
System.out.println("Can not connect to the URL");
}
return conn;
}
public static void updatelongurl()
{
// System.out.println("Short URL: "+ shortURL);
// urlConn = connectURL(shortURL);
// urlConn.getHeaderFields();
// System.out.println("Original URL: "+ urlConn.getURL());
/* connectURL - This function will take a valid url and return a
URL object representing the url address. */
}
public class MyCrawler extends WebCrawler {
private Pattern FILTERS = Pattern.compile(".*(\\.(css|js|bmp|gif|jpe?g"
+ "|png|tiff?|mid|mp2|mp3|mp4"
+ "|wav|avi|mov|mpeg|ram|m4v|pdf"
+ "|rm|smil|wmv|swf|wma|zip|rar|gz))$");
/**
* You should implement this function to specify whether
* the given url should be crawled or not (based on your
* crawling logic).
*/
#Override
public boolean shouldVisit(WebURL url) {
String href = url.getURL().toLowerCase();
return !FILTERS.matcher(href).matches() && href.startsWith("http://www.ics.uci.edu/");
}
/**
* This function is called when a page is fetched and ready
* to be processed by your program.
*/
#Override
public void visit(Page page) {
String url = page.getWebURL().getURL();
System.out.println("URL: " + url);
if (page.getParseData() instanceof HtmlParseData) {
HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
String text = htmlParseData.getText();
String html = htmlParseData.getHtml();
List<WebURL> links = htmlParseData.getOutgoingUrls();
System.out.println("Text length: " + text.length());
System.out.println("Html length: " + html.length());
System.out.println("Number of outgoing links: " + links.size());
}
}
}
This is a pretty strange error since the code seems to be clean. Try to start eclipse with the -clean option on command line.
Change
String crawlStorageFolder = "/data/crawl/root";
to
String crawlStorageFolder = "./data/crawl/root";
i.e. add a leading .

Flex 3: Getting variables from URL

If I have an application located at http://sitename.com/myapp/ and i want to pass in a variable via the url (i.e. - http://sitename.com/myapp/?name=Joe), how can I get that name variable into a string var?
I use the class Adobe provided in this article.
package
{
import flash.external.*;
import flash.utils.*;
public class QueryString
{
private var _queryString:String;
private var _all:String;
private var _params:Object;
public function get queryString():String
{
return _queryString;
}
public function get url():String
{
return _all;
}
public function get parameters():Object
{
return _params;
}
public function QueryString()
{
readQueryString();
}
private function readQueryString():void
{
_params = {};
try
{
_all =
ExternalInterface.call("window.location.href.toString");
_queryString =
ExternalInterface.call("window.location.search.substring", 1);
if(_queryString)
{
var params:Array = _queryString.split('&');
var length:uint = params.length;
for (var i:uint=0,index:int=-1; i 0)
{
var key:String = kvPair.substring(0,index);
var value:String = kvPair.substring(index+1);
_params[key] = value;
}
}
}
}catch(e:Error) { trace("Some error occured.
ExternalInterface doesn't work in Standalone player."); }
}
}
}
UPDATE: An updated version of this class can also be found here, although I haven't tried this one.
UPDATE 2:
Here's an example on how to use the Querystring class:
public function CheckForIDInQuerystring():void
{
// sample URL: http://www.mysite.com/index.aspx?id=12345
var qs:QueryString = new QueryString;
if (qs.parameters.id != null)
{
// URL contains the "id" parameter
trace(qs.parameters.id);
}
else
{
// URL doesn't contain the "id" parameter
trace("No id found.");
}
}
Divide 'em with String.split() and conquer:
var url:String = "http://www.xxx.zzz/myapp?arg1=vae&arg2=victus";
var params:String = url.substr(url.lastIndexOf("?") + 1);
if (params.length == url.length) return; //no params
for each (var pair:String in params.split("&"))
{
trace("Got parameter:");
var nameValue:Array = pair.split("=");
trace("name: " + nameValue[0] + ", value: " + nameValue[1]);
}
Output:
Got parameter:
name: arg1, value: vae
Got parameter:
name: arg2, value: victus

Resources