/
sherpajs.go
136 lines (118 loc) · 3.05 KB
/
sherpajs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package sherpa
var sherpaJS = `
'use strict';
(function(undefined) {
var sherpa = {};
// prepare basic support for promises.
// we return functions with a "then" method only. our "then" isn't chainable. and you don't get other promise-related methods.
// but this "then" is enough so your browser's promise library (or a polyfill) can turn it into a real promise.
function thenable(fn) {
var settled = false;
var fulfilled = false;
var result = null;
var goods = [];
var bads = [];
// promise lib will call the returned function, make it the same as our .then function
var nfn = function(goodfn, badfn) {
if(settled) {
if(fulfilled && goodfn) {
goodfn(result);
}
if(!fulfilled && badfn) {
badfn(result);
}
} else {
if(goodfn) {
goods.push(goodfn);
}
if(badfn) {
bads.push(badfn);
}
}
};
nfn.then = nfn;
function done() {
while(fulfilled && goods.length > 0) {
goods.shift()(result);
}
while(!fulfilled && bads.length > 0) {
bads.shift()(result);
}
}
function makeSettle(xfulfilled) {
return function(arg) {
if(settled) {
return;
}
settled = true;
fulfilled = xfulfilled;
result = arg;
done();
};
}
var resolve = makeSettle(true);
var reject = makeSettle(false);
try {
fn(resolve, reject);
} catch(e) {
reject(e);
}
return nfn;
}
function postJSON(url, param, success, error) {
var req = new window.XMLHttpRequest();
req.open('POST', url, true);
req.onload = function onload() {
if(req.status >= 200 && req.status < 400) {
success(JSON.parse(req.responseText));
} else {
if(req.status === 404) {
error({code: 'sherpaBadFunction', message: 'function does not exist'});
} else {
error({code: 'sherpaHttpError', message: 'error calling function, HTTP status: '+req.status});
}
}
};
req.onerror = function onerror() {
error({code: 'sherpaClientError', message: 'connection failed'});
};
req.setRequestHeader('Content-Type', 'application/json');
req.send(JSON.stringify(param));
}
function makeFunction(api, name) {
return function() {
var params = Array.prototype.slice.call(arguments, 0);
return api._wrapThenable(thenable(function(resolve, reject) {
postJSON(api._sherpa.baseurl+name, {params: params}, function(response) {
if(response && response.error) {
reject(response.error);
} else if(response && response.hasOwnProperty('result')) {
resolve(response.result);
} else {
reject({code: 'sherpaBadResponse', message: "invalid sherpa response object, missing 'result'"});
}
}, reject);
}));
};
}
sherpa.init = function init(_sherpa) {
var api = {};
function _wrapThenable(thenable) {
return thenable;
}
function _call(name) {
return makeFunction(api, name).apply(Array.prototype.slice.call(arguments, 1));
}
api._sherpa = _sherpa;
api._wrapThenable = _wrapThenable;
api._call = _call;
for(var i = 0; i < _sherpa.functions.length; i++) {
var fn = _sherpa.functions[i];
api[fn] = makeFunction(api, fn);
}
return api;
};
var _sherpa = {{.sherpaJSON}};
window[_sherpa.id] = sherpa.init(_sherpa);
})();
`