mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-04 22:32:45 +08:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
709c2c6ac7 |
20
main.go
20
main.go
@@ -15,6 +15,7 @@ import (
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -46,6 +47,7 @@ func main() {
|
||||
}
|
||||
addr := flag.String("port", "8000", "http server port")
|
||||
flag.Parse()
|
||||
http.HandleFunc("/instance/listDir", listDir)
|
||||
http.HandleFunc("/instance/import", importInstance)
|
||||
http.HandleFunc("/instance/updateConfig", updateConfig)
|
||||
http.HandleFunc("/instance/list", listInstance)
|
||||
@@ -59,6 +61,24 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func listDir(w http.ResponseWriter, r *http.Request) {
|
||||
if input := r.URL.Query().Get("input"); input != "" {
|
||||
if dir, err := os.Open(filepath.Dir(input)); err == nil {
|
||||
var dirs []string
|
||||
if infos, err := dir.Readdir(0); err == nil {
|
||||
for _, info := range infos {
|
||||
if info.IsDir() {
|
||||
dirs = append(dirs, info.Name())
|
||||
}
|
||||
}
|
||||
if bytes, err := json.Marshal(dirs); err == nil {
|
||||
w.Write(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func importInstance(w http.ResponseWriter, r *http.Request) {
|
||||
var e error
|
||||
defer func() {
|
||||
|
@@ -41,10 +41,10 @@ func run() {
|
||||
config.splitFunc = config.splitByTime
|
||||
}
|
||||
config.createTime = time.Now()
|
||||
file, err := os.OpenFile(path.Join(config.Path, fmt.Sprintf("%s.log", config.createTime.Format("2006-01-02T15:04:05"))), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
|
||||
err := os.MkdirAll(config.Path, 0666)
|
||||
config.file, err = os.OpenFile(path.Join(config.Path, fmt.Sprintf("%s.log", config.createTime.Format("2006-01-02T15:04:05"))), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err == nil {
|
||||
config.file = file
|
||||
stat, _ := file.Stat()
|
||||
stat, _ := config.file.Stat()
|
||||
config.currentSize = stat.Size()
|
||||
AddWriter(config)
|
||||
} else {
|
||||
@@ -71,3 +71,8 @@ func (l *LogRotate) Write(data []byte) (n int, err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//func (l *LogRotate) FindLog(grep string) string{
|
||||
// cmd:=exec.Command("grep",fmt.Sprintf("\"%s\"",grep),l.Path)
|
||||
// err:=cmd.Run()
|
||||
//}
|
||||
|
2
pm/dist/index.html
vendored
2
pm/dist/index.html
vendored
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Monibuca Instance Manager</title><script src=ajax.js></script><link href=/css/app.200d2f8f.css rel=preload as=style><link href=/css/chunk-vendors.22ebf426.css rel=preload as=style><link href=/js/app.f5cfbf83.js rel=preload as=script><link href=/js/chunk-vendors.470a264b.js rel=preload as=script><link href=/css/chunk-vendors.22ebf426.css rel=stylesheet><link href=/css/app.200d2f8f.css rel=stylesheet></head><body><noscript><strong>We're sorry but pm doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.470a264b.js></script><script src=/js/app.f5cfbf83.js></script></body></html>
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Monibuca Instance Manager</title><script src=ajax.js></script><link href=/css/app.200d2f8f.css rel=preload as=style><link href=/css/chunk-vendors.22ebf426.css rel=preload as=style><link href=/js/app.13e2de5f.js rel=preload as=script><link href=/js/chunk-vendors.2e3b192a.js rel=preload as=script><link href=/css/chunk-vendors.22ebf426.css rel=stylesheet><link href=/css/app.200d2f8f.css rel=stylesheet></head><body><noscript><strong>We're sorry but pm doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.2e3b192a.js></script><script src=/js/app.13e2de5f.js></script></body></html>
|
2
pm/dist/js/app.13e2de5f.js
vendored
Normal file
2
pm/dist/js/app.13e2de5f.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
pm/dist/js/app.13e2de5f.js.map
vendored
Normal file
1
pm/dist/js/app.13e2de5f.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
pm/dist/js/app.f5cfbf83.js
vendored
2
pm/dist/js/app.f5cfbf83.js
vendored
File diff suppressed because one or more lines are too long
1
pm/dist/js/app.f5cfbf83.js.map
vendored
1
pm/dist/js/app.f5cfbf83.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
pm/dist/js/chunk-vendors.2e3b192a.js.map
vendored
Normal file
1
pm/dist/js/chunk-vendors.2e3b192a.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
pm/dist/js/chunk-vendors.470a264b.js.map
vendored
1
pm/dist/js/chunk-vendors.470a264b.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -38,7 +38,7 @@
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"rules": {},
|
||||
"rules": {"no-console": "off"},
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
@@ -1,16 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<i-input v-model="instanceName" :placeholder="defaultInstanceName">
|
||||
<PathSelector v-model="instancePath" placeholder="输入实例所在的路径"></PathSelector>
|
||||
<i-input style="width: 300px;margin:40px auto" v-model="instanceName" :placeholder="defaultInstanceName" search enter-button="Import" @on-search="doImport">
|
||||
<span slot="prepend">实例名称</span>
|
||||
</i-input>
|
||||
<i-input prefix="ios-home" v-model="instancePath" placeholder="输入实例所在的路径" search enter-button="Import" @on-search="doImport">
|
||||
</i-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PathSelector from "./PathSelector"
|
||||
export default {
|
||||
name: "ImportInstance",
|
||||
components:{
|
||||
PathSelector
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
instancePath:"",
|
||||
@@ -19,7 +22,10 @@
|
||||
},
|
||||
computed:{
|
||||
defaultInstanceName(){
|
||||
return this.instancePath.replace(/\\/g,"/").split("/").pop()
|
||||
let path = this.instancePath.replace(/\\/g,"/")
|
||||
let s = path.split("/")
|
||||
if(path.endsWith("/")) s.pop()
|
||||
return s.pop()
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
|
66
pm/src/components/PathSelector.vue
Normal file
66
pm/src/components/PathSelector.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div>
|
||||
<i-input ref="input" v-bind="$attrs" v-on="$listeners" clearable @on-change="onInput">
|
||||
<Button slot="prepend" icon="md-arrow-round-up" @click="goUp"></Button>
|
||||
</i-input>
|
||||
<CellGroup @on-click="onSelectCand">
|
||||
<Cell v-for="item in candidate" :key="item" :title="item" :name="item"></Cell>
|
||||
</CellGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "PathSelector",
|
||||
data() {
|
||||
return {
|
||||
candidate: [],
|
||||
lastInput: "",
|
||||
searching: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dir(){
|
||||
let paths = this.$refs.input.value.split("/");
|
||||
paths.pop();
|
||||
return paths.join("/");
|
||||
},
|
||||
goUp() {
|
||||
this.lastInput = this.$attrs.value = this.dir()
|
||||
this.$refs.input.$emit('input', this.$attrs.value)
|
||||
this.search(this.lastInput)
|
||||
},
|
||||
onSelectCand(name) {
|
||||
this.lastInput = this.$attrs.value = this.dir()+"/"+name+"/"
|
||||
this.$refs.input.$emit('input', this.$attrs.value)
|
||||
this.search(this.lastInput)
|
||||
},
|
||||
onInput(evt) {
|
||||
this.lastInput = evt.target.value
|
||||
this.search(this.lastInput)
|
||||
},
|
||||
search(v) {
|
||||
if(this.searching)return
|
||||
window.ajax.getJSON("/instance/listDir?input=" + v).then(x => {
|
||||
this.candidate = x
|
||||
if (this.lastInput != v) {
|
||||
this.search(this.lastInput)
|
||||
}else{
|
||||
this.searching = false
|
||||
}
|
||||
}).catch(e => {
|
||||
this.$Message.error(e)
|
||||
if (this.lastInput != v) {
|
||||
this.search(this.lastInput)
|
||||
}else{
|
||||
this.searching = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -13,21 +13,18 @@
|
||||
<Step title="完成" content="完成实例创建"></Step>
|
||||
</Steps>
|
||||
<div style="margin:50px;width:auto">
|
||||
<i-input v-model="createPath" v-if="createStep==0">
|
||||
<Button slot="prepend" icon="md-arrow-round-up" @click="goUp"></Button>
|
||||
</i-input>
|
||||
<List v-else-if="createStep==1" border>
|
||||
<ListItem v-for="(item,name) in plugins" :key="name">
|
||||
<ListItemMeta :title="name" :description="item.Path"></ListItemMeta>
|
||||
{{item.Config}}
|
||||
<template slot="action">
|
||||
<li @click="removePlugin(name)">
|
||||
<Icon type="ios-trash"/>
|
||||
移除
|
||||
</li>
|
||||
</template>
|
||||
</ListItem>
|
||||
</List>
|
||||
<PathSelector v-model="createPath" v-if="createStep==0"></PathSelector>
|
||||
<div style="display: flex;flex-wrap: wrap" v-else-if="createStep==1">
|
||||
<Card v-for="(item,name) in plugins" :key="name" style="width:200px;margin:5px">
|
||||
<Poptip :content="item.Description" slot="extra" width="200" word-wrap>
|
||||
<Icon size="18" type="ios-help-circle-outline" style="cursor:pointer"/>
|
||||
</Poptip>
|
||||
<Poptip :content="item.Path" trigger="hover" word-wrap slot="title">
|
||||
<Checkbox v-model="item.enabled" style="color: #eb5e46">{{name}}</Checkbox>
|
||||
</Poptip>
|
||||
<i-input type="textarea" v-model="item.Config" placeholder="请输入toml格式"></i-input>
|
||||
</Card>
|
||||
</div>
|
||||
<div v-else>
|
||||
<h3>实例名称:</h3>
|
||||
<i-input
|
||||
@@ -90,14 +87,9 @@
|
||||
<i-input v-model="formPlugin.Name" placeholder="插件名称必须和插件注册时的名称一致"></i-input>
|
||||
</FormItem>
|
||||
<FormItem label="插件包地址">
|
||||
<i-input v-model="formPlugin.Path">
|
||||
<Button slot="append" @click="showBuiltinPlugin=true">内置插件</Button>
|
||||
</i-input>
|
||||
<i-input v-model="formPlugin.Path"></i-input>
|
||||
</FormItem>
|
||||
<Alert show-icon
|
||||
type="warning"
|
||||
v-if="!isBuiltInPlugin(formPlugin.Path)"
|
||||
>
|
||||
<Alert show-icon type="warning">
|
||||
如果该插件是私有仓库,请到服务器上输入:echo "machine {{privateHost}} login 用户名 password 密码" >> ~/.netrc
|
||||
并且添加环境变量GOPRIVATE={{privateHost}}
|
||||
</Alert>
|
||||
@@ -106,19 +98,6 @@
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Modal v-model="showBuiltinPlugin">
|
||||
<List>
|
||||
<ListItem v-for="(item,name) in $store.state.defaultPlugins" :key="name">
|
||||
<ListItemMeta :title="name" :description="item[2]"></ListItemMeta>
|
||||
<template slot="action">
|
||||
<li @click="addBuiltin(name,item)">
|
||||
<Icon type="ios-add"/>
|
||||
添加
|
||||
</li>
|
||||
</template>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Modal>
|
||||
<CreateInstance v-model="showCreate" :info="createInfo"></CreateInstance>
|
||||
</Layout>
|
||||
</template>
|
||||
@@ -127,32 +106,42 @@
|
||||
import CreateInstance from "../components/CreateInstance";
|
||||
import InstanceList from "../components/InstanceList";
|
||||
import ImportInstance from "../components/ImportInstance";
|
||||
import PathSelector from "../components/PathSelector"
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CreateInstance,InstanceList,ImportInstance
|
||||
CreateInstance, InstanceList, ImportInstance, PathSelector
|
||||
},
|
||||
data() {
|
||||
let plugins = {}
|
||||
for (let name in this.$store.state.defaultPlugins) {
|
||||
plugins[name] = {
|
||||
Name: name,
|
||||
enabled: ["GateWay", "LogRotate", "Jessica"].includes(name),
|
||||
Path: "github.com/langhuihui/monibuca/plugins/" + this.$store.state.defaultPlugins[name][0],
|
||||
Config: this.$store.state.defaultPlugins[name][1],
|
||||
Description: this.$store.state.defaultPlugins[name][2],
|
||||
}
|
||||
}
|
||||
return {
|
||||
instanceName: "",
|
||||
createStep: 0,
|
||||
showCreate: false,
|
||||
createInfo: null,
|
||||
createPath: "/opt/monibuca",
|
||||
plugins: {},
|
||||
plugins,
|
||||
showAddPlugin: false,
|
||||
formPlugin: {},
|
||||
showBuiltinPlugin: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pluginStr() {
|
||||
return Object.values(this.plugins)
|
||||
return Object.values(this.plugins).filter(x => x.enabled)
|
||||
.map(x => x.Path)
|
||||
.join("\n");
|
||||
},
|
||||
configStr() {
|
||||
return Object.values(this.plugins)
|
||||
return Object.values(this.plugins).filter(x => x.enabled)
|
||||
.map(
|
||||
x => `[Plugins.${x.Name}]
|
||||
${x.Config || ""}`
|
||||
@@ -168,9 +157,6 @@ ${x.Config || ""}`
|
||||
},
|
||||
|
||||
methods: {
|
||||
isBuiltInPlugin(path){
|
||||
return Object.values(this.$store.state.defaultPlugins).some(x=>"github.com/langhuihui/monibuca/plugins/"+x[0]==path)
|
||||
},
|
||||
goUp() {
|
||||
let paths = this.createPath.split("/");
|
||||
paths.pop();
|
||||
@@ -181,7 +167,7 @@ ${x.Config || ""}`
|
||||
this.createInfo = {
|
||||
Name: this.instanceName || this.createPath.split("/").pop(),
|
||||
Path: this.createPath,
|
||||
Plugins: Object.values(this.plugins).map(x => x.Path),
|
||||
Plugins: Object.values(this.plugins).filter(x => x.enabled).map(x => x.Path),
|
||||
Config: this.configStr
|
||||
};
|
||||
},
|
||||
@@ -189,16 +175,6 @@ ${x.Config || ""}`
|
||||
this.plugins[this.formPlugin.Name] = this.formPlugin;
|
||||
this.formPlugin = {};
|
||||
},
|
||||
removePlugin(name) {
|
||||
delete this.plugins[name];
|
||||
this.$forceUpdate();
|
||||
},
|
||||
addBuiltin(name, item) {
|
||||
this.formPlugin.Name = name;
|
||||
this.formPlugin.Path = "github.com/langhuihui/monibuca/plugins/"+item[0];
|
||||
this.formPlugin.Config = item[1];
|
||||
this.showBuiltinPlugin = false;
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user