UNPKG

@openveo/publish

Version:
297 lines (246 loc) 10.3 kB
'use strict'; /** * @module publish/providers/mediaPlatforms/tls/TlsProvider */ var path = require('path'); var util = require('util'); var nanoid = require('nanoid').nanoid; var async = require('async'); var openVeoApi = require('@openveo/api'); var MediaPlatformProvider = process.requirePublish('app/server/providers/mediaPlatforms/MediaPlatformProvider.js'); var PropertyProvider = process.requirePublish('app/server/providers/PropertyProvider.js'); var TlsClient = process.requirePublish('app/server/providers/mediaPlatforms/tls/TlsClient.js'); var ResourceFilter = openVeoApi.storages.ResourceFilter; /** * Defines a TlsProvider to interact with TLS platform. * * @class TlsProvider * @extends module:publish/providers/mediaPlatforms/MediaPlatformProvider~MediaPlatformProvider * @constructor * @param {Object} providerConf TLS configuration * @param {String} providerConf.nfsPath The absolute path of the NFS directory shared with TLS * @param {String} providerConf.mediaDirectoryPath The path of the directory where to store TLS medias. This is * relative to nfsPath * @param {String} providerConf.accessToken The TLS API authentication token * @param {String} providerConf.url The TLS web service URL * @param {String} [providerConf.certificate] The absolute path of the full certificate chain if the top level * authority is not part of system well known authorities */ function TlsProvider(providerConf) { TlsProvider.super_.call(this, providerConf); if (!providerConf.nfsPath || typeof providerConf.nfsPath !== 'string') throw new TypeError('Invalid NFS path: ' + providerConf.nfsPath); Object.defineProperties(this, /** @lends module:publish/providers/mediaPlatforms/tls/TlsProvider~TlsProvider */ { /** * The TLS client to interact with TLS web service. * * @type {module:publish/providers/mediaPlatforms/tls/TlsClient~TlsClient} * @instance * @readonly */ client: { value: new TlsClient(providerConf.url, providerConf.accessToken, providerConf.certificate) }, /** * The absolute path to the directory containing medias. * * @type {String} * @instance * @readonly */ mediaDirectoryPath: { value: path.join(providerConf.nfsPath, providerConf.mediaDirectoryPath || '') } } ); } module.exports = TlsProvider; util.inherits(TlsProvider, MediaPlatformProvider); /** * Uploads a media to the TLS platform. * * Media is uploaded on a local directory as OpenVeo and TLS share a common directory through NFS. * * @param {String} mediaFilePath The absolute path of the media to upload * @param {module:publish/providers/mediaPlatforms/MediaPlatformProvider~MediaPlatformProvider~uploadCallback} callback * The function to call when it's done */ TlsProvider.prototype.upload = function(mediaFilePath, callback) { var self = this; var mediaId = nanoid(); var mediaFileName = 'video.mp4'; var mediaFinalPath = path.join(this.mediaDirectoryPath, mediaId, mediaFileName); // Create media directory and copy media file to its final directory openVeoApi.fileSystem.copy(mediaFilePath, mediaFinalPath, function(error) { if (error) return callback(error); // Send media information to TLS self.client.put('videos/' + mediaId, { path: path.join(self.conf.mediaDirectoryPath, mediaId, mediaFileName) }).then(function(response) { callback(null, mediaId); }).catch(function(error) { // Something went wrong, remove the media directory openVeoApi.fileSystem.rm(path.join(self.mediaDirectoryPath, mediaId), function(rmError) { callback(rmError || error); }); }); }); }; /** * Gets information about medias hosted by TLS. * * @param {Array} mediasIds The TLS ids of the medias * @param {Array} expectedMediasHeights The expected medias heights in the same order as medias ids. This is not used * for TLS provider as TLS doesn't transcode medias * @param {module:publish/providers/mediaPlatforms/MediaPlatformProvider~MediaPlatformProvider~getMediaInfoCallback} * callback The function to call when it's done */ TlsProvider.prototype.getMediasInfo = function(mediasIds, expectedMediasHeights, callback) { var self = this; var parallel = []; var infos = {sources: [], available: true}; mediasIds.forEach(function(mediaId) { parallel.push(function(callback) { // Get media information from TLS return self.client.get('videos/' + mediaId).then(function(response) { if (!response.available) infos.available = false; infos.sources.push({ adaptive: [ { mimeType: 'application/x-mpegURL', link: response.link } ] }); callback(); }).catch(callback); }); }); async.parallel(parallel, function(error) { if (error) return callback(error); callback(null, infos); }); }; /** * Removes medias from TLS platform. * * @param {Array} mediaIds TLS media ids to remove * @param {callback} callback The function to call when it's done */ TlsProvider.prototype.remove = function(mediaIds, callback) { var self = this; var asyncFunctions = []; mediaIds.forEach(function(mediaId) { asyncFunctions.push(function(callback) { // First send remove instruction to TLS self.client.delete('videos/' + mediaId).then(function(reponse) { // Secondly remove media from local file system openVeoApi.fileSystem.rm(path.join(self.mediaDirectoryPath, mediaId), callback); }).catch(callback); }); }); async.series(asyncFunctions, function(error) { callback(error); }); }; /** * Updates a media resources on the platform. * * If media has several resources on the platform, the same update will be performed for all resources. * Actually only the media title and media custom properties are synchronized with TLS. * * @param {Object} media The media * @param {Array} media.mediaId The list of media resource ids * @param {Object} data The datas to update * @param {String} [data.title] The media title * @param {Object} [data.properties] The media custom properties with id / value pairs, custom properties corresponding * to the one in TLS configuration will be updated, others won't * @param {Boolean} force true to force the update even if title and properties haven't changed, false otherwise * @param {callback} callback The function to call when it's done */ TlsProvider.prototype.update = function(media, data, force, callback) { if (!data.title && (!data.properties || !Object.keys(data.properties).length)) return callback(); var self = this; var asyncFunctions = []; var properties = {}; var settings; // Get TLS settings asyncFunctions.push(function(callback) { process.api.getCoreApi().settingProvider.getOne( new ResourceFilter().equal('id', 'publish-tls'), null, function(error, tlsSettings) { settings = tlsSettings && tlsSettings.value && tlsSettings.value.properties; callback(error); } ); }); // Get more information about the custom properties being updated asyncFunctions.push(function(callback) { if (!data.properties || !settings || !settings.length) return callback(); var propertyProvider = new PropertyProvider(process.api.getCoreApi().getDatabase()); propertyProvider.getAll( new ResourceFilter().in('id', Object.keys(data.properties)), ['id', 'name', 'type'], {id: 'desc'}, function(error, fetchedProperties) { if (error) return callback(error); // TLS expects the name of the custom property associated to its value // Find the name of each custom property being updated for (var id in data.properties) { for (var j = 0; j < fetchedProperties.length; j++) { var fetchedProperty = fetchedProperties[j]; if (fetchedProperty.id === id) { // Property found // Only custom properties defined in TLS settings can be updated if (settings.indexOf(id) === -1) break; var actualValue = media.properties && media.properties[id]; // Make sure property value has changed before doing anything (force by passes this verification) if (fetchedProperty.type === PropertyProvider.TYPES.LIST && !force) { actualValue = media.properties ? media.properties[id] || [] : []; if (openVeoApi.util.intersectArray(data.properties[id], actualValue).length) break; } else if (data.properties[id] === actualValue && !force) break; // TLS expects dates in their literal forms, not a timestamp // Convert values of custom properties of type DATE_TIME into date literals if (fetchedProperty.type === PropertyProvider.TYPES.DATE_TIME) properties[fetchedProperty.name] = new Date(data.properties[id]); else properties[fetchedProperty.name] = data.properties[id]; break; } } } callback(error); } ); }); // Update resources on TLS platform media.mediaId.forEach(function(mediaId) { asyncFunctions.push(function(callback) { var modifications = {}; var callbackHasBeenCalled = false; // Make sure that title has changed if defined (force by passes this verification) // If neither title nor properties have changed, there is nothing more to do if ((!data.title || (data.title === media.title && !force)) && !Object.keys(properties).length) { return callback(); } if (data.title) modifications.title = data.title; Object.assign(modifications, properties); self.client.patch('videos/' + mediaId, modifications).then(function() { if (!callbackHasBeenCalled) (callbackHasBeenCalled = true) && callback(); }).catch(function(error) { if (!callbackHasBeenCalled) (callbackHasBeenCalled = true) && callback(error); else throw error; }); }); }); async.series(asyncFunctions, function(error) { callback(error); }); };