
{  "name": "rabid-oil-clean-6o8jz",  "productName": "rabid-oil-clean-6o8jz",  "description": "My Electron application description",  "keywords": [],  "main": "./main.js",  "version": "1.0.0",  "author": "liubo",  "scripts": {    "start": "electron ."  },  "dependencies": {},  "devDependencies": {    "electron": "20.0.1"  }}
<!DOCTYPE html><html><head>  <meta charset="UTF-8">  <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->  <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> -->  <title>Hello World!</title></head><body>  <h1>Hello World!</h1>  We are using Node.js <span id="node-version"></span>,  Chromium <span id="chrome-version"></span>,  and Electron <span id="electron-version"></span>.  <br />  <button id="newWIn">新建窗口</button>  <br />  <button id="upload1">下载1</button>  <button id="upload2">下载2</button>  <br />  <button id="cancel1">取消1</button>  <button id="cancel2">取消2</button>  <br />  <div>    <div>下载任务</div>    <div id="downloads">    </div>  </div>  <h1 id="h1"></h1>  <!-- You can also require other files to run in this process -->  <script src="./child.js"></script>  <style>    * {      padding: 0;      margin: 0;      word-break: break-all;    }  </style></body></html>
// This file is required by the index.html file and will// be executed in the renderer process for that window.// No Node.js APIs are available in this process because// `nodeIntegration` is turned off. Use `preload.js` to// selectively enable features needed in the rendering// process.// All of the Node.js APIs are available in the preload process.// It has the same sandbox as a Chrome extension.const { ipcRenderer, contextBridge } = require("electron");window.addEventListener("DOMContentLoaded", () => {  const replaceText = (selector, text) => {    const element = document.getElementById(selector);    if (element) element.innerText = text;  };  for (const type of ["chrome", "node", "electron"]) {    replaceText(`${type}-version`, process.versions[type]);  }});window.app = {  ipcReceive: (channel, callback) => {    ipcRenderer.on(channel, (eventt, ...rest) => {      callback(...rest);    });  },  ipcSend: (channel, ...msg) => {    ipcRenderer.send(channel, ...msg);  },  ipcInvoke: (channel, ...msg) => {    return ipcRenderer.invoke(channel, ...msg);  },}let newWIn = document.querySelector("#newWIn");let cancel1 = document.querySelector("#cancel1");let cancel2 = document.querySelector("#cancel2");let upload1 = document.querySelector("#upload1");let upload2 = document.querySelector("#upload2");let h1 = document.querySelector("#h1");let downloads = document.querySelector("#downloads");(async function () {  let res = await window.app.ipcInvoke("getCount");  console.log(res, "-------------");  h1.innerHTML = res;})();newWIn.addEventListener("click", () => {  window.app.ipcInvoke("createWindow");});cancel1.addEventListener("click", () => {  window.app.ipcInvoke("cancel", { id: 1 });});cancel2.addEventListener("click", () => {  window.app.ipcInvoke("cancel", { id: 2 });});upload1.addEventListener("click", () => {  window.app.ipcInvoke("upload", {    id: 1,    url: "https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe",  });});upload2.addEventListener("click", () => {  window.app.ipcInvoke("upload", {    id: 2,    url: "https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe",  });});window.app.ipcReceive("data-update", (data) => {  console.log(data, "-------------");  h1.innerHTML = data;});
<!DOCTYPE html><html>  <head>    <meta charset="UTF-8">    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->    <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"> -->    <title>Hello World!</title>  </head>  <body>    <h1>Hello World!</h1>    We are using Node.js <span id="node-version"></span>,    Chromium <span id="chrome-version"></span>,    and Electron <span id="electron-version"></span>.    <button id="newWIn">新建窗口</button>    <br />    <button id="upload1">下载1</button>    <button id="upload2">下载2</button>    <br />    <button id="cancel1">取消1</button>    <button id="cancel2">取消2</button>    <br />    <div>      <div>下载任务</div>      <div id="downloads">      </div>    </div>    <h1 id="h1"></h1>    <!-- You can also require other files to run in this process -->    <script src="./renderer.js"></script>    <style>      * {        padding: 0;        margin: 0;        word-break: break-all;      }    </style>  </body></html>
// Modules to control application life and create native browser windowconst { app, BrowserWindow, ipcMain } = require('electron')const path = require('path')const http = require('http')const https = require('https')ipcMain.handle('createWindow', () => {  createWindow()})let manage = []let count = 0ipcMain.handle('upload', (event, { id, url }) => {  console.log(id, url)  download(id, url)})function filter(manage) {  let res = []  for (let cur of manage) {    let could = {}    for (let n of Object.keys(cur)) {      if (n === 'client') {        could[n] = null      } else {        could[n] = cur[n]      }    }    res.push(could)  }  return res}function download(id, url) {  let run = manage.find(n => n.id === id)  if (run && run.status === 'runing') return  let cur = run ? run : {    id,    url,    persent: 0,    // controller,    client: null,    status: 'runing'  }  if (!run) {    manage.push(cur)  } else {    run.persent = 0    run.status = 'runing'  }  debugger;  const options = {    method: "GET",    responseType: "blob",    // signal,    headers: {      // "Content-Type": "application/json"    },  };  console.log(url, options);  if (url.startsWith("https://")) {    const clientRequest = https.request(url, options, (incomingMessage) => {      debugger;      console.log(`状态码: ${incomingMessage.statusCode}`);      let contentLength = incomingMessage.headers["content-length"];      let load = 0;      incomingMessage.on("data", (d) => {        // console.log(incomingMessage)        debugger;        load += d.length;        // process.stdout.write(d);        let persent = Math.floor((load / contentLength) * 10000) / 100;        console.log(d.length, load, contentLength, `${persent}%`);        cur.persent = persent        let res = filter(manage)        notify(JSON.stringify(res))      });      incomingMessage.on("end", () => {        console.log("end");      });    });    cur.client = clientRequest    clientRequest.end();    clientRequest.on("error", (error) => {      console.error(error);    });    clientRequest.on("close", (val) => {      console.log("close");    });  } else {    const clientRequest = http.request(url, options, (incomingMessage) => {      debugger;      console.log(`状态码: ${incomingMessage.statusCode}`);      let contentLength = incomingMessage.headers["content-length"];      let load = 0;      incomingMessage.on("data", (d) => {        // console.log(incomingMessage)        debugger;        load += d.length;        // process.stdout.write(d);        let persent = Math.floor((load / contentLength) * 10000) / 100;        console.log(d.length, load, contentLength, `${persent}%`);        cur.persent = persent        let res = filter(manage)        notify(JSON.stringify(res))      });      incomingMessage.on("end", () => {        console.log("end");      });    });    cur.client = clientRequest    clientRequest.end();    clientRequest.on("error", (error) => {      console.error(error);    });    clientRequest.on("close", (val) => {      console.log("close");    });  }}/* 通知给窗口 */function notify(message) {  let wins = BrowserWindow.getAllWindows()  for (let win of wins) {    // console.log(win)    win.webContents.send('data-update', message)  }}ipcMain.handle('cancel', (event, { id }) => {  console.log(id)  let cur = manage.find(n => n.id === id)  // cur.controller.abort();  cur.status = 'cancel'  cur.client.destroy()  let res = filter(manage)  notify(JSON.stringify(res))})ipcMain.handle('getCount', () => {  return count})function createWindow() {  // Create the browser window.  const mainWindow = new BrowserWindow({    width: 800,    height: 600,    webPreferences: {      preload: path.join(__dirname, 'preload.js')    }  })  // and load the index.html of the app.  mainWindow.loadFile('index.html')  // Open the DevTools.  // mainWindow.webContents.openDevTools()}// This method will be called when Electron has finished// initialization and is ready to create browser windows.// Some APIs can only be used after this event occurs.app.whenReady().then(() => {  createWindow()  app.on('activate', function () {    // On macOS it's common to re-create a window in the app when the    // dock icon is clicked and there are no other windows open.    if (BrowserWindow.getAllWindows().length === 0) createWindow()  })})// Quit when all windows are closed, except on macOS. There, it's common// for applications and their menu bar to stay active until the user quits// explicitly with Cmd + Q.app.on('window-all-closed', function () {  if (process.platform !== 'darwin') app.quit()})// In this file you can include the rest of your app's specific main process// code. You can also put them in separate files and require them here.
// All of the Node.js APIs are available in the preload process.// It has the same sandbox as a Chrome extension.const { ipcRenderer, contextBridge } = require("electron");window.addEventListener('DOMContentLoaded', () => {  const replaceText = (selector, text) => {    const element = document.getElementById(selector)    if (element) element.innerText = text  }  for (const type of ['chrome', 'node', 'electron']) {    replaceText(`${type}-version`, process.versions[type])  }})contextBridge.exposeInMainWorld('app', {  ipcReceive: (channel, callback) => {    ipcRenderer.on(channel, (eventt, ...rest) => {      callback(...rest)    })  },  ipcSend: (channel, ...msg) => {    ipcRenderer.send(channel, ...msg)  },  ipcInvoke: (channel, ...msg) => {    return ipcRenderer.invoke(channel, ...msg)  },})
// This file is required by the index.html file and will// be executed in the renderer process for that window.// No Node.js APIs are available in this process because// `nodeIntegration` is turned off. Use `preload.js` to// selectively enable features needed in the rendering// process.let newWIn = document.querySelector('#newWIn')let cancel1 = document.querySelector('#cancel1')let cancel2 = document.querySelector('#cancel2')let upload1 = document.querySelector('#upload1')let upload2 = document.querySelector('#upload2')let h1 = document.querySelector('#h1')let downloads = document.querySelector("#downloads")    ; (async function () {        let res = await window.app.ipcInvoke('getCount')        console.log(res, '-------------')        h1.innerHTML = res    })()newWIn.addEventListener('click', () => {    window.app.ipcInvoke('createWindow')})cancel1.addEventListener('click', () => {    window.app.ipcInvoke('cancel', { id: 1 })})cancel2.addEventListener('click', () => {    window.app.ipcInvoke('cancel', { id: 2 })})upload1.addEventListener('click', () => {    window.app.ipcInvoke('upload', { id: 1, url: 'https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe' })})upload2.addEventListener('click', () => {    window.app.ipcInvoke('upload', { id: 2, url: 'https://download.jetbrains.com.cn/python/pycharm-professional-2022.2.1.exe' })})window.app.ipcReceive('data-update', (data) => {    console.log(data, '-------------')    h1.innerHTML = data})