From a6154e0d23e9d95b195380d0428fdebdd530f889 Mon Sep 17 00:00:00 2001 From: Marc Platt Date: Thu, 22 May 2025 11:42:20 -0400 Subject: [PATCH 1/3] increase fd limit for mac and linux. mac uses custom module that is built in CI to enable setrlimit syscall. linux using prlimit for increase --- .github/workflows/build.yml | 17 ++++++- .gitignore | 3 ++ public/electron.js | 24 ++++++++++ public/modules/README.md | 31 +++++++++++++ public/modules/binding.gyp | 14 ++++++ public/modules/chainManager.js | 52 ++++++++++++++++++--- public/modules/fdLimitManager.js | 80 ++++++++++++++++++++++++++++++++ public/modules/package.json | 13 ++++++ public/modules/set_limits.cc | 36 ++++++++++++++ 9 files changed, 262 insertions(+), 8 deletions(-) create mode 100644 public/modules/README.md create mode 100644 public/modules/binding.gyp create mode 100644 public/modules/fdLimitManager.js create mode 100644 public/modules/package.json create mode 100644 public/modules/set_limits.cc diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f66b143..d0c9309 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,6 +71,20 @@ jobs: # --------------------------------- # macOS Build # --------------------------------- + - name: Install node-addon-api for macOS + if: matrix.os == 'macos-latest' + run: | + cd public/modules + npm install node-addon-api + + - name: Build native fd limit module for macOS + if: matrix.os == 'macos-latest' + run: | + cd public/modules + npx node-gyp rebuild + # Verify module was built + ls -la build/Release || echo "Native module build failed, app will use fallback" + - name: Build & Sign Electron app (macOS) if: matrix.os == 'macos-latest' env: @@ -200,7 +214,8 @@ jobs: name: Upload to releases.drivechain.info runs-on: ubuntu-latest needs: [build] - if: github.event_name == 'push' && github.repository_owner == 'LayerTwo-Labs' + # Only run on master branch in the main repository + if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository_owner == 'LayerTwo-Labs' steps: - name: Download artifacts uses: actions/download-artifact@v4 diff --git a/.gitignore b/.gitignore index 800f3a8..35eff7e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ # production /build /dist +/public/modules/build/ +/public/modules/node_modules/ +/public/modules/package-lock.json # misc .DS_Store diff --git a/public/electron.js b/public/electron.js index b4fdc8f..e210e89 100644 --- a/public/electron.js +++ b/public/electron.js @@ -1,4 +1,5 @@ const { app, BrowserWindow, ipcMain, shell, powerSaveBlocker } = require("electron"); +const { execSync } = require('child_process'); // Disable sandbox for Linux if (process.platform === 'linux') { @@ -19,6 +20,26 @@ const ApiManager = require("./modules/apiManager"); const DirectoryManager = require("./modules/directoryManager"); const UpdateManager = require("./modules/updateManager"); +// Increase file descriptor limits +function increaseFileDescriptorLimits() { + try { + // Lazy-load the fdLimitManager to avoid circular dependencies + const fdLimitManager = require('./modules/fdLimitManager'); + + // Try to set the limit to 65536 + const success = fdLimitManager.setFdLimit(65536); + + if (success) { + console.log(`Successfully increased file descriptor limit to 65536`); + } else if (process.platform === 'darwin') { + console.log(`Could not increase file descriptor limit using native module.`); + console.log(`Child processes will use per-process limits via spawnWithHighLimits.`); + } + } catch (error) { + // Silent error handling to avoid startup issues + } +} + const configPath = path.join(__dirname, "chain_config.json"); let config; let mainWindow = null; @@ -856,6 +877,9 @@ async function initialize() { app.commandLine.appendSwitch('no-sandbox'); async function startApp() { + // Increase file descriptor limits first + increaseFileDescriptorLimits(); + // Show loading window first createLoadingWindow(); diff --git a/public/modules/README.md b/public/modules/README.md new file mode 100644 index 0000000..fcc052f --- /dev/null +++ b/public/modules/README.md @@ -0,0 +1,31 @@ +# File Descriptor Limit Manager + +This module provides a way to increase file descriptor limits for the Drivechain Launcher application. + +## Platform Support + +- **macOS**: Uses a native addon to directly call `setrlimit()` syscall for reliable limit increase +- **Linux**: Uses `prlimit` command to increase limits for the current process +- **Windows**: No special handling needed + +## Building the Native Module + +The native module is only used on macOS. To build it: + +1. Ensure you have node-gyp requirements installed: + - Xcode Command Line Tools + - Python + +2. Navigate to this directory and run: + +```bash +cd public/modules +npm install +``` + +This will automatically build the native module if possible. If building fails, the application will +fall back to a shell-based approach which may not be as reliable. + +## Using in Code + +The module is automatically used by the application to increase file descriptor limits. \ No newline at end of file diff --git a/public/modules/binding.gyp b/public/modules/binding.gyp new file mode 100644 index 0000000..f3322fb --- /dev/null +++ b/public/modules/binding.gyp @@ -0,0 +1,14 @@ +{ + "targets": [ + { + "target_name": "set_limits", + "cflags!": [ "-fno-exceptions" ], + "cflags_cc!": [ "-fno-exceptions" ], + "sources": [ "set_limits.cc" ], + "include_dirs": [ + " 0 && + currentFdLimit < 10000) { + console.log('Using shell wrapper for file descriptor limits'); + + // If we're going to use shell, make sure options has the right structure + const finalOptions = { + ...options, + shell: true, + env: { ...process.env, ...(options.env || {}) } + }; + + // Escape command and args for shell + const escapedCommand = command.replace(/"/g, '\\"'); + const escapedArgs = args.map(arg => `"${arg.replace(/"/g, '\\"')}"`).join(' '); + + // Use bash -c to set ulimit then run the command + return spawn('bash', ['-c', `ulimit -n 65536 && "${escapedCommand}" ${escapedArgs}`], finalOptions); + } + + // For all other cases, spawn normally + return spawn(command, args, options); +} class ChainManager { constructor(mainWindow, config, downloadManager) { @@ -293,7 +333,7 @@ class ChainManager { await fs.promises.chmod(fullBinaryPath, "755"); } - const childProcess = spawn(fullBinaryPath, [], { + const childProcess = spawnWithHighLimits(fullBinaryPath, [], { cwd: basePath, // Ensure SIGINT is used for graceful shutdown on Windows windowsHide: true @@ -329,7 +369,7 @@ class ChainManager { const args = [...baseArgs, ...additionalArgs]; console.log(`Starting ${chainId} with args:`, args); - const childProcess = spawn(fullBinaryPath, args, { cwd: basePath }); + const childProcess = spawnWithHighLimits(fullBinaryPath, args, { cwd: basePath }); this.runningProcesses[chainId] = childProcess; if (chainId !== 'bitcoin') { @@ -615,16 +655,14 @@ class ChainManager { } console.log('Attempting graceful shutdown with:', bitcoinCliPath); - const stopProcess = spawn(bitcoinCliPath, [ + const stopProcess = spawnWithHighLimits(bitcoinCliPath, [ '-signet', '-rpcuser=user', '-rpcpassword=password', '-rpcport=38332', '-rpcbind=0.0.0.0', 'stop' - ], { - shell: true - }); + ], { shell: true }); stopProcess.stderr.on('data', (data) => { console.error('bitcoin-cli error:', data.toString()); diff --git a/public/modules/fdLimitManager.js b/public/modules/fdLimitManager.js new file mode 100644 index 0000000..b8e1d2c --- /dev/null +++ b/public/modules/fdLimitManager.js @@ -0,0 +1,80 @@ +const { execSync } = require('child_process'); +const fs = require('fs-extra'); +const path = require('path'); +const { app } = require('electron'); + +class FdLimitManager { + constructor() { + this.initialized = false; + this.nativeModule = null; + + // Only try to load native module on macOS + if (process.platform === 'darwin') { + try { + // Path to where the binary would be after building + const modulePath = path.join(__dirname, 'build/Release/set_limits.node'); + + // Check if the module exists + if (fs.existsSync(modulePath)) { + this.nativeModule = require(modulePath); + this.initialized = true; + console.log('Successfully loaded native setrlimit module'); + } else { + console.error('Native module not found, perhaps it needs to be built'); + } + } catch (error) { + console.error('Failed to load native module:', error); + } + } + } + + /** + * Set file descriptor limits for the current process + * @param {number} limit - The limit to set + * @returns {boolean} - Whether the operation was successful + */ + setFdLimit(limit) { + if (process.platform === 'darwin') { + if (this.initialized && this.nativeModule) { + try { + const result = this.nativeModule.setFileDescriptorLimit(limit); + return result === 0; // 0 means success in syscalls + } catch (error) { + console.error('Failed to set file descriptor limit:', error); + return false; + } + } + return false; + } + else if (process.platform === 'linux') { + try { + execSync(`prlimit --pid ${process.pid} --nofile=${limit}:${limit}`); + return true; + } catch (error) { + console.error('Failed to set file descriptor limit on Linux:', error); + return false; + } + } + + // On Windows, no special handling needed + return true; + } + + /** + * Get the current file descriptor limit + * @returns {number} - The current limit or -1 if unknown + */ + getCurrentLimit() { + if (process.platform === 'darwin' || process.platform === 'linux') { + try { + const output = execSync('ulimit -n').toString().trim(); + return parseInt(output, 10) || -1; + } catch (error) { + console.error('Failed to get current file descriptor limit:', error); + } + } + return -1; + } +} + +module.exports = new FdLimitManager(); \ No newline at end of file diff --git a/public/modules/package.json b/public/modules/package.json new file mode 100644 index 0000000..2776529 --- /dev/null +++ b/public/modules/package.json @@ -0,0 +1,13 @@ +{ + "name": "set-limits", + "version": "1.0.0", + "description": "Native module for setting file descriptor limits", + "main": "fdLimitManager.js", + "scripts": { + "install": "node-gyp rebuild || echo 'Native module build failed, will use fallback'" + }, + "dependencies": { + "node-addon-api": "^5.0.0" + }, + "gypfile": true +} \ No newline at end of file diff --git a/public/modules/set_limits.cc b/public/modules/set_limits.cc new file mode 100644 index 0000000..8e08cbb --- /dev/null +++ b/public/modules/set_limits.cc @@ -0,0 +1,36 @@ +#include +#include + +Napi::Value SetFileDescriptorLimit(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + // Check if we have the limit argument + if (info.Length() < 1 || !info[0].IsNumber()) { + Napi::TypeError::New(env, "Number expected for limit").ThrowAsJavaScriptException(); + return env.Null(); + } + + // Get the limit from JavaScript + int limit = info[0].As().Int32Value(); + + // Set up the rlimit struct + struct rlimit rlim; + rlim.rlim_cur = limit; + rlim.rlim_max = limit; + + // Make the syscall + int result = setrlimit(RLIMIT_NOFILE, &rlim); + + // Return the result to JavaScript (0 means success) + return Napi::Number::New(env, result); +} + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set( + Napi::String::New(env, "setFileDescriptorLimit"), + Napi::Function::New(env, SetFileDescriptorLimit) + ); + return exports; +} + +NODE_API_MODULE(set_limits, Init) \ No newline at end of file From 561ba463c5884a3a008a5f3f7b1998b10eca941c Mon Sep 17 00:00:00 2001 From: Marc Platt Date: Thu, 22 May 2025 12:17:22 -0400 Subject: [PATCH 2/3] simplify logic and don't use ulimit. only touch soft limit and set to 1000. --- public/electron.js | 30 +++++++++++++------ public/modules/chainManager.js | 25 +--------------- public/modules/fdLimitManager.js | 49 ++++++++++++++++---------------- public/modules/set_limits.cc | 21 ++++++++++---- 4 files changed, 63 insertions(+), 62 deletions(-) diff --git a/public/electron.js b/public/electron.js index e210e89..f55852e 100644 --- a/public/electron.js +++ b/public/electron.js @@ -26,14 +26,28 @@ function increaseFileDescriptorLimits() { // Lazy-load the fdLimitManager to avoid circular dependencies const fdLimitManager = require('./modules/fdLimitManager'); - // Try to set the limit to 65536 - const success = fdLimitManager.setFdLimit(65536); - - if (success) { - console.log(`Successfully increased file descriptor limit to 65536`); - } else if (process.platform === 'darwin') { - console.log(`Could not increase file descriptor limit using native module.`); - console.log(`Child processes will use per-process limits via spawnWithHighLimits.`); + // For macOS, use the native module + if (process.platform === 'darwin') { + // Try to set the soft limit to 1000 without changing hard limit + const success = fdLimitManager.setFdLimit(1000); + + if (success) { + console.log(`Successfully increased file descriptor soft limit to 1000`); + } else { + console.log(`Could not increase file descriptor limit using native module.`); + console.log(`Child processes will use per-process limits via spawnWithHighLimits.`); + } + } + // For Linux, use prlimit to just set the soft limit + else if (process.platform === 'linux') { + try { + const { execSync } = require('child_process'); + // Set only the soft limit, keep hard limit as-is with empty value + execSync(`prlimit --pid ${process.pid} --nofile=1000:`); + console.log(`Successfully increased file descriptor soft limit to 1000`); + } catch (error) { + console.error('Failed to set file descriptor limit on Linux:', error); + } } } catch (error) { // Silent error handling to avoid startup issues diff --git a/public/modules/chainManager.js b/public/modules/chainManager.js index 52617c6..2b4c2f3 100644 --- a/public/modules/chainManager.js +++ b/public/modules/chainManager.js @@ -19,30 +19,7 @@ function spawnWithHighLimits(command, args, options = {}) { return spawn(command, args, options); } - // On macOS, if we can't use the native module and current limit is too low, - // we have to fall back to a shell-based approach - if (process.platform === 'darwin' && - !fdLimitManager.initialized && - currentFdLimit > 0 && - currentFdLimit < 10000) { - console.log('Using shell wrapper for file descriptor limits'); - - // If we're going to use shell, make sure options has the right structure - const finalOptions = { - ...options, - shell: true, - env: { ...process.env, ...(options.env || {}) } - }; - - // Escape command and args for shell - const escapedCommand = command.replace(/"/g, '\\"'); - const escapedArgs = args.map(arg => `"${arg.replace(/"/g, '\\"')}"`).join(' '); - - // Use bash -c to set ulimit then run the command - return spawn('bash', ['-c', `ulimit -n 65536 && "${escapedCommand}" ${escapedArgs}`], finalOptions); - } - - // For all other cases, spawn normally + // For all platforms, just use normal spawn - fd limits are handled globally in app initialization return spawn(command, args, options); } diff --git a/public/modules/fdLimitManager.js b/public/modules/fdLimitManager.js index b8e1d2c..47b2a4c 100644 --- a/public/modules/fdLimitManager.js +++ b/public/modules/fdLimitManager.js @@ -1,7 +1,6 @@ const { execSync } = require('child_process'); const fs = require('fs-extra'); const path = require('path'); -const { app } = require('electron'); class FdLimitManager { constructor() { @@ -34,30 +33,18 @@ class FdLimitManager { * @returns {boolean} - Whether the operation was successful */ setFdLimit(limit) { - if (process.platform === 'darwin') { - if (this.initialized && this.nativeModule) { - try { - const result = this.nativeModule.setFileDescriptorLimit(limit); - return result === 0; // 0 means success in syscalls - } catch (error) { - console.error('Failed to set file descriptor limit:', error); - return false; - } - } - return false; - } - else if (process.platform === 'linux') { + // This only works on macOS with the native module + if (process.platform === 'darwin' && this.initialized && this.nativeModule) { try { - execSync(`prlimit --pid ${process.pid} --nofile=${limit}:${limit}`); - return true; + const result = this.nativeModule.setFileDescriptorLimit(limit); + return result === 0; // 0 means success in syscalls } catch (error) { - console.error('Failed to set file descriptor limit on Linux:', error); + console.error('Failed to set file descriptor limit:', error); return false; } } - // On Windows, no special handling needed - return true; + return false; } /** @@ -65,14 +52,26 @@ class FdLimitManager { * @returns {number} - The current limit or -1 if unknown */ getCurrentLimit() { - if (process.platform === 'darwin' || process.platform === 'linux') { - try { - const output = execSync('ulimit -n').toString().trim(); - return parseInt(output, 10) || -1; - } catch (error) { - console.error('Failed to get current file descriptor limit:', error); + try { + if (process.platform === 'darwin') { + // On macOS, get process-specific limit if possible + if (this.initialized && this.nativeModule) { + // If we have the native module, assume the limit was set by it + // In the future, we could add a getrlimit call to the native module + return 1000; + } + // Fallback - this isn't ideal but better than nothing + return -1; + } else if (process.platform === 'linux') { + // On Linux, use prlimit to get the process-specific limit + const output = execSync(`prlimit --pid ${process.pid} --nofile --raw --noheadings`).toString().trim(); + const [soft] = output.split(/\s+/).map(Number); + return soft || -1; } + } catch (error) { + console.error('Failed to get current file descriptor limit:', error); } + return -1; } } diff --git a/public/modules/set_limits.cc b/public/modules/set_limits.cc index 8e08cbb..b5c3466 100644 --- a/public/modules/set_limits.cc +++ b/public/modules/set_limits.cc @@ -13,13 +13,24 @@ Napi::Value SetFileDescriptorLimit(const Napi::CallbackInfo& info) { // Get the limit from JavaScript int limit = info[0].As().Int32Value(); - // Set up the rlimit struct - struct rlimit rlim; - rlim.rlim_cur = limit; - rlim.rlim_max = limit; + // Get current limits + struct rlimit current_rlim; + if (getrlimit(RLIMIT_NOFILE, ¤t_rlim) != 0) { + return Napi::Number::New(env, -1); // Error + } + + // Don't set limit higher than the hard limit + if (limit > current_rlim.rlim_max) { + limit = current_rlim.rlim_max; + } + + // Set up new rlimit - only change soft limit + struct rlimit new_rlim; + new_rlim.rlim_cur = limit; + new_rlim.rlim_max = current_rlim.rlim_max; // Keep existing hard limit // Make the syscall - int result = setrlimit(RLIMIT_NOFILE, &rlim); + int result = setrlimit(RLIMIT_NOFILE, &new_rlim); // Return the result to JavaScript (0 means success) return Napi::Number::New(env, result); From f4d1d1de48ecd1b8dcbd8c58d80e352e3a8ad728 Mon Sep 17 00:00:00 2001 From: Marc Platt Date: Thu, 22 May 2025 12:53:29 -0400 Subject: [PATCH 3/3] remove spawn wrapper and add wrapper for get file --- public/electron.js | 14 +++++++++----- public/modules/chainManager.js | 17 +++-------------- public/modules/fdLimitManager.js | 24 +++++++++++++++++------- public/modules/set_limits.cc | 21 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/public/electron.js b/public/electron.js index f55852e..e12e356 100644 --- a/public/electron.js +++ b/public/electron.js @@ -29,13 +29,13 @@ function increaseFileDescriptorLimits() { // For macOS, use the native module if (process.platform === 'darwin') { // Try to set the soft limit to 1000 without changing hard limit - const success = fdLimitManager.setFdLimit(1000); + const result = fdLimitManager.setFdLimit(1000); - if (success) { - console.log(`Successfully increased file descriptor soft limit to 1000`); + if (result.success) { + console.log(`Successfully increased file descriptor soft limit to ${result.limit}`); } else { console.log(`Could not increase file descriptor limit using native module.`); - console.log(`Child processes will use per-process limits via spawnWithHighLimits.`); + console.log(`Child processes will run with default system limits.`); } } // For Linux, use prlimit to just set the soft limit @@ -44,7 +44,11 @@ function increaseFileDescriptorLimits() { const { execSync } = require('child_process'); // Set only the soft limit, keep hard limit as-is with empty value execSync(`prlimit --pid ${process.pid} --nofile=1000:`); - console.log(`Successfully increased file descriptor soft limit to 1000`); + + // Verify the limit was set + const output = execSync(`prlimit --pid ${process.pid} --nofile --raw --noheadings`).toString().trim(); + const [soft] = output.split(/\s+/).map(Number); + console.log(`Successfully increased file descriptor soft limit to ${soft}`); } catch (error) { console.error('Failed to set file descriptor limit on Linux:', error); } diff --git a/public/modules/chainManager.js b/public/modules/chainManager.js index 2b4c2f3..5eb4e83 100644 --- a/public/modules/chainManager.js +++ b/public/modules/chainManager.js @@ -12,17 +12,6 @@ const fdLimitManager = require('./fdLimitManager'); const currentFdLimit = fdLimitManager.getCurrentLimit(); console.log(`Current file descriptor limit: ${currentFdLimit}`); -// Wrapper for spawn that handles file descriptor limits -function spawnWithHighLimits(command, args, options = {}) { - // Handle utility commands directly without modification - if (command.includes('open') || command.includes('killall') || command.includes('taskkill')) { - return spawn(command, args, options); - } - - // For all platforms, just use normal spawn - fd limits are handled globally in app initialization - return spawn(command, args, options); -} - class ChainManager { constructor(mainWindow, config, downloadManager) { this.mainWindow = mainWindow; @@ -310,7 +299,7 @@ class ChainManager { await fs.promises.chmod(fullBinaryPath, "755"); } - const childProcess = spawnWithHighLimits(fullBinaryPath, [], { + const childProcess = spawn(fullBinaryPath, [], { cwd: basePath, // Ensure SIGINT is used for graceful shutdown on Windows windowsHide: true @@ -346,7 +335,7 @@ class ChainManager { const args = [...baseArgs, ...additionalArgs]; console.log(`Starting ${chainId} with args:`, args); - const childProcess = spawnWithHighLimits(fullBinaryPath, args, { cwd: basePath }); + const childProcess = spawn(fullBinaryPath, args, { cwd: basePath }); this.runningProcesses[chainId] = childProcess; if (chainId !== 'bitcoin') { @@ -632,7 +621,7 @@ class ChainManager { } console.log('Attempting graceful shutdown with:', bitcoinCliPath); - const stopProcess = spawnWithHighLimits(bitcoinCliPath, [ + const stopProcess = spawn(bitcoinCliPath, [ '-signet', '-rpcuser=user', '-rpcpassword=password', diff --git a/public/modules/fdLimitManager.js b/public/modules/fdLimitManager.js index 47b2a4c..9541ef8 100644 --- a/public/modules/fdLimitManager.js +++ b/public/modules/fdLimitManager.js @@ -30,21 +30,31 @@ class FdLimitManager { /** * Set file descriptor limits for the current process * @param {number} limit - The limit to set - * @returns {boolean} - Whether the operation was successful + * @returns {object} - Object with success boolean and actual limit set */ setFdLimit(limit) { // This only works on macOS with the native module if (process.platform === 'darwin' && this.initialized && this.nativeModule) { try { const result = this.nativeModule.setFileDescriptorLimit(limit); - return result === 0; // 0 means success in syscalls + + if (result === 0) { // 0 means success in syscalls + // Get the actual limit that was set (might be different from requested) + const actualLimits = this.nativeModule.getFileDescriptorLimit(); + return { + success: true, + limit: actualLimits.soft + }; + } + + return { success: false, limit: 0 }; } catch (error) { console.error('Failed to set file descriptor limit:', error); - return false; + return { success: false, limit: 0 }; } } - return false; + return { success: false, limit: 0 }; } /** @@ -56,9 +66,9 @@ class FdLimitManager { if (process.platform === 'darwin') { // On macOS, get process-specific limit if possible if (this.initialized && this.nativeModule) { - // If we have the native module, assume the limit was set by it - // In the future, we could add a getrlimit call to the native module - return 1000; + // Use the native module to get the current limit + const limits = this.nativeModule.getFileDescriptorLimit(); + return limits.soft || -1; } // Fallback - this isn't ideal but better than nothing return -1; diff --git a/public/modules/set_limits.cc b/public/modules/set_limits.cc index b5c3466..dcc77ce 100644 --- a/public/modules/set_limits.cc +++ b/public/modules/set_limits.cc @@ -1,6 +1,23 @@ #include #include +Napi::Value GetFileDescriptorLimit(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + // Get current limits + struct rlimit current_rlim; + if (getrlimit(RLIMIT_NOFILE, ¤t_rlim) != 0) { + return Napi::Number::New(env, -1); // Error + } + + // Create object with soft and hard limits + Napi::Object result = Napi::Object::New(env); + result.Set("soft", Napi::Number::New(env, current_rlim.rlim_cur)); + result.Set("hard", Napi::Number::New(env, current_rlim.rlim_max)); + + return result; +} + Napi::Value SetFileDescriptorLimit(const Napi::CallbackInfo& info) { Napi::Env env = info.Env(); @@ -41,6 +58,10 @@ Napi::Object Init(Napi::Env env, Napi::Object exports) { Napi::String::New(env, "setFileDescriptorLimit"), Napi::Function::New(env, SetFileDescriptorLimit) ); + exports.Set( + Napi::String::New(env, "getFileDescriptorLimit"), + Napi::Function::New(env, GetFileDescriptorLimit) + ); return exports; }