Skip to content

Commit 2882977

Browse files
Merge branch 'databento-integration' of https://github.com/Joseph-Matteo-Scorsone/Lean.DataSource.DataBento into databento-integration
2 parents 7e04cb4 + 141d3c2 commit 2882977

1 file changed

Lines changed: 20 additions & 88 deletions

File tree

QuantConnect.DataBento/DataBentoRawLiveClient.cs

Lines changed: 20 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.IO;
1919
using System.Text;
2020
using System.Net.Sockets;
21+
using System.Text;
2122
using System.Text.Json;
2223
using System.Security.Cryptography;
2324
using System.Threading;
@@ -127,104 +128,35 @@ private async Task<bool> AuthenticateAsync()
127128

128129
try
129130
{
130-
// Read greeting and challenge from gateway
131-
var responseBuffer = new byte[1024];
132-
var messageBuffer = new StringBuilder();
133-
134-
// Read until we have both the version and cram messages
135-
string? version = null;
136-
string? cram = null;
137-
138-
while (version == null || cram == null)
131+
// DataBento authentication message format
132+
var authMessage = new
139133
{
140-
var authenticationBytesRead = await _stream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
141-
if (authenticationBytesRead == 0)
142-
{
143-
Log.Error("DatabentoRawClient.AuthenticateAsync(): Connection closed during authentication");
144-
return false;
145-
}
146-
147-
var receivedData = Encoding.UTF8.GetString(responseBuffer, 0, authenticationBytesRead);
148-
messageBuffer.Append(receivedData);
149-
150-
var messages = messageBuffer.ToString().Split('\n', StringSplitOptions.RemoveEmptyEntries);
151-
152-
foreach (var msg in messages)
153-
{
154-
if (msg.StartsWith("lsg_version="))
155-
{
156-
version = msg.Substring("lsg_version=".Length);
157-
Log.Trace($"DatabentoRawClient.AuthenticateAsync(): Gateway version: {version}");
158-
}
159-
else if (msg.StartsWith("cram="))
160-
{
161-
cram = msg.Substring("cram=".Length);
162-
Log.Trace($"DatabentoRawClient.AuthenticateAsync(): Received CRAM challenge");
163-
}
164-
}
165-
}
134+
msg_type = "authenticate",
135+
api_key = _apiKey,
136+
version = "1.0"
137+
};
138+
139+
var authJson = JsonSerializer.Serialize(authMessage);
140+
var authBytes = Encoding.UTF8.GetBytes(authJson + "\n");
166141

167-
if (string.IsNullOrEmpty(cram))
168-
{
169-
Log.Error("DatabentoRawClient.AuthenticateAsync(): No CRAM challenge received");
170-
return false;
171-
}
172-
173-
// Generate authentication response
174-
// Concatenate cram and API key: $cram|$key
175-
var cramAndKey = $"{cram}|{_apiKey}";
176-
177-
// Hash with SHA-256
178-
string authHash;
179-
using (var sha256 = SHA256.Create())
180-
{
181-
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(cramAndKey));
182-
authHash = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
183-
}
184-
185-
// Get last 5 characters of API key (bucket_id)
186-
var bucketId = _apiKey.Substring(_apiKey.Length - 5);
187-
188-
// Create auth response: $hash-$bucket_id
189-
var authResponse = $"{authHash}-{bucketId}";
190-
191-
// Send authentication message
192-
// Format: auth=$authResponse|dataset=GLBX.MDP3|encoding=dbn|ts_out=0\n
193-
var authMessage = $"auth={authResponse}|dataset=GLBX.MDP3|encoding=json|ts_out=0\n";
194-
var authBytes = Encoding.UTF8.GetBytes(authMessage);
195-
196142
await _stream.WriteAsync(authBytes, 0, authBytes.Length);
197143
await _stream.FlushAsync();
198-
199-
Log.Trace("DatabentoRawClient.AuthenticateAsync(): Sent authentication message");
200-
144+
201145
// Read authentication response
202146
messageBuffer.Clear();
203147
var bytesRead = await _stream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
204148
var response = Encoding.UTF8.GetString(responseBuffer, 0, bytesRead);
205-
206-
Log.Trace($"DatabentoRawClient.AuthenticateAsync(): Auth response: {response}");
207-
208-
// Check for success response: success=1|session_id=...
209-
if (response.Contains("success=1"))
149+
150+
Log.Debug($"DatabentoRawClient.AuthenticateAsync(): Auth response: {response}");
151+
152+
// Parse response to check if authentication was successful
153+
var responseDoc = JsonDocument.Parse(response.Trim());
154+
if (responseDoc.RootElement.TryGetProperty("success", out var successElement))
210155
{
211-
// Extract session ID if needed
212-
if (response.Contains("session_id="))
213-
{
214-
var sessionIdStart = response.IndexOf("session_id=") + "session_id=".Length;
215-
var sessionIdEnd = response.IndexOf('|', sessionIdStart);
216-
if (sessionIdEnd == -1) sessionIdEnd = response.IndexOf('\n', sessionIdStart);
217-
if (sessionIdEnd > sessionIdStart)
218-
{
219-
var sessionId = response.Substring(sessionIdStart, sessionIdEnd - sessionIdStart);
220-
Log.Trace($"DatabentoRawClient.AuthenticateAsync(): Session ID: {sessionId}");
221-
}
222-
}
223-
return true;
156+
return successElement.GetBoolean();
224157
}
225-
226-
Log.Trace($"DatabentoRawClient.AuthenticateAsync(): Authentication failed: {response}");
227-
return false;
158+
159+
return response.Contains("success") || response.Contains("authenticated");
228160
}
229161
catch (Exception ex)
230162
{

0 commit comments

Comments
 (0)