Refactor Channels and Streams APIs: Update Member streams type to an array, enhance error handling in publishUri method, and add extractMediaType utility function.
This commit is contained in:
@@ -19,14 +19,12 @@ export type Member = {
|
|||||||
sessionId: string;
|
sessionId: string;
|
||||||
screenName: string;
|
screenName: string;
|
||||||
role: string;
|
role: string;
|
||||||
streams: [
|
streams: {
|
||||||
{
|
type: string;
|
||||||
type: string;
|
uri: string;
|
||||||
uri: string;
|
audioState: string;
|
||||||
audioState: string;
|
videoState: string;
|
||||||
videoState: string;
|
}[];
|
||||||
}
|
|
||||||
];
|
|
||||||
state: string;
|
state: string;
|
||||||
lastUpdate: number;
|
lastUpdate: number;
|
||||||
};
|
};
|
||||||
@@ -36,6 +34,16 @@ type GetChannelParams = {
|
|||||||
channelId?: string;
|
channelId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type KillChannelResponse = {
|
||||||
|
status: string;
|
||||||
|
killedMembers: Member[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type ForkChannelResponse = {
|
||||||
|
status: string;
|
||||||
|
members: Member[];
|
||||||
|
};
|
||||||
|
|
||||||
export class ChannelError extends Error {
|
export class ChannelError extends Error {
|
||||||
constructor(
|
constructor(
|
||||||
message: string,
|
message: string,
|
||||||
@@ -46,16 +54,6 @@ export class ChannelError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type KillChannelResponse = {
|
|
||||||
status: string;
|
|
||||||
killedMembers: Member[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type ForkChannelResponse = {
|
|
||||||
status: string;
|
|
||||||
members: Member[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Channels {
|
export class Channels {
|
||||||
private readonly _httpRequests: PCastHttpRequests;
|
private readonly _httpRequests: PCastHttpRequests;
|
||||||
private readonly _channelsByAlias: Map<ChannelAlias, Channel> = new Map();
|
private readonly _channelsByAlias: Map<ChannelAlias, Channel> = new Map();
|
||||||
@@ -195,22 +193,23 @@ export class Channels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async getPublishSourceStreamId(channelId: string, retryCount: number = 3): Promise<string | null> {
|
public async getPublishSourceStreamId(channelId: string, retryCount: number = 3): Promise<string | null> {
|
||||||
const retryCountRemaining = retryCount || 3;
|
|
||||||
const channelMembers = await this.getMembers(channelId);
|
const channelMembers = await this.getMembers(channelId);
|
||||||
|
console.log('channelMembers [%o] retryCount [%d]', channelMembers, retryCount);
|
||||||
if (channelMembers.length === 0) {
|
if (channelMembers.length === 0) {
|
||||||
if (retryCountRemaining > 0) {
|
if (retryCount > 0) {
|
||||||
return this.getPublishSourceStreamId(channelId, retryCountRemaining - 1);
|
|
||||||
|
return this.getPublishSourceStreamId(channelId, retryCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const presenter = channelMembers.find(member => member.role === 'Presenter');
|
const presenter = channelMembers.find(member => member.role === 'Presenter');
|
||||||
|
|
||||||
if (!presenter) {
|
if (!presenter) {
|
||||||
if (retryCountRemaining > 0) {
|
if (retryCount > 0) {
|
||||||
return this.getPublishSourceStreamId(channelId, retryCountRemaining - 1);
|
return this.getPublishSourceStreamId(channelId, retryCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -218,7 +217,7 @@ export class Channels {
|
|||||||
|
|
||||||
const publishSourceStreamIdRegExp = /pcast:\/\/.*\/([^?]*)/;
|
const publishSourceStreamIdRegExp = /pcast:\/\/.*\/([^?]*)/;
|
||||||
|
|
||||||
return presenter.streams[0].uri.match(publishSourceStreamIdRegExp)?.[1] ?? null;
|
return presenter.streams[0]?.uri?.match(publishSourceStreamIdRegExp)?.[1] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fork(sourceChannelId: string, destinationChannelId: string): Promise<ForkChannelResponse> {
|
public async fork(sourceChannelId: string, destinationChannelId: string): Promise<ForkChannelResponse> {
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ export class Streams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async publishUri(mediaUri: string, token: string) {
|
public async publishUri(mediaUri: string, token: string) {
|
||||||
const mediaType = mediaUri.split('.')?.at(-1);
|
const mediaType = this.extractMediaType(mediaUri);
|
||||||
|
|
||||||
if (!mediaType) {
|
if (!mediaType) {
|
||||||
throw new Error('Invalid media URI no media type found');
|
throw new Error('Invalid media URI: no media type found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this._httpRequests.request<IResponse<string>>(HttpMethod.PUT, `/stream/publish/uri/${mediaType}`, {
|
const response = await this._httpRequests.request<IResponse<string>>(HttpMethod.PUT, `/stream/publish/uri/${mediaType}`, {
|
||||||
@@ -26,4 +26,28 @@ export class Streams {
|
|||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extractMediaType(uri: string): string | undefined {
|
||||||
|
try {
|
||||||
|
const url = new URL(uri);
|
||||||
|
const pathname = url.pathname;
|
||||||
|
const lastDotIndex = pathname.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (lastDotIndex === -1 || lastDotIndex === pathname.length - 1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathname.slice(lastDotIndex + 1).toLowerCase();
|
||||||
|
} catch {
|
||||||
|
// Fallback for non-URL strings (e.g., relative paths)
|
||||||
|
const cleanUri = uri.split('?')[0]?.split('#')[0];
|
||||||
|
const lastDotIndex = cleanUri?.lastIndexOf('.');
|
||||||
|
|
||||||
|
if (lastDotIndex === -1 || lastDotIndex === cleanUri?.length || lastDotIndex === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleanUri?.slice(lastDotIndex + 1).toLowerCase() ?? undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user