check.mjs 5.6 KB

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