Skip to content

Commit 99635fc

Browse files
committed
Update to proper path and update error handling
1 parent 23430a4 commit 99635fc

File tree

4 files changed

+146
-46
lines changed

4 files changed

+146
-46
lines changed

.github/workflows/docker-build-push.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535
run: |
3636
docker build . -t fleet-telemetry-consumer:${{ env.image_tag }}
3737
docker tag fleet-telemetry-consumer:${{ env.image_tag }} quay.io/rajsinghcpre/fleet-telemetry-consumer:${{ env.image_tag }}
38-
docker push quay.io/rajsinghcpre/fleet-telemetry-consumer:${{ env.image_tag }}
38+
docker push --force quay.io/rajsinghcpre/fleet-telemetry-consumer:${{ env.image_tag }}

examples/kustomization/fleet-telemetry-consumer.yaml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,27 @@ spec:
4040
- name: tesla-ssl
4141
mountPath: /secrets/tesla-ssl
4242
- name: fleet-telemetry-consumer
43-
image: quay.io/rajsinghcpre/fleet-telemetry-consumer:refactor-c9e0a4199e390d82a7d239e37d27f31bd1adb1fc
44-
command: ["main.go"]
43+
image: quay.io/rajsinghcpre/fleet-telemetry-consumer:refactor
44+
# command: ["sleep", "infinity"]
45+
command: ["/app/main"]
4546
ports:
4647
- containerPort: 3000
4748
volumeMounts:
4849
- name: tesla-ssl
49-
mountPath: /secrets/tesla-ssl
50+
mountPath: /app/secrets/tesla-ssl
5051
- name: fleet-api
51-
mountPath: /secrets/fleet-api
52+
mountPath: /app/secrets/fleet-api
5253
- name: pg
53-
mountPath: /secrets/pg
54+
mountPath: /app/secrets/pg
55+
- name: fleet-telemetry-ssl
56+
mountPath: /app/secrets/fleet-telemetry-ssl
5457
volumes:
5558
- name: tesla-ssl
5659
secret:
5760
secretName: tesla-raj-tls
61+
- name: fleet-telemetry-ssl
62+
secret:
63+
secretName: fleet-telemetry-tesla-raj-tls
5864
- name: fleet-api
5965
secret:
6066
secretName: tesla-fleet-api

main.go

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -265,14 +265,6 @@ var (
265265
domainName []byte
266266
)
267267

