diff --git a/.travis.yml b/.travis.yml index ebac674..3a1a3a5 100755 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,10 @@ language: node_js dist: trusty node_js: - - node + - '10' + - '9' + - '8' + - '6' addons: apt: @@ -39,6 +42,6 @@ deploy: on: branch: master tags: true - node: node + node: '10' api_key: secure: kkdWKa9iqJNKrfvW1pLgVx0EUBGcx+VGOzKG7xvxSfpNudZpuoGjWL4p9fQQD5TRELGwY7KCpFfZPbp2dnHQ9z82lW2XmnEC+bcskmfO/PXLJi3uyLrEY7iBwR3UhiWSdKRaPptfnndQrC21jmlweJNMCTWW8VqgvYupYITf9mfIq0WbEmFMeXJr7KzRO1yX4uAOOqnSTb60uRSrg+9V000cmDi246ir2ApaRw6NBOmI2v0kbirdbDe/vcAclgD2K0CFV7h8HIucbiU1DWBF2aQY3u5II4mItM4yskv0BmOr4vxXR0+7B/iysZNjWtXLbt4CiekvQKADUqPFpPk33LTjPxtAzdUYhHaoGTwchCIpkJG32KqTBL1+9h2I8WyhB3tKgxbFTZynkBihS2mYJad+rdO2RCXZtFZxf9bPWv6+PGelKnTFFBR9gPGTha4FeIeYZyuxuecAE7I+0UhS+wvwls3Xstro9fw+OwyvTysMEWOrjm1DvBuZyNnkqcfBKt3q4MOZsEHFnTEu6A1htr96FutAj/vap0e1RMokhMSIbe/hwq3whmELzWpRkOVDPEZfN47PCYc3f/UfYf0RMSWthibZOD30IX3207LsOgxZXfH3PDVcG9q0lvowGKWMcKy7d6+VVqgE97Aq7i07fizbpMWbNY7cStNy26m6IxM= diff --git a/appveyor.yml b/appveyor.yml index 64f8e9a..2883696 100755 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,18 +5,22 @@ skip_branch_with_pr: true image: Visual Studio 2017 environment: - nodejs_version: "10" + matrix: + - nodejs_version: "10" + - nodejs_version: "9" + - nodejs_version: "8" + - nodejs_version: "6" configuration: Release platform: x64 install: - - ps: Install-Product node $env:nodejs_version $env:platform + - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) + - node --version + - npm --version - npm install test_script: - - node --version - - npm --version - npm test after_test: @@ -37,3 +41,4 @@ deploy: secure: eMIAnmLDhZy2Sq/UAXB50fYr1C2BugaafN8XiV6Wur8wMvPLXWIuCKU7Jt/Y9Of6 on: appveyor_repo_tag: true + nodejs_version: "10" diff --git a/example/errors.js b/example/errors.js new file mode 100644 index 0000000..820f6f8 --- /dev/null +++ b/example/errors.js @@ -0,0 +1,50 @@ +const libui = require('..'); + +const win = new libui.UiWindow('Errors example', 320, 60, true); +win.margined = true; + +const msg = (err) => { + console.log('Another click will terminate the app.'); + process.removeListener('uncaughtException', msg); +}; + +process.on('uncaughtException', msg); + +const toolbar = new libui.UiHorizontalBox(); +const setEntryBtn = new libui.UiButton('Uncaught error'); +setEntryBtn.onClicked(() => { + throw new Error('ciao'); +}); +toolbar.append(setEntryBtn, false); +const setSearchBtn = new libui.UiButton('No errors'); +setSearchBtn.onClicked(() => { + console.log('clicked'); +}); +toolbar.append(setSearchBtn, false); +const setPasswordBtn = new libui.UiButton('Set password'); +setPasswordBtn.onClicked(() => {}); +toolbar.append(setPasswordBtn, false); + +const setSpinboxBtn = new libui.UiButton('Set number'); +setSpinboxBtn.onClicked(() => {}); +toolbar.append(setSpinboxBtn, false); + +const toggleReadOnlyBtn = new libui.UiButton('Set ReadOnly'); +toggleReadOnlyBtn.onClicked(() => { + + }); +toolbar.append(toggleReadOnlyBtn, false); + +const box = new libui.UiVerticalBox(); +box.padded = true; +box.append(toolbar); +win.setChild(box); + +win.onClosing(() => { + win.close(); + libui.stopLoop(); +}); + +win.show(); + +libui.startLoop(); diff --git a/example/event-loop.js b/example/event-loop.js index dd7e4ff..2b8ba59 100644 --- a/example/event-loop.js +++ b/example/event-loop.js @@ -128,7 +128,8 @@ function makeToolbar() { timeoutHandle = setTimeout((a, b, c) => { const elapsed = Date.now() - now; - logAppend(`Custom setTimeout: ${now} - elapsed ${elapsed} ms. Args: ${a} ${b} ${c}`); + logAppend(`Custom setTimeout: ${now} - elapsed ${elapsed} ms. Args: ${a} ${ + b} ${c}`); }, 1000, 'custom', 'args', 2); }); toolbar.append(btnCustom, false); @@ -144,7 +145,8 @@ function makeToolbar() { let now = Date.now(); intervalHandler = setInterval((a, b, c) => { const elapsed = Date.now() - now; - logAppend(`Custom setInterval: ${now} - elapsed ${elapsed} ms. Args: ${a} ${b} ${c}`); + logAppend(`Custom setInterval: ${now} - elapsed ${elapsed} ms. Args: ${a} ${ + b} ${c}`); now = Date.now(); }, 50, 'my', 'args', 2); }); diff --git a/example/forms.js b/example/forms.js index 74cce2b..9673c45 100644 --- a/example/forms.js +++ b/example/forms.js @@ -37,10 +37,6 @@ win.show(); libui.startLoop(); function setJSON() { - const data = { - name: name.text, - surname: surname.text, - age: age.value - }; + const data = {name: name.text, surname: surname.text, age: age.value}; JSONData.text = JSON.stringify(data, null, 4); } diff --git a/index.js b/index.js index 140cafa..9a34991 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ const libui = require(`${__dirname}/node_libui.node`); -const async_hooks = require('async_hooks'); +const async_hooks = require('@creditkarma/async-hooks'); const EventLoop = libui.EventLoop; delete libui.EventLoop; diff --git a/package-lock.json b/package-lock.json index d3be4a7..ab25807 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@creditkarma/async-hooks": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@creditkarma/async-hooks/-/async-hooks-0.0.4.tgz", + "integrity": "sha1-tbs0g/Ar9yw7LcDrojFm0/awoFg=" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", diff --git a/package.json b/package.json index 91d2085..33ae7f3 100755 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "GUI" ], "engines": { - "node": ">=8" + "node": ">=6.14.2" }, "libui": "alpha3.5-master-002", "scripts": { @@ -25,9 +25,10 @@ "install": "npm run --silent download-libui && npm run --silent download-libui-napi || npm run build", "test": "tape test.js", "precommit": "check-clang-format \"'npm run lint'\"", - "lint": "clang-format -i --glob='{js/*.js,src/**/*.{h,c,m},index.js,example.js,test.js,example/*/*.js}'" + "lint": "clang-format -i --glob='{example/*.js, js/*.js,src/**/*.{h,c,m},index.js,example.js,test.js,example/*/*.js,tools/*.js}'" }, "dependencies": { + "@creditkarma/async-hooks": "0.0.4", "home-path": "^1.0.5", "is-ci": "^1.1.0", "mkdirp": "^0.5.1", diff --git a/src/events.c b/src/events.c index 2c22a6e..73fc4d8 100644 --- a/src/events.c +++ b/src/events.c @@ -11,11 +11,11 @@ napi_value fire_event(struct event_t *event) { napi_value resource_object; status = napi_create_object(env, &resource_object); CHECK_STATUS_UNCAUGHT(status, napi_create_object, NULL); - - napi_callback_scope scope; - status = napi_open_callback_scope(env, resource_object, event->context, &scope); - CHECK_STATUS_UNCAUGHT(status, napi_open_callback_scope, NULL); - + /* + napi_callback_scope scope; + status = napi_open_callback_scope(env, resource_object, event->context, &scope); + CHECK_STATUS_UNCAUGHT(status, napi_open_callback_scope, NULL); + */ napi_value cb; status = napi_get_reference_value(env, event->cb_ref, &cb); CHECK_STATUS_UNCAUGHT(status, napi_get_reference_value, NULL); @@ -28,15 +28,20 @@ napi_value fire_event(struct event_t *event) { if (status == napi_pending_exception) { napi_value last_exception; napi_get_and_clear_last_exception(env, &last_exception); - napi_fatal_exception(env, last_exception); - return NULL; + napi_value stack; + size_t string_len = 5000; + char stack_str[5001]; + napi_get_named_property(env, last_exception, "stack", &stack); + napi_get_value_string_utf8(env, stack, stack_str, string_len + 1, &string_len); + napi_fatal_error("fire_event", NAPI_AUTO_LENGTH, stack_str, NAPI_AUTO_LENGTH); + return last_exception; } CHECK_STATUS_UNCAUGHT(status, napi_make_callback, NULL); - - status = napi_close_callback_scope(env, scope); - CHECK_STATUS_UNCAUGHT(status, napi_close_callback_scope, NULL); - + /* + status = napi_close_callback_scope(env, scope); + CHECK_STATUS_UNCAUGHT(status, napi_close_callback_scope, NULL); + */ status = napi_close_handle_scope(env, handle_scope); CHECK_STATUS_UNCAUGHT(status, napi_close_handle_scope, NULL); diff --git a/src/includes/napi_utils.h b/src/includes/napi_utils.h index 0f06889..5798a8d 100644 --- a/src/includes/napi_utils.h +++ b/src/includes/napi_utils.h @@ -154,11 +154,7 @@ NULL, &ret); \ char err[1024]; \ snprintf(err, 1024, #FN " failed with code %d: %s\n", result->engine_error_code, \ result->error_message); \ - napi_value error; \ - napi_value error_msg; \ - napi_create_string_utf8(env, err, NAPI_AUTO_LENGTH, &error_msg); \ - napi_create_error(env, NULL, error_msg, &error); \ - napi_fatal_exception(env, error); \ + napi_fatal_error("", NAPI_AUTO_LENGTH, err, NAPI_AUTO_LENGTH); \ return ERROR_RET; \ } diff --git a/tools/lib.js b/tools/lib.js new file mode 100644 index 0000000..d01a4aa --- /dev/null +++ b/tools/lib.js @@ -0,0 +1,80 @@ +const fs = require('fs'); +const path = require('path'); +const mv = require('mv'); +const https = require('https'); +const homePath = require('home-path'); +const mkdirp = require('mkdirp'); + +const debug = require('debug')('libui-download'); + +const requestHttps = url => new Promise((resolve, reject) => { + const req = https.get(url, resolve); + req.on('error', reject); +}); + +module.exports = function(project) { + const PROJECT = project.toUpperCase(); + return { + requestHttps, + mkCacheDir(cache) { + try { + mkdirp.sync(cache); + return cache; + } catch (err) { + if (err.code !== 'EACCES') { + debug('mkCacheDir error: ', err.stack); + throw err; + } + + // try local folder if homedir is off limits (e.g. some linuxes return '/' + // as homedir) + var localCache = path.resolve('./.' + project); + + mkdirp.sync(localCache); + return localCache; + } + }, + cacheDir(opts) { + opts = opts || {}; + var homeDir = homePath(); + return opts.cache || path.join(homeDir, './.' + project); + }, + buildUrl(opts, filename) { + var url = process.env[`NPM_CONFIG_${PROJECT}_MIRROR`] || + process.env[`${PROJECT}_MIRROR`] || opts.mirror || + `https://github.com/parro-it/${project}/releases/download/`; + + url += process.env[`${PROJECT}_CUSTOM_DIR`] || opts.customDir || opts.version; + url += '/'; + url += process.env[`${PROJECT}_CUSTOM_FILENAME`] || opts.customFilename || + filename; + return url; + }, + doDownload(res, url, target, cachedZip) { + if (res.statusCode !== 200) { + throw new Error(`Https request failed for ${ + res.headers.location} with code ${res.statusCode}.`); + } + + debug(`Https request for ${url} ok with code 200.`); + + const fileWrite = res.pipe(fs.createWriteStream(target)); + + return new Promise((resolve, reject) => { + const finish = () => { + debug('end stream reached', target, cachedZip); + mv(target, cachedZip, function(err) { + if (err) { + reject(err); + } else { + resolve(cachedZip); + } + }); + }; + + fileWrite.on('finish', finish); + fileWrite.on('error', reject); + }); + } + }; +}; \ No newline at end of file diff --git a/tools/libui-download.js b/tools/libui-download.js index 180e45d..2617127 100644 --- a/tools/libui-download.js +++ b/tools/libui-download.js @@ -2,88 +2,49 @@ const fs = require('fs'); const os = require('os'); const path = require('path'); const mkdirp = require('mkdirp'); -const homePath = require('home-path'); -const mv = require('mv'); const _debug = require('debug'); -const https = require('https'); const tar = require('tar'); -const utils = require('util'); +const {mkCacheDir, cacheDir, buildUrl, requestHttps, doDownload} = + require('./lib')('libui'); -const mkdir = utils.promisify(mkdirp) const debug = _debug('libui-download'); -const requestHttps = url => new Promise((resolve, reject) => { - const req = https.get(url, resolve); - req.on('error', reject); -}); - -const pathExists = utils.promisify(fs.exists); function nodePlatformToOS(arch) { switch (arch) { - case 'darwin': return 'osx'; - case 'win32': return 'windows'; - case 'linux': return 'linux'; - default: throw new Error('Unknown platform ' + arch); + case 'darwin': + return 'osx'; + case 'win32': + return 'windows'; + case 'linux': + return 'linux'; + default: + throw new Error('Unknown platform ' + arch); } } -function cacheDir(opts = {}) { - var homeDir = homePath(); - return opts.cache || path.join(homeDir, './.libui'); -} - -async function mkCacheDir(cache) { - try { - await mkdir(cache); - return cache; - } catch (err) { - if (err.code !== 'EACCES') { - debug('mkCacheDir error: ', err.stack); - throw err; - } - - // try local folder if homedir is off limits (e.g. some linuxes return '/' as homedir) - var localCache = path.resolve('./.libui'); - - await mkdir(localCache); - return localCache; - } -} - -function buildUrl(opts, filename) { - var url = process.env.NPM_CONFIG_LIBUI_MIRROR || - process.env.LIBUI_MIRROR || - opts.mirror || - 'https://github.com/parro-it/libui/releases/download/'; - - url += process.env.LIBUI_CUSTOM_DIR || opts.customDir || opts.version; - url += '/'; - url += process.env.LIBUI_CUSTOM_FILENAME || opts.customFilename || filename; - return url; -} - -async function download(opts) { +function download(opts) { const platform = nodePlatformToOS(opts.platform || os.platform()); const arch = opts.arch || os.arch(); const version = opts.version; const symbols = opts.symbols || false; - const filename = 'libui-shared-' + platform + '-' + arch + '-' + version + (symbols ? '-symbols' : '') + '.tar.gz'; + const filename = 'libui-shared-' + platform + '-' + arch + '-' + version + + (symbols ? '-symbols' : '') + '.tar.gz'; if (!version) { throw new Error('must specify needed version of libui in package.json'); } const url = buildUrl(opts, filename); const cache = cacheDir(opts.cache); - const actualCache = await mkCacheDir(cache); + const actualCache = mkCacheDir(cache); debug('info', {cache: cache, filename: filename, url: url}); let cachedZip = path.join(cache, filename); - const exists = await pathExists(cachedZip); + const exists = fs.existsSync(cachedZip); if (exists) { debug('zip exists', cachedZip); - return cachedZip; + return Promise.resolve(cachedZip); } debug('creating cache/tmp dirs'); @@ -92,56 +53,34 @@ async function download(opts) { cachedZip = path.join(actualCache, filename); // in case cache dir changed // download to tmpdir - var tmpdir = path.join( - os.tmpdir(), - 'libui-tmp-download-' + process.pid + '-' + Date.now() - ); + var tmpdir = + path.join(os.tmpdir(), 'libui-tmp-download-' + process.pid + '-' + Date.now()); - await mkdir(tmpdir); + mkdirp.sync(tmpdir); debug(tmpdir + 'created'); debug('downloading zip', url, 'to', tmpdir); const target = path.join(tmpdir, filename); - const resRedirect = await requestHttps(url); - if (resRedirect.statusCode !== 302) { - throw new Error(`Https request failed for ${url} with code ${resRedirect.statusCode}: resource not found.`); - } - - - const res = await requestHttps(resRedirect.headers.location); - if (res.statusCode !== 200) { - throw new Error(`Https request failed for ${res.headers.location} with code ${res.statusCode}.`); - } - - debug(`Https request for ${url} ok with code 200.`); - - const fileWrite = res.pipe(fs.createWriteStream(target)); - - return await new Promise(async(resolve, reject) => { - - const finish = () => { - debug('end stream reached', target, cachedZip); - mv(target, cachedZip, function (err) { - if (err) { - reject(err); - } else { - resolve(cachedZip); - } - }); - }; - - fileWrite.on('finish', finish); - fileWrite.on('error', reject); - }); + return requestHttps(url) + .then(resRedirect => { + if (resRedirect.statusCode !== 302) { + throw new Error(`Https request failed for ${url} with code ${ + resRedirect.statusCode}: resource not found.`); + } + return resRedirect; + }) + .then(resRedirect => requestHttps(resRedirect.headers.location)) + .then(res => doDownload(res, url, target, cachedZip)) } -async function main() { - const zipPath = await download({version: process.env.npm_package_libui}); - console.log('Downloaded zip:', zipPath); - await tar.extract({file: zipPath}); - console.log('Libui binaries extracted to:', process.cwd()); +function main() { + return download({version: process.env.npm_package_libui}).then(zipPath => { + console.log('Downloaded zip:', zipPath); + tar.extract({file: zipPath, sync: true}); + console.log('Libui binaries extracted to:', process.cwd()); + }); } main().catch(err => { diff --git a/tools/libui-napi-download.js b/tools/libui-napi-download.js index 3fe7809..9abc59d 100644 --- a/tools/libui-napi-download.js +++ b/tools/libui-napi-download.js @@ -2,68 +2,28 @@ const fs = require('fs'); const os = require('os'); const path = require('path'); const mkdirp = require('mkdirp'); -const homePath = require('home-path'); -const mv = require('mv'); const _debug = require('debug'); -const https = require('https'); const tar = require('tar'); -const utils = require('util'); const isCI = require('is-ci'); +const {mkCacheDir, cacheDir, buildUrl, requestHttps, doDownload} = + require('./lib')('libui-napi'); -const mkdir = utils.promisify(mkdirp) const debug = _debug('libui-napi-download'); -const requestHttps = url => new Promise((resolve, reject) => { - const req = https.get(url, resolve); - req.on('error', reject); -}); - -const pathExists = utils.promisify(fs.exists); function nodePlatformToOS(arch) { switch (arch) { - case 'darwin': return 'osx'; - case 'win32': return 'win'; - case 'linux': return 'linux'; - default: throw new Error('Unknown platform ' + arch); - } -} - -function cacheDir(opts = {}) { - var homeDir = homePath(); - return opts.cache || path.join(homeDir, './.libui-napi'); -} - -async function mkCacheDir(cache) { - try { - await mkdir(cache); - return cache; - } catch (err) { - if (err.code !== 'EACCES') { - debug('mkCacheDir error: ', err.stack); - throw err; - } - - // try local folder if homedir is off limits (e.g. some linuxes return '/' as homedir) - var localCache = path.resolve('./.libui-napi'); - - await mkdir(localCache); - return localCache; + case 'darwin': + return 'osx'; + case 'win32': + return 'win'; + case 'linux': + return 'linux'; + default: + throw new Error('Unknown platform ' + arch); } } -function buildUrl(opts, filename) { - var url = process.env.NPM_CONFIG_LIBUI_MIRROR || - process.env.LIBUI_MIRROR || - opts.mirror || - 'https://github.com/parro-it/libui-napi/releases/download/'; - - url += process.env.LIBUI_CUSTOM_DIR || opts.customDir || opts.version; - url += '/'; - url += process.env.LIBUI_CUSTOM_FILENAME || opts.customFilename || filename; - return url; -} - -async function download(opts) { +function download(opts) { const platform = nodePlatformToOS(opts.platform || os.platform()); let arch = opts.arch || os.arch(); if (platform !== 'win' && arch === 'x64') { @@ -77,16 +37,16 @@ async function download(opts) { const url = buildUrl(opts, filename); const cache = cacheDir(opts.cache); - const actualCache = await mkCacheDir(cache); + const actualCache = mkCacheDir(cache); debug('info', {cache: cache, filename: filename, url: url}); let cachedZip = path.join(cache, filename); - const exists = await pathExists(cachedZip); + const exists = fs.existsSync(cachedZip); if (exists) { debug('zip exists', cachedZip); - return cachedZip; + return Promise.resolve(cachedZip); } debug('creating cache/tmp dirs'); @@ -95,66 +55,43 @@ async function download(opts) { cachedZip = path.join(actualCache, filename); // in case cache dir changed // download to tmpdir - var tmpdir = path.join( - os.tmpdir(), - 'libui-napi-tmp-download-' + process.pid + '-' + Date.now() - ); + var tmpdir = path.join(os.tmpdir(), + 'libui-napi-tmp-download-' + process.pid + '-' + Date.now()); - await mkdir(tmpdir); + mkdirp.sync(tmpdir); debug(tmpdir + 'created'); debug('downloading zip', url, 'to', tmpdir); const target = path.join(tmpdir, filename); - const resRedirect = await requestHttps(url); - if (resRedirect.statusCode === 404) { - throw new Error(`Prebuilt binaries not found for your platform and architecture.`); - } - - if (resRedirect.statusCode !== 302) { - throw new Error(`Https request failed for ${url} with code ${resRedirect.statusCode}: resource not found.`); - } - - - const res = await requestHttps(resRedirect.headers.location); - if (res.statusCode !== 200) { - throw new Error(`Https request failed for ${res.headers.location} with code ${res.statusCode}.`); - } - - debug(`Https request for ${url} ok with code 200.`); - - const fileWrite = res.pipe(fs.createWriteStream(target)); - - return new Promise(async(resolve, reject) => { - - const finish = () => { - debug('end stream reached', target, cachedZip); - mv(target, cachedZip, function (err) { - if (err) { - reject(err); - } else { - resolve(cachedZip); - } - }); - }; - - fileWrite.on('finish', finish); - fileWrite.on('error', reject); - }); + return requestHttps(url) + .then(resRedirect => { + if (resRedirect.statusCode === 404) { + throw new Error( + `Prebuilt binaries not found for your platform and architecture.`); + } + if (resRedirect.statusCode !== 302) { + throw new Error(`Https request failed for ${url} with code ${ + resRedirect.statusCode}: resource not found.`); + } + return resRedirect; + }) + .then(resRedirect => requestHttps(resRedirect.headers.location)) + .then(res => doDownload(res, url, target, cachedZip)) } -async function main() { - +function main() { if (isCI) { console.log('Running on a CI server, force rebuild.'); process.exit(1); } - const zipPath = await download({version: process.env.npm_package_version}); - console.log('Downloaded zip:', zipPath); - await tar.extract({file: zipPath}); - console.log('Libui-napi binaries extracted to:', process.cwd()); + return download({version: process.env.npm_package_version}).then(zipPath => { + console.log('Downloaded zip:', zipPath); + tar.extract({file: zipPath, sync: true}); + console.log('Libui-napi binaries extracted to:', process.cwd()); + }); } main().catch(err => {