Chore: create rule set / Add China IP sing-box

This commit is contained in:
SukkaW
2024-08-14 02:29:03 +08:00
parent da50896ae0
commit 640bac160c
14 changed files with 102 additions and 170 deletions

View File

@@ -7,7 +7,7 @@ import fs from 'fs';
import { fastStringArrayJoin, writeFile } from './misc';
import { readFileByLine } from './fetch-text-by-line';
import stringify from 'json-stringify-pretty-compact';
import { surgeDomainsetToSingbox, surgeRulesetToSingbox } from './singbox';
import { ipCidrListToSingbox, surgeDomainsetToSingbox, surgeRulesetToSingbox } from './singbox';
export async function compareAndWriteFile(span: Span, linesA: string[], filePath: string) {
let isEqual = true;
@@ -79,7 +79,7 @@ export async function compareAndWriteFile(span: Span, linesA: string[], filePath
});
}
export const withBannerArray = (title: string, description: string[] | readonly string[], date: Date, content: string[]) => {
const withBannerArray = (title: string, description: string[] | readonly string[], date: Date, content: string[]) => {
return [
'#########################################',
`# ${title}`,
@@ -154,15 +154,32 @@ const MARK = 'this_ruleset_is_made_by_sukkaw.ruleset.skk.moe';
export const createRuleset = (
parentSpan: Span,
title: string, description: string[] | readonly string[], date: Date, content: string[],
type: ('ruleset' | 'domainset' | string & {}),
type: 'ruleset' | 'domainset' | 'ipcidr' | 'ipcidr6',
surgePath: string, clashPath: string, singBoxPath: string, _clashMrsPath?: string
) => parentSpan.traceChild(`create ruleset: ${path.basename(surgePath, path.extname(surgePath))}`).traceAsyncFn(async (childSpan) => {
const surgeContent = withBannerArray(
title, description, date,
type === 'domainset'
? [MARK, ...content]
: sortRuleSet([`DOMAIN,${MARK}`, ...content])
);
content = sortRuleSet(content);
const surgeContent = childSpan.traceChildSync('process surge ruleset', () => {
let _surgeContent;
switch (type) {
case 'domainset':
_surgeContent = [MARK, ...content];
break;
case 'ruleset':
_surgeContent = [`DOMAIN,${MARK}`, ...content];
break;
case 'ipcidr':
_surgeContent = [`DOMAIN,${MARK}`, ...content.map(i => `IP-CIDR,${i}`)];
break;
case 'ipcidr6':
_surgeContent = [`DOMAIN,${MARK}`, ...content.map(i => `IP-CIDR6,${i}`)];
break;
default:
throw new TypeError(`Unknown type: ${type}`);
}
return withBannerArray(title, description, date, _surgeContent);
});
const clashContent = childSpan.traceChildSync('convert incoming ruleset to clash', () => {
let _clashContent;
switch (type) {
@@ -172,6 +189,10 @@ export const createRuleset = (
case 'ruleset':
_clashContent = [`DOMAIN,${MARK}`, ...surgeRulesetToClashClassicalTextRuleset(content)];
break;
case 'ipcidr':
case 'ipcidr6':
_clashContent = content;
break;
default:
throw new TypeError(`Unknown type: ${type}`);
}
@@ -186,6 +207,10 @@ export const createRuleset = (
case 'ruleset':
_singBoxContent = surgeRulesetToSingbox([`DOMAIN,${MARK}`, ...content]);
break;
case 'ipcidr':
case 'ipcidr6':
_singBoxContent = ipCidrListToSingbox(content);
break;
default:
throw new TypeError(`Unknown type: ${type}`);
}

View File

@@ -1,4 +1,4 @@
import { dirname } from 'path';
import path, { dirname } from 'path';
import fs from 'fs';
import fsp from 'fs/promises';
import { makeRe } from 'picomatch';
@@ -33,3 +33,15 @@ export const writeFile: Write = async (destination: string, input, dir = dirname
export const domainWildCardToRegex = (domain: string) => {
return makeRe(domain, { contains: false, strictSlashes: true }).source;
};
const OUTPUT_SURGE_DIR = path.resolve(__dirname, '../../List');
const OUTPUT_CLASH_DIR = path.resolve(__dirname, '../../Clash');
const OUTPUT_SINGBOX_DIR = path.resolve(__dirname, '../../sing-box');
export const output = (id: string, type: 'non_ip' | 'ip' | 'domainset') => {
return [
path.join(OUTPUT_SURGE_DIR, type, id + '.conf'),
path.join(OUTPUT_CLASH_DIR, type, id + '.txt'),
path.join(OUTPUT_SINGBOX_DIR, type, id + '.json')
] as const;
};

View File

@@ -110,3 +110,12 @@ export const surgeDomainsetToSingbox = (domainset: string[]) => {
rules: [rule]
};
};
export const ipCidrListToSingbox = (ipCidrList: string[]): SingboxSourceFormat => {
return {
version: 2,
rules: [{
ip_cidr: ipCidrList
}]
};
};

View File

@@ -1,54 +0,0 @@
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Polyfill for TextEncoderStream and TextDecoderStream
// Modified by Sukka (https://skk.moe) to increase compatibility and performance with Bun.
export class PolyfillTextDecoderStream extends TransformStream<Uint8Array, string> {
readonly fatal: boolean;
readonly ignoreBOM: boolean;
constructor(
public readonly encoding: BufferEncoding = 'utf-8',
{
fatal = false,
ignoreBOM = false
}: ConstructorParameters<typeof TextDecoder>[1] = {}
) {
const decoder = new TextDecoder(encoding, { fatal, ignoreBOM });
const nonLastChunkDecoderOpt = { stream: true };
super({
transform(chunk: Uint8Array, controller: TransformStreamDefaultController<string>) {
const decoded = decoder.decode(chunk, nonLastChunkDecoderOpt);
controller.enqueue(decoded);
},
flush(controller: TransformStreamDefaultController<string>) {
// If {fatal: false} is in options (the default), then the final call to
// decode() can produce extra output (usually the unicode replacement
// character 0xFFFD). When fatal is true, this call is just used for its
// side-effect of throwing a TypeError exception if the input is
// incomplete.
const output = decoder.decode();
if (output.length > 0) {
controller.enqueue(output);
}
}
});
this.fatal = fatal;
this.ignoreBOM = ignoreBOM;
}
}