This commit is contained in:
Martino Ferrari
2026-06-24 01:39:15 +02:00
parent 11120bedca
commit c0f7e662be
76 changed files with 4368 additions and 210 deletions
+5 -5
View File
@@ -36,11 +36,11 @@ type archiveResponse []struct {
}
type archivePoint struct {
Secs int64 `json:"secs"`
Nanos int64 `json:"nanos"`
Val any `json:"val"`
Severity int `json:"severity"`
Status int `json:"status"`
Secs int64 `json:"secs"`
Nanos int64 `json:"nanos"`
Val any `json:"val"`
Severity int `json:"severity"`
Status int `json:"status"`
}
// fetchArchiveHistory queries the EPICS Archive Appliance JSON API for
+4 -5
View File
@@ -67,14 +67,13 @@ type caChannel struct {
// EPICS is the Channel Access data source.
type EPICS struct {
caAddrList string
archiveURL string
cfURL string
caAddrList string
archiveURL string
cfURL string
autoSyncFilter string
autoSyncFromArchiver bool
// caCtx is the CA context created in Connect().
Stored as unsafe.Pointer
// caCtx is the CA context created in Connect(). Stored as unsafe.Pointer
// because the C type (ca_client_context *) is opaque. Every goroutine
// that calls CA functions must call caAttachContext(caCtx) first, because
// Go goroutines can run on any OS thread and CA contexts are thread-local.
+3 -3
View File
@@ -28,9 +28,9 @@ func Available() bool { return true }
// EPICS is the pure-Go Channel Access data source.
type EPICS struct {
caAddrList string
archiveURL string
cfURL string
caAddrList string
archiveURL string
cfURL string
autoSyncFilter string
autoSyncFromArchiver bool
pvNames []string // pre-fetched at connect time for ListSignals
+1 -1
View File
@@ -18,7 +18,7 @@ const updateInterval = 100 * time.Millisecond // 10 Hz default
type signalDef struct {
meta datasource.Metadata
interval time.Duration // 0 → updateInterval
interval time.Duration // 0 → updateInterval
fn func(t time.Time) any
}
+7 -7
View File
@@ -4,13 +4,13 @@ package synthetic
// SignalDef describes one synthetic signal.
type SignalDef struct {
Name string `json:"name"`
DS string `json:"ds"` // upstream data source name
Signal string `json:"signal"` // upstream signal name (or "" for constant)
Inputs []InputRef `json:"inputs"` // alternative multi-input format
Pipeline []NodeDef `json:"pipeline"` // ordered list of DSP nodes
Graph *Graph `json:"graph,omitempty"` // DAG form (preferred when present)
Meta MetaOverride `json:"meta"` // optional metadata overrides
Name string `json:"name"`
DS string `json:"ds"` // upstream data source name
Signal string `json:"signal"` // upstream signal name (or "" for constant)
Inputs []InputRef `json:"inputs"` // alternative multi-input format
Pipeline []NodeDef `json:"pipeline"` // ordered list of DSP nodes
Graph *Graph `json:"graph,omitempty"` // DAG form (preferred when present)
Meta MetaOverride `json:"meta"` // optional metadata overrides
// Visibility controls who sees this signal in the signal tree:
// "global" — listed in every panel's edit mode
+4 -4
View File
@@ -13,10 +13,10 @@ import (
// each node's inputs already resolved. Op-node state maps persist across
// evaluations (for stateful nodes like moving_average / lua).
type runtimeGraph struct {
order []*rtNode // topological order (sources first, output last)
sources []rtSource // source nodes, in topological order
outputID string // id of the output node
outType dsp.ValType // best-effort output type (scalar/array/unknown)
order []*rtNode // topological order (sources first, output last)
sources []rtSource // source nodes, in topological order
outputID string // id of the output node
outType dsp.ValType // best-effort output type (scalar/array/unknown)
}
type rtNode struct {
@@ -18,8 +18,8 @@ type seqSource struct {
seq []datasource.Value
}
func (s *seqSource) Name() string { return s.name }
func (s *seqSource) Connect(context.Context) error { return nil }
func (s *seqSource) Name() string { return s.name }
func (s *seqSource) Connect(context.Context) error { return nil }
func (s *seqSource) ListSignals(context.Context) ([]datasource.Metadata, error) { return nil, nil }
func (s *seqSource) GetMetadata(context.Context, string) (datasource.Metadata, error) {
return datasource.Metadata{Name: "x", Type: datasource.TypeFloat64}, nil
+28
View File
@@ -0,0 +1,28 @@
package datasource
import (
"context"
"testing"
)
// TestWithUserAndUserFrom covers the context identity round-trip, including the
// empty-user passthrough and the missing-identity fallback.
func TestWithUserAndUserFrom(t *testing.T) {
base := context.Background()
// No identity present.
if u, ok := UserFrom(base); ok || u != "" {
t.Errorf("UserFrom(empty) = %q,%v want \"\",false", u, ok)
}
// Empty user must not attach a value.
if ctx := WithUser(base, ""); ctx != base {
t.Error("WithUser with empty user should return the original context")
}
// Real identity round-trips.
ctx := WithUser(base, "alice")
if u, ok := UserFrom(ctx); !ok || u != "alice" {
t.Errorf("UserFrom = %q,%v want alice,true", u, ok)
}
}