"""Lambda function module.""" import subprocess import config from src import constants from src.common import elastic_transcoder from src.common import s3 from src.common import status from src.common import util from src.common.constants import encoding_statuses from src.common.constants import errors from src.common.lambda_exceptions import LambdaError from src.common.lambda_exceptions import LambdaStatusError class WaveformError(LambdaStatusError): """Exception class for waveform generation errors.""" def _log_error(errs, key, bucket): status.send_encoding_status( status_name=encoding_statuses.ERROR, key=key, bucket=bucket, errors=errs ) def generate_waveform(input_asset_signed_url, file_type): """Call ows-asset post asset handlers. Args: input_asset_signed_url (str): Signed URL of the input asset. file_type (str): The file_type of the file. Returns: tuple: (stdout, stderr). """ try: get_file = subprocess.Popen( ['curl', input_asset_signed_url], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) gen_waveform = subprocess.Popen( [ config.BIN_PATH, '--input-format', file_type, '--output-format', constants.AUDIO_WAVEFORM_OUTPUT_FORMAT, '-b', constants.AUDIO_WAVEFORM_BITS, '-z', constants.AUDIO_WAVEFORM_ZOOM_LEVEL ], stdin=get_file.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) get_file.stdout.close() return gen_waveform.communicate() except subprocess.CalledProcessError as cpe: raise WaveformError( error_code=errors.AUDIO_WAVEFORM_ERROR_CODE, error_params={'message': cpe.stderr}) def handler(event, context): """Lambda entry point.""" try: bucket, key, asset_config, file_type = util.extract_event(event) status.send_encoding_status( status_name=encoding_statuses.PROCESSING, key=key, bucket=bucket ) input_asset_signed_url = s3.create_presigned_url(bucket, key) out, err = generate_waveform(input_asset_signed_url, file_type) out_filename = '{}.{}'.format(util.generate_unique_filename(), 'dat') s3.upload_file_from_stdout( std_out=out, key=out_filename, bucket=asset_config.get(config.OUTPUT_BUCKET_NAME), content_type='binary/octet-stream' ) result_asset = { 'key': out_filename, 'asset_type': 'DAT', 'asset_subtype': None, } elastic_transcoder.create_job( pipeline_id=asset_config.get(config.ELASTIC_TRANSCODER_ID), key=key, presets=[elastic_transcoder.PRESET_FLAC, elastic_transcoder.PRESET_MP3_320K]) status.send_encoding_status( status_name=encoding_statuses.WAVEFORM_COMPLETED, key=key, bucket=bucket, final_assets=[result_asset]) return {'status': 'OK', 'message': constants.AUDIO_WAVEFORM_GENERATION_SUCCESSFUL} except LambdaStatusError as error: config.logger.exception(str(error)) # if this is a malformed event but we have the key, we can send the error to the microserivce. # if the key is missing, then we cant post the status if 'key' in event: _log_error(error.errors, event.get('key'), event.get('bucket', None)) raise except LambdaError as error: config.logger.exception(str(error)) raise except Exception as error: config.logger.exception(str(error)) e = dict() msg = errors.ERROR_MESSAGES.get(errors.AUDIO_WAVEFORM_ERROR_CODE).format(**{'message': str(error)}) e[errors.AUDIO_WAVEFORM_ERROR_CODE] = msg _log_error(e, key, bucket) raise