polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
690 lines • 31.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChannelHandler = void 0;
const base_handler_1 = require("./base.handler");
const channel_service_1 = require("../services/channel.service");
const errors_1 = require("../utils/errors");
class ChannelHandler extends base_handler_1.BaseHandler {
constructor(authConfig, serviceConfig) {
super();
this.channelService = new channel_service_1.ChannelService(authConfig, serviceConfig);
}
async create(options) {
return this.executeWithErrorHandling(async () => {
this.validateCreateOptions(options);
const request = this.transformToCreateRequest(options);
const channel = await this.channelService.createChannel(request);
this.displayChannelCreated(channel, options.output);
}, 'channel.create');
}
async listChannels(options = {}) {
return this.executeWithErrorHandling(async () => {
this.validateListOptions(options);
const request = this.transformToListRequest(options);
const channels = await this.channelService.listChannels(request);
this.displayChannelsList(channels, request, options.output);
}, 'channel.list');
}
async getChannelDetail(options) {
return this.executeWithErrorHandling(async () => {
this.validateGetOptions(options);
const request = this.transformToDetailRequest(options);
const channelDetail = await this.channelService.getChannelDetail(request);
this.displayChannelDetail(channelDetail, options.output);
}, 'channel.get');
}
async updateChannel(options) {
return this.executeWithErrorHandling(async () => {
this.validateUpdateOptions(options);
const request = this.transformToUpdateRequest(options);
await this.channelService.updateChannel(request);
this.displayChannelUpdated(options);
}, 'channel.update');
}
async deleteChannel(options) {
return this.executeWithErrorHandling(async () => {
this.validateSingleDeleteOptions(options);
if (!options.force) {
const { confirmDeletion } = await Promise.resolve().then(() => __importStar(require('../utils/confirmation')));
const confirmed = await confirmDeletion(`Are you sure you want to delete channel '${options.channelId}'? This action cannot be undone.`, 'yes');
if (!confirmed) {
this.displayInfo('Channel deletion cancelled by user');
return;
}
}
await this.channelService.deleteChannel(options.channelId);
this.displayChannelDeleted(options);
}, 'channel.delete');
}
async deleteChannels(options) {
return this.executeWithErrorHandling(async () => {
this.validateDeleteOptions(options);
const request = this.transformToDeleteRequest(options);
await this.channelService.batchDeleteChannels(request);
this.displayChannelsDeleted(options);
}, 'channel.delete');
}
validateCreateOptions(options) {
const errors = [];
if (!options.name || typeof options.name !== 'string') {
errors.push('Channel name is required and must be a string');
}
else if (options.name.trim().length === 0) {
errors.push('Channel name cannot be empty');
}
else if (options.name.length > 100) {
errors.push('Channel name cannot exceed 100 characters');
}
if (options.description !== undefined) {
if (typeof options.description !== 'string') {
errors.push('Description must be a string');
}
else if (options.description.length > 500) {
errors.push('Description cannot exceed 500 characters');
}
}
if (options.maxViewers !== undefined) {
if (typeof options.maxViewers !== 'number' || options.maxViewers < 0) {
errors.push('Max viewers must be a non-negative number');
}
else if (options.maxViewers > 100000) {
errors.push('Max viewers cannot exceed 100,000');
}
}
if (options.autoRecord !== undefined && typeof options.autoRecord !== 'boolean') {
errors.push('Auto record must be a boolean value');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (options.scene !== undefined) {
const validScenes = ['topclass', 'cloudclass', 'telecast', 'akt'];
if (!validScenes.includes(options.scene)) {
errors.push(`Scene must be one of: ${validScenes.join(', ')}`);
}
}
if (options.template !== undefined) {
const validTemplates = ['ppt', 'video'];
if (!validTemplates.includes(options.template)) {
errors.push(`Template must be one of: ${validTemplates.join(', ')}`);
}
}
if (options.password !== undefined) {
if (typeof options.password !== 'string') {
errors.push('Password must be a string');
}
else if (options.password.length < 6 || options.password.length > 16) {
errors.push('Password must be 6-16 characters long');
}
else if (!/^[a-zA-Z0-9]+$/.test(options.password)) {
errors.push('Password must contain only alphanumeric characters');
}
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel creation options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
transformToCreateRequest(options) {
const request = {
name: options.name.trim(),
newScene: options.scene || 'topclass',
template: options.template || 'ppt'
};
if (options.password) {
request.channelPasswd = options.password;
}
return request;
}
displayChannelCreated(channel, format = 'table') {
const displayData = {
channelId: channel.channelId,
name: channel.name,
userId: channel.userId,
password: channel.channelPasswd ? '***' : '-',
scene: channel.newScene,
template: channel.template,
status: channel.status || 'waiting',
created: channel.createdAt ? channel.createdAt.toLocaleString() : 'Just now'
};
this.displaySuccess('Channel created successfully', displayData, format);
if (format === 'table') {
this.displayInfo('Channel is ready for streaming configuration');
if (channel.channelPasswd) {
this.displayWarning('Channel password has been set - remember to provide it to viewers');
}
}
}
validateListOptions(options) {
const errors = [];
if (options.page !== undefined) {
if (typeof options.page !== 'number' || !Number.isInteger(options.page) || options.page < 1) {
errors.push('Page must be a positive integer (minimum 1)');
}
}
if (options.limit !== undefined) {
if (typeof options.limit !== 'number' || !Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100) {
errors.push('Limit must be an integer between 1 and 100');
}
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (options.categoryId !== undefined && (typeof options.categoryId !== 'string' || options.categoryId.trim().length === 0)) {
errors.push('Category ID must be a non-empty string');
}
if (options.keyword !== undefined && (typeof options.keyword !== 'string' || options.keyword.trim().length === 0)) {
errors.push('Keyword must be a non-empty string');
}
if (options.labelId !== undefined && (typeof options.labelId !== 'string' || options.labelId.trim().length === 0)) {
errors.push('Label ID must be a non-empty string');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel list options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateGetOptions(options) {
const errors = [];
if (!options.channelId) {
errors.push('Channel ID is required');
}
else if (typeof options.channelId !== 'string') {
errors.push('Channel ID must be a string');
}
else if (options.channelId.trim().length === 0) {
errors.push('Channel ID cannot be empty');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel get options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateUpdateOptions(options) {
const errors = [];
if (!options.channelId) {
errors.push('Channel ID is required');
}
else if (typeof options.channelId !== 'string') {
errors.push('Channel ID must be a string');
}
else if (options.channelId.trim().length === 0) {
errors.push('Channel ID cannot be empty');
}
const updateFields = [
'name', 'description', 'publisher', 'password', 'maxViewers',
'autoRecord', 'startTime', 'endTime', 'pageView', 'likes',
'coverImg', 'splashImg'
];
const hasUpdateField = updateFields.some(field => options[field] !== undefined);
if (!hasUpdateField) {
errors.push('At least one update parameter must be provided');
}
if (options.name !== undefined) {
if (typeof options.name !== 'string') {
errors.push('Channel name must be a string');
}
else if (options.name.trim().length === 0) {
errors.push('Channel name cannot be empty');
}
else if (options.name.length > 100) {
errors.push('Channel name cannot exceed 100 characters');
}
}
if (options.description !== undefined) {
if (typeof options.description !== 'string') {
errors.push('Description must be a string');
}
else if (options.description.length > 500) {
errors.push('Description cannot exceed 500 characters');
}
}
if (options.publisher !== undefined) {
if (typeof options.publisher !== 'string') {
errors.push('Publisher must be a string');
}
}
if (options.password !== undefined) {
if (typeof options.password !== 'string') {
errors.push('Password must be a string');
}
else if (options.password.length < 6 || options.password.length > 16) {
errors.push('Password must be 6-16 characters long');
}
else if (!/^[a-zA-Z0-9]+$/.test(options.password)) {
errors.push('Password must contain only alphanumeric characters');
}
}
if (options.maxViewers !== undefined) {
if (typeof options.maxViewers !== 'number' || options.maxViewers <= 0) {
errors.push('Max viewers must be a positive number');
}
}
if (options.autoRecord !== undefined && typeof options.autoRecord !== 'boolean') {
errors.push('Auto record must be a boolean value');
}
if (options.startTime !== undefined) {
if (typeof options.startTime !== 'number' || options.startTime < 0) {
errors.push('Start time must be a non-negative timestamp');
}
}
if (options.endTime !== undefined) {
if (typeof options.endTime !== 'number' || options.endTime < 0) {
errors.push('End time must be a non-negative timestamp');
}
if (options.startTime !== undefined && options.endTime <= options.startTime) {
errors.push('End time must be greater than start time');
}
}
if (options.pageView !== undefined) {
if (typeof options.pageView !== 'number' || options.pageView < 0) {
errors.push('Page view count must be a non-negative number');
}
}
if (options.likes !== undefined) {
if (typeof options.likes !== 'number' || options.likes < 0) {
errors.push('Likes count must be a non-negative number');
}
}
if (options.coverImg !== undefined && typeof options.coverImg !== 'string') {
errors.push('Cover image URL must be a string');
}
if (options.splashImg !== undefined && typeof options.splashImg !== 'string') {
errors.push('Splash image URL must be a string');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel update options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
transformToUpdateRequest(options) {
const request = {
channelId: options.channelId.trim()
};
const basicSetting = {};
let hasBasicSetting = false;
if (options.name !== undefined) {
basicSetting.name = options.name.trim();
hasBasicSetting = true;
}
if (options.description !== undefined) {
basicSetting.desc = options.description;
hasBasicSetting = true;
}
if (options.publisher !== undefined) {
basicSetting.publisher = options.publisher;
hasBasicSetting = true;
}
if (options.password !== undefined) {
basicSetting.channelPasswd = options.password;
hasBasicSetting = true;
}
if (options.maxViewers !== undefined) {
basicSetting.maxViewer = options.maxViewers;
hasBasicSetting = true;
}
if (options.startTime !== undefined) {
basicSetting.startTime = options.startTime;
hasBasicSetting = true;
}
if (options.endTime !== undefined) {
basicSetting.endTime = options.endTime;
hasBasicSetting = true;
}
if (options.pageView !== undefined) {
basicSetting.pageView = options.pageView;
hasBasicSetting = true;
}
if (options.likes !== undefined) {
basicSetting.likes = options.likes;
hasBasicSetting = true;
}
if (options.coverImg !== undefined) {
basicSetting.coverImg = options.coverImg;
hasBasicSetting = true;
}
if (options.splashImg !== undefined) {
basicSetting.splashImg = options.splashImg;
hasBasicSetting = true;
}
if (hasBasicSetting) {
request.basicSetting = basicSetting;
}
return request;
}
displayChannelUpdated(options) {
const updateSummary = [];
if (options.name !== undefined)
updateSummary.push(`Name: ${options.name}`);
if (options.description !== undefined)
updateSummary.push(`Description: ${options.description}`);
if (options.publisher !== undefined)
updateSummary.push(`Publisher: ${options.publisher}`);
if (options.password !== undefined)
updateSummary.push('Password: ***');
if (options.maxViewers !== undefined)
updateSummary.push(`Max Viewers: ${options.maxViewers}`);
if (options.startTime !== undefined)
updateSummary.push(`Start Time: ${new Date(options.startTime).toLocaleString()}`);
if (options.endTime !== undefined)
updateSummary.push(`End Time: ${new Date(options.endTime).toLocaleString()}`);
if (options.pageView !== undefined)
updateSummary.push(`Page Views: ${options.pageView}`);
if (options.likes !== undefined)
updateSummary.push(`Likes: ${options.likes}`);
if (options.coverImg !== undefined)
updateSummary.push(`Cover Image: ${options.coverImg}`);
if (options.splashImg !== undefined)
updateSummary.push(`Splash Image: ${options.splashImg}`);
this.displaySuccess(`Channel ${options.channelId} updated successfully`);
if (updateSummary.length > 0) {
this.displayInfo('Updated fields:');
updateSummary.forEach(summary => this.displayInfo(` • ${summary}`));
}
if (options.password) {
this.displayWarning('Channel password has been updated - remember to provide it to viewers');
}
}
validateSingleDeleteOptions(options) {
const errors = [];
if (!options.channelId) {
errors.push('Channel ID is required');
}
else if (typeof options.channelId !== 'string') {
errors.push('Channel ID must be a string');
}
else if (options.channelId.trim().length === 0) {
errors.push('Channel ID cannot be empty');
}
if (options.force !== undefined && typeof options.force !== 'boolean') {
errors.push('Force flag must be a boolean value');
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel delete options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
validateDeleteOptions(options) {
const errors = [];
if (!options.channelIds) {
errors.push('Channel IDs are required');
}
else if (!Array.isArray(options.channelIds)) {
errors.push('Channel IDs must be an array');
}
else if (options.channelIds.length === 0) {
errors.push('At least one channel ID must be provided');
}
else if (options.channelIds.length > 100) {
errors.push('Cannot delete more than 100 channels at once');
}
else {
for (let i = 0; i < options.channelIds.length; i++) {
const channelId = options.channelIds[i];
if (typeof channelId !== 'string') {
errors.push(`Channel ID at position ${i + 1} must be a string`);
}
else if (channelId.trim().length === 0) {
errors.push(`Channel ID at position ${i + 1} cannot be empty`);
}
}
}
if (options.output !== undefined && !['table', 'json'].includes(options.output)) {
errors.push('Output format must be either "table" or "json"');
}
if (errors.length > 0) {
throw new errors_1.PolyVValidationError(`Channel delete options validation failed: ${errors.join(', ')}`, 'options', options, 'validation_failed');
}
}
transformToDeleteRequest(options) {
return {
channelIds: options.channelIds.map((id) => id.trim())
};
}
displayChannelsDeleted(options) {
const channelCount = options.channelIds.length;
const channelText = channelCount === 1 ? 'channel' : 'channels';
this.displaySuccess(`Successfully deleted ${channelCount} ${channelText}`);
if (options.output === 'json') {
const jsonData = {
deleted: true,
channelIds: options.channelIds,
count: channelCount
};
this.displayData(jsonData, 'json');
}
else {
this.displayInfo('Deleted channels:');
options.channelIds.forEach((channelId) => {
this.displayInfo(` • Channel ${channelId}`);
});
}
}
displayChannelDeleted(options) {
this.displaySuccess(`Successfully deleted channel ${options.channelId}`);
if (options.output === 'json') {
const jsonData = {
deleted: true,
channelId: options.channelId,
timestamp: new Date().toISOString()
};
this.displayData(jsonData, 'json');
}
else {
this.displayInfo(`Channel ${options.channelId} has been permanently deleted`);
this.displayWarning('This action cannot be undone');
}
}
transformToListRequest(options) {
const request = {};
if (options.page !== undefined) {
request.page = options.page;
}
if (options.limit !== undefined) {
request.limit = options.limit;
}
if (options.categoryId) {
request.categoryId = options.categoryId.trim();
}
if (options.keyword) {
request.keyword = options.keyword.trim();
}
if (options.labelId) {
request.labelId = options.labelId.trim();
}
return request;
}
transformToDetailRequest(options) {
return {
channelId: options.channelId.trim()
};
}
displayChannelsList(channels, request, format = 'table') {
if (channels.length === 0) {
this.displayInfo('No channels found');
return;
}
if (format === 'json') {
const jsonData = {
channels: channels.map(channel => ({
channelId: channel.channelId,
name: channel.name,
status: channel.status,
scene: channel.scene,
template: channel.template,
createdAt: channel.createdAt.toISOString(),
description: channel.description,
maxViewers: channel.maxViewers
})),
pagination: {
page: request.page ?? 1,
limit: request.limit ?? 20,
total: channels.length
}
};
this.displayData(jsonData, 'json');
}
else {
const tableData = channels.map(channel => ({
'Channel ID': channel.channelId,
'Name': channel.name,
'Status': channel.status,
'Scene': channel.scene,
'Template': channel.template,
'Created': channel.createdAt.toLocaleDateString()
}));
this.displaySuccess(`Found ${channels.length} channels`, tableData, 'table');
const page = request.page ?? 1;
const limit = request.limit ?? 20;
this.displayInfo(`Page ${page}, showing up to ${limit} channels per page`);
}
}
displayChannelDetail(channelDetail, format = 'table') {
if (format === 'json') {
const jsonData = {
channelId: channelDetail.channelId,
name: channelDetail.name,
scene: channelDetail.scene,
newScene: channelDetail.newScene,
template: channelDetail.template,
channelPasswd: channelDetail.channelPasswd ? '***masked***' : null,
publisher: channelDetail.publisher,
startTime: channelDetail.startTime,
endTime: channelDetail.endTime,
pureRtcEnabled: channelDetail.pureRtcEnabled,
pageView: channelDetail.pageView,
likes: channelDetail.likes,
coverImg: channelDetail.coverImg,
splashImg: channelDetail.splashImg,
splashEnabled: channelDetail.splashEnabled,
bgImg: channelDetail.bgImg,
desc: channelDetail.desc,
consultingMenuEnabled: channelDetail.consultingMenuEnabled,
maxViewerRestrict: channelDetail.maxViewerRestrict,
maxViewer: channelDetail.maxViewer,
watchStatus: channelDetail.watchStatus,
watchStatusText: channelDetail.watchStatusText,
userCategory: channelDetail.userCategory,
authSettings: channelDetail.authSettings,
linkMicLimit: channelDetail.linkMicLimit,
createdAccountId: channelDetail.createdAccountId,
createdAccountEmail: channelDetail.createdAccountEmail,
createdTime: channelDetail.createdTime,
labelData: channelDetail.labelData,
clientAloneTemplateBackgroundUrl: channelDetail.clientAloneTemplateBackgroundUrl,
liveCdnBackgroundUrl: channelDetail.liveCdnBackgroundUrl,
pushUrl: channelDetail.pushUrl ? '***masked***' : null,
pushSecret: channelDetail.pushSecret ? '***masked***' : null,
streamType: channelDetail.streamType,
onlyOutEnabled: channelDetail.onlyOutEnabled
};
this.displayData(jsonData, 'json');
}
else {
this.displaySuccess(`Channel Details: ${channelDetail.name}`, null, 'table');
const basicInfo = {
'Channel ID': channelDetail.channelId.toString(),
'Name': channelDetail.name,
'Publisher': channelDetail.publisher || '-',
'Description': channelDetail.desc || '-',
'Status': `${channelDetail.watchStatus} (${channelDetail.watchStatusText})`,
'Scene': channelDetail.newScene !== 'undefined' ? channelDetail.newScene : channelDetail.scene,
'Template': channelDetail.template !== 'undefined' ? channelDetail.template : '-'
};
this.displayInfo('📋 Basic Information');
this.displayData(basicInfo, 'table');
const configInfo = {
'Channel Password': channelDetail.channelPasswd ? 'Set (***masked***)' : 'Not set',
'Pure RTC': channelDetail.pureRtcEnabled === 'Y' ? 'Enabled' : 'Disabled',
'Max Viewer Restrict': channelDetail.maxViewerRestrict === 'Y' ? 'Enabled' : 'Disabled',
'Max Viewers': channelDetail.maxViewer > 0 ? channelDetail.maxViewer.toString() : 'Unlimited',
'Link Mic Limit': channelDetail.linkMicLimit.toString(),
'Consulting Menu': channelDetail.consultingMenuEnabled === 'Y' ? 'Enabled' : 'Disabled',
'Splash Page': channelDetail.splashEnabled === 'Y' ? 'Enabled' : 'Disabled'
};
this.displayInfo('⚙️ Configuration');
this.displayData(configInfo, 'table');
const statsInfo = {
'Page Views': channelDetail.pageView.toString(),
'Likes': channelDetail.likes.toString(),
'Start Time': channelDetail.startTime > 0 ? new Date(channelDetail.startTime).toLocaleString() : 'Not set',
'End Time': channelDetail.endTime > 0 ? new Date(channelDetail.endTime).toLocaleString() : 'Not set',
'Created Time': new Date(channelDetail.createdTime).toLocaleString(),
'Created By': channelDetail.createdAccountEmail || channelDetail.createdAccountId
};
this.displayInfo('📊 Statistics & Timing');
this.displayData(statsInfo, 'table');
if (channelDetail.userCategory) {
const categoryInfo = {
'Category ID': channelDetail.userCategory.categoryId.toString(),
'Category Name': channelDetail.userCategory.categoryName,
'Rank': channelDetail.userCategory.rank.toString()
};
this.displayInfo('📁 Category Information');
this.displayData(categoryInfo, 'table');
}
if (channelDetail.authSettings && channelDetail.authSettings.length > 0) {
const authSummary = channelDetail.authSettings.map((auth) => ({
'Rank': auth.rank.toString(),
'Type': auth.authType,
'Enabled': auth.enabled,
'Global Setting': auth.globalSettingEnabled
}));
this.displayInfo('🔐 Authentication Settings');
this.displayData(authSummary, 'table');
}
if (channelDetail.labelData && channelDetail.labelData.length > 0) {
this.displayInfo(`Labels: ${channelDetail.labelData.join(', ')}`);
}
const urls = [];
if (channelDetail.coverImg)
urls.push(`Cover Image: ${channelDetail.coverImg}`);
if (channelDetail.splashImg)
urls.push(`Splash Image: ${channelDetail.splashImg}`);
if (channelDetail.bgImg)
urls.push(`Background Image: ${channelDetail.bgImg}`);
if (urls.length > 0) {
this.displayInfo('Images:\n' + urls.join('\n'));
}
}
}
}
exports.ChannelHandler = ChannelHandler;
//# sourceMappingURL=channel.handler.js.map