check.mjs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import fs from "fs-extra";
  2. import zlib from "zlib";
  3. import path from "path";
  4. import AdmZip from "adm-zip";
  5. import fetch from "node-fetch";
  6. import proxyAgent from "https-proxy-agent";
  7. import { execSync } from "child_process";
  8. const cwd = process.cwd();
  9. const FORCE = process.argv.includes("--force");
  10. /**
  11. * get the correct clash release infomation
  12. */
  13. function resolveClash() {
  14. const { platform, arch } = process;
  15. const CLASH_URL_PREFIX =
  16. "https://github.com/Dreamacro/clash/releases/download/premium/";
  17. const CLASH_LATEST_DATE = "2022.04.11";
  18. // todo
  19. const map = {
  20. "win32-x64": "clash-windows-amd64",
  21. "darwin-x64": "clash-darwin-amd64",
  22. "darwin-arm64": "clash-darwin-arm64",
  23. "linux-x64": "clash-linux-amd64",
  24. };
  25. const name = map[`${platform}-${arch}`];
  26. if (!name) {
  27. throw new Error(`unsupport platform "${platform}-${arch}"`);
  28. }
  29. const isWin = platform === "win32";
  30. const zip = isWin ? "zip" : "gz";
  31. const url = `${CLASH_URL_PREFIX}${name}-${CLASH_LATEST_DATE}.${zip}`;
  32. const exefile = `${name}${isWin ? ".exe" : ""}`;
  33. const zipfile = `${name}.${zip}`;
  34. return { url, zip, exefile, zipfile };
  35. }
  36. /**
  37. * get the sidecar bin
  38. */
  39. async function resolveSidecar() {
  40. const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
  41. const host = execSync("rustc -vV | grep host").toString().slice(6).trim();
  42. const ext = process.platform === "win32" ? ".exe" : "";
  43. const sidecarFile = `clash-${host}${ext}`;
  44. const sidecarPath = path.join(sidecarDir, sidecarFile);
  45. await fs.mkdirp(sidecarDir);
  46. if (!FORCE && (await fs.pathExists(sidecarPath))) return;
  47. // download sidecar
  48. const binInfo = resolveClash();
  49. const tempDir = path.join(cwd, "pre-dev-temp");
  50. const tempZip = path.join(tempDir, binInfo.zipfile);
  51. const tempExe = path.join(tempDir, binInfo.exefile);
  52. await fs.mkdirp(tempDir);
  53. if (!(await fs.pathExists(tempZip))) await downloadFile(binInfo.url, tempZip);
  54. if (binInfo.zip === "zip") {
  55. const zip = new AdmZip(tempZip);
  56. zip.getEntries().forEach((entry) => {
  57. console.log("[INFO]: entry name", entry.entryName);
  58. });
  59. zip.extractAllTo(tempDir, true);
  60. // save as sidecar
  61. await fs.rename(tempExe, sidecarPath);
  62. console.log(`[INFO]: unzip finished`);
  63. } else {
  64. // gz
  65. const readStream = fs.createReadStream(tempZip);
  66. const writeStream = fs.createWriteStream(sidecarPath);
  67. readStream
  68. .pipe(zlib.createGunzip())
  69. .pipe(writeStream)
  70. .on("finish", () => {
  71. console.log(`[INFO]: gunzip finished`);
  72. execSync(`chmod 755 ${sidecarPath}`);
  73. console.log(`[INFO]: chmod binary finished`);
  74. })
  75. .on("error", (error) => console.error(error));
  76. }
  77. // delete temp dir
  78. await fs.remove(tempDir);
  79. }
  80. /**
  81. * only Windows
  82. * get the wintun.dll (not required)
  83. */
  84. async function resolveWintun() {
  85. const { platform } = process;
  86. if (platform !== "win32") return;
  87. const url = "https://www.wintun.net/builds/wintun-0.14.1.zip";
  88. const tempDir = path.join(cwd, "pre-dev-temp-1");
  89. const tempZip = path.join(tempDir, "wintun.zip");
  90. const wintunPath = path.join(tempDir, "wintun/bin/amd64/wintun.dll");
  91. const targetPath = path.join(cwd, "src-tauri/resources", "wintun.dll");
  92. if (!FORCE && (await fs.pathExists(targetPath))) return;
  93. await fs.mkdirp(tempDir);
  94. if (!(await fs.pathExists(tempZip))) {
  95. await downloadFile(url, tempZip);
  96. }
  97. // unzip
  98. const zip = new AdmZip(tempZip);
  99. zip.extractAllTo(tempDir, true);
  100. if (!(await fs.pathExists(wintunPath))) {
  101. throw new Error(`path not found "${wintunPath}"`);
  102. }
  103. // move wintun.dll to resources
  104. await fs.rename(wintunPath, targetPath);
  105. // delete temp dir
  106. await fs.remove(tempDir);
  107. console.log(`[INFO]: resolve wintun.dll finished`);
  108. }
  109. /**
  110. * get the Country.mmdb (not required)
  111. */
  112. async function resolveMmdb() {
  113. const url =
  114. "https://github.com/Dreamacro/maxmind-geoip/releases/latest/download/Country.mmdb";
  115. const resDir = path.join(cwd, "src-tauri", "resources");
  116. const resPath = path.join(resDir, "Country.mmdb");
  117. if (!FORCE && (await fs.pathExists(resPath))) return;
  118. await fs.mkdirp(resDir);
  119. await downloadFile(url, resPath);
  120. }
  121. /**
  122. * download file and save to `path`
  123. */
  124. async function downloadFile(url, path) {
  125. console.log(`[INFO]: downloading from "${url}"`);
  126. const options = {};
  127. const httpProxy =
  128. process.env.HTTP_PROXY ||
  129. process.env.http_proxy ||
  130. process.env.HTTPS_PROXY ||
  131. process.env.https_proxy;
  132. if (httpProxy) {
  133. options.agent = proxyAgent(httpProxy);
  134. }
  135. const response = await fetch(url, {
  136. ...options,
  137. method: "GET",
  138. headers: { "Content-Type": "application/octet-stream" },
  139. });
  140. const buffer = await response.arrayBuffer();
  141. await fs.writeFile(path, new Uint8Array(buffer));
  142. console.log(`[INFO]: download finished "${url}"`);
  143. }
  144. /// main
  145. resolveSidecar().catch(console.error);
  146. resolveWintun().catch(console.error);
  147. resolveMmdb().catch(console.error);