feat: add Fiber HTTPS server with embedded static files
This commit is contained in:
119
main.go
Normal file
119
main.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"github.com/imbytecat/voicepaste/internal/asr"
|
||||
"github.com/imbytecat/voicepaste/internal/config"
|
||||
"github.com/imbytecat/voicepaste/internal/paste"
|
||||
"github.com/imbytecat/voicepaste/internal/server"
|
||||
"github.com/imbytecat/voicepaste/internal/ws"
|
||||
)
|
||||
|
||||
//go:embed all:web
|
||||
var webFS embed.FS
|
||||
var version = "dev"
|
||||
|
||||
func main() {
|
||||
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
||||
Level: slog.LevelInfo,
|
||||
})))
|
||||
|
||||
slog.Info("VoicePaste", "version", version)
|
||||
|
||||
// Load config
|
||||
cfg, err := config.Load("")
|
||||
if err != nil {
|
||||
slog.Error("failed to load config", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Start config hot-reload watcher
|
||||
config.WatchAndReload("")
|
||||
|
||||
// Initialize clipboard
|
||||
if err := paste.Init(); err != nil {
|
||||
slog.Warn("clipboard init failed, paste will be unavailable", "err", err)
|
||||
}
|
||||
// Detect LAN IP
|
||||
lanIP, err := server.GetLANIP()
|
||||
if err != nil {
|
||||
slog.Error("failed to detect LAN IP", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Generate auth token
|
||||
token := server.GenerateToken()
|
||||
|
||||
// Build URL
|
||||
scheme := "https"
|
||||
if !cfg.Server.TLSAuto {
|
||||
scheme = "http"
|
||||
}
|
||||
url := fmt.Sprintf("%s://%s:%d/?token=%s", scheme, lanIP, cfg.Server.Port, token)
|
||||
|
||||
// Print connection info
|
||||
fmt.Println()
|
||||
fmt.Println("╔══════════════════════════════════════╗")
|
||||
fmt.Println("║ VoicePaste Ready ║")
|
||||
fmt.Println("╚══════════════════════════════════════╝")
|
||||
fmt.Println()
|
||||
fmt.Printf(" URL: %s\n", url)
|
||||
fmt.Println()
|
||||
printQRCode(url)
|
||||
fmt.Println()
|
||||
fmt.Println(" Scan QR code with your phone to connect.")
|
||||
fmt.Println(" Press Ctrl+C to stop.")
|
||||
fmt.Println()
|
||||
|
||||
// Create and start server
|
||||
webContent, _ := fs.Sub(webFS, "web")
|
||||
srv := server.New(token, lanIP, webContent)
|
||||
|
||||
// Build ASR factory from config
|
||||
asrCfg := asr.Config{
|
||||
AppKey: cfg.Doubao.AppKey,
|
||||
AccessKey: cfg.Doubao.AccessKey,
|
||||
ResourceID: cfg.Doubao.ResourceID,
|
||||
}
|
||||
asrFactory := func(resultCh chan<- ws.ServerMsg) (func([]byte), func(), error) {
|
||||
client, err := asr.Dial(asrCfg, resultCh)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sendAudio := func(pcm []byte) {
|
||||
if err := client.SendAudio(pcm, false); err != nil {
|
||||
slog.Warn("send audio to asr", "err", err)
|
||||
}
|
||||
}
|
||||
cleanup := func() {
|
||||
// Send last empty frame to signal end
|
||||
_ = client.SendAudio(nil, true)
|
||||
client.Close()
|
||||
}
|
||||
return sendAudio, cleanup, nil
|
||||
}
|
||||
|
||||
// Register WebSocket handler
|
||||
wsHandler := ws.NewHandler(token, paste.Paste, asrFactory)
|
||||
wsHandler.Register(srv.App())
|
||||
|
||||
// Graceful shutdown
|
||||
go func() {
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigCh
|
||||
slog.Info("shutting down...")
|
||||
srv.Shutdown()
|
||||
}()
|
||||
|
||||
if err := srv.Start(); err != nil {
|
||||
slog.Error("server error", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user