mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-16 03:32:17 +08:00
use nodejs vm and get script log
This commit is contained in:
parent
82d42be8d5
commit
1e2b0b92cc
|
@ -89,7 +89,7 @@ export async function createOverride(item: Partial<IOverrideItem>): Promise<IOve
|
|||
return newItem
|
||||
}
|
||||
|
||||
export async function getOverride(id: string, ext: 'js' | 'yaml'): Promise<string> {
|
||||
export async function getOverride(id: string, ext: 'js' | 'yaml' | 'log'): Promise<string> {
|
||||
if (!existsSync(overridePath(id, ext))) {
|
||||
return ''
|
||||
}
|
||||
|
|
|
@ -6,10 +6,12 @@ import {
|
|||
getOverride,
|
||||
getOverrideItem
|
||||
} from '../config'
|
||||
import { mihomoWorkConfigPath } from '../utils/dirs'
|
||||
import { mihomoWorkConfigPath, overridePath } from '../utils/dirs'
|
||||
import yaml from 'yaml'
|
||||
import { readFile, writeFile } from 'fs/promises'
|
||||
import { deepMerge } from '../utils/merge'
|
||||
import vm from 'vm'
|
||||
import { writeFileSync } from 'fs'
|
||||
|
||||
export async function generateProfile(): Promise<void> {
|
||||
const { current } = await getProfileConfig()
|
||||
|
@ -29,7 +31,7 @@ async function overrideProfile(
|
|||
const content = await getOverride(ov, item?.ext || 'js')
|
||||
switch (item?.ext) {
|
||||
case 'js':
|
||||
profile = runOverrideScript(profile, content)
|
||||
profile = runOverrideScript(profile, content, item)
|
||||
break
|
||||
case 'yaml': {
|
||||
const patch = yaml.parse(content)
|
||||
|
@ -47,13 +49,45 @@ async function overrideProfile(
|
|||
return profile
|
||||
}
|
||||
|
||||
function runOverrideScript(profile: IMihomoConfig, script: string): IMihomoConfig {
|
||||
function runOverrideScript(
|
||||
profile: IMihomoConfig,
|
||||
script: string,
|
||||
item: IOverrideItem
|
||||
): IMihomoConfig {
|
||||
const log = (type: string, data: string, flag = 'a'): void => {
|
||||
writeFileSync(overridePath(item.id, 'log'), `[${type}] ${data}\n`, {
|
||||
encoding: 'utf-8',
|
||||
flag
|
||||
})
|
||||
}
|
||||
try {
|
||||
const func = eval(`${script} main`)
|
||||
const newProfile = func(profile)
|
||||
if (typeof newProfile !== 'object') return profile
|
||||
const ctx = {
|
||||
console: Object.freeze({
|
||||
log(data: never) {
|
||||
log('log', JSON.stringify(data))
|
||||
},
|
||||
info(data: never) {
|
||||
log('info', JSON.stringify(data))
|
||||
},
|
||||
error(data: never) {
|
||||
log('error', JSON.stringify(data))
|
||||
},
|
||||
debug(data: never) {
|
||||
log('debug', JSON.stringify(data))
|
||||
}
|
||||
})
|
||||
}
|
||||
vm.createContext(ctx)
|
||||
const code = `${script} main(${JSON.stringify(profile)})`
|
||||
log('info', '开始执行脚本', 'w')
|
||||
const newProfile = vm.runInContext(code, ctx)
|
||||
if (typeof newProfile !== 'object') {
|
||||
throw new Error('脚本返回值必须是对象')
|
||||
}
|
||||
log('info', '脚本执行成功')
|
||||
return newProfile
|
||||
} catch (e) {
|
||||
log('exception', `脚本执行失败: ${e}`)
|
||||
return profile
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export function overrideConfigPath(): string {
|
|||
return path.join(dataDir(), 'override.yaml')
|
||||
}
|
||||
|
||||
export function overridePath(id: string, ext: 'js' | 'yaml'): string {
|
||||
export function overridePath(id: string, ext: 'js' | 'yaml' | 'log'): string {
|
||||
return path.join(overrideDir(), `${id}.${ext}`)
|
||||
}
|
||||
|
||||
|
|
58
src/renderer/src/components/override/exec-log-modal.tsx
Normal file
58
src/renderer/src/components/override/exec-log-modal.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
Modal,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalBody,
|
||||
ModalFooter,
|
||||
Button,
|
||||
Divider
|
||||
} from '@nextui-org/react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { getOverride } from '@renderer/utils/ipc'
|
||||
interface Props {
|
||||
id: string
|
||||
onClose: () => void
|
||||
}
|
||||
const ExecLogModal: React.FC<Props> = (props) => {
|
||||
const { id, onClose } = props
|
||||
const [logs, setLogs] = useState<string[]>([])
|
||||
|
||||
const getLog = async (): Promise<void> => {
|
||||
setLogs((await getOverride(id, 'log')).split('\n').filter(Boolean))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getLog()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
backdrop="blur"
|
||||
hideCloseButton
|
||||
isOpen={true}
|
||||
onOpenChange={onClose}
|
||||
scrollBehavior="inside"
|
||||
>
|
||||
<ModalContent>
|
||||
<ModalHeader className="flex">执行日志</ModalHeader>
|
||||
<ModalBody>
|
||||
{logs.map((log) => {
|
||||
return (
|
||||
<>
|
||||
<small className="break-all">{log}</small>
|
||||
<Divider />
|
||||
</>
|
||||
)
|
||||
})}
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button variant="light" onPress={onClose}>
|
||||
关闭
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ExecLogModal
|
|
@ -15,6 +15,7 @@ import EditFileModal from './edit-file-modal'
|
|||
import EditInfoModal from './edit-info-modal'
|
||||
import { useSortable } from '@dnd-kit/sortable'
|
||||
import { CSS } from '@dnd-kit/utilities'
|
||||
import ExecLogModal from './exec-log-modal'
|
||||
|
||||
interface Props {
|
||||
info: IOverrideItem
|
||||
|
@ -43,6 +44,13 @@ const menuItems: MenuItem[] = [
|
|||
{
|
||||
key: 'edit-file',
|
||||
label: '编辑文件',
|
||||
showDivider: false,
|
||||
color: 'default',
|
||||
className: ''
|
||||
} as MenuItem,
|
||||
{
|
||||
key: 'exec-log',
|
||||
label: '执行日志',
|
||||
showDivider: true,
|
||||
color: 'default',
|
||||
className: ''
|
||||
|
@ -62,6 +70,7 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||
const [updating, setUpdating] = useState(false)
|
||||
const [openInfo, setOpenInfo] = useState(false)
|
||||
const [openFile, setOpenFile] = useState(false)
|
||||
const [openLog, setOpenLog] = useState(false)
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
|
@ -85,6 +94,10 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||
setOpenFile(true)
|
||||
break
|
||||
}
|
||||
case 'exec-log': {
|
||||
setOpenLog(true)
|
||||
break
|
||||
}
|
||||
case 'delete': {
|
||||
removeOverrideItem(info.id)
|
||||
mutateOverrideConfig()
|
||||
|
@ -129,6 +142,7 @@ const OverrideItem: React.FC<Props> = (props) => {
|
|||
updateOverrideItem={updateOverrideItem}
|
||||
/>
|
||||
)}
|
||||
{openLog && <ExecLogModal id={info.id} onClose={() => setOpenLog(false)} />}
|
||||
<Card
|
||||
fullWidth
|
||||
isPressable
|
||||
|
|
|
@ -181,7 +181,7 @@ export async function updateOverrideItem(item: IOverrideItem): Promise<void> {
|
|||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('updateOverrideItem', item))
|
||||
}
|
||||
|
||||
export async function getOverride(id: string, ext: 'js' | 'yaml'): Promise<string> {
|
||||
export async function getOverride(id: string, ext: 'js' | 'yaml' | 'log'): Promise<string> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('getOverride', id, ext))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user