Concierge-Sessions

 view release on metacpan or  search on metacpan

lib/Concierge/Sessions/File.pm  view on Meta::CPAN

package Concierge::Sessions::File v0.11.1;
use v5.36;

use parent 'Concierge::Sessions::Base';

use File::Spec;
use Carp qw(croak);
use JSON::PP;

sub new {
    my ($class, %args) = @_;
    my $self = $class->SUPER::new(%args);
    $self->{storage_dir} = $args{storage_dir} || '/tmp/sessions';

    unless (-d $self->{storage_dir}) {
        unless (mkdir $self->{storage_dir}) {
            croak "Failed to create storage directory '$self->{storage_dir}': $!";
        }
    }

    unless (chmod 0700, $self->{storage_dir}) {
        croak "Failed to set permissions on storage directory '$self->{storage_dir}': $!";
    }

    return $self;
}

sub create_session {
    my ($self, %args) = @_;

    return { success => 0, message => "Cannot create session without user_id" }
    	unless $args{user_id};

    my $user_id = $args{user_id};

    # Delete any existing sessions for this user (enforce single session per user)
    $self->delete_user_session($user_id);

    my $session_id		= $self->generate_session_id();

    my $session_file	= File::Spec->catfile($self->{storage_dir}, $session_id);

    # Write over session file if it already exists (unlikely)
    my $fh;
	unless (open $fh, '>', $session_file) {
		return { success => 0, message => "Cannot create session file: $!" };
	}
	unless (chmod 0600, $session_file) {
		close $fh;
		return { success => 0, message => "Cannot set session file permissions: $!" };
	}

    # Build session_info structure
    my $now = time();

    # Handle session timeout: 'indefinite' or numeric value in seconds
    my $timeout = $args{session_timeout} || $self->{session_timeout};
    my $expiration;
    if (defined $timeout && $timeout eq 'indefinite') {
        $expiration = 'indefinite';
    } else {
        $expiration = $now + $timeout;
    }

    my $data	= $args{data} || {}; # for app data
    my $session_info = {
		session_id	     => $session_id,
		user_id         => $user_id,
        created_at      => $now,
        expires_at      => $expiration,
        last_updated    => $now,
        session_timeout => $timeout,
        status          => {
            state => 'active',
            dirty => 0,
        },
        data            => $data,
    };

    # Encode to JSON with pretty formatting and write with trailing newline
    my $json = JSON::PP->new->utf8->pretty->encode($session_info);
    unless (print $fh $json, "\n") {
        close $fh;
        return { success => 0, message => "Cannot write to session file: $!" };
    }

    unless (close $fh) {
        return { success => 0, message => "Cannot close session file: $!" };
    }

    return { success => 1, session_id => $session_id };
}

sub get_session_info {
    my ($self, $session_id) = @_;

    unless ($session_id) {
        return { success => 0, message => "Session ID required to retrieve session from File backend" };
    }

    my $session_file = File::Spec->catfile($self->{storage_dir}, $session_id);

    unless (-f $session_file) {
        return { success => 0, message => "Session file not found" };
    }

    my $fh;
    unless (open $fh, '<', $session_file) {



( run in 0.531 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )