diff --git a/Makefile b/Makefile
index 330dc96..054ab4f 100644
--- a/Makefile
+++ b/Makefile
@@ -5,4 +5,4 @@ run:
APP_LOG_PRETTY=true \
APP_DB_TYPE=sqlite \
APP_DATA=work \
- go run main.go
\ No newline at end of file
+ go run cmd/test/main.go
\ No newline at end of file
diff --git a/README.md b/README.md
index b126c23..dd63f95 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
# Kumoly App
-combine all needed module into one lib
\ No newline at end of file
+combine all needed module into one lib
+
+## Run
+
+```
+
+```
\ No newline at end of file
diff --git a/scripts/build.sh b/build.sh
similarity index 100%
rename from scripts/build.sh
rename to build.sh
diff --git a/main.go b/cmd/test/main.go
similarity index 76%
rename from main.go
rename to cmd/test/main.go
index 674cc2f..758eed3 100644
--- a/main.go
+++ b/cmd/test/main.go
@@ -2,6 +2,7 @@ package main
import (
"kumoly.io/kumoly/app/auth"
+ "kumoly.io/kumoly/app/history"
"kumoly.io/kumoly/app/server"
"kumoly.io/kumoly/app/store"
"kumoly.io/kumoly/app/system"
@@ -17,7 +18,7 @@ func main() {
auth.SetDB(store.DB)
sys.Inject(auth.Injector(server.API))
- sys.Append(server, auth.New(server), &task.Service{})
+ sys.Append(server, auth.New(server), &task.Service{}, &history.Service{})
sys.Start()
}
diff --git a/history/helper.go b/history/helper.go
new file mode 100644
index 0000000..f1bf463
--- /dev/null
+++ b/history/helper.go
@@ -0,0 +1,27 @@
+package history
+
+import "kumoly.io/kumoly/app/util"
+
+func Error() *History {
+ h := getBase()
+ h.Type = ERROR
+ if !PROD {
+ h.Trace = util.Stack()
+ }
+ return h
+}
+
+func Info() *History {
+ h := getBase()
+ h.Type = INFO
+ return h
+}
+
+func getBase() *History {
+ mod, file := util.CallerMod(3)
+ h := &History{
+ Module: mod,
+ Caller: file,
+ }
+ return h
+}
diff --git a/history/history.go b/history/history.go
new file mode 100644
index 0000000..0e06433
--- /dev/null
+++ b/history/history.go
@@ -0,0 +1,102 @@
+package history
+
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/rs/zerolog/log"
+ "gorm.io/gorm"
+ "kumoly.io/kumoly/app/errors"
+ "kumoly.io/kumoly/app/store"
+)
+
+var PROD = false
+
+const (
+ ERROR = "ERROR"
+ INFO = "INFO"
+)
+
+type History struct {
+ ID uint `gorm:"primaryKey"`
+ CreatedAt time.Time
+
+ Module string
+ Type string
+
+ Message string
+ BodyJson string
+ Body interface{} `gorm:"-"`
+ Issuer string
+ Caller string
+ Trace string
+}
+
+func (h *History) BeforeCreate(tx *gorm.DB) (err error) {
+ if h.Body != nil {
+ body, err := json.Marshal(h.Body)
+ if err != nil {
+ h.BodyJson = string(body)
+ }
+ }
+ return
+}
+
+var Tunnel chan *History
+var quit chan struct{}
+var started chan struct{}
+
+func init() {
+ Tunnel = make(chan *History)
+ quit = make(chan struct{}, 1)
+ started = make(chan struct{}, 1)
+}
+
+func Start(r Receiver) {
+ select {
+ case started <- struct{}{}:
+ default:
+ panic(errors.New(500, "history reporter has already started!"))
+ }
+ go func() {
+ for {
+ select {
+ case h := <-Tunnel:
+ if Interceptor != nil {
+ go Interceptor(h)
+ }
+ r(h)
+ case <-quit:
+ <-started
+ return
+ }
+ }
+ }()
+}
+
+func Stop() {
+ quit <- struct{}{}
+}
+
+func Send(h *History) {
+ if h.Type == "" {
+ h.Type = INFO
+ }
+ Tunnel <- h
+}
+
+type Receiver func(*History)
+
+var Interceptor func(*History) = nil
+
+var DBReceiver Receiver = func(h *History) {
+ err := store.DB.Create(h).Error
+ if err != nil {
+ log.Error().Str("mod", "history").Err(err).Msg("DBReceiver error")
+ }
+}
+
+var ConsoleReceiver Receiver = func(h *History) {
+ fmt.Printf("%+v\n", h)
+}
diff --git a/history/history_test.go b/history/history_test.go
new file mode 100644
index 0000000..b9852fa
--- /dev/null
+++ b/history/history_test.go
@@ -0,0 +1,32 @@
+package history
+
+import (
+ "testing"
+ "time"
+
+ "kumoly.io/kumoly/app/util"
+)
+
+func TestHistory(t *testing.T) {
+ t.Log("start")
+ Start(func(h *History) {
+ t.Logf("%+v\n", h)
+ })
+ go func() {
+ for {
+ Send(&History{
+ Module: "test",
+ Type: INFO,
+ Message: "testing",
+ Body: time.Now().String(),
+ Caller: util.Caller(2),
+ })
+ time.Sleep(time.Second)
+ }
+ }()
+
+ time.Sleep(time.Second * 20)
+ Stop()
+ t.Log("stoped")
+ time.Sleep(time.Second * 2)
+}
diff --git a/history/service.go b/history/service.go
new file mode 100644
index 0000000..e561d71
--- /dev/null
+++ b/history/service.go
@@ -0,0 +1,34 @@
+package history
+
+import (
+ "github.com/rs/zerolog/log"
+ "github.com/spf13/viper"
+ "kumoly.io/kumoly/app/store"
+ "kumoly.io/kumoly/app/system"
+)
+
+type Service struct {
+ system.BaseService
+}
+
+func (srv Service) GetName() string { return "history.Service" }
+func (srv Service) IsService() bool { return true }
+func (srv Service) Init() error {
+ PROD = viper.GetBool("prod")
+ l := log.With().Str("mod", "history").
+ Str("service", "history.Service").
+ Logger()
+ l.Debug().Msg("Migrating database for history.Service ...")
+ if err := store.Migrate(&History{}); err != nil {
+ l.Error().Err(err).Msg("Migrating database")
+ return err
+ }
+ return nil
+}
+func (srv Service) Main() error {
+ Start(DBReceiver)
+ return nil
+}
+func (srv Service) Del() {
+ Stop()
+}
diff --git a/messenger/base.gohtml b/messenger/base.gohtml
new file mode 100644
index 0000000..4adfac3
--- /dev/null
+++ b/messenger/base.gohtml
@@ -0,0 +1,476 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ if .Hermes.Product.Logo }}
+
+ {{ else }}
+ {{ .Hermes.Product.Name }}
+ {{ end }}
+
+ |
+
+
+
+
+
+
+
+
+ {{if .Email.Body.Title }}{{ .Email.Body.Title }}{{ else }}{{ .Email.Body.Greeting }} {{ .Email.Body.Name }},{{ end }}
+ {{ with .Email.Body.Intros }}
+ {{ if gt (len .) 0 }}
+ {{ range $line := . }}
+ {{ $line }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ {{ if (ne .Email.Body.FreeMarkdown "") }}
+ {{ .Email.Body.FreeMarkdown.ToHTML }}
+ {{ else }}
+ {{ with .Email.Body.Dictionary }}
+ {{ if gt (len .) 0 }}
+
+ {{ range $entry := . }}
+ - {{ $entry.Key }}:
+ - {{ $entry.Value }}
+ {{ end }}
+
+ {{ end }}
+ {{ end }}
+
+ {{ with .Email.Body.Table }}
+ {{ $data := .Data }}
+ {{ $columns := .Columns }}
+ {{ if gt (len $data) 0 }}
+
+
+
+
+
+ {{ $col := index $data 0 }}
+ {{ range $entry := $col }}
+
+ {{ $entry.Key }}
+ |
+ {{ end }}
+
+ {{ range $row := $data }}
+
+ {{ range $cell := $row }}
+
+ {{ $cell.Value }}
+ |
+ {{ end }}
+
+ {{ end }}
+
+ |
+
+
+ {{ end }}
+ {{ end }}
+
+ {{ with .Email.Body.Actions }}
+ {{ if gt (len .) 0 }}
+ {{ range $action := . }}
+ {{ $action.Instructions }}
+ {{ $length := len $action.Button.Text }}
+ {{ $width := add (mul $length 9) 20 }}
+ {{if (lt $width 200)}}{{$width = 200}}{{else if (gt $width 570)}}{{$width = 570}}{{else}}{{end}}
+ {{safe "" }}
+ {{safe ""}}
+
+ {{safe "" }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ {{ with .Email.Body.Outros }}
+ {{ if gt (len .) 0 }}
+ {{ range $line := . }}
+ {{ $line }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+
+ {{.Email.Body.Signature}},
+
+ {{.Hermes.Product.Name}}
+
+ {{ if (eq .Email.Body.FreeMarkdown "") }}
+ {{ with .Email.Body.Actions }}
+
+
+ {{ range $action := . }}
+ {{if $action.Button.Text}}
+
+
+ {{$.Hermes.Product.TroubleText | replace "{ACTION}" $action.Button.Text}}
+ {{ $action.Button.Link }}
+ |
+
+ {{ end }}
+ {{ end }}
+
+
+ {{ end }}
+ {{ end }}
+ |
+
+
+ |
+
+
+
+
+ |
+
+
+ |
+
+
+
+
\ No newline at end of file
diff --git a/messenger/messenger.go b/messenger/messenger.go
new file mode 100644
index 0000000..8393a7d
--- /dev/null
+++ b/messenger/messenger.go
@@ -0,0 +1,5 @@
+package messenger
+
+func init() {
+
+}
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000..e8149a4
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,9 @@
+
+export APP_SERVER_HOST=127.0.0.1
+export APP_SERVER_PORT=8000
+export APP_LOG_LEVEL=-1
+export APP_PROD=false
+export APP_LOG_PRETTY=true
+export APP_DB_TYPE=sqlite
+export APP_DATA=work
+go run cmd/test/main.go
\ No newline at end of file
diff --git a/system/helper.go b/system/helper.go
index 243843a..ac27e9a 100644
--- a/system/helper.go
+++ b/system/helper.go
@@ -9,7 +9,7 @@ import (
type BaseService struct{}
func (srv BaseService) GetName() string { return "base" }
-func (srv BaseService) GetDependencies() []string { return []string{""} }
+func (srv BaseService) GetDependencies() []string { return []string{} }
func (srv BaseService) IsService() bool { return false }
func (srv BaseService) Init() error { return nil }
func (srv BaseService) Load() error { return nil }
diff --git a/system/setup.go b/system/setup.go
index 753f44e..0aabf29 100644
--- a/system/setup.go
+++ b/system/setup.go
@@ -1,6 +1,7 @@
package system
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -42,6 +43,7 @@ func init() {
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv()
viper.SetConfigType("json")
+ setup()
}
func setup() {
@@ -60,9 +62,24 @@ func setup() {
if cc, ok := i.(string); ok {
c = cc
}
- // if len(c) > 0 {
-
- // }
+ if len(c) > 0 {
+ // shorten caller to mod/file:line
+ segs := strings.Split(c, ":")
+ file := segs[len(segs)-2]
+ short := file
+ skip := false
+ for i := len(file) - 1; i > 0; i-- {
+ if file[i] == '/' {
+ if !skip {
+ skip = true
+ continue
+ }
+ short = file[i+1:]
+ break
+ }
+ }
+ return fmt.Sprintf("%v:%v", short, segs[len(segs)-1])
+ }
return c
},
})
diff --git a/system/system.go b/system/system.go
index 01fea71..c6302a9 100644
--- a/system/system.go
+++ b/system/system.go
@@ -98,7 +98,7 @@ func New() *System {
}
func (sys *System) Start() {
- setup()
+ // setup()
sys.order()
sys.status = sys_init
go func() {
diff --git a/util/logging.go b/util/logging.go
index 80e92ea..2111582 100644
--- a/util/logging.go
+++ b/util/logging.go
@@ -7,11 +7,39 @@ import (
"runtime"
)
+func Stack() string {
+ buf := make([]byte, 1024)
+ for {
+ n := runtime.Stack(buf, false)
+ if n < len(buf) {
+ return string(buf[:n])
+ }
+ buf = make([]byte, 2*len(buf))
+ }
+}
+
func CallerFull(depth int) string {
_, file, line, _ := runtime.Caller(depth)
return fmt.Sprintf("%s:%d", file, line)
}
+func CallerMod(depth int) (mod, file string) {
+ _, f, l, _ := runtime.Caller(depth)
+ ptr := 0
+ for i := len(f) - 1; i > 0; i-- {
+ if f[i] == '/' {
+ if ptr == 0 {
+ file = fmt.Sprintf("%v:%v", f[i+1:], l)
+ ptr = i
+ } else {
+ mod = f[i+1 : ptr]
+ break
+ }
+ }
+ }
+ return
+}
+
func Caller(depth int) string {
_, file, line, _ := runtime.Caller(depth)
short := file
diff --git a/util/logging_test.go b/util/logging_test.go
new file mode 100644
index 0000000..4e456d6
--- /dev/null
+++ b/util/logging_test.go
@@ -0,0 +1,22 @@
+package util
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestStack(t *testing.T) {
+ fmt.Println(Stack())
+}
+
+func TestCallerFull(t *testing.T) {
+ fmt.Println(CallerFull(1))
+}
+
+func TestCallerMod(t *testing.T) {
+ fmt.Println(CallerMod(1))
+}
+
+func TestCaller(t *testing.T) {
+ fmt.Println(Caller(1))
+}