Gemini Test
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
unit Myc.System.Quota;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Win.Registry,
|
||||
Winapi.Windows,
|
||||
System.Classes;
|
||||
|
||||
type
|
||||
// Handles global quota tracking via Windows Registry
|
||||
TGlobalQuota = class
|
||||
private
|
||||
const
|
||||
REG_KEY = 'Software\Myc\GeminiTools\Quota';
|
||||
|
||||
// Value names
|
||||
const
|
||||
VAL_TOTAL_TOKENS = 'TotalTokens';
|
||||
const
|
||||
VAL_DAILY_TOKENS = 'DailyTokens';
|
||||
const
|
||||
VAL_LAST_RESET = 'LastReset'; // Manual reset timestamp
|
||||
const
|
||||
VAL_LAST_UPDATE = 'LastUpdate'; // Last modification timestamp
|
||||
const
|
||||
VAL_DAILY_DATE = 'DailyDate'; // Date for the daily counter reference
|
||||
|
||||
public
|
||||
// Adds tokens to global and daily counters thread-safely
|
||||
// Automatically resets the daily counter if the day has changed
|
||||
class procedure AddTokens(Count: Integer);
|
||||
|
||||
// Reads the all-time total from registry
|
||||
class function GetTotal: Int64;
|
||||
|
||||
// Reads the accumulated tokens for the current day
|
||||
class function GetDailyTotal: Int64;
|
||||
|
||||
// Returns the date and time of the last modification (AddTokens)
|
||||
class function GetLastUpdate: TDateTime;
|
||||
|
||||
// Returns the date and time of the last manual reset
|
||||
class function GetLastReset: TDateTime;
|
||||
|
||||
// Resets all counters (Total and Daily) to zero
|
||||
class procedure Reset;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TGlobalQuota }
|
||||
|
||||
class procedure TGlobalQuota.AddTokens(Count: Integer);
|
||||
var
|
||||
reg: TRegistry;
|
||||
mutex: THandle;
|
||||
totalTokens, dailyTokens: Int64;
|
||||
strValue: string;
|
||||
lastDailyDate, today: TDateTime;
|
||||
begin
|
||||
if Count <= 0 then
|
||||
exit;
|
||||
|
||||
// Use a named mutex to prevent race conditions between different processes
|
||||
mutex := CreateMutex(nil, False, 'GlobalGeminiQuotaMutex');
|
||||
if WaitForSingleObject(mutex, 2000) = WAIT_OBJECT_0 then
|
||||
try
|
||||
reg := TRegistry.Create(KEY_READ or KEY_WRITE);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, True) then
|
||||
begin
|
||||
// 1. Handle Total Tokens
|
||||
totalTokens := 0;
|
||||
if reg.ValueExists(VAL_TOTAL_TOKENS) then
|
||||
begin
|
||||
strValue := reg.ReadString(VAL_TOTAL_TOKENS);
|
||||
TryStrToInt64(strValue, totalTokens);
|
||||
end;
|
||||
totalTokens := totalTokens + Count;
|
||||
|
||||
// 2. Handle Daily Tokens
|
||||
dailyTokens := 0;
|
||||
lastDailyDate := 0;
|
||||
today := Trunc(Now); // Date part only
|
||||
|
||||
if reg.ValueExists(VAL_DAILY_DATE) then
|
||||
lastDailyDate := reg.ReadDate(VAL_DAILY_DATE);
|
||||
|
||||
// Check if we are on a new day
|
||||
if lastDailyDate = today then
|
||||
begin
|
||||
// Same day, read existing daily count
|
||||
if reg.ValueExists(VAL_DAILY_TOKENS) then
|
||||
begin
|
||||
strValue := reg.ReadString(VAL_DAILY_TOKENS);
|
||||
TryStrToInt64(strValue, dailyTokens);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// New day (or first run), dailyTokens remains 0
|
||||
// Update the reference date
|
||||
reg.WriteDate(VAL_DAILY_DATE, today);
|
||||
end;
|
||||
|
||||
dailyTokens := dailyTokens + Count;
|
||||
|
||||
// 3. Write updates
|
||||
// Store numbers as String to support Int64 (Registry WriteInteger is 32-bit in older API wrappers)
|
||||
reg.WriteString(VAL_TOTAL_TOKENS, totalTokens.ToString);
|
||||
reg.WriteString(VAL_DAILY_TOKENS, dailyTokens.ToString);
|
||||
reg.WriteDateTime(VAL_LAST_UPDATE, Now);
|
||||
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
finally
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TGlobalQuota.GetTotal: Int64;
|
||||
var
|
||||
reg: TRegistry;
|
||||
strValue: string;
|
||||
begin
|
||||
Result := 0;
|
||||
reg := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, False) then
|
||||
begin
|
||||
if reg.ValueExists(VAL_TOTAL_TOKENS) then
|
||||
begin
|
||||
strValue := reg.ReadString(VAL_TOTAL_TOKENS);
|
||||
TryStrToInt64(strValue, Result);
|
||||
end;
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TGlobalQuota.GetDailyTotal: Int64;
|
||||
var
|
||||
reg: TRegistry;
|
||||
strValue: string;
|
||||
lastDailyDate: TDateTime;
|
||||
begin
|
||||
Result := 0;
|
||||
reg := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, False) then
|
||||
begin
|
||||
// Check if the stored daily count belongs to today
|
||||
if reg.ValueExists(VAL_DAILY_DATE) then
|
||||
begin
|
||||
lastDailyDate := reg.ReadDate(VAL_DAILY_DATE);
|
||||
if lastDailyDate = Trunc(Now) then
|
||||
begin
|
||||
if reg.ValueExists(VAL_DAILY_TOKENS) then
|
||||
begin
|
||||
strValue := reg.ReadString(VAL_DAILY_TOKENS);
|
||||
TryStrToInt64(strValue, Result);
|
||||
end;
|
||||
end;
|
||||
// If date differs, Result remains 0 (logic effectively resets on read, though write happens in AddTokens)
|
||||
end;
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TGlobalQuota.GetLastUpdate: TDateTime;
|
||||
var
|
||||
reg: TRegistry;
|
||||
begin
|
||||
Result := 0;
|
||||
reg := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, False) then
|
||||
begin
|
||||
if reg.ValueExists(VAL_LAST_UPDATE) then
|
||||
Result := reg.ReadDateTime(VAL_LAST_UPDATE);
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TGlobalQuota.GetLastReset: TDateTime;
|
||||
var
|
||||
reg: TRegistry;
|
||||
begin
|
||||
Result := 0;
|
||||
reg := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, False) then
|
||||
begin
|
||||
if reg.ValueExists(VAL_LAST_RESET) then
|
||||
Result := reg.ReadDateTime(VAL_LAST_RESET);
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
class procedure TGlobalQuota.Reset;
|
||||
var
|
||||
reg: TRegistry;
|
||||
mutex: THandle;
|
||||
begin
|
||||
// Reset also needs Mutex protection to avoid conflicting writes with AddTokens
|
||||
mutex := CreateMutex(nil, False, 'GlobalGeminiQuotaMutex');
|
||||
if WaitForSingleObject(mutex, 2000) = WAIT_OBJECT_0 then
|
||||
try
|
||||
reg := TRegistry.Create(KEY_WRITE);
|
||||
try
|
||||
reg.RootKey := HKEY_CURRENT_USER;
|
||||
if reg.OpenKey(REG_KEY, True) then
|
||||
begin
|
||||
reg.WriteString(VAL_TOTAL_TOKENS, '0');
|
||||
reg.WriteString(VAL_DAILY_TOKENS, '0');
|
||||
reg.WriteDate(VAL_DAILY_DATE, Trunc(Now));
|
||||
reg.WriteDateTime(VAL_LAST_RESET, Now);
|
||||
// We typically update LastUpdate on reset as well, or leave it as the last "Add" action.
|
||||
// Here we update it to indicate change.
|
||||
reg.WriteDateTime(VAL_LAST_UPDATE, Now);
|
||||
reg.CloseKey;
|
||||
end;
|
||||
finally
|
||||
reg.Free;
|
||||
end;
|
||||
finally
|
||||
ReleaseMutex(mutex);
|
||||
CloseHandle(mutex);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user