// Copyright 2026 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package object import ( "fmt" "sync" "github.com/casdoor/casdoor/log" ) var ( runningCollectors = map[string]log.LogProvider{} // providerGetId() -> LogProvider runningCollectorsMu sync.Mutex ) // InitLogProviders scans all globally-configured Log providers and starts // background collection for pull-based providers (e.g. System Log, SELinux Log) // and registers passive providers (e.g. OpenClaw). // It is called once from main() after the database is ready. func InitLogProviders() { providers, err := GetGlobalProviders() if err != nil { return } for _, p := range providers { if p.Category != "Log" { continue } if p.State == "Disabled" { continue } switch p.Type { case "System Log", "SELinux Log": startLogCollector(p) case "Agent": if p.SubType == "OpenClaw" { startOpenClawProvider(p) startOpenClawTranscriptSync(p) } } } } func stopCollector(id string) { runningCollectorsMu.Lock() defer runningCollectorsMu.Unlock() if existing, ok := runningCollectors[id]; ok { _ = existing.Stop() delete(runningCollectors, id) } } // startLogCollector starts a pull-based log collector (System Log / SELinux Log) // for the given provider. If a collector for the same provider is already // running it is stopped first. func startLogCollector(provider *Provider) { id := provider.GetId() stopCollector(id) lp, err := log.GetLogProvider(provider.Type, provider.Host, provider.Port, provider.Title) if err != nil { return } providerName := provider.Name addEntry := func(owner, createdTime, _ string, message string) error { name := log.GenerateEntryName() entry := &Entry{ Owner: owner, Name: name, CreatedTime: createdTime, UpdatedTime: createdTime, DisplayName: name, Provider: providerName, Message: message, } _, err := AddEntry(entry) return err } onError := func(err error) { fmt.Printf("InitLogProviders: collector for provider %s stopped with error: %v\n", providerName, err) } if err := lp.Start(addEntry, onError); err != nil { fmt.Printf("InitLogProviders: failed to start collector for provider %s: %v\n", providerName, err) return } runningCollectorsMu.Lock() defer runningCollectorsMu.Unlock() runningCollectors[id] = lp } // startOpenClawProvider registers an OpenClaw provider in runningCollectors so // that incoming OTLP requests can be routed to it by IP. func startOpenClawProvider(provider *Provider) { id := provider.GetId() stopCollector(id) lp, err := GetLogProviderFromProvider(provider) if err != nil { fmt.Printf("InitLogProviders: failed to create OpenClaw provider %s: %v\n", provider.Name, err) return } runningCollectorsMu.Lock() defer runningCollectorsMu.Unlock() runningCollectors[id] = lp } func refreshLogProviderRuntime(oldID string, provider *Provider) { if provider == nil { if oldID != "" { stopLogProviderRuntime(oldID) } return } if oldID != "" { stopLogProviderRuntime(oldID) } if provider.Category != "Log" { return } if provider.State == "Disabled" { return } switch provider.Type { case "System Log", "SELinux Log": startLogCollector(provider) case "Agent": if provider.SubType == "OpenClaw" { startOpenClawProvider(provider) startOpenClawTranscriptSync(provider) } } } func stopLogProviderRuntime(providerID string) { if providerID == "" { return } stopCollector(providerID) stopOpenClawTranscriptSync(providerID) } // GetOpenClawProviderByIP returns the running OpenClawProvider whose Host field // matches clientIP, or whose Host is empty (meaning any IP is allowed). // Returns nil if no matching provider is registered. func GetOpenClawProviderByIP(clientIP string) (*log.OpenClawProvider, error) { providers := []*Provider{} err := ormer.Engine.Where("category = ? AND type = ? AND sub_type = ? AND (state = ? OR state = ?)", "Log", "Agent", "OpenClaw", "Enabled", "").Find(&providers) if err != nil { return nil, err } runningCollectorsMu.Lock() defer runningCollectorsMu.Unlock() for _, p := range providers { if p.Host == "" || p.Host == clientIP { if lp, ok := runningCollectors[p.GetId()]; ok { if ocp, ok := lp.(*log.OpenClawProvider); ok { return ocp, nil } } } } return nil, nil }