वास्तविक उदाहरणों के साथ Electron IPC संचार की व्याख्या

इलेक्ट्रॉन इंटर-प्रोसेस संचार (IPC) आरेख

HTML, CSS और JavaScript जैसी वेब तकनीकों का उपयोग करके क्रॉस-प्लेटफ़ॉर्म डेस्कटॉप एप्लिकेशन बनाने के लिए इलेक्ट्रॉन (Electron) सबसे लोकप्रिय फ्रेमवर्क में से एक है। हुड के तहत, इलेक्ट्रॉन एक मल्टी-प्रोसेस आर्किटेक्चर चलाता है जिसमें एक मुख्य प्रोसेस (Main Process) (जो Node.js चलाता है) और एक या अधिक रेंडरर प्रोसेस (Renderer Process) (जो UI रेंडर करने के लिए Chromium चलाता है) शामिल होते हैं।

सुरक्षा जोखिमों के कारण, आधुनिक इलेक्ट्रॉन एप्लिकेशन रेंडरर प्रोसेस को ऑपरेटिंग सिस्टम से अलग (आइसोलेट) रखते हैं। इसका मतलब है कि आप सीधे रेंडरर UI से Node.js मॉड्यूल या सिस्टम संसाधनों (जैसे फ़ाइलें पढ़ना या डेटाबेस में क्वेरी करना) तक नहीं पहुँच सकते।

इस अंतर को सुरक्षित रूप से पाटने के लिए, इलेक्ट्रॉन इंटर-प्रोसेस कम्युनिकेशन (IPC) का उपयोग करता है।

इस गाइड में, हम समझाएंगे कि इलेक्ट्रॉन IPC कैसे काम करता है और वास्तविक, प्रोडक्शन-रेडी कोड उदाहरणों के साथ तीन बुनियादी संचार पैटर्नों का पता लगाएंगे।


1. रेंडरर से मुख्य प्रोसेस (एक-तरफ़ा / One-Way)

इस पैटर्न का उपयोग तब किया जाता है जब रेंडरर बिना किसी प्रतिक्रिया की प्रतीक्षा किए मुख्य प्रोसेस को एक कमांड या एक्शन भेजना चाहता है। एक सामान्य उदाहरण एप्लिकेशन विंडो को छोटा करने या बंद करने के लिए UI में एक बटन पर क्लिक करना है।

आइए देखें कि इसे तीन प्रमुख फ़ाइलों: main.js, preload.js, और renderer.js में कैसे लागू किया जाता है।

मुख्य प्रोसेस (main.js)

हम रेंडरर प्रोसेस से आने वाले इवेंट्स को सुनने के लिए ipcMain.on का उपयोग करते हैं।

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false
    }
  });
  win.loadFile('index.html');
}

// रेंडरर से आने वाले 'close-app' इवेंट को सुनें
ipcMain.on('close-app', () => {
  app.quit();
});

प्रीलोड स्क्रिप्ट (preload.js)

हम पूरे ipcRenderer मॉड्यूल को रेंडरर के सामने उजागर किए बिना एक सुरक्षित रैपर प्रदान करने के लिए contextBridge.exposeInMainWorld का उपयोग करते हैं।

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  closeApp: () => ipcRenderer.send('close-app')
});

रेंडरर प्रोसेस (renderer.js)

हम window ऑब्जेक्ट पर उजागर किए गए फ़ंक्शन को कॉल करते हैं।

const closeButton = document.getElementById('close-btn');

closeButton.addEventListener('click', () => {
  window.electronAPI.closeApp();
});

2. रेंडरर से मुख्य प्रोसेस (दो-तरफ़ा / अनुरोध-प्रतिक्रिया)

इस पैटर्न का उपयोग तब किया जाता है जब रेंडरर को मुख्य प्रोसेस से डेटा का अनुरोध करने या सिस्टम ऑपरेशन शुरू करने और परिणाम की प्रतीक्षा करने की आवश्यकता होती है (जैसे, फ़ाइल पढ़ना या सुरक्षित डेटाबेस क्वेरी करना)।

हम मुख्य प्रोसेस में ipcMain.handle और प्रीलोड स्क्रिप्ट में ipcRenderer.invoke का उपयोग करते हैं।

मुख्य प्रोसेस (main.js)

ipcMain.handle का उपयोग करके अनुरोध सुनें और एसिंक्रोनस रूप से डेटा वापस करें।

const { ipcMain } = require('electron');
const fs = require('fs/promises');

// 'read-file' कॉल को एसिंक्रोनस रूप से संभालें
ipcMain.handle('read-file', async (event, filePath) => {
  try {
    const data = await fs.readFile(filePath, 'utf-8');
    return { success: true, content: data };
  } catch (error) {
    return { success: false, error: error.message };
  }
});

प्रीलोड स्क्रिप्ट (preload.js)

एक एसिंक्रोनस रैपर उजागर करें जो एक Promise लौटाता है।

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  readFile: (filePath) => ipcRenderer.invoke('read-file', filePath)
});

रेंडरर प्रोसेस (renderer.js)

