├── Gruntfile.js
├── README.md
├── dist
└── yar.min.js
├── example
├── example.html
└── server.php
├── lib
├── cstruct
│ └── cstruct.js
└── stringview
│ └── stringview.js
├── package.json
└── src
└── yar.js
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt){
2 | grunt.initConfig({
3 | uglify:{
4 | app:{
5 | files: {
6 | 'dist/yar.min.js':[
7 | './src/stringview.js',
8 | './src/yar.js'
9 | ]
10 | }
11 | }
12 | },
13 | clean : {
14 | spm : ['.build','build','dist']
15 | }
16 |
17 | });
18 |
19 | grunt.loadNpmTasks('grunt-contrib-clean');
20 | grunt.loadNpmTasks('grunt-contrib-uglify');
21 |
22 |
23 | grunt.registerTask('build',['uglify:app'])
24 |
25 | };
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ###Intro
2 | ---
3 | 这是一个[Yar(一个轻量高效率的RPC框架)](https://github.com/laruence/yar)的浏览器版本调用客户端
4 | 利用HTML5的 ArrayBuffer实现二进制传输。
5 |
6 | 当前尚处于开发阶段,请勿用于生产环境
7 |
8 |
9 | ###Install
10 | ---
11 |
12 | git clone https://github.com/weixinhost/yar-javascript-client
13 |
14 | ###Example
15 | ---
16 | ```HTML
17 |
23 | ```
24 |
25 | ###CStruct
26 | 在 lib/cstruct 是一个使用js语言c变量/数组/结构体的二进制操作。未来将增加nodejs的支持
27 |
28 | ###Todo
29 | ---
30 | - 支援JQuery进行Ajax请求
31 | - 支援并发请求
32 | - 浏览器兼容
33 | - CStruct 支援 nodejs
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/dist/yar.min.js:
--------------------------------------------------------------------------------
1 | !function(a){function b(){this.struct=new CStruct.CStruct({id:new CStruct.CVal("uint32",0),version:new CStruct.CVal("uint16",1),magic_number:new CStruct.CVal("uint32",2162158688),reserved:new CStruct.CVal("uint32",0),provider:new CStruct.CArray(32),token:new CStruct.CArray(32),body_len:new CStruct.CVal("uint32",0),pack:new CStruct.CVal("string","JSON\x00\x00\x00\x00"),body:new CStruct.CVal("string","")},["id","version","magic_number","reserved","provider","token","body_len","pack","body"])}function c(a){this.address=a}b.prototype.create=function(a){return"object"==typeof a&&(a=JSON.stringify(a)),this.struct.get("body_len").val=a.length,this.struct.get("body").val=a,this.struct.get("id").val=123456789,this.struct.raw()},c.prototype.call=function(a,c,d){var e={i:123456789,m:""+a,p:c||[]},f=new b;f.id=e.id;var g=f.create(e),h=new XMLHttpRequest;h.onreadystatechange=function(){if(4==h.readyState){var a=h.responseText,b=a.substr(90,a.length-89);b=JSON.parse(b),"undefined"!=typeof b.e,"function"==typeof d&&d(b.r)}},h.open("POST",this.address,!0),h.send(g)},a.YarClient=c}(window,void 0);
--------------------------------------------------------------------------------
/example/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Yar.js Test
6 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/example/server.php:
--------------------------------------------------------------------------------
1 | handle();
20 |
--------------------------------------------------------------------------------
/lib/cstruct/cstruct.js:
--------------------------------------------------------------------------------
1 | /****
2 | * 使用js描述c语言变量的内存布局
3 | *
4 | */
5 |
6 | (function(global,undefined){
7 | function CVal(type,val){
8 | this.type = type;
9 | this.val = val;
10 | }
11 |
12 | CVal.prototype.TYPE_DEFINE = {
13 |
14 | 'int8':1,
15 | 'uint8':1,
16 |
17 | 'int16':2,
18 | 'uint16':2,
19 |
20 | 'int32':4,
21 | 'uint32':4,
22 |
23 | 'float32':4,
24 | 'float64':8,
25 | 'double':8,
26 |
27 | 'string':-1, //for dynamic string like char *
28 | 'raw':-1 //is packed data
29 |
30 | };
31 |
32 |
33 | CVal.prototype.raw = function(view,offset){
34 | var _view = null;
35 | switch(this.type){
36 | case 'string' :{
37 | _view = new StringView(this.val,this.STRING_ENCODING,0,this.val.length);
38 | var _len = _view.bufferView.byteLength;
39 | for(var i=0;i<_len;i++){
40 | view.setUint8(offset,_view.bufferView[i]);
41 | offset+=1;
42 | }
43 | return offset;
44 | }break;
45 |
46 | case 'raw':{ //todo
47 | return offset;
48 | }break;
49 |
50 | default :{
51 | var _len = this.TYPE_DEFINE[this.type];
52 | var _buffer = new ArrayBuffer(_len);
53 | _view = new DataView(_buffer);
54 | if(_len){
55 | switch(this.type){
56 | case 'int8' :{
57 | view.setInt8(offset,parseInt(this.val));
58 | }break;
59 | case 'uint8' :{
60 | view.setUint8(offset,parseInt(this.val));
61 | }break;
62 | case 'int16' :{
63 | view.setInt16(offset,parseInt(this.val));
64 | }break;
65 | case 'uint16' :{
66 | view.setUint16(offset,parseInt(this.val));
67 | }break;
68 | case 'int32' :{
69 | view.setInt32(offset,parseInt(this.val));
70 | }break;
71 | case 'uint32' :{
72 | view.setUint32(offset,parseInt(this.val));
73 | }break;
74 | case 'float32' :{
75 | view.setFloat32(offset,parseFloat(this.val));
76 | }break;
77 | case 'double' :
78 | case 'float64' :{
79 | view.setFloat64(offset,parseFloat(this.val));
80 | }break;
81 | }
82 | offset += _len;
83 | }
84 | }
85 | }
86 |
87 | return offset;
88 | }
89 |
90 | CVal.prototype.byte_length = function(){
91 | var _len = 0;
92 | switch(this.type){
93 | case 'string' :{
94 | var _view = new StringView(this.val,this.STRING_ENCODING,0,this.val.length);
95 | _len = _view.bufferView.byteLength;
96 | }break;
97 |
98 | case 'raw' :{
99 | return (this.val.length);
100 | }break;
101 |
102 | default :{
103 | _len = this.TYPE_DEFINE[this.type];
104 | }
105 | }
106 | return _len;
107 | }
108 |
109 | CVal.prototype.STRING_ENCODING ='UTF-8';
110 |
111 |
112 | function CArray(length){
113 | this.length = length;
114 | this.data = [];
115 | for(var i=0;i -9007199254740992 && nVal < 9007199254740992 && Math.floor(nVal) === nVal;
8 | };
9 | }
10 |
11 |
12 | function StringView (vInput, sEncoding /* optional (default: UTF-8) */, nOffset /* optional */, nLength /* optional */) {
13 |
14 | var fTAView, aWhole, aRaw, fPutOutptCode, fGetOutptChrSize, nInptLen, nStartIdx = isFinite(nOffset) ? nOffset : 0, nTranscrType = 15;
15 |
16 | if (sEncoding) { this.encoding = sEncoding.toString(); }
17 |
18 | encSwitch: switch (this.encoding) {
19 | case "UTF-8":
20 | fPutOutptCode = StringView.putUTF8CharCode;
21 | fGetOutptChrSize = StringView.getUTF8CharLength;
22 | fTAView = Uint8Array;
23 | break encSwitch;
24 | case "UTF-16":
25 | fPutOutptCode = StringView.putUTF16CharCode;
26 | fGetOutptChrSize = StringView.getUTF16CharLength;
27 | fTAView = Uint16Array;
28 | break encSwitch;
29 | case "UTF-32":
30 | fTAView = Uint32Array;
31 | nTranscrType &= 14;
32 | break encSwitch;
33 | default:
34 | /* case "ASCII", or case "BinaryString" or unknown cases */
35 | fTAView = Uint8Array;
36 | nTranscrType &= 14;
37 | }
38 |
39 | typeSwitch: switch (typeof vInput) {
40 | case "string":
41 | /* the input argument is a primitive string: a new buffer will be created. */
42 | nTranscrType &= 7;
43 | break typeSwitch;
44 | case "object":
45 | classSwitch: switch (vInput.constructor) {
46 | case StringView:
47 | /* the input argument is a stringView: a new buffer will be created. */
48 | nTranscrType &= 3;
49 | break typeSwitch;
50 | case String:
51 | /* the input argument is an objectified string: a new buffer will be created. */
52 | nTranscrType &= 7;
53 | break typeSwitch;
54 | case ArrayBuffer:
55 | /* the input argument is an arrayBuffer: the buffer will be shared. */
56 | aWhole = new fTAView(vInput);
57 | nInptLen = this.encoding === "UTF-32" ?
58 | vInput.byteLength >>> 2
59 | : this.encoding === "UTF-16" ?
60 | vInput.byteLength >>> 1
61 | :
62 | vInput.byteLength;
63 | aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ?
64 | aWhole
65 | : new fTAView(vInput, nStartIdx, !isFinite(nLength) ? nInptLen - nStartIdx : nLength);
66 |
67 | break typeSwitch;
68 | case Uint32Array:
69 | case Uint16Array:
70 | case Uint8Array:
71 | /* the input argument is a typedArray: the buffer, and possibly the array itself, will be shared. */
72 | fTAView = vInput.constructor;
73 | nInptLen = vInput.length;
74 | aWhole = vInput.byteOffset === 0 && vInput.length === (
75 | fTAView === Uint32Array ?
76 | vInput.buffer.byteLength >>> 2
77 | : fTAView === Uint16Array ?
78 | vInput.buffer.byteLength >>> 1
79 | :
80 | vInput.buffer.byteLength
81 | ) ? vInput : new fTAView(vInput.buffer);
82 | aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ?
83 | vInput
84 | : vInput.subarray(nStartIdx, isFinite(nLength) ? nStartIdx + nLength : nInptLen);
85 |
86 | break typeSwitch;
87 | default:
88 | /* the input argument is an array or another serializable object: a new typedArray will be created. */
89 | aWhole = new fTAView(vInput);
90 | nInptLen = aWhole.length;
91 | aRaw = nStartIdx === 0 && (!isFinite(nLength) || nLength === nInptLen) ?
92 | aWhole
93 | : aWhole.subarray(nStartIdx, isFinite(nLength) ? nStartIdx + nLength : nInptLen);
94 | }
95 | break typeSwitch;
96 | default:
97 | /* the input argument is a number, a boolean or a function: a new typedArray will be created. */
98 | aWhole = aRaw = new fTAView(Number(vInput) || 0);
99 |
100 | }
101 |
102 | if (nTranscrType < 8) {
103 |
104 | var vSource, nOutptLen, nCharStart, nCharEnd, nEndIdx, fGetInptChrSize, fGetInptChrCode;
105 |
106 | if (nTranscrType & 4) { /* input is string */
107 |
108 | vSource = vInput;
109 | nOutptLen = nInptLen = vSource.length;
110 | nTranscrType ^= this.encoding === "UTF-32" ? 0 : 2;
111 | /* ...or...: nTranscrType ^= Number(this.encoding !== "UTF-32") << 1; */
112 | nStartIdx = nCharStart = nOffset ? Math.max((nOutptLen + nOffset) % nOutptLen, 0) : 0;
113 | nEndIdx = nCharEnd = (Number.isInteger(nLength) ? Math.min(Math.max(nLength, 0) + nStartIdx, nOutptLen) : nOutptLen) - 1;
114 |
115 | } else { /* input is stringView */
116 |
117 | vSource = vInput.rawData;
118 | nInptLen = vInput.makeIndex();
119 | nStartIdx = nCharStart = nOffset ? Math.max((nInptLen + nOffset) % nInptLen, 0) : 0;
120 | nOutptLen = Number.isInteger(nLength) ? Math.min(Math.max(nLength, 0), nInptLen - nCharStart) : nInptLen;
121 | nEndIdx = nCharEnd = nOutptLen + nCharStart;
122 |
123 | if (vInput.encoding === "UTF-8") {
124 | fGetInptChrSize = StringView.getUTF8CharLength;
125 | fGetInptChrCode = StringView.loadUTF8CharCode;
126 | } else if (vInput.encoding === "UTF-16") {
127 | fGetInptChrSize = StringView.getUTF16CharLength;
128 | fGetInptChrCode = StringView.loadUTF16CharCode;
129 | } else {
130 | nTranscrType &= 1;
131 | }
132 |
133 | }
134 |
135 | if (nOutptLen === 0 || nTranscrType < 4 && vSource.encoding === this.encoding && nCharStart === 0 && nOutptLen === nInptLen) {
136 |
137 | /* the encoding is the same, the length too and the offset is 0... or the input is empty! */
138 |
139 | nTranscrType = 7;
140 |
141 | }
142 |
143 | conversionSwitch: switch (nTranscrType) {
144 |
145 | case 0:
146 |
147 | /* both the source and the new StringView have a fixed-length encoding... */
148 |
149 | aWhole = new fTAView(nOutptLen);
150 | for (var nOutptIdx = 0; nOutptIdx < nOutptLen; aWhole[nOutptIdx] = vSource[nStartIdx + nOutptIdx++]);
151 | break conversionSwitch;
152 |
153 | case 1:
154 |
155 | /* the source has a fixed-length encoding but the new StringView has a variable-length encoding... */
156 |
157 | /* mapping... */
158 |
159 | nOutptLen = 0;
160 |
161 | for (var nInptIdx = nStartIdx; nInptIdx < nEndIdx; nInptIdx++) {
162 | nOutptLen += fGetOutptChrSize(vSource[nInptIdx]);
163 | }
164 |
165 | aWhole = new fTAView(nOutptLen);
166 |
167 | /* transcription of the source... */
168 |
169 | for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx++) {
170 | nOutptIdx = fPutOutptCode(aWhole, vSource[nInptIdx], nOutptIdx);
171 | }
172 |
173 | break conversionSwitch;
174 |
175 | case 2:
176 |
177 | /* the source has a variable-length encoding but the new StringView has a fixed-length encoding... */
178 |
179 | /* mapping... */
180 |
181 | nStartIdx = 0;
182 |
183 | var nChrCode;
184 |
185 | for (nChrIdx = 0; nChrIdx < nCharStart; nChrIdx++) {
186 | nChrCode = fGetInptChrCode(vSource, nStartIdx);
187 | nStartIdx += fGetInptChrSize(nChrCode);
188 | }
189 |
190 | aWhole = new fTAView(nOutptLen);
191 |
192 | /* transcription of the source... */
193 |
194 | for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx += fGetInptChrSize(nChrCode), nOutptIdx++) {
195 | nChrCode = fGetInptChrCode(vSource, nInptIdx);
196 | aWhole[nOutptIdx] = nChrCode;
197 | }
198 |
199 | break conversionSwitch;
200 |
201 | case 3:
202 |
203 | /* both the source and the new StringView have a variable-length encoding... */
204 |
205 | /* mapping... */
206 |
207 | nOutptLen = 0;
208 |
209 | var nChrCode;
210 |
211 | for (var nChrIdx = 0, nInptIdx = 0; nChrIdx < nCharEnd; nInptIdx += fGetInptChrSize(nChrCode)) {
212 | nChrCode = fGetInptChrCode(vSource, nInptIdx);
213 | if (nChrIdx === nCharStart) { nStartIdx = nInptIdx; }
214 | if (++nChrIdx > nCharStart) { nOutptLen += fGetOutptChrSize(nChrCode); }
215 | }
216 |
217 | aWhole = new fTAView(nOutptLen);
218 |
219 | /* transcription... */
220 |
221 | for (var nInptIdx = nStartIdx, nOutptIdx = 0; nOutptIdx < nOutptLen; nInptIdx += fGetInptChrSize(nChrCode)) {
222 | nChrCode = fGetInptChrCode(vSource, nInptIdx);
223 | nOutptIdx = fPutOutptCode(aWhole, nChrCode, nOutptIdx);
224 | }
225 |
226 | break conversionSwitch;
227 |
228 | case 4:
229 |
230 | /* DOMString to ASCII or BinaryString or other unknown encodings */
231 |
232 | aWhole = new fTAView(nOutptLen);
233 |
234 | /* transcription... */
235 |
236 | for (var nIdx = 0; nIdx < nOutptLen; nIdx++) {
237 | aWhole[nIdx] = vSource.charCodeAt(nIdx) & 0xff;
238 | }
239 |
240 | break conversionSwitch;
241 |
242 | case 5:
243 |
244 | /* DOMString to UTF-8 or to UTF-16 */
245 |
246 | /* mapping... */
247 |
248 | nOutptLen = 0;
249 |
250 | for (var nMapIdx = 0; nMapIdx < nInptLen; nMapIdx++) {
251 | if (nMapIdx === nCharStart) { nStartIdx = nOutptLen; }
252 | nOutptLen += fGetOutptChrSize(vSource.charCodeAt(nMapIdx));
253 | if (nMapIdx === nCharEnd) { nEndIdx = nOutptLen; }
254 | }
255 |
256 | aWhole = new fTAView(nOutptLen);
257 |
258 | /* transcription... */
259 |
260 | for (var nOutptIdx = 0, nChrIdx = 0; nOutptIdx < nOutptLen; nChrIdx++) {
261 | nOutptIdx = fPutOutptCode(aWhole, vSource.charCodeAt(nChrIdx), nOutptIdx);
262 | }
263 |
264 | break conversionSwitch;
265 |
266 | case 6:
267 |
268 | /* DOMString to UTF-32 */
269 |
270 | aWhole = new fTAView(nOutptLen);
271 |
272 | /* transcription... */
273 |
274 | for (var nIdx = 0; nIdx < nOutptLen; nIdx++) {
275 | aWhole[nIdx] = vSource.charCodeAt(nIdx);
276 | }
277 |
278 | break conversionSwitch;
279 |
280 | case 7:
281 |
282 | aWhole = new fTAView(nOutptLen ? vSource : 0);
283 | break conversionSwitch;
284 |
285 | }
286 |
287 | aRaw = nTranscrType > 3 && (nStartIdx > 0 || nEndIdx < aWhole.length - 1) ? aWhole.subarray(nStartIdx, nEndIdx) : aWhole;
288 |
289 | }
290 |
291 | this.buffer = aWhole.buffer;
292 | this.bufferView = aWhole;
293 | this.rawData = aRaw;
294 |
295 | Object.freeze(this);
296 |
297 | }
298 |
299 | /* CONSTRUCTOR'S METHODS */
300 |
301 | StringView.loadUTF8CharCode = function (aChars, nIdx) {
302 |
303 | var nLen = aChars.length, nPart = aChars[nIdx];
304 |
305 | return nPart > 251 && nPart < 254 && nIdx + 5 < nLen ?
306 | /* (nPart - 252 << 32) is not possible in ECMAScript! So...: */
307 | /* six bytes */ (nPart - 252) * 1073741824 + (aChars[nIdx + 1] - 128 << 24) + (aChars[nIdx + 2] - 128 << 18) + (aChars[nIdx + 3] - 128 << 12) + (aChars[nIdx + 4] - 128 << 6) + aChars[nIdx + 5] - 128
308 | : nPart > 247 && nPart < 252 && nIdx + 4 < nLen ?
309 | /* five bytes */ (nPart - 248 << 24) + (aChars[nIdx + 1] - 128 << 18) + (aChars[nIdx + 2] - 128 << 12) + (aChars[nIdx + 3] - 128 << 6) + aChars[nIdx + 4] - 128
310 | : nPart > 239 && nPart < 248 && nIdx + 3 < nLen ?
311 | /* four bytes */(nPart - 240 << 18) + (aChars[nIdx + 1] - 128 << 12) + (aChars[nIdx + 2] - 128 << 6) + aChars[nIdx + 3] - 128
312 | : nPart > 223 && nPart < 240 && nIdx + 2 < nLen ?
313 | /* three bytes */ (nPart - 224 << 12) + (aChars[nIdx + 1] - 128 << 6) + aChars[nIdx + 2] - 128
314 | : nPart > 191 && nPart < 224 && nIdx + 1 < nLen ?
315 | /* two bytes */ (nPart - 192 << 6) + aChars[nIdx + 1] - 128
316 | :
317 | /* one byte */ nPart;
318 |
319 | };
320 |
321 | StringView.putUTF8CharCode = function (aTarget, nChar, nPutAt) {
322 |
323 | var nIdx = nPutAt;
324 |
325 | if (nChar < 0x80 /* 128 */) {
326 | /* one byte */
327 | aTarget[nIdx++] = nChar;
328 | } else if (nChar < 0x800 /* 2048 */) {
329 | /* two bytes */
330 | aTarget[nIdx++] = 0xc0 /* 192 */ + (nChar >>> 6);
331 | aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */);
332 | } else if (nChar < 0x10000 /* 65536 */) {
333 | /* three bytes */
334 | aTarget[nIdx++] = 0xe0 /* 224 */ + (nChar >>> 12);
335 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */);
336 | aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */);
337 | } else if (nChar < 0x200000 /* 2097152 */) {
338 | /* four bytes */
339 | aTarget[nIdx++] = 0xf0 /* 240 */ + (nChar >>> 18);
340 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */);
341 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */);
342 | aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */);
343 | } else if (nChar < 0x4000000 /* 67108864 */) {
344 | /* five bytes */
345 | aTarget[nIdx++] = 0xf8 /* 248 */ + (nChar >>> 24);
346 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 18) & 0x3f /* 63 */);
347 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */);
348 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */);
349 | aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */);
350 | } else /* if (nChar <= 0x7fffffff) */ { /* 2147483647 */
351 | /* six bytes */
352 | aTarget[nIdx++] = 0xfc /* 252 */ + /* (nChar >>> 32) is not possible in ECMAScript! So...: */ (nChar / 1073741824);
353 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 24) & 0x3f /* 63 */);
354 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 18) & 0x3f /* 63 */);
355 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 12) & 0x3f /* 63 */);
356 | aTarget[nIdx++] = 0x80 /* 128 */ + ((nChar >>> 6) & 0x3f /* 63 */);
357 | aTarget[nIdx++] = 0x80 /* 128 */ + (nChar & 0x3f /* 63 */);
358 | }
359 | return nIdx;
360 | };
361 |
362 | StringView.getUTF8CharLength = function (nChar) {
363 | return nChar < 0x80 ? 1 : nChar < 0x800 ? 2 : nChar < 0x10000 ? 3 : nChar < 0x200000 ? 4 : nChar < 0x4000000 ? 5 : 6;
364 | };
365 |
366 | StringView.loadUTF16CharCode = function (aChars, nIdx) {
367 |
368 | /* UTF-16 to DOMString decoding algorithm */
369 | var nFrstChr = aChars[nIdx];
370 |
371 | return nFrstChr > 0xD7BF /* 55231 */ && nIdx + 1 < aChars.length ?
372 | (nFrstChr - 0xD800 /* 55296 */ << 10) + aChars[nIdx + 1] + 0x2400 /* 9216 */
373 | : nFrstChr;
374 |
375 | };
376 |
377 | StringView.putUTF16CharCode = function (aTarget, nChar, nPutAt) {
378 |
379 | var nIdx = nPutAt;
380 |
381 | if (nChar < 0x10000 /* 65536 */) {
382 | /* one element */
383 | aTarget[nIdx++] = nChar;
384 | } else {
385 | /* two elements */
386 | aTarget[nIdx++] = 0xD7C0 /* 55232 */ + (nChar >>> 10);
387 | aTarget[nIdx++] = 0xDC00 /* 56320 */ + (nChar & 0x3FF /* 1023 */);
388 | }
389 |
390 | return nIdx;
391 |
392 | };
393 |
394 | StringView.getUTF16CharLength = function (nChar) {
395 | return nChar < 0x10000 ? 1 : 2;
396 | };
397 |
398 | /* Array of bytes to base64 string decoding */
399 |
400 | StringView.b64ToUint6 = function (nChr) {
401 |
402 | return nChr > 64 && nChr < 91 ?
403 | nChr - 65
404 | : nChr > 96 && nChr < 123 ?
405 | nChr - 71
406 | : nChr > 47 && nChr < 58 ?
407 | nChr + 4
408 | : nChr === 43 ?
409 | 62
410 | : nChr === 47 ?
411 | 63
412 | :
413 | 0;
414 |
415 | };
416 |
417 | StringView.uint6ToB64 = function (nUint6) {
418 |
419 | return nUint6 < 26 ?
420 | nUint6 + 65
421 | : nUint6 < 52 ?
422 | nUint6 + 71
423 | : nUint6 < 62 ?
424 | nUint6 - 4
425 | : nUint6 === 62 ?
426 | 43
427 | : nUint6 === 63 ?
428 | 47
429 | :
430 | 65;
431 |
432 | };
433 |
434 | /* Base64 string to array encoding */
435 |
436 | StringView.bytesToBase64 = function (aBytes) {
437 |
438 | var sB64Enc = "";
439 |
440 | for (var nMod3, nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
441 | nMod3 = nIdx % 3;
442 | if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
443 | nUint24 |= aBytes[nIdx] << (16 >>> nMod3 & 24);
444 | if (nMod3 === 2 || aBytes.length - nIdx === 1) {
445 | sB64Enc += String.fromCharCode(StringView.uint6ToB64(nUint24 >>> 18 & 63), StringView.uint6ToB64(nUint24 >>> 12 & 63), StringView.uint6ToB64(nUint24 >>> 6 & 63), StringView.uint6ToB64(nUint24 & 63));
446 | nUint24 = 0;
447 | }
448 | }
449 |
450 | return sB64Enc.replace(/A(?=A$|$)/g, "=");
451 |
452 | };
453 |
454 |
455 | StringView.base64ToBytes = function (sBase64, nBlockBytes) {
456 |
457 | var
458 | sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length,
459 | nOutLen = nBlockBytes ? Math.ceil((nInLen * 3 + 1 >>> 2) / nBlockBytes) * nBlockBytes : nInLen * 3 + 1 >>> 2, aBytes = new Uint8Array(nOutLen);
460 |
461 | for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
462 | nMod4 = nInIdx & 3;
463 | nUint24 |= StringView.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
464 | if (nMod4 === 3 || nInLen - nInIdx === 1) {
465 | for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
466 | aBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255;
467 | }
468 | nUint24 = 0;
469 | }
470 | }
471 |
472 | return aBytes;
473 |
474 | };
475 |
476 | StringView.makeFromBase64 = function (sB64Inpt, sEncoding, nByteOffset, nLength) {
477 |
478 | return new StringView(sEncoding === "UTF-16" || sEncoding === "UTF-32" ? StringView.base64ToBytes(sB64Inpt, sEncoding === "UTF-16" ? 2 : 4).buffer : StringView.base64ToBytes(sB64Inpt), sEncoding, nByteOffset, nLength);
479 |
480 | };
481 |
482 | /* DEFAULT VALUES */
483 |
484 | StringView.prototype.encoding = "UTF-8"; /* Default encoding... */
485 |
486 | /* INSTANCES' METHODS */
487 |
488 | StringView.prototype.makeIndex = function (nChrLength, nStartFrom) {
489 |
490 | var
491 |
492 | aTarget = this.rawData, nChrEnd, nRawLength = aTarget.length,
493 | nStartIdx = nStartFrom || 0, nIdxEnd = nStartIdx, nStopAtChr = isNaN(nChrLength) ? Infinity : nChrLength;
494 |
495 | if (nChrLength + 1 > aTarget.length) { throw new RangeError("StringView.prototype.makeIndex - The offset can\'t be major than the length of the array - 1."); }
496 |
497 | switch (this.encoding) {
498 |
499 | case "UTF-8":
500 |
501 | var nPart;
502 |
503 | for (nChrEnd = 0; nIdxEnd < nRawLength && nChrEnd < nStopAtChr; nChrEnd++) {
504 | nPart = aTarget[nIdxEnd];
505 | nIdxEnd += nPart > 251 && nPart < 254 && nIdxEnd + 5 < nRawLength ? 6
506 | : nPart > 247 && nPart < 252 && nIdxEnd + 4 < nRawLength ? 5
507 | : nPart > 239 && nPart < 248 && nIdxEnd + 3 < nRawLength ? 4
508 | : nPart > 223 && nPart < 240 && nIdxEnd + 2 < nRawLength ? 3
509 | : nPart > 191 && nPart < 224 && nIdxEnd + 1 < nRawLength ? 2
510 | : 1;
511 | }
512 |
513 | break;
514 |
515 | case "UTF-16":
516 |
517 | for (nChrEnd = nStartIdx; nIdxEnd < nRawLength && nChrEnd < nStopAtChr; nChrEnd++) {
518 | nIdxEnd += aTarget[nIdxEnd] > 0xD7BF /* 55231 */ && nIdxEnd + 1 < aTarget.length ? 2 : 1;
519 | }
520 |
521 | break;
522 |
523 | default:
524 |
525 | nIdxEnd = nChrEnd = isFinite(nChrLength) ? nChrLength : nRawLength - 1;
526 |
527 | }
528 |
529 | if (nChrLength) { return nIdxEnd; }
530 |
531 | return nChrEnd;
532 |
533 | };
534 |
535 | StringView.prototype.toBase64 = function (bWholeBuffer) {
536 |
537 | return StringView.bytesToBase64(
538 | bWholeBuffer ?
539 | (
540 | this.bufferView.constructor === Uint8Array ?
541 | this.bufferView
542 | :
543 | new Uint8Array(this.buffer)
544 | )
545 | : this.rawData.constructor === Uint8Array ?
546 | this.rawData
547 | :
548 | new Uint8Array(this.buffer, this.rawData.byteOffset, this.rawData.length << (this.rawData.constructor === Uint16Array ? 1 : 2))
549 | );
550 |
551 | };
552 |
553 | StringView.prototype.subview = function (nCharOffset /* optional */, nCharLength /* optional */) {
554 |
555 | var
556 |
557 | nChrLen, nCharStart, nStrLen, bVariableLen = this.encoding === "UTF-8" || this.encoding === "UTF-16",
558 | nStartOffset = nCharOffset, nStringLength, nRawLen = this.rawData.length;
559 |
560 | if (nRawLen === 0) {
561 | return new StringView(this.buffer, this.encoding);
562 | }
563 |
564 | nStringLength = bVariableLen ? this.makeIndex() : nRawLen;
565 | nCharStart = nCharOffset ? Math.max((nStringLength + nCharOffset) % nStringLength, 0) : 0;
566 | nStrLen = Number.isInteger(nCharLength) ? Math.max(nCharLength, 0) + nCharStart > nStringLength ? nStringLength - nCharStart : nCharLength : nStringLength;
567 |
568 | if (nCharStart === 0 && nStrLen === nStringLength) { return this; }
569 |
570 | if (bVariableLen) {
571 | nStartOffset = this.makeIndex(nCharStart);
572 | nChrLen = this.makeIndex(nStrLen, nStartOffset) - nStartOffset;
573 | } else {
574 | nStartOffset = nCharStart;
575 | nChrLen = nStrLen - nCharStart;
576 | }
577 |
578 | if (this.encoding === "UTF-16") {
579 | nStartOffset <<= 1;
580 | } else if (this.encoding === "UTF-32") {
581 | nStartOffset <<= 2;
582 | }
583 |
584 | return new StringView(this.buffer, this.encoding, nStartOffset, nChrLen);
585 |
586 | };
587 |
588 | StringView.prototype.forEachChar = function (fCallback, oThat, nChrOffset, nChrLen) {
589 |
590 | var aSource = this.rawData, nRawEnd, nRawIdx;
591 |
592 | if (this.encoding === "UTF-8" || this.encoding === "UTF-16") {
593 |
594 | var fGetInptChrSize, fGetInptChrCode;
595 |
596 | if (this.encoding === "UTF-8") {
597 | fGetInptChrSize = StringView.getUTF8CharLength;
598 | fGetInptChrCode = StringView.loadUTF8CharCode;
599 | } else if (this.encoding === "UTF-16") {
600 | fGetInptChrSize = StringView.getUTF16CharLength;
601 | fGetInptChrCode = StringView.loadUTF16CharCode;
602 | }
603 |
604 | nRawIdx = isFinite(nChrOffset) ? this.makeIndex(nChrOffset) : 0;
605 | nRawEnd = isFinite(nChrLen) ? this.makeIndex(nChrLen, nRawIdx) : aSource.length;
606 |
607 | for (var nChrCode, nChrIdx = 0; nRawIdx < nRawEnd; nChrIdx++) {
608 | nChrCode = fGetInptChrCode(aSource, nRawIdx);
609 | fCallback.call(oThat || null, nChrCode, nChrIdx, nRawIdx, aSource);
610 | nRawIdx += fGetInptChrSize(nChrCode);
611 | }
612 |
613 | } else {
614 |
615 | nRawIdx = isFinite(nChrOffset) ? nChrOffset : 0;
616 | nRawEnd = isFinite(nChrLen) ? nChrLen + nRawIdx : aSource.length;
617 |
618 | for (nRawIdx; nRawIdx < nRawEnd; nRawIdx++) {
619 | fCallback.call(oThat || null, aSource[nRawIdx], nRawIdx, nRawIdx, aSource);
620 | }
621 |
622 | }
623 |
624 | };
625 |
626 | StringView.prototype.valueOf = StringView.prototype.toString = function () {
627 |
628 | if (this.encoding !== "UTF-8" && this.encoding !== "UTF-16") {
629 | /* ASCII, UTF-32 or BinaryString to DOMString */
630 | return String.fromCharCode.apply(null, this.rawData);
631 | }
632 |
633 | var fGetCode, fGetIncr, sView = "";
634 |
635 | if (this.encoding === "UTF-8") {
636 | fGetIncr = StringView.getUTF8CharLength;
637 | fGetCode = StringView.loadUTF8CharCode;
638 | } else if (this.encoding === "UTF-16") {
639 | fGetIncr = StringView.getUTF16CharLength;
640 | fGetCode = StringView.loadUTF16CharCode;
641 | }
642 |
643 | for (var nChr, nLen = this.rawData.length, nIdx = 0; nIdx < nLen; nIdx += fGetIncr(nChr)) {
644 | nChr = fGetCode(this.rawData, nIdx);
645 | sView += String.fromCharCode(nChr);
646 | }
647 |
648 | return sView;
649 |
650 | };
651 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "yar-javascript-client",
3 | "version": "1.0.0",
4 | "description": "Yar RPC FrameWork Client for browser",
5 | "main": "yar.js",
6 | "directories": {
7 | "doc": "docs"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/weixinhost/yar-javascript-client"
12 | },
13 | "author": "misko_lee",
14 | "license": "MIT",
15 | "devDependencies": {
16 | "grunt": "~0.4.1",
17 | "grunt-cmd-concat": "^0.2.7",
18 | "grunt-cmd-transport": "^0.4.1",
19 | "grunt-contrib-clean": "^0.5.0",
20 | "grunt-contrib-cssmin": "^0.10.0",
21 | "grunt-contrib-jshint": "~0.6.0",
22 | "grunt-contrib-nodeunit": "~0.2.0",
23 | "grunt-contrib-uglify": "~0.2.2"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/yar.js:
--------------------------------------------------------------------------------
1 |
2 | (function(window,undefined){
3 |
4 | function yar_exception(message){
5 | return 'Yar Exception:'+(message || 'unknow exception');
6 | }
7 |
8 | function random_id(){
9 | return 1000000 + (parseInt(Math.random() * 10000000));
10 | }
11 |
12 | function str_byte_length(str){
13 | var doubleByteChars = str.match(/[^\x00-\xfe]/ig);
14 | return str.length + (doubleByteChars == null ? 0 : doubleByteChars.length);
15 | }
16 |
17 | function Yar_Header(){
18 |
19 | this.struct = new CStruct.CStruct(
20 | {
21 | id : new CStruct.CVal('uint32',0),
22 | version : new CStruct.CVal('uint16',1),
23 | magic_number : new CStruct.CVal('uint32',0x80DFEC60),
24 | reserved : new CStruct.CVal('uint32',0),
25 | provider : new CStruct.CArray(32),
26 | token : new CStruct.CArray(32),
27 | body_len : new CStruct.CVal('uint32',0),
28 | pack : new CStruct.CVal('string','JSON\0\0\0\0'),
29 | body : new CStruct.CVal('string','')
30 | },
31 | ['id','version','magic_number','reserved','provider','token','body_len','pack','body']
32 | );
33 |
34 |
35 |
36 | }
37 |
38 | Yar_Header.prototype.create = function(body){
39 | if('object' == typeof body){
40 | body = JSON.stringify(body);
41 | }
42 | this.struct.get('body_len').val = body.length;
43 | this.struct.get('body').val = body;
44 | this.struct.get('id').val =123456789;
45 | return this.struct.raw();
46 | }
47 |
48 | function YarClient(server){
49 | this.address = server;
50 | }
51 |
52 | YarClient.prototype.call = function(method,parmters,callback){
53 | var _request = {
54 | i:123456789,
55 | 'm':(''+method),
56 | 'p':parmters || []
57 | };
58 | var _header = new Yar_Header();
59 | _header.id = _request['id'];
60 | var _send = _header.create(_request);
61 | var exchange=new XMLHttpRequest();
62 | exchange.onreadystatechange = function () {
63 | if (exchange.readyState == 4) {
64 | var _str = exchange.responseText;
65 | var response = _str.substr(90,_str.length - 89);
66 | response = JSON.parse(response);
67 | if('object' != typeof response){
68 | // throw yar_exception("yar protocol parse error!");
69 | }
70 | if('undefined' != typeof response['e']){
71 | // throw yar_exception(response['e']);
72 | }
73 | if('function' == typeof callback){
74 | callback(response['r']);
75 | }
76 | }
77 | }
78 | exchange.open("POST",this.address,true);
79 | exchange.send(_send);
80 | }
81 |
82 | window.YarClient = YarClient;
83 | })(window,undefined);
--------------------------------------------------------------------------------