mirror of
https://github.com/samuelncui/yatm.git
synced 2026-08-31 13:17:13 +00:00
feat: rebrand to yatm
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
domain: http://127.0.0.1:8080
|
||||
listen: 127.0.0.1:8080
|
||||
debug_listen: 127.0.0.1:8081
|
||||
|
||||
database:
|
||||
dialect: sqlite
|
||||
dsn: ./tapes.db
|
||||
|
||||
tape_devices:
|
||||
- /dev/nst0
|
||||
|
||||
paths:
|
||||
work: ./
|
||||
source: ./
|
||||
target: ./
|
||||
|
||||
scripts:
|
||||
encrypt: ./scripts/encrypt
|
||||
mkfs: ./scripts/mkfs
|
||||
mount: ./scripts/mount
|
||||
umount: ./scripts/umount
|
||||
read_info: ./scripts/readinfo
|
||||
@@ -0,0 +1,151 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
|
||||
"github.com/improbable-eng/grpc-web/go/grpcweb"
|
||||
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||
"github.com/rifflock/lfshook"
|
||||
"github.com/samuelncui/yatm/apis"
|
||||
"github.com/samuelncui/yatm/entity"
|
||||
"github.com/samuelncui/yatm/executor"
|
||||
"github.com/samuelncui/yatm/library"
|
||||
"github.com/samuelncui/yatm/resource"
|
||||
"github.com/samuelncui/yatm/tools"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Domain string `yaml:"domain"`
|
||||
Listen string `yaml:"listen"`
|
||||
DebugListen string `yaml:"debug_listen"`
|
||||
|
||||
Database struct {
|
||||
Dialect string `yaml:"dialect"`
|
||||
DSN string `yaml:"dsn"`
|
||||
} `yaml:"database"`
|
||||
|
||||
Paths executor.Paths `yaml:"paths"`
|
||||
TapeDevices []string `yaml:"tape_devices"`
|
||||
Scripts executor.Scripts `yaml:"scripts"`
|
||||
}
|
||||
|
||||
var (
|
||||
configPath = flag.String("config", "./config.yaml", "config file path")
|
||||
)
|
||||
|
||||
func main() {
|
||||
logWriter, err := rotatelogs.New(
|
||||
"./run.log.%Y%m%d%H%M",
|
||||
rotatelogs.WithLinkName("./run.log"),
|
||||
rotatelogs.WithMaxAge(time.Duration(86400)*time.Second),
|
||||
rotatelogs.WithRotationTime(time.Duration(604800)*time.Second),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logrus.AddHook(lfshook.NewHook(
|
||||
lfshook.WriterMap{
|
||||
logrus.InfoLevel: logWriter,
|
||||
logrus.ErrorLevel: logWriter,
|
||||
},
|
||||
&logrus.TextFormatter{},
|
||||
))
|
||||
|
||||
flag.Parse()
|
||||
cf, err := os.Open(*configPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conf := new(config)
|
||||
if err := yaml.NewDecoder(cf).Decode(conf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logrus.Infof("read config success, conf= '%+v'", conf)
|
||||
|
||||
if conf.DebugListen != "" {
|
||||
go tools.Wrap(context.Background(), func() { tools.NewDebugServer(conf.DebugListen) })
|
||||
}
|
||||
|
||||
db, err := resource.NewDBConn(conf.Database.Dialect, conf.Database.DSN)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
lib := library.New(db)
|
||||
if err := lib.AutoMigrate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
exe := executor.New(db, lib, conf.TapeDevices, conf.Paths, conf.Scripts)
|
||||
if err := exe.AutoMigrate(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
grpcPanicRecoveryHandler := func(p any) (err error) {
|
||||
logrus.Infof("recovered from panic, %v, stack= %s", p, debug.Stack())
|
||||
return status.Errorf(codes.Internal, "%s", p)
|
||||
}
|
||||
s := grpc.NewServer(
|
||||
grpc.ChainUnaryInterceptor(
|
||||
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)),
|
||||
),
|
||||
grpc.ChainStreamInterceptor(
|
||||
recovery.StreamServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)),
|
||||
),
|
||||
)
|
||||
api := apis.New(conf.Paths.Source, lib, exe)
|
||||
entity.RegisterServiceServer(s, api)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
grpcWebServer := grpcweb.WrapServer(s, grpcweb.WithOriginFunc(func(origin string) bool { return true }))
|
||||
mux.Handle("/services/", http.StripPrefix("/services/", grpcWebServer))
|
||||
mux.Handle("/files/", http.StripPrefix("/files", api.Uploader()))
|
||||
|
||||
fs := http.FileServer(http.Dir("./frontend/assets"))
|
||||
mux.Handle("/assets/", http.StripPrefix("/assets/", fs))
|
||||
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
indexBuf, err := os.ReadFile("./frontend/index.html")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.Write(bytes.ReplaceAll(indexBuf, []byte("%%API_BASE%%"), []byte(fmt.Sprintf("%s/services", conf.Domain))))
|
||||
})
|
||||
|
||||
srv := &http.Server{
|
||||
Handler: mux,
|
||||
Addr: conf.Listen,
|
||||
}
|
||||
|
||||
go func() {
|
||||
<-tools.ShutdownContext.Done()
|
||||
logrus.Infof("Graceful shutdown, wait for working process")
|
||||
start := time.Now()
|
||||
tools.Wait()
|
||||
logrus.Infof("Graceful shutdown, wait done, duration= %s", time.Since(start))
|
||||
srv.Shutdown(context.Background())
|
||||
}()
|
||||
|
||||
log.Printf("http server listening at %v", srv.Addr)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
log.Fatalf("failed to serve: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=YATM Service
|
||||
Documentation=https://github.com/samuelncui/yatm/
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/yatm
|
||||
ExecStart=/opt/yatm/yatm-httpd
|
||||
Restart=always
|
||||
RestartSec=15
|
||||
StartLimitInterval=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user