268-
func getBaseURL(c *fiber.Ctx) string {
269-
protocol := "http"
270-
if c.Protocol() == "https" || c.Get("X-Forwarded-Proto") == "https" {
271-
protocol = "https"
272-
}
273-
return fmt.Sprintf("%s://%s", protocol, c.Hostname())
274-
}
275-
276268
func getRedirectURI(c *fiber.Ctx) string {
277269
host := c.Hostname()
278270
// Use exact URIs as registered in Tesla Developer Portal
@@ -349,12 +341,16 @@ func exchangeAuthCode(code string, c *fiber.Ctx) (*TokenResponse, error) {
349341
}
350342

351343
func getVehicles(token string) (*VehicleResponse, error) {
352-
req, err := http.NewRequest("GET", "https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles", nil)
344+
url := "https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles"
345+
log.Printf("Making request to Fleet API: GET %s", url)
346+
347+
req, err := http.NewRequest("GET", url, nil)
353348
if err != nil {
354349
return nil, fmt.Errorf("error creating request: %v", err)
355350
}
356351

357352
req.Header.Set("Authorization", "Bearer "+token)
353+
log.Printf("Request headers: %v", req.Header)
358354

359355
client := &http.Client{}
360356
resp, err := client.Do(req)
@@ -368,8 +364,8 @@ func getVehicles(token string) (*VehicleResponse, error) {
368364
return nil, fmt.Errorf("error reading response: %v", err)
369365
}
370366

371-
log.Printf("Vehicles response status: %d", resp.StatusCode)
372-
log.Printf("Vehicles response body: %s", string(body))
367+
log.Printf("Fleet API Response for GET %s:\nStatus: %d\nHeaders: %v\nBody: %s",
368+
url, resp.StatusCode, resp.Header, string(body))
373369

374370
if resp.StatusCode != http.StatusOK {
375371
return nil, fmt.Errorf("failed to get vehicles with status %d: %s", resp.StatusCode, string(body))
@@ -383,15 +379,6 @@ func getVehicles(token string) (*VehicleResponse, error) {
383379
return &vehicleResp, nil
384380
}
385381

386-
func getVirtualKeyURL() string {
387-
domain := strings.TrimSpace(string(domainName))
388-
domain = strings.ToLower(domain)
389-
domain = strings.TrimPrefix(domain, "https://")
390-
domain = strings.TrimPrefix(domain, "http://")
391-
domain = strings.TrimSuffix(domain, "/")
392-
return fmt.Sprintf("https://www.tesla.com/_ak/%s", domain)
393-
}
394-
395382
// Update configure telemetry function
396383
func configureTelemetry(vin, accessToken string) error {
397384
// Tesla's proxy runs on localhost:4443 with HTTPS
@@ -465,10 +452,9 @@ func configureTelemetry(vin, accessToken string) error {
465452
req.Header.Set("Content-Type", "application/json")
466453
req.Header.Set("Authorization", "Bearer "+accessToken)
467454

468-
// Create a custom HTTP client that skips TLS verification for localhost
469455
tr := &http.Transport{
470456
TLSClientConfig: &tls.Config{
471-
InsecureSkipVerify: true, // Skip verification since it's localhost
457+
InsecureSkipVerify: true,
472458
},
473459
}
474460
client := &http.Client{Transport: tr}
@@ -480,13 +466,33 @@ func configureTelemetry(vin, accessToken string) error {
480466
defer resp.Body.Close()
481467

482468
body, _ := io.ReadAll(resp.Body)
469+
log.Printf("Telemetry configuration response: %s", string(body))
470+
471+
// Parse the response to check for missing key
472+
var result struct {
473+
Response struct {
474+
UpdatedVehicles int `json:"updated_vehicles"`
475+
SkippedVehicles struct {
476+
MissingKey []string `json:"missing_key"`
477+
} `json:"skipped_vehicles"`
478+
} `json:"response"`
479+
}
480+
481+
if err := json.Unmarshal(body, &result); err != nil {
482+
return fmt.Errorf("error parsing response: %v", err)
483+
}
484+
485+
// Check if this VIN is in the missing_key list
486+
for _, missingVIN := range result.Response.SkippedVehicles.MissingKey {
487+
if missingVIN == vin {
488+
return fmt.Errorf("missing_key: Virtual key not paired with vehicle. Please pair your virtual key at https://www.tesla.com/_ak/tesla.rajsingh.info")
489+
}
490+
}
491+
483492
if resp.StatusCode != http.StatusOK {
484493
return fmt.Errorf("failed to configure telemetry with status %d: %s", resp.StatusCode, string(body))
485494
}
486495

487-
// Log the response for debugging
488-
log.Printf("Telemetry configuration response: %s", string(body))
489-
490496
return nil
491497
}
492498

@@ -526,12 +532,16 @@ func getUserInfo(accessToken string) (*UserInfo, error) {
526532
}
527533

528534
func getTeslaUserInfo(accessToken string) (*TeslaUserResponse, error) {
529-
req, err := http.NewRequest("GET", "https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/users/me", nil)
535+
url := "https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/users/me"
536+
log.Printf("Making request to Fleet API: GET %s", url)
537+
538+
req, err := http.NewRequest("GET", url, nil)
530539
if err != nil {
531540
return nil, fmt.Errorf("error creating request: %v", err)
532541
}
533542

534543
req.Header.Set("Authorization", "Bearer "+accessToken)
544+
log.Printf("Request headers: %v", req.Header)
535545

536546
client := &http.Client{}
537547
resp, err := client.Do(req)
@@ -545,8 +555,8 @@ func getTeslaUserInfo(accessToken string) (*TeslaUserResponse, error) {
545555
return nil, fmt.Errorf("error reading response: %v", err)
546556
}
547557

548-
log.Printf("Tesla user info response status: %d", resp.StatusCode)
549-
log.Printf("Tesla user info response body: %s", string(body))
558+
log.Printf("Fleet API Response for GET %s:\nStatus: %d\nHeaders: %v\nBody: %s",
559+
url, resp.StatusCode, resp.Header, string(body))
550560

551561
if resp.StatusCode != http.StatusOK {
552562
return nil, fmt.Errorf("failed to get Tesla user info with status %d: %s", resp.StatusCode, string(body))

views/dashboard.html

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,52 @@
329329
method: 'POST',
330330
});
331331
const data = await response.json();
332+
332333
if (response.ok) {
333-
showResponse('Telemetry Configuration', 'Vehicle successfully programmed for telemetry. The page will refresh when you close this message.', 'success');
334-
reloadAfterClose(document.getElementById('responsePanel'));
334+
const content = document.getElementById('responseContent');
335+
content.innerHTML = `<div style="margin-bottom: 15px;">Vehicle successfully programmed for telemetry. The page will refresh when you close this message.</div>
336+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
337+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
338+
339+
const panel = document.getElementById('responsePanel');
340+
panel.className = 'response-panel success';
341+
document.getElementById('responseTitle').textContent = 'Telemetry Configuration';
342+
panel.style.display = 'block';
343+
reloadAfterClose(panel);
335344
} else {
336-
showResponse('Error', data.error, 'error');
345+
if (data.error && data.error.startsWith('missing_key:')) {
346+
const panel = document.getElementById('responsePanel');
347+
panel.className = 'response-panel error';
348+
document.getElementById('responseTitle').textContent = 'Virtual Key Required';
349+
const content = document.getElementById('responseContent');
350+
content.innerHTML = `<div style="margin-bottom: 15px;">This vehicle requires a virtual key to be paired before it can be programmed for telemetry.</div>
351+
<a href="https://www.tesla.com/_ak/tesla.rajsingh.info" target="_blank"
352+
style="background: #2ecc71; color: white; padding: 10px 20px; border-radius: 4px; text-decoration: none; display: inline-block; margin-bottom: 15px;">
353+
Pair Virtual Key
354+
</a>
355+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
356+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
357+
panel.style.display = 'block';
358+
} else {
359+
const content = document.getElementById('responseContent');
360+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${data.error}</div>
361+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
362+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
363+
364+
const panel = document.getElementById('responsePanel');
365+
panel.className = 'response-panel error';
366+
document.getElementById('responseTitle').textContent = 'Error';
367+
panel.style.display = 'block';
368+
}
337369
}
338370
} catch (error) {
339-
showResponse('Error', error.message, 'error');
371+
const content = document.getElementById('responseContent');
372+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${error.message}</div>`;
373+
374+
const panel = document.getElementById('responsePanel');
375+
panel.className = 'response-panel error';
376+
document.getElementById('responseTitle').textContent = 'Error';
377+
panel.style.display = 'block';
340378
}
341379
}
342380

@@ -345,12 +383,33 @@
345383
const response = await fetch(`/api/vehicles/${vin}/telemetry`);
346384
const data = await response.json();
347385
if (response.ok) {
348-
showResponse('Telemetry Configuration', data);
386+
const content = document.getElementById('responseContent');
387+
content.innerHTML = `<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
388+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
389+
390+
const panel = document.getElementById('responsePanel');
391+
panel.className = 'response-panel success';
392+
document.getElementById('responseTitle').textContent = 'Telemetry Configuration';
393+
panel.style.display = 'block';
349394
} else {
350-
showResponse('Error', data.error, 'error');
395+
const content = document.getElementById('responseContent');
396+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${data.error}</div>
397+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
398+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
399+
400+
const panel = document.getElementById('responsePanel');
401+
panel.className = 'response-panel error';
402+
document.getElementById('responseTitle').textContent = 'Error';
403+
panel.style.display = 'block';
351404
}
352405
} catch (error) {
353-
showResponse('Error', error.message, 'error');
406+
const content = document.getElementById('responseContent');
407+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${error.message}</div>`;
408+
409+
const panel = document.getElementById('responsePanel');
410+
panel.className = 'response-panel error';
411+
document.getElementById('responseTitle').textContent = 'Error';
412+
panel.style.display = 'block';
354413
}
355414
}
356415

@@ -361,13 +420,35 @@
361420
});
362421
const data = await response.json();
363422
if (response.ok) {
364-
showResponse('Configuration Deleted', 'Telemetry configuration successfully deleted. The page will refresh when you close this message.', 'success');
365-
reloadAfterClose(document.getElementById('responsePanel'));
423+
const content = document.getElementById('responseContent');
424+
content.innerHTML = `<div style="margin-bottom: 15px;">Telemetry configuration successfully deleted. The page will refresh when you close this message.</div>
425+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
426+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
427+
428+
const panel = document.getElementById('responsePanel');
429+
panel.className = 'response-panel success';
430+
document.getElementById('responseTitle').textContent = 'Configuration Deleted';
431+
panel.style.display = 'block';
432+
reloadAfterClose(panel);
366433
} else {
367-
showResponse('Error', data.error, 'error');
434+
const content = document.getElementById('responseContent');
435+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${data.error}</div>
436+
<div style="font-weight: bold; margin-bottom: 5px;">Tesla Fleet API Response:</div>
437+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 0;">${JSON.stringify(data, null, 2)}</pre>`;
438+
439+
const panel = document.getElementById('responsePanel');
440+
panel.className = 'response-panel error';
441+
document.getElementById('responseTitle').textContent = 'Error';
442+
panel.style.display = 'block';
368443
}
369444
} catch (error) {
370-
showResponse('Error', error.message, 'error');
445+
const content = document.getElementById('responseContent');
446+
content.innerHTML = `<div style="margin-bottom: 15px; color: #e74c3c;">${error.message}</div>`;
447+
448+
const panel = document.getElementById('responsePanel');
449+
panel.className = 'response-panel error';
450+
document.getElementById('responseTitle').textContent = 'Error';
451+
panel.style.display = 'block';
371452
}
372453
}
373454

@@ -435,7 +516,10 @@
435516
<div class="container">
436517
<div class="header">
437518
<h1>{{.Title}}</h1>
438-
<a href="/auth" class="header-button">Add Tesla Account</a>
519+
<div style="display: flex; gap: 10px;">
520+
<a href="https://www.tesla.com/_ak/tesla.rajsingh.info" target="_blank" class="header-button">Pair Virtual Key</a>
521+
<a href="/auth" class="header-button">Add Tesla Account</a>
522+
</div>
439523
</div>
440524

441525
{{if .ShowSuccess}}

0 commit comments

Comments
 (0)