fix(smartcard): fix transmission service rework

This commit is contained in:
Bastien Wirtz
2025-09-28 22:06:53 +02:00
parent 92a79ffdfb
commit 4904717db0
3 changed files with 31 additions and 28 deletions

View File

@@ -724,7 +724,8 @@ Displays Traefik.
## Transmission
This service displays the global upload and download rates, as well as the number of active torrents from your Transmission daemon. The service communicates with the Transmission RPC interface which needs to be accessible from the browser. Make sure to configure appropriate CORS headers if accessing from a different domain.
Displays the global upload and download rates, as well as the number of active torrents from your Transmission daemon.
The service communicates with the Transmission RPC interface which needs to be accessible from the browser.
```yaml
- name: "Transmission"
@@ -732,16 +733,12 @@ This service displays the global upload and download rates, as well as the numbe
url: "http://192.168.1.2:9091" # Your Transmission web interface URL
type: "Transmission"
auth: "username:password" # Optional: HTTP Basic Auth
interval: 5000 # Optional: Interval for updating data (ms)
interval: 5000 # Optional: Interval for refreshing data (ms)
target: "_blank" # Optional: HTML a tag target attribute
```
**Configuration Options:**
- `auth`: Optional HTTP Basic Authentication in "username:password" format
- `interval`: How often to refresh data in milliseconds
The service automatically handles Transmission's session management and CSRF protection.
## Truenas Scale
Displays TrueNAS version.

View File

@@ -58,6 +58,7 @@ export default {
count: null,
error: null,
sessionId: null,
retry: 0,
}),
computed: {
downRate: function () {
@@ -87,11 +88,6 @@ export default {
transmissionRequest: async function (method) {
const options = this.getRequestHeaders(method);
// Add HTTP Basic Auth if credentials are provided
if (this.item.auth) {
options.headers["Authorization"] = `Basic ${btoa(this.item.auth)}`;
}
// Add session ID header if we have one
if (this.sessionId) {
options.headers["X-Transmission-Session-Id"] = this.sessionId;
@@ -101,21 +97,12 @@ export default {
return await this.fetch("transmission/rpc", options);
} catch (error) {
// Handle Transmission's 409 session requirement
if (error.message.includes("409")) {
const sessionOptions = this.getRequestHeaders("session-get");
const sessionResponse = this.fetch(
"transmission/rpc",
sessionOptions,
);
if (error.message.includes("409")) {
this.sessionId = sessionResponse.headers.get(
"X-Transmission-Session-Id",
);
if (this.sessionId) {
options.headers["X-Transmission-Session-Id"] = this.sessionId;
return await this.fetch("transmission/rpc", options);
}
if (error.cause.status == 409 && this.retry <= 1) {
const sessionId = await this.getSession();
if (sessionId) {
this.sessionId = sessionId;
this.retry++;
return this.transmissionRequest(method);
}
}
console.error("Transmission RPC error:", error);
@@ -123,13 +110,31 @@ export default {
}
},
getRequestHeaders: function (method) {
return {
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ method }),
};
if (this.item.auth) {
options.headers["Authorization"] = `Basic ${btoa(this.item.auth)}`;
}
return options;
},
getSession: async function () {
try {
await this.fetch(
"transmission/rpc",
this.getRequestHeaders("session-get"),
);
} catch (error) {
if (error.cause.status == 409) {
return error.cause.headers.get("X-Transmission-Session-Id");
}
}
},
getStats: async function () {
try {

View File

@@ -55,6 +55,7 @@ export default {
if (!success) {
throw new Error(
`Fail to fetch ressource: (${response.status} error)`,
{ cause: response },
);
}