Samrat_Sarkar | 2022-11-04 15:06:53 UTC | #1
Hi Team ,
I'm following this tutorial to bulk download a number of recordings using the Javascript SDK. https://developer.genesys.cloud/analyticsdatamanagement/recording/recordings-downloader#configure-sdk-settings
I have set up the javascript file in a nodejs environment . I want to download recordings from .ie org.
I am getting an error which I don't understand. Want your help to mitigate the error .
Below I have pasted the js file and the error .
This is the js file which I am executing :
// >> START recordings-downloader // Import built in libraries needed. const http = require('https'); const fs = require('fs');
let batchRequestBody = { batchDownloadRequestList: [] };
// Set Genesys Cloud objects const platformClient = require('purecloud-platform-client-v2'); const client = platformClient.ApiClient.instance;
// >> START recordings-downloader-step-4 // Create API instances const conversationsApi = new platformClient.ConversationsApi(); const recordingApi = new platformClient.RecordingApi(); // >> END recordings-downloader-step-4
// >> START recordings-downloader-step-1 // Get client credentials from environment variables const CLIENTID = process.env.GENESYSCLOUDCLIENTID; const CLIENTSECRET = process.env.GENESYSCLOUDCLIENTSECRET; const ORGREGION = process.env.GENESYSCLOUDREGION; // eg. useast1 const CLOUDENVIRONMENT = process.env.GENESYSCLOUDENVIRONMENT;
// >> START recordings-downloader-step-2 // Set environment //const environment = platformClient.PureCloudRegionHosts[ORGREGION]; const environment = CLOUDENVIRONMENT; if(environment) client.setEnvironment(environment); // >> END recordings-downloader-step-2 // >> END recordings-downloader-step-1
// >> START recordings-downloader-step-3 // OAuth input client.loginClientCredentialsGrant(CLIENTID, CLIENTSECRET) // >> END recordings-downloader-step-3 .then(() => { let dates = "2022-03-09T13:00:00.000Z/2022-03-10T00:00:00.000Z"; downloadAllRecordings(dates); })
.catch((err) => { // Handle failure response console.log(err); });
// >> START recordings-downloader-step-5 // Process and build the request for downloading the recordings // Get the conversations within the date interval and start adding them to batch request function downloadAllRecordings (dates) { console.log('Start batch request process');
let body = { interval: dates }; // Object | query
conversationsApi.postAnalyticsConversationsDetailsQuery(body) .then((conversationDetails) => { let conversationDetail = []; for (conversations of conversationDetails.conversations) { conversationDetail.push(addConversationRecordingsToBatch(conversations.conversationId)); } return Promise.all(conversationDetail); }) // Send a batch request and start polling for updates .then(() => { return recordingApi.postRecordingBatchrequests(batchRequestBody); }) // Start downloading the recording files individually .then((result) => { return getRecordingStatus(result); }) .then((completedBatchStatus) => { for (recording of completedBatchStatus.results) { // If there is an errorMsg skip the recording download if (recording.errorMsg) { console.log("Skipping this recording. Reason: " + recording.errorMsg) continue; } else { downloadRecording(recording); } } }) .catch((err) => { console.log('There was an error: '); console.error(err); }); } // >> END recordings-downloader-step-5
// >> START recordings-downloader-step-6 // Get all the recordings metadata of the conversation and add it to the global batch request object function addConversationRecordingsToBatch (conversationId) { return recordingApi.getConversationRecordingmetadata(conversationId) .then((recordingsData) => { // Iterate through every result, check if there are one or more recordingIds in every conversation for (recording of recordingsData) { let batchRequest = {}; batchRequest.conversationId = recording.conversationId; batchRequest.recordingId = recording.id; batchRequestBody.batchDownloadRequestList.push(batchRequest); console.log('Added ' + recording.conversationId + ' to batch request'); } }) .catch((err) => { console.log('There was a failure calling getConversationRecordingmetadata'); console.error(err); }); } // >> END recordings-downloader-step-6
// Plot conversationId and recordingId to request for batchdownload Recordings function getRecordingStatus (recordingBatchRequest) { return new Promise((resolve, reject) => { let recursiveRequest = () => { recordingApi.getRecordingBatchrequest(recordingBatchRequest.id) .then((result) => { if (result.expectedResultCount !== result.resultCount) { console.log('Batch Result Status:' + result.resultCount + '/' + result.expectedResultCount)
// Simple polling through recursion setTimeout(() => recursiveRequest(), 5000); } else { // Once result count reach expected. resolve(result); } }) .catch((err) => { console.log('There was a failure calling getRecordingBatchrequest'); console.error(err); reject(err); }); }; recursiveRequest(); }); }
// >> START recordings-downloader-step-7 // Get extension of every recording function getExtension (recording) { // Store the contentType to a variable that will be used later to determine the extension of recordings let contentType = recording.contentType; // Split the text and gets the extension that will be used for the recording let ext = contentType.split('/').slice(-1); ext = String(ext);
// For the JSON special case if (ext.length >= 4) { console.log('length' + ext.length); ext = ext.substring(0, 4); return ext; } else { return ext; } } // >> END recordings-downloader-step-7
// >> START recordings-downloader-step-8 // Download Recordings function downloadRecording (recording) { console.log('Downloading now. Please wait...'); let ext = getExtension(recording); let conversationId = recording.conversationId; let recordingId = recording.recordingId; let sourceURL = recording.resultUrl; let targetDirectory = '.'; let fileName = conversationId + '_' + recordingId;
const file = fs.createWriteStream((targetDirectory + fileName + '.' + ext)); http.get(sourceURL, function (response) { response.pipe(file); }); }
This is the console error I am getting : :thinking: :thinking:
[AxiosError: Request failed with status code 400] { code: 'ERRBADREQUEST', config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [Function: httpAdapter], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function] }, validateStatus: [Function: validateStatus], headers: { Accept: 'application/json, text/plain, /', 'Content-Type': 'application/x-www-form-urlencoded', Authorization: 'Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==', 'User-Agent': 'axios/0.27.2', 'Content-Length': 29 }, method: 'post', url: 'https://login.mypurecloud.com/oauth/token', data: 'granttype=clientcredentials' }, request: <ref *1> ClientRequest { _events: [Object: null prototype] { abort: [Function (anonymous)], aborted: [Function (anonymous)], connect: [Function (anonymous)], error: [Function (anonymous)], socket: [Function (anonymous)], timeout: [Function (anonymous)], prefinish: [Function: requestOnPrefinish] }, _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: true, chunkedEncoding: false, shouldKeepAlive: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: null, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: TLSSocket { _tlsOptions: [Object], _secureEstablished: true, _securePending: false, _newSessionPending: false, _controlReleased: true, secureConnecting: false, _SNICallback: null, servername: 'login.mypurecloud.com', alpnProtocol: false, authorized: true, authorizationError: null, encrypted: true, _events: [Object: null prototype], _eventsCount: 10, connecting: false, _hadError: false, _parent: null, _host: 'login.mypurecloud.com', _readableState: [ReadableState], _maxListeners: undefined, _writableState: [WritableState], allowHalfOpen: false, _sockname: null, _pendingData: null, _pendingEncoding: '', server: undefined, _server: null, ssl: [TLSWrap], _requestCert: true, _rejectUnauthorized: true, parser: null, httpMessage: [Circular *1], [Symbol(res)]: [TLSWrap], [Symbol(verified)]: true, [Symbol(pendingSession)]: null, [Symbol(asyncid_symbol)]: 8, [Symbol(kHandle)]: [TLSWrap], [Symbol(kSetNoDelay)]: false, [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: null, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(kCapture)]: false, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0, [Symbol(connect-options)]: [Object], [Symbol(RequestTimeout)]: undefined }, _header: 'POST /oauth/token HTTP/1.1\r\n' + 'Accept: application/json, text/plain, /\r\n' + 'Content-Type: application/x-www-form-urlencoded\r\n' + 'Authorization: Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Content-Length: 29\r\n' + 'Host: login.mypurecloud.com\r\n' + 'Connection: close\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: noopPendingOutput], agent: Agent { _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object], requests: {}, sockets: [Object], freeSockets: {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: Infinity, maxFreeSockets: 256, scheduling: 'lifo', maxTotalSockets: Infinity, totalSocketCount: 1, maxCachedSessions: 100, _sessionCache: [Object], [Symbol(kCapture)]: false }, socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/oauth/token', _ended: true, res: IncomingMessage { _readableState: [ReadableState], _events: [Object: null prototype], _eventsCount: 4, _maxListeners: undefined, socket: [TLSSocket], httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: true, headers: [Object], rawHeaders: [Array], trailers: {}, rawTrailers: [], aborted: false, upgrade: false, url: '', method: null, statusCode: 400, statusMessage: 'Bad Request', client: [TLSSocket], _consuming: false, _dumped: false, req: [Circular *1], responseUrl: 'https://login.mypurecloud.com/oauth/token', redirects: [], [Symbol(kCapture)]: false, [Symbol(RequestTimeout)]: undefined }, aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'login.mypurecloud.com', protocol: 'https:', _redirectable: Writable { _writableState: [WritableState], _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _options: [Object], _ended: true, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 29, _requestBodyBuffers: [], _onNativeResponse: [Function (anonymous)], _currentRequest: [Circular *1], currentUrl: 'https://login.mypurecloud.com/oauth/token', [Symbol(kCapture)]: false }, [Symbol(kCapture)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] { accept: [Array], 'content-type': [Array], authorization: [Array], 'user-agent': [Array], 'content-length': [Array], host: [Array] } }, response: { status: 400, statusText: 'Bad Request', headers: { date: 'Fri, 04 Nov 2022 12:04:45 GMT', 'content-type': 'application/json', 'content-length': '99', connection: 'close', 'inin-correlation-id': '795bee43-dfa4-4bba-687e-ad20fc42feb6', 'strict-transport-security': 'max-age=7776000', vary: 'Accept-Encoding' }, config: { transitional: [Object], adapter: [Function: httpAdapter], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: [Object], validateStatus: [Function: validateStatus], headers: [Object], method: 'post', url: 'https://login.mypurecloud.com/oauth/token', data: 'granttype=client_credentials' }, request: <ref *1> ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: true, chunkedEncoding: false, shouldKeepAlive: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: null, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: [TLSSocket], _header: 'POST /oauth/token HTTP/1.1\r\n' + 'Accept: application/json, text/plain, /\r\n' + 'Content-Type: application/x-www-form-urlencoded\r\n' + 'Authorization: Basic dW5kZWZpbmVkOnVuZGVmaW5lZA==\r\n' + 'User-Agent: axios/0.27.2\r\n' + 'Content-Length: 29\r\n' + 'Host: login.mypurecloud.com\r\n' + 'Connection: close\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: noopPendingOutput], agent: [Agent], socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/oauth/token', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'login.mypurecloud.com', protocol: 'https:', redirectable: [Writable], [Symbol(kCapture)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] }, data: { error: 'invalidclient', description: 'client not found', error_description: 'client not found' } } }
Process finished with exit code 0
tim.smith | 2022-11-10 19:35:58 UTC | #2
Samrat_Sarkar, post:1, topic:17069
data: {
error: 'invalid_client',
description: 'client not found',
error_description: 'client not found'
}
The OAuth client you're using either has a typo or doesn't exist in that region.
system | 2022-12-11 19:36:13 UTC | #3
This topic was automatically closed 31 days after the last reply. New replies are no longer allowed.
This post was migrated from the old Developer Forum.
ref: 17069