lockserver 0.1.2

A distributed lock server for coordinating access to shared resources.
Documentation
# Lockserver

[![CI](https://github.com/benliao/lockserver/workflows/CI/badge.svg)](https://github.com/benliao/lockserver/actions)
[![Security](https://github.com/benliao/lockserver/workflows/Security/badge.svg)](https://github.com/benliao/lockserver/actions)
[![Crates.io](https://img.shields.io/crates/v/lockserver.svg)](https://crates.io/crates/lockserver)
[![Downloads](https://img.shields.io/crates/d/lockserver.svg)](https://crates.io/crates/lockserver)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Lockserver is a distributed lock server for coordinating access to shared resources across multiple workers or processes. It provides an HTTP API and a Rust client library with ergonomic macros for easy distributed locking.

## Features
- Simple API for acquiring and releasing locks
- HTTP API only (no TCP service)
- Client library with ergonomic macros (`lock_scope!`)
- Blocking and non-blocking lock acquisition
- Ready for publishing to crates.io

## Usage


### Start the server



## Security: Shared Secret Authorization

All client requests must include a shared secret for authorization. The server and client must agree on the same secret, set via the `LOCKSERVER_SECRET` environment variable or `.env` file. The client sends this secret in the `X-LOCKSERVER-SECRET` HTTP header.

**Example .env:**
```
LOCKSERVER_SECRET=your-strong-secret
```

**Server:**
```
LOCKSERVER_SECRET=your-strong-secret
cargo run --release
```

**Client:**
```
LOCKSERVER_SECRET=your-strong-secret
```

Or pass the secret directly to the client constructor.

You can configure the bind IP and HTTP port using CLI arguments, environment variables, or a `.env` file (using dotenvy):

**CLI arguments (override env/.env):**

```sh
cargo run --release -- --bind 127.0.0.1 --port 9000
# or short form:
cargo run --release -- -b 127.0.0.1 -p 9000
```

**Environment variables or .env file:**

```
LOCKSERVER_BIND_IP=127.0.0.1
LOCKSERVER_PORT=9000
```

Then just run:

```sh
cargo run --release
```



### HTTP API (default port 8080)

- Acquire a lock:
  `POST /acquire` with JSON `{ "resource": "myres", "owner": "worker1" }`
- Release a lock:
  `POST /release` with JSON `{ "resource": "myres", "owner": "worker1" }`

Example using `curl` (with secret):

```sh
curl -X POST -H "Content-Type: application/json" -H "X-LOCKSERVER-SECRET: your-strong-secret" \
  -d '{"resource":"myres","owner":"worker1"}' http://localhost:8080/acquire
curl -X POST -H "Content-Type: application/json" -H "X-LOCKSERVER-SECRET: your-strong-secret" \
  -d '{"resource":"myres","owner":"worker1"}' http://localhost:8080/release
```


### Rust Client Library & Macro

Add to your `Cargo.toml`:

```toml
[dependencies]
lockserver = "0.1"
```


#### Client configuration

The client can load the server address and owner from environment variables or a `.env` file:

```
LOCKSERVER_ADDR=127.0.0.1:8080
LOCKSERVER_OWNER=worker1
```

Or pass them directly:

```rust
use lockserver::{LockserverClient, lock_scope};


// Loads from env/.env if None (including secret)
let client = LockserverClient::new_with_env(None::<String>, None::<String>, None::<String>);
lock_scope!(&client, "resource", {
  // critical section
});

// Override address, owner, or secret:
let client = LockserverClient::new_with_env(
    Some("192.168.1.10:9000"),
    Some("myworker"),
    Some("your-strong-secret")
);

// Non-blocking mode:
if let Ok(()) = client.acquire_with_mode("resource", lockserver::LockMode::NonBlocking) {
  let _guard = lockserver::LockGuard::new(&client, "resource");
  // critical section
}
```

For more advanced usage, see the integration tests in `tests/lock_scope_macro.rs`.

## License

Licensed under the [MIT License](LICENSE).