-
-
Notifications
You must be signed in to change notification settings - Fork 2
API Quick Reference
This is a simple and straight forward quick reference.
JSON over TCP. One connection per request. One request per payload. Send a newline-terminated JSON string, read the response, close the connection.
Default host: 0.0.0.0 (all interfaces)
Default port: 37373
All traffic on the wire is encoded. Nothing is plain text. Default encoding: table-based byte-to-character mapping. Replaceable via Encoder/Decoder parameters in the client library.
DataStore MUST be a printable string. No escaped characters. No binary blobs. No raw bytes. This is a requirement. Jackrabbit DLM works with ANY language and ANY framework. Printable strings are the universal format. If you need to store binary data, encode it first (Base64, hex, etc). The encoded string is what goes into DataStore.
Every request. No exceptions.
| Field | Type | Description |
|---|---|---|
ID |
string | Requester unique identifier |
FileName |
string | Resource name |
Action |
string | Lock, Unlock, Get, Put, Erase, Version |
Expire |
string | TTL in seconds (numeric string) |
One action per request. The library enforces this. Retry() (Lock, Unlock) never includes DataStore. RetryData() (Get, Put, Erase) always includes DataStore.
Acquires a lock. Creates if not exists or expired. Renews if same ID already owns (Relock). Denied if different ID owns it.
Request:
{ "ID": "DEADBEEF", "FileName": "myResource", "Action": "Lock", "Expire": "30" }
Responses:
{ "Status": "Locked", "ID": "DEADBEEF" }
{ "Status": "NotOwner" }
{ "Status": "BadPayload" }
{ "Status": "NO" }
Releases a lock. Owner only. Non-existent resource returns Unlocked (idempotent).
Request:
{ "ID": "DEADBEEF", "FileName": "myResource", "Action": "Unlock", "Expire": "0" }
Responses:
{ "Status": "Unlocked", "ID": "DEADBEEF" }
{ "Status": "NotOwner" }
{ "Status": "Unlocked" }
Stores data. Owner only. Creates new entry if not exists or expired. Updates and renews if same ID owns it.
DataStore MUST be a printable string.
Request:
{ "ID": "DEADBEEF", "FileName": "myResource", "Action": "Put", "Expire": "300", "DataStore": "step 2 complete" }
Responses:
{ "Status": "Done", "ID": "DEADBEEF" }
{ "Status": "NotOwner" }
{ "Status": "BadPayload" }
{ "Status": "NO" }
Retrieves stored data. Owner only. Returns DataStore if exists and not expired.
Request:
{ "ID": "DEADBEEF", "FileName": "myResource", "Action": "Get", "Expire": "0" }
Responses:
{ "Status": "Done", "ID": "DEADBEEF", "DataStore": "step 2 complete" }
{ "Status": "NoData", "ID": "DEADBEEF" }
{ "Status": "NotFound" }
{ "Status": "NotOwner" }
{ "Status": "Corruption" }
Removes stored data. Owner only. Sets expiration to zero, clears DataStore.
Request:
{ "ID": "DEADBEEF", "FileName": "myResource", "Action": "Erase", "Expire": "0" }
Responses:
{ "Status": "Done", "ID": "DEADBEEF" }
{ "Status": "NotFound" }
{ "Status": "NotOwner" }
{ "Status": "Corruption" }
Returns server version. No ownership check required.
Request:
{ "ID": "any", "FileName": "any", "Action": "Version", "Expire": "0" }
Response:
{ "Status": "Version", "ID": "JackrabbitDLM/0.0.0.2.830" }
| Status | Meaning |
|---|---|
Locked |
Lock acquired or renewed |
Unlocked |
Lock released (or did not exist) |
Done |
Put, Get, or Erase succeeded |
NotOwner |
Request denied, another ID owns the resource |
NotFound |
Resource does not exist |
NoData |
Resource exists but has no DataStore |
BadPayload |
Malformed JSON, missing fields, or size limit |
BadAction |
Action not recognized |
NO |
Server memory overloaded |
Corruption |
Disk data corrupted or entry invalid |
Version |
Response to Version action |
Change them to meet your needs.
| Limit | Value | Notes |
|---|---|---|
| Max Payload | 10 MB | Total incoming payload per connection |
| Max DataStore (anon) | 16 KB | Without authentication |
| Max TTL (anon) | 3543 s | Without authentication (~59 min) |
| Read Block Size | 4096 B | Socket read chunk size |
| Listen Backlog | 1024 | Pending connections queue |
Authenticated entries (Name/Identity) can exceed DataStore size limits. MaxSize is configured per identity.
Required when DataStore exceeds 16KB or TTL exceeds 3543s.
Optional fields in request:
| Field | Description |
|---|---|
Name |
Authentication name (maps to config file) |
Identity |
Identity string from config file |
Config file location: /home/JackrabbitDLM/Config/{Name}.cfg
Create with: ./DLMIdentity myWorker
Failed authentication returns BadPayload. No reason given.
from DLMLocker import Locker
lock = Locker(filename, Retry=7, RetrySleep=1, Timeout=300,
ID=None, Host='', Port=37373,
Encoder=None, Decoder=None,
name=None, identity=None)| Parameter | Default | Description |
|---|---|---|
filename |
required | Resource name |
Retry |
7 | Retry attempts on failure |
RetrySleep |
1 | Seconds between retries |
Timeout |
300 | Socket timeout in seconds |
ID |
auto | Unique identifier (generated if None) |
Host |
127.0.0.1 | Server hostname |
Port |
37373 | Server port |
Encoder |
default | Custom encoding function |
Decoder |
default | Custom decoding function |
name |
None | Authentication name |
identity |
None | Authentication identity string |
| Attribute | Description |
|---|---|
Error |
None on success, error string on failure |
ID |
The unique identifier for this Locker instance |
VERSION |
Client library version string |
Acquires lock with automatic retries.
result = lock.Lock(expire=30)
# Returns: 'locked' or 'failure'Single-pass lock attempt. No retries.
result = lock.IsLocked(expire=10)
# Returns: 'locked', 'notowner', or NoneReleases lock with automatic retries.
result = lock.Unlock()
# Returns: 'unlocked' or 'failure'Stores data. Data is encoded before sending. Automatic retries.
result = lock.Put(expire=300, data="step 2 complete")
# Returns: response payload or 'failure'Retrieves data. DataStore is decoded automatically.
result = lock.Get()
# Returns: {'Status': 'Done', 'ID': '...', 'DataStore': 'step 2 complete'}
# Returns: None on failureRemoves data with automatic retries.
result = lock.Erase()
# Returns: response payload or 'failure'Returns server and client version combined.
v = lock.Version()
# Returns: "JackrabbitDLM/0.0.0.2.830:0.0.0.1.580"
# server version ^^^^ ^^^^ client versionChecks if JackrabbitDLM is running. Calls Version() and checks if 'JackrabbitDLM' is in the returned string.
if lock.IsDLM():
print("Server is up")
# If server is down: Version() returns "Error:0.0.0.1.580"
# 'JackrabbitDLM' NOT in string, IsDLM returns FalseLocks and Data use two separate Locker instances with two separate IDs. Same class, same server, different wire identity.
Lock channel: uses Retry() (Lock/Unlock). No DataStore on wire. Data channel: uses RetryData() (Get/Put/Erase). DataStore on wire.
from DLMLocker import Locker
gate = Locker("myResource", ID="worker-gate", Retry=5, RetrySleep=1)
data = Locker("myResource", ID="worker-data", Retry=5, RetrySleep=1)
if gate.Lock(expire=10) == 'locked':
try:
state = data.Get()
if 'DataStore' in state:
count = int(state['DataStore'])
data.Put(data=str(count + 1), expire=300)
finally:
gate.Unlock()Different IDs. Optionally different Encoders. Lock TTL is short (10s) for fast healing. Data TTL is longer (300s) for persistence.
Replace default encoding by passing functions to constructor.
import base64
import json
from DLMLocker import Locker
def my_encoder(data):
if isinstance(data, dict):
data = json.dumps(data)
if isinstance(data, str):
data = data.encode('utf-8')
return base64.b64encode(data).decode()
def my_decoder(data):
return base64.b64decode(data.encode()).decode()
data = Locker("myResource", ID="worker-data",
Encoder=my_encoder, Decoder=my_decoder)If you would like to help support this project financially, please click on the heart shaped sponsor's button in the right column of this page.