Skip to content

Instantly share code, notes, and snippets.

@bastman
Created November 16, 2011 19:09
Show Gist options
  • Save bastman/1371010 to your computer and use it in GitHub Desktop.
Save bastman/1371010 to your computer and use it in GitHub Desktop.
jsonrpc client (as3)
package com.application.rpc
{
/**
* ...
* @author seb
*/
public dynamic class CallbackVO extends Object
{
public function CallbackVO(data:Object=null)
{
if (data is Object) {
for (var key in data) {
this[key] = data[key];
}
}
}
public function getScope():Object
{
return this["scope"];
}
public function setScope(value:Object):void
{
this["scope"] = value;
}
public function getOnError():Function
{
return this["error"];
}
public function setOnError(value:Function):void
{
this["error"] = value;
}
public function getOnResult():Function
{
return this["result"];
}
public function setOnResult(value:Function):void
{
this["result"] = value;
}
public function getOnInvoke():Function
{
return this["invoke"];
}
public function setOnInvoke(value:Function):void
{
this["invoke"] = value;
}
public function getOnProgress():Function
{
return this["progress"];
}
public function setOnProgress(value:Function):void
{
this["progress"] = value;
}
public function getOnResponse():Function
{
return this["response"];
}
public function setOnResponse(value:Function):void
{
this["response"] = value;
}
}
}
package com.application.rpc
{
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
import flash.events.HTTPStatusEvent;
import flash.net.URLLoaderDataFormat;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.net.URLRequestMethod;
import com.adobe.serialization.json.JSON;
/**
* ...
* @author seb
*/
public class Client
{
// where is your gateway / endpoint url?
public var url:String = "http://www.example.com/rpc/json.php";
// do a form post? optional, e.g.field="jsonrpc" --> $_POST["jsonrpc"]
public var formFieldName:String = null;
public var rpcMethodPrefix:String = null; //e.g."HelloworldServer.Api.Fb.";
// global callbacks - are you sure you want to use'em?
protected var _callback:CallbackVO;
public function getCallback():CallbackVO
{
if (!(_callback is CallbackVO)) {
_callback = newCallbackVO();
}
return _callback;
}
// inject rpc properties on each rpc call
protected var _baseParams:Object = {};
public function get baseParams():Object
{
if (!(_baseParams is Object)) {
_baseParams = { };
}
if ((_baseParams==null)) {
_baseParams = { };
}
return _baseParams;
}
public function set baseParams(value:Object) {
_baseParams = value;
}
// singleton
private static var _instance:Client;
public static function getInstance():Client
{
if (!_instance) {
_instance = new Client();
}
return _instance;
}
// +++++++++++ constructor +++++++++++++
public function Client() {
// constructor code
super();
_instance = this;
}
// ++++++++++ methods +++++++++++++++++++
public function newCallbackVO():CallbackVO
{
return new CallbackVO();
}
public function invoke($method:String, $params:Array, $on:Object):RpcVO
{
if (!($method is String)) {
$method = "";
}
if (!($params is Array)) {
$params = [];
}
var rpc:RpcVO = _newRpc(
url,
$method,
$params,
baseParams
);
rpc.on = new CallbackVO($on);
rpc.client = this;
rpc.loader.load(rpc.request);
return rpc;
}
protected function _newRpc($url, $method, $params, $baseParams):RpcVO
{
var rpc:RpcVO = new RpcVO({
client: null,
loader: null,
request:null,
rpc: null,
url: null,
bytesLoaded: 0,
bytesTotal: 0,
onLoaderEvent:null,
response: {
error:null,
result: null
},
on: {
scope: null,
error: null,
result: null,
response: null,
progress: null
}
});
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest();
rpc.loader = loader;
rpc.request = request;
var variables:URLVariables = new URLVariables();
if ((rpcMethodPrefix is String) && (rpcMethodPrefix.length > 0)) {
$method = rpcMethodPrefix + "" + $method;
}
var jsonrpc={
method:$method,
params:$params
}
// apply baseParams if there are any
if ($baseParams is Object)
{
for (var key in $baseParams)
{
jsonrpc[key]=$baseParams[key];
}
}
rpc.rpc = jsonrpc;
var jsonrpcstring=JSON.encode(jsonrpc);
variables.jsonrpc=jsonrpcstring;
request.url = $url;
rpc.url = request.url;
if ((formFieldName is String) && (formFieldName.length > 0)) {
// a form post
request.data=variables;
} else {
// a raw body post
request.data = jsonrpcstring;
//request.contentType = URLLoaderDataFormat.BINARY;
request.contentType = "application/json";
}
request.method=URLRequestMethod.POST;
// no!: request.contentType=URLLoaderDataFormat.VARIABLES;
// loader event handlers
rpc.onLoaderEvent = function(event:Event) {
switch(event.type) {
case Event.OPEN: {
// call request.invoke handler
_onInvoke(rpc);
break;
}
case ProgressEvent.PROGRESS: {
if (rpc) {
// actually does not work for some ajax calls
var bytesTotal = 0 + (event as ProgressEvent).bytesTotal;
var bytesLoaded = 0 + (event as ProgressEvent).bytesLoaded;
rpc.bytesLoaded = bytesLoaded;
rpc.bytesTotal = bytesTotal;
}
// call request.progress handler
_onProgress(rpc);
break;
}
case HTTPStatusEvent.HTTP_STATUS: {
//ignore
break;
}
case Event.COMPLETE: {
try {
var response = {
error:null,
result:null
}
var responseText = event.currentTarget.data;
if (!(responseText is String)) {
throw new Error("invalid response");
}
var responseData = JSON.decode(responseText);
if (!(responseData is Object)) {
throw new Error("invalid response");
}
if (responseData==null) {
throw new Error("invalid response");
}
if (!(responseData.hasOwnProperty("result"))) {
throw new Error("invalid response");
}
if (!(responseData.hasOwnProperty("error"))) {
throw new Error("invalid response");
}
response = {
error:responseData.error,
result:responseData.result
}
// you want all keys in your response?
for (var key in responseData) {
response[key] = responseData[key];
}
} catch (error:Error) {
response = {
result:null,
error: {
message: error.message
}
}
}
if (rpc) {
rpc.response = response;
}
// call response handler
_onResponse(rpc);
// call response.error OR response.result handler
if (response.error) {
// call response.error handler
_onError(rpc);
return;
} else {
// call response.result handler
_onResult(rpc);
}
break;
}
case IOErrorEvent.IO_ERROR:
case SecurityErrorEvent.SECURITY_ERROR: {
if (rpc) {
if (!rpc.response) {
rpc.response = {
result: null
}
}
rpc.response.error = {
message: "CLIENT_ERROR"
}
if (event.type == IOErrorEvent.IO_ERROR) {
rpc.response.error.message = "CLIENT_IOERROR";
}
if (event.type == SecurityErrorEvent.SECURITY_ERROR) {
rpc.response.error.message = "CLIENT_SECURITYERROR";
}
}
// call response handler
_onResponse(rpc);
// call response.error handler
_onError(rpc);
break;
}
default: {
break;
}
}
}
// add loader listeners
loader.addEventListener(Event.COMPLETE, rpc.onLoaderEvent);
loader.addEventListener(Event.OPEN, rpc.onLoaderEvent);
loader.addEventListener(ProgressEvent.PROGRESS, rpc.onLoaderEvent);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, rpc.onLoaderEvent);
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, rpc.onLoaderEvent);
loader.addEventListener(IOErrorEvent.IO_ERROR, rpc.onLoaderEvent);
// return rpc object
return rpc;
}
protected function _onInvoke(rpc:RpcVO)
{
//trace(this + "._onInvoke()");
if (!rpc) {
return;
}
// call client callback
if (
(rpc) && (getCallback())
&& (getCallback().getOnInvoke() is Function)
) {
getCallback().getOnInvoke().call(
getCallback().getScope(), rpc
);
}
// call request callback
if (
(rpc) && (rpc.getCallback())
&& (rpc.getCallback().getOnInvoke() is Function)
) {
rpc.getCallback().getOnInvoke().call(
rpc.getCallback().getScope(), rpc
);
}
}
protected function _onProgress(rpc:RpcVO)
{
//trace(this + "._onProgress()");
if (!rpc) {
return;
}
// call client callback
if (
(rpc) && (getCallback())
&& (getCallback().getOnProgress() is Function)
) {
getCallback().getOnProgress().call(
getCallback().getScope(), rpc
);
}
// call request callback
if (
(rpc) && (rpc.getCallback())
&& (rpc.getCallback().getOnProgress() is Function)
) {
rpc.getCallback().getOnProgress().call(
rpc.getCallback().getScope(), rpc
);
}
}
protected function _onResponse(rpc:RpcVO)
{
//trace(this + "._onResponse()");
if (!rpc) {
return;
}
// call client callback
if (
(rpc) && (getCallback())
&& (getCallback().getOnResponse() is Function)
) {
getCallback().getOnResponse().call(
getCallback().getScope(), rpc
);
}
// call request callback
if (
(rpc) && (rpc.getCallback())
&& (rpc.getCallback().getOnResponse() is Function)
) {
rpc.getCallback().getOnResponse().call(
rpc.getCallback().getScope(), rpc
);
}
}
protected function _onError(rpc:RpcVO)
{
//trace(this + "._onError()");
if (!rpc) {
return;
}
// call client callback
if (
(rpc) && (getCallback())
&& (getCallback().getOnError() is Function)
) {
getCallback().getOnError().call(
getCallback().getScope(), rpc
);
}
// call request callback
if (
(rpc) && (rpc.getCallback())
&& (rpc.getCallback().getOnError() is Function)
) {
rpc.getCallback().getOnError().call(
rpc.getCallback().getScope(), rpc
);
}
}
protected function _onResult(rpc:RpcVO)
{
//trace(this + "._onResult()");
if (!rpc) {
return;
}
// call client callback
if (
(rpc) && (getCallback())
&& (getCallback().getOnResult() is Function)
) {
getCallback().getOnResult().call(
getCallback().getScope(), rpc
);
}
// call request callback
if (
(rpc) && (rpc.getCallback())
&& (rpc.getCallback().getOnResult() is Function)
) {
rpc.getCallback().getOnResult().call(
rpc.getCallback().getScope(), rpc
);
}
}
}
}
package com.application.rpc
{
/**
* ...
* @author seb
*/
import com.application.rpc.RpcVO;
import com.application.rpc.ResponseVO;
public class Example
{
protected var _rpcClient:Client;
public function getRpcClient():Client
{
return _rpcClient;
}
public function run()
{
// rpc
_initRpcClient(
"http://cms.omg.com.local.basilicom.de/service/rpc",
"de.sony.adventskalendar2011."
);
// do something
_doSomething();
}
protected function _doSomething()
{
getRpcClient().invoke("Test.say", ["hello wörld"], {
"scope":this,
"response":function(rpc:RpcVO) {
trace(this + ".response() ... ");
var responseVO:ResponseVO = (rpc as RpcVO).getResponse();
if (responseVO.hasError()) {
throw new Error(responseVO.getErrorMessage());
return;
}
trace(" ... success! result=" + responseVO.getResult());
}
});
}
protected function _initRpcClient(
$url:String, $rpcMethodPrefix:String
)
{
var rpcClient:Client = Client.getInstance();
_rpcClient = rpcClient;
rpcClient.url = $url;
rpcClient.rpcMethodPrefix = $rpcMethodPrefix;
_initRpcDefaultCallbacks();
}
protected function _initRpcDefaultCallbacks()
{
var rpcClient = this.getRpcClient();
// global callbacks for the dirty stuff
rpcClient.getCallback().setScope(this);
// on invoke
rpcClient.getCallback().setOnInvoke(
function(rpc:RpcVO) {
trace(this + " global on invoke ... ");
trace("... rpc = " + (rpc as RpcVO).getRpcAsJson());
trace("... rpc url = "+ (rpc as RpcVO).getUrl());
}
);
// on progress
rpcClient.getCallback().setOnProgress(
function(rpc:RpcVO) {
// makes n sense in most ajax env's
trace(this + " global on progress ... ");
trace(" ... progress "
+ (rpc as RpcVO).getBytesLoaded()
+ " / " +(rpc as RpcVO).getBytesTotal()+" bytes"
+ " (" +(rpc as RpcVO).getPercentageLoaded() + " %)"
);
}
);
// on response
rpcClient.getCallback().setOnResponse(
function(rpc:RpcVO) {
trace(this + " global on response ... ");
trace(" ... response (json) = "
+ (rpc as RpcVO).getResponse().toJson()
);
}
);
// on result: everything is fine. (success!)
rpcClient.getCallback().setOnResult(
function(rpc:RpcVO) {
trace(this + " global on result ... ");
trace("... result (json) = "
+ (rpc as RpcVO).getResponse()
.getResultAsJson()
);
}
);
// on error: wtf? server dude. fix your shit!
rpcClient.getCallback().setOnError(
function(rpc:RpcVO) {
trace(this + " global on error ... ");
trace(" ... error (json) = "
+ (rpc as RpcVO).getResponse()
.getErrorAsJson()
);
}
);
}
}
}
package com.application.rpc
{
/**
* ...
* @author seb
*/
import com.adobe.serialization.json.JSON;
public dynamic class ResponseVO extends Object
{
public function ResponseVO(data:Object = null)
{
if (data is Object) {
for (var key in data) {
this[key] = data[key];
}
}
}
public function getResult():*
{
return this["result"];
}
public function getError():*
{
return this["error"];
}
public function hasError():Boolean
{
var error:* = this.getError();
if (error == null) {
return false;
}
if (error == undefined) {
return false;
}
return true;
}
public function toJson():String
{
var o:Object = {};
for (var key in this) {
o[key] = this[key];
}
return JSON.encode(o);
}
public function getResultAsJson():String
{
var value = this["result"];
return JSON.encode(value);
}
public function getErrorAsJson():String
{
var value = this["error"];
return JSON.encode(value);
}
public function getErrorMessage():String
{
var message:String = "";
var error:Object = this.getError();
if ((error == null)) {
return message;
}
if (error.hasOwnProperty("message")) {
message = error.message;
}
return message;
}
}
}
package com.application.rpc
{
/**
* ...
* @author seb
*/
import com.adobe.serialization.json.JSON;
public dynamic class RpcVO extends Object
{
public function RpcVO(data:Object=null)
{
if (data is Object) {
for (var key in data) {
this[key] = data[key];
}
}
}
public function getCallback():CallbackVO
{
return this["on"];
}
public function getResponse():ResponseVO {
var value:* = this["response"];
if (!(value is ResponseVO)) {
value = new ResponseVO(value);
}
this["response"] = value;
return value;
}
public function getRpc():Object
{
return this["rpc"];
}
public function getRpcAsJson():String
{
var rpc = this["rpc"];
var rpcText = JSON.encode(rpc);
return rpcText;
}
public function getUrl():String
{
return this["url"];
}
public function getBytesLoaded():Number
{
return this["bytesLoaded"];
}
public function getBytesTotal():Number
{
return this["bytesTotal"];
}
public function getPercentageLoaded():Number
{
var bytesLoaded:Number = 0 + getBytesLoaded();
var bytesTotal:Number = 0 + getBytesTotal();
var value = 0;
if (bytesTotal > 0) {
value = (bytesLoaded / bytesTotal);
value = value * 100;
value = Math.round(value);
}
return value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment