diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ea2b055..6638d9bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,7 +146,11 @@ jobs: - name: Build native module working-directory: bindings/node - run: npx napi build --release + # --platform puts the target triple into the filename so the loader's + # `wickra..node` lookup finds the freshly built binary instead + # of falling back to the per-platform npm subpackage (which doesn't + # exist yet for win32-x64-msvc). + run: npx napi build --platform --release - name: Run Node tests working-directory: bindings/node diff --git a/bindings/node/index.js b/bindings/node/index.js index 306036fb..122c7674 100644 --- a/bindings/node/index.js +++ b/bindings/node/index.js @@ -1,50 +1,340 @@ +/* tslint:disable */ /* eslint-disable */ /* prettier-ignore */ -// Platform-aware loader for the Wickra Node native binding. -// -// In production (after `npm install wickra`) the actual `.node` binary -// lives inside a per-platform subpackage that npm installs as an -// optional dependency — e.g. `wickra-linux-x64-gnu`. In development -// (after `napi build --platform`) the binary sits next to this file. -// We try the local path first and fall back to the subpackage so the -// same loader works in both modes. -const { platform, arch } = process; -const { join } = require('node:path'); -const { existsSync } = require('node:fs'); +/* auto-generated by NAPI-RS */ -const TARGETS = { - 'linux-x64': 'linux-x64-gnu', - 'darwin-x64': 'darwin-x64', - 'darwin-arm64': 'darwin-arm64', - 'win32-x64': 'win32-x64-msvc', -}; +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') -function load() { - const key = `${platform}-${arch}`; - const target = TARGETS[key]; - if (!target) { - throw new Error( - `wickra: this platform/architecture combination is not supported (${key}). ` + - 'Open an issue at https://github.com/kingchenc/wickra/issues with your platform details.' - ); - } +const { platform, arch } = process - const localBinary = join(__dirname, `wickra.${target}.node`); - if (existsSync(localBinary)) { - return require(localBinary); - } +let nativeBinding = null +let localFileExisted = false +let loadError = null - try { - return require(`wickra-${target}`); - } catch (err) { - throw new Error( - `wickra: failed to load the native binding for ${key}. ` + - `Expected either ${localBinary} or the wickra-${target} package to be installed. ` + - `Run \`npm install\` again, or build from source with \`npm run build\`. ` + - `Underlying error: ${err.message}` - ); +function isMusl() { + // For Node 10 + if (!process.report || typeof process.report.getReport !== 'function') { + try { + const lddPath = require('child_process').execSync('which ldd').toString().trim() + return readFileSync(lddPath, 'utf8').includes('musl') + } catch (e) { + return true + } + } else { + const { glibcVersionRuntime } = process.report.getReport().header + return !glibcVersionRuntime } } -module.exports = load(); +switch (platform) { + case 'android': + switch (arch) { + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'wickra.android-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.android-arm64.node') + } else { + nativeBinding = require('wickra-android-arm64') + } + } catch (e) { + loadError = e + } + break + case 'arm': + localFileExisted = existsSync(join(__dirname, 'wickra.android-arm-eabi.node')) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.android-arm-eabi.node') + } else { + nativeBinding = require('wickra-android-arm-eabi') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Android ${arch}`) + } + break + case 'win32': + switch (arch) { + case 'x64': + localFileExisted = existsSync( + join(__dirname, 'wickra.win32-x64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.win32-x64-msvc.node') + } else { + nativeBinding = require('wickra-win32-x64-msvc') + } + } catch (e) { + loadError = e + } + break + case 'ia32': + localFileExisted = existsSync( + join(__dirname, 'wickra.win32-ia32-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.win32-ia32-msvc.node') + } else { + nativeBinding = require('wickra-win32-ia32-msvc') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'wickra.win32-arm64-msvc.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.win32-arm64-msvc.node') + } else { + nativeBinding = require('wickra-win32-arm64-msvc') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Windows: ${arch}`) + } + break + case 'darwin': + localFileExisted = existsSync(join(__dirname, 'wickra.darwin-universal.node')) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.darwin-universal.node') + } else { + nativeBinding = require('wickra-darwin-universal') + } + break + } catch {} + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'wickra.darwin-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.darwin-x64.node') + } else { + nativeBinding = require('wickra-darwin-x64') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync( + join(__dirname, 'wickra.darwin-arm64.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.darwin-arm64.node') + } else { + nativeBinding = require('wickra-darwin-arm64') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on macOS: ${arch}`) + } + break + case 'freebsd': + if (arch !== 'x64') { + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + } + localFileExisted = existsSync(join(__dirname, 'wickra.freebsd-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.freebsd-x64.node') + } else { + nativeBinding = require('wickra-freebsd-x64') + } + } catch (e) { + loadError = e + } + break + case 'linux': + switch (arch) { + case 'x64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-x64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-x64-musl.node') + } else { + nativeBinding = require('wickra-linux-x64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-x64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-x64-gnu.node') + } else { + nativeBinding = require('wickra-linux-x64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-arm64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-arm64-musl.node') + } else { + nativeBinding = require('wickra-linux-arm64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-arm64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-arm64-gnu.node') + } else { + nativeBinding = require('wickra-linux-arm64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-arm-musleabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-arm-musleabihf.node') + } else { + nativeBinding = require('wickra-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-arm-gnueabihf.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('wickra-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-riscv64-musl.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-riscv64-musl.node') + } else { + nativeBinding = require('wickra-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-riscv64-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-riscv64-gnu.node') + } else { + nativeBinding = require('wickra-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync( + join(__dirname, 'wickra.linux-s390x-gnu.node') + ) + try { + if (localFileExisted) { + nativeBinding = require('./wickra.linux-s390x-gnu.node') + } else { + nativeBinding = require('wickra-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Linux: ${arch}`) + } + break + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) +} + +if (!nativeBinding) { + if (loadError) { + throw loadError + } + throw new Error(`Failed to load native binding`) +} + +const { version, SMA, EMA, WMA, RSI, DEMA, TEMA, HMA, ROC, TRIX, MACD, BollingerBands, ATR, Stochastic, OBV, ADX, CCI, WilliamsR, MFI, PSAR, Keltner, Donchian, VWAP, AwesomeOscillator, Aroon, KAMA } = nativeBinding + +module.exports.version = version +module.exports.SMA = SMA +module.exports.EMA = EMA +module.exports.WMA = WMA +module.exports.RSI = RSI +module.exports.DEMA = DEMA +module.exports.TEMA = TEMA +module.exports.HMA = HMA +module.exports.ROC = ROC +module.exports.TRIX = TRIX +module.exports.MACD = MACD +module.exports.BollingerBands = BollingerBands +module.exports.ATR = ATR +module.exports.Stochastic = Stochastic +module.exports.OBV = OBV +module.exports.ADX = ADX +module.exports.CCI = CCI +module.exports.WilliamsR = WilliamsR +module.exports.MFI = MFI +module.exports.PSAR = PSAR +module.exports.Keltner = Keltner +module.exports.Donchian = Donchian +module.exports.VWAP = VWAP +module.exports.AwesomeOscillator = AwesomeOscillator +module.exports.Aroon = Aroon +module.exports.KAMA = KAMA