put method

  1. @override
Future<void> put(
  1. String key,
  2. dynamic value,
  3. Duration ttl
)
override

Stores a value in the cache with a specified time-to-live (TTL).

The key is a unique identifier for the cached item. The value can be any dynamic type, and it will be stored for the duration specified by ttl. After the TTL expires, the item may be automatically removed from the cache.

Throws an exception if the key is null or empty, or if ttl is negative. Implementations should handle serialization of complex value types if needed.

  • Parameters:
    • key: A non-null, non-empty string representing the cache key.
    • value: The data to be cached, which can be of any type.
    • ttl: The duration for which the item should remain in the cache.

Implementation

@override
Future<void> put(String key, dynamic value, Duration ttl) async {
  if (key.isEmpty) {
    throw ArgumentError('Cache key cannot be empty');
  }

  if (ttl.isNegative) {
    throw ArgumentError('TTL duration cannot be negative');
  }

  final filePath = _getFilePath(key);

  // Prepare cache data with metadata
  final now = DateTime.now();
  final expiresAt = now.add(ttl);
  final data = {
    'value': value,
    'expires_at': expiresAt.toIso8601String(),
    'created_at': now.toIso8601String(),
    'ttl_seconds': ttl.inSeconds,
    'compressed': false,
  };

  // Encode data to JSON
  var encodedData = jsonEncode(data);

  // Apply compression if enabled and beneficial
  if (_enableCompression && encodedData.length > _compressionThreshold) {
    final compressedBytes = gzip.encode(utf8.encode(encodedData));
    if (compressedBytes.length < encodedData.length) {
      encodedData = base64Encode(compressedBytes);
      data['compressed'] = true;
    }
  }

  // Check file size limit
  if (encodedData.length > _maxFileSize) {
    throw FileSystemException(
      'Cache data size (${encodedData.length} bytes) exceeds maximum file size ($_maxFileSize bytes)',
      filePath,
    );
  }

  // Write to file using IOSink for better Windows compatibility
  final file = File(filePath);
  final sink = file.openWrite();
  sink.write(encodedData);
  await sink.close();

  // Set file permissions if supported (Unix systems)
  try {
    await Process.run(
      'chmod',
      ['${_filePermissions.toRadixString(8)}', filePath],
    );
  } catch (e) {
    // Silently fail if chmod is not available (e.g., on Windows)
  }

  // Update statistics and persist metadata
  _stats.sets++;
  await _saveMetadata();
}