前回(memcachedサーバをPHPで作ってみた - yoshida_eth0の日記)はサーバ、今回はクライアント。
FlexでMemcachedサーバにソケット通信する奴を作って、それをJavaScriptと連携させた。
果たして実用性があるかは解らないけど、技術的には出来た、という話。
作った後に調べたら、同じような事をしてる人がなんと3人もいた。
JNEXTもJaxerも使った事ない。
どうやらクライアントに各々インストールしなきゃいけないものらしい。
FLASH + JavaScript で memcached と通信 - Hotdocs
http://www.hotdocs.jp/file/7139
Javascriptでmemcachedにソケット通信する - akihitoの日記
http://d.hatena.ne.jp/t-akihito/20071005/p1
jsmemcached-client - Project Hosting on Google Code
http://code.google.com/p/jsmemcached-client/
対応コマンド
GZip圧縮は非対応。
・set
・add
・replace
・append
・prepend
・incr
・decr
・get
・delete
・flush_all
・quit
・version
作ったもの
MemcachedClient.mxml
MemcachedStrを使って作った。
機能一覧。
MemcachedJS.mxml
MemcachedStrを使って作った。
JavaScriptで使えるように、ExternalInterface.addCallback()とかExternalInterface.call()とかやってる。
JavaScript側からコールバック関数を指定するタイミングが難しかったからflashvarsで指定出来るようにした。
MemcachedJS.html
SWFと連携するためのJavaScript。
ソース
jp/eth0/Memcached.as
package jp.eth0 { import flash.net.Socket; import flash.utils.ByteArray; import mx.utils.StringUtil; import flash.events.EventDispatcher; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.events.ProgressEvent; public class Memcached extends EventDispatcher { public static var RESPONSE:String = "response"; private var sock:Socket; public var lastRequest:Object; public var lastResponse:Object; // コンストラクタ public function Memcached() { sock = new Socket() // イベントリスナー登録 sock.addEventListener(Event.CLOSE, dispatchEvent); sock.addEventListener(Event.CONNECT, dispatchEvent); sock.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent); sock.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent); sock.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); } // 接続 public function connect(host:String, port:int = 11211):void { sock.connect(host, port); } // set public function doSet(key:String, value:ByteArray, flag:int = 0, expire:int = 0, mode:String = 'set'):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(mode + " " + key + " " + flag + " " + expire + " " + value.length + "\r\n"); ba.writeBytes(value); ba.writeUTFBytes("\r\n"); return write(ba); } // add public function doAdd(key:String, value:ByteArray, flag:int = 0, expire:int = 0):Boolean { return doSet(key, value, flag, expire, 'add'); } // replace public function doReplace(key:String, value:ByteArray, flag:int = 0, expire:int = 0):Boolean { return doSet(key, value, flag, expire, 'replace'); } // append public function doAppend(key:String, value:ByteArray, flag:int = 0, expire:int = 0):Boolean { return doSet(key, value, flag, expire, 'append'); } // prepend public function doPrepend(key:String, value:ByteArray, flag:int = 0, expire:int = 0):Boolean { return doSet(key, value, flag, expire, 'prepend'); } // incr public function doIncr(key:String, value:int, mode:String = 'incr'):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(mode + " " + key + " " + value + "\r\n"); return write(ba); } // decr public function doDecr(key:String, value:int):Boolean { return doIncr(key, value, 'decr'); } // get public function doGet(key:String):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes("get " + key + "\r\n"); return write(ba); } // delete public function doDelete(key:String, timeout:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes("delete " + key + " " + timeout + "\r\n"); return write(ba); } // flush public function doFlush(timeout:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes("flush_all " + timeout + "\r\n"); return write(ba); } // quit public function doQuit():Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes("quit\r\n"); return write(ba); } // version public function doVersion():Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes("version\r\n"); return write(ba); } // ソケットに書き込む private function write(value:ByteArray):Boolean { lastRequest = new Object(); if (isConnect()) { lastRequest['mode'] = StringUtil.trim(value.toString().split(' ')[0]); lastRequest['write'] = value; sock.writeBytes(value); sock.flush(); return true; } return false; } /* イベント */ // イベントハンドラ private function socketDataHandler(event:ProgressEvent):void { var response:ByteArray = new ByteArray(); sock.readBytes(response); lastResponse = Memcached.parseResponse(lastRequest['mode'], response); dispatchEvent(new Event(Memcached.RESPONSE)); } /* Util */ // 接続中か否か public function isConnect():Boolean { if (sock && sock.connected) { return true; } return false; } /* レスポンス解析 */ public static function parseResponse(mode:String, resp:ByteArray):Object { var result:Object = new Object(); result['mode'] = mode; result['response'] = resp; result['success'] = false; switch (mode) { case 'set': case 'add': case 'replace': case 'append': case 'prepend': Memcached.parseSet(result); break; case 'incr': case 'decr': Memcached.parseIncr(result); break; case 'get': Memcached.parseGet(result); break; case 'delete': Memcached.parseDelete(result); break; case 'flush_all': Memcached.parseFlushAll(result); break; case 'quit': result['result'] = true; break; case 'version': Memcached.parseVersion(result); break; } return result; } private static function parseSet(result:Object):void { if (result['response'].toString()=="STORED\r\n") { result['success'] = true; } } private static function parseIncr(result:Object):void { if (result['response'].toString()!="NOT_FOUND\r\n") { result['success'] = true; result['value'] = int(StringUtil.trim(result['response'])); } } private static function parseGet(result:Object):void { var info:String = result['response'].toString().split("\r\n", 1)[0]; var info_arr:Array = info.split(" "); if (info_arr.length==4 && info_arr[0]=="VALUE") { result['success'] = true; result['key'] = info_arr[1]; result['flag'] = int(info_arr[2]); result['length'] = int(info_arr[3]); result['value'] = new ByteArray(); result['value'].writeBytes(result['response'], uint(info.length + 2), uint(info_arr[3])); } } private static function parseDelete(result:Object):void { if (result['response'].toString()=="DELETED\r\n") { result['success'] = true; } } private static function parseFlushAll(result:Object):void { if (result['response'].toString()=="OK\r\n") { result['success'] = true; } } private static function parseVersion(result:Object):void { if (result['response'].toString().substr(0, 8)=="VERSION ") { result['success'] = true; result['value'] = StringUtil.trim(result['response'].toString().substr(8)); } } } }
jp/eth0/MemcachedStr.as
package jp.eth0 { import flash.utils.ByteArray; import jp.eth0.Memcached; import flash.events.Event; import flash.events.IOErrorEvent; import flash.events.SecurityErrorEvent; import flash.events.EventDispatcher; public class MemcachedStr extends EventDispatcher { public static var RESPONSE:String = "response"; private var mc:Memcached; public var lastRequest:Object; public var lastResponse:Object; /* コンストラクタ */ public function MemcachedStr() { mc = new Memcached(); // イベントリスナー登録 mc.addEventListener(Event.CLOSE, dispatchEvent); mc.addEventListener(Event.CONNECT, dispatchEvent); mc.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent); mc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent); mc.addEventListener(Memcached.RESPONSE, responseHandler); } /* ラッパー */ public function connect(host:String, port:int = 11211):void { mc.connect(host, port); } public function doSet(key:String, value:String, flag:int = 0, expire:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(value); var result:Boolean = mc.doSet(key, ba, flag, expire); lastRequest = mc.lastRequest; return result; } public function doAdd(key:String, value:String, flag:int = 0, expire:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(value); var result:Boolean = mc.doAdd(key, ba, flag, expire); lastRequest = mc.lastRequest; return result; } public function doReplace(key:String, value:String, flag:int = 0, expire:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(value); var result:Boolean = mc.doReplace(key, ba, flag, expire); lastRequest = mc.lastRequest; return result; } public function doAppend(key:String, value:String, flag:int = 0, expire:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(value); var result:Boolean = mc.doAppend(key, ba, flag, expire); lastRequest = mc.lastRequest; return result; } public function doPrepend(key:String, value:String, flag:int = 0, expire:int = 0):Boolean { var ba:ByteArray = new ByteArray(); ba.writeUTFBytes(value); var result:Boolean = mc.doPrepend(key, ba, flag, expire); lastRequest = mc.lastRequest; return result; } public function doIncr(key:String, value:int):Boolean { var result:Boolean = mc.doIncr(key, value); lastRequest = mc.lastRequest; return result; } public function doDecr(key:String, value:int):Boolean { var result:Boolean = mc.doDecr(key, value); lastRequest = mc.lastRequest; return result; } public function doGet(key:String):Boolean { var result:Boolean = mc.doGet(key); lastRequest = mc.lastRequest; return result; } public function doDelete(key:String, timeout:int):Boolean { var result:Boolean = mc.doDelete(key, timeout); lastRequest = mc.lastRequest; return result; } public function doFlush(timeout:int):Boolean { var result:Boolean = mc.doFlush(timeout); lastRequest = mc.lastRequest; return result; } public function doQuit():Boolean { var result:Boolean = mc.doQuit(); lastRequest = mc.lastRequest; return result; } public function doVersion():Boolean { var result:Boolean = mc.doVersion(); lastRequest = mc.lastRequest; return result; } public function isConnect():Boolean { return mc.isConnect(); } /* イベントハンドラ */ public function responseHandler(event:Event):void { lastResponse = mc.lastResponse; for (var key:String in lastResponse) { if (mc.lastResponse[key] is ByteArray) { lastResponse[key] = lastResponse[key].toString(); } } dispatchEvent(new Event(MemcachedStr.RESPONSE)); } } }
MemcachedClient.mxml
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()"> <mx:Script> <![CDATA[ import flash.events.*; import mx.controls.Alert; import mx.utils.ObjectUtil; import jp.eth0.MemcachedStr; /* var */ [Bindable] private var mc:MemcachedStr; /* init */ private function init():void{ mc = new MemcachedStr(); mc.addEventListener(Event.CLOSE, closeHandler); mc.addEventListener(Event.CONNECT, connectHandler); mc.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); mc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); mc.addEventListener(MemcachedStr.RESPONSE, responseHandler); } /* イベントハンドラ */ public function closeHandler(event:Event):void { Alert.show("close"); } public function connectHandler(event:Event):void { Alert.show("connect"); } public function ioErrorHandler(event:IOErrorEvent):void { Alert.show("io_error"); } public function securityErrorHandler(event:SecurityErrorEvent):void { Alert.show("security_error"); } public function responseHandler(event:Event):void { Alert.show(ObjectUtil.toString(mc.lastResponse)); } ]]> </mx:Script> <!-- connect --> <mx:Form> <mx:FormHeading label="connect"/> <mx:FormItem label="host"> <mx:TextInput id="host" width="200" text="localhost"/> </mx:FormItem> <mx:FormItem label="port"> <mx:TextInput id="port" width="200" text="11211"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.connect(host.text, int(port.text))}"/> </mx:FormItem> </mx:Form> <!-- set --> <mx:Form> <mx:FormHeading label="set"/> <mx:FormItem label="key"> <mx:TextInput id="set_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="set_value" width="200"/> </mx:FormItem> <mx:FormItem label="flag"> <mx:TextInput id="set_flag" width="200"/> </mx:FormItem> <mx:FormItem label="expire"> <mx:TextInput id="set_expire" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doSet(set_key.text, set_value.text, int(set_flag.text), int(set_expire.text))}"/> </mx:FormItem> </mx:Form> <!-- add --> <mx:Form> <mx:FormHeading label="add"/> <mx:FormItem label="key"> <mx:TextInput id="add_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="add_value" width="200"/> </mx:FormItem> <mx:FormItem label="flag"> <mx:TextInput id="add_flag" width="200"/> </mx:FormItem> <mx:FormItem label="expire"> <mx:TextInput id="add_expire" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doAdd(add_key.text, add_value.text, int(add_flag.text), int(add_expire.text))}"/> </mx:FormItem> </mx:Form> <!-- replace --> <mx:Form> <mx:FormHeading label="replace"/> <mx:FormItem label="key"> <mx:TextInput id="replace_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="replace_value" width="200"/> </mx:FormItem> <mx:FormItem label="flag"> <mx:TextInput id="replace_flag" width="200"/> </mx:FormItem> <mx:FormItem label="expire"> <mx:TextInput id="replace_expire" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doReplace(replace_key.text, replace_value.text, int(replace_flag.text), int(replace_expire.text))}"/> </mx:FormItem> </mx:Form> <!-- append --> <mx:Form> <mx:FormHeading label="append"/> <mx:FormItem label="key"> <mx:TextInput id="append_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="append_value" width="200"/> </mx:FormItem> <mx:FormItem label="flag"> <mx:TextInput id="append_flag" width="200"/> </mx:FormItem> <mx:FormItem label="expire"> <mx:TextInput id="append_expire" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doAppend(append_key.text, append_value.text, int(append_flag.text), int(append_expire.text))}"/> </mx:FormItem> </mx:Form> <!-- prepend --> <mx:Form> <mx:FormHeading label="prepend"/> <mx:FormItem label="key"> <mx:TextInput id="prepend_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="prepend_value" width="200"/> </mx:FormItem> <mx:FormItem label="flag"> <mx:TextInput id="prepend_flag" width="200"/> </mx:FormItem> <mx:FormItem label="expire"> <mx:TextInput id="prepend_expire" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doPrepend(prepend_key.text, prepend_value.text, int(prepend_flag.text), int(prepend_expire.text))}"/> </mx:FormItem> </mx:Form> <!-- incr --> <mx:Form> <mx:FormHeading label="incr"/> <mx:FormItem label="key"> <mx:TextInput id="incr_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="incr_value" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doIncr(incr_key.text, int(incr_value.text))}"/> </mx:FormItem> </mx:Form> <!-- decr --> <mx:Form> <mx:FormHeading label="decr"/> <mx:FormItem label="key"> <mx:TextInput id="decr_key" width="200"/> </mx:FormItem> <mx:FormItem label="value"> <mx:TextInput id="decr_value" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doDecr(decr_key.text, int(decr_value.text))}"/> </mx:FormItem> </mx:Form> <!-- get --> <mx:Form> <mx:FormHeading label="get"/> <mx:FormItem label="key"> <mx:TextInput id="get_key" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doGet(get_key.text)}"/> </mx:FormItem> </mx:Form> <!-- delete --> <mx:Form> <mx:FormHeading label="delete"/> <mx:FormItem label="key"> <mx:TextInput id="delete_key" width="200"/> </mx:FormItem> <mx:FormItem label="timeout"> <mx:TextInput id="delete_timeout" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doDelete(delete_key.text, int(delete_timeout.text))}"/> </mx:FormItem> </mx:Form> <!-- flush --> <mx:Form> <mx:FormHeading label="flush"/> <mx:FormItem label="timeout"> <mx:TextInput id="flush_timeout" width="200"/> </mx:FormItem> <mx:FormItem> <mx:Button label="submit" click="{mc.doFlush(int(flush_timeout.text))}"/> </mx:FormItem> </mx:Form> <!-- quit --> <mx:Form> <mx:FormHeading label="quit"/> <mx:FormItem> <mx:Button label="submit" click="{mc.doQuit()}"/> </mx:FormItem> </mx:Form> <!-- version --> <mx:Form> <mx:FormHeading label="version"/> <mx:FormItem> <mx:Button label="submit" click="{mc.doVersion()}"/> </mx:FormItem> </mx:Form> <!-- isConnect --> <mx:Form> <mx:FormHeading label="isConnect"/> <mx:FormItem> <mx:Button label="submit" click="{Alert.show(mc.isConnect().toString())}"/> </mx:FormItem> </mx:Form> </mx:Application>
MemcachedJS.mxml
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()"> <mx:Script> <![CDATA[ import flash.events.*; import mx.controls.Alert; import mx.utils.ObjectUtil; import jp.eth0.MemcachedStr; import flash.system.Security; /* var */ private var mc:MemcachedStr; private var handler:Object = { 'create':null, 'close':null, 'connect':null, 'io_error':null, 'security_error':null, 'response':null }; /* init */ private function init():void{ mc = new MemcachedStr(); // JavaScriptからのアクセスを許可 Security.allowDomain('*'); // JavaScriptから呼び出す関数を登録 ExternalInterface.addCallback('setHandler', setHandler); ExternalInterface.addCallback('connect', mc.connect); ExternalInterface.addCallback('doSet', mc.doSet); ExternalInterface.addCallback('doAdd', mc.doAdd); ExternalInterface.addCallback('doReplace', mc.doReplace); ExternalInterface.addCallback('doAppend', mc.doAppend); ExternalInterface.addCallback('doPrepend', mc.doPrepend); ExternalInterface.addCallback('doIncr', mc.doIncr); ExternalInterface.addCallback('doDecr', mc.doDecr); ExternalInterface.addCallback('doGet', mc.doGet); ExternalInterface.addCallback('doDelete', mc.doDelete); ExternalInterface.addCallback('doFlush', mc.doFlush); ExternalInterface.addCallback('doQuit', mc.doQuit); ExternalInterface.addCallback('doVersion', mc.doVersion); ExternalInterface.addCallback('isConnect', mc.isConnect); // イベントリスナー登録 mc.addEventListener(Event.CLOSE, closeHandler); mc.addEventListener(Event.CONNECT, connectHandler); mc.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); mc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); mc.addEventListener(MemcachedStr.RESPONSE, responseHandler); // FlashVarsからハンドラ登録 for (var event:String in handler) { if (Application.application.parameters[event]!=null) { handler[event] = Application.application.parameters[event]; } } // Createハンドラが設定されていたら実行 if (handler['create']) { ExternalInterface.call(handler['create']); } } /* イベントリスナー設定 */ public function setHandler(event:String, jsfunc:String):Boolean { Alert.show("setHandler "+event+" "+jsfunc); if (handler.hasOwnProperty(event)) { handler[event] = jsfunc; return true; } return false; } /* イベントハンドラ */ public function closeHandler(event:Event):void { Alert.show("close"); if (handler['close']) { ExternalInterface.call(handler['close']); } } public function connectHandler(event:Event):void { Alert.show("connect"); if (handler['connect']) { ExternalInterface.call(handler['connect']); } } public function ioErrorHandler(event:IOErrorEvent):void { Alert.show("io_error"); if (handler['io_error']) { ExternalInterface.call(handler['io_error']); } } public function securityErrorHandler(event:SecurityErrorEvent):void { Alert.show("security_error"); if (handler['security_error']) { ExternalInterface.call(handler['security_error']); } } public function responseHandler(event:Event):void { Alert.show(ObjectUtil.toString(mc.lastResponse)); if (handler['response']) { ExternalInterface.call(handler['response'], mc.lastResponse); } } ]]> </mx:Script> </mx:Application>
MemcachedJS.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <title>Memcached Javascript</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript"> swfobject.embedSWF("MemcachedJS.swf", "MemcachedJS", "300", "150", "9.0.0", null, {'create':'setHandler'}, null, {'allowScriptAccess':'always'}); function thisMovie(movieName) { if (navigator.appName.indexOf("Microsoft") != -1) { return window[movieName]; } else { return document[movieName]; } } function setHandler() { thisMovie('MemcachedJS').setHandler('close', 'closeHandler'); thisMovie('MemcachedJS').setHandler('connect', 'connectHandler'); thisMovie('MemcachedJS').setHandler('io_error', 'ioErrorHandler'); thisMovie('MemcachedJS').setHandler('security_error', 'securityErrorHandler'); thisMovie('MemcachedJS').setHandler('response', 'responseHandler'); } function closeHandler() { showLog("close"); } function connectHandler() { showLog("connect"); } function ioErrorHandler() { showLog("io_error"); } function securityErrorHandler() { showLog("security_error"); } function responseHandler(resp) { showLog(resp) } function showLog(log) { if ("console" in window) { console.log(log); } else { var message = ''; if (typeof(log)=='object') { for (var i in log) { if (typeof(log[i])=='string') { message += i + ' = "' + log[i] + '"' + "\n"; } else { message += i + ' = ' + log[i] + "\n"; } } } else { message = log; } alert(message); } } </script> </head> <body> <div id="MemcachedJS"> <h1>Alternative content</h1> <p><a href="http://www.adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p> </div> <hr /> <!-- connect --> <form> connect<br /> host : <input type="text" id="host" value="localhost" /><br /> port : <input type="text" id="port" value="11211" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').connect(host.value, parseInt(port.value));"> </form> <hr /> <!-- set --> <form> set<br /> key : <input type="text" id="set_key" value="" /><br /> value : <input type="text" id="set_value" value="" /><br /> flag : <input type="text" id="set_flag" value="0" /><br /> exipire : <input type="text" id="set_expire" value="0" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doSet(set_key.value, set_value.value, parseInt(set_flag.value), parseInt(set_expire.value));"> </form> <hr /> <!-- add --> <form> add<br /> key : <input type="text" id="add_key" value="" /><br /> value : <input type="text" id="add_value" value="" /><br /> flag : <input type="text" id="add_flag" value="0" /><br /> exipire : <input type="text" id="add_expire" value="0" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doAdd(add_key.value, add_value.value, parseInt(add_flag.value), parseInt(add_expire.value));"> </form> <hr /> <!-- replace --> <form> replace<br /> key : <input type="text" id="replace_key" value="" /><br /> value : <input type="text" id="replace_value" value="" /><br /> flag : <input type="text" id="replace_flag" value="0" /><br /> exipire : <input type="text" id="replace_expire" value="0" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doReplace(replace_key.value, replace_value.value, parseInt(replace_flag.value), parseInt(replace_expire.value));"> </form> <hr /> <!-- append --> <form> append<br /> key : <input type="text" id="append_key" value="" /><br /> value : <input type="text" id="append_value" value="" /><br /> flag : <input type="text" id="append_flag" value="0" /><br /> exipire : <input type="text" id="append_expire" value="0" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doAppend(append_key.value, append_value.value, parseInt(append_flag.value), parseInt(append_expire.value));"> </form> <hr /> <!-- prepend --> <form> prepend<br /> key : <input type="text" id="prepend_key" value="" /><br /> value : <input type="text" id="prepend_value" value="" /><br /> flag : <input type="text" id="prepend_flag" value="0" /><br /> exipire : <input type="text" id="prepend_expire" value="0" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doPrepend(prepend_key.value, prepend_value.value, parseInt(prepend_flag.value), parseInt(prepend_expire.value));"> </form> <hr /> <!-- incr --> <form> incr<br /> key : <input type="text" id="incr_key" value="" /><br /> value : <input type="text" id="incr_value" value="" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doIncr(incr_key.value, parseInt(incr_value.value));"> </form> <hr /> <!-- decr --> <form> decr<br /> key : <input type="text" id="decr_key" value="" /><br /> value : <input type="text" id="decr_value" value="" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doDecr(decr_key.value, parseInt(decr_value.value));"> </form> <hr /> <!-- get --> <form> get<br /> key : <input type="text" id="get_key" value="" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doGet(get_key.value);"> </form> <hr /> <!-- delete --> <form> delete<br /> key : <input type="text" id="delete_key" value="" /><br /> timeout : <input type="text" id="delete_timeout" value="" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doDelete(delete_key.value, parseInt(delete_timeout.value));"> </form> <hr /> <!-- flush --> <form> flush<br /> timeout : <input type="text" id="flush_timeout" value="" /><br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doFlush(parseInt(flush_timeout.value));"> </form> <hr /> <!-- quit --> <form> quit<br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doQuit();"> </form> <hr /> <!-- version --> <form> version<br /> <input type="button" value="submit" onclick="thisMovie('MemcachedJS').doVersion();"> </form> <hr /> <!-- isConnect --> <form> isConnect<br /> <input type="button" value="submit" onclick="showLog(thisMovie('MemcachedJS').isConnect());"> </form> </body> </html>
追記 (2009-12-31 04:33:47)
1つ目のリンクの、Flash+JavaScriptでMemcachedに通信のプレゼンしてる方のはてな記事みつけた。
タイトルがアレだから見つからなかったっぽい。
二番煎じの存在アピールにトラックバック送信させて頂いたり頂かなかったり。
ニコニコ大百科とか作ってる方らしい。
やっぱりはてなはすごい人いっぱいいるなぁ。
もっと早く始めればよかった。
グニャラは大変なFlashを描いていきました - グニャラくんのグニャグニャ備忘録@はてな
http://d.hatena.ne.jp/tasukuchan/20080127/flash_javascript_perl
グニャラくん ★とは (グニャラクンとは) - ニコニコ大百科
http://dic.nicovideo.jp/a/%E3%82%B0%E3%83%8B%E3%83%A3%E3%83%A9%E3%81%8F%E3%82%93%20%E2%98%85