diff --git a/samples/Samples.Echo/Samples.Echo.csproj b/samples/Samples.Echo/Samples.Echo.csproj new file mode 100644 index 0000000..d156e7f --- /dev/null +++ b/samples/Samples.Echo/Samples.Echo.csproj @@ -0,0 +1,78 @@ + + + + + Debug + {F706A854-E68F-4AE2-AE2A-714110651EED} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + bin + v4.5 + full + true + 1.4 + true + + + + + + + + + + + + + + + + + + + + web.config + + + web.config + + + + 12.0 + + + Samples.Echo + + + + + + + + True + True + 23485 + / + http://localhost:23485/ + False + False + + + False + + + + + + false + true + + + true + false + + + xcopy /d "$(SolutionDir)\src\stormancer-sdk-js\stormancer.js" ".." + + + \ No newline at end of file diff --git a/samples/Samples.Echo/Scripts/msgPack.ts b/samples/Samples.Echo/Scripts/msgPack.ts new file mode 100644 index 0000000..e3a42a4 --- /dev/null +++ b/samples/Samples.Echo/Scripts/msgPack.ts @@ -0,0 +1,726 @@ +/// + +/*!{id:msgpack.js,ver:1.05,license:"MIT",author:"uupaa.js@gmail.com"}*/ + +// === msgpack === +// MessagePack -> http://msgpack.sourceforge.net/ + +declare function vblen(b); +declare function vbstr(b); + +this.msgpack || (function (globalScope) { + + globalScope.msgpack = { + pack: msgpackpack, // msgpack.pack(data:Mix, + // toString:Boolean = false):ByteArray/ByteString/false + // [1][mix to String] msgpack.pack({}, true) -> "..." + // [2][mix to ByteArray] msgpack.pack({}) -> [...] + unpack: msgpackunpack, // msgpack.unpack(data:BinaryString/ByteArray):Mix + // [1][String to mix] msgpack.unpack("...") -> {} + // [2][ByteArray to mix] msgpack.unpack([...]) -> {} + worker: "msgpack.js", // msgpack.worker - WebWorkers script filename + upload: msgpackupload, // msgpack.upload(url:String, option:Hash, callback:Function) + download: msgpackdownload // msgpack.download(url:String, option:Hash, callback:Function) + }; + + var _ie = /MSIE/.test(navigator.userAgent), + _bin2num = {}, // BinaryStringToNumber { "\00": 0, ... "\ff": 255 } + _num2bin = {}, // NumberToBinaryString { 0: "\00", ... 255: "\ff" } + _num2b64 = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz0123456789+/").split(""), + _buf = [], // decode buffer + _idx = 0, // decode buffer[index] + _error = 0, // msgpack.pack() error code. 1 = CYCLIC_REFERENCE_ERROR + _isArray = Array.isArray || (function (mix) { + return Object.prototype.toString.call(mix) === "[object Array]"; + }), + _toString = String.fromCharCode, // CharCode/ByteArray to String + _MAX_DEPTH = 512; + + // for WebWorkers Code Block + (self).importScripts && (onmessage = function (event) { + if (event.data.method === "pack") { + (window).postMessage(base64encode(msgpackpack(event.data.data))); + } else { + (window).postMessage(msgpackunpack(event.data.data)); + } + }); + + // msgpack.pack + function msgpackpack(data, // @param Mix: + settings?) { // @param Boolean(= false): + // @return ByteArray/BinaryString/false: + // false is error return + // [1][mix to String] msgpack.pack({}, true) -> "..." + // [2][mix to ByteArray] msgpack.pack({}) -> [...] + var toString = false; + _error = 0; + if (!settings) { + settings = {byteProperties:[]}; + } + var byteArray = encode([], data, 0,settings); + + return _error ? false + : toString ? byteArrayToByteString(byteArray) + : byteArray; + } + + // msgpack.unpack + function msgpackunpack(data, settings?) { // @param BinaryString/ByteArray: + // @return Mix/undefined: + // undefined is error return + // [1][String to mix] msgpack.unpack("...") -> {} + // [2][ByteArray to mix] msgpack.unpack([...]) -> {} + if (!settings) { + settings = { byteProperties: [] }; + } + _buf = typeof data === "string" ? toByteArray(data) : data; + _idx = -1; + return decode(settings); // mix or undefined + } + + // inner - encoder + function encode(rv, // @param ByteArray: result + mix, // @param Mix: source data + depth, // @param Number: depth + settings?, + bytesArray? + ) { + var size, i, iz, c, pos, // for UTF8.encode, Array.encode, Hash.encode + high, low, sign, exp, frac; // for IEEE754 + + if (mix == null) { // null or undefined -> 0xc0 ( null ) + rv.push(0xc0); + } else if (mix === false) { // false -> 0xc2 ( false ) + rv.push(0xc2); + } else if (mix === true) { // true -> 0xc3 ( true ) + rv.push(0xc3); + } else { + switch (typeof mix) { + case "number": + if (mix !== mix) { // isNaN + rv.push(0xcb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); // quiet NaN + } else if (mix === Infinity) { + rv.push(0xcb, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // positive infinity + } else if (Math.floor(mix) === mix) { // int or uint + if (mix < 0) { + // int + if (mix >= -32) { // negative fixnum + rv.push(0xe0 + mix + 32); + } else if (mix > -0x80) { + rv.push(0xd0, mix + 0x100); + } else if (mix > -0x8000) { + mix += 0x10000; + rv.push(0xd1, mix >> 8, mix & 0xff); + } else if (mix > -0x80000000) { + mix += 0x100000000; + rv.push(0xd2, mix >>> 24, (mix >> 16) & 0xff, + (mix >> 8) & 0xff, mix & 0xff); + } else { + high = Math.floor(mix / 0x100000000); + low = mix & 0xffffffff; + rv.push(0xd3, (high >> 24) & 0xff, (high >> 16) & 0xff, + (high >> 8) & 0xff, high & 0xff, + (low >> 24) & 0xff, (low >> 16) & 0xff, + (low >> 8) & 0xff, low & 0xff); + } + } else { + // uint + if (mix < 0x80) { + rv.push(mix); // positive fixnum + } else if (mix < 0x100) { // uint 8 + rv.push(0xcc, mix); + } else if (mix < 0x10000) { // uint 16 + rv.push(0xcd, mix >> 8, mix & 0xff); + } else if (mix < 0x100000000) { // uint 32 + rv.push(0xce, mix >>> 24, (mix >> 16) & 0xff, + (mix >> 8) & 0xff, mix & 0xff); + } else { + high = Math.floor(mix / 0x100000000); + low = mix & 0xffffffff; + rv.push(0xcf, (high >> 24) & 0xff, (high >> 16) & 0xff, + (high >> 8) & 0xff, high & 0xff, + (low >> 24) & 0xff, (low >> 16) & 0xff, + (low >> 8) & 0xff, low & 0xff); + } + } + } else { // double + // THX!! @edvakf + // http://javascript.g.hatena.ne.jp/edvakf/20101128/1291000731 + sign = mix < 0; + sign && (mix *= -1); + + // add offset 1023 to ensure positive + // 0.6931471805599453 = Math.LN2; + exp = ((Math.log(mix) / 0.6931471805599453) + 1023) | 0; + + // shift 52 - (exp - 1023) bits to make integer part exactly 53 bits, + // then throw away trash less than decimal point + frac = mix * Math.pow(2, 52 + 1023 - exp); + + // S+-Exp(11)--++-----------------Fraction(52bits)-----------------------+ + // || || | + // v+----------++--------------------------------------------------------+ + // 00000000|00000000|00000000|00000000|00000000|00000000|00000000|00000000 + // 6 5 55 4 4 3 2 1 8 0 + // 3 6 21 8 0 2 4 6 + // + // +----------high(32bits)-----------+ +----------low(32bits)------------+ + // | | | | + // +---------------------------------+ +---------------------------------+ + // 3 2 21 1 8 0 + // 1 4 09 6 + low = frac & 0xffffffff; + sign && (exp |= 0x800); + high = ((frac / 0x100000000) & 0xfffff) | (exp << 20); + + rv.push(0xcb, (high >> 24) & 0xff, (high >> 16) & 0xff, + (high >> 8) & 0xff, high & 0xff, + (low >> 24) & 0xff, (low >> 16) & 0xff, + (low >> 8) & 0xff, low & 0xff); + } + break; + case "string": + // http://d.hatena.ne.jp/uupaa/20101128 + iz = mix.length; + pos = rv.length; // keep rewrite position + + rv.push(0); // placeholder + + // utf8.encode + for (i = 0; i < iz; ++i) { + c = mix.charCodeAt(i); + if (c < 0x80) { // ASCII(0x00 ~ 0x7f) + rv.push(c & 0x7f); + } else if (c < 0x0800) { + rv.push(((c >>> 6) & 0x1f) | 0xc0, (c & 0x3f) | 0x80); + } else if (c < 0x10000) { + rv.push(((c >>> 12) & 0x0f) | 0xe0, + ((c >>> 6) & 0x3f) | 0x80, (c & 0x3f) | 0x80); + } + } + size = rv.length - pos - 1; + + if (size < 32) { + rv[pos] = 0xa0 + size; // rewrite + } else if (size < 0x10000) { // 16 + rv.splice(pos, 1, 0xda, size >> 8, size & 0xff); + } else if (size < 0x100000000) { // 32 + rv.splice(pos, 1, 0xdb, + size >>> 24, (size >> 16) & 0xff, + (size >> 8) & 0xff, size & 0xff); + } + break; + default: // array or hash + if (++depth >= _MAX_DEPTH) { + _error = 1; // CYCLIC_REFERENCE_ERROR + return rv = []; // clear + } + if (_isArray(mix)) { + if (bytesArray) { + size = mix.length; + if (size < 32) { + rv.push(0xa0 + size); + } else if (size < 0x10000) { // 16 + rv.push(0xda, size >> 8, size & 0xff); + } else if (size < 0x100000000) { // 32 + rv.push(0xdb, size >>> 24, (size >> 16) & 0xff, + (size >> 8) & 0xff, size & 0xff); + } + for (i = 0; i < size; ++i) { + rv.push(mix[i]); + } + } + else { + size = mix.length; + if (size < 16) { + rv.push(0x90 + size); + } else if (size < 0x10000) { // 16 + rv.push(0xdc, size >> 8, size & 0xff); + } else if (size < 0x100000000) { // 32 + rv.push(0xdd, size >>> 24, (size >> 16) & 0xff, + (size >> 8) & 0xff, size & 0xff); + } + for (i = 0; i < size; ++i) { + encode(rv, mix[i], depth,settings); + } + } + } else { // hash + // http://d.hatena.ne.jp/uupaa/20101129 + pos = rv.length; // keep rewrite position + rv.push(0); // placeholder + size = 0; + for (i in mix) { + if (typeof (mix[i]) == "function") { + continue; + } + ++size; + encode(rv, i, depth); + if ($.inArray(i,settings.byteProperties)!=-1) { + encode(rv, mix[i], depth,settings,true); + } + else { + encode(rv, mix[i], depth, settings,false); + } + } + if (size < 16) { + rv[pos] = 0x80 + size; // rewrite + } else if (size < 0x10000) { // 16 + rv.splice(pos, 1, 0xde, size >> 8, size & 0xff); + } else if (size < 0x100000000) { // 32 + rv.splice(pos, 1, 0xdf, + size >>> 24, (size >> 16) & 0xff, + (size >> 8) & 0xff, size & 0xff); + } + } + } + } + return rv; + } + + // inner - decoder + function decode(settings,rawAsArray?) { // @return Mix: + var size, i, iz, c, num = 0, + sign, exp, frac, ary, hash, + buf = _buf, type = buf[++_idx],key; + + if (type >= 0xe0) { // Negative FixNum (111x xxxx) (-32 ~ -1) + return type - 0x100; + } + if (type < 0xc0) { + if (type < 0x80) { // Positive FixNum (0xxx xxxx) (0 ~ 127) + return type; + } + if (type < 0x90) { // FixMap (1000 xxxx) + num = type - 0x80; + type = 0x80; + } else if (type < 0xa0) { // FixArray (1001 xxxx) + num = type - 0x90; + type = 0x90; + } else { // if (type < 0xc0) { // FixRaw (101x xxxx) + num = type - 0xa0; + type = 0xa0; + } + } + switch (type) { + case 0xc0: return null; + case 0xc2: return false; + case 0xc3: return true; + case 0xca: // float + num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + sign = num & 0x80000000; // 1bit + exp = (num >> 23) & 0xff; // 8bits + frac = num & 0x7fffff; // 23bits + if (!num || num === 0x80000000) { // 0.0 or -0.0 + return 0; + } + if (exp === 0xff) { // NaN or Infinity + return frac ? NaN : Infinity; + } + return (sign ? -1 : 1) * + (frac | 0x800000) * Math.pow(2, exp - 127 - 23); // 127: bias + case 0xcb: // double + num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + sign = num & 0x80000000; // 1bit + exp = (num >> 20) & 0x7ff; // 11bits + frac = num & 0xfffff; // 52bits - 32bits (high word) + if (!num || num === 0x80000000) { // 0.0 or -0.0 + _idx += 4; + return 0; + } + if (exp === 0x7ff) { // NaN or Infinity + _idx += 4; + return frac ? NaN : Infinity; + } + num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + return (sign ? -1 : 1) * + ((frac | 0x100000) * Math.pow(2, exp - 1023 - 20) // 1023: bias + + num * Math.pow(2, exp - 1023 - 52)); + // 0xcf: uint64, 0xce: uint32, 0xcd: uint16 + case 0xcf: num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + return num * 0x100000000 + + buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + case 0xce: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xcd: num += buf[++_idx] << 8; + case 0xcc: return num + buf[++_idx]; + // 0xd3: int64, 0xd2: int32, 0xd1: int16, 0xd0: int8 + case 0xd3: num = buf[++_idx]; + if (num & 0x80) { // sign -> avoid overflow + return ((num ^ 0xff) * 0x100000000000000 + + (buf[++_idx] ^ 0xff) * 0x1000000000000 + + (buf[++_idx] ^ 0xff) * 0x10000000000 + + (buf[++_idx] ^ 0xff) * 0x100000000 + + (buf[++_idx] ^ 0xff) * 0x1000000 + + (buf[++_idx] ^ 0xff) * 0x10000 + + (buf[++_idx] ^ 0xff) * 0x100 + + (buf[++_idx] ^ 0xff) + 1) * -1; + } + return num * 0x100000000000000 + + buf[++_idx] * 0x1000000000000 + + buf[++_idx] * 0x10000000000 + + buf[++_idx] * 0x100000000 + + buf[++_idx] * 0x1000000 + + buf[++_idx] * 0x10000 + + buf[++_idx] * 0x100 + + buf[++_idx]; + case 0xd2: num = buf[++_idx] * 0x1000000 + (buf[++_idx] << 16) + + (buf[++_idx] << 8) + buf[++_idx]; + return num < 0x80000000 ? num : num - 0x100000000; // 0x80000000 * 2 + case 0xd1: num = (buf[++_idx] << 8) + buf[++_idx]; + return num < 0x8000 ? num : num - 0x10000; // 0x8000 * 2 + case 0xd0: num = buf[++_idx]; + return num < 0x80 ? num : num - 0x100; // 0x80 * 2 + // 0xdb: raw32, 0xda: raw16, 0xa0: raw ( string ) (or Array if rawAsArray == true) + case 0xdb: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xda: num += (buf[++_idx] << 8) + buf[++_idx]; + case 0xa0: + if (rawAsArray) { + for (ary = [], i = _idx, iz = i + num; i < iz;) { + ary.push(buf[++i]); + } + _idx = i; + return ary; + } + else {// utf8.decode + + for (ary = [], i = _idx, iz = i + num; i < iz;) { + c = buf[++i]; // lead byte + ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f) + c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) : + ((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6 + | (buf[++i] & 0x3f))); + } + _idx = i; + return ary.length < 10240 ? _toString.apply(null, ary) + : byteArrayToByteString(ary); + } + // 0xdf: map32, 0xde: map16, 0x80: map + case 0xdf: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xde: num += (buf[++_idx] << 8) + buf[++_idx]; + case 0x80: hash = {}; + while (num--) { + // make key/value pair + size = buf[++_idx] - 0xa0; + + for (ary = [], i = _idx, iz = i + size; i < iz;) { + c = buf[++i]; // lead byte + ary.push(c < 0x80 ? c : // ASCII(0x00 ~ 0x7f) + c < 0xe0 ? ((c & 0x1f) << 6 | (buf[++i] & 0x3f)) : + ((c & 0x0f) << 12 | (buf[++i] & 0x3f) << 6 + | (buf[++i] & 0x3f))); + } + _idx = i; + key = _toString.apply(null, ary) + if ($.inArray(key, settings.byteProperties) != -1) { + hash[key] = decode(settings,true); + } + else { + + hash[key] = decode(settings); + } + } + return hash; + // 0xdd: array32, 0xdc: array16, 0x90: array + case 0xdd: num += buf[++_idx] * 0x1000000 + (buf[++_idx] << 16); + case 0xdc: num += (buf[++_idx] << 8) + buf[++_idx]; + case 0x90: ary = []; + while (num--) { + ary.push(decode(settings,rawAsArray)); + } + return ary; + } + return; + } + + // inner - byteArray To ByteString + function byteArrayToByteString(byteArray) { // @param ByteArray + // @return String + // http://d.hatena.ne.jp/uupaa/20101128 + try { + return _toString.apply(this, byteArray); // toString + } catch (err) { + ; // avoid "Maximum call stack size exceeded" + } + var rv = [], i = 0, iz = byteArray.length, num2bin = _num2bin; + + for (; i < iz; ++i) { + rv[i] = num2bin[byteArray[i]]; + } + return rv.join(""); + } + + // msgpack.download - load from server + function msgpackdownload(url, // @param String: + option, // @param Hash: { worker, timeout, before, after } + // option.worker - Boolean(= false): true is use WebWorkers + // option.timeout - Number(= 10): timeout sec + // option.before - Function: before(xhr, option) + // option.after - Function: after(xhr, option, { status, ok }) + callback) { // @param Function: callback(data, option, { status, ok }) + // data - Mix/null: + // option - Hash: + // status - Number: HTTP status code + // ok - Boolean: + option.method = "GET"; + option.binary = true; + ajax(url, option, callback); + } + + // msgpack.upload - save to server + function msgpackupload(url, // @param String: + option, // @param Hash: { data, worker, timeout, before, after } + // option.data - Mix: + // option.worker - Boolean(= false): true is use WebWorkers + // option.timeout - Number(= 10): timeout sec + // option.before - Function: before(xhr, option) + // option.after - Function: after(xhr, option, { status, ok }) + callback) { // @param Function: callback(data, option, { status, ok }) + // data - String: responseText + // option - Hash: + // status - Number: HTTP status code + // ok - Boolean: + option.method = "PUT"; + option.binary = true; + + if (option.worker && globalScope.Worker) { + var worker = new Worker(globalScope.msgpack.worker); + + worker.onmessage = function (event) { + option.data = event.data; + ajax(url, option, callback); + }; + worker.postMessage({ method: "pack", data: option.data }); + } else { + // pack and base64 encode + option.data = base64encode(msgpackpack(option.data)); + ajax(url, option, callback); + } + } + + // inner - + function ajax(url, // @param String: + option, // @param Hash: { data, ifmod, method, timeout, + // header, binary, before, after, worker } + // option.data - Mix: upload data + // option.ifmod - Boolean: true is "If-Modified-Since" header + // option.method - String: "GET", "POST", "PUT" + // option.timeout - Number(= 10): timeout sec + // option.header - Hash(= {}): { key: "value", ... } + // option.binary - Boolean(= false): true is binary data + // option.before - Function: before(xhr, option) + // option.after - Function: after(xhr, option, { status, ok }) + // option.worker - Boolean(= false): true is use WebWorkers + callback) { // @param Function: callback(data, option, { status, ok }) + // data - String/Mix/null: + // option - Hash: + // status - Number: HTTP status code + // ok - Boolean: + function readyStateChange() { + if (xhr.readyState === 4) { + var data, status = xhr.status, worker, byteArray, + rv = { status: status, ok: status >= 200 && status < 300 }; + + if (!run++) { + if (method === "PUT") { + data = rv.ok ? xhr.responseText : ""; + } else { + if (rv.ok) { + if (option.worker && globalScope.Worker) { + worker = new Worker(globalScope.msgpack.worker); + worker.onmessage = function (event) { + callback(event.data, option, rv); + }; + worker.postMessage({ + method: "unpack", + data: xhr.responseText + }); + gc(); + return; + } else { + byteArray = _ie ? toByteArrayIE(xhr) + : toByteArray(xhr.responseText); + data = msgpackunpack(byteArray); + } + } + } + after && after(xhr, option, rv); + callback(data, option, rv); + gc(); + } + } + } + + function ng(abort, status) { + if (!run++) { + var rv = { status: status || 400, ok: false }; + + after && after(xhr, option, rv); + callback(null, option, rv); + gc(abort); + } + } + + function gc(abort?) { + abort && xhr && xhr.abort && xhr.abort(); + watchdog && (clearTimeout(watchdog), watchdog = 0); + xhr = null; + globalScope.addEventListener && + globalScope.removeEventListener("beforeunload", ng, false); + } + + var watchdog = 0, + method = option.method || "GET", + header = option.header || {}, + before = option.before, + after = option.after, + data = option.data || null, + xhr = globalScope.XMLHttpRequest ? new XMLHttpRequest() : + globalScope.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : + null, + run = 0, i, + overrideMimeType = "overrideMimeType", + setRequestHeader = "setRequestHeader", + getbinary = method === "GET" && option.binary; + + try { + xhr.onreadystatechange = readyStateChange; + xhr.open(method, url, true); // ASync + + before && before(xhr, option); + + getbinary && xhr[overrideMimeType] && + xhr[overrideMimeType]("text/plain; charset=x-user-defined"); + data && + xhr[setRequestHeader]("Content-Type", + "application/x-www-form-urlencoded"); + + for (i in header) { + xhr[setRequestHeader](i, header[i]); + } + + globalScope.addEventListener && + globalScope.addEventListener("beforeunload", ng, false); // 400: Bad Request + + xhr.send(data); + watchdog = setTimeout(function () { + ng(1, 408); // 408: Request Time-out + }, (option.timeout || 10) * 1000); + } catch (err) { + ng(0, 400); // 400: Bad Request + } + } + + // inner - BinaryString To ByteArray + function toByteArray(data) { // @param BinaryString: "\00\01" + // @return ByteArray: [0x00, 0x01] + var rv = [], bin2num = _bin2num, remain, + ary = data.split(""), + i = -1, iz; + + iz = ary.length; + remain = iz % 8; + + while (remain--) { + ++i; + rv[i] = bin2num[ary[i]]; + } + remain = iz >> 3; + while (remain--) { + rv.push(bin2num[ary[++i]], bin2num[ary[++i]], + bin2num[ary[++i]], bin2num[ary[++i]], + bin2num[ary[++i]], bin2num[ary[++i]], + bin2num[ary[++i]], bin2num[ary[++i]]); + } + return rv; + } + + // inner - BinaryString to ByteArray + function toByteArrayIE(xhr) { + var rv = [], data, remain, + charCodeAt = "charCodeAt", + loop, v0, v1, v2, v3, v4, v5, v6, v7, + i = -1, iz; + + iz = vblen(xhr); + data = vbstr(xhr); + loop = Math.ceil(iz / 2); + remain = loop % 8; + + while (remain--) { + v0 = data[charCodeAt](++i); // 0x00,0x01 -> 0x0100 + rv.push(v0 & 0xff, v0 >> 8); + } + remain = loop >> 3; + while (remain--) { + v0 = data[charCodeAt](++i); + v1 = data[charCodeAt](++i); + v2 = data[charCodeAt](++i); + v3 = data[charCodeAt](++i); + v4 = data[charCodeAt](++i); + v5 = data[charCodeAt](++i); + v6 = data[charCodeAt](++i); + v7 = data[charCodeAt](++i); + rv.push(v0 & 0xff, v0 >> 8, v1 & 0xff, v1 >> 8, + v2 & 0xff, v2 >> 8, v3 & 0xff, v3 >> 8, + v4 & 0xff, v4 >> 8, v5 & 0xff, v5 >> 8, + v6 & 0xff, v6 >> 8, v7 & 0xff, v7 >> 8); + } + iz % 2 && rv.pop(); + + return rv; + } + + // inner - base64.encode + function base64encode(data) { // @param ByteArray: + // @return Base64String: + var rv = [], + c = 0, i = -1, iz = data.length, + pad = [0, 2, 1][data.length % 3], + num2bin = _num2bin, + num2b64 = _num2b64; + + if (globalScope.btoa) { + while (i < iz) { + rv.push(num2bin[data[++i]]); + } + return btoa(rv.join("")); + } + --iz; + while (i < iz) { + c = (data[++i] << 16) | (data[++i] << 8) | (data[++i]); // 24bit + rv.push(num2b64[(c >> 18) & 0x3f], + num2b64[(c >> 12) & 0x3f], + num2b64[(c >> 6) & 0x3f], + num2b64[c & 0x3f]); + } + pad > 1 && (rv[rv.length - 2] = "="); + pad > 0 && (rv[rv.length - 1] = "="); + return rv.join(""); + } + + // --- init --- + (function () { + var i = 0, v; + + for (; i < 0x100; ++i) { + v = _toString(i); + _bin2num[v] = i; // "\00" -> 0x00 + _num2bin[i] = v; // 0 -> "\00" + } + // http://twitter.com/edvakf/statuses/15576483807 + for (i = 0x80; i < 0x100; ++i) { // [Webkit][Gecko] + _bin2num[_toString(0xf700 + i)] = i; // "\f780" -> 0x80 + } + })(); + + _ie && document.write(' - diff --git a/src/stormancer-sdk-js/web.Debug.config b/samples/Samples.Echo/web.Debug.config similarity index 100% rename from src/stormancer-sdk-js/web.Debug.config rename to samples/Samples.Echo/web.Debug.config diff --git a/src/stormancer-sdk-js/web.Release.config b/samples/Samples.Echo/web.Release.config similarity index 100% rename from src/stormancer-sdk-js/web.Release.config rename to samples/Samples.Echo/web.Release.config diff --git a/src/stormancer-sdk-js/Client.ts b/src/stormancer-sdk-js/Client.ts index 5687b83..8fd7444 100644 --- a/src/stormancer-sdk-js/Client.ts +++ b/src/stormancer-sdk-js/Client.ts @@ -100,12 +100,13 @@ module Stormancer { var parameter: SceneInfosRequestDto = { Metadata: self._serverConnection.metadata, Token: ci.token }; return self.sendSystemRequest(MessageIDTypes.ID_GET_SCENE_INFOS, parameter); }).then((result: SceneInfosDto) => { - if (!self._serverConnection.serializer) { + if (!self._serverConnection.serializerChosen) { if (!result.SelectedSerializer) { throw new Error("No serializer selected."); } self._serverConnection.serializer = self._serializers[result.SelectedSerializer]; self._serverConnection.metadata["serializer"] = result.SelectedSerializer; + self._serverConnection.serializerChosen = true; } var scene = new Scene(self._serverConnection, self, sceneId, ci.token, result); return scene; diff --git a/src/stormancer-sdk-js/Core/IConnection.ts b/src/stormancer-sdk-js/Core/IConnection.ts index 4f671ad..9fa2191 100644 --- a/src/stormancer-sdk-js/Core/IConnection.ts +++ b/src/stormancer-sdk-js/Core/IConnection.ts @@ -50,6 +50,7 @@ module Stormancer { // Returns advanced statistics about the connection. //getConnectionStatistics(): IConnectionStatistics; + serializerChosen: boolean; serializer: ISerializer; } } diff --git a/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts b/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts index 0be59f8..0b10c22 100644 --- a/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts +++ b/src/stormancer-sdk-js/Transports/WebSocketClientConnection.ts @@ -63,6 +63,7 @@ module Stormancer { this.application = application; } - public serializer: ISerializer; + public serializerChosen: boolean = false; + public serializer: ISerializer = new MsgPackSerializer(); } } diff --git a/src/stormancer-sdk-js/stormancer-sdk-js.csproj b/src/stormancer-sdk-js/stormancer-sdk-js.csproj index 5155ef6..1de927f 100644 --- a/src/stormancer-sdk-js/stormancer-sdk-js.csproj +++ b/src/stormancer-sdk-js/stormancer-sdk-js.csproj @@ -18,16 +18,12 @@ - - - - @@ -70,12 +66,6 @@ - - web.config - - - web.config - 12.0 @@ -107,6 +97,7 @@ True true stormancer.js + True true diff --git a/stormancer-sdk-js.sln b/stormancer-sdk-js.sln index 301451e..f84bce1 100644 --- a/stormancer-sdk-js.sln +++ b/stormancer-sdk-js.sln @@ -9,6 +9,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{8A09 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "stormancer-sdk-js", "src\stormancer-sdk-js\stormancer-sdk-js.csproj", "{AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Echo", "samples\Samples.Echo\Samples.Echo.csproj", "{F706A854-E68F-4AE2-AE2A-714110651EED}" + ProjectSection(ProjectDependencies) = postProject + {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7} = {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -19,11 +24,16 @@ Global {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7}.Release|Any CPU.Build.0 = Release|Any CPU + {F706A854-E68F-4AE2-AE2A-714110651EED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F706A854-E68F-4AE2-AE2A-714110651EED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F706A854-E68F-4AE2-AE2A-714110651EED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F706A854-E68F-4AE2-AE2A-714110651EED}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {AC5DB693-0AAB-4BA7-8D74-67C307BCDCE7} = {EF042117-5269-4865-B492-6C0A3802F940} + {F706A854-E68F-4AE2-AE2A-714110651EED} = {8A0942AA-DC07-4A67-9192-91F4EEEEA3D5} EndGlobalSection EndGlobal