build-domestic-direct-lan-ruleset-dns-mapping-module.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // @ts-check
  2. import path from 'path';
  3. import { DOMESTICS } from '../Source/non_ip/domestic';
  4. import { DIRECTS, LANS } from '../Source/non_ip/direct';
  5. import { readFileIntoProcessedArray } from './lib/fetch-text-by-line';
  6. import { compareAndWriteFile, createRuleset } from './lib/create-file';
  7. import { task } from './trace';
  8. import { SHARED_DESCRIPTION } from './lib/constants';
  9. import { createMemoizedPromise } from './lib/memo-promise';
  10. import * as yaml from 'yaml';
  11. export const getDomesticAndDirectDomainsRulesetPromise = createMemoizedPromise(async () => {
  12. const domestics = await readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/domestic.conf'));
  13. const directs = await readFileIntoProcessedArray(path.resolve(import.meta.dir, '../Source/non_ip/direct.conf'));
  14. const lans: string[] = [];
  15. Object.entries(DOMESTICS).forEach(([, { domains }]) => {
  16. domestics.push(...domains.map((domain) => `DOMAIN-SUFFIX,${domain}`));
  17. });
  18. Object.entries(DIRECTS).forEach(([, { domains }]) => {
  19. directs.push(...domains.map((domain) => `DOMAIN-SUFFIX,${domain}`));
  20. });
  21. Object.entries(LANS).forEach(([, { domains }]) => {
  22. lans.push(...domains.map((domain) => `DOMAIN-SUFFIX,${domain}`));
  23. });
  24. return [domestics, directs, lans] as const;
  25. });
  26. export const buildDomesticRuleset = task(import.meta.main, import.meta.path)(async (span) => {
  27. const res = await getDomesticAndDirectDomainsRulesetPromise();
  28. const dataset = [...Object.entries(DOMESTICS), ...Object.entries(DIRECTS), ...Object.entries(LANS)];
  29. return Promise.all([
  30. createRuleset(
  31. span,
  32. 'Sukka\'s Ruleset - Domestic Domains',
  33. [
  34. ...SHARED_DESCRIPTION,
  35. '',
  36. 'This file contains known addresses that are avaliable in the Mainland China.'
  37. ],
  38. new Date(),
  39. res[0],
  40. 'ruleset',
  41. path.resolve(import.meta.dir, '../List/non_ip/domestic.conf'),
  42. path.resolve(import.meta.dir, '../Clash/non_ip/domestic.txt')
  43. ),
  44. createRuleset(
  45. span,
  46. 'Sukka\'s Ruleset - Direct Rules',
  47. [
  48. ...SHARED_DESCRIPTION,
  49. '',
  50. 'This file contains domains and process that should not be proxied.'
  51. ],
  52. new Date(),
  53. res[1],
  54. 'ruleset',
  55. path.resolve(import.meta.dir, '../List/non_ip/direct.conf'),
  56. path.resolve(import.meta.dir, '../Clash/non_ip/direct.txt')
  57. ),
  58. createRuleset(
  59. span,
  60. 'Sukka\'s Ruleset - LAN',
  61. [
  62. ...SHARED_DESCRIPTION,
  63. '',
  64. 'This file includes rules for LAN DOMAIN and reserved TLDs.'
  65. ],
  66. new Date(),
  67. res[2],
  68. 'ruleset',
  69. path.resolve(import.meta.dir, '../List/non_ip/lan.conf'),
  70. path.resolve(import.meta.dir, '../Clash/non_ip/lan.txt')
  71. ),
  72. compareAndWriteFile(
  73. span,
  74. [
  75. '#!name=[Sukka] Local DNS Mapping',
  76. `#!desc=Last Updated: ${new Date().toISOString()}`,
  77. '',
  78. '[Host]',
  79. ...dataset.flatMap(([, { domains, dns, ...rest }]) => [
  80. ...(
  81. 'hosts' in rest
  82. ? Object.entries(rest.hosts).flatMap(([dns, ips]: [dns: string, ips: string[]]) => `${dns} = ${ips.join(', ')}`)
  83. : []
  84. ),
  85. ...domains.flatMap((domain) => [
  86. `${domain} = server:${dns}`,
  87. `*.${domain} = server:${dns}`
  88. ])
  89. ])
  90. ],
  91. path.resolve(import.meta.dir, '../Modules/sukka_local_dns_mapping.sgmodule')
  92. ),
  93. Bun.write(
  94. path.resolve(import.meta.dir, '../Internal/clash_nameserver_policy.yaml'),
  95. yaml.stringify(
  96. {
  97. dns: {
  98. 'nameserver-policy': dataset.reduce<Record<string, string | string[]>>(
  99. (acc, [, { domains, dns }]) => {
  100. domains.forEach((domain) => {
  101. acc[`+.${domain}`] = dns === 'system'
  102. ? [
  103. 'system://',
  104. 'system',
  105. 'dhcp://system'
  106. ]
  107. : dns;
  108. });
  109. return acc;
  110. },
  111. {}
  112. )
  113. },
  114. hosts: dataset.reduce<Record<string, string>>(
  115. (acc, [, { domains, dns, ...rest }]) => {
  116. if ('hosts' in rest) {
  117. Object.assign(acc, rest.hosts);
  118. }
  119. return acc;
  120. },
  121. {}
  122. )
  123. },
  124. { version: '1.1' }
  125. )
  126. )
  127. ]);
  128. });