From 227477d17f87d70101093597756012d0d8bf06dd Mon Sep 17 00:00:00 2001 From: maze Date: Mon, 23 Feb 2026 21:15:48 +0100 Subject: [PATCH] Re-added hamview-receiver --- .gitea/workflows/build.yaml | 85 +++++++++++++++++----------- .gitignore | 23 ++++++++ LICENSE | 18 ++++++ README.md | 3 + cmd/hamview-receiver/Dockerfile | 12 ++++ cmd/hamview-receiver/entrypoint.sh | 17 ++++++ cmd/hamview-receiver/main.go | 49 ++++++++++++++++ cmd/hamview-receiver/run_aprsis.go | 77 +++++++++++++++++++++++++ cmd/hamview-receiver/run_meshcore.go | 79 ++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- 11 files changed, 333 insertions(+), 36 deletions(-) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cmd/hamview-receiver/Dockerfile create mode 100755 cmd/hamview-receiver/entrypoint.sh create mode 100644 cmd/hamview-receiver/main.go create mode 100644 cmd/hamview-receiver/run_aprsis.go create mode 100644 cmd/hamview-receiver/run_meshcore.go diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index 8696bb7..c9a58c6 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -24,22 +24,29 @@ jobs: name: Build collector runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - name: Checkout + uses: actions/checkout@v6 + - name: Setup Go + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' check-latest: false - name: Download modules run: go mod download - name: Make build directory - run: mkdir -p build && readlink -f build + run: mkdir -p build - name: Build - run: go build -o build/hamview-collector ./cmd/hamview-collector && ls -al $(readlink -f build/hamview-collector) - - name: Debug env - run: env + run: | + go build -o build/hamview-collector ./cmd/hamview-collector && \ + ls -al $(readlink -f build/hamview-collector) - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log into Container Registry + - name: Log into Docker Container Registry + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Log into Gitea Container Registry uses: docker/login-action@v3 with: registry: ${{ vars.REGISTRY }} @@ -49,7 +56,7 @@ jobs: uses: docker/build-push-action@v6 with: push: true - tags: ham/hamview:collector + tags: ${{ vars.REGISTRY }}/ham/hamview/collector:dev file: ./cmd/hamview-collector/Dockerfile context: . platforms: | @@ -58,40 +65,52 @@ jobs: build_receiver: name: Build receiver runs-on: ubuntu-latest - strategy: - matrix: - include: - - goos: linux - goarch: amd64 - goarm: "" - - goos: linux - goarch: arm - goarm: "6" - - goos: linux - goarch: arm - goarm: "7" steps: - - uses: actions/checkout@v6 - - uses: actions/setup-go@v6 + - name: Checkout + uses: actions/checkout@v6 + - name: Setup Go + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' check-latest: false - - name: Set target variables - run: | - echo "GOOS=${{ matrix.goos }}" >> $GITHUB_ENV - echo "GOARCH=${{ matrix.goarch }}" >> $GITHUB_ENV - if [ -n "${{ matrix.goarm }}" ]; then - echo "GOARM=${{ matrix.goarm }}" >> $GITHUB_ENV - fi - name: Download modules run: go mod download - name: Make build directory run: mkdir -p build && readlink -f build - - name: Build - run: go build -o build/hamview-receiver.${{ matrix.goarch }}${{ matrix.goarm }} ./cmd/hamview-receiver && readlink -f build/hamview-receiver.${{ matrix.goarch }}${{ matrix.goarm }} + - name: Build amd64 + env: + GOOS: linux + GOARCH: amd64 + run: | + GOOS=$GOOS GOARCH=$GOARCH \ + go build -o build/hamview-receiver-$GOARCH cmd/hamview-receiver && \ + readlink -f build/hamview-receiver-$GOARCH + - name: Build arm6 + env: + GOOS: linux + GOARCH: arm + GOARM: 6 + run: | + GOOS=$GOOS GOARCH=$GOARCH GOARM=$GOARM \ + go build -o build/hamview-receiver-$GOARCH$GOARM cmd/hamview-receiver && \ + readlink -f build/hamview-receiver-$GOARCH$GOARM + - name: Build arm7 + env: + GOOS: linux + GOARCH: arm + GOARM: 7 + run: | + GOOS=$GOOS GOARCH=$GOARCH GOARM=$GOARM \ + go build -o build/hamview-receiver-$GOARCH$GOARM cmd/hamview-receiver && \ + readlink -f build/hamview-receiver-$GOARCH$GOARM - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log into Container Registry + - name: Log into Docker Container Registry + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKER_USER }} + password: ${{ secrets.DOCKER_TOKEN }} + - name: Log into Gitea Container Registry uses: docker/login-action@v3 with: registry: ${{ vars.REGISTRY }} @@ -101,7 +120,7 @@ jobs: uses: docker/build-push-action@v6 with: push: true - tags: ham/hamview:receiver + tags: ${{ vars.REGISTRY }}/ham/hamview/receiver:dev file: ./cmd/hamview-receiver/Dockerfile context: . platforms: | diff --git a/.gitignore b/.gitignore index f703715..c343446 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,26 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + # Build artifacts build/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a34bf1e --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +MIT License + +Copyright (c) 2026 ham + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d369001 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# hamview + +HAMView radio receiver diff --git a/cmd/hamview-receiver/Dockerfile b/cmd/hamview-receiver/Dockerfile new file mode 100644 index 0000000..aa1412a --- /dev/null +++ b/cmd/hamview-receiver/Dockerfile @@ -0,0 +1,12 @@ +FROM alpine:3 +RUN apk add --no-cache dumb-init=1.2.5-r3 + +WORKDIR /app + +ARG TARGETARCH +ARG TARGETVARIANT +COPY ./etc /app/config +COPY ./build/hamview-receiver-${TARGETARCH}${TARGETVARIANT#v} /app/hamview-receiver +COPY ./entrypoint.sh /entrypoint.sh + +ENTRYPOINT ["dumb-init", "/entrypoint.sh"] diff --git a/cmd/hamview-receiver/entrypoint.sh b/cmd/hamview-receiver/entrypoint.sh new file mode 100755 index 0000000..0d7df45 --- /dev/null +++ b/cmd/hamview-receiver/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +run() { + case "${PROTOCOL}" in + "") exec "/app/hamview-receiver" help ;; + *) exec "/app/hamview-receiver" --config "/app/config/hamview-${PROTOCOL}.yaml" "${PROTOCOL}" ;; + esac +} + +case "$@" in + "") + run + ;; + *) + exec "/bin/sh" -c "$@" + ;; +esac diff --git a/cmd/hamview-receiver/main.go b/cmd/hamview-receiver/main.go new file mode 100644 index 0000000..ed290e3 --- /dev/null +++ b/cmd/hamview-receiver/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v3" + + "git.maze.io/ham/hamview/cmd" +) + +var logger *logrus.Logger + +func main() { + cmd := &cli.Command{ + Name: "hamview-receiver", + Usage: "Receiver for HAM radio protocols", + Action: func(context.Context, *cli.Command) error { + fmt.Println("boom! I say!") + return nil + }, + Flags: cmd.AllFlags("hamview-receiver.yaml"), + Commands: []*cli.Command{ + { + Name: "aprsis", + Usage: "Start an APRS-IS proxy", + Before: cmd.ConfigureLogging(&logger), + Action: runAPRSIS, + }, + { + Name: "meshcore", + Usage: "Start a MeshCore receiver", + Before: cmd.ConfigureLogging(&logger), + Action: runMeshCore, + }, + }, + } + + if err := cmd.Run(context.Background(), os.Args); err != nil { + log.Fatal(err) + } +} + +func waitForInterrupt() error { + return cmd.WaitForInterrupt(logger, "receiver") +} diff --git a/cmd/hamview-receiver/run_aprsis.go b/cmd/hamview-receiver/run_aprsis.go new file mode 100644 index 0000000..db172c8 --- /dev/null +++ b/cmd/hamview-receiver/run_aprsis.go @@ -0,0 +1,77 @@ +package main + +import ( + "context" + + "github.com/urfave/cli/v3" + + "git.maze.io/go/ham/protocol/aprs/aprsis" + + "git.maze.io/ham/hamview" + "git.maze.io/ham/hamview/cmd" +) + +type aprsisConfig struct { + Broker hamview.BrokerConfig `yaml:"broker"` + Receiver hamview.APRSISConfig `yaml:"receiver"` + Include []string `yaml:"include"` +} + +func (config *aprsisConfig) Includes() []string { + includes := config.Include + config.Include = nil + return includes +} + +func runAPRSIS(ctx context.Context, command *cli.Command) error { + var config = aprsisConfig{ + Receiver: hamview.APRSISConfig{ + Listen: hamview.DefaultAPRSISListen, + Server: hamview.DefaultAPRSISServer, + }, + } + if err := cmd.Load(logger, command.String(cmd.FlagConfig), &config); err != nil { + return err + } + + logger.Infof("receiver: starting APRS-IS proxy on tcp://%s to tcp://%s", + config.Receiver.Listen, + config.Receiver.Server) + proxy, err := aprsis.NewProxy(config.Receiver.Listen, config.Receiver.Server) + if err != nil { + return err + } + + proxy.OnClient = func(callsign string, client *aprsis.ProxyClient) { + go receiveAPRSIS(&config.Broker, callsign, client) + } + + return waitForInterrupt() +} + +func receiveAPRSIS(config *hamview.BrokerConfig, callsign string, client *aprsis.ProxyClient) { + defer func() { _ = client.Close() }() + + broker, err := hamview.NewBroker(config) + if err != nil { + logger.Errorf("receiver: can't setup to broker: %v", err) + return + } + defer func() { _ = broker.Close() }() + + info := client.Info() // TODO: enrich info from config? + + if err = broker.StartRadio("aprs", info); err != nil { + logger.Fatalf("receiver: can't start broker: %v", err) + return + } + + logger.Infof("receiver: start receiving packets from station: %s", callsign) + for packet := range client.RawPackets() { + logger.Debugf("aprs packet: %#+v", packet) + if err := broker.PublishPacket("aprs/packet", packet); err != nil { + logger.Error(err) + } + } + logger.Infof("receiver: stopped receiving packets from station: %s", callsign) +} diff --git a/cmd/hamview-receiver/run_meshcore.go b/cmd/hamview-receiver/run_meshcore.go new file mode 100644 index 0000000..f64f5ca --- /dev/null +++ b/cmd/hamview-receiver/run_meshcore.go @@ -0,0 +1,79 @@ +package main + +import ( + "context" + + "github.com/urfave/cli/v3" + + "git.maze.io/go/ham/protocol" + "git.maze.io/go/ham/protocol/meshcore" + + "git.maze.io/ham/hamview" + "git.maze.io/ham/hamview/cmd" +) + +type meshCoreConfig struct { + Broker hamview.BrokerConfig `yaml:"broker"` + Receiver hamview.MeshCoreConfig `yaml:"receiver"` + Include []string `yaml:"include"` +} + +func (config *meshCoreConfig) Includes() []string { + includes := config.Include + config.Include = nil + return includes +} + +func runMeshCore(ctx context.Context, command *cli.Command) error { + var config meshCoreConfig + if err := cmd.Load(logger, command.String(cmd.FlagConfig), &config); err != nil { + return err + } + + broker, err := hamview.NewBroker(&config.Broker) + if err != nil { + return err + } + defer func() { _ = broker.Close() }() + + receiver, err := hamview.NewMeshCoreReceiver(&config.Receiver) + if err != nil { + return err + } + defer func() { _ = receiver.Close() }() + + info := receiver.Info() // TODO: enrich info from config? + if err = broker.StartRadio(protocol.MeshCore, info); err != nil { + logger.Fatalf("receiver: can't start broker: %v", err) + return err + } + + // Trace scheduler + //go receiver.RunTraces() + + // Packet decoder + go func() { + logger.Info("receiver: start receiving packets") + for packet := range receiver.RawPackets() { + if len(packet.Raw) >= 1 { + var ( + header = packet.Raw[0] + version = (header >> 6) & 0x03 + routeType = meshcore.RouteType(header & 0x03) + payloadType = meshcore.PayloadType((header >> 2) & 0x0F) + ) + logger.Debugf("meshcore packet: %d %s %s: %d bytes", + version, + routeType, + payloadType, + len(packet.Raw)) + } + if err = broker.PublishPacket("meshcore/packet", packet); err != nil { + logger.Errorf("receiver: failed to publish packet: %v", err) + } + } + logger.Warn("receiver: closing") + }() + + return waitForInterrupt() +} diff --git a/go.mod b/go.mod index 6ecaed5..b3eac61 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.maze.io/ham/hamview go 1.25.6 require ( - git.maze.io/go/ham v0.1.0 + git.maze.io/go/ham v0.1.1-0.20260223201507-65f3fe39a98b github.com/Vaniog/go-postgis v0.0.0-20240619200434-9c2eb8ed621e github.com/cemkiy/echo-logrus v0.0.0-20200218141616-06f9cd1dae34 github.com/cridenour/go-postgis v1.0.1 diff --git a/go.sum b/go.sum index f58aafd..3123d60 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -git.maze.io/go/ham v0.0.0-20260222201625-824bde5d5525 h1:No1WgUBujHY8tSMfIFuvcAJ5qe9RK6o2WgmZROp5+JM= -git.maze.io/go/ham v0.0.0-20260222201625-824bde5d5525/go.mod h1:+WuiawzNBqlWgklVoodUAJc0cV+NDW6RR8Tn+AW8hsU= git.maze.io/go/ham v0.1.0 h1:ytqqkGux4E6h3QbCB3zJy/Ngc+fEqodyMpepbp9o/ts= git.maze.io/go/ham v0.1.0/go.mod h1:+WuiawzNBqlWgklVoodUAJc0cV+NDW6RR8Tn+AW8hsU= +git.maze.io/go/ham v0.1.1-0.20260223201507-65f3fe39a98b h1:Wzt2uXbqW9h/159KeXY95CrDoLN0m3HCxPC6jPLO6ws= +git.maze.io/go/ham v0.1.1-0.20260223201507-65f3fe39a98b/go.mod h1:+WuiawzNBqlWgklVoodUAJc0cV+NDW6RR8Tn+AW8hsU= github.com/Vaniog/go-postgis v0.0.0-20240619200434-9c2eb8ed621e h1:Ck+0lNRr62RM/LNKkkD0R1aJ2DvgELqmmuNvyyHL75E= github.com/Vaniog/go-postgis v0.0.0-20240619200434-9c2eb8ed621e/go.mod h1:o3MIxN5drWoGBTtBGtLqFZlr7RjfdQKnfwYXoUU77vU= github.com/cemkiy/echo-logrus v0.0.0-20200218141616-06f9cd1dae34 h1:cGxEwqDl+PiqPtJpQNoiJIXcrVEkkSMuMQtb+PPAHL4=