Skip to content

API Quick Reference

Rose Heart edited this page Apr 20, 2026 · 1 revision

JackrabbitDLM API Reference

This is a simple and straight forward quick reference.

Protocol

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.

Required Fields

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.

Actions

Lock

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" }

Unlock

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" }

Put

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" }

Get

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" }

Erase

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" }

Version

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" }

Response Status Codes

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

Limits

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.

Authentication

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.

Client Library

Constructor

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

Attributes

Attribute Description
Error None on success, error string on failure
ID The unique identifier for this Locker instance
VERSION Client library version string

Library Methods

Lock(expire=300)

Acquires lock with automatic retries.

result = lock.Lock(expire=30)
# Returns: 'locked' or 'failure'

IsLocked(expire=300)

Single-pass lock attempt. No retries.

result = lock.IsLocked(expire=10)
# Returns: 'locked', 'notowner', or None

Unlock()

Releases lock with automatic retries.

result = lock.Unlock()
# Returns: 'unlocked' or 'failure'

Put(expire, data)

Stores data. Data is encoded before sending. Automatic retries.

result = lock.Put(expire=300, data="step 2 complete")
# Returns: response payload or 'failure'

Get()

Retrieves data. DataStore is decoded automatically.

result = lock.Get()
# Returns: {'Status': 'Done', 'ID': '...', 'DataStore': 'step 2 complete'}
# Returns: None on failure

Erase()

Removes data with automatic retries.

result = lock.Erase()
# Returns: response payload or 'failure'

Version()

Returns server and client version combined.

v = lock.Version()
# Returns: "JackrabbitDLM/0.0.0.2.830:0.0.0.1.580"
#               server version ^^^^ ^^^^ client version

IsDLM()

Checks 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 False

Two-Channel Pattern

Locks 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.

Custom Encoding

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)