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

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