fix: #44, #45
continuous-integration/drone/tag Build is passing Details

feat/muzan v0.1.5
Evan Chen 2021-11-03 16:21:49 +08:00
parent 38afcf64cf
commit 3a64217a10
7 changed files with 104 additions and 11 deletions

View File

@ -2,10 +2,12 @@ package configui
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
) )
func (cui *ConfigUI) ListFiles(w http.ResponseWriter, r *http.Request) { func (cui *ConfigUI) ListFiles(w http.ResponseWriter, r *http.Request) {
@ -27,11 +29,63 @@ func (cui *ConfigUI) GetFile(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
stat, err := os.Stat(file.Path)
if err != nil {
panic(err)
}
response, err := json.Marshal(map[string]string{ response, err := json.Marshal(map[string]string{
"path": file.Path, "path": file.Path,
"name": file.Name, "name": file.Name,
"action": file.Action, "action": file.Action,
"data": string(data), "data": string(data),
"delta": strconv.Itoa(int(stat.Size())),
})
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json")
w.Write(response)
}
func (cui *ConfigUI) GetDelta(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
delta, err := strconv.ParseInt(r.URL.Query().Get("delta"), 10, 64)
if err != nil {
panic(err)
}
file, err := cui.File(name)
if err != nil {
response(w, 404, []byte("file not found"))
return
}
f, err := os.Open(file.Path)
if err != nil {
panic(err)
}
defer f.Close()
stat, err := os.Stat(file.Path)
if err != nil {
panic(err)
}
if delta > stat.Size() {
panic(fmt.Errorf("delta(%d) is larger than file size(%d)", delta, stat.Size()))
}
if stat.Size() < delta {
panic(fmt.Errorf("delta(%d) is smaller than file size(%d)", delta, stat.Size()))
}
buf := make([]byte, stat.Size()-delta)
_, err = f.ReadAt(buf, delta)
if err != nil {
panic(err)
}
response, err := json.Marshal(map[string]string{
"path": file.Path,
"name": file.Name,
"action": file.Action,
"data": string(buf),
"delta": strconv.Itoa(int(stat.Size())),
}) })
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -33,6 +33,7 @@ func response(w http.ResponseWriter, status int, body []byte) (int, error) {
} }
func abort(w http.ResponseWriter, err interface{}) (int, error) { func abort(w http.ResponseWriter, err interface{}) (int, error) {
log.Println(err)
switch v := err.(type) { switch v := err.(type) {
case int: case int:
w.WriteHeader(v) w.WriteHeader(v)

File diff suppressed because one or more lines are too long

View File

@ -59,6 +59,13 @@ func (cui *ConfigUI) mux() *http.ServeMux {
w.WriteHeader(404) w.WriteHeader(404)
} }
}) })
cuiR.HandleFunc("/api/delta", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
cui.GetDelta(w, r)
} else {
w.WriteHeader(404)
}
})
cuiR.HandleFunc("/api/apply", func(w http.ResponseWriter, r *http.Request) { cuiR.HandleFunc("/api/apply", func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" { if r.Method == "POST" {
cui.Apply(w, r) cui.Apply(w, r)

View File

@ -2,12 +2,13 @@
<footer class="footer"> <footer class="footer">
<div class="content has-text-right"> <div class="content has-text-right">
<p> <p>
<strong>Configui</strong> {{.Version}} by <a href="https://kumoly.io/evanchen">Evan Chen</a>. <strong>Configui</strong> {{.Version}} by <a href="mailto:evanchen@kumoly.io">Evan Chen</a>.
</p> </p>
</div> </div>
</footer> </footer>
<script src="{{.BaseUrl}}public/ace/js/ace.js" type="text/javascript" charset="utf-8"></script> <script src="{{.BaseUrl}}public/ace/js/ace.js" type="text/javascript" charset="utf-8"></script>
<script src="{{.BaseUrl}}public/ace/js/ext-beautify.js" type="text/javascript" charset="utf-8"></script> <script src="{{.BaseUrl}}public/ace/js/ext-beautify.js" type="text/javascript" charset="utf-8"></script>
<script src="{{.BaseUrl}}public/ace/js/ext-searchbox.js" type="text/javascript" charset="utf-8"></script>
{{template "base/script" .}} {{template "base/script" .}}
<!-- <script src="/public/js/main.js"></script> --> <!-- <script src="/public/js/main.js"></script> -->
</body> </body>

View File

@ -1,30 +1,30 @@
{{define "base/script"}} {{define "base/script"}}
<script> <script>
window.ToolIsFollow = false; window.ToolIsFollow = false;
window.LastDelta = 0;
window.ContentChanged = false; window.ContentChanged = false;
async function FileGet(follower=false){ async function FileGet(){
let f = '' if (Active == '{{.AppName}}') {
if (Active == 'ConfigUI') { const res = await fetch('{{.BaseUrl}}api/conf')
if (follower) f = '?f=true'
const res = await fetch('{{.BaseUrl}}api/conf'+f)
.catch(err=>{console.log(err);return;}); .catch(err=>{console.log(err);return;});
const body = await res.text(); const body = await res.text();
if(!res.ok){ if(!res.ok){
Catch(res) Catch(res)
return return
} }
LastDelta = 0;
editor.session.setValue(body); editor.session.setValue(body);
} }
else { else {
if (follower) f = '&f=true' const res = await fetch('{{.BaseUrl}}api/file?name=' + Active)
const res = await fetch('{{.BaseUrl}}api/file?name=' + Active + f)
.catch(err=>{console.log(err);return;}); .catch(err=>{console.log(err);return;});
const body = await res.json(); const body = await res.json();
if(!res.ok){ if(!res.ok){
Catch(res) Catch(res)
return return
} }
LastDelta = body.delta;
editor.session.setValue(body.data); editor.session.setValue(body.data);
} }
} }
@ -75,6 +75,24 @@ async function FileApply(){
} }
} }
async function FileDelta(){
if (Active == '{{.AppName}}') {
await FileGet()
return
}
else {
const res = await fetch('{{.BaseUrl}}api/delta?f=true&name=' + Active+'&delta='+LastDelta)
.catch(err=>{console.log(err);return;});
const body = await res.json();
if(!res.ok){
Catch(res)
return
}
LastDelta = body.delta;
editor.session.setValue(editor.getValue()+body.data);
}
}
async function Catch(res){ async function Catch(res){
{{/* console.trace() {{/* console.trace()
console.log(res) */}} console.log(res) */}}
@ -107,7 +125,7 @@ function setResult(){
// for follow mode // for follow mode
setInterval((async ()=>{ setInterval((async ()=>{
if (ToolIsFollow){ if (ToolIsFollow){
await FileGet(true) await FileDelta()
editor.gotoLine(editor.session.getLength()); editor.gotoLine(editor.session.getLength());
} }
}), 1000) }), 1000)

View File

@ -164,20 +164,24 @@ function toolSetFontSize(obj){
function toolFollow(){ function toolFollow(){
if (ToolIsFollow){ if (ToolIsFollow){
ToolIsFollow = false ToolIsFollow = false;
editor.setReadOnly({{.File.RO}});
let el = document.getElementById('toolFollow'); let el = document.getElementById('toolFollow');
let icon = document.getElementById('toolFollowIcon'); let icon = document.getElementById('toolFollowIcon');
el.classList.remove('is-primary'); el.classList.remove('is-primary');
icon.classList.remove('icn-spinner'); icon.classList.remove('icn-spinner');
icon.innerText='sync_disabled'; icon.innerText='sync_disabled';
} else { } else {
ToolIsFollow = true editor.setReadOnly(true);
let el = document.getElementById('toolFollow'); let el = document.getElementById('toolFollow');
let icon = document.getElementById('toolFollowIcon'); let icon = document.getElementById('toolFollowIcon');
el.classList.add('is-primary'); el.classList.add('is-primary');
icon.innerText='sync'; icon.innerText='sync';
icon.classList.add('icn-spinner'); icon.classList.add('icn-spinner');
editor.gotoLine(editor.session.getLength()); editor.gotoLine(editor.session.getLength());
FileGet().then(()=>{
ToolIsFollow = true
})
} }
} }