mirror of
https://github.com/InazumaV/Ratte.git
synced 2026-02-04 04:30:09 +00:00
Initial commit
This commit is contained in:
8
common/file/file.go
Normal file
8
common/file/file.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package file
|
||||
|
||||
import "os"
|
||||
|
||||
func IsExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil || !os.IsNotExist(err)
|
||||
}
|
||||
112
common/json/trim.go
Normal file
112
common/json/trim.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
type TrimNodeReader struct {
|
||||
r io.Reader
|
||||
br *bytes.Reader
|
||||
}
|
||||
|
||||
func isNL(c byte) bool {
|
||||
return c == '\n' || c == '\r'
|
||||
}
|
||||
|
||||
func isWS(c byte) bool {
|
||||
return c == ' ' || c == '\t' || isNL(c)
|
||||
}
|
||||
|
||||
func consumeComment(s []byte, i int) int {
|
||||
if i < len(s) && s[i] == '/' {
|
||||
s[i-1] = ' '
|
||||
for ; i < len(s) && !isNL(s[i]); i += 1 {
|
||||
s[i] = ' '
|
||||
}
|
||||
}
|
||||
if i < len(s) && s[i] == '*' {
|
||||
s[i-1] = ' '
|
||||
s[i] = ' '
|
||||
for ; i < len(s); i += 1 {
|
||||
if s[i] != '*' {
|
||||
s[i] = ' '
|
||||
} else {
|
||||
s[i] = ' '
|
||||
i++
|
||||
if i < len(s) {
|
||||
if s[i] == '/' {
|
||||
s[i] = ' '
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func prep(r io.Reader) (s []byte, err error) {
|
||||
buf := &bytes.Buffer{}
|
||||
_, err = io.Copy(buf, r)
|
||||
s = buf.Bytes()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(s) {
|
||||
switch s[i] {
|
||||
case '"':
|
||||
i += 1
|
||||
for i < len(s) {
|
||||
if s[i] == '"' {
|
||||
i += 1
|
||||
break
|
||||
} else if s[i] == '\\' {
|
||||
i += 1
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
case '/':
|
||||
i = consumeComment(s, i+1)
|
||||
case ',':
|
||||
j := i
|
||||
for {
|
||||
i += 1
|
||||
if i >= len(s) {
|
||||
break
|
||||
} else if s[i] == '}' || s[i] == ']' {
|
||||
s[j] = ' '
|
||||
break
|
||||
} else if s[i] == '/' {
|
||||
i = consumeComment(s, i+1)
|
||||
} else if !isWS(s[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Read acts as a proxy for the underlying reader and cleans p
|
||||
// of comments and trailing commas preceeding ] and }
|
||||
// comments are delimitted by // up until the end the line
|
||||
func (st *TrimNodeReader) Read(p []byte) (n int, err error) {
|
||||
if st.br == nil {
|
||||
var s []byte
|
||||
if s, err = prep(st.r); err != nil {
|
||||
return
|
||||
}
|
||||
st.br = bytes.NewReader(s)
|
||||
}
|
||||
return st.br.Read(p)
|
||||
}
|
||||
|
||||
// NewTrimNodeReader New returns an io.Reader acting as proxy to r
|
||||
func NewTrimNodeReader(r io.Reader) io.Reader {
|
||||
return &TrimNodeReader{r: r}
|
||||
}
|
||||
10
common/maps/maps.go
Normal file
10
common/maps/maps.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package maps
|
||||
|
||||
func Merge[k comparable, v any](m1 map[k]v, m2 ...map[k]v) map[k]v {
|
||||
for _, m2v := range m2 {
|
||||
for k2, v2 := range m2v {
|
||||
m1[k2] = v2
|
||||
}
|
||||
}
|
||||
return m1
|
||||
}
|
||||
18
common/slices/slice.go
Normal file
18
common/slices/slice.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package slices
|
||||
|
||||
func Range[t any](sl []t, handle func(i int, v t) (_break bool)) {
|
||||
for i := range sl {
|
||||
b := handle(i, sl[i])
|
||||
if b {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RangeToNew[old, new any](sl []old, handle func(i int, v old) new) []new {
|
||||
ns := make([]new, len(sl))
|
||||
for i := range ns {
|
||||
ns[i] = handle(i, sl[i])
|
||||
}
|
||||
return ns
|
||||
}
|
||||
75
common/watcher/http.go
Normal file
75
common/watcher/http.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package watcher
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type HTTPWatcher struct {
|
||||
hash [32]byte
|
||||
url string
|
||||
interval uint
|
||||
handler EventHandler
|
||||
errorHandler ErrorHandler
|
||||
close chan struct{}
|
||||
}
|
||||
|
||||
func NewHTTPWatcher(url string, interval uint) *HTTPWatcher {
|
||||
return &HTTPWatcher{
|
||||
url: url,
|
||||
interval: interval,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *HTTPWatcher) handle() error {
|
||||
rsp, err := http.Get(w.url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("request error: %w", err)
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
b, err := io.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read body error: %w", err)
|
||||
}
|
||||
h := sha256.Sum256(b)
|
||||
if bytes.Equal(w.hash[:], h[:]) {
|
||||
return nil
|
||||
}
|
||||
w.hash = h
|
||||
err = w.handler(w.url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("handle error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *HTTPWatcher) SetEventHandler(handler EventHandler) {
|
||||
w.handler = handler
|
||||
}
|
||||
|
||||
func (w *HTTPWatcher) SetErrorHandler(handler ErrorHandler) {
|
||||
w.errorHandler = handler
|
||||
}
|
||||
|
||||
func (w *HTTPWatcher) Watch() error {
|
||||
go func() {
|
||||
for range time.Tick(time.Duration(w.interval) * time.Second) {
|
||||
select {
|
||||
case <-w.close:
|
||||
return
|
||||
default:
|
||||
}
|
||||
w.errorHandler(w.handle())
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *HTTPWatcher) Close() error {
|
||||
close(w.close)
|
||||
return nil
|
||||
}
|
||||
85
common/watcher/local.go
Normal file
85
common/watcher/local.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package watcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
type LocalWatcher struct {
|
||||
dir string
|
||||
filenames []string
|
||||
handler EventHandler
|
||||
errorHandler ErrorHandler
|
||||
watcher *fsnotify.Watcher
|
||||
close chan struct{}
|
||||
}
|
||||
|
||||
func NewLocalWatcher(dir string, filenames []string) *LocalWatcher {
|
||||
return &LocalWatcher{
|
||||
dir: dir,
|
||||
filenames: filenames,
|
||||
close: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LocalWatcher) SetEventHandler(handler EventHandler) {
|
||||
w.handler = handler
|
||||
}
|
||||
func (w *LocalWatcher) SetErrorHandler(handler ErrorHandler) {
|
||||
w.errorHandler = handler
|
||||
}
|
||||
|
||||
func (w *LocalWatcher) handle(e fsnotify.Event) error {
|
||||
if (!e.Has(fsnotify.Write)) && (!e.Has(fsnotify.Create)) {
|
||||
return nil
|
||||
}
|
||||
name := path.Base(e.Name)
|
||||
file := ""
|
||||
for _, filename := range w.filenames {
|
||||
ok, _ := path.Match(filename, name)
|
||||
if ok {
|
||||
file = filename
|
||||
}
|
||||
}
|
||||
if len(file) == 0 {
|
||||
return nil
|
||||
}
|
||||
err := w.handler(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *LocalWatcher) Watch() error {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return fmt.Errorf("new watcher error: %s", err)
|
||||
}
|
||||
go func() {
|
||||
defer watcher.Close()
|
||||
for {
|
||||
select {
|
||||
case e := <-watcher.Events:
|
||||
err := w.handle(e)
|
||||
if err != nil {
|
||||
w.errorHandler(err)
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
if err != nil {
|
||||
w.errorHandler(err)
|
||||
}
|
||||
case <-w.close:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return watcher.Add(w.dir)
|
||||
}
|
||||
|
||||
func (w *LocalWatcher) Close() error {
|
||||
close(w.close)
|
||||
return w.watcher.Close()
|
||||
}
|
||||
11
common/watcher/watcher.go
Normal file
11
common/watcher/watcher.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package watcher
|
||||
|
||||
type EventHandler func(filename string) error
|
||||
type ErrorHandler func(err error)
|
||||
|
||||
type Watcher interface {
|
||||
SetEventHandler(handler EventHandler)
|
||||
SetErrorHandler(handler ErrorHandler)
|
||||
Watch() error
|
||||
Close() error
|
||||
}
|
||||
Reference in New Issue
Block a user