लौटाए गए Promise के हल (resolve) होने की प्रतीक्षा करने के लिए await का उपयोग करें।

const readBtn = document.getElementById('read-btn');

readBtn.addEventListener('click', async () => {
  const result = await window.electronAPI.readFile('/path/to/file.txt');
  if (result.success) {
    console.log('फ़ाइल सामग्री:', result.content);
  } else {
    console.error('फ़ाइल पढ़ने में विफल:', result.error);
  }
});

3. मुख्य प्रोसेस से रेंडरर (एक-तरफ़ा सूचना)

इस पैटर्न का उपयोग तब किया जाता है जब मुख्य प्रोसेस को रेंडरर प्रोसेस में अपडेट या सूचनाएं भेजने की आवश्यकता होती है (जैसे, डाउनलोड प्रगति पट्टी अपडेट, एप्लिकेशन मेनू क्लिक, या पृष्ठभूमि सेवा स्थिति अपडेट)।

हम मुख्य प्रोसेस में webContents.send और प्रीलोड स्क्रिप्ट में ipcRenderer.on का उपयोग करते हैं।

मुख्य प्रोसेस (main.js)

सक्रिय विंडो के webContents प्राप्त करें और संदेश भेजें।

// उदाहरण: डाउनलोड प्रगति अपडेट भेजना
function trackDownloadProgress(mainWindow) {
  let progress = 0;
  const interval = setInterval(() => {
    progress += 10;
    mainWindow.webContents.send('download-progress', progress);
    
    if (progress >= 100) {
      clearInterval(interval);
    }
  }, 1000);
}

प्रीलोड स्क्रिप्ट (preload.js)

एक सब्सक्रिप्शन विधि उजागर करें जो एक कॉलबैक फ़ंक्शन लेती है। मेमोरी लीक को रोकने के लिए क्लीनअप (लिसनर हटाने वाला) फ़ंक्शन वापस करना एक अच्छा अभ्यास है।

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  onDownloadProgress: (callback) => {
    const subscription = (event, value) => callback(value);
    ipcRenderer.on('download-progress', subscription);
    
    // मेमोरी लीक को रोकने के लिए क्लीनअप फ़ंक्शन लौटाएं
    return () => {
      ipcRenderer.removeListener('download-progress', subscription);
    };
  }
});

रेंडरर प्रोसेस (renderer.js)

इवेंट्स को सब्सक्राइब करें और UI अपडेट करें।

const progressBar = document.getElementById('progress-bar');

const unsubscribe = window.electronAPI.onDownloadProgress((progress) => {
  progressBar.style.width = `${progress}%`;
  progressBar.textContent = `${progress}%`;
  
  if (progress === 100) {
    console.log('डाउनलोड पूरा हुआ!');
    unsubscribe(); // मेमोरी लीक से बचने के लिए लिसनर को साफ़ करें
  }
});

4. सुरक्षा संबंधी सर्वोत्तम अभ्यास

इलेक्ट्रॉन IPC के साथ काम करते समय सुरक्षा आपकी सर्वोच्च प्राथमिकता होनी चाहिए। यदि IPC सुरक्षित नहीं है, तो रेंडरर प्रोसेस में इंजेक्ट किया गया दुर्भावनापूर्ण कोड पूरे ऑपरेटिंग सिस्टम से समझौता कर सकता है।

इन महत्वपूर्ण नियमों का पालन करें:

  1. ipcRenderer को कभी भी सीधे उजागर न करें: contextBridge.exposeInMainWorld('electron', ipcRenderer) न लिखें। ऐसा करने से रेंडरर को कोई भी IPC संदेश भेजने की पूरी छूट मिल जाती है, जिससे सुरक्षा सीमाएं टूट जाती हैं।
  2. समीपस्थ अलगाव (Context Isolation) सक्षम रखें: हमेशा webPreferences में contextIsolation: true और nodeIntegration: false सेट करें।
  3. इनपुट मान्य (Validate) करें: मुख्य प्रोसेस में प्राप्त तर्कों (जैसे फ़ाइल पथ या डेटाबेस क्वेरी) को निष्पादित करने से पहले हमेशा उन्हें सत्यापित करें।
  4. ipcMain.on + webContents.send के बजाय ipcMain.handle को प्राथमिकता दें: अनुरोध-प्रतिक्रिया पैटर्न के लिए, invoke/handle अधिक साफ है, Promise को मूल रूप से हल करता है, और कई लिसनर कॉलबैक के घालमेल से बचाता है।

निष्कर्ष

IPC संचार को समझना सुरक्षित, उच्च प्रदर्शन करने वाले और मजबूत इलेक्ट्रॉन एप्लिकेशन बनाने की कुंजी है। काम के लिए सही पैटर्न का उपयोग करके और कॉन्टेक्स्ट आइसोलेशन लागू करके, आप अपने उपयोगकर्ताओं को सुरक्षित रखते हुए डेस्कटॉप पर Node.js की पूरी शक्ति का लाभ उठा सकते हैं।


Ghaznix ब्लॉग पर और अधिक डेवलपर अंतर्दृष्टि खोजें →