NAME

IPC::Manager::Client::JSONFile - Single JSON file as a message store

DESCRIPTION

This protocol stores all client state, messages, and statistics in a single JSON file. The file is the "route". All access is serialised with flock(2) — a shared lock for reads and an exclusive lock for writes. Every mutation reads the file, modifies the in-memory structure, and rewrites the entire file.

State is cached in memory and only re-read when the file has changed. When Linux::Inotify2 is available the file is watched for IN_MODIFY / IN_CLOSE_WRITE events; otherwise the file's mtime is compared to detect changes.

This protocol is simple and portable but not suited for high-throughput workloads; the file-level lock serialises all operations across all clients.

SYNOPSIS

use IPC::Manager qw/ipcm_spawn ipcm_connect/;

my $spawn = ipcm_spawn(protocol => 'JSONFile');

my $con1 = $spawn->connect('con1');
my $con2 = ipcm_connect(con2 => $spawn->info);

$con1->send_message(con2 => {hello => 'world'});

my @messages = $con2->get_messages;

FILE STRUCTURE

The route is the path to a single JSON file created by spawn(). The file contains one JSON object with three top-level keys:

{
    "clients":  { ... },
    "messages": { ... },
    "stats":    { ... }
}

clients

A hash mapping each connected client's ID to its metadata. A client entry is added during init() (connect) and removed during post_disconnect_hook().

"clients": {
    "con1": { "pid": 12345 },
    "con2": { "pid": 12346 }
}
pid

The process ID that owns the connection. Written at connect and checked at reconnect to prevent duplicate ownership.

messages

A hash mapping each client ID to an array of pending messages addressed to that client. Messages are plain JSON objects (the output of IPC::Manager::Message->TO_JSON). send_message() appends to the recipient's array; get_messages() drains it.

"messages": {
    "con1": [],
    "con2": [
        {
            "id":        "019D55F2-...",
            "stamp":     1775263425.787,
            "from":      "con1",
            "to":        "con2",
            "broadcast": null,
            "content":   { "hello": "world" }
        }
    ]
}

Each message object has the following fields:

id

A UUID string uniquely identifying the message.

stamp

A high-resolution Unix timestamp (seconds since epoch with sub-second precision) indicating when the message was created.

from

The client ID of the sender.

to

The client ID of the intended recipient.

broadcast

true if the message was sent via broadcast(), null otherwise.

content

The application payload — any JSON-serialisable value (hash, array, string, number, etc.).

stats

A hash mapping client IDs to their send/receive statistics. Entries are written by write_stats() (called during disconnect) and persist after the client entry is removed, so that all_stats() and Spawn->sanity_check() can compare totals after all clients have disconnected.

"stats": {
    "con1": {
        "read": { "con2": 3 },
        "sent": { "con2": 5 }
    },
    "con2": {
        "read": { "con1": 5 },
        "sent": { "con1": 3 }
    }
}
read

A hash mapping sender client IDs to the number of messages received from that sender.

sent

A hash mapping recipient client IDs to the number of messages sent to that recipient.

CONCURRENCY

All file access is protected by flock(2):

  • Read operations (peers, peer_exists, peer_pid, ready_messages, read_stats, all_stats) acquire a shared lock (LOCK_SH). Multiple readers may proceed concurrently.

  • Write operations (init, send_message, get_messages, write_stats, post_disconnect_hook) acquire an exclusive lock (LOCK_EX), re-read the file to get the latest state, modify it, and rewrite the entire file.

State is cached in memory and only re-read from disk when a change is detected. When Linux::Inotify2 is available, the file is watched for IN_MODIFY / IN_CLOSE_WRITE events. Otherwise the file's mtime is compared against the cached value. After each write the cache is updated and any self-generated inotify events are drained so the cache is not spuriously invalidated.

METHODS

See IPC::Manager::Client for inherited methods.

SOURCE

The source code repository for IPC::Manager can be found at https://github.com/exodist/IPC-Manager.

MAINTAINERS

Chad Granum <exodist@cpan.org>

AUTHORS

Chad Granum <exodist@cpan.org>

COPYRIGHT

Copyright Chad Granum <exodist7@gmail.com>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See https://dev.perl.org/licenses/