Newer
Older
exporter / Exporter.as
package
{
	import flash.display.*;
	import flash.net.*;
	import flash.events.*;
	import flash.desktop.*;
	import flash.errors.*;
	import flash.system.*;
	import flash.utils.*;
	import by.blooddy.crypto.*;

	public class Exporter extends MovieClip
	{
		public static var Instance:Exporter = null;
		
		public static var DefaultPort:int = 7890;
		private var driver:Socket = null;
		public function Exporter()
		{
			Instance = this;
			
			try
			{
				NativeApplication.nativeApplication.addEventListener("invoke", ApplicationInvoked);
			}
			catch (e)
			{
				// not an air runtime app
				ConnectDriver(DefaultPort);	// try default port
			}
		}
		
		public function ApplicationInvoked(e)
		{
			if (e.arguments.length == 1)
			{
				ConnectDriver(parseInt(e.arguments[0]));
			}
			else
			{
				ConnectDriver(DefaultPort);
			}
		}
		
		private function ConnectDriver(port)
		{
			Trace("Attempting to connect to driver");
			try
			{
				var s:Socket = new Socket();
				s.addEventListener(IOErrorEvent.IO_ERROR, DriverError);
				s.addEventListener(Event.CONNECT, DriverConnected);
				s.connect("localhost", port);
			}
			catch (e)
			{
				Trace("Error establishing wrapper connection");
			}
		}
		
		private function DriverError(e)
		{
			Trace("  Failed to connect");
		}
		
		private function DriverConnected(e)
		{
			Trace("  Connected");
			driver = e.target as Socket;
			driver.addEventListener(ProgressEvent.SOCKET_DATA, DriverRecv);
		}
		
		private function Quit()
		{
			fscommand("quit");
			try
			{
				NativeApplication.nativeApplication.exit();
			} catch (e)
			{
				
			}
		}

		private var jobQueue:Array = new Array();
		private var activeJob:Job = null;
		private function QueueJob(jobParams)
		{
			var input:ByteArray = null;
			if (jobParams.hasOwnProperty("input"))
			{
				input = Base64.decode("" + jobParams.input);
			}
						
			if (!jobParams.hasOwnProperty("id"))
			{
				Print("Failure: job details didn't contain job id");
				CheckNewJob();
				return;
			}
			var id:int = parseInt(jobParams.id);
			
			if (!jobParams.hasOwnProperty("name"))
			{
				Print("Failure: job " + id + " details didn't contain job name");
				JobFailed(id);
				return;
			}
			var name:String = "" + jobParams.name;

			delete jobParams.command;
			delete jobParams.input;
			delete jobParams.id;
			
			var job:Job = new Job(id, name, input, jobParams);
			jobQueue.push(job);
			CheckNewJob();
		}
		
		private function JobFailed(id:int)
		{
			DriverCommand("done", {id:id});
			CheckNewJob();
		}
		
		private function CheckNewJob()
		{
			if (activeJob == null && jobQueue.length > 0)
			{
				activeJob = jobQueue.shift();
				activeJob.Go(JobComplete);
			}
		}
		
		private function JobComplete()
		{
			Trace("Done: " + activeJob.GetID());
			DriverCommand("done", activeJob.GetCompletedData());
			
			activeJob = null;
			CheckNewJob();
		}
		
		private function DispatchCommand(cmdData)
		{
			try
			{
				if (cmdData.hasOwnProperty("command"))
				{
					var cmd = "" + cmdData.command;
					//Trace("cmd: " + cmd);
					switch (cmd)
					{
						case "trace":
							Trace(cmdData.string);
						break;
						case "exit":
							Quit();
						break;
						case "job":
							QueueJob(cmdData);
						break;
						default:
							Trace("Recv unknown: " + JSON.stringify(cmdData));
						break;
					}
				}
			} catch (e)
			{
				Print(e.getStackTrace());
			}
		}
		
		private var buffer:ByteArray = new ByteArray();
		private var swpBuffer:ByteArray = new ByteArray();
		private function DriverRecv(e)
		{
			var oldPos = buffer.position;
			//Trace("recv");
			try
			{
				driver.readBytes(buffer, buffer.length, driver.bytesAvailable);
				//Trace(buffer.length - buffer.position);				
				var msg = buffer.readUTF();

				buffer.readBytes(swpBuffer);
				buffer.clear();
				
				var tmp = buffer;
				buffer = swpBuffer;
				swpBuffer = tmp;
				
				var cmdData = JSON.parse(msg);
				DispatchCommand(cmdData);
			}
			catch (eof:EOFError)
			{
				buffer.position = oldPos;
				//Trace("Waiting for more data... " + driver.bytesAvailable + " " + (buffer.length - buffer.position));
				// wait for more data
			}
			catch (err:IOError)
			{
				Trace("Driver IO error");
			}
			catch (err)
			{
				Trace("Problem reading from driver:\n" + err.toString());
			}
		}
		
		private function DriverCommand(cmd:String, data = null)
		{
			var obj = {command:cmd};
			if (data != null)
			{
				for (var k in data)
				{
					obj[k] = data[k];
				}
			}
			DriverSend(JSON.stringify(obj));
		}
		
		private function DriverSend(str:String)
		{
			if (driver != null)
			{
				Trace(str);
				driver.writeUTF(str);
				driver.flush();
			}
		}
		
		public function Trace(str)
		{
			str = "" + str;
			traceText.x = 2;

			trace(str);
			traceText.width = stage.stageWidth - 4;
			traceText.height = stage.stageHeight - 4;
			if (traceText.text == "")
			{
				traceText.text = str;
			}
			else
			{
				traceText.appendText("\n" + str);
			}
			traceText.y = stage.height - traceText.textHeight - 2;
		}
		
		public function Print(str:String, localTrace:Boolean = true)
		{
			if (localTrace || driver == null)
			{
				Trace(str);
			}
			else
			{
				trace(str);
			}
			if (driver != null)
			{
				DriverCommand("print", {string:str + "\n"});
			}
		}
	}
}