blob: 9fcc104bf1c7816bad2706ef7a69dfba7959d348 [file] [log] [blame]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert';
import 'dart:io';
import 'package:clock/clock.dart';
import 'package:file/file.dart';
import 'package:path/path.dart' as p;
import 'constants.dart';
import 'initializer.dart';
class Session {
final Directory homeDirectory;
final FileSystem fs;
final File _sessionFile;
late int _sessionId;
late int _lastPing;
Session({
required this.homeDirectory,
required this.fs,
}) : _sessionFile = fs.file(p.join(
homeDirectory.path, kDartToolDirectoryName, kSessionFileName)) {
_refreshSessionData();
}
/// This will use the data parsed from the
/// session json file in the dart-tool directory
/// to get the session id if the last ping was within
/// [sessionDurationMinutes]
///
/// If time since last ping exceeds the duration, then the file
/// will be updated with a new session id and that will be returned
///
/// Note, the file will always be updated when calling this method
/// because the last ping variable will always need to be persisted
int getSessionId() {
_refreshSessionData();
final DateTime now = clock.now();
// Convert the epoch time from the last ping into datetime and
// check if we are within the [sessionDurationMinutes]
final DateTime lastPingDateTime =
DateTime.fromMillisecondsSinceEpoch(_lastPing);
if (now.difference(lastPingDateTime).inMinutes > kSessionDurationMinutes) {
// In this case, we will need to change both the session id
// and the last ping value
_sessionId = now.millisecondsSinceEpoch;
}
// Update the last ping to reflect session activity continuing
_lastPing = now.millisecondsSinceEpoch;
// Rewrite the session object back to the file to persist
// for future events
_sessionFile.writeAsStringSync(toJson());
return _sessionId;
}
/// Return a json formatted representation of the class
String toJson() => jsonEncode(<String, int>{
'session_id': _sessionId,
'last_ping': _lastPing,
});
/// This will go to the session file within the dart-tool
/// directory and fetch the latest data from the json to update
/// the class's variables. If the json file is malformed, a new
/// session file will be recreated
///
/// This allows the session data in this class to always be up
/// to date incase another tool is also calling this package and
/// making updates to the session file
void _refreshSessionData() {
/// Using a nested function here to reduce verbosity
void parseContents() {
final String sessionFileContents = _sessionFile.readAsStringSync();
final Map<String, Object?> sessionObj = jsonDecode(sessionFileContents);
_sessionId = sessionObj['session_id'] as int;
_lastPing = sessionObj['last_ping'] as int;
}
try {
parseContents();
} on FormatException {
Initializer.createSessionFile(sessionFile: _sessionFile);
parseContents();
} on PathNotFoundException {
Initializer.createSessionFile(sessionFile: _sessionFile);
parseContents();
}
}
}
class NoopSession implements Session {
@override
final int _lastPing = 0;
@override
final int _sessionId = DateTime.now().millisecondsSinceEpoch;
@override
void _refreshSessionData() {}
@override
File get _sessionFile => throw UnimplementedError();
@override
FileSystem get fs => throw UnimplementedError();
@override
int getSessionId() => _sessionId;
@override
Directory get homeDirectory => throw UnimplementedError();
@override
String toJson() {
throw UnimplementedError();
}
@override
set _lastPing(int lastPing) {}
@override
set _sessionId(int sessionId) {}
}