Shared Objects Send Method() - actionscript-3

There appears to be an error in the Adobe documentation in regards using the shared object.send(). I am trying to execute the send method to all clients.
I copied the client and server-side code from Adobe and I am unable to invoke the function.
This is my compile error in the output
Line 31 1119: Access of possibly undefined property doSomething through a reference with static type flash.net:SharedObject.
Any suggestions how i can fix this to as3 novice. Please can anyone help me?
var nc:NetConnection = new NetConnection();
nc.connect("rtmfp://localhost/submitSend");
nc.addEventListener(NetStatusEvent.NET_STATUS, netHandler);
function netHandler(event:NetStatusEvent):void{
switch(event.info.code){
case "NetConnection.Connect.Sucess":
trace("Connecting...");
break;
case "NetConnection.Connect.Failed":
trace("Unable to connect up");
break;
case "NetConnection.Connect.Rejected":
trace("Whoops");
break;
}
}
var so:SharedObject = SharedObject.getRemote("mySo", nc.uri, true);
so.connect(nc);
so.doSomething = function(str) {
// Process the str object.
};
Server side:
var so = SharedObject.get("mySo", true);
so.send("doSomething", "This is a test");

As said in my previous comment, a link to the document you're refering to would be welcome to help people helping you...
Here is already some points that ought to be mentionned:
You should add your event listeners before any call to connect().
You should connect your shared object only once you received the NetConnection.Connect.Success event (by the way, you have a typo in your sample on this name)
You should set you class instance as the client of your shared object.
I'm not sure all of this will fix your issue but you can try this:
var nc:NetConnection = new NetConnection();
private function netHandler(event:NetStatusEvent):void
{
switch(event.info.code)
{
case "NetConnection.Connect.Success":
{
trace("Connecting...");
connectSharedObject();
break;
}
case "NetConnection.Connect.Failed":
{
trace("Unable to connect up");
break;
}
case "NetConnection.Connect.Rejected":
{
trace("Whoops");
break;
}
}
}
private function connectSharedObject():void
{
var so:SharedObject = SharedObject.getRemote("mySo", nc.uri, true);
so.client = this;
so.connect(nc);
}
public function doSomething(str:String):void
{
// Process the str object.
}
nc.addEventListener(NetStatusEvent.NET_STATUS, netHandler);
nc.connect("rtmfp://localhost/submitSend");

Related

Deal connection lost in ActionScript 3

I have this code:
public function Json2Me(_urlJSON:String) {
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
request.url = _urlJSON;
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR,informadorIO);
loader.load(request);
}
private function onLoaderComplete(e:Event):void{
var loader:URLLoader = URLLoader(e.target);
JSONEnviado = com.adobe.serialization.json.JSON.decode(loader.data);
dispatchEvent(new Event("LanzaJSON"));
}
public function informadorIO(e:Event):void{
trace(e);
}
I need to protect my code against connection lost, so what I have to do to keep my project running?
You can catch the IO errors on url loader:
loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
private function ioErrorHandler(event:IOErrorEvent):void {
// URLLoader io failed
trace("ioErrorHandler: " + event);
// retry Json2Me maybe? How many times before you fail completely? Notify user?
Json2Me("https://someurl.com/xxxxx")
}
Also the uncaughtErrorEvents on the Loader/LoaderInfo can catch things like not even having a network connection.
LoaderInfo.uncaughtErrorEvents: to detect uncaught errors in code
defined in the same SWF. Loader.uncaughtErrorEvents: to detect
uncaught errors in code defined in the SWF loaded by a Loader object.
Example:
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, onUncaughtError);
private function onUncaughtError(e:UncaughtErrorEvent):void {
e.preventDefault();
trace("onUncaughtError!!! - " + e.toString());
// Notify user of failure?...
}
You can also use a HTTPStatusEvent which can give use the returned HTTP status ( or even the returned HTTP response headers for an AIR app ) :
var url_loader:URLLoader = new URLLoader()
url_loader.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS, on_http_status); // works only for AIR
url_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, on_http_status);
url_loader.load(new URLRequest('http://www.example.com'))
function on_http_status(e:HTTPStatusEvent): void
{
trace(e.type); // gives, for example : httpStatus
trace(e.status); // gives, for example : 200
}
Hope that can help.

Error hanlder for FileStream - AS3 AIR

