diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..539a8dd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +on: + push: + tags: ["v*"] + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: write + +jobs: + semver-checks: + name: Semver Checks + # GATED alongside publish: cargo-semver-checks needs a published baseline on + # the registry to diff against, which doesn't exist until the first publish. + # Enable by setting SIMPLE_DOIP_PUBLISH_ENABLED=true once a baseline version + # has been published to crates.io. + if: vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: simple_doip + + publish: + name: Publish to crates.io + needs: semver-checks + # GATED: enable by setting repo variable SIMPLE_DOIP_PUBLISH_ENABLED=true + # once CARGO_REGISTRY_TOKEN exists in secrets and the team decides to cut a + # first version. Publishing goes to crates.io and needs only the token + + # crates.io reachability — not the Kellnr proxy (that fronts crates.io for + # dft-side consumption of the published crate, a separate concern). + if: github.event_name == 'push' && vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo install cargo-release --version '^0.25' --locked + # --allow-branch '*': a tag-push CI run is in detached-HEAD state, which + # cargo-release's branch check would otherwise reject. Publishing is + # already gated by the job `if:` above; this only relaxes the ref check. + - run: cargo release publish --workspace --allow-branch '*' --no-confirm --execute + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 0551c3d..45d0e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,12 @@ name = "simple_doip" version = "0.1.0" edition = "2024" +description = "DoIP (Diagnostics over IP, ISO 13400) protocol implementation" +license = "MIT OR Apache-2.0" +repository = "https://github.com/luminartech/simple_doip" +readme = "README.md" +keywords = ["doip", "iso13400", "diagnostics", "automotive", "uds"] +categories = ["network-programming"] [dependencies] async-trait = "0.1" diff --git a/release.toml b/release.toml new file mode 100644 index 0000000..11e8dab --- /dev/null +++ b/release.toml @@ -0,0 +1,9 @@ +# cargo-release config for the standalone simple_doip repo. +shared-version = false +publish = false # CI owns publishing +registry = "crates-io" # source of truth under Option B +tag-name = "v{{version}}" +tag-message = "simple_doip v{{version}}" +pre-release-commit-message = "chore(release): v{{version}}" +allow-branch = ["main"] +pre-release-hook = ["cargo", "test", "--workspace", "--locked"] diff --git a/src/client.rs b/src/client.rs index 355b969..4aa1b68 100644 --- a/src/client.rs +++ b/src/client.rs @@ -217,8 +217,7 @@ where pub async fn reconnect(&mut self) -> Result, Error> { let _ = Self::bind_socket(&self.control_sender, &self.client_options).await?; trace!("Reconnected, checking for in-flight messages over 5 seconds"); - let res = - tokio::time::timeout(Duration::from_millis(5000), self.update_receiver.recv()).await; + let res = tokio::time::timeout(Duration::from_secs(5), self.update_receiver.recv()).await; // Elapsed error handling, no response in flight let Ok(res) = res else { return Ok(None); diff --git a/src/client_inner.rs b/src/client_inner.rs index 159edf3..eba6996 100644 --- a/src/client_inner.rs +++ b/src/client_inner.rs @@ -35,13 +35,13 @@ pub(super) enum ControlMessage { oneshot::Sender>, ), - /// Send diagnostic message and wait for DoIP ACK only (not full response) + /// Send diagnostic message and wait for `DoIP` ACK only (not full response) SendDiagnosticMessage(Message, oneshot::Sender>), /// Wait for next diagnostic response (no send) ReceiveDiagnosticResponse(std::time::Duration, oneshot::Sender>), - /// Internal: waiting for ACK only (after SendDiagnosticMessage) + /// Internal: waiting for ACK only (after `SendDiagnosticMessage`) AwaitAck(oneshot::Sender>), } diff --git a/src/connection.rs b/src/connection.rs index 1fd1bf6..9b52b82 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -122,7 +122,7 @@ impl Connector for ConnectorSocket { /// Establishes a connection via a TCP listener socket. /// /// Instead of connecting to a remote server, this connector binds to the given -/// address and waits for an incoming connection. This is used for DoIPInt (VCC) +/// address and waits for an incoming connection. This is used for `DoIPInt` (VCC) /// where the sensor initiates the TCP connection to the tester. #[derive(Clone, Debug)] pub struct ListenerSocket; @@ -158,7 +158,7 @@ impl Connector for ListenerSocket { let tcp_listener = tcp_socket.listen(1)?; let local_addr = tcp_listener.local_addr()?; debug!("DoIPInt entity listening on {local_addr}"); - let result = tokio::time::timeout(Duration::from_secs(120), tcp_listener.accept()).await; + let result = tokio::time::timeout(Duration::from_mins(2), tcp_listener.accept()).await; // Drop the listener once connected so other processes can bind to the same port drop(tcp_listener); diff --git a/src/lib.rs b/src/lib.rs index ee718ed..4d3ad73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ pub const TCP_TIMEOUT_INITIAL_INACTIVITY: time::Duration = time::Duration::from_ /// General inactivity timeout for TCP connections. Timeout is 300 seconds (5 minutes). /// /// If no data is sent or received for this duration, the connection is closed by the `DoIP` entity -pub const TCP_TIMEOUT_GENERAL_INACTIVITY: time::Duration = time::Duration::from_secs(300); +pub const TCP_TIMEOUT_GENERAL_INACTIVITY: time::Duration = time::Duration::from_mins(5); /// Alive check for the maximum amount of time an entity waits for an alive check response after having /// made an alive check request. Timeout is 5 seconds.