From 0655b43c8ab8dac66711d390e35105cd1f029223 Mon Sep 17 00:00:00 2001 From: Francesco Noacco Date: Wed, 6 Dec 2023 16:01:35 +0100 Subject: [PATCH 1/2] ci: fix code generation in codegen-check the file was not updated when we moved from `make all` to `make install` for adding files in the libraries Signed-off-by: Francesco Noacco --- .github/workflows/codegen-check.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codegen-check.yaml b/.github/workflows/codegen-check.yaml index 73c062a..405d1c1 100644 --- a/.github/workflows/codegen-check.yaml +++ b/.github/workflows/codegen-check.yaml @@ -27,6 +27,6 @@ jobs: - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable - name: Generate code - run: make all + run: make install --always-make - name: Check diff in generated code run: ./scripts/check_diff.sh From 4aadd378a1bc640d9ee061903f0ff506e860a280 Mon Sep 17 00:00:00 2001 From: Francesco Noacco Date: Thu, 12 Oct 2023 17:29:29 +0200 Subject: [PATCH 2/2] feat(elixir): init elixir project Signed-off-by: Francesco Noacco --- .github/workflows/ci.yaml | 3 + .github/workflows/codegen-check.yaml | 8 +++ .github/workflows/elixir-check.yaml | 36 ++++++++++ .reuse/dep5 | 4 ++ Makefile | 39 +++++++++- .../.formatter.exs | 7 ++ .../edgehog_device_forwarder_proto/.gitignore | 29 ++++++++ .../edgehog_device_forwarder_proto/README.md | 25 +++++++ .../lib/edgehog_device_forwarder_proto.ex | 5 ++ .../edgehog/device/forwarder/http.pb.ex | 72 +++++++++++++++++++ .../edgehog/device/forwarder/message.pb.ex | 10 +++ .../edgehog/device/forwarder/ws.pb.ex | 27 +++++++ elixir/edgehog_device_forwarder_proto/mix.exs | 28 ++++++++ .../edgehog_device_forwarder_proto/mix.lock | 3 + .../mix.lock.license | 2 + .../edgehog_device_forwarder_proto_test.exs | 22 ++++++ .../test/test_helper.exs | 4 ++ scripts/elixir_deps_check.sh | 15 ++++ 18 files changed, 336 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/elixir-check.yaml create mode 100644 elixir/edgehog_device_forwarder_proto/.formatter.exs create mode 100644 elixir/edgehog_device_forwarder_proto/.gitignore create mode 100644 elixir/edgehog_device_forwarder_proto/README.md create mode 100644 elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto.ex create mode 100644 elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/http.pb.ex create mode 100644 elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/message.pb.ex create mode 100644 elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/ws.pb.ex create mode 100644 elixir/edgehog_device_forwarder_proto/mix.exs create mode 100644 elixir/edgehog_device_forwarder_proto/mix.lock create mode 100644 elixir/edgehog_device_forwarder_proto/mix.lock.license create mode 100644 elixir/edgehog_device_forwarder_proto/test/edgehog_device_forwarder_proto_test.exs create mode 100644 elixir/edgehog_device_forwarder_proto/test/test_helper.exs create mode 100644 scripts/elixir_deps_check.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bcfc6b7..6a7117b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,3 +24,6 @@ jobs: rust-check: needs: [codegen-check] uses: ./.github/workflows/rust-check.yaml + elixir-check: + needs: [codegen-check] + uses: ./.github/workflows/elixir-check.yaml diff --git a/.github/workflows/codegen-check.yaml b/.github/workflows/codegen-check.yaml index 405d1c1..997d833 100644 --- a/.github/workflows/codegen-check.yaml +++ b/.github/workflows/codegen-check.yaml @@ -26,6 +26,14 @@ jobs: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: erlef/setup-beam@v1 + with: + otp-version: '26' + elixir-version: '1.15.7' + - name: Install elixir protobuf compiler + run: | + mix escript.install hex protobuf --force + echo "$HOME/.mix/escripts" >> "$GITHUB_PATH" - name: Generate code run: make install --always-make - name: Check diff in generated code diff --git a/.github/workflows/elixir-check.yaml b/.github/workflows/elixir-check.yaml new file mode 100644 index 0000000..1c520c2 --- /dev/null +++ b/.github/workflows/elixir-check.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +permissions: + contents: read +on: + workflow_call: + +defaults: + run: + working-directory: elixir/edgehog_device_forwarder_proto +jobs: + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: '26' + elixir-version: '1.15.7' + - name: Fetch dependencies + run: mix do deps.get --only test, deps.compile + - name: Check formatting + run: mix format --check-formatted + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: '26' + elixir-version: '1.15.7' + - name: Fetch dependencies + run: mix do deps.get --only test, deps.compile + - name: Run tests + run: mix test diff --git a/.reuse/dep5 b/.reuse/dep5 index 3d531b6..d692299 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -5,3 +5,7 @@ Source: https://github.com/edgehog-device-manager/edgehog-device-forwarder-proto Files: out/* rust/Cargo.lock rust/edgehog-device-forwarder-proto/src/proto.rs Copyright: 2023 SECO Mind Srl License: Apache-2.0 + +Files: elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/**/*.ex +Copyright: 2023 SECO Mind Srl +License: Apache-2.0 diff --git a/Makefile b/Makefile index a49c7c6..ff30c06 100644 --- a/Makefile +++ b/Makefile @@ -27,27 +27,36 @@ CANONICAL_CURDIR = $(realpath $(CURDIR)) PROTO_DIR = $(CANONICAL_CURDIR)/proto RUST_LANG_DIR = $(CANONICAL_CURDIR)/rust +ELIXIR_LANG_DIR = $(CANONICAL_CURDIR)/elixir +ELIXIR_LANG_LIB=$(ELIXIR_LANG_DIR)/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto BASE_DIR := $(CANONICAL_O) $(if $(BASE_DIR),, $(error output directory "$(O)" does not exist)) BUILD_DIR := $(BASE_DIR)/build RUST_BUILD_DIR := $(BUILD_DIR)/rust +ELIXIR_BUILD_DIR := $(BUILD_DIR)/elixir -FILES=$(wildcard proto/edgehog/device/forwarder/*.proto) +FILES=$(wildcard $(PROTO_DIR)/edgehog/device/forwarder/*.proto) PROTOC_CHECK_SCRIPT=$(CANONICAL_CURDIR)/scripts/protoc_check.sh +ELIXIR_DEPS_CHECK_SCRIPT=$(CANONICAL_CURDIR)/scripts/elixir_deps_check.sh RUST_LANG=$(RUST_BUILD_DIR)/proto.rs RUST_FILES=$(shell find "$(RUST_LANG_DIR)/rust-codegen" -type f -regex '.*(rs|Cargo.toml|Cargo.lock)$$') \ $(RUST_LANG_DIR)/Cargo.toml $(RUST_LANG_DIR)/Cargo.lock +ELIXIR_LANG=$(ELIXIR_BUILD_DIR)/edgehog/device/forwarder/http.pb.ex \ + $(ELIXIR_BUILD_DIR)/edgehog/device/forwarder/ws.pb.ex \ + $(ELIXIR_BUILD_DIR)/edgehog/device/forwarder/message.pb.ex +ELIXIR_FILES="$(ELIXIR_LANG_LIB)/edgehog/device/forwarder/"{http,ws,message}.pb.ex + # This is our default rule, so must come first .PHONY: all -all: rust +all: rust elixir .PHONY: install -install: rust-install +install: rust-install elixir-install .PHONY: clean clean: @@ -71,6 +80,30 @@ rust-install: rust rust-dirclean: rm -rf $(RUST_BUILD_DIR) +$(ELIXIR_LANG) &: $(FILES) + mkdir -p $(ELIXIR_BUILD_DIR) + protoc \ + --elixir_out=$(ELIXIR_BUILD_DIR) \ + --elixir_opt=package_prefix=EdgehogDeviceForwarderProto \ + --proto_path=$(PROTO_DIR) \ + $(FILES) + mix format $(ELIXIR_LANG) + +elixir-dependencies-check: $(ELIXIR_DEPS_CHECK_SCRIPT) + $(SHELL) $(ELIXIR_DEPS_CHECK_SCRIPT) + +.PHONY: elixir +elixir: protoc-check elixir-dependencies-check $(ELIXIR_LANG) + +.PHONY: elixir-install +elixir-install: elixir + mkdir -p "$(ELIXIR_LANG_LIB)/edgehog/device/forwarder/" + install -m 644 $(ELIXIR_LANG) "$(ELIXIR_LANG_LIB)/edgehog/device/forwarder/" + +.PHONY: elixir-dirclean +elixir-dirclean: + rm -rf $(ELIXIR_BUILD_DIR) + .PHONY: help help: @echo 'Cleaning:' diff --git a/elixir/edgehog_device_forwarder_proto/.formatter.exs b/elixir/edgehog_device_forwarder_proto/.formatter.exs new file mode 100644 index 0000000..cc8bc0c --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/.formatter.exs @@ -0,0 +1,7 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], + import_deps: [:protobuf] +] diff --git a/elixir/edgehog_device_forwarder_proto/.gitignore b/elixir/edgehog_device_forwarder_proto/.gitignore new file mode 100644 index 0000000..0a31c0f --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/.gitignore @@ -0,0 +1,29 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +edgehog_device_forwarder_proto-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/elixir/edgehog_device_forwarder_proto/README.md b/elixir/edgehog_device_forwarder_proto/README.md new file mode 100644 index 0000000..314a34f --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/README.md @@ -0,0 +1,25 @@ + + +# EdgehogDeviceForwarderProto + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `edgehog_device_forwarder_proto` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:edgehog_device_forwarder_proto, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at . diff --git a/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto.ex b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto.ex new file mode 100644 index 0000000..db42552 --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto.ex @@ -0,0 +1,5 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +defmodule EdgehogDeviceForwarderProto do +end diff --git a/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/http.pb.ex b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/http.pb.ex new file mode 100644 index 0000000..194314b --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/http.pb.ex @@ -0,0 +1,72 @@ +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Request.HeadersEntry do + @moduledoc false + + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:key, 1, type: :string) + field(:value, 2, type: :string) +end + +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Request do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:path, 1, type: :string) + field(:method, 2, type: :string) + field(:query_string, 3, type: :string, json_name: "queryString") + + field(:headers, 4, + repeated: true, + type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Request.HeadersEntry, + map: true + ) + + field(:body, 5, type: :bytes) + field(:port, 6, type: :uint32) +end + +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Response.HeadersEntry do + @moduledoc false + + use Protobuf, map: true, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:key, 1, type: :string) + field(:value, 2, type: :string) +end + +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Response do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:status_code, 1, type: :uint32, json_name: "statusCode") + + field(:headers, 2, + repeated: true, + type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Response.HeadersEntry, + map: true + ) + + field(:body, 3, type: :bytes) +end + +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof(:message, 0) + + field(:request_id, 1, type: :bytes, json_name: "requestId") + + field(:request, 2, + type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Request, + oneof: 0 + ) + + field(:response, 3, + type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http.Response, + oneof: 0 + ) +end diff --git a/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/message.pb.ex b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/message.pb.ex new file mode 100644 index 0000000..679433c --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/message.pb.ex @@ -0,0 +1,10 @@ +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Message do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof(:protocol, 0) + + field(:http, 1, type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.Http, oneof: 0) + field(:ws, 2, type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.WebSocket, oneof: 0) +end diff --git a/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/ws.pb.ex b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/ws.pb.ex new file mode 100644 index 0000000..cf4793f --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/lib/edgehog_device_forwarder_proto/edgehog/device/forwarder/ws.pb.ex @@ -0,0 +1,27 @@ +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.WebSocket.Close do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + field(:code, 1, type: :uint32) + field(:reason, 2, type: :string) +end + +defmodule EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.WebSocket do + @moduledoc false + + use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0" + + oneof(:message, 0) + + field(:socket_id, 1, type: :bytes, json_name: "socketId") + field(:text, 2, type: :string, oneof: 0) + field(:binary, 3, type: :bytes, oneof: 0) + field(:ping, 4, type: :bytes, oneof: 0) + field(:pong, 5, type: :bytes, oneof: 0) + + field(:close, 6, + type: EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.WebSocket.Close, + oneof: 0 + ) +end diff --git a/elixir/edgehog_device_forwarder_proto/mix.exs b/elixir/edgehog_device_forwarder_proto/mix.exs new file mode 100644 index 0000000..274b7f6 --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/mix.exs @@ -0,0 +1,28 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +defmodule EdgehogDeviceForwarderProto.MixProject do + use Mix.Project + + def project do + [ + app: :edgehog_device_forwarder_proto, + version: "0.0.1", + elixir: "~> 1.15", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [ + extra_applications: [:logger] + ] + end + + defp deps do + [ + {:protobuf, "~> 0.12"} + ] + end +end diff --git a/elixir/edgehog_device_forwarder_proto/mix.lock b/elixir/edgehog_device_forwarder_proto/mix.lock new file mode 100644 index 0000000..50d4595 --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/mix.lock @@ -0,0 +1,3 @@ +%{ + "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, +} diff --git a/elixir/edgehog_device_forwarder_proto/mix.lock.license b/elixir/edgehog_device_forwarder_proto/mix.lock.license new file mode 100644 index 0000000..e9e3811 --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/mix.lock.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2023 SECO Mind Srl +SPDX-License-Identifier: Apache-2.0 diff --git a/elixir/edgehog_device_forwarder_proto/test/edgehog_device_forwarder_proto_test.exs b/elixir/edgehog_device_forwarder_proto/test/edgehog_device_forwarder_proto_test.exs new file mode 100644 index 0000000..c3aea6d --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/test/edgehog_device_forwarder_proto_test.exs @@ -0,0 +1,22 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +defmodule EdgehogDeviceForwarderProtoTest do + use ExUnit.Case + alias EdgehogDeviceForwarderProto.Edgehog.Device.Forwarder.{Message, Http, WebSocket} + doctest EdgehogDeviceForwarderProto + + test "encode and decode test" do + ws = %WebSocket{socket_id: <<>>, message: {:text, "some string"}} + assert ws == ws |> WebSocket.encode() |> WebSocket.decode() + + http_response = %Http.Response{status_code: 200, headers: %{}, body: <<>>} + http = %Http{request_id: <<>>, message: {:response, http_response}} + + assert http == http |> Http.encode() |> Http.decode() + + message = %Message{protocol: {:ws, ws}} + assert message == message |> Message.encode() |> Message.decode() + assert {:ws, ^ws} = message |> Message.encode() |> Message.decode() |> Map.get(:protocol) + end +end diff --git a/elixir/edgehog_device_forwarder_proto/test/test_helper.exs b/elixir/edgehog_device_forwarder_proto/test/test_helper.exs new file mode 100644 index 0000000..d0f7637 --- /dev/null +++ b/elixir/edgehog_device_forwarder_proto/test/test_helper.exs @@ -0,0 +1,4 @@ +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +ExUnit.start() diff --git a/scripts/elixir_deps_check.sh b/scripts/elixir_deps_check.sh new file mode 100644 index 0000000..15bcd02 --- /dev/null +++ b/scripts/elixir_deps_check.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# Copyright 2023 SECO Mind Srl +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +PROTOC_GEN_ELIXIR_VERSION="0.12.0" +version=$(protoc-gen-elixir --version) + +if [ "$version" != "$PROTOC_GEN_ELIXIR_VERSION" ]; then + echo "incompatible elixir-protobuf version: found \"$version\", \ +expected \"$PROTOC_GEN_ELIXIR_VERSION\"" >&2 + exit 1 +fi