Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cidr聚合工具 #161

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ const nextConfig = withPlugins([withTM], {
permanent: true,
},
];
}: undefined,
} : undefined,
webpack: (config) => {
config.resolve.fallback = { fs: false };
config.experiments = {
asyncWebAssembly: true,
};
return config;
},
});
Expand Down
222 changes: 222 additions & 0 deletions public/pkg/cidr_aggregator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
let wasm;

const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );

if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };

let cachedUint8ArrayMemory0 = null;

function getUint8ArrayMemory0() {
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8ArrayMemory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
}

const heap = new Array(128).fill(undefined);

heap.push(undefined, null, true, false);

let heap_next = heap.length;

function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];

heap[idx] = obj;
return idx;
}

let WASM_VECTOR_LEN = 0;

const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );

const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});

function passStringToWasm0(arg, malloc, realloc) {

if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}

let len = arg.length;
let ptr = malloc(len, 1) >>> 0;

const mem = getUint8ArrayMemory0();

let offset = 0;

for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}

if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);

offset += ret.written;
ptr = realloc(ptr, len, offset, 1) >>> 0;
}

WASM_VECTOR_LEN = offset;
return ptr;
}

function getObject(idx) { return heap[idx]; }

function dropObject(idx) {
if (idx < 132) return;
heap[idx] = heap_next;
heap_next = idx;
}

function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
/**
* @param {string} cidrs
* @param {boolean} reverse
* @param {boolean} exclude_reserved
* @returns {any}
*/
export function aggregate(cidrs, reverse, exclude_reserved) {
const ptr0 = passStringToWasm0(cidrs, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.aggregate(ptr0, len0, reverse, exclude_reserved);
return takeObject(ret);
}

async function __wbg_load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);

} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);

} else {
throw e;
}
}
}

const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);

} else {
const instance = await WebAssembly.instantiate(module, imports);

if (instance instanceof WebAssembly.Instance) {
return { instance, module };

} else {
return instance;
}
}
}

function __wbg_get_imports() {
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_json_parse = function(arg0, arg1) {
const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};

return imports;
}

function __wbg_init_memory(imports, memory) {

}

function __wbg_finalize_init(instance, module) {
wasm = instance.exports;
__wbg_init.__wbindgen_wasm_module = module;
cachedUint8ArrayMemory0 = null;



return wasm;
}

function initSync(module) {
if (wasm !== undefined) return wasm;


if (typeof module !== 'undefined' && Object.getPrototypeOf(module) === Object.prototype)
({module} = module)
else
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')

const imports = __wbg_get_imports();

__wbg_init_memory(imports);

if (!(module instanceof WebAssembly.Module)) {
module = new WebAssembly.Module(module);
}

const instance = new WebAssembly.Instance(module, imports);

return __wbg_finalize_init(instance, module);
}

async function __wbg_init(module_or_path) {
if (wasm !== undefined) return wasm;


if (typeof module_or_path !== 'undefined' && Object.getPrototypeOf(module_or_path) === Object.prototype)
({module_or_path} = module_or_path)
else
console.warn('using deprecated parameters for the initialization function; pass a single object instead')

if (typeof module_or_path === 'undefined') {
module_or_path = new URL('cidr_aggregator_bg.wasm', import.meta.url);
}
const imports = __wbg_get_imports();

if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
module_or_path = fetch(module_or_path);
}

__wbg_init_memory(imports);

const { instance, module } = await __wbg_load(await module_or_path, imports);

return __wbg_finalize_init(instance, module);
}

export { initSync };
export default __wbg_init;
Binary file added public/pkg/cidr_aggregator_bg.wasm
Binary file not shown.
37 changes: 37 additions & 0 deletions src/components/CIDR/InputEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { countLines } from '@/utils';
import { Box, TextField, Typography } from '@mui/material';
import { useMemo } from 'react';
import WarningFab from './WarningFab';

export default function InputEditor({
input,
setInput,
output,
}: {
input: string;
output: any;
setInput: (value: string) => void;
}) {
return (
<Box sx={{ position: 'relative' }}>
<TextField
id='input'
label='输入'
placeholder={`6.6.6.0/24\n192.168.1.0/24\n192.168.0.0/16`}
multiline
fullWidth
autoFocus
rows={10}
inputProps={{ wrap: 'soft' }}
value={input}
onChange={(event) => setInput(event.target.value)}
/>
<Box>
<Typography variant='caption' color='textSecondary'>
行数: {useMemo(() => countLines(input), [input])}{' '}
</Typography>
</Box>
<WarningFab invalidLines={output?.invalid} />
</Box>
);
}
38 changes: 38 additions & 0 deletions src/components/CIDR/OptionsControl.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Button, Grid } from '@mui/material';
import { ForwardedRef, forwardRef } from 'react';

function OptionsControl(
{
ipKind,
toggleIpv4,
toggleIpv6,
bogonFilter,
toggleReservedFilter,
handleAggregate,
}: {
ipKind: string;
toggleIpv4: () => void;
toggleIpv6: () => void;
bogonFilter?: string;
toggleReservedFilter: () => void;
handleAggregate: (reverse?: boolean) => void;
},
ref: ForwardedRef<any>
) {
return (
<Grid container ref={ref} direction='row' justifyContent='flex-end'>
<Grid item>
<Button
color='primary'
size='small'
variant='contained'
onClick={() => handleAggregate()}
>
聚合
</Button>
</Grid>
</Grid>
);
}

export default forwardRef(OptionsControl);
34 changes: 34 additions & 0 deletions src/components/CIDR/OutputEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Box, TextField } from '@mui/material';
import OutputStatusLine from './OutputStatusLine';

export default function OutputEditor({
ipKind,
output,
}: {
ipKind: string;
output: any;
}) {
return (
<Box position='relative'>
{' '}
<TextField
id='input'
label='输出'
placeholder='No input'
multiline
fullWidth
rows={10}
inputProps={{ wrap: 'soft' }}
value={[
ipKind !== 'ipv6' && output?.v4?.ranges,
ipKind !== 'ipv4' && output?.v6?.ranges,
]
.filter((v) => v)
.join('\n')}
/>
<Box>
<OutputStatusLine output={output} />
</Box>
</Box>
);
}
27 changes: 27 additions & 0 deletions src/components/CIDR/OutputStatusLine.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Grid, Typography } from '@mui/material';

function Partial({ name, status }: { name: string; status: any }) {
return (
<Typography variant='caption' color='textSecondary'>
{name}: {status?.line_count_before ?? 0}
<abbr title='行数'> 行 </abbr>/ {status?.address_count_before ?? '0'} 个
&nbsp;&nbsp;➟&nbsp;&nbsp;
<b>{status?.line_count_after ?? 0}</b>
<abbr title='行数'> 行</abbr> /{' '}
<b>{status?.address_count_after ?? '0'} </b>个
</Typography>
);
}

export default function OutputStatusLine({ output }: { output: any }) {
return (
<Grid container direction='row' justifyContent='space-between'>
<Grid item>
<Partial name='IPv4' status={output?.v4} />
</Grid>
<Grid item>
<Partial name='IPv6' status={output?.v6} />
</Grid>
</Grid>
);
}
Loading
Loading