1 | var Base = require('../base')
|
2 | , Connector = require('./connector')
|
3 | , fs = require('fs')
|
4 | , socketIoPkgJson = require('socket.io-client/package.json')
|
5 |
|
6 | var debug = Base.logger('ix-publisher')
|
7 |
|
8 | var exportInfo
|
9 | var exportedProps
|
10 | var deviceData = null
|
11 | var _deviceData = false
|
12 |
|
13 |
|
14 | exports.publishAndFindProxy = function(ixApiDir, cb_err_data){
|
15 | loadIxExports(ixApiDir, function(err, methodInfo){
|
16 | if (err) { cb_err_data(err); return }
|
17 | publishExportsAndGetProxy(methodInfo, cb_err_data)
|
18 | })
|
19 | }
|
20 |
|
21 | var withDeviceData = exports.withDeviceData = function(cb_err_data){
|
22 | if (_deviceData) { cb_err_data(null, deviceData); return }
|
23 | _deviceData = true;
|
24 | deviceData = { secret: Base.env.IX_DEVICE_SECRET }
|
25 | if (Base.env.IX_DEVICE_KEY) {
|
26 | console.log('DEVICE KEY: '+Base.env.IX_DEVICE_KEY)
|
27 | deviceData.key = Base.env.IX_DEVICE_KEY
|
28 | cb_err_data(null, deviceData)
|
29 | }
|
30 | else if (Base.env.IX_DEVICE_KEY_FILE === 'NONE') {
|
31 | cb_err_data(null, deviceData)
|
32 | }
|
33 | else {
|
34 | fs.readFile(Base.env.IX_DEVICE_KEY_FILE || '/factory/serial_number', { encoding: 'utf8' }, function(err,file){
|
35 | debug('withDeviceKey', err, file)
|
36 | var key = null
|
37 | if (file) {
|
38 | key = file.split(/\n/)[0].trim()
|
39 | console.log('DEVICE KEY: '+key)
|
40 | }
|
41 | deviceData.key = key
|
42 | cb_err_data(err, deviceData)
|
43 | })
|
44 | }
|
45 | }
|
46 |
|
47 | exports.ixCallNodejs = function(callData, responder){
|
48 | debug('ixCallNodejs', callData)
|
49 | var func = findProp(callData.api)
|
50 | if (func) {
|
51 | exports.ixCall(callData, responder, function(cd, clientCallback){
|
52 | var args = cd.args.slice(0)
|
53 | args.push(clientCallback)
|
54 | func.apply({}, args)
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | })
|
70 | }
|
71 | else {
|
72 | debug('ixCallNodejs', "Property not exported: '"+callData.api+"'.")
|
73 | throw 'Invalid function: '+callData.api
|
74 | }
|
75 | }
|
76 |
|
77 | exports.ixCall = function(callData, responder, invoker){
|
78 | var timeoutSecs = Number(callData.timeout || Base.env.IX_PROXY_TIMEOUT)
|
79 | if (!(timeoutSecs > 0)) {
|
80 | timeoutSecs = 30
|
81 | }
|
82 | var wait = timeoutSecs * 1000
|
83 | var timerOn = true
|
84 | var timer = setTimeout(function(){
|
85 | if (timerOn) {
|
86 | timerOn = false
|
87 | var err = 'TIMEOUT: Callback not invoked after '+(wait/1000)+' seconds, aborting. (Start server with the environment variable FAAS_IX_PROXY_TIMEOUT set to customize the timeout.)'
|
88 | debug('ixCall', err)
|
89 | responder({ reason: err })
|
90 | }
|
91 | }, wait)
|
92 | var clientCallback = function(err, data){
|
93 | debug('clientCallback', { err: err, data: data })
|
94 | if (err instanceof Error) {
|
95 | err = {
|
96 | name: err.name,
|
97 | message: err.message
|
98 | }
|
99 | }
|
100 | if (timerOn) {
|
101 | timerOn = false
|
102 | clearTimeout(timer)
|
103 | responder(err, data)
|
104 | }
|
105 | }
|
106 | try {
|
107 | invoker(callData, clientCallback)
|
108 | }
|
109 | catch(e){
|
110 | clientCallback(e)
|
111 | }
|
112 | }
|
113 |
|
114 | var loadIxExports = function(ixApiDir, cb_err_exportInfo){
|
115 | exportInfo = {}
|
116 | exportedProps = {}
|
117 | var ixDirname = ixApiDir || Base.env.IX_API_DIR || 'faas-ix'
|
118 | var ixDir = process.cwd()+'/'+ixDirname
|
119 | fs.readdir(ixDir, function(err, files){
|
120 | debug('readdir', { err: err, files: files })
|
121 | if (err) { cb_err_exportInfo(err, files); return }
|
122 | var file, path, fexports, modName, meta
|
123 | for (var i = 0; i < files.length; i++) {
|
124 | file = files[i]
|
125 | path = ixDir+'/'+file
|
126 | try {
|
127 | if (file.match(/\w$/)) {
|
128 | fexports = require(path)
|
129 | debug('loadIxExports:file', file, fexports)
|
130 | modName = file
|
131 | modName = modName.replace(/\.(js|json|node)$/i, '')
|
132 | modName = modName.replace(/\W/g, '_')
|
133 | meta = exportInfo[modName]
|
134 | if (exportInfo[modName]) {
|
135 | console.log("Multiple definitions found for module '"+modName+"', only using definitions from file '"+meta.file+"' (discarding '"+file+"').")
|
136 | }
|
137 | else {
|
138 | exportInfo[modName] = { file: file, exports: metaForObj(fexports) }
|
139 | exportedProps[modName] = fexports
|
140 | }
|
141 | }
|
142 | }
|
143 | catch(e) {
|
144 | console.log('Unable to load module '+path+':', e)
|
145 | }
|
146 | }
|
147 | debug('loadIxExports:exportInfo', JSON.stringify(exportInfo))
|
148 | cb_err_exportInfo(null, exportInfo)
|
149 | })
|
150 | }
|
151 |
|
152 | var metaForObj = function(obj){
|
153 | var info
|
154 | var attName, att, metaInfo
|
155 | if (Base.utils.isFobject(obj)) {
|
156 | info = { isFunc: Base.utils.isFunction(obj) }
|
157 | if (Base.utils.isFunction(obj)) {
|
158 | info.isFunc = true
|
159 | }
|
160 | for (attName in obj) { if (obj.hasOwnProperty(attName)) {
|
161 | if (!info.atts) { info.atts = {} }
|
162 | att = obj[attName]
|
163 | metaInfo = metaForObj(att)
|
164 | info.atts[attName] = metaInfo
|
165 | } }
|
166 | }
|
167 | else {
|
168 | info = { value: obj }
|
169 | }
|
170 |
|
171 | return info
|
172 | }
|
173 |
|
174 | var publishExportsAndGetProxy = exports.publishExportsAndGetProxy = function(exportInfo, cb_err_data) {
|
175 | debug('sioVer', socketIoPkgJson.version)
|
176 | withDeviceData(function(err, device){
|
177 | Base.api({
|
178 | url: { pathname: '/ix/publishAndProxy', query: { sioVer: socketIoPkgJson.version } }
|
179 | , data: { exportInfo: exportInfo, device: device }
|
180 | , method: 'POST'
|
181 | }, cb_err_data)
|
182 | })
|
183 | }
|
184 |
|
185 | exports.publishHttpAndFindProxy = function(cb_err_data) {
|
186 | debug('sioVer', socketIoPkgJson.version)
|
187 | withDeviceData(function(err, device){
|
188 | Base.api({
|
189 | url: { pathname: '/ix/httpAndProxy', query: { sioVer: socketIoPkgJson.version } }
|
190 | , data: { device: device }
|
191 | , method: 'POST'
|
192 | }, cb_err_data)
|
193 | })
|
194 | }
|
195 |
|
196 | var findProp = function(name){
|
197 | var names = name.split('.')
|
198 | return findPropHelper(names, exportedProps)
|
199 | }
|
200 |
|
201 | var findPropHelper = function(names, props){
|
202 | var name = names.shift()
|
203 | var prop = props[name]
|
204 | if (prop && names.length > 0) {
|
205 | prop = findPropHelper(names, prop)
|
206 | }
|
207 | return prop
|
208 | }
|