I'm saving an object to a file using FileStream. The object I'm saving has variables in it:
var saveObj:Object = new Object()
saveObj['FirstName']="Georges"
saveObj['LastName']="St-Pierre"
MY question is this: How do I make an error handler for a variable missing when I load the File? For example 'Firstname' is missing. How do I do that? This is the code I have but it doesn't work.
private function F_loadData():void {
folder = File.documentsDirectory.resolvePath("saved projects");
var file:File = folder.resolvePath("mySave.adktf");
var stream:FileStream = new FileStream();
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
stream.openAsync(file, FileMode.READ);
var myLoadedObj:Object = stream.readObject();
stream.close()
trace(myLoadedObj.MiddleName)
}
private function completeHandler(event:Event):void {
trace("load Complete")//not final. Just for testing
}
private function progressHandler(event:ProgressEvent):void {
// ...
}
//I was hoping the error would call this function
private function errorHandler(event:IOErrorEvent):void {
trace("Error found")//not final. Just for testing
}
trace(myLoadedObj.MiddleName) should return an error and i was hoping that it would call the error Handler function that I made, but it didn't. It still returns an error. So how and what type of error handler should I use?
Since you are opening your file asynchronously, you need to wait to use readObject until after the complete event.
The error handler you've defined is only applicable to the loading of the file. SO if there is a problem opening the file the error handler will be called, any other kind of error is outside that scope.
Try something like this:
private var stream:FileStream;
private function F_loadData():void {
folder = File.documentsDirectory.resolvePath("saved projects");
var file:File = folder.resolvePath("mySave.adktf");
if(file.exists){
stream = new FileStream();
stream.addEventListener(Event.COMPLETE, completeHandler);
stream.addEventListener(ProgressEvent.PROGRESS, progressHandler);
stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
stream.openAsync(file, FileMode.READ);
//now wait for it to load
}else{
//file doesn't exist, do something
}
}
private function completeHandler(e:Event):void {
trace("load Complete")//not final. Just for testing
var myLoadedObj:Object = stream.readObject();
stream.close();
stream = null;
if(!myLoadedObj.MiddleName || myLoadedObj.MiddleName == ""){
//Middle name is missing or empty, do something
}
if(!myLoadedObj.FirstName || myLoadedObj.FirstName == ""){
//First name is missing or empty, do something
}
}
You may be better suited to using a custom class for your save object, something like this:
package {
public class SaveObject {
public var middleName:String;
public var lastName:String;
//any other properties
public function validate():Boolean {
//write some validation
//if you want lazy validation, you could do this: (untested)
for (var i in obj){
if(obj[i] is String && (obj[i] == null || obj[i] == "")){
return false;
}
}
return true;
}
}
}
Then, you can do this: (in your constructor)
flash.net.registerClassAlias("SaveData",SaveData);
Then you can do the following:
var mySaveData:SaveData = new SaveData();
//set properties
stream.writeObject(mySaveData);
//then later
var mySaveData:SaveData = stream.readObject();
if(!mySaveData.validate()){
//do something, it's invalid
}

How to use remote SharedObject in AS3 and Red5

I wish to use remote SharedObject so I created a simple script to test out the techniques. When I ran the following code as two instances of SWF, both instances output 1, which was incorrect because the second instance was supposed to output 2.
import flash.net.SharedObject;
import flash.events.SyncEvent;
var nc:NetConnection;
var so:SharedObject;
nc = new NetConnection();
nc.client = { onBWDone: function():void{} };
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.connect("rtmp://localhost:1935/live");
var t = new TextField();
addChild(t);
function onNetStatus(event:NetStatusEvent):void{
if(event.info.code == "NetConnection.Connect.Success"){
so = SharedObject.getRemote("shObj",nc.uri);
so.connect(nc);
if (!(so.data.total > 0 && so.data.total<1000)) {// undefined
so.data.total=1;
} else so.data.total=2;
t.text=so.data.total;
}
}
Did I miss out something? Do I need to make some special settings to Flash or Red5? Do I need to create a special directory? Must I use a special event listener? Could anyone correct the code for me?
(09 Apr 2014)
When I used an event listener like the following, I got a blank screen for both instances, which was strange because I expected at least the second screen to show '2'. Can someone explain the behavior?
import flash.net.SharedObject;
import flash.events.SyncEvent;
var nc:NetConnection;
var so:SharedObject;
nc = new NetConnection();
nc.client = { onBWDone: function():void{} };
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.connect("rtmp://localhost:1935/live");
var t = new TextField();
addChild(t);
function onNetStatus(event:NetStatusEvent):void{
if(event.info.code == "NetConnection.Connect.Success"){
so = SharedObject.getRemote("shObj",nc.uri);
so.addEventListener(SyncEvent.SYNC,syncHandler);
so.connect(nc);
so.setProperty("total",2);
}
}
function syncHandler(event:SyncEvent):void{
if (so.data.total) {
t.text = so.data.total;
}
}
Basically for the use of Shared Objects, I would recommend splitting the job into three seperate parts.
Attach Event Listener and connect to the Shared Object
function onNetStatus(event:NetStatusEvent):void
{
if(event.info.code == "NetConnection.Connect.Success")
{
so = SharedObject.getRemote("shObj",nc.uri);
so.addEventListener(SyncEvent.SYNC,syncHandler); //add event listener for Shared Object
so.connect(nc);
}
}
Complete the Event Handler method to reflect changes in the value of Shared Object
/* This function is called whenever there is change in Shared Object data */
function syncHandler(event:SyncEvent):void
{
if(so.data.total) //if total field exists in the Shared Object
trace(so.data.total);
}
Change the data in Shared Object:
Use the setProperty method of Shared Object here. Invoke this method when you need to change the value (maybe at button click or on occurrence of certain Event)
/* This function writes values to the Shared Object */
function changeValue(newValue:String)
{
so.setProperty("total",newValue);
}

