continuous-integration/drone Build is failing
Migrate the workspace to React and Ant Design, improve account forms and responsive layouts, support outbound diagnostics and SSH fingerprint confirmation, and persist the management startup port. Preserve database migrations, remove S3 settings storage, and improve gateway audit handling.
88 lines
2.6 KiB
Go
88 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"linkport/internal/api"
|
|
"linkport/internal/desktop"
|
|
"linkport/internal/gateway"
|
|
"linkport/internal/store"
|
|
"linkport/web"
|
|
)
|
|
|
|
// runManagement owns the listener, desktop setup, serving and graceful shutdown.
|
|
func runManagement(s *store.Store, m *gateway.Manager, local *desktop.Config, authEnabled bool) error {
|
|
port, err := s.StartupPort()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot load startup port: %w", err)
|
|
}
|
|
server := api.New(s, m, strings.EqualFold(os.Getenv("LINKPORT_SECURE_COOKIE"), "true"), authEnabled)
|
|
srv := &http.Server{Addr: env("LINKPORT_HTTP_ADDR", net.JoinHostPort("127.0.0.1", strconv.Itoa(port))), Handler: server.Handler(web.Handler()), ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 30 * time.Second, WriteTimeout: 45 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 16}
|
|
if local != nil || !authEnabled {
|
|
host, _, e := net.SplitHostPort(srv.Addr)
|
|
if e != nil || net.ParseIP(host) == nil || !net.ParseIP(host).IsLoopback() {
|
|
return fmt.Errorf("desktop/development mode requires a loopback LINKPORT_HTTP_ADDR, such as 127.0.0.1:0; enable LINKPORT_AUTH_ENABLED for remote deployment")
|
|
}
|
|
}
|
|
listener, err := net.Listen("tcp", srv.Addr)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot listen on %s (linkport may already be running): %w", srv.Addr, err)
|
|
}
|
|
defer listener.Close()
|
|
url := "http://" + listener.Addr().String()
|
|
if local != nil {
|
|
var setupPath string
|
|
if authEnabled {
|
|
srv.Handler, setupPath, err = desktop.Setup(s, srv.Handler, listener.Addr().String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
url += setupPath
|
|
fmt.Printf("数据目录:%s\n关闭服务请按 Ctrl+C。\n", local.Dir)
|
|
}
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer stop()
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
log.Printf("linkport management listening on %s", listener.Addr())
|
|
done <- srv.Serve(listener)
|
|
}()
|
|
fmt.Println("管理页面:" + url)
|
|
if local != nil {
|
|
if os.Getenv("LINKPORT_NO_BROWSER") != "1" {
|
|
if e := desktop.OpenBrowser(url); e != nil {
|
|
log.Printf("请手动打开管理页面:%v", e)
|
|
}
|
|
}
|
|
}
|
|
s.Prune()
|
|
ticker := time.NewTicker(time.Hour)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case e := <-done:
|
|
if e == http.ErrServerClosed {
|
|
return nil
|
|
}
|
|
return e
|
|
case <-ticker.C:
|
|
s.Prune()
|
|
case <-ctx.Done():
|
|
shutdown, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
return srv.Shutdown(shutdown)
|
|
}
|
|
}
|
|
}
|