Async-Redis

 view release on metacpan or  search on metacpan

examples/pagi-chat/lib/ChatApp/State.pm  view on Meta::CPAN

    return unless $data && %$data;

    # Deserialize rooms
    $data->{rooms} = $data->{rooms} ? $JSON->decode($data->{rooms}) : {};
    $data->{connected} = $data->{connected} ? 1 : 0;

    return $data;
}

async sub get_session_by_name {
    my ($name) = @_;

    # Scan for session with this name (not efficient, but works for demo)
    my $cursor = "0";
    do {
        my $result = await $redis->scan($cursor, MATCH => 'session:*', COUNT => 100);
        $cursor = $result->[0];
        my $keys = $result->[1] // [];

        for my $key (@$keys) {
            my $session = await $redis->hgetall($key);
            if ($session && $session->{name} eq $name && $session->{connected}) {
                $session->{rooms} = $session->{rooms} ? $JSON->decode($session->{rooms}) : {};
                return $session;
            }
        }
    } while ($cursor && $cursor ne "0");

    return;
}

async sub create_session {
    my ($session_id, $name, $send_cb) = @_;

    my $session = {
        id        => $session_id,
        name      => $name,
        connected => 1,
        joined_at => time(),
        last_seen => time(),
        rooms     => {},
    };

    await $redis->hmset("session:$session_id",
        id        => $session_id,
        name      => $name,
        connected => 1,
        joined_at => $session->{joined_at},
        last_seen => $session->{last_seen},
        rooms     => '{}',
    );
    await $redis->expire("session:$session_id", SESSION_TTL);
    await $redis->sadd('connected:sessions', $session_id);

    # Track locally for this worker
    register_local_session($session_id, $send_cb);

    return $session;
}

async sub update_session {
    my ($session_id, $updates) = @_;

    my @args;
    for my $key (keys %$updates) {
        my $val = $updates->{$key};
        $val = $JSON->encode($val) if ref $val;
        push @args, $key, $val;
    }

    await $redis->hmset("session:$session_id", @args) if @args;
    await $redis->expire("session:$session_id", SESSION_TTL);
}

async sub set_session_connected {
    my ($session_id, $send_cb) = @_;

    await update_session($session_id, { connected => 1, last_seen => time() });
    await $redis->sadd('connected:sessions', $session_id);
    register_local_session($session_id, $send_cb);

    return await get_session($session_id);
}

async sub set_session_disconnected {
    my ($session_id) = @_;

    await update_session($session_id, { connected => 0 });
    await $redis->srem('connected:sessions', $session_id);
    unregister_local_session($session_id);
}

async sub is_session_connected {
    my ($session_id) = @_;
    my $connected = await $redis->hget("session:$session_id", 'connected');
    return $connected ? 1 : 0;
}

async sub remove_session {
    my ($session_id) = @_;

    my $session = await get_session($session_id);
    return unless $session;

    # Leave all rooms
    for my $room_name (keys %{$session->{rooms}}) {
        await remove_user_from_room($session_id, $room_name, 1);
    }

    await $redis->del("session:$session_id");
    await $redis->srem('connected:sessions', $session_id);
    unregister_local_session($session_id);

    return $session;
}

# Room management
async sub get_room {
    my ($name) = @_;

    my $exists = await $redis->exists("room:$name");



( run in 2.171 seconds using v1.01-cache-2.11-cpan-9581c071862 )