# /vault/lock/{channel}

> Kind 8: a key locked; ok, sent when the lock is held, or an error, in exactly one message.

Canonical: https://provider.diverge.network/2.3.0/proxy/vault/lock/
Specification revision: 2.3.0

The ask is kind `8` on [`/requests`](/2.3.0/proxy/requests/):

```text
[8][ttl: u32, big-endian][key …]
```

The server answers on `/vault/lock/{channel}` by sending exactly one
message and closing the connection. A path that the proxy or the server closes cleanly with no message
before the close states that the ask was not served. An abrupt end of the
path leaves the operation failed, and the proxy does not ask it
again, as [Vault](/2.3.0/proxy/vault/) provides.

- **The answer is sent when the lock is held.** The server sends
  `0` when the container holds the lock, however long that takes. The
  TTL, in seconds, runs from the grant. A lock on a key the container
  already holds refreshes the TTL, and the server sends `0` at once.
  A lock whose TTL expires is released, and the server sends no
  message about the release. A TTL of `0` is refused, and the server
  sends `1` and a message.
- **The holder.** The container holds the lock, not a connection.
  The lock survives the ending of every path and of `/requests` until
  the container unlocks it or its TTL expires.

The ask is defined by `diverge-provider-sdk/src/shared/containers/vault/lock/request/request.rs`:

```rust
//! Hold a key's lock.

use std::convert::Infallible;

use super::super::super::RequestError;
use crate::encode::{Encode, Writer};

/// Hold a key's lock for a while, waiting for it. Answered `Ok` once
/// held — see [the module](super::super::super) for whose the lock is, how the TTL
/// is refreshed, and how it ends.
///
/// ```text
/// [ttl: u32 BE seconds][key: utf8…]
/// ```
///
/// The TTL leads so the key can be the rest. Answered with one
/// [`response::Frame`](super::super::response::Frame).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Request<'a> {
    /// The key.
    pub key: &'a str,
    /// How long the lock is held from the grant, in seconds, unless
    /// refreshed by another `Lock` or released by an
    /// [`unlock`](super::super::super::unlock). `0` is refused.
    pub ttl: u32,
}

/// The bytes the TTL occupies.
const TTL_LEN: usize = 4;

impl Encode for Request<'_> {
    /// [`Infallible`]: four known bytes and bytes copied.
    type Error = Infallible;

    fn encode(&self, out: &mut Writer<'_>) -> Result<(), Infallible> {
        out.extend_from_slice(&self.ttl.to_be_bytes());
        out.extend_from_slice(self.key.as_bytes());
        Ok(())
    }
}

impl<'a> Request<'a> {
    /// Decode from the bytes after the ask's kind. The key borrows
    /// from `bytes`.
    pub fn decode(bytes: &'a [u8]) -> Result<Self, RequestError> {
        let ttl: &[u8; TTL_LEN] = bytes
            .get(..TTL_LEN)
            .and_then(|head| head.try_into().ok())
            .ok_or(RequestError::Truncated)?;
        let key = std::str::from_utf8(&bytes[TTL_LEN..])
            .map_err(|_| RequestError::KeyUtf8)?;
        Ok(Request {
            key,
            ttl: u32::from_be_bytes(*ttl),
        })
    }
}
```

The answer is the frame defined on [Vault](/2.3.0/proxy/vault/): a first byte of `0` states that the operation was done; a first byte of `1` is followed by a message stating why it was not.
