From 5d57ea5c710c2c670c42c5fe3bb42bfa62a38992 Mon Sep 17 00:00:00 2001 From: DownerCase <119755054+DownerCase@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:22:32 +0000 Subject: [PATCH] feat: Update Dockerfile to be based on Alpine and update eCAL (#36) --- .devcontainer/Dockerfile | 88 ++++++++----------- .github/workflows/ci.yml | 6 +- .golangci.yaml | 2 + cmd/go.mod | 2 +- cmd/monitor/common.go | 5 +- cmd/monitor/config_page.go | 3 +- cmd/monitor/hosts_list.go | 3 +- cmd/monitor/log_list.go | 3 +- cmd/monitor/page_processes_detailed.go | 3 +- cmd/monitor/page_processes_main.go | 3 +- cmd/monitor/page_services_detailed.go | 9 +- cmd/monitor/page_services_main.go | 19 ++-- cmd/monitor/page_topics_detailed.go | 4 +- cmd/monitor/page_topics_main.go | 17 ++-- cmd/monitor/page_topics_messages.go | 9 +- ecal/core.go | 10 ++- ecal/logging/callback.go | 1 + ecal/logging/logging.go | 2 + ecal/monitoring/callback.go | 49 ++++++----- ecal/monitoring/monitoring.go | 14 ++- .../subscriber/protobuf_subscriber.go | 16 +++- ecal/publisher/cgo_wrapping.go | 1 + ecal/publisher/publisher.go | 6 +- ecal/registration/registration.go | 6 +- ecal/string/subscriber/string_subscriber.go | 4 +- ecal/subscriber/cgo_wrapping.go | 1 + ecal/subscriber/subscriber.go | 5 +- ecal/types.cpp | 12 ++- ecal/types.go | 2 +- ecal/types.h | 14 ++- 30 files changed, 172 insertions(+), 147 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 53803b2..02fc9cd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,56 +1,54 @@ -ARG BASE_IMAGE=docker.io/ubuntu:oracular-20241120 +ARG BASE_IMAGE=docker.io/alpine:3.21.2 ### # Build eCAL 6 from source ### FROM ${BASE_IMAGE} AS builder -RUN apt-get update && apt-get install --no-install-recommends -y\ - ca-certificates \ +RUN apk add --no-cache \ + asio-dev \ cmake \ g++ \ git \ - libasio-dev \ - libprotobuf-dev \ - libprotoc-dev \ - libtclap-dev \ - libyaml-cpp-dev \ - ninja-build \ - protobuf-compiler \ - && rm -rf /var/lib/apt/lists/* + ninja-is-really-ninja \ + protobuf-dev \ + tclap-dev \ + yaml-cpp-dev \ + # fts functions which are missing musl libc + musl-fts-dev # filter=tree:0 will fetch the commits but their trees will be fetched on-demand # So we end up with the full commit history but only download trees for HEAD # This is needed over shallow clone for the tag-based auto-versioning # Reset added to ensure the same commit is always used, even if master advances -RUN git clone --single-branch --filter=tree:0 --branch master https://github.com/eclipse-ecal/ecal.git /ecal \ - && git -C ./ecal reset --hard 00f8ef0a2af296911e7de661e9c5f61a68abf809 -WORKDIR /ecal - -# Only download the submodules for dependencies not available as system packages -RUN git submodule update --init --single-branch --depth 1 \ +RUN git clone --single-branch --filter=tree:0 --branch alpine https://github.com/DownerCase/ecal.git /ecal \ + && git -C /ecal reset --hard c9e9a489e44420899693bba7360ce1e235d691e6 \ + # Only download the submodules for dependencies not available as system packages + && git -C /ecal submodule update --init --single-branch --depth 1 \ thirdparty/recycle/recycle \ thirdparty/tcp_pubsub/tcp_pubsub \ thirdparty/ecaludp/ecaludp +WORKDIR /ecal + # TODO: Blocker for installing to / or / usr # - Fix usage of `INSTALL_INCLUDE_DIR` instead of `eCAL_install_include_dir` # - Get CMakeFunctions to use GNUInstallDirs -# Configure a minimal build with less vendored dependencies -RUN cmake --preset core -G Ninja \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_STAGING_PREFIX=staging \ - -DBUILD_TIME=OFF \ - -DECAL_THIRDPARTY_BUILD_ASIO=OFF \ - -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ - -DECAL_THIRDPARTY_BUILD_TCLAP=OFF - -RUN cmake --build --preset core - -# Component based install avoids the unneeded `app` component -RUN cmake --install ./out/core/build --strip --component configuration \ +RUN \ + # Configure a minimal build with less vendored dependencies + cmake --preset core -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_STAGING_PREFIX=staging \ + -DBUILD_TIME=OFF \ + -DECAL_THIRDPARTY_BUILD_ASIO=OFF \ + -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ + -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ + -DECAL_THIRDPARTY_BUILD_TCLAP=OFF \ + # Build core preset + && cmake --build --preset core \ + # Component based install avoids the unneeded `app` component + && cmake --install ./out/core/build --strip --component configuration \ && cmake --install ./out/core/build --strip --component sdk \ && cmake --install ./out/core/build --strip --component Unspecified @@ -61,36 +59,28 @@ FROM ${BASE_IMAGE} AS dev-base LABEL org.opencontainers.image.source https://github.com/downercase/ecal-go -RUN apt-get update && apt-get install --no-install-recommends -y\ - g++ \ - libyaml-cpp0.8 \ - && rm -rf /var/lib/apt/lists/* - -# copy the ca-certificate.crt from the build stage -COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ - COPY --from=builder /ecal/staging /usr/local -# Update dynamic linker so it knows about our new libraries -RUN ldconfig - ### # Dev build-stage, for consuming eCAL and building/testing the C interface library ### FROM dev-base AS dev-cpp -RUN apt-get update && apt-get install --no-install-recommends -y\ +RUN apk add --no-cache \ cmake \ - libprotobuf-dev \ - ninja-build \ - && rm -rf /var/lib/apt/lists/* + g++ \ + protobuf-dev \ + # Ninja build compatible + samurai ### # Dev build-stage, for consuming eCAL and building/testing the Go code ### FROM dev-base AS dev-go -RUN apt-get update && apt-get install --no-install-recommends -y\ - golang \ - && rm -rf /var/lib/apt/lists/* +RUN apk add --no-cache \ + g++ \ + go \ + musl-fts \ + yaml-cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfa9cab..b5a85e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,7 +80,11 @@ jobs: - uses: actions/checkout@v4 - name: Configure - run: cmake -S . -B build -G Ninja -Werror=dev -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DCMAKE_TOOLCHAIN_FILE=project/gcc.cmake + run: 'cmake -S . -B build -G Ninja -Werror=dev + -DCMAKE_COMPILE_WARNING_AS_ERROR=ON + -DCMAKE_TOOLCHAIN_FILE=project/gcc.cmake + -DCMAKE_CXX_FLAGS="-Wall -Wextra -Wpedantic -Wconversion" + ' - name: Build run: cmake --build ./build diff --git a/.golangci.yaml b/.golangci.yaml index 8045ff2..4ac98cd 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -16,6 +16,8 @@ linters-settings: - standard - default - localmodule + gomoddirectives: + replace-local: true ireturn: allow: - tea.Model diff --git a/cmd/go.mod b/cmd/go.mod index 66d5d5a..d46a2ac 100644 --- a/cmd/go.mod +++ b/cmd/go.mod @@ -1,4 +1,4 @@ -module cmd +module github.com/DownerCase/ecal-go/cmd go 1.23.2 diff --git a/cmd/monitor/common.go b/cmd/monitor/common.go index 03af39c..97dacba 100644 --- a/cmd/monitor/common.go +++ b/cmd/monitor/common.go @@ -4,10 +4,9 @@ import ( "errors" "fmt" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) var ( @@ -54,7 +53,7 @@ func getTopicMonitoring(topicType TopicType) []monitoring.TopicMon { return nil } -func getTopicFromID(topicType TopicType, id string) (monitoring.TopicMon, error) { +func getTopicFromID(topicType TopicType, id uint64) (monitoring.TopicMon, error) { topicList := getTopicMonitoring(topicType) for _, topic := range topicList { if topic.TopicID == id { diff --git a/cmd/monitor/config_page.go b/cmd/monitor/config_page.go index 5715e31..5cbfd34 100644 --- a/cmd/monitor/config_page.go +++ b/cmd/monitor/config_page.go @@ -1,10 +1,9 @@ package main import ( + "github.com/DownerCase/ecal-go/ecal" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal" ) type ModelConfig struct { diff --git a/cmd/monitor/hosts_list.go b/cmd/monitor/hosts_list.go index b6ebd2c..480fc5c 100644 --- a/cmd/monitor/hosts_list.go +++ b/cmd/monitor/hosts_list.go @@ -3,10 +3,9 @@ package main import ( "strconv" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type ModelHosts struct { diff --git a/cmd/monitor/log_list.go b/cmd/monitor/log_list.go index aabafb8..de12cb8 100644 --- a/cmd/monitor/log_list.go +++ b/cmd/monitor/log_list.go @@ -3,12 +3,11 @@ package main import ( "time" + "github.com/DownerCase/ecal-go/ecal/logging" "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/logging" ) type LoggingPage int diff --git a/cmd/monitor/page_processes_detailed.go b/cmd/monitor/page_processes_detailed.go index 950ed8b..af267dd 100644 --- a/cmd/monitor/page_processes_detailed.go +++ b/cmd/monitor/page_processes_detailed.go @@ -4,10 +4,9 @@ import ( "fmt" "strconv" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type ModelProcessDetailed struct { diff --git a/cmd/monitor/page_processes_main.go b/cmd/monitor/page_processes_main.go index 757925f..a066873 100644 --- a/cmd/monitor/page_processes_main.go +++ b/cmd/monitor/page_processes_main.go @@ -4,10 +4,9 @@ import ( "path/filepath" "strconv" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type ModelProcessesMain struct { diff --git a/cmd/monitor/page_services_detailed.go b/cmd/monitor/page_services_detailed.go index 65fa6a7..2f46cad 100644 --- a/cmd/monitor/page_services_detailed.go +++ b/cmd/monitor/page_services_detailed.go @@ -4,15 +4,14 @@ import ( "fmt" "strconv" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type ModelServiceDetailed struct { table table.Model - ID string + ID uint64 IsServer bool } @@ -24,7 +23,7 @@ func NewDetailedServiceModel() *ModelServiceDetailed { return &ModelServiceDetailed{ table: NewTable(cols), - ID: "", + ID: 0, } } @@ -97,7 +96,7 @@ func getMethodRows(b monitoring.ServiceBase) []table.Row { for _, method := range b.Methods { rows = append(rows, table.Row{ method.Name, - fmt.Sprintf("%s -> %s (Called x%v)", method.RequestType.Type, method.ResponseType.Type, method.CallCount), + fmt.Sprintf("%v -> %v (Called x%v)", method.RequestType.Name, method.ResponseType.Name, method.CallCount), }) } diff --git a/cmd/monitor/page_services_main.go b/cmd/monitor/page_services_main.go index 820256f..33e8d2e 100644 --- a/cmd/monitor/page_services_main.go +++ b/cmd/monitor/page_services_main.go @@ -1,12 +1,12 @@ package main import ( + "fmt" "strconv" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type ModelServicesMain struct { @@ -39,13 +39,18 @@ func (m *ModelServicesMain) View() string { return baseStyle.Render(m.table.View()) + "\n" + m.table.HelpView() } -func (m *ModelServicesMain) GetSelectedID() (string, bool, error) { +func (m *ModelServicesMain) GetSelectedID() (uint64, bool, error) { row := m.table.SelectedRow() if row == nil { - return "", false, errEmptyTable + return 0, false, errEmptyTable + } + + id, err := strconv.ParseUint(row[0], 10, 64) + if err != nil { + err = fmt.Errorf("services - GetSelectedID() %w", err) } - return row[0], row[1] == "S", nil + return id, row[1] == "S", err } func (m *ModelServicesMain) updateTable(msg tea.Msg) tea.Cmd { @@ -78,14 +83,14 @@ func serviceToRow(service monitoring.ServiceBase) table.Row { func clientToRow(client monitoring.ClientMon) table.Row { return append( - []string{client.ID, "C"}, + []string{strconv.FormatUint(client.ID, 10), "C"}, serviceToRow(client.ServiceBase)..., ) } func serverToRow(server monitoring.ServerMon) table.Row { return append( - []string{server.ID, "S"}, + []string{strconv.FormatUint(server.ID, 10), "S"}, serviceToRow(server.ServiceBase)..., ) } diff --git a/cmd/monitor/page_topics_detailed.go b/cmd/monitor/page_topics_detailed.go index 1cff566..3ab750b 100644 --- a/cmd/monitor/page_topics_detailed.go +++ b/cmd/monitor/page_topics_detailed.go @@ -10,7 +10,7 @@ import ( type ModelTopicDetailed struct { table table.Model - id string `exhaustruct:"optional"` + id uint64 `exhaustruct:"optional"` topicType TopicType `exhaustruct:"optional"` } @@ -25,7 +25,7 @@ func NewDetailedModel() *ModelTopicDetailed { } } -func (m *ModelTopicDetailed) ShowTopic(topicID string, topicType TopicType) { +func (m *ModelTopicDetailed) ShowTopic(topicID uint64, topicType TopicType) { m.id = topicID m.topicType = topicType m.updateDetailedTable(nil) diff --git a/cmd/monitor/page_topics_main.go b/cmd/monitor/page_topics_main.go index b12cd96..a586a3d 100644 --- a/cmd/monitor/page_topics_main.go +++ b/cmd/monitor/page_topics_main.go @@ -1,15 +1,15 @@ package main import ( + "fmt" "strconv" "strings" + "github.com/DownerCase/ecal-go/ecal/monitoring" "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/table" tea "github.com/charmbracelet/bubbletea" - - "github.com/DownerCase/ecal-go/ecal/monitoring" ) type topicsKeyMap struct { @@ -122,10 +122,10 @@ func (m *ModelTopicsMain) View() string { return baseStyle.Render(m.table.View()) + "\n" + m.help.View(m.keymap) } -func (m *ModelTopicsMain) GetSelectedID() (string, TopicType, error) { +func (m *ModelTopicsMain) GetSelectedID() (uint64, TopicType, error) { row := m.table.SelectedRow() if row == nil { - return "", 0, errEmptyTable + return 0, 0, errEmptyTable } var topicType TopicType @@ -137,7 +137,12 @@ func (m *ModelTopicsMain) GetSelectedID() (string, TopicType, error) { topicType = topicTypePublisher } - return row[0], topicType, nil + id, err := strconv.ParseUint(row[0], 10, 64) + if err != nil { + err = fmt.Errorf("topics - GetSelectedID(): %w", err) + } + + return id, topicType, err } func (m *ModelTopicsMain) updateTopicsTable(msg tea.Msg) { @@ -168,7 +173,7 @@ func (m *ModelTopicsMain) updateTopicsTable(msg tea.Msg) { func topicToRow(topic monitoring.TopicMon) table.Row { return []string{ - topic.TopicID, + strconv.FormatUint(topic.TopicID, 10), strings.ToUpper(topic.Direction[0:1]), topic.TopicName, topic.Datatype.Name, diff --git a/cmd/monitor/page_topics_messages.go b/cmd/monitor/page_topics_messages.go index 20655a3..f45e66e 100644 --- a/cmd/monitor/page_topics_messages.go +++ b/cmd/monitor/page_topics_messages.go @@ -6,19 +6,18 @@ import ( "strconv" "strings" + "github.com/DownerCase/ecal-go/ecal/monitoring" + "github.com/DownerCase/ecal-go/ecal/subscriber" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" "github.com/muesli/reflow/wrap" - - "github.com/DownerCase/ecal-go/ecal/monitoring" - "github.com/DownerCase/ecal-go/ecal/subscriber" ) type ModelTopicMessages struct { viewport viewport.Model mon monitoring.TopicMon topicType TopicType - topicID string + topicID uint64 subscriber *subscriber.Subscriber msg []byte deserializer func([]byte) string @@ -76,7 +75,7 @@ func (m *ModelTopicMessages) Refresh() { m.mon, _ = getTopicFromID(m.topicType, m.topicID) } -func (m *ModelTopicMessages) ShowTopic(topicID string, topicType TopicType) { +func (m *ModelTopicMessages) ShowTopic(topicID uint64, topicType TopicType) { if m.topicID != topicID { m.topicType = topicType m.topicID = topicID diff --git a/ecal/core.go b/ecal/core.go index 146f3ab..d19bf79 100644 --- a/ecal/core.go +++ b/ecal/core.go @@ -11,7 +11,7 @@ import ( ) const ( - // eCAL Components + // eCAL Components. CNone uint = 0x000 CPublisher uint = 0x001 CSubscriber uint = 0x002 @@ -38,6 +38,7 @@ func NewConfig(opts ...ConfigOption) Config { for _, opt := range opts { opt(&cfg) } + return cfg } @@ -65,8 +66,11 @@ func Initialize(config Config, unitName string, components uint) bool { receive_enabled: C.bool(config.Logging.ReceiveEnabled), }, } + unitNameC := C.CString(unitName) + defer C.free(unsafe.Pointer(unitNameC)) + return bool(C.Initialize(&cconfig, unitNameC, C.uint(components))) } @@ -84,7 +88,9 @@ func IsComponentInitialized(component uint) bool { func SetUnitName(unitName string) bool { unitNameC := C.CString(unitName) + defer C.free(unsafe.Pointer(unitNameC)) + return bool(C.SetUnitName(unitNameC)) } @@ -96,8 +102,10 @@ func Ok() bool { // is planned to be removed! func GetConfig() string { var cfg string + handle := cgo.NewHandle(&cfg) defer handle.Delete() C.GetConfig(C.uintptr_t(handle)) + return cfg } diff --git a/ecal/logging/callback.go b/ecal/logging/callback.go index f794cd4..c6e42d0 100644 --- a/ecal/logging/callback.go +++ b/ecal/logging/callback.go @@ -22,6 +22,7 @@ func copyToLogMessages(cmsgs []C.struct_CLogMessage) []LogMessage { Level: Level(msg.level), } } + return msgs } diff --git a/ecal/logging/logging.go b/ecal/logging/logging.go index f217e45..d37b14f 100644 --- a/ecal/logging/logging.go +++ b/ecal/logging/logging.go @@ -6,6 +6,7 @@ package logging // void GoLog(enum eCAL_Logging_eLogLevel level, _GoString_ msg) { // Log(level, _GoStringPtr(msg), _GoStringLen(msg)); // } +//// C preamble. import "C" import ( @@ -76,6 +77,7 @@ func GetLogging() Logging { handle := cgo.NewHandle(&logs) C.GetLogging(C.uintptr_t(handle)) handle.Delete() + return logs } diff --git a/ecal/monitoring/callback.go b/ecal/monitoring/callback.go index aba0a3f..016e19f 100644 --- a/ecal/monitoring/callback.go +++ b/ecal/monitoring/callback.go @@ -10,28 +10,33 @@ import ( "github.com/DownerCase/ecal-go/ecal" ) +func copyToDatatype(datatype C.struct_CDatatype) ecal.DataType { + return ecal.DataType{ + Name: C.GoString(datatype.name), + Encoding: C.GoString(datatype.encoding), + } +} + func copyToTopicMons(ctopics []C.struct_CTopicMon) []TopicMon { topics := make([]TopicMon, len(ctopics)) for idx, pub := range ctopics { topics[idx] = TopicMon{ - TopicID: C.GoString(pub.topic_id), - RegistrationClock: int32(pub.registration_clock), - TopicName: C.GoString(pub.topic_name), - DataClock: int64(pub.data_clock), - DataFreq: int32(pub.data_freq), - TopicSize: int32(pub.topic_size), - UnitName: C.GoString(pub.unit_name), - Direction: C.GoString(pub.direction), - Datatype: ecal.DataType{ - Name: C.GoString(pub.datatype.name), - Encoding: C.GoString(pub.datatype.encoding), - }, + TopicID: uint64(pub.topic_id), + RegistrationClock: int32(pub.registration_clock), + TopicName: C.GoString(pub.topic_name), + DataClock: int64(pub.data_clock), + DataFreq: int32(pub.data_freq), + TopicSize: int32(pub.topic_size), + UnitName: C.GoString(pub.unit_name), + Direction: C.GoString(pub.direction), + Datatype: copyToDatatype(pub.datatype), ConnectionsLocal: int32(pub.connections_local), ConnectionsExternal: int32(pub.connections_external), MessageDrops: int32(pub.message_drops), HostName: C.GoString(pub.host_name), } } + return topics } @@ -52,6 +57,7 @@ func copyToProcessMons(cprocs []C.struct_CProcessMon) []ProcessMon { RuntimeVersion: C.GoString(proc.runtime), // eCAL Version in use } } + return procs } @@ -59,25 +65,20 @@ func copyToMethodMons(cmethods []C.struct_CMethodMon) []MethodMon { methods := make([]MethodMon, len(cmethods)) for idx, cmethod := range cmethods { methods[idx] = MethodMon{ - Name: C.GoString(cmethod.name), - RequestType: methodType{ - Type: C.GoString(cmethod.request_name), - Descriptor: C.GoString(cmethod.request_desc), - }, - ResponseType: methodType{ - Type: C.GoString(cmethod.response_name), - Descriptor: C.GoString(cmethod.response_desc), - }, - CallCount: int64(cmethod.call_count), + Name: C.GoString(cmethod.name), + RequestType: copyToDatatype(cmethod.req_datatype), + ResponseType: copyToDatatype(cmethod.resp_datatype), + CallCount: int64(cmethod.call_count), } } + return methods } func copyToServiceBase(cbase C.struct_CServiceCommon) ServiceBase { return ServiceBase{ Name: C.GoString(cbase.name), - ID: C.GoString(cbase.id), + ID: uint64(cbase.id), RegistrationClock: int32(cbase.registration_clock), HostName: C.GoString(cbase.host_name), Process: C.GoString(cbase.process_name), @@ -97,6 +98,7 @@ func copyToServerMons(cservers []C.struct_CServerMon) []ServerMon { PortV1: uint32(cserver.port_v1), } } + return servers } @@ -107,6 +109,7 @@ func copyToClientMons(cclients []C.struct_CClientMon) []ClientMon { ServiceBase: copyToServiceBase(cclient.base), } } + return clients } diff --git a/ecal/monitoring/monitoring.go b/ecal/monitoring/monitoring.go index 7a792c8..689f8bd 100644 --- a/ecal/monitoring/monitoring.go +++ b/ecal/monitoring/monitoring.go @@ -60,7 +60,7 @@ type TopicMon struct { // pid int32 // process_name string UnitName string - TopicID string + TopicID uint64 TopicName string Direction string Datatype ecal.DataType @@ -91,21 +91,16 @@ type ProcessMon struct { RuntimeVersion string // eCAL Version in use } -type methodType struct { - Type string - Descriptor string -} - type MethodMon struct { Name string - RequestType methodType - ResponseType methodType + RequestType ecal.DataType + ResponseType ecal.DataType CallCount int64 } type ServiceBase struct { Name string - ID string + ID uint64 Methods []MethodMon RegistrationClock int32 // registration heart beat HostName string @@ -140,5 +135,6 @@ func GetMonitoring(entities MonitorEntity) Monitoring { // via the handle C.GetMonitoring(C.uintptr_t(handle), C.uint(entities)) handle.Delete() + return mon } diff --git a/ecal/protobuf/subscriber/protobuf_subscriber.go b/ecal/protobuf/subscriber/protobuf_subscriber.go index 56772d3..7bc3a3f 100644 --- a/ecal/protobuf/subscriber/protobuf_subscriber.go +++ b/ecal/protobuf/subscriber/protobuf_subscriber.go @@ -14,20 +14,21 @@ import ( "github.com/DownerCase/ecal-go/internal/protobuf" ) -// Type must be a pointer and implement the proto.Message interface +// Type must be a pointer and implement the proto.Message interface. type Msg[T any] interface { *T proto.Message } // Both the concrete type and its proto.Message implementing pointer version -// are required to be able to both deserialize and create new values to return +// are required to be able to both deserialize and create new values to return. type Subscriber[U any, T Msg[U]] struct { subscriber.Subscriber } func New[U any, T Msg[U]](topic string) (*Subscriber[U, T], error) { var msg T + sub, err := subscriber.New(topic, subscriber.DataType{ Name: protobuf.GetFullName(msg), @@ -35,22 +36,26 @@ func New[U any, T Msg[U]](topic string) (*Subscriber[U, T], error) { Descriptor: protobuf.GetProtoMessageDescription(msg), }, ) - sub.Deserialize = deserialize[U, T] - psub := &Subscriber[U, T]{*sub} if err != nil { err = fmt.Errorf("protobuf Subscriber[%v].New(): %w", reflect.TypeFor[T](), err) } + + sub.Deserialize = deserialize[U, T] + psub := &Subscriber[U, T]{*sub} + return psub, err } func (s *Subscriber[U, T]) Receive(timeout time.Duration) (U, error) { var u U + var msg any select { case msg = <-s.Messages: case <-time.After(timeout): return u, fmt.Errorf("[Receive[%v]()]: %w", reflect.TypeFor[U](), subscriber.ErrRcvTimeout) } + switch msg := msg.(type) { case error: return u, msg @@ -65,10 +70,13 @@ func deserialize[U any, T Msg[U]](data unsafe.Pointer, dataLen int) any { // WARNING: Creates a Go slice backed by C data and deserializes into a Go // value which gets put into the channel bytesUnsafe := unsafe.Slice((*byte)(data), dataLen) + var msg U + err := proto.Unmarshal(bytesUnsafe, T(&msg)) if err != nil { return fmt.Errorf("protobuf Subscriber[%v].deserialize(): %w", reflect.TypeFor[T](), err) } + return msg } diff --git a/ecal/publisher/cgo_wrapping.go b/ecal/publisher/cgo_wrapping.go index 525305d..8c642a8 100644 --- a/ecal/publisher/cgo_wrapping.go +++ b/ecal/publisher/cgo_wrapping.go @@ -16,4 +16,5 @@ package publisher // descriptor, descriptor_len // ); //} +//// C preamble. import "C" diff --git a/ecal/publisher/publisher.go b/ecal/publisher/publisher.go index 4ce079f..d529e2a 100644 --- a/ecal/publisher/publisher.go +++ b/ecal/publisher/publisher.go @@ -2,13 +2,14 @@ package publisher // #cgo LDFLAGS: -lecal_core // #cgo CPPFLAGS: -I${SRCDIR}/../../ -//#include "publisher.h" +// #include "publisher.h" // bool GoNewPublisher( // uintptr_t handle, // _GoString_ topic, // _GoString_ name, _GoString_ encoding, // const char* const descriptor, size_t descriptor_len // ); +// // C preamble. import "C" import ( @@ -53,7 +54,9 @@ func New(topic string, datatype DataType) (*Publisher, error) { handle.Delete() return nil, ErrFailedNew } + go pub.sendMessages() + return pub, nil } @@ -62,6 +65,7 @@ func (p *Publisher) Delete() { p.stopped = true close(p.Messages) } + if !bool(C.DestroyPublisher(C.uintptr_t(p.handle))) { // "Failed to delete publisher" return diff --git a/ecal/registration/registration.go b/ecal/registration/registration.go index 0faf6c7..bbaa69b 100644 --- a/ecal/registration/registration.go +++ b/ecal/registration/registration.go @@ -32,6 +32,7 @@ func AddPublisherEventCallback(callback func(ecal.TopicID, Event)) CallbackToken ecalToken: uint(ecalToken), goHandle: handle, } + return token } @@ -47,6 +48,7 @@ func AddSubscriberEventCallback(callback func(ecal.TopicID, Event)) CallbackToke ecalToken: uint(ecalToken), goHandle: handle, } + return token } @@ -58,7 +60,7 @@ func RemSubscriberCallback(token CallbackToken) { func toTopicID(id *C.struct_CTopicId) ecal.TopicID { return ecal.TopicID{ TopicID: ecal.EntityID{ - EntityID: C.GoString(id.topic_id.entity_id), + EntityID: uint64(id.topic_id.entity_id), ProcessID: int32(id.topic_id.process_id), HostName: C.GoString(id.topic_id.host_name), }, @@ -69,9 +71,11 @@ func toTopicID(id *C.struct_CTopicId) ecal.TopicID { //export goTopicEventCallback func goTopicEventCallback(handle C.uintptr_t, id C.struct_CTopicId, event C.uint8_t) { h := cgo.Handle(handle) + f, ok := h.Value().(func(ecal.TopicID, Event)) if !ok { log.Panic("Invalid handle passed to registration callback") } + f(toTopicID(&id), Event(event)) } diff --git a/ecal/string/subscriber/string_subscriber.go b/ecal/string/subscriber/string_subscriber.go index 526937f..9ac469f 100644 --- a/ecal/string/subscriber/string_subscriber.go +++ b/ecal/string/subscriber/string_subscriber.go @@ -21,10 +21,12 @@ func New(topic string) (*Subscriber, error) { Encoding: "base", }, ) - sub.Deserialize = deserialize if err != nil { err = fmt.Errorf("string Subscriber.New(): %w", err) } + + sub.Deserialize = deserialize + return &Subscriber{*sub}, err } diff --git a/ecal/subscriber/cgo_wrapping.go b/ecal/subscriber/cgo_wrapping.go index 06175bf..bdafb88 100644 --- a/ecal/subscriber/cgo_wrapping.go +++ b/ecal/subscriber/cgo_wrapping.go @@ -16,4 +16,5 @@ package subscriber // descriptor, descriptor_len // ); //} +//// C preamble. import "C" diff --git a/ecal/subscriber/subscriber.go b/ecal/subscriber/subscriber.go index 96bcfab..c06350e 100644 --- a/ecal/subscriber/subscriber.go +++ b/ecal/subscriber/subscriber.go @@ -70,6 +70,7 @@ func (p *Subscriber) Delete() { p.stopped = true close(p.Messages) } + if !bool(C.DestroySubscriber(C.uintptr_t(p.handle))) { // "Failed to delete subscriber" return @@ -78,7 +79,7 @@ func (p *Subscriber) Delete() { p.handle.Delete() } -// Receive a new message from the eCAL receive callback +// Receive a new message from the eCAL receive callback. func (p *Subscriber) Receive(timeout time.Duration) ([]byte, error) { select { case msg := <-p.Messages: @@ -88,7 +89,7 @@ func (p *Subscriber) Receive(timeout time.Duration) ([]byte, error) { } } -// Deserialize straight from the eCAL internal buffer to our Go []byte +// Deserialize straight from the eCAL internal buffer to our Go []byte. func deserializer(data unsafe.Pointer, dataLen int) any { return C.GoBytes(data, C.int(dataLen)) } diff --git a/ecal/types.cpp b/ecal/types.cpp index 57ac93a..56463c6 100644 --- a/ecal/types.cpp +++ b/ecal/types.cpp @@ -15,7 +15,7 @@ int safe_len(size_t str_len) { template CServiceCommon toServiceCommon(const T &t) { return { t.sname.c_str(), - t.sid.c_str(), + t.sid, nullptr, // Methods are filled in a separate pass t.methods.size(), t.hname.c_str(), @@ -43,7 +43,7 @@ CDatatype toCType(const eCAL::SDataTypeInformation &datatype) { CTopicId toCType(const eCAL::Registration::STopicId &id) { return { { - id.topic_id.entity_id.data(), + id.topic_id.entity_id, id.topic_id.host_name.data(), id.topic_id.process_id, {}, @@ -56,7 +56,7 @@ CTopicMon toCType(const eCAL::Monitoring::STopicMon &topic) { return { topic.uname.c_str(), topic.hname.c_str(), - topic.tid.c_str(), + topic.tid, topic.tname.c_str(), topic.direction.c_str(), toCType(topic.tdatatype), @@ -111,10 +111,8 @@ CServerMon toCType(const eCAL::Monitoring::SServerMon &server) { CMethodMon toCType(const eCAL::Monitoring::SMethodMon &method) { return { method.mname.c_str(), - method.req_type.c_str(), - method.req_desc.c_str(), - method.resp_type.c_str(), - method.resp_desc.c_str(), + toCType(method.req_datatype), + toCType(method.resp_datatype), method.call_count }; } diff --git a/ecal/types.go b/ecal/types.go index 35c3e07..8f565ab 100644 --- a/ecal/types.go +++ b/ecal/types.go @@ -1,7 +1,7 @@ package ecal type EntityID struct { - EntityID string + EntityID uint64 ProcessID int32 HostName string } diff --git a/ecal/types.h b/ecal/types.h index 7d3f466..c71ec86 100644 --- a/ecal/types.h +++ b/ecal/types.h @@ -11,10 +11,10 @@ extern "C" { #endif struct CEntityId { - const char *entity_id; + uint64_t entity_id; const char *host_name; int32_t process_id; - char _PADDING[4]; + char PADDING[4]; }; struct CTopicId { @@ -33,7 +33,7 @@ struct CDatatype { struct CTopicMon { const char *unit_name; const char *host_name; - const char *topic_id; + uint64_t topic_id; const char *topic_name; const char *direction; struct CDatatype datatype; @@ -64,16 +64,14 @@ struct CProcessMon { struct CMethodMon { const char *name; - const char *request_name; - const char *request_desc; - const char *response_name; - const char *response_desc; + struct CDatatype req_datatype; + struct CDatatype resp_datatype; int64_t call_count; }; struct CServiceCommon { const char *name; - const char *id; + uint64_t id; const struct CMethodMon *methods; size_t methods_len; const char *host_name;