read method

  1. @override
Future<Session> read(
  1. Request request,
  2. String name
)
override

Reads an existing session or creates a new one if it does not exist.

This method retrieves a session associated with the given request and session name. If a session exists, it's loaded; otherwise, a new session is created.

The request object provides context, including cookies or headers used to identify the session. The name parameter uniquely identifies the session.

Returns a Future<Session> that completes with the loaded or newly created Session object.

Example:

final session = await store.read(request, 'my_session');

Implementation

@override
Future<Session> read(Request request, String name) async {
  Cookie cookie = request.cookies.firstWhere(
    (c) => c.name == name,
    orElse: () => Cookie(name, ''),
  );

  if (cookie.value.isEmpty) {
    final header = request.header(HttpHeaders.cookieHeader);
    if (header.isNotEmpty) {
      for (final entry in header.split(';')) {
        final trimmed = entry.trim();
        if (trimmed.isEmpty) continue;
        final separatorIndex = trimmed.indexOf('=');
        if (separatorIndex == -1) continue;
        final cookieName = trimmed.substring(0, separatorIndex).trim();
        if (cookieName != name) continue;
        final cookieValue = trimmed.substring(separatorIndex + 1).trim();
        if (cookieValue.isEmpty) continue;
        cookie = Cookie(cookieName, cookieValue);
        break;
      }
    }
  }

  if (cookie.value.isEmpty) {
    return Session(name: name, options: defaultOptions);
  }

  var value = cookie.value;
  try {
    value = Uri.decodeComponent(value);
  } catch (_) {
    // Value was not URI-encoded; continue with original payload for legacy cookies.
  }
  // Unwind the codec chain in the same order it was applied during encoding.
  for (final codec in _decodeCodecs) {
    try {
      final decoded = codec.decode(name, value);

      // The encoding step stores the next payload under the `"data"` key.
      if (decoded.containsKey('data') && decoded['data'] is String) {
        value = decoded['data'] as String;
      } else {
        // Fallback for single-codec or legacy payloads.
        value = jsonEncode(decoded);
      }
    } catch (e) {
      // Try the next codec in the chain
      continue;
    }
  }

  try {
    final Map<String, dynamic> data =
        jsonDecode(value) as Map<String, dynamic>;
    final session = Session(
      name: name,
      options: defaultOptions,
      id: data['id'] as String?,
      values: Map<String, dynamic>.from(data['values'] as Map),
      createdAt: DateTime.parse(data['created_at'] as String),
      lastAccessed: DateTime.parse(data['last_accessed'] as String),
    );

    if (data['is_new'] != null) session.isNew = data['is_new'] as bool;
    if (data['destroyed'] == true) session.destroy();

    return session;
  } catch (e) {
    return Session(name: name, options: defaultOptions);
  }
}