ActionScript 3: How to remove EventListener with anon functions

I have written code as follows.
Problem is that I can't remove Event.COMPLETE event listener and when I call the loadData function twice or more, it works 2 times or more. Sorry for my bad english and worse explanation but I need to fix it today and I don't know what to do.
I think the code is pretty obvious. please help!
var ldr:URLLoader = new URLLoader();
function loadData(text_place, scrollbar, fileURL:String):void {
text_place.wordWrap = true;
var f:TextFormat = new TextFormat();
f.align = TextFormatAlign.RIGHT;
text_place.setTextFormat(f);
ldr.dataFormat = URLLoaderDataFormat.TEXT;
ldr.load(new URLRequest(fileURL));
ldr.addEventListener(Event.COMPLETE, function ldr_complete(evt:Event){
initText(text_place, ldr.data, scrollbar);
});
ldr.addEventListener(IOErrorEvent.IO_ERROR, loadError);
}
function initText(text_place:TLFTextField, fileContent, scrollbar):void {
ldr.removeEventListener(IOErrorEvent.IO_ERROR, loadError);
text_place.htmlText = "";
text_place.tlfMarkup = fileContent;
scrollbar.update();
trace("Data loaded");
}
function loadError(e:IOErrorEvent):void {
trace("Error loading an external file.");
}
just avoid writing function enclosures and extend the scope of the complete function's passed arguments so it can access them.
var ldr:URLLoader = new URLLoader();
var text_place:TextField;
var scrollbar:Object; //or whatever it is
function loadData(text_place, scrollbar, fileURL:String):void
{
var f:TextFormat = new TextFormat();
f.align = TextFormatAlign.RIGHT;
text_place.wordWrap = true;
text_place.setTextFormat(f);
scrollbar = scrollbar;
ldr.dataFormat = URLLoaderDataFormat.TEXT;
ldr.load(new URLRequest(fileURL));
ldr.addEventListener(IOErrorEvent.IO_ERROR, loadError);
ldr.addEventListener(Event.COMPLETE, loadComplete);
}
function initText(text_place:TLFTextField, fileContent, scrollbar):void
{
removeLoaderEventListeners();
text_place.htmlText = "";
text_place.tlfMarkup = fileContent;
scrollbar.update();
trace("Data loaded");
}
function loadError(e:IOErrorEvent):void
{
removeLoaderEventListeners();
trace("Error loading an external file.");
}
function loadComplete(evt:Event):void
{
removeLoaderEventListeners();
initText(text_place, ldr.data, scrollbar);
}
function removeLoaderEventListeners():void
{
ldr.removeEventListener(IOErrorEvent.IO_ERROR, loadError);
ldr.removeEventListener(Event.COMPLETE, loadComplete);
}
if you want to stop listening for an event after it triggered, you can unregister the anonymous listener in itself:
ldr.addEventListener(Event.COMPLETE, function(event:Event):void
{
event.target.removeEventListener(event.type, arguments.callee);
// ... do whatever you need to do here
});
But if you also want to stop listening for other events from the same dispatcher when it completes, such as your IOErrorEvent.IO_ERROR listener, you'd still need a reference to that listener to remove it.
There is a simpler way. Instead of removing event listeners, close the loader.
ldr.close();
Per the documentation:
Closes the load operation in progress. Any load operation in progress
is immediately terminated. If no URL is currently being streamed, an
invalid stream error is thrown.

URLRequest or Loader simply not working on some computers?

So my problem may be a little bigger than that, but I'm not certain. I'm creating a custom flash photo viewer for a client that dynamically loads the images with Loader objects. It takes a folder name in a specified directory on the server and calls a php page (using URLRequest) to get the workable contents of the folder. And then it loads it up from that array.
Here's the problem: it works FINE on my machine and every machine I've tested it on, but it DOESN'T work on my client's machine or some of his customer's machines. The loader bar that's at the bottom of the screen doesn't start to fill, which means that the images aren't starting to even load, and the status bar indicates that it continues to wait for a the server, yet never finishes waiting. This is consistent on a single machine, but varies across machines.
I've added diagnostics (a custom class I made to track certain vars and collect errors) to the thing to catch any errors, but it reports nothing on my client's machine. I've added flash version checking code, so the possibility of a lower version messing it up is gone...
I guess my question is, is there anything (security, environment, etc) that I could have overlooked that doesn't allow request objects or something to work on certain machines?? I've been ripping my hair out trying to figure this out!
My code (relevant sections):
public static const LOADLIMIT:int = 4;
public var paramObj:Object;
private var imageRequests:Vector.<URLRequest>;
private var loaderObj:Vector.<Loader>;
private var nextToLoad:int = -1;
//...
public function Player(){
//...
paramObj = loaderInfo.parameters;
if (!paramObj.root) paramObj.root = "http://site.com/images/";
paramObj.imgloc = paramObj.imgloc;
var res = bootstrapImages(paramObj.imgloc);
if (res is String){
loadErrorMsg.text = res;
loadErrorMsg.visible = true;
log.log(res);
}
//...
}
private function bootstrapImages(imgloc:String):*{
try{
if (!imgloc) return "No image location specified";
var req:URLRequest = new URLRequest(paramObj.root+"getdirlist.php?name="+imgloc);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, directoryLoaded);
loader.addEventListener(IOErrorEvent.IO_ERROR, function(ex:IOError){
loadErrorMsg.text = "Error retreiving album data.";
loadErrorMsg.visible = true;
log.log(ex);
});
loader.load(req);
} catch (ex:Error){
log.log(ex); throw ex;
}
}
private function directoryLoaded(e:Event){
try{
//directory will come down as a json array
trace(e.target.data);
try {
var items:Array = JSON.decode(e.target.data);
} catch (ex:Error){
trace (ex.getStackTrace());
loadErrorMsg.text = "Error parsing album data.";
loadErrorMsg.visible = true;
log.log(ex);
return;
}
if (items.length == 0){
loadErrorMsg.text = "Invalid album name";
loadErrorMsg.visible = true;
log.log("Items length is 0.");
return;
}
imageRequests = new Vector.<URLRequest>();
loaderObj = new Vector.<Loader>();
for each(var item:String in items){
imageRequests.push(new URLRequest(paramObj.root+"coffeeimages/"+paramObj.imgloc+"/"+item));
loaderObj.push(null);
}
//...show UI...
for (var i:int = 0; i < LOADLIMIT; i++){
imageLoaded(null);
}
} catch (ex:Error){
log.log(ex); throw ex;
}
}
private function imageLoaded(e:Event){
try{
//if this was called as a result of the load event, start the slideshow! :D
if (e != null && e.target != null) {
//stage.addChild((e.target as LoaderInfo).loader);
trace(loaderObj[0]);
if (loaderObj[0] != null && //if the first image is loaded
loaderObj[0].contentLoaderInfo.bytesLoaded >= loaderObj[0].contentLoaderInfo.bytesTotal){
trace(loaderObj[0].contentLoaderInfo.bytesLoaded, loaderObj[0].contentLoaderInfo.bytesTotal);
loadErrorMsg.visible = false;
playSlideshow(true);
}
}
trace((e)?e.target:null, loaderObj);
nextToLoad++;
if (nextToLoad >= imageRequests.length) return;
var r:URLRequest = imageRequests[nextToLoad];
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
l.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(ex:ErrorEvent){
loadErrorMsg.text = "Error parsing image data.";
loadErrorMsg.visible = true;
log.log(ex);
});
l.load(r);
loaderObj[nextToLoad] = l;
log.addObjectWatch(l);
} catch (ex:Error){
log.log(ex); throw ex;
}
}
Also, here's the player live on the site. Ctrl+Alt+Home brings up my diagnostics panel. Please tell me if it doesn't work for you as well, so I can be more worried about this... :/ Thanks.
Edit: I have added more debugging information. Turns out that on the computers that cannot load it, they are getting an HTTP status 0 returned when trying to bootstrap the album information. I have no idea what that means...
So, the problem was a matter of the URL its requesting...
My client was typing "www.site.com", while my code was requesting to "site.com". To Adobe, this is a cross site request, and NOT ALLOWED by default. One solution (and probably the easiest one) is to add a file called "crossdomain.xml" to the root folder of the website. Flash looks for this file when making a request. One example that worked for me is as follows:
//crossdomain.xml
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*.site.com" secure="false"/>
</cross-domain-policy>
Other solutions involve redirecting to one of the two ("site.com" redirects to "www.site.com"), or doing url rewriting, or getting url that they entered.
A few things I noticed, you are only listening for Event.COMPLETE and IOErrorEvent.IO_ERROR. I'd suggest also listening for HTTPStatusEvent.HTTP_STATUS, Event.OPEN, though I haven't added those in, they may provide useful information if you still aren't getting anywhere.
You should not need a LoaderContext object if you are only loading images and not accessing their content, so that (security) really should not be a problem. You should definitely separate out your logic in imageLoaded so that it is not both the initiator and the completion handler for your Loaders.
Anyway, no clue if this will be of use to you, but I've made your code substantially more readable and reworked some things that made little sense.
public static const LOADLIMIT:int = 4;
private var paramObj:Object;
private var imageRequests:Vector.<URLRequest>;
private var loaderObj:Vector.<Loader>;
private var nextToLoad:int = -1;
public function Player(){
paramObj = loaderInfo.parameters;
//what is this all about, your backup URL is useless?
if (!paramObj.root) {
paramObj.root = "http://site.com/images/";
}
var res = bootstrapImages();
if (res.length > 0){
loadErrorMsg.text = res;
loadErrorMsg.visible = true;
//log.log kills me
log.log(res);
}
}
private function bootstrapImages():String {
try {
var req:URLRequest = new URLRequest(paramObj.root + "getdirlist.php?name=" + paramObj.imgloc);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, directoryLoaded);
loader.addEventListener(IOErrorEvent.IO_ERROR, dataIOError);
loader.load(req);
} catch (ex:Error) {
log.log(ex);
}
return "";
}
private function directoryLoaded(e:Event):void{
trace(e.target.data);
try {
var items:Array = JSON.decode(e.target.data);
} catch (ex:Error){
trace (ex.getStackTrace());
loadErrorMsg.text = "Error parsing album data.";
loadErrorMsg.visible = true;
log.log(ex);
return;
}
if (items.length == 0){
loadErrorMsg.text = "Invalid album name";
loadErrorMsg.visible = true;
log.log("Items length is 0.");
return;
}
imageRequests = new Vector.<URLRequest>();
loaderObj = new Vector.<Loader>();
for each(var item:String in items){
imageRequests.push(new URLRequest(paramObj.root+"coffeeimages/"+paramObj.imgloc+"/"+item));
loaderObj.push(new Loader());
}
for (var i:int = 0; i < LOADLIMIT; i++){
loadNextImage();
}
}
private function loadNextImage():void {
nextToLoad++;
if (nextToLoad < imageRequests.length) {
loaderObj[nextToLoad].contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
loaderObj[nextToLoad].contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, dataIOError);
try {
loaderObj[nextToLoad].load(imageRequests[nextToLoad]);
}
catch (e:Error) {
log.log(ex);
}
log.addObjectWatch(loaderObj[nextToLoad]);
}
}
private function dataIOError(e:IOError):void {
loadErrorMsg.text = "IOError: " + e.errorID + " - " + e.name + ", " + e.message;
loadErrorMsg.visible = true;
log.log(ex);
}
private function imageLoaded(e:Event){
//Start the slideshow if the first image has loaded
loadNextImage();
if (e.target == loaderObj[0]) {
trace(loaderObj[0].contentLoaderInfo.bytesLoaded, loaderObj[0].contentLoaderInfo.bytesTotal);
loadErrorMsg.visible = false;
playSlideshow(true);
}
}
Edit: You may simply wish to scrap your loading code entirely and instead use Bulk Loader
I like the crossdomain.xml solution mentioned above, but we had a similar problem on our client PC's. The problem was that adblocker browser plugins were blocking the URLRequest of the actionscript. We are currently finding a solution to this.