mirror of
https://github.com/xfgryujk/blivechat.git
synced 2024-12-26 21:00:15 +08:00
添加插件管理前端
This commit is contained in:
parent
e1d0473627
commit
29ff61748b
@ -24,4 +24,7 @@ data/emoticons/*
|
|||||||
!data/custom_public/
|
!data/custom_public/
|
||||||
data/custom_public/*
|
data/custom_public/*
|
||||||
!data/custom_public/README.txt
|
!data/custom_public/README.txt
|
||||||
|
!data/plugins/
|
||||||
|
data/plugins/*
|
||||||
|
!data/plugins/.gitkeep
|
||||||
log/*
|
log/*
|
||||||
|
@ -24,6 +24,8 @@ class _AdminHandlerBase(api.base.ApiHandler):
|
|||||||
if not cfg.enable_admin_plugins:
|
if not cfg.enable_admin_plugins:
|
||||||
raise tornado.web.HTTPError(403)
|
raise tornado.web.HTTPError(403)
|
||||||
|
|
||||||
|
logger.info('client=%s requesting admin plugin, cls=%s', self.request.remote_ip, type(self).__name__)
|
||||||
|
|
||||||
super().prepare()
|
super().prepare()
|
||||||
|
|
||||||
def _get_plugin(self):
|
def _get_plugin(self):
|
||||||
@ -60,16 +62,21 @@ class EnableHandler(_AdminHandlerBase):
|
|||||||
enabled = bool(self.json_args.get('enabled', False))
|
enabled = bool(self.json_args.get('enabled', False))
|
||||||
|
|
||||||
plugin = self._get_plugin()
|
plugin = self._get_plugin()
|
||||||
|
old_enabled = plugin.enabled
|
||||||
|
is_switch_success = True
|
||||||
msg = ''
|
msg = ''
|
||||||
try:
|
try:
|
||||||
plugin.enabled = enabled
|
plugin.enabled = enabled
|
||||||
except services.plugin.StartTooFrequently as e:
|
except services.plugin.SwitchTooFrequently as e:
|
||||||
|
is_switch_success = False
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
plugin.enabled = False
|
plugin.enabled = old_enabled
|
||||||
except services.plugin.StartPluginError as e:
|
except services.plugin.SwitchPluginError as e:
|
||||||
|
is_switch_success = False
|
||||||
msg = str(e)
|
msg = str(e)
|
||||||
self.write({
|
self.write({
|
||||||
'enabled': plugin.enabled,
|
'enabled': plugin.enabled,
|
||||||
|
'isSwitchSuccess': is_switch_success,
|
||||||
'msg': msg
|
'msg': msg
|
||||||
})
|
})
|
||||||
|
|
||||||
|
16
frontend/src/api/plugins.js
Normal file
16
frontend/src/api/plugins.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export async function getPlugins() {
|
||||||
|
return (await axios.get('/api/plugin/plugins')).data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setEnabled(pluginId, enabled) {
|
||||||
|
return (await axios.post('/api/plugin/enable_plugin', {
|
||||||
|
pluginId,
|
||||||
|
enabled
|
||||||
|
})).data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function openAdminUi(pluginId) {
|
||||||
|
return (await axios.post('/api/plugin/open_admin_ui', { pluginId })).data
|
||||||
|
}
|
@ -3,6 +3,7 @@ export default {
|
|||||||
home: 'Home',
|
home: 'Home',
|
||||||
stylegen: 'Style Generator',
|
stylegen: 'Style Generator',
|
||||||
help: 'Help',
|
help: 'Help',
|
||||||
|
plugins: 'Plugins',
|
||||||
links: 'Links',
|
links: 'Links',
|
||||||
projectAddress: 'Project Address',
|
projectAddress: 'Project Address',
|
||||||
discussion: 'Discussions',
|
discussion: 'Discussions',
|
||||||
@ -169,5 +170,25 @@ export default {
|
|||||||
sendGift: 'Sent {giftName}x{num}',
|
sendGift: 'Sent {giftName}x{num}',
|
||||||
membershipTitle: 'New member',
|
membershipTitle: 'New member',
|
||||||
tickerMembership: 'Member'
|
tickerMembership: 'Member'
|
||||||
}
|
},
|
||||||
|
plugins: {
|
||||||
|
plugins: 'Plugins',
|
||||||
|
help: 'Help',
|
||||||
|
helpContent: `\
|
||||||
|
<p>Plugins can add more functionality to blivechat, such as message logging, text to speech, song requests, etc. Plugins may
|
||||||
|
be developed by third-party authors, and the security and quality are the responsibility of the plugin author. You can
|
||||||
|
find some published plugins in <a target="_blank" href="https://github.com/xfgryujk/blivechat/discussions/categories/%E6%8F%92%E4%BB%B6"
|
||||||
|
>GitHub Discussions</a></p>
|
||||||
|
<p>Plugin installation method: Put the extracted plugin directory into the "data/plugins" directory, then restart blivechat</p>
|
||||||
|
<p>Notes: Most plugins require enabling the "Relay messages by the server" option and connecting to the room
|
||||||
|
in order to receive messages</p>
|
||||||
|
<p><a target="_blank" href="https://github.com/xfgryujk/blivechat/wiki/%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F">
|
||||||
|
Plugin development documentation</a></p>
|
||||||
|
`,
|
||||||
|
author: 'Author: ',
|
||||||
|
disabledByServer: 'Administration for plugins is disabled by the server',
|
||||||
|
admin: 'Admin',
|
||||||
|
connected: 'Connected',
|
||||||
|
unconnected: 'Unconnected',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ export default {
|
|||||||
home: 'トップページ',
|
home: 'トップページ',
|
||||||
stylegen: 'スタイルジェネレータ',
|
stylegen: 'スタイルジェネレータ',
|
||||||
help: 'ヘルプ',
|
help: 'ヘルプ',
|
||||||
|
plugins: 'プラグイン',
|
||||||
links: 'リンク',
|
links: 'リンク',
|
||||||
projectAddress: 'プロジェクトアドレス',
|
projectAddress: 'プロジェクトアドレス',
|
||||||
discussion: '議論',
|
discussion: '議論',
|
||||||
@ -169,5 +170,25 @@ export default {
|
|||||||
sendGift: '{giftName}x{num} を贈りました',
|
sendGift: '{giftName}x{num} を贈りました',
|
||||||
membershipTitle: '新規メンバー',
|
membershipTitle: '新規メンバー',
|
||||||
tickerMembership: 'メンバー'
|
tickerMembership: 'メンバー'
|
||||||
}
|
},
|
||||||
|
plugins: {
|
||||||
|
plugins: 'プラグイン',
|
||||||
|
help: 'ヘルプ',
|
||||||
|
helpContent: `\
|
||||||
|
<p>プラグインは、メッセージの記録、テキスト読み上げ、曲リクエストなど、blivechatにさらなる機能を追加できます。
|
||||||
|
プラグインはサードパーティの作者によって開発される場合があり、セキュリティと品質はプラグイン作者の責任です。
|
||||||
|
いくつかの公開されたプラグインは<a target="_blank" href="https://github.com/xfgryujk/blivechat/discussions/categories/%E6%8F%92%E4%BB%B6"
|
||||||
|
>GitHub Discussions</a>で見つけることができます</p>
|
||||||
|
<p>プラグインのインストール方法:抽出されたプラグインディレクトリを「data/plugins」ディレクトリに配置し、blivechatを再起動します</p>
|
||||||
|
<p>注意:ほとんどのプラグインは、「サーバを介してメッセージを転送する」オプションを有効にし、メッセージを受信するために
|
||||||
|
ルームに接続する必要があります</p>
|
||||||
|
<p><a target="_blank" href="https://github.com/xfgryujk/blivechat/wiki/%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F"
|
||||||
|
>プラグイン開発ドキュメント</a></p>
|
||||||
|
`,
|
||||||
|
author: '作者:',
|
||||||
|
disabledByServer: 'プラグインの管理は、サーバーによって無効にされています',
|
||||||
|
admin: '管理',
|
||||||
|
connected: '接続済み',
|
||||||
|
unconnected: '未接続',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ export default {
|
|||||||
home: '首页',
|
home: '首页',
|
||||||
stylegen: '样式生成器',
|
stylegen: '样式生成器',
|
||||||
help: '帮助',
|
help: '帮助',
|
||||||
|
plugins: '插件',
|
||||||
links: '常用链接',
|
links: '常用链接',
|
||||||
projectAddress: '项目地址',
|
projectAddress: '项目地址',
|
||||||
discussion: '反馈 / 交流',
|
discussion: '反馈 / 交流',
|
||||||
@ -169,5 +170,22 @@ export default {
|
|||||||
sendGift: '赠送 {giftName}x{num}',
|
sendGift: '赠送 {giftName}x{num}',
|
||||||
membershipTitle: '新会员',
|
membershipTitle: '新会员',
|
||||||
tickerMembership: '会员'
|
tickerMembership: '会员'
|
||||||
}
|
},
|
||||||
|
plugins: {
|
||||||
|
plugins: '插件',
|
||||||
|
help: '帮助',
|
||||||
|
helpContent: `\
|
||||||
|
<p>插件可以给blivechat添加更多功能,比如消息日志、语音播报、点歌等。插件可能由第三方作者开发,其安全性和质量由插件作者负责。
|
||||||
|
你可以在<a target="_blank" href="https://github.com/xfgryujk/blivechat/discussions/categories/%E6%8F%92%E4%BB%B6"
|
||||||
|
>GitHub Discussions</a>获取一些已发布的插件</p>
|
||||||
|
<p>插件安装方法:把解压后的插件目录放到“data/plugins”目录,然后重启blivechat</p>
|
||||||
|
<p>注意事项:大部分插件需要开启“通过服务器转发消息”,并且连接到房间,才能接收消息</p>
|
||||||
|
<p><a target="_blank" href="https://github.com/xfgryujk/blivechat/wiki/%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F">插件开发文档</a></p>
|
||||||
|
`,
|
||||||
|
author: '作者:',
|
||||||
|
disabledByServer: '已被服务器禁用',
|
||||||
|
admin: '管理',
|
||||||
|
connected: '已连接',
|
||||||
|
unconnected: '未连接',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
<el-menu-item :index="$router.resolve({ name: 'help' }).href">
|
<el-menu-item :index="$router.resolve({ name: 'help' }).href">
|
||||||
<i class="el-icon-question"></i>{{ $t('sidebar.help') }}
|
<i class="el-icon-question"></i>{{ $t('sidebar.help') }}
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
<el-menu-item :index="$router.resolve({ name: 'plugins' }).href">
|
||||||
|
<i class="el-icon-magic-stick"></i>{{ $t('sidebar.plugins') }}
|
||||||
|
</el-menu-item>
|
||||||
<el-submenu index="1">
|
<el-submenu index="1">
|
||||||
<template slot="title">
|
<template slot="title">
|
||||||
<i class="el-icon-link"></i>{{ $t('sidebar.links') }}
|
<i class="el-icon-link"></i>{{ $t('sidebar.links') }}
|
||||||
|
@ -21,7 +21,8 @@ const router = new VueRouter({
|
|||||||
children: [
|
children: [
|
||||||
{ path: '', name: 'home', component: () => import('./views/Home') },
|
{ path: '', name: 'home', component: () => import('./views/Home') },
|
||||||
{ path: 'stylegen', name: 'stylegen', component: () => import('./views/StyleGenerator') },
|
{ path: 'stylegen', name: 'stylegen', component: () => import('./views/StyleGenerator') },
|
||||||
{ path: 'help', name: 'help', component: () => import('./views/Help') }
|
{ path: 'help', name: 'help', component: () => import('./views/Help') },
|
||||||
|
{ path: 'plugins', name: 'plugins', component: () => import('./views/Plugins') },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
183
frontend/src/views/Plugins.vue
Normal file
183
frontend/src/views/Plugins.vue
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<h1 style="display: inline;">{{ $t('plugins.plugins') }}</h1>
|
||||||
|
<el-button round icon="el-icon-question" class="push-inline-end" @click="isHelpVisible = true">{{
|
||||||
|
$t('plugins.help')
|
||||||
|
}}</el-button>
|
||||||
|
<el-dialog :title="$t('plugins.help')" :visible.sync="isHelpVisible">
|
||||||
|
<div style="word-break: initial;" v-html="$t('plugins.helpContent')"></div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-empty v-if="plugins.length === 0" description=""></el-empty>
|
||||||
|
<el-row v-else :gutter="16">
|
||||||
|
<el-col v-for="plugin in plugins" :key="plugin.id" :sm="24" :md="12">
|
||||||
|
<el-card class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="title-line">
|
||||||
|
<h3 class="name">{{ plugin.name }}</h3>
|
||||||
|
<span class="version">{{ plugin.version }}</span>
|
||||||
|
<span class="author push-inline-end">{{ $t('plugins.author') }}{{ plugin.author }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="description">{{ plugin.description }}</div>
|
||||||
|
|
||||||
|
<div class="operations">
|
||||||
|
<el-tooltip :content="$t('plugins.disabledByServer')" :disabled="serverConfig.enableAdminPlugins">
|
||||||
|
<el-button type="primary" :disabled="!serverConfig.enableAdminPlugins || !plugin.isConnected"
|
||||||
|
:loading="getPluginCtx(plugin.id).isOperating" @click="adminPlugin(plugin)"
|
||||||
|
>{{ $t('plugins.admin') }}</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tag v-if="plugin.isConnected" type="success" class="status push-inline-end">{{ $t('plugins.connected') }}</el-tag>
|
||||||
|
<el-tag v-else type="danger" class="status push-inline-end">{{ $t('plugins.unconnected') }}</el-tag>
|
||||||
|
<el-switch :value="plugin.enabled" :disabled="!serverConfig.enableAdminPlugins || getPluginCtx(plugin.id).isOperating"
|
||||||
|
@change="enabled => setPluginEnabled(plugin, enabled)"
|
||||||
|
></el-switch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as mainApi from '@/api/main'
|
||||||
|
import * as pluginsApi from '@/api/plugins'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Plugins',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
serverConfig: {
|
||||||
|
enableAdminPlugins: true
|
||||||
|
},
|
||||||
|
isHelpVisible: false,
|
||||||
|
plugins: [],
|
||||||
|
pluginCtxMap: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateServerConfig()
|
||||||
|
this.updatePlugins()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getPluginCtx(pluginId) {
|
||||||
|
let ctx = this.pluginCtxMap[pluginId]
|
||||||
|
if (ctx === undefined) {
|
||||||
|
ctx = {
|
||||||
|
isOperating: false,
|
||||||
|
}
|
||||||
|
this.$set(this.pluginCtxMap, pluginId, ctx)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
|
async updateServerConfig() {
|
||||||
|
try {
|
||||||
|
this.serverConfig = (await mainApi.getServerInfo()).config
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error(`Failed to fetch server information: ${e}`)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async updatePlugins() {
|
||||||
|
try {
|
||||||
|
this.plugins = (await pluginsApi.getPlugins()).plugins
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error(`Failed to fetch plugins: ${e}`)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async adminPlugin(plugin) {
|
||||||
|
let ctx = this.getPluginCtx(plugin.id)
|
||||||
|
ctx.isOperating = true
|
||||||
|
try {
|
||||||
|
await pluginsApi.openAdminUi(plugin.id)
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error(`Request failed: ${e}`)
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
ctx.isOperating = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async setPluginEnabled(plugin, enabled) {
|
||||||
|
let ctx = this.getPluginCtx(plugin.id)
|
||||||
|
ctx.isOperating = true
|
||||||
|
try {
|
||||||
|
let res
|
||||||
|
try {
|
||||||
|
res = await pluginsApi.setEnabled(plugin.id, enabled)
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error(`Request failed: ${e}`)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
plugin.enabled = res.enabled
|
||||||
|
if (!res.isSwitchSuccess) {
|
||||||
|
this.$message.error(`Failed to switch the plugin: ${res.msg}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => window.setTimeout(resolve, 3000))
|
||||||
|
this.updatePlugins()
|
||||||
|
} finally {
|
||||||
|
ctx.isOperating = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.push-inline-end {
|
||||||
|
margin-inline-start: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-block-end: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-line {
|
||||||
|
margin-block-end: 1em;
|
||||||
|
flex: none;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: baseline;
|
||||||
|
text-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin-block: 0 0;
|
||||||
|
margin-inline-end: 8px;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author {
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin-block-end: 1em;
|
||||||
|
flex: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operations {
|
||||||
|
flex: none;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
margin-inline-end: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,7 @@
|
|||||||
"name": "消息日志",
|
"name": "消息日志",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "xfgryujk",
|
"author": "xfgryujk",
|
||||||
"description": "把收到的消息记录到文件中",
|
"description": "把收到的消息记录到文件中。点击管理打开日志目录。日志不会自动清理,记得定期清理",
|
||||||
"run": "msg-logging.exe",
|
"run": "msg-logging.exe",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"name": "文字转语音",
|
"name": "文字转语音",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "xfgryujk",
|
"author": "xfgryujk",
|
||||||
"description": "用语音读出收到的消息",
|
"description": "用语音读出收到的消息。点击管理打开配置文件,编辑保存后重启插件生效",
|
||||||
"run": "text-to-speech.exe",
|
"run": "text-to-speech.exe",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ def init():
|
|||||||
if plugin.enabled:
|
if plugin.enabled:
|
||||||
try:
|
try:
|
||||||
plugin.start()
|
plugin.start()
|
||||||
except StartPluginError:
|
except SwitchPluginError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -130,21 +130,21 @@ class PluginConfig:
|
|||||||
cfg['version'] = self.version
|
cfg['version'] = self.version
|
||||||
cfg['author'] = self.author
|
cfg['author'] = self.author
|
||||||
cfg['description'] = self.description
|
cfg['description'] = self.description
|
||||||
cfg['run_cmd'] = self.run_cmd
|
cfg['run'] = self.run_cmd
|
||||||
cfg['enabled'] = self.enabled
|
cfg['enabled'] = self.enabled
|
||||||
|
|
||||||
tmp_path = path + '.tmp'
|
tmp_path = path + '.tmp'
|
||||||
with open(tmp_path, encoding='utf-8') as f:
|
with open(tmp_path, 'w', encoding='utf-8') as f:
|
||||||
json.dump(cfg, f, ensure_ascii=False, indent=2)
|
json.dump(cfg, f, ensure_ascii=False, indent=2)
|
||||||
os.replace(tmp_path, path)
|
os.replace(tmp_path, path)
|
||||||
|
|
||||||
|
|
||||||
class StartPluginError(Exception):
|
class SwitchPluginError(Exception):
|
||||||
"""启动插件时错误"""
|
"""开关插件时错误"""
|
||||||
|
|
||||||
|
|
||||||
class StartTooFrequently(StartPluginError):
|
class SwitchTooFrequently(SwitchPluginError):
|
||||||
"""启动插件太频繁"""
|
"""开关插件太频繁"""
|
||||||
|
|
||||||
|
|
||||||
class Plugin:
|
class Plugin:
|
||||||
@ -152,7 +152,7 @@ class Plugin:
|
|||||||
self._id = plugin_id
|
self._id = plugin_id
|
||||||
self._config = cfg
|
self._config = cfg
|
||||||
|
|
||||||
self._last_start_time = datetime.datetime.fromtimestamp(0)
|
self._last_switch_time = datetime.datetime.fromtimestamp(0)
|
||||||
self._token = ''
|
self._token = ''
|
||||||
self._client: Optional['api.plugin.PluginWsHandler'] = None
|
self._client: Optional['api.plugin.PluginWsHandler'] = None
|
||||||
|
|
||||||
@ -204,11 +204,7 @@ class Plugin:
|
|||||||
def start(self):
|
def start(self):
|
||||||
if self.is_started:
|
if self.is_started:
|
||||||
return
|
return
|
||||||
|
self._refresh_last_switch_time()
|
||||||
cur_time = datetime.datetime.now()
|
|
||||||
if cur_time - self._last_start_time < datetime.timedelta(seconds=3):
|
|
||||||
raise StartTooFrequently(f'plugin={self._id} starts too frequently')
|
|
||||||
self._last_start_time = cur_time
|
|
||||||
|
|
||||||
token = ''.join(random.choice(string.hexdigits) for _ in range(32))
|
token = ''.join(random.choice(string.hexdigits) for _ in range(32))
|
||||||
self._set_token(token)
|
self._set_token(token)
|
||||||
@ -228,10 +224,19 @@ class Plugin:
|
|||||||
)
|
)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.exception('plugin=%s failed to start', self._id)
|
logger.exception('plugin=%s failed to start', self._id)
|
||||||
raise StartPluginError(str(e))
|
raise SwitchPluginError(str(e))
|
||||||
|
|
||||||
|
def _refresh_last_switch_time(self):
|
||||||
|
cur_time = datetime.datetime.now()
|
||||||
|
if cur_time - self._last_switch_time < datetime.timedelta(seconds=3):
|
||||||
|
raise SwitchTooFrequently(f'plugin={self._id} switches too frequently')
|
||||||
|
self._last_switch_time = cur_time
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.is_started:
|
if not self.is_started:
|
||||||
|
return
|
||||||
|
self._refresh_last_switch_time()
|
||||||
|
|
||||||
self._set_token('')
|
self._set_token('')
|
||||||
|
|
||||||
def _set_token(self, token):
|
def _set_token(self, token):
|
||||||
|
Loading…
Reference in New Issue
Block a user