import { homedir } from 'os' ; import { join as pathjoin } from 'path' ; import Yaml from 'js-yaml' ; import fse from 'fs-extra' ; import request from 'umi-request' ; import store from '@ui/store' ; import { ClashConfig } from '@ui/common/define' ; import { ProxyGroupType } from '@ui/common/define/ClashConfig' ; export default async function genConfig ( options = { } ) { const { forceUpdate = false } = options ; const rootState = store . getState ( ) ; const subscribeList = rootState . librarySubscribe . list ; const subscribeDetail = rootState . librarySubscribe . detail ; const ruleList = rootState . libraryRuleList . list ; const { list : resultList , name } = rootState . currentConfig ; const resultItemList = resultList . map ( ( { type , id } ) => { if ( type === 'subscribe' ) { const item = subscribeList . find ( ( x ) => x . id === id ) ; if ( item ) { return { item , type } ; } } if ( type === 'rule' ) { const item = ruleList . find ( ( x ) => x . id === id ) ; if ( item ) { return { item , type } ; } } } ) . filter ( Boolean ) ; const subscribeArr = resultItemList . filter ( ( x ) => x . type === 'subscribe' ) ; const ruleArr = resultItemList . filter ( ( x ) => x . type === 'rule' ) ; /**
     * config merge
     */ let config = { } ; for ( const r of ruleArr ) { const { item } = r ; const { type , url , content } = item ; let usingContent = content ; if ( type === 'remote' ) { usingContent = await request . get ( url , { responseType : 'text' , headers : { 'x-extra-headers' : JSON . stringify ( { 'user-agent' : 'clash' } ) } , } ) ; } const cur = Yaml . load ( usingContent ) ; const { rules , ... otherConfig } = cur ; config = { ... otherConfig , ... config , rules : [ ... ( config . rules || [ ] ) , ... ( rules || [ ] ) ] } ; } /**
     * subscribe
     */ if ( ! config . proxies || ! Array . isArray ( config . proxies ) ) { config . proxies = [ ] ; } if ( ! config [ 'proxy-groups' ] || ! Array . isArray ( config [ 'proxy-groups' ] ) ) { config [ 'proxy-groups' ] = [ ] ; } for ( const s of subscribeArr ) { const { item } = s ; const { url } = item ; let servers ; await store . dispatch . librarySubscribe . update ( { url , silent : true , forceUpdate } ) ; servers = store . getState ( ) . librarySubscribe . detail [ url ] ; config . proxies = config . proxies . concat ( servers ) ; } const proxyGroups = config [ 'proxy-groups' ] ; const allProxies = config . proxies . map ( ( row ) => row . name ) ; proxyGroups . filter ( ( item ) => ! item . proxies || ! Array . isArray ( item . proxies ) || ! item . proxies . length ) . forEach ( ( item ) => { item . proxies = allProxies ; } ) ; const existNames = proxyGroups . map ( ( i ) => i . name ) ; for ( const line of config . rules ) { const use = line . split ( ',' ) . slice ( - 1 ) [ 0 ] ; if ( ! use ) continue ; if ( [ 'DIRECT' , 'REJECT' , 'no-resolve' ] . includes ( use ) ) continue ; if ( existNames . includes ( use ) ) continue ; const newgroup = { name : use , type : ProxyGroupType . Select , proxies : [ 'DIRECT' , 'Proxy' , 'REJECT' ] , } ; config [ 'proxy-groups' ] . push ( newgroup ) ; existNames . push ( use ) ; } const configYaml = Yaml . safeDump ( config ) ; const file = getConfigFile ( name ) ; fse . writeFileSync ( file , configYaml ) ; console . log ( configYaml ) ; console . log ( '[done]: %s writed' , file ) ; return { success : true , filename : file , msg : `${ file } writed` , } ; } export const DEFAULT_NAME = 'clash-config-manager' ; export function getConfigFile ( name ) { name = name || DEFAULT_NAME ; return pathjoin ( homedir ( ) , `.config/clash/${ name }.yaml` ) ; } export function getConfigFileDisplay ( name ) { name = name || DEFAULT_NAME ; return `~/.config/clash/${ name }.yaml` ; }