feat: expand vehicle data platform capabilities
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
|
||||
"lingniu/vehicle-data-platform/apps/api/internal/config"
|
||||
"lingniu/vehicle-data-platform/apps/api/internal/httpx"
|
||||
"lingniu/vehicle-data-platform/apps/api/internal/openplatform"
|
||||
"lingniu/vehicle-data-platform/apps/api/internal/platform"
|
||||
"lingniu/vehicle-data-platform/apps/api/internal/static"
|
||||
)
|
||||
@@ -72,7 +74,12 @@ func NewServer(cfg config.Config) http.Handler {
|
||||
log.Printf("production mysql store enabled")
|
||||
}
|
||||
}
|
||||
var api http.Handler = platform.NewHandler(platform.NewServiceWithRuntime(store, platform.RuntimeInfo{
|
||||
host, _ := os.Hostname()
|
||||
workerHost := strings.TrimSpace(host)
|
||||
if workerHost == "" {
|
||||
workerHost = "api"
|
||||
}
|
||||
platformService := platform.NewServiceWithRuntime(store, platform.RuntimeInfo{
|
||||
DataMode: dataMode,
|
||||
ExportDir: strings.TrimSpace(cfg.ExportDir),
|
||||
RequestTimeoutMs: int(cfg.RequestTimeout / time.Millisecond),
|
||||
@@ -84,13 +91,30 @@ func NewServer(cfg config.Config) http.Handler {
|
||||
PlatformRelease: strings.TrimSpace(cfg.PlatformRelease),
|
||||
AlertStreamMode: strings.TrimSpace(cfg.AlertStreamMode),
|
||||
AlertStreamConsumerGroup: strings.TrimSpace(cfg.AlertStreamKafkaGroup),
|
||||
}))
|
||||
AlertNotificationConfig: alertNotificationConfig(cfg, dataMode),
|
||||
HistoryCleanupAutomation: cfg.HistoryCleanupAutomation,
|
||||
HistoryCleanupPoll: cfg.HistoryCleanupPollInterval,
|
||||
HistoryCleanupLease: cfg.HistoryCleanupLease,
|
||||
HistoryCleanupWorkerID: "cleanup-scheduler-" + workerHost,
|
||||
})
|
||||
platformService.StartHistoryExportCleanupAutomation(context.Background())
|
||||
var api http.Handler = platform.NewHandler(platformService)
|
||||
if storeErr != nil {
|
||||
log.Printf("platform data store unavailable: %v", storeErr)
|
||||
api = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
httpx.WriteError(w, http.StatusServiceUnavailable, "DATA_STORE_UNAVAILABLE", "生产数据源不可用", storeErr.Error(), requestTraceID(r))
|
||||
})
|
||||
}
|
||||
if authDB != nil && storeErr == nil {
|
||||
openPlatformHandler := openplatform.NewAdminHandler(
|
||||
openplatform.NewService(openplatform.NewMySQLRepository(authDB)),
|
||||
openplatform.NewPortalService(authDB, cfg.SessionTTL),
|
||||
)
|
||||
internalMux := http.NewServeMux()
|
||||
internalMux.Handle("/api/v2/open-platform/", openPlatformHandler)
|
||||
internalMux.Handle("/", api)
|
||||
api = internalMux
|
||||
}
|
||||
// Reverse geocoding consumes the server-side AMap credential, so it must
|
||||
// stay behind the same authentication boundary as the platform API.
|
||||
api = withAMapReverseGeocodeAPI(api, cfg, "https://restapi.amap.com", http.DefaultClient)
|
||||
@@ -100,6 +124,32 @@ func NewServer(cfg config.Config) http.Handler {
|
||||
return withRequestTimeout(handler, cfg.RequestTimeout)
|
||||
}
|
||||
|
||||
func alertNotificationConfig(cfg config.Config, dataMode string) platform.AlertNotificationConfig {
|
||||
channels := []platform.AlertNotificationChannelCapability{
|
||||
{Channel: "in_app", Label: "站内信", Configured: true},
|
||||
{Channel: "sms", Label: "短信", Configured: dataMode == "mock" || strings.TrimSpace(cfg.AlertNotificationSMSURL) != "" && strings.TrimSpace(cfg.AlertNotificationSMSSecret) != ""},
|
||||
{Channel: "email", Label: "邮件", Configured: dataMode == "mock" || strings.TrimSpace(cfg.AlertNotificationEmailURL) != "" && strings.TrimSpace(cfg.AlertNotificationEmailSecret) != ""},
|
||||
{Channel: "wecom", Label: "企业通讯", Configured: dataMode == "mock" || strings.TrimSpace(cfg.AlertNotificationWeComURL) != "" && strings.TrimSpace(cfg.AlertNotificationWeComSecret) != ""},
|
||||
}
|
||||
targets := []platform.AlertNotificationTargetOption{{ID: "platform-operators", Label: "平台值班组", Channels: []string{"in_app"}}}
|
||||
raw := strings.TrimSpace(cfg.AlertNotificationTargetsJSON)
|
||||
if raw == "" && dataMode == "mock" {
|
||||
targets = []platform.AlertNotificationTargetOption{
|
||||
{ID: "platform-operators", Label: "平台值班组", Channels: []string{"in_app", "email", "wecom"}},
|
||||
{ID: "night-shift", Label: "夜班负责人", Channels: []string{"in_app", "sms", "wecom"}},
|
||||
{ID: "data-platform", Label: "数据平台负责人", Channels: []string{"in_app", "email", "wecom"}},
|
||||
}
|
||||
} else if raw != "" {
|
||||
var configured []platform.AlertNotificationTargetOption
|
||||
if err := json.Unmarshal([]byte(raw), &configured); err != nil {
|
||||
log.Printf("alert notification target catalog ignored: %v", err)
|
||||
} else {
|
||||
targets = configured
|
||||
}
|
||||
}
|
||||
return platform.NormalizeAlertNotificationConfig(platform.AlertNotificationConfig{Targets: targets, Channels: channels})
|
||||
}
|
||||
|
||||
func withAppConfig(next http.Handler, cfg config.Config) http.Handler {
|
||||
type appConfig struct {
|
||||
AMapWebJSKey string `json:"amapWebJsKey,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user