Skip to content

Commit fc8da45

Browse files
adding initial websocket support
1 parent 901d6bb commit fc8da45

File tree

6 files changed

+108
-1
lines changed

6 files changed

+108
-1
lines changed

package-lock.json

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { ClientInfo, DeviceInfo } from './models';
1212
import { getAuthorizationHeader } from './utils';
1313
import { getSessionApi } from './utils/api/session-api';
1414
import { getUserApi } from './utils/api/user-api';
15+
import { WebSocketService } from './websocket';
1516

1617
/** The authorization header field name. */
1718
export const AUTHORIZATION_HEADER = 'Authorization';
@@ -26,6 +27,7 @@ export class Api {
2627
deviceInfo;
2728
accessToken;
2829
axiosInstance;
30+
webSocket;
2931

3032
constructor(
3133
basePath: string,
@@ -40,6 +42,7 @@ export class Api {
4042
this.deviceInfo = deviceInfo;
4143
this.accessToken = accessToken;
4244
this.axiosInstance = axiosInstance;
45+
this.webSocket = new WebSocketService(this)
4346
}
4447

4548
get configuration(): Configuration {

src/utils/url/constants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ export const HTTP_PROTOCOL = 'http:';
1010
/** The https protocol string. */
1111
export const HTTPS_PROTOCOL = 'https:';
1212

13+
/**
14+
* The websocket protocol string
15+
*/
16+
export const WS_PROTOCOL = 'ws:';
17+
18+
/**
19+
* The secure websocket protocol string
20+
*/
21+
export const WSS_PROTOCOL = 'wss:';
22+
1323
/** The default port for the http protocol. */
1424
export const HTTP_PORT = 80;
1525

src/utils/url/websocket.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { HTTP_PROTOCOL, parseUrl, WS_PROTOCOL, WSS_PROTOCOL } from ".";
2+
import { Api } from "../../api";
3+
4+
5+
/**
6+
*
7+
* @param basePath The {@link Api.basePath} to connect to
8+
*/
9+
export default function getWebSocketUrl(basePath: string) : URL {
10+
11+
let protocol;
12+
13+
const baseUrl = parseUrl(basePath)
14+
15+
if (baseUrl.protocol.startsWith(HTTP_PROTOCOL))
16+
protocol = WS_PROTOCOL
17+
else
18+
protocol = WSS_PROTOCOL
19+
20+
return new URL(`${protocol}//${baseUrl.host}`)
21+
}

src/websocket/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this
4+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
*/
6+
7+
export * from "./websocket-service";

src/websocket/websocket-service.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Api } from "../api";
2+
import { SessionsMessage } from "../generated-client";
3+
import getWebSocketUrl from "../utils/url/websocket";
4+
5+
6+
/**
7+
* A class used for managing the lifecycle of websocket connections
8+
* to Jellyfin
9+
*/
10+
export class WebSocketService {
11+
12+
private api;
13+
private socket : WebSocket | undefined
14+
15+
constructor(api : Api) {
16+
this.api = api
17+
}
18+
19+
private shouldOpenWebSocket(accessToken : string) {
20+
21+
const socketClosed = this.socket === undefined || this.socket.readyState === WebSocket.CLOSED
22+
23+
// TODO: Add validation around accessToken
24+
return socketClosed && accessToken.length > 0
25+
}
26+
27+
/**
28+
* Ensures a websocket connection to the server is active by establishing a new connection
29+
* if a connection doesn't already exist or the previous connection is closed.
30+
*
31+
* Depends on the {@link Api.basePath} and {@link Api.accessToken} being valid and
32+
* populated.
33+
*
34+
* @param onOpen An optional callback to run when the socket is opened
35+
* @param onClose An optional callback to run when the socket is closed
36+
*/
37+
ensureWebSocket(onOpen?: () => Promise<void>, onClose?: () => Promise<void>) {
38+
39+
if (this.shouldOpenWebSocket(this.api.accessToken)) {
40+
41+
const webSocketUrl = getWebSocketUrl(this.api.basePath)
42+
43+
this.socket = new WebSocket(webSocketUrl)
44+
}
45+
46+
this.socket.onopen = onOpen
47+
this.socket.onclose = onClose
48+
}
49+
50+
sendMessage(message: SessionsMessage) {
51+
52+
}
53+
}

0 commit comments

Comments
 (0)