Compare commits

...

1 Commits

Author SHA1 Message Date
langhuihui
709c2c6ac7 增加目录候选功能 2020-02-17 11:48:58 +08:00
14 changed files with 145 additions and 72 deletions

20
main.go
View File

@@ -15,6 +15,7 @@ import (
"os/exec" "os/exec"
"os/user" "os/user"
"path" "path"
"path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"strings" "strings"
@@ -46,6 +47,7 @@ func main() {
} }
addr := flag.String("port", "8000", "http server port") addr := flag.String("port", "8000", "http server port")
flag.Parse() flag.Parse()
http.HandleFunc("/instance/listDir", listDir)
http.HandleFunc("/instance/import", importInstance) http.HandleFunc("/instance/import", importInstance)
http.HandleFunc("/instance/updateConfig", updateConfig) http.HandleFunc("/instance/updateConfig", updateConfig)
http.HandleFunc("/instance/list", listInstance) 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) { func importInstance(w http.ResponseWriter, r *http.Request) {
var e error var e error
defer func() { defer func() {

View File

@@ -41,10 +41,10 @@ func run() {
config.splitFunc = config.splitByTime config.splitFunc = config.splitByTime
} }
config.createTime = time.Now() 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 { if err == nil {
config.file = file stat, _ := config.file.Stat()
stat, _ := file.Stat()
config.currentSize = stat.Size() config.currentSize = stat.Size()
AddWriter(config) AddWriter(config)
} else { } else {
@@ -71,3 +71,8 @@ func (l *LogRotate) Write(data []byte) (n int, err error) {
} }
return 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
View File

@@ -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

File diff suppressed because one or more lines are too long

1
pm/dist/js/app.13e2de5f.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -38,7 +38,7 @@
"plugin:vue/essential", "plugin:vue/essential",
"eslint:recommended" "eslint:recommended"
], ],
"rules": {}, "rules": {"no-console": "off"},
"parserOptions": { "parserOptions": {
"parser": "babel-eslint" "parser": "babel-eslint"
} }

View File

@@ -1,16 +1,19 @@
<template> <template>
<div> <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> <span slot="prepend">实例名称</span>
</i-input> </i-input>
<i-input prefix="ios-home" v-model="instancePath" placeholder="输入实例所在的路径" search enter-button="Import" @on-search="doImport">
</i-input>
</div> </div>
</template> </template>
<script> <script>
import PathSelector from "./PathSelector"
export default { export default {
name: "ImportInstance", name: "ImportInstance",
components:{
PathSelector
},
data(){ data(){
return { return {
instancePath:"", instancePath:"",
@@ -19,7 +22,10 @@
}, },
computed:{ computed:{
defaultInstanceName(){ 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:{ methods:{

View 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>

View File

@@ -13,21 +13,18 @@
<Step title="完成" content="完成实例创建"></Step> <Step title="完成" content="完成实例创建"></Step>
</Steps> </Steps>
<div style="margin:50px;width:auto"> <div style="margin:50px;width:auto">
<i-input v-model="createPath" v-if="createStep==0"> <PathSelector v-model="createPath" v-if="createStep==0"></PathSelector>
<Button slot="prepend" icon="md-arrow-round-up" @click="goUp"></Button> <div style="display: flex;flex-wrap: wrap" v-else-if="createStep==1">
</i-input> <Card v-for="(item,name) in plugins" :key="name" style="width:200px;margin:5px">
<List v-else-if="createStep==1" border> <Poptip :content="item.Description" slot="extra" width="200" word-wrap>
<ListItem v-for="(item,name) in plugins" :key="name"> <Icon size="18" type="ios-help-circle-outline" style="cursor:pointer"/>
<ListItemMeta :title="name" :description="item.Path"></ListItemMeta> </Poptip>
{{item.Config}} <Poptip :content="item.Path" trigger="hover" word-wrap slot="title">
<template slot="action"> <Checkbox v-model="item.enabled" style="color: #eb5e46">{{name}}</Checkbox>
<li @click="removePlugin(name)"> </Poptip>
<Icon type="ios-trash"/> <i-input type="textarea" v-model="item.Config" placeholder="请输入toml格式"></i-input>
移除 </Card>
</li> </div>
</template>
</ListItem>
</List>
<div v-else> <div v-else>
<h3>实例名称</h3> <h3>实例名称</h3>
<i-input <i-input
@@ -90,14 +87,9 @@
<i-input v-model="formPlugin.Name" placeholder="插件名称必须和插件注册时的名称一致"></i-input> <i-input v-model="formPlugin.Name" placeholder="插件名称必须和插件注册时的名称一致"></i-input>
</FormItem> </FormItem>
<FormItem label="插件包地址"> <FormItem label="插件包地址">
<i-input v-model="formPlugin.Path"> <i-input v-model="formPlugin.Path"></i-input>
<Button slot="append" @click="showBuiltinPlugin=true">内置插件</Button>
</i-input>
</FormItem> </FormItem>
<Alert show-icon <Alert show-icon type="warning">
type="warning"
v-if="!isBuiltInPlugin(formPlugin.Path)"
>
如果该插件是私有仓库请到服务器上输入echo "machine {{privateHost}} login 用户名 password 密码" >> ~/.netrc 如果该插件是私有仓库请到服务器上输入echo "machine {{privateHost}} login 用户名 password 密码" >> ~/.netrc
并且添加环境变量GOPRIVATE={{privateHost}} 并且添加环境变量GOPRIVATE={{privateHost}}
</Alert> </Alert>
@@ -106,19 +98,6 @@
</FormItem> </FormItem>
</Form> </Form>
</Modal> </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> <CreateInstance v-model="showCreate" :info="createInfo"></CreateInstance>
</Layout> </Layout>
</template> </template>
@@ -127,32 +106,42 @@
import CreateInstance from "../components/CreateInstance"; import CreateInstance from "../components/CreateInstance";
import InstanceList from "../components/InstanceList"; import InstanceList from "../components/InstanceList";
import ImportInstance from "../components/ImportInstance"; import ImportInstance from "../components/ImportInstance";
import PathSelector from "../components/PathSelector"
export default { export default {
components: { components: {
CreateInstance,InstanceList,ImportInstance CreateInstance, InstanceList, ImportInstance, PathSelector
}, },
data() { 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 { return {
instanceName: "", instanceName: "",
createStep: 0, createStep: 0,
showCreate: false, showCreate: false,
createInfo: null, createInfo: null,
createPath: "/opt/monibuca", createPath: "/opt/monibuca",
plugins: {}, plugins,
showAddPlugin: false, showAddPlugin: false,
formPlugin: {}, formPlugin: {},
showBuiltinPlugin: false,
}; };
}, },
computed: { computed: {
pluginStr() { pluginStr() {
return Object.values(this.plugins) return Object.values(this.plugins).filter(x => x.enabled)
.map(x => x.Path) .map(x => x.Path)
.join("\n"); .join("\n");
}, },
configStr() { configStr() {
return Object.values(this.plugins) return Object.values(this.plugins).filter(x => x.enabled)
.map( .map(
x => `[Plugins.${x.Name}] x => `[Plugins.${x.Name}]
${x.Config || ""}` ${x.Config || ""}`
@@ -168,9 +157,6 @@ ${x.Config || ""}`
}, },
methods: { methods: {
isBuiltInPlugin(path){
return Object.values(this.$store.state.defaultPlugins).some(x=>"github.com/langhuihui/monibuca/plugins/"+x[0]==path)
},
goUp() { goUp() {
let paths = this.createPath.split("/"); let paths = this.createPath.split("/");
paths.pop(); paths.pop();
@@ -181,7 +167,7 @@ ${x.Config || ""}`
this.createInfo = { this.createInfo = {
Name: this.instanceName || this.createPath.split("/").pop(), Name: this.instanceName || this.createPath.split("/").pop(),
Path: this.createPath, 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 Config: this.configStr
}; };
}, },
@@ -189,16 +175,6 @@ ${x.Config || ""}`
this.plugins[this.formPlugin.Name] = this.formPlugin; this.plugins[this.formPlugin.Name] = this.formPlugin;
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> </script>