Skip to content

Commit

Permalink
feat(webui): package installation
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 15, 2021
1 parent 983c374 commit 2327490
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 6 deletions.
20 changes: 16 additions & 4 deletions packages/plugin-webui/client/views/awesome/package.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
target="blank" rel="noopener noreferrer"
>{{ data.name.replace('koishi-plugin-', '') }}</a>
<k-badge type="success" v-if="data.official">官方</k-badge>
<k-badge type="warning" v-if="hasUpdate">可更新</k-badge>
<k-badge type="default" v-if="data.local?.isWorkspace">本地</k-badge>
<k-badge type="warning" v-else-if="hasUpdate">可更新</k-badge>
</div>
<div class="description">
{{ data.description }}
Expand All @@ -18,16 +19,19 @@
<td class="size">{{ formatSize(data.size) }}</td>
<td class="score">{{ +data.score.final.toFixed(2) }}</td>
<td class="operation">
<k-button frameless v-if="hasUpdate || !data.local"
>{{ data.local ? '更新' : '下载' }}</k-button>
<span v-if="downloading.includes(data.name)">安装中</span>
<k-button frameless v-else-if="!data.local || hasUpdate"
@click="toggle(data)"
>{{ data.local ? '更新' : '安装' }}</k-button>
</td>
</tr>
</template>

<script lang="ts" setup>
import type { Awesome } from '~/server'
import { defineProps, computed } from 'vue'
import { send, user } from '~/client'
import { defineProps, computed, ref } from 'vue'
const props = defineProps<{ data: Awesome.PackageData }>()
Expand All @@ -44,6 +48,14 @@ function formatSize(size: number) {
}
}
const downloading = ref([])
function toggle(data: Awesome.PackageData) {
const { id, token } = user.value
send('install', { name: `${data.name}@${data.version}`, id, token })
downloading.value.push(data.name)
}
</script>

<style lang="scss">
Expand Down
38 changes: 36 additions & 2 deletions packages/plugin-webui/src/payload/awesome.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Context, pick, version as coreVersion } from 'koishi-core'
import { dirname } from 'path'
import { promises as fs } from 'fs'
import { dirname, resolve } from 'path'
import { existsSync, promises as fs } from 'fs'
import { spawn, StdioOptions } from 'child_process'
import { satisfies } from 'semver'
import axios from 'axios'

Expand Down Expand Up @@ -41,6 +42,32 @@ const officialPlugins = [
'puppeteer', 'schedule', 'teach', 'tools', 'webui',
]

type Manager = 'yarn' | 'npm'

const cwd = process.cwd()

function execute(bin: string, args: string[] = [], stdio: StdioOptions = 'inherit') {
// fix for #205
// https://stackoverflow.com/questions/43230346/error-spawn-npm-enoent
const child = spawn(bin + (process.platform === 'win32' ? '.cmd' : ''), args, { stdio })
return new Promise<number>((resolve) => {
child.on('close', resolve)
})
}

let _managerPromise: Promise<Manager>
async function getManager(): Promise<Manager> {
if (existsSync(resolve(cwd, 'yarn.lock'))) return 'yarn'
if (existsSync(resolve(cwd, 'package-lock.json'))) return 'npm'
if (!await execute('yarn', ['--version'], 'ignore')) return 'yarn'
return 'npm'
}

const installArgs: Record<Manager, string[]> = {
yarn: ['add'],
npm: ['install', '--loglevel', 'error'],
}

class Awesome {
cached: Promise<Awesome.PackageData[]>

Expand Down Expand Up @@ -114,6 +141,13 @@ class Awesome {
} as Awesome.PackageData
})).then(data => data.filter(Boolean))
}

async install(name: string) {
const kind = await (_managerPromise ||= getManager())
const args = [...installArgs[kind], name]
await execute(kind, args)
this.ctx.webui.broadcast('awesome', await this.get(true))
}
}

namespace Awesome {
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-webui/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,13 @@ export namespace WebServer {
this.authority = user.authority
}

listeners.install = async function ({ id, token, name }) {
const user = await this.validate(id, token, ['name', 'authority'])
if (!user) return
if (user.authority < 4) return this.send('unauthorized')
this.webui.sources.awesome.install(name)
}

listeners.switch = async function ({ id, token, plugin }) {
const user = await this.validate(id, token, ['name', 'authority'])
if (!user) return
Expand Down

0 comments on commit 2327490

Please sign in to comment.