Fix longstanding architectural issues

This commit is contained in:
hensm
2022-09-01 02:14:00 +01:00
committed by Matt Hensman
parent 83c81219d7
commit 7a35da2ba1
30 changed files with 1274 additions and 1282 deletions

View File

@@ -4,16 +4,7 @@ import { v4 as uuid } from "uuid";
import logger from "../../lib/logger";
import eventMessaging from "../eventMessaging";
import type {
ErrorCallback,
LoadSuccessCallback,
MediaListener,
MessageListener,
SuccessCallback,
UpdateListener
} from "../types";
import eventMessaging from "../pageMessenging";
import {
MediaStatus,
@@ -24,7 +15,12 @@ import {
} from "./types";
import { SessionStatus } from "./enums";
import type { Image, Receiver, SenderApplication } from "./classes";
import type {
Error as CastError,
Image,
Receiver,
SenderApplication
} from "./classes";
import { MediaCommand } from "./media/enums";
import type { LoadRequest, QueueLoadRequest, QueueItem } from "./media/classes";
@@ -101,17 +97,20 @@ function updateMedia(media: Media, status: MediaStatus) {
}
}
type MessageListener = (namespace: string, message: string) => void;
type UpdateListener = (isAlive: boolean) => void;
export default class Session {
#loadMediaSuccessCallback?: (media: Media) => void;
#loadMediaErrorCallback?: ErrorCallback;
#loadMediaRequest?: LoadRequest;
#loadMediaSuccessCallback?: (media: Media) => void;
#loadMediaErrorCallback?: (err: CastError) => void;
_messageListeners = new Map<string, Set<MessageListener>>();
_updateListeners = new Set<UpdateListener>();
_sendMessageCallbacks = new Map<
string,
[SuccessCallback?, ErrorCallback?]
[(() => void)?, ((err: CastError) => void)?]
>();
media: Media[] = [];
@@ -203,10 +202,10 @@ export default class Session {
});
};
addMediaListener(_mediaListener: MediaListener) {
addMediaListener(_mediaListener: (media: Media) => void) {
logger.info("STUB :: Session#addMediaListener");
}
removeMediaListener(_mediaListener: MediaListener) {
removeMediaListener(_mediaListener: (media: Media) => void) {
logger.info("STUB :: Session#removeMediaListener");
}
@@ -228,14 +227,17 @@ export default class Session {
this._updateListeners.delete(listener);
}
leave(_successCallback?: SuccessCallback, _errorCallback?: ErrorCallback) {
leave(
_successCallback?: () => void,
_errorCallback?: (err: CastError) => void
) {
logger.info("STUB :: Session#leave");
}
loadMedia(
loadRequest: LoadRequest,
successCallback?: LoadSuccessCallback,
errorCallback?: ErrorCallback
successCallback?: (media: Media) => void,
errorCallback?: (err: CastError) => void
) {
this.#loadMediaSuccessCallback = successCallback;
this.#loadMediaErrorCallback = errorCallback;
@@ -246,8 +248,8 @@ export default class Session {
queueLoad(
_queueLoadRequest: QueueLoadRequest,
_successCallback?: LoadSuccessCallback,
_errorCallback?: ErrorCallback
_successCallback?: (media: Media) => void,
_errorCallback?: (err: CastError) => void
) {
logger.info("STUB :: Session#queueLoad");
}
@@ -255,8 +257,8 @@ export default class Session {
sendMessage(
namespace: string,
message: object | string,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
const messageId = uuid();
@@ -278,8 +280,8 @@ export default class Session {
setReceiverMuted(
muted: boolean,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this.#sendReceiverMessage({ type: "SET_VOLUME", volume: { muted } })
.then(successCallback)
@@ -288,8 +290,8 @@ export default class Session {
setReceiverVolumeLevel(
newLevel: number,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this.#sendReceiverMessage({
type: "SET_VOLUME",
@@ -299,7 +301,10 @@ export default class Session {
.catch(errorCallback);
}
stop(successCallback?: SuccessCallback, errorCallback?: ErrorCallback) {
stop(
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this.#sendReceiverMessage({ type: "STOP", sessionId: this.sessionId })
.then(successCallback)
.catch(errorCallback);

View File

@@ -6,6 +6,7 @@ import {
AutoJoinPolicy,
Capability,
DefaultActionPolicy,
ReceiverAvailability,
ReceiverType,
VolumeControlType
} from "./enums";
@@ -14,7 +15,7 @@ export class ApiConfig {
constructor(
public sessionRequest: SessionRequest,
public sessionListener: (session: Session) => void,
public receiverListener: (availability: string) => void,
public receiverListener: (availability: ReceiverAvailability) => void,
public autoJoinPolicy: string = AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED,
public defaultActionPolicy: string = DefaultActionPolicy.CREATE_SESSION

View File

@@ -3,9 +3,7 @@
import logger from "../../lib/logger";
import type { Message } from "../../messaging";
import eventMessaging from "../eventMessaging";
import type { ErrorCallback, SuccessCallback } from "../types";
import pageMessenging from "../pageMessenging";
import {
AutoJoinPolicy,
@@ -25,7 +23,7 @@ import {
ApiConfig,
CredentialsData,
DialRequest,
Error as Error_,
Error as CastError,
Image,
Receiver,
ReceiverDisplayStatus,
@@ -51,15 +49,16 @@ export default class {
#apiConfig?: ApiConfig;
#sessionRequest?: SessionRequest;
#receiverAvailability = ReceiverAvailability.UNAVAILABLE;
#initializeSuccessCallback?: () => void;
#requestSessionSuccessCallback?: RequestSessionSuccessCallback;
#requestSessionErrorCallback?: ErrorCallback;
#requestSessionErrorCallback?: (err: CastError) => void;
#initializeSuccessCallback?: SuccessCallback;
#sessions = new Map<string, Session>();
#receiverActionListeners = new Set<ReceiverActionListener>();
#receiverAvailability = ReceiverAvailability.UNAVAILABLE;
#sessions = new Map<string, Session>();
// Enums
AutoJoinPolicy = AutoJoinPolicy;
@@ -78,7 +77,7 @@ export default class {
ApiConfig = ApiConfig;
CredentialsData = CredentialsData;
DialRequest = DialRequest;
Error = Error_;
Error = CastError;
Image = Image;
Receiver = Receiver;
ReceiverDisplayStatus = ReceiverDisplayStatus;
@@ -95,17 +94,17 @@ export default class {
timeout = new Timeout();
constructor() {
eventMessaging.page.addListener(this.#onMessage.bind(this));
pageMessenging.page.addListener(this.#onMessage.bind(this));
}
#onMessage(message: Message) {
switch (message.subject) {
case "cast:initialized":
this.isAvailable = true;
this.#initializeSuccessCallback?.();
this.#apiConfig?.receiverListener(this.#receiverAvailability);
this.isAvailable = true;
break;
/**
@@ -185,7 +184,7 @@ export default class {
break;
}
case "cast:receivedSessionMessage": {
case "cast:sessionMessageReceived": {
const { sessionId, namespace, messageData } = message.data;
const session = this.#sessions.get(sessionId);
if (session) {
@@ -213,7 +212,7 @@ export default class {
const [successCallback, errorCallback] = callbacks;
if (error) {
errorCallback?.(new Error_(error));
errorCallback?.(new CastError(error));
return;
}
@@ -223,7 +222,7 @@ export default class {
break;
}
case "cast:updateReceiverAvailability": {
case "cast:receiverAvailabilityUpdated": {
const availability = message.data.isAvailable
? ReceiverAvailability.AVAILABLE
: ReceiverAvailability.UNAVAILABLE;
@@ -238,19 +237,19 @@ export default class {
}
// Popup closed before session established
case "cast:selectReceiver/cancelled": {
case "cast:sessionRequestCancelled": {
if (this.#sessionRequest) {
this.#sessionRequest = undefined;
this.#requestSessionErrorCallback?.(
new Error_(ErrorCode.CANCEL)
new CastError(ErrorCode.CANCEL)
);
}
break;
}
case "cast:sendReceiverAction": {
case "cast:receiverAction": {
for (const actionListener of this.#receiverActionListeners) {
actionListener(message.data.receiver, message.data.action);
}
@@ -262,14 +261,14 @@ export default class {
initialize(
apiConfig: ApiConfig,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
logger.info("cast.initialize");
// Already initialized
if (this.#apiConfig) {
errorCallback?.(new Error_(ErrorCode.INVALID_PARAMETER));
errorCallback?.(new CastError(ErrorCode.INVALID_PARAMETER));
return;
}
@@ -279,7 +278,7 @@ export default class {
this.#initializeSuccessCallback = successCallback;
}
eventMessaging.page.sendMessage({
pageMessenging.page.sendMessage({
subject: "main:initializeCast",
data: { apiConfig: this.#apiConfig }
});
@@ -287,21 +286,21 @@ export default class {
requestSession(
successCallback: RequestSessionSuccessCallback,
errorCallback: ErrorCallback,
errorCallback: (err: CastError) => void,
newSessionRequest?: SessionRequest
) {
logger.info("cast.requestSession");
// Not yet initialized
if (!this.#apiConfig) {
errorCallback?.(new Error_(ErrorCode.API_NOT_INITIALIZED));
errorCallback?.(new CastError(ErrorCode.API_NOT_INITIALIZED));
return;
}
// Already requesting session
if (this.#sessionRequest) {
errorCallback?.(
new Error_(
new CastError(
ErrorCode.INVALID_PARAMETER,
"Session request already in progress."
)
@@ -310,7 +309,7 @@ export default class {
}
if (this.#receiverAvailability === ReceiverAvailability.UNAVAILABLE) {
errorCallback?.(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
errorCallback?.(new CastError(ErrorCode.RECEIVER_UNAVAILABLE));
return;
}
@@ -322,8 +321,8 @@ export default class {
this.#requestSessionErrorCallback = errorCallback;
// Open receiver selector UI
eventMessaging.page.sendMessage({
subject: "main:selectReceiver",
pageMessenging.page.sendMessage({
subject: "main:requestSession",
data: { sessionRequest: this.#sessionRequest }
});
}
@@ -334,8 +333,8 @@ export default class {
setCustomReceivers(
_receivers: Receiver[],
_successCallback?: SuccessCallback,
_errorCallback?: ErrorCallback
_successCallback?: () => void,
_errorCallback?: (err: CastError) => void
): void {
logger.info("STUB :: cast.setCustomReceivers");
}

View File

@@ -1,10 +1,10 @@
"use strict";
import { v1 as uuid } from "uuid";
import { v4 as uuid } from "uuid";
import logger from "../../../lib/logger";
import { Volume, Error as _Error } from "../classes";
import { Volume, Error as CastError } from "../classes";
import {
BreakStatus,
EditTracksInfoRequest,
@@ -30,16 +30,13 @@ import {
import { PlayerState, RepeatMode } from "./enums";
import { ErrorCode } from "../enums";
import type {
ErrorCallback,
SuccessCallback,
UpdateListener
} from "../../types";
import type { SenderMediaMessage } from "../types";
import { getEstimatedTime } from "../../utils";
export const NS_MEDIA = "urn:x-cast:com.google.cast.media";
type UpdateListener = (isAlive: boolean) => void;
export default class Media {
#id = uuid();
@@ -85,8 +82,8 @@ export default class Media {
editTracksInfo(
editTracksInfoRequest: EditTracksInfoRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...editTracksInfoRequest,
@@ -161,8 +158,8 @@ export default class Media {
*/
getStatus(
getStatusRequest = new GetStatusRequest(),
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...getStatusRequest,
@@ -175,8 +172,8 @@ export default class Media {
pause(
pauseRequest = new PauseRequest(),
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...pauseRequest,
@@ -189,8 +186,8 @@ export default class Media {
play(
playRequest = new PlayRequest(),
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...playRequest,
@@ -203,8 +200,8 @@ export default class Media {
queueAppendItem(
item: QueueItem,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...new QueueInsertItemsRequest([item]),
@@ -218,8 +215,8 @@ export default class Media {
queueInsertItems(
queueInsertItemsRequest: QueueInsertItemsRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...queueInsertItemsRequest,
@@ -233,8 +230,8 @@ export default class Media {
queueJumpToItem(
itemId: number,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
if (this.items?.find(item => item.itemId === itemId)) {
const jumpRequest = new QueueJumpRequest();
@@ -254,8 +251,8 @@ export default class Media {
queueMoveItemToNewIndex(
itemId: number,
newIndex: number,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
// Return early if not in queue
if (!this.items) {
@@ -268,7 +265,7 @@ export default class Media {
// New index must not be negative
if (newIndex < 0) {
if (errorCallback) {
errorCallback(new _Error(ErrorCode.INVALID_PARAMETER));
errorCallback(new CastError(ErrorCode.INVALID_PARAMETER));
}
} else if (newIndex == itemIndex) {
if (successCallback) {
@@ -298,8 +295,8 @@ export default class Media {
}
queueNext(
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
const jumpRequest = new QueueJumpRequest();
jumpRequest.jump = 1;
@@ -315,8 +312,8 @@ export default class Media {
}
queuePrev(
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
const jumpRequest = new QueueJumpRequest();
jumpRequest.jump = -1;
@@ -333,8 +330,8 @@ export default class Media {
queueRemoveItem(
itemId: number,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
const item = this.items?.find(item => item.itemId === itemId);
if (item) {
@@ -348,8 +345,8 @@ export default class Media {
queueRemoveItems(
queueRemoveItemsRequest: QueueRemoveItemsRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...queueRemoveItemsRequest,
@@ -364,8 +361,8 @@ export default class Media {
queueReorderItems(
queueReorderItemsRequest: QueueReorderItemsRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...queueReorderItemsRequest,
@@ -380,8 +377,8 @@ export default class Media {
queueSetRepeatMode(
repeatMode: string,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
const setPropertiesRequest = new QueueSetPropertiesRequest();
setPropertiesRequest.repeatMode = repeatMode;
@@ -398,8 +395,8 @@ export default class Media {
queueUpdateItems(
queueUpdateItemsRequest: QueueUpdateItemsRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...queueUpdateItemsRequest,
@@ -413,8 +410,8 @@ export default class Media {
seek(
seekRequest: SeekRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...seekRequest,
@@ -427,8 +424,8 @@ export default class Media {
setVolume(
volumeRequest: VolumeRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
this._sendMediaMessage({
...volumeRequest,
@@ -441,8 +438,8 @@ export default class Media {
stop(
stopRequest?: StopRequest,
successCallback?: SuccessCallback,
errorCallback?: ErrorCallback
successCallback?: () => void,
errorCallback?: (err: CastError) => void
) {
if (!stopRequest) {
stopRequest = new StopRequest();