Skip to content

Commit

Permalink
feat: ruleset hub
Browse files Browse the repository at this point in the history
  • Loading branch information
Ayideyia committed Sep 27, 2024
1 parent 773fca6 commit 826ebda
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 8 deletions.
14 changes: 9 additions & 5 deletions frontend/src/lang/locale/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ export default {
expire: 'Expire',
subtype: 'Subscription Type',
website: 'Website',
empty: 'The subscription list is empty. Please {action} a subscription first.',
empty: 'The subscription list is empty. Please{action}a subscription first.',
enterLink: 'Enter subscription link',
proxyCount: 'Proxy Count',
editProxies: 'Edit Proxies',
Expand Down Expand Up @@ -400,7 +400,7 @@ export default {
},
profiles: {
shouldStop: 'Unable to delete, this profile is in use.',
empty: 'The profiles list is empty, Please {action} a profile first.',
empty: 'The profiles list is empty, Please{action}a profile first.',
copytoClipboard: 'Generate config to clipboard',
generateAndView: 'Generate and View',
copy: 'Copy and Paste',
Expand All @@ -423,7 +423,11 @@ export default {
updating: 'Updating'
},
rulesets: {
empty: 'The ruleset list is empty. Please {action} a ruleset first.',
hub: 'Ruleset-Hub',
total: 'Number of rule-sets',
noDesc: 'No description',
updating: 'Updating',
empty: 'The ruleset list is empty. Please{action}or import from the{import}first.',
rulesetCount: 'Ruleset Count',
editRuleset: 'Edit Rules',
selectRuleType: 'Select Rule Type'
Expand Down Expand Up @@ -461,7 +465,7 @@ export default {
},
plugins: {
updating: 'Updating',
empty: 'The plugin list is empty. Please {action} or import from the {import} first.',
empty: 'The plugin list is empty. Please{action}or import from the{import}first.',
source: 'Source',
reload: 'Reload',
configuration: 'Configure',
Expand Down Expand Up @@ -497,7 +501,7 @@ export default {
endTime: 'End Time',
time: 'Time',
result: 'Result',
empty: 'The scheduled task list is empty. Please {action} a scheduled task first.',
empty: 'The scheduled task list is empty. Please{action}a scheduled task first.',
run: 'Run now',
log: 'View log'
},
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/lang/locale/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,11 @@ export default {
updating: '更新中'
},
rulesets: {
empty: '规则集列表为空,请先{action}规则集。',
hub: '规则集中心',
total: '规则集数量为',
noDesc: '无描述信息',
updating: '更新中',
empty: '规则集列表为空,请先{action}或从{import}导入。',
rulesetCount: '规则数量',
editRuleset: '编辑规则集文件',
selectRuleType: '选择规则类型'
Expand Down
198 changes: 198 additions & 0 deletions frontend/src/views/RulesetsView/components/RulesetHub.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useMessage } from '@/hooks'
import { ignoredError } from '@/utils'
import { useRulesetsStore } from '@/stores'
import { HttpGet, Readfile, Writefile } from '@/bridge'
import { RulesetFormat } from '@/constant'
type RulesetHub = {
geosite: string
geoip: string
list: { name: string; type: 'geosite' | 'geoip'; description: string; count: number }[]
}
const loading = ref(false)
const rulesetHub = ref<RulesetHub>({ geosite: '', geoip: '', list: [] })
const cacheFile = 'data/.cache/ruleset-list.json'
const hubUrl = 'https://github.com/GUI-for-Cores/Ruleset-Hub/releases/download/latest/sing.json'
const { t } = useI18n()
const { message } = useMessage()
const rulesetsStore = useRulesetsStore()
const keywords = ref('')
const filteredList = computed(() => {
if (!keywords.value) return rulesetHub.value.list
return rulesetHub.value.list.filter((ruleset) => ruleset.name.includes(keywords.value))
})
const updateList = async () => {
loading.value = true
try {
const { body } = await HttpGet<string>(hubUrl)
rulesetHub.value = JSON.parse(body)
await Writefile(cacheFile, body)
message.success('plugins.updateSuccess')
} catch (error: any) {
message.error(error)
}
loading.value = false
}
const getList = async () => {
const body = await ignoredError(Readfile, cacheFile)
if (body) {
rulesetHub.value = JSON.parse(body)
return
}
updateList()
}
const handleAddRuleset = async (ruleset: RulesetHub['list'][number], format: RulesetFormat) => {
const suffix = { [RulesetFormat.Binary]: '.srs', [RulesetFormat.Source]: '.json' }[format]
const id = ruleset.type + '_' + ruleset.name + '.' + format
const file = ruleset.type + '_' + ruleset.name + suffix
const basrUrl = { geosite: rulesetHub.value.geosite, geoip: rulesetHub.value.geoip }[ruleset.type]
try {
await rulesetsStore.addRuleset({
id,
tag: ruleset.name,
updateTime: 0,
disabled: false,
type: 'Http',
format,
path: 'data/rulesets/' + file,
url: basrUrl + ruleset.name + suffix,
count: ruleset.count
})
const { success } = message.info('rulesets.updating')
await rulesetsStore.updateRuleset(id)
success('common.success')
} catch (error: any) {
console.error(error)
message.error(error.message || error)
}
}
const isAlreadyAdded = (id: string) => rulesetsStore.getRulesetById(id)
getList()
</script>

<template>
<div class="ruleset-hub">
<div v-if="loading" class="loading"><Button type="text" loading /></div>
<template v-else>
<div class="header">
<Button type="text">{{ t('rulesets.total') }} : {{ rulesetHub.list.length }}</Button>
<Input
v-model="keywords"
size="small"
clearable
auto-size
:placeholder="t('common.keywords')"
class="ml-8 flex-1"
/>
<Button @click="updateList" type="link" class="ml-auto">
{{ t('plugins.update') }}
</Button>
</div>

<div class="list">
<Card
v-for="ruleset in filteredList"
:key="ruleset.name + ruleset.type"
:title="ruleset.name"
class="ruleset-item"
>
<template #extra>
<Tag size="small" color="cyan">{{ ruleset.type }}</Tag>
</template>
<div class="description">
{{ ruleset.description || t('rulesets.noDesc') }}
</div>
<div class="action">
<template
v-if="isAlreadyAdded(ruleset.type + '_' + ruleset.name + '.' + RulesetFormat.Source)"
>
<Button type="text" size="small">
{{ t('ruleset.format.source') }} {{ t('common.added') }}
</Button>
</template>
<template v-else>
<Button
@click="handleAddRuleset(ruleset, RulesetFormat.Source)"
type="link"
size="small"
>
{{ t('common.add') }} {{ t('ruleset.format.source') }}
</Button>
</template>
<template
v-if="isAlreadyAdded(ruleset.type + '_' + ruleset.name + '.' + RulesetFormat.Binary)"
>
<Button type="text" size="small">
{{ t('ruleset.format.binary') }} {{ t('common.added') }}
</Button>
</template>
<template v-else>
<Button
@click="handleAddRuleset(ruleset, RulesetFormat.Binary)"
type="link"
size="small"
>
{{ t('common.add') }} {{ t('ruleset.format.binary') }}
</Button>
</template>
</div>
</Card>
</div>
</template>
</div>
</template>

<style lang="less" scoped>
.ruleset-hub {
display: flex;
flex-direction: column;
height: 100%;
.ruleset-item {
display: inline-block;
margin: 4px;
font-size: 12px;
width: calc(33.333% - 8px);
.description {
margin: 4px 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action {
text-align: right;
}
}
}
.loading {
display: flex;
justify-content: center;
height: 98%;
}
.header {
display: flex;
align-items: center;
}
.list {
padding-bottom: 16px;
overflow: auto;
}
</style>
27 changes: 25 additions & 2 deletions frontend/src/views/RulesetsView/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import {
import RulesetForm from './components/RulesetForm.vue'
import RulesetView from './components/RulesetView.vue'
import RulesetHub from './components/RulesetHub.vue'
const showRulesetForm = ref(false)
const showRulesetList = ref(false)
const showRulesetHub = ref(false)
const rulesetTitle = ref('')
const rulesetFormID = ref()
const rulesetFormIsUpdate = ref(false)
Expand Down Expand Up @@ -58,6 +60,10 @@ const envStore = useEnvStore()
const rulesetsStore = useRulesetsStore()
const appSettingsStore = useAppSettingsStore()
const handleImportRuleset = async () => {
showRulesetHub.value = true
}
const handleAddRuleset = async () => {
rulesetFormIsUpdate.value = false
showRulesetForm.value = true
Expand Down Expand Up @@ -177,6 +183,9 @@ const onSortUpdate = debounce(rulesetsStore.saveRulesets, 1000)
<template #action>
<Button @click="handleAddRuleset" type="link">{{ t('common.add') }}</Button>
</template>
<template #import>
<Button @click="handleImportRuleset" type="link">{{ t('rulesets.hub') }}</Button>
</template>
</I18nT>
</template>
</Empty>
Expand All @@ -190,11 +199,13 @@ const onSortUpdate = debounce(rulesetsStore.saveRulesets, 1000)
{ label: 'common.list', value: View.List }
]"
/>
<Button @click="handleImportRuleset" type="link" class="ml-auto">
{{ t('rulesets.hub') }}
</Button>
<Button
@click="handleUpdateRulesets"
:disabled="noUpdateNeeded"
:type="noUpdateNeeded ? 'text' : 'link'"
class="ml-auto"
>
{{ t('common.updateAll') }}
</Button>
Expand Down Expand Up @@ -268,7 +279,7 @@ const onSortUpdate = debounce(rulesetsStore.saveRulesets, 1000)
</Button>
</template>

<div>
<div v-if="r.format === RulesetFormat.Binary">
{{ t('ruleset.format.name') }}
:
{{ r.format || '--' }}
Expand Down Expand Up @@ -311,6 +322,18 @@ const onSortUpdate = debounce(rulesetsStore.saveRulesets, 1000)
<RulesetForm :is-update="rulesetFormIsUpdate" :id="rulesetFormID" />
</Modal>

<Modal
v-model:open="showRulesetHub"
title="rulesets.hub"
:submit="false"
mask-closable
cancel-text="common.close"
height="90"
width="90"
>
<RulesetHub />
</Modal>

<Modal
v-model:open="showRulesetList"
:title="rulesetTitle"
Expand Down

0 comments on commit 826ebda

Please sign in to comment.