def _before_requests(): """Executed before each request for this blueprint. Get the request form and session details. Returns: None|Response: In case of validation error, returns a Flask response, None otherwise. """ logger.info('API request [endpoint: "%s"]', request.endpoint) form = VectorEmbedForm( ) if request.endpoint[7:12] == 'embed' else VectorDetectForm() if not form.validate_on_submit(): return make_response(form.errors, 400) session = get_session() src_file = os.path.join(os.environ['INPUT_DIR'], form.original.data) g.src_file = src_file g.form = form g.session = session g.params = parse_read_options(form) if request.endpoint[7:12] != 'embed': g.test_file = os.path.join(os.environ['INPUT_DIR'], form.test.data) g.test_params = parse_read_options(form, prefix='test_')
def detect_message(): """**Flask POST rule**. Detect an invisible message. --- post: summary: Detect an invisible message. description: Detect an invisible message, previously embedded to the raster. tags: - Raster parameters: - idempotencyKey requestBody: required: true content: application/json: schema: rasterDetectForm responses: 200: promptDetectResponse 202: deferredResponse 400: validationErrorResponse """ logger.info('API request [endpoint: "%s"]', request.endpoint) form = RasterDetectForm() if not form.validate_on_submit(): return make_response(form.errors, 400) g.session = get_session() raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data) watermarked = os.path.join(os.environ['INPUT_DIR'], form.watermarked.data) if form.response.data == 'prompt': session, message, success, error_msg = raster_detect_process( g.session, raster, watermarked) if not success: db_update_queue_status(g.session['ticket'], completed=True, success=False, error_msg=error_msg) return make_response({'error': error_msg}, 500) db_update_queue_status(session['ticket'], completed=True, success=True, result=message) return make_response({'type': 'prompt', 'key': message}, 200) future = executor.submit(raster_detect_process, g.session, raster, watermarked) future.add_done_callback(async_callback) return make_response( { 'type': 'deferred', 'ticket': g.session['ticket'], 'statusUri': "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket']) }, 202)
def embed_message(): """**Flask POST rule**. Embed an invisible message. --- post: summary: Embed an invisible message. description: Embed an invisible message to raster. tags: - Raster parameters: - idempotencyKey requestBody: required: true content: application/json: schema: rasterEmbedMessageForm responses: 200: promptEmbedResponse 202: deferredResponse 400: validationErrorResponse """ logger.info('API request [endpoint: "%s"]', request.endpoint) form = RasterEmbedForm() if not form.validate_on_submit(): return make_response(form.errors, 400) g.session = get_session() raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data) if form.response.data == 'prompt': session, export, success, error_msg = raster_embed_process( 'message', g.session, raster, form.message.data) if not success: db_update_queue_status(g.session['ticket'], completed=True, success=False, error_msg=error_msg) return make_response({'error': error_msg}, 500) path = copy_to_output(export, session['ticket']) db_update_queue_status(session['ticket'], completed=True, success=True, result=path) return make_response({'type': 'prompt', 'path': path}, 200) future = executor.submit(raster_embed_process, 'message', g.session, raster, form.message.data) future.add_done_callback(async_callback) return make_response( { 'type': 'deferred', 'ticket': g.session['ticket'], 'statusUri': "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket']) }, 202)
def info(): """**Flask GET rule**. Get the running processes. --- get: summary: Get the running processes. description: Get the running processes among all sessions. tags: - Jobs responses: 200: description: The list of the running processes. content: application/json: schema: type: array items: description: Details of the process. type: object properties: ticket: type: string description: The ticket assigne to the process. example: caff960ab6f1627c11b0de3c6406a140 idempotencyKey: type: string description: The X-Idempotency-Key sent in the headers of the request (null if the request was not associated with an idempotency key). example: e5d16e99-dee1-4d16-acce-ca0f20a83a0a requestType: type: string description: Type of the request. initiated: type: string format: date-time description: The timestamp of the request. """ logger.info('API request [endpoint: "%s"]', request.endpoint) running = db_get_active_jobs() return make_response(jsonify(running), 200)
def embed_watermark(): """**Flask POST rule**. Embed a visible watermark. --- post: summary: Embed a visible watermark. description: Embed a visible watermark, placed according to the given parameters. tags: - Raster parameters: - idempotencyKey requestBody: required: true content: application/json: schema: rasterEmbedWatermarkForm responses: 200: promptEmbedResponse 202: deferredResponse 400: validationErrorResponse """ logger.info('API request [endpoint: "%s"]', request.endpoint) form = RasterVisibleEmbedForm() if not form.validate_on_submit(): return make_response(form.errors, 400) g.session = get_session() raster = os.path.join(os.environ['INPUT_DIR'], form.raster.data) watermark = os.path.join(os.environ['INPUT_DIR'], form.watermark.data) params = { 'transparency': form.transparency.data, 'fit': form.fit.data, 'position': form.position.data } if params['fit'] == 'tile': params['distance'] = (form.distance_x.data, form.distance_y.data) if form.response.data == 'prompt': session, export, success, error_msg = raster_embed_process( 'watermark', g.session, raster, watermark, **params) if not success: db_update_queue_status(g.session['ticket'], completed=True, success=False, error_msg=error_msg) return make_response({'error': error_msg}, 500) path = copy_to_output(export, session['ticket']) db_update_queue_status(session['ticket'], completed=True, success=True, result=path) return make_response({'type': 'prompt', 'path': path}, 200) future = executor.submit(raster_embed_process, 'watermark', g.session, raster, watermark, **params) future.add_done_callback(async_callback) return make_response( { 'type': 'deferred', 'ticket': g.session['ticket'], 'statusUri': "/jobs/status?ticket={ticket}".format(ticket=g.session['ticket']) }, 202)
def status(): """**Flask GET rule**. Returns the status of a process. --- get: summary: Returns the status of a process. description: Returns the status of the process identified by a ticket or idempotency key. tags: - Jobs parameters: - name: ticket in: query schema: type: string required: false description: The request ticket (required if *idempotency-key* is not given). - name: idempotency-key in: query schema: type: string required: false description: The idempotency-key sent with the request (required if *ticket* is not given). responses: 200: description: The process was found and the response contains its status details. content: application/json: schema: type: object properties: ticket: type: string description: Request ticket. example: caff960ab6f1627c11b0de3c6406a140 idempotencyKey: type: string description: The X-Idempotency-Key sent in the headers of the request (null if the request was not associated with an idempotency key). example: e5d16e99-dee1-4d16-acce-ca0f20a83a0a requestType: type: string enum: - ingest - export description: Type of the request. initiated: type: string format: date-time description: The timestamp of the request. executionTime: type: number format: float description: The execution time in seconds. example: 8.29 completed: type: boolean description: Whether the process has been completed. success: type: boolean description: Whether the process has been completed succesfully. errorMessage: type: string description: The error message in case of failure. resource: type: object description: The resource, in case the process result is a resource. properties: link: type: string description: The link to download a resource resulted from an export request; null for any other type of request. example: /download/my_dataset.tar.gz outputPath: type: string description: The relative path of the resource resulted from an export request in the output directory; null for any other type of request or if copy to the output directory was not requested. example: 2102/{token}/caff960ab6f1627c11b0de3c6406a140/my_dataset.tar.gz key: type: string description: The result of the process. example: 09061d7e-3b1a-4a14-bfa5-b65b9ce0412d 400: description: Both query parameters are missing. content: application/json: schema: type: object properties: status: type: string description: Error message example: One of 'ticket', 'idempotency-key' is required in query parameters. 404: description: The ticket or idempotency-key not found. content: application/json: schema: type: object properties: status: type: string description: Error message example: Process not found. """ ticket = request.args.get('ticket') key = request.args.get('idempotency-key') logger.info('API request [endpoint: "%s", ticket: "%s", idempotency-key: "%s"]', request.endpoint, ticket, key) if ticket is not None: queue = Queue().get(ticket=ticket) elif key is not None: queue = Queue().get(idempotency_key=key) else: return make_response({"status": "One of 'ticket', 'idempotency-key' is required in query parameters."}, 400) if queue is None: return make_response({"status": "Process not found."}, 404) resource = {'link': None, 'outputPath': None} key = None if queue['result'] is not None: if os.path.isfile(os.path.join(os.environ['OUTPUT_DIR'], queue['result'])): resource = {'link': '/download/{ticket}/{filename}'.format(ticket=queue['ticket'], filename=os.path.basename(queue['result'])), 'outputPath': queue['result']} else: key = queue['result'] info = { "ticket": queue['ticket'], "idempotencyKey": queue['idempotency_key'], "requestType": queue['request'], "initiated": queue['initiated'], "executionTime": queue['execution_time'], "completed": queue['completed'], "success": queue['success'], "errorMessage": queue['error_msg'], "resource": resource, "key": key } return make_response(info, 200)
def health(): """**Flask GET rule** Perform basic health checks. --- get: summary: Get health status. tags: - Misc responses: 200: description: An object with status information. content: application/json: schema: type: object properties: status: type: string enum: - OK - FAILED description: A status of 'OK' or 'FAILED'. details: type: object description: The reason of failure for each component, or 'OK' if not failed. properties: gdal: type: string example: OK filesystem: type: string example: OK db: type: string example: OK """ from osgeo import ogr logger.info('Performing health checks...') msg = {'gdal': 'OK', 'filesystem': 'OK', 'db': 'OK'} status = True for drv in ['CSV', 'GeoJSON', 'ESRI Shapefile']: if ogr.GetDriverByName(drv) is None: msg['gdal'] = 'GDAL is not properly installed.' status = False break for path in [os.environ['WORKING_DIR'], os.environ['OUTPUT_DIR']]: try: _checkDirectoryWritable(path) except Exception as e: msg['filesystem'] = str(e) status = False break try: _checkConnectToDB() except Exception as e: msg['db'] = str(e) status = False return make_response( { 'status': 'OK' if status else 'FAILED', 'details': msg }, 200)
def download(ticket, filename): """**Flask GET rule Download a resource. --- get: summary: Download a resource. tags: - Misc parameters: - name: ticket in: path schema: type: string description: The ticket of the request resulted in the resource. - name: filename in: path schema: type: string description: The requested file name. responses: 200: description: The requested file. content: application/x-tar: schema: type: string format: binary 404: description: Ticket not found. content: application/json: schema: type: object properties: status: type: string description: Error message example: Ticket not found. 410: description: Resource not available. content: application/json: schema: type: object properties: status: type: string description: Error message example: Resource not available. """ logger.info('API request [endpoint: "%s"]', request.endpoint) queue = Queue().get(ticket=ticket) if queue is None: return make_response({"status": "Ticket not found."}, 404) path = os.path.join(os.environ['OUTPUT_DIR'], queue['result']) if filename != os.path.basename( queue['result']) or not os.path.isfile(path): return make_response({"status": "Resource not available."}, 410) return send_file(path)