@naanlang/naan 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +46 -0
- package/dist/env_web.js +431 -0
- package/dist/naan.min.js +73 -0
- package/frameworks/browser/browser.nlg +30 -0
- package/frameworks/browser/pouchdb/pouchdb.min.js +7 -0
- package/frameworks/browser/spark-md5/spark-md5.min.js +1 -0
- package/frameworks/browser/sworker.js +192 -0
- package/frameworks/browser/terminals.nlg +787 -0
- package/frameworks/browser/workers.nlg +386 -0
- package/frameworks/client/apiclient.nlg +183 -0
- package/frameworks/client/client.nlg +29 -0
- package/frameworks/client/psm_client.nlg +572 -0
- package/frameworks/common/common.nlg +464 -0
- package/frameworks/common/preferences.nlg +131 -0
- package/frameworks/common/repltools.nlg +100 -0
- package/frameworks/common/watching.nlg +97 -0
- package/frameworks/node/apiserver.nlg +399 -0
- package/frameworks/node/filesystem.nlg +1012 -0
- package/frameworks/node/gitter.nlg +234 -0
- package/frameworks/node/node.nlg +81 -0
- package/frameworks/node/psm_server.nlg +465 -0
- package/frameworks/node/worker.nlg +560 -0
- package/frameworks/project/build.nlg +1229 -0
- package/frameworks/project/jszip.js +30 -0
- package/frameworks/project/jszip.nlg +87 -0
- package/frameworks/project/proj_cliser.nlg +139 -0
- package/frameworks/project/proj_console.nlg +137 -0
- package/frameworks/project/proj_folder.nlg +143 -0
- package/frameworks/project/proj_lambda.nlg +137 -0
- package/frameworks/project/proj_static.nlg +138 -0
- package/frameworks/project/project.nlg +29 -0
- package/frameworks/project/projects.nlg +587 -0
- package/frameworks/project/uglifyjs.js +1 -0
- package/frameworks/project/uglifyjs.nlg +79 -0
- package/frameworks/running/debugcom.nlg +163 -0
- package/frameworks/running/debugnub.nlg +565 -0
- package/frameworks/running/debugutil.nlg +510 -0
- package/frameworks/running/executors.nlg +767 -0
- package/frameworks/running/running.nlg +151 -0
- package/frameworks/running/sourcecode.nlg +346 -0
- package/frameworks/running/taskexec.nlg +196 -0
- package/frameworks/storage/dbt_pouch.nlg +773 -0
- package/frameworks/storage/file_manager.nlg +772 -0
- package/frameworks/storage/psm.nlg +326 -0
- package/frameworks/storage/psm_dbtables.nlg +814 -0
- package/frameworks/storage/resources.nlg +445 -0
- package/frameworks/storage/storage.nlg +52 -0
- package/lib/browser/env_web.js +431 -0
- package/lib/browser/env_webworker.js +146 -0
- package/lib/browser/require.js +1653 -0
- package/lib/core/naanlib.js +73 -0
- package/lib/env_node.js +282 -0
- package/lib/env_nodeworker.js +165 -0
- package/lib/node_repl.js +25 -0
- package/lib/node_repl_init.nlg +52 -0
- package/package.json +13 -0
- package/plugins/gitClient/clientops.nlg +317 -0
- package/plugins/gitClient/gitClient.nlg +63 -0
- package/plugins/gitClient/gitutils.nlg +1331 -0
- package/plugins/gitClient/minimatch.js +945 -0
- package/plugins/gitClient/minimatch_license.txt +15 -0
- package/plugins/gitClient/minimatch_readme.md +208 -0
- package/plugins/nodeLib/nodeLib.nlg +26 -0
- package/plugins/nodeLib/node_cp.nlg +65 -0
- package/plugins/nodeLib/node_fs.nlg +137 -0
- package/plugins/nodeLib/node_https.nlg +172 -0
- package/plugins/nodeLib/node_util.nlg +180 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +88 -0
- package/plugins/serviceAws/aws/lambda_rest_index.js +122 -0
- package/plugins/serviceAws/aws/lambda_rest_init.nlg +58 -0
- package/plugins/serviceAws/aws/lambda_ws_index.js +498 -0
- package/plugins/serviceAws/aws/lambda_ws_init.nlg +49 -0
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +122 -0
- package/plugins/serviceAws/aws_cognito.nlg +76 -0
- package/plugins/serviceAws/aws_dynamo.nlg +509 -0
- package/plugins/serviceAws/aws_lambda.nlg +95 -0
- package/plugins/serviceAws/aws_s3.nlg +134 -0
- package/plugins/serviceAws/aws_utils.nlg +86 -0
- package/plugins/serviceAws/dbt_aws.nlg +769 -0
- package/plugins/serviceAws/lambda_naan_control.nlg +175 -0
- package/plugins/serviceAws/psm_aws.nlg +258 -0
- package/plugins/serviceAws/serviceAws.nlg +38 -0
- package/plugins/serviceGitHub/gitops.nlg +522 -0
- package/plugins/serviceGitHub/psm_github.nlg +205 -0
- package/plugins/serviceGitHub/serviceGitHub.nlg +65 -0
- package/plugins/serviceGitLab/gitops.nlg +528 -0
- package/plugins/serviceGitLab/psm_gitlab.nlg +205 -0
- package/plugins/serviceGitLab/serviceGitLab.nlg +65 -0
- package/test/harness.nlg +312 -0
- package/test/node_test.js +33 -0
- package/test/test_01_core.nlg +768 -0
- package/test/test_02_context.nlg +269 -0
- package/test/test_03_jsinterop.nlg +137 -0
- package/test/test_04_numerics.nlg +450 -0
- package/test/test_05_strings.nlg +63 -0
- package/test/test_06_lingoparse.nlg +500 -0
- package/test/test_07_lingo.nlg +623 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* watching.nlg
|
|
3
|
+
* naanlib/frameworks/common/watching
|
|
4
|
+
*
|
|
5
|
+
* A simple notificaiton system to broadcast change to interested parties.
|
|
6
|
+
*
|
|
7
|
+
* column positioning: // // !
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2019-2021 by Richard C. Zulch
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* Watchable
|
|
16
|
+
*
|
|
17
|
+
* Watchable objects provide a common protocol to broadcast change notifications and to allow
|
|
18
|
+
* interested parties to subscribe using register and unregister. A watchable is an instance for a
|
|
19
|
+
* particular broadcast topic. Watchers are procedures that subscribe to a watchable to be notified.
|
|
20
|
+
* The owner of the watchable is responsible for telling it about changes by calling the notify
|
|
21
|
+
* method with a changes dictionary. Each notification can report any number of changes to multiple
|
|
22
|
+
* items.
|
|
23
|
+
*
|
|
24
|
+
* A {changes} dictionary has the following structure, where each field is optional:
|
|
25
|
+
* {
|
|
26
|
+
* added: [<item>,<item>...<item>]
|
|
27
|
+
* changed: [<item>,<item>...<item>]
|
|
28
|
+
* deleted: [<item>,<item>...<item>]
|
|
29
|
+
* <custom>: [<item>,<item>...<item>]
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
closure Watchable(local watch, watchers) {
|
|
35
|
+
watch = new(object, this)
|
|
36
|
+
reset()
|
|
37
|
+
|
|
38
|
+
// notify
|
|
39
|
+
//
|
|
40
|
+
// Notify watchers using:
|
|
41
|
+
// watcher(classID, {changes})
|
|
42
|
+
watch.notify = function notify(classID, changes, local watcher) {
|
|
43
|
+
for watcher in watchers
|
|
44
|
+
call(watcher, classID, changes)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// watch
|
|
48
|
+
//
|
|
49
|
+
// Call the specified watch function after changes occur:
|
|
50
|
+
// watcher(classID, {changes})
|
|
51
|
+
watch.watch = function watch(proc, local wadex) {
|
|
52
|
+
wadex = watchers.findIndex(function(item) {
|
|
53
|
+
item eq proc
|
|
54
|
+
})
|
|
55
|
+
if wadex < 0
|
|
56
|
+
watchers.push(proc)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// unWatch
|
|
60
|
+
//
|
|
61
|
+
// Stop calling the specified watch function after changes occur.
|
|
62
|
+
watch.unWatch = function unWatch(proc, local wadex) {
|
|
63
|
+
wadex = watchers.findIndex(function(item) {
|
|
64
|
+
item eq proc
|
|
65
|
+
})
|
|
66
|
+
if wadex >= 0
|
|
67
|
+
watchers.splice(wadex)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// reset
|
|
71
|
+
//
|
|
72
|
+
// Reset the watch list.
|
|
73
|
+
watch.reset = function reset() {
|
|
74
|
+
watchers = []
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// finis
|
|
78
|
+
watch
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* wachInit
|
|
84
|
+
*
|
|
85
|
+
* Initialize the component.
|
|
86
|
+
*
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
function wachInit(local manifest) {
|
|
90
|
+
manifest = `(Watchable, wachInit)
|
|
91
|
+
|
|
92
|
+
Naan.module.build(module.id, "watching", function(modobj, compobj) {
|
|
93
|
+
require("./common.nlg")
|
|
94
|
+
compobj.manifest = manifest
|
|
95
|
+
module.exports.Watchable = Watchable
|
|
96
|
+
})
|
|
97
|
+
} ();
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* apiserver.nlg
|
|
3
|
+
* Naanlib/frameworks/node
|
|
4
|
+
*
|
|
5
|
+
* NaanIDE API server with HTTP using Expressjs.
|
|
6
|
+
*
|
|
7
|
+
* column positioning: // // !
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2017-2021 by Richard C. Zulch
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* MakeAPI
|
|
16
|
+
*
|
|
17
|
+
* Make an API server object.
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
closure MakeAPI(port, options, callback, local chroot, server) {
|
|
22
|
+
if !options
|
|
23
|
+
options = { }
|
|
24
|
+
else
|
|
25
|
+
options = new(options)
|
|
26
|
+
if !options.relpath
|
|
27
|
+
options.relpath = ""
|
|
28
|
+
|
|
29
|
+
chroot = JSpath.join(js.d, options.relpath)
|
|
30
|
+
if not string(chroot) || chroot.length < 2 {
|
|
31
|
+
debuglog("APIserver: invalid path", chroot)
|
|
32
|
+
return (false)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
server = new(object, this)
|
|
36
|
+
server.psm = require("./psm_server.nlg").MakeServerPSM(server)
|
|
37
|
+
server.root = chroot
|
|
38
|
+
server.app = express()
|
|
39
|
+
server.notifyq = []
|
|
40
|
+
server.responseq = []
|
|
41
|
+
server.projects = { }
|
|
42
|
+
|
|
43
|
+
// close
|
|
44
|
+
//
|
|
45
|
+
// Close the server.
|
|
46
|
+
|
|
47
|
+
server.close = function close() {
|
|
48
|
+
if server.ws
|
|
49
|
+
server.ws.close()
|
|
50
|
+
server.http.close(function(){debuglog("API Server closed")})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Register
|
|
54
|
+
//
|
|
55
|
+
// Register a subsystem to receive websocket messages from client connections. The caller will
|
|
56
|
+
// have the wsReceive method invoked:
|
|
57
|
+
// wsReceive(message, conn)
|
|
58
|
+
// And can send a reply on the specified connection.
|
|
59
|
+
|
|
60
|
+
server.Register = function Register(serverID, subsystem) {
|
|
61
|
+
server.ws.subsystems[serverID] = subsystem
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//
|
|
65
|
+
// status and message notification
|
|
66
|
+
//
|
|
67
|
+
|
|
68
|
+
function notifyReaper(maxage, local oldest) {
|
|
69
|
+
oldest = Date.now() - maxage
|
|
70
|
+
server.notifyq = server.notifyq.filter(function(item,index,array){
|
|
71
|
+
item.stamp >= oldest
|
|
72
|
+
})
|
|
73
|
+
server.responseq.forEach(function(item,index,array){
|
|
74
|
+
item.poll()
|
|
75
|
+
})
|
|
76
|
+
server.responseq = server.responseq.filter(function(item,index,array){
|
|
77
|
+
item.active
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
// Notification responses are only removed from the response queue by the reaper, which means
|
|
81
|
+
// that the reaper must run periodically so that they don't accumulate if no new messages are
|
|
82
|
+
// created for a long period. Note that responses don't delete themselves from the queue when
|
|
83
|
+
// they complete because that can happen inside responseq.forEach(), which could be quite bad.
|
|
84
|
+
// A response timeout can even happen inside the forEach, so it's safest just to remove the
|
|
85
|
+
// responses in one place.
|
|
86
|
+
closure scheduleReaper(interval) {
|
|
87
|
+
future(function reaper(){ scheduleReaper(interval), notifyReaper(interval) }, interval)
|
|
88
|
+
} (30000)
|
|
89
|
+
|
|
90
|
+
server.notify = function notify(message) {
|
|
91
|
+
if not dictionary(message)
|
|
92
|
+
message = {type: "status", message: message}
|
|
93
|
+
message.stamp = Date.now()
|
|
94
|
+
server.notifyq.push(message)
|
|
95
|
+
notifyReaper(30000)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//
|
|
99
|
+
// body parsing
|
|
100
|
+
//
|
|
101
|
+
|
|
102
|
+
server.app.use(bodyParser.text({limit: "20mb"}))
|
|
103
|
+
server.app.use(bodyParser.raw({limit: "20mb"}))
|
|
104
|
+
|
|
105
|
+
//
|
|
106
|
+
// Express.js endpoints
|
|
107
|
+
//
|
|
108
|
+
|
|
109
|
+
server.app.use(function(req,res,next) {
|
|
110
|
+
res.header("Access-Control-Allow-Origin", "*")
|
|
111
|
+
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
|
|
112
|
+
next()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
server.app.use("", express.static(chroot))
|
|
116
|
+
let (pathpair) {
|
|
117
|
+
for pathpair in options.statics
|
|
118
|
+
server.app.use(pathpair.0, express.static(pathpair.1))
|
|
119
|
+
}()
|
|
120
|
+
|
|
121
|
+
// "/"
|
|
122
|
+
|
|
123
|
+
server.app.get("/", function(req, res) {
|
|
124
|
+
res.send("<u>NaanIDE API</u><br>\r\n"
|
|
125
|
+
" /readfile?path=<i>filepath</i><br>\r\n"
|
|
126
|
+
" /status?timeout=<i>msec</i>&after=<i>stamp</i><br>\r\n")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// "/readfile"
|
|
130
|
+
|
|
131
|
+
server.app.get("/readfile", closure(req, res) {
|
|
132
|
+
if not string(req.query.path)
|
|
133
|
+
res.status(400).send("Invalid filename")
|
|
134
|
+
else if RegExp("^\\.\\.[/\\\\]|[/\\\\]\\.\\.$|[/\\\\]\\.\\.[/\\\\]").test(req.query.path)
|
|
135
|
+
res.status(403).send("\"Parent path references forbidden\"")
|
|
136
|
+
else
|
|
137
|
+
closure (local filepath, options) {
|
|
138
|
+
filepath = req.query.path
|
|
139
|
+
options = {
|
|
140
|
+
dotfiles: "allow"
|
|
141
|
+
}
|
|
142
|
+
if filepath.charAt(0) != JSpath.sep
|
|
143
|
+
options.root = chroot
|
|
144
|
+
res.sendFile(filepath, options, function (err, local status) {
|
|
145
|
+
if err {
|
|
146
|
+
if err.code == "ENOENT"
|
|
147
|
+
status = 404
|
|
148
|
+
else
|
|
149
|
+
status = 500
|
|
150
|
+
res.status(status).end()
|
|
151
|
+
ErrorDebuglog(Error("Server: /readfile", filepath, err))
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
}()
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// "/status"
|
|
158
|
+
|
|
159
|
+
server.app.get("/status", closure(req,res, local timeoutms, after, responder) {
|
|
160
|
+
timeoutms = toint(req.query.timeout)
|
|
161
|
+
after = toint(req.query.after)
|
|
162
|
+
if not integer(timeoutms) or timeoutms > 10000
|
|
163
|
+
res.status(400).send("timeout is integer milliseconds no greater than 10000")
|
|
164
|
+
else if not integer(after)
|
|
165
|
+
res.status(400).send("after must be an integer")
|
|
166
|
+
else {
|
|
167
|
+
responder = new(dictionary)
|
|
168
|
+
responder.active = true
|
|
169
|
+
responder.poll = function(timeout, local queued) {
|
|
170
|
+
if responder.active {
|
|
171
|
+
queued = server.notifyq.filter(function(item,index,array) { item.stamp > after })
|
|
172
|
+
if queued.length > 0
|
|
173
|
+
res.send(js.g.JSON.stringify(queued))
|
|
174
|
+
else if timeout
|
|
175
|
+
res.status(200).end()
|
|
176
|
+
else
|
|
177
|
+
return (true)
|
|
178
|
+
}
|
|
179
|
+
responder.active = false
|
|
180
|
+
}
|
|
181
|
+
if responder.poll() {
|
|
182
|
+
future(function poll(){ responder.poll(true) }, timeoutms)
|
|
183
|
+
server.responseq.push(responder)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
// "/psm"
|
|
189
|
+
|
|
190
|
+
server.app.all("/psm", closure(req, res) {
|
|
191
|
+
if !server.hostfs
|
|
192
|
+
res.status(503).send("host filesystem not available")
|
|
193
|
+
else
|
|
194
|
+
server.hostfs.api(req, res)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
//
|
|
198
|
+
// initialize the server
|
|
199
|
+
//
|
|
200
|
+
|
|
201
|
+
let(local pending, result) {
|
|
202
|
+
pending = new(nonce)
|
|
203
|
+
|
|
204
|
+
// find our port
|
|
205
|
+
|
|
206
|
+
loop {
|
|
207
|
+
server.http = server.app.listen(port, function(){
|
|
208
|
+
pending.signal({}) // success
|
|
209
|
+
}).on("error", function (err) {
|
|
210
|
+
if err.code == "EADDRINUSE"
|
|
211
|
+
++port // try next port
|
|
212
|
+
else {
|
|
213
|
+
pending.result = Error("server listen error", err) // permanent failure
|
|
214
|
+
callback(err, false)
|
|
215
|
+
}
|
|
216
|
+
pending.signal(pending.result)
|
|
217
|
+
})
|
|
218
|
+
if pending.wait()
|
|
219
|
+
break
|
|
220
|
+
pending.reset()
|
|
221
|
+
}
|
|
222
|
+
if pending.result
|
|
223
|
+
return (false) // failed to open
|
|
224
|
+
|
|
225
|
+
// start the services
|
|
226
|
+
|
|
227
|
+
server.ws = WebSocketServer(server)
|
|
228
|
+
server.port = port
|
|
229
|
+
callback(false, port, server) // notify of success
|
|
230
|
+
debuglog("server open on port", port)
|
|
231
|
+
result = server.psm.conns.NodeFS.connect("Host", "NideFS", list("")) // ### this should go through resource tracker
|
|
232
|
+
if result.0
|
|
233
|
+
ErrorDebuglog(Error("can't access HostFS", result.0))
|
|
234
|
+
else
|
|
235
|
+
server.hostfs = result.1
|
|
236
|
+
}()
|
|
237
|
+
|
|
238
|
+
// return new API server object
|
|
239
|
+
server
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
/*
|
|
244
|
+
* WebSocketServer
|
|
245
|
+
*
|
|
246
|
+
* WebSocket server objects. This is used by the HTTP server for websocket communications.
|
|
247
|
+
*
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
closure WebSocketServer(server, local websocks) {
|
|
251
|
+
websocks = new(object, this)
|
|
252
|
+
websocks.conns = [] // our connections
|
|
253
|
+
websocks.subsystems = { } // registered subsystems
|
|
254
|
+
websocks.wss = xnew(ws.Server, { noServer: true })
|
|
255
|
+
|
|
256
|
+
// Server upgrade handler
|
|
257
|
+
|
|
258
|
+
server.http.on("upgrade", function(request, socket, head) {
|
|
259
|
+
websocks.wss.handleUpgrade(request, socket, head, function (csock) {
|
|
260
|
+
websocks.wss.emit("connection", csock, request)
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
// Event handlers
|
|
265
|
+
|
|
266
|
+
websocks.wss.on("connection", function(socket, request) {
|
|
267
|
+
websocks.conns.push(WesCon(websocks, socket, request))
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
server.wss.on("error", function(error) {
|
|
271
|
+
ErrorDebuglog(Error("ws server error:", error))
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
server.wss.on("close", function() {
|
|
275
|
+
debuglog("WebSocketServer has closed")
|
|
276
|
+
websocks.closed = true // note that we are closed
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
// closeConn
|
|
280
|
+
// respond to connection closing
|
|
281
|
+
|
|
282
|
+
websocks.closeConn = function closeConn(conn) {
|
|
283
|
+
websocks.conns = websocks.conns.filter(function(item) {
|
|
284
|
+
!(item eq conn)
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// finis
|
|
289
|
+
websocks
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
/*
|
|
294
|
+
* WesCon
|
|
295
|
+
*
|
|
296
|
+
* WebSocket socket objects, which represent a connection with a particular client. These are
|
|
297
|
+
* created automatically by an API server instance when a client connects. The protocol is JSON with
|
|
298
|
+
* the top level being a dictionary having the following static keys specified by the client:
|
|
299
|
+
* serverID: defined by the server, this string defines where requests should be routed.
|
|
300
|
+
* clientID: defined by the client, this string defines where replies should be sent.
|
|
301
|
+
* These are class (code) designators. Further keys can be defined to identify a specific instance on
|
|
302
|
+
* the client or server.
|
|
303
|
+
*
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
closure WesCon(websocks, socket, request, local wescon) {
|
|
307
|
+
wescon = new(object, this)
|
|
308
|
+
wescon.socket = socket
|
|
309
|
+
wescon.serverIDs = []
|
|
310
|
+
|
|
311
|
+
// on message
|
|
312
|
+
//
|
|
313
|
+
// Incoming data.
|
|
314
|
+
|
|
315
|
+
socket.on("message", function onmessage(text, local message, error) {
|
|
316
|
+
try {
|
|
317
|
+
message = new(js.g.JSON.parse(text))
|
|
318
|
+
if message.clientID && websocks.subsystems[message.serverID] {
|
|
319
|
+
wescon.serverIDs.push(message.serverID) // ### track subsystems for closing
|
|
320
|
+
websocks.subsystems[message.serverID].wsReceive(message, wescon)
|
|
321
|
+
}
|
|
322
|
+
else
|
|
323
|
+
error = Error("can't route message")
|
|
324
|
+
} catch {
|
|
325
|
+
if true
|
|
326
|
+
error = Error("can't decode message JSON", exception)
|
|
327
|
+
}
|
|
328
|
+
if error
|
|
329
|
+
socket.send(js.g.JSON.stringify([error]))
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
// on error
|
|
333
|
+
//
|
|
334
|
+
// Error has occurred on this connection.
|
|
335
|
+
|
|
336
|
+
socket.on("error", function onerror(error) {
|
|
337
|
+
debuglog("connection error", error)
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
// on close
|
|
341
|
+
//
|
|
342
|
+
// Connection has closed.
|
|
343
|
+
|
|
344
|
+
socket.on("close", function onclose(code, reason, local serverID) {
|
|
345
|
+
if code != 1000 && code != 1001 && code != 1005
|
|
346
|
+
debuglog("connection has closed:", code, reason)
|
|
347
|
+
websocks.closeConn(wescon)
|
|
348
|
+
wecson.closed = {
|
|
349
|
+
code: code
|
|
350
|
+
reason: reason
|
|
351
|
+
}
|
|
352
|
+
for serverID in wescon.serverIDs
|
|
353
|
+
websocks.subsystems[message.serverID].wsClose(wescon) // notify of our closures
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
// send
|
|
357
|
+
//
|
|
358
|
+
// Send a dictionary, which must have a clientID defined.
|
|
359
|
+
|
|
360
|
+
wescon.send = function send(message) {
|
|
361
|
+
if !message.clientID || !message.serverID
|
|
362
|
+
throw("Wescon.send: client and server IDs required")
|
|
363
|
+
if wescon.closed
|
|
364
|
+
list(Error("Socket connection closed", wescon.closed))
|
|
365
|
+
socket.send(js.g.JSON.stringify(message)),
|
|
366
|
+
[false, {ok: true}]
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// finis
|
|
370
|
+
wescon
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
/*
|
|
375
|
+
* ApisInit
|
|
376
|
+
*
|
|
377
|
+
* Initialize the module.
|
|
378
|
+
*
|
|
379
|
+
*/
|
|
380
|
+
|
|
381
|
+
function ApisInit(local manifest) {
|
|
382
|
+
|
|
383
|
+
manifest = `(MakeAPI, WebSocketServer, WesCon, ApisInit)
|
|
384
|
+
|
|
385
|
+
Naan.module.build(module.id, "API", function(modobj, compobj) {
|
|
386
|
+
require("./node.nlg")
|
|
387
|
+
compobj.manifest = manifest
|
|
388
|
+
modobj.exports.MakeAPI = MakeAPI
|
|
389
|
+
|
|
390
|
+
express = js.r("express")
|
|
391
|
+
bodyParser = js.r("body-parser")
|
|
392
|
+
textParser = bodyParser.text()
|
|
393
|
+
ws = js.r("ws")
|
|
394
|
+
|
|
395
|
+
require("./filesystem.nlg")
|
|
396
|
+
require("./psm_server.nlg")
|
|
397
|
+
require("./worker.nlg")
|
|
398
|
+
})
|
|
399
|
+
}();
|