Page MenuHomePhabricator

No OneTemporary

diff --git a/RANGE_API_SUMMARY.md b/RANGE_API_SUMMARY.md
deleted file mode 100644
index 05a0e22..0000000
--- a/RANGE_API_SUMMARY.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Range API Implementation Summary
-
-## Overview
-
-A complete REST API has been implemented for the Range functionality in the Collar project. The Range API provides endpoints for managing fixed-size ranges with automatic position assignment, useful for allocating unique identifiers, session tokens, or any bounded resource allocation scenario.
-
-## Implementation Details
-
-### API Endpoints Added
-
-The following 6 endpoints were added to `collar/crates/api/src/lib.rs`:
-
-1. **POST** `/store/range/{name}/{size}` - Define a new range
-2. **POST** `/store/range/{name}/assign/{value}` - Assign value to next available position
-3. **GET** `/store/range/{name}/{position}` - Get value at specific position
-4. **GET** `/store/range/{name}` - List all assignments in a range
-5. **GET** `/store/ranges` - List all defined ranges
-6. **POST** `/store/range/{name}/unassign/{value}` - Remove value and free its position
-
-### Handler Functions
-
-Each endpoint is implemented with a corresponding async handler function:
-
-- `post_range_define` - Creates ranges with specified size
-- `post_range_assign` - Assigns values to next free position
-- `get_range_position` - Retrieves values by position
-- `get_range_list` - Lists all assignments in a range
-- `get_ranges_list` - Lists all available ranges
-- `post_range_unassign` - Removes assignments and frees positions
-
-### Integration
-
-The API integrates seamlessly with the existing collar infrastructure:
-
-- Uses the same `AppState` pattern as existing namespace endpoints
-- Accesses `RangeStore` via `state.collar.store.ranges()`
-- Follows consistent error handling patterns
-- Returns descriptive success/error messages
-
-### Key Features
-
-- **Automatic Position Assignment**: Values are assigned to the lowest available position
-- **Position Reuse**: Unassigned positions become available for new assignments
-- **Range Validation**: Prevents operations on undefined ranges or out-of-bounds positions
-- **Value Uniqueness**: Each value can only be assigned once per range
-- **Atomic Operations**: All operations are transactionally safe
-
-### Documentation
-
-Complete API documentation with examples has been provided in `collar/docs/range_api.md`, including:
-
-- Endpoint specifications with parameters
-- Usage examples with curl commands
-- Complete workflow demonstration
-- Error scenarios and responses
-
-### Testing
-
-A test script `test_range_api.sh` has been created to verify all API functionality with a complete workflow test.
-
-## Benefits
-
-This implementation provides:
-
-- RESTful interface to range functionality
-- Consistent API design with existing endpoints
-- Comprehensive error handling and user feedback
-- Production-ready code with proper validation
-- Complete documentation and testing support
-
-The Range API is now ready for integration and use in collar applications requiring bounded resource allocation with automatic position management.
\ No newline at end of file
diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs
index 9027b90..a15ccca 100644
--- a/crates/api/src/lib.rs
+++ b/crates/api/src/lib.rs
@@ -1,142 +1,142 @@
use std::sync::Arc;
use axum::{
routing::get,
extract::{State, Path},
routing::post,
};
pub use axum::serve;
struct AppState {
collar: libcollar::State,
}
pub fn app(collar: libcollar::State) -> axum::Router {
let state = Arc::new(AppState { collar });
// build our application with a single route
let app = axum::Router::new()
.route("/", get(|| async { "collared." }))
.route("/ng/eiface/{name}", post(post_ng_eiface))
.route("/store/namespace/{name}", post(post_ns))
.route("/store/namespace/{name}/{key}/{value}", post(post_ns_key))
.route("/store/namespace/{name}/{key}", get(get_ns_key))
- .route("/store/range/{name}/{size}", post(post_range_define))
+ .route("/store/range/new/{name}/{size}", post(post_range_define))
.route("/store/range/{name}/assign/{value}", post(post_range_assign))
+ .route("/store/range/{name}/unassign/{value}", post(post_range_unassign))
.route("/store/range/{name}/{position}", get(get_range_position))
.route("/store/range/{name}", get(get_range_list))
.route("/store/ranges", get(get_ranges_list))
- .route("/store/range/{name}/unassign/{value}", post(post_range_unassign))
.with_state(state)
.layer(tower_http::trace::TraceLayer::new_for_http());
app
}
async fn post_ns(State(state): State<Arc<AppState>>, Path(name): Path<String>) -> Result<String, String> {
let ns = state.collar.store.namespaces();
// First, ensure the namespace exists
if let Err(e) = ns.define(&name) {
return Err(format!("Failed to define namespace '{}': {:?}", name, e));
}
Ok("ok".to_string())
}
async fn post_ns_key(State(state): State<Arc<AppState>>, Path((name, key, value)): Path<(String, String, String)>) -> Result<String, String> {
let ns = state.collar.store.namespaces();
// Try to reserve the key-value pair
match ns.reserve(&name, &key, &value) {
Ok(_) => Ok(format!("Reserved key '{}' with value '{}' in namespace '{}'", key, value, name)),
Err(e) => Err(format!("Failed to reserve key '{}' in namespace '{}': {:?}", key, name, e)),
}
}
async fn get_ns_key(State(state): State<Arc<AppState>>, Path((name, key)): Path<(String, String)>) -> Result<String, String> {
let ns = state.collar.store.namespaces();
match ns.get(&name, &key) {
Ok(Some(value)) => Ok(value),
Ok(None) => Err(format!("Key '{}' not found in namespace '{}'", key, name)),
Err(e) => Err(format!("Failed to get key '{}' from namespace '{}': {:?}", key, name, e)),
}
}
async fn post_ng_eiface(State(state): State<Arc<AppState>>, Path(name): Path<String>) -> Result<String, String> {
let fname = name.clone();
let result = state.collar.leash().gated(move || {
Ok(libcollar::ng::new_eiface(&name))
}).await;
Ok(format!("sup {} => {:?}", &fname, result))
}
async fn post_range_define(State(state): State<Arc<AppState>>, Path((name, size)): Path<(String, u64)>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.define(&name, size) {
Ok(_) => Ok(format!("Defined range '{}' with size {}", name, size)),
Err(e) => Err(format!("Failed to define range '{}': {:?}", name, e)),
}
}
async fn post_range_assign(State(state): State<Arc<AppState>>, Path((name, value)): Path<(String, String)>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.assign(&name, &value) {
Ok(position) => Ok(format!("Assigned '{}' to position {} in range '{}'", value, position, name)),
Err(e) => Err(format!("Failed to assign '{}' to range '{}': {:?}", value, name, e)),
}
}
async fn get_range_position(State(state): State<Arc<AppState>>, Path((name, position)): Path<(String, u64)>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.get(&name, position) {
Ok(Some(value)) => Ok(value),
Ok(None) => Err(format!("No value at position {} in range '{}'", position, name)),
Err(e) => Err(format!("Failed to get position {} from range '{}': {:?}", position, name, e)),
}
}
async fn get_range_list(State(state): State<Arc<AppState>>, Path(name): Path<String>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.list_range(&name) {
Ok(assignments) => {
let mut result = format!("Assignments in range '{}':\n", name);
for (position, value) in assignments {
result.push_str(&format!(" {}: {}\n", position, value));
}
Ok(result)
},
Err(e) => Err(format!("Failed to list range '{}': {:?}", name, e)),
}
}
async fn get_ranges_list(State(state): State<Arc<AppState>>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.list_ranges() {
Ok(range_list) => {
let mut result = "Available ranges:\n".to_string();
for (name, size) in range_list {
result.push_str(&format!(" {} (size: {})\n", name, size));
}
Ok(result)
},
Err(e) => Err(format!("Failed to list ranges: {:?}", e)),
}
}
async fn post_range_unassign(State(state): State<Arc<AppState>>, Path((name, value)): Path<(String, String)>) -> Result<String, String> {
let ranges = state.collar.store.ranges();
match ranges.unassign(&name, &value) {
Ok(true) => Ok(format!("Unassigned '{}' from range '{}'", value, name)),
Ok(false) => Err(format!("Value '{}' not found in range '{}'", value, name)),
Err(e) => Err(format!("Failed to unassign '{}' from range '{}': {:?}", value, name, e)),
}
}
diff --git a/docs/range_api.md b/docs/range_api.md
deleted file mode 100644
index d607744..0000000
--- a/docs/range_api.md
+++ /dev/null
@@ -1,184 +0,0 @@
-# Range API Documentation
-
-The Range API provides endpoints for managing fixed-size ranges with automatic position assignment. This is useful for allocating unique identifiers, session tokens, or any scenario where you need to assign values to specific positions within a bounded range.
-
-## Overview
-
-Ranges are fixed-size buckets that automatically assign values to the next available position (bit). Each range has:
-- A unique name
-- A fixed maximum size (number of positions)
-- Automatic position assignment starting from 0
-- Ability to free positions when values are removed
-
-## Endpoints
-
-### Define a Range
-
-Create a new range with a specified size.
-
-```http
-POST /store/range/{name}/{size}
-```
-
-**Parameters:**
-- `name` (string): Unique name for the range
-- `size` (u64): Maximum number of positions in the range
-
-**Example:**
-```bash
-curl -X POST http://localhost:3000/store/range/user_ids/1000
-```
-
-**Response:**
-```
-Defined range 'user_ids' with size 1000
-```
-
-### Assign Value to Range
-
-Assign a value to the next available position in the range.
-
-```http
-POST /store/range/{name}/assign/{value}
-```
-
-**Parameters:**
-- `name` (string): Name of the range
-- `value` (string): Value to assign
-
-**Example:**
-```bash
-curl -X POST http://localhost:3000/store/range/user_ids/assign/alice@example.com
-```
-
-**Response:**
-```
-Assigned 'alice@example.com' to position 0 in range 'user_ids'
-```
-
-### Get Value at Position
-
-Retrieve the value assigned to a specific position.
-
-```http
-GET /store/range/{name}/{position}
-```
-
-**Parameters:**
-- `name` (string): Name of the range
-- `position` (u64): Position to query
-
-**Example:**
-```bash
-curl http://localhost:3000/store/range/user_ids/0
-```
-
-**Response:**
-```
-alice@example.com
-```
-
-### List Range Assignments
-
-List all assignments in a specific range.
-
-```http
-GET /store/range/{name}
-```
-
-**Parameters:**
-- `name` (string): Name of the range
-
-**Example:**
-```bash
-curl http://localhost:3000/store/range/user_ids
-```
-
-**Response:**
-```
-Assignments in range 'user_ids':
- 0: alice@example.com
- 1: bob@example.com
- 2: charlie@example.com
-```
-
-### List All Ranges
-
-List all defined ranges and their sizes.
-
-```http
-GET /store/ranges
-```
-
-**Example:**
-```bash
-curl http://localhost:3000/store/ranges
-```
-
-**Response:**
-```
-Available ranges:
- session_tokens (size: 64)
- user_ids (size: 1000)
-```
-
-### Unassign Value
-
-Remove a value from the range, freeing its position for reuse.
-
-```http
-POST /store/range/{name}/unassign/{value}
-```
-
-**Parameters:**
-- `name` (string): Name of the range
-- `value` (string): Value to remove
-
-**Example:**
-```bash
-curl -X POST http://localhost:3000/store/range/user_ids/unassign/bob@example.com
-```
-
-**Response:**
-```
-Unassigned 'bob@example.com' from range 'user_ids'
-```
-
-## Usage Example
-
-Here's a complete example workflow:
-
-```bash
-# 1. Define a range for user IDs
-curl -X POST http://localhost:3000/store/range/user_ids/100
-
-# 2. Assign some users
-curl -X POST http://localhost:3000/store/range/user_ids/assign/alice@example.com
-curl -X POST http://localhost:3000/store/range/user_ids/assign/bob@example.com
-curl -X POST http://localhost:3000/store/range/user_ids/assign/charlie@example.com
-
-# 3. List all assignments
-curl http://localhost:3000/store/range/user_ids
-
-# 4. Get a specific user
-curl http://localhost:3000/store/range/user_ids/0
-
-# 5. Remove Bob's assignment
-curl -X POST http://localhost:3000/store/range/user_ids/unassign/bob@example.com
-
-# 6. Assign a new user (will reuse Bob's old position)
-curl -X POST http://localhost:3000/store/range/user_ids/assign/dave@example.com
-
-# 7. List all ranges
-curl http://localhost:3000/store/ranges
-```
-
-## Error Responses
-
-All endpoints return HTTP 200 on success with a descriptive message, or HTTP 500 on error with an error message.
-
-Common error scenarios:
-- Range not found
-- Position out of bounds
-- Value not found in range
-- Range is full (no available positions)
\ No newline at end of file
diff --git a/test_range_api.sh b/test_range_api.sh
deleted file mode 100755
index 0732365..0000000
--- a/test_range_api.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-
-# Test script for Range API functionality
-set -e
-
-API_BASE="http://localhost:3000"
-
-echo "Testing Range API..."
-
-# Test 1: Define a range
-echo "1. Defining range 'test_users' with size 10..."
-curl -s -X POST "$API_BASE/store/range/test_users/10"
-echo
-
-# Test 2: Assign some values
-echo "2. Assigning users to range..."
-curl -s -X POST "$API_BASE/store/range/test_users/assign/alice@example.com"
-echo
-curl -s -X POST "$API_BASE/store/range/test_users/assign/bob@example.com"
-echo
-curl -s -X POST "$API_BASE/store/range/test_users/assign/charlie@example.com"
-echo
-
-# Test 3: List all assignments
-echo "3. Listing all assignments in range..."
-curl -s "$API_BASE/store/range/test_users"
-echo
-
-# Test 4: Get specific position
-echo "4. Getting value at position 0..."
-curl -s "$API_BASE/store/range/test_users/0"
-echo
-
-# Test 5: List all ranges
-echo "5. Listing all ranges..."
-curl -s "$API_BASE/store/ranges"
-echo
-
-# Test 6: Unassign a value
-echo "6. Unassigning bob@example.com..."
-curl -s -X POST "$API_BASE/store/range/test_users/unassign/bob@example.com"
-echo
-
-# Test 7: Assign new user (should reuse bob's position)
-echo "7. Assigning dave@example.com (should reuse position 1)..."
-curl -s -X POST "$API_BASE/store/range/test_users/assign/dave@example.com"
-echo
-
-# Test 8: List updated assignments
-echo "8. Final state of assignments..."
-curl -s "$API_BASE/store/range/test_users"
-echo
-
-echo "Range API test completed!"
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jun 8, 9:42 AM (12 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
47576
Default Alt Text
(14 KB)

Event Timeline