after updating to iOS 11.1 the .sqlite download fails. I have verified that I have the Alamofire libraries up to date (4.5.1), I have uninstalled and reinstalled using pod. I have cleaned the project and tried to debug it but I can not find the problem, only i note that the temporaryURL is nil.
My code:
let parameters: Parameters = [:]
var filePath: URL?
let destination: (URL, HTTPURLResponse) -> (URL, DownloadRequest.DownloadOptions) = {
(temporaryURL, response) in
if let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first, let suggestedFilename = response.suggestedFilename {
filePath = directoryURL.appendingPathComponent("\(suggestedFilename)")
return (filePath!, [.removePreviousFile, .createIntermediateDirectories])
}
return (temporaryURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download("https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3", method: .get, parameters: parameters, encoding: JSONEncoding.default, to: destination)
.downloadProgress { progress in
DispatchQueue.main.async
{
/.../
}
}
.validate { request, response, temporaryURL, destinationURL in
/.../
return .success
}
.response { response in
debugPrint(response)
print("Descarga finalizada");
/.../
}
The .downloadProgress works fine. But when it reaches 100% the process does not continue and is waiting until it ends because of the waiting time exhausted (-1001)
The console Output with the debug:
2017-11-07 12:04:28.422333+0100 Target[673:215766] Task <26F62B6A-FEB4-4908-92C9-D3F9C9886C81>.<4> finished with error - code: -1001
Alamofire.DefaultDownloadResponse(request: Optional(https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3), response: Optional(<NSHTTPURLResponse: 0x1c0235220> { URL: https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3 } { Status Code: 200, Headers {
"Accept-Ranges" = (
bytes
);
"Content-Length" = (
28086272
);
"Content-Type" = (
"application/octet-stream"
);
Date = (
"Tue, 07 Nov 2017 11:02:52 GMT"
);
Etag = (
"\"xxxxxxxxxxxxxxxxx\""
);
"Last-Modified" = (
"Tue, 07 Nov 2017 01:44:00 GMT"
);
Server = (
AmazonS3
);
"x-amz-id-12" = (
"LiCdsdasdasfsdfdsffgsfdsw3o+npOhfUVLdZ/KlTWgLXdPNPU8iYnZIkeGoRvBkLbKwFFY="
);
"x-amz-request-id" = (
9CD8D133234DB
);
} }), temporaryURL: nil, destinationURL: nil, resumeData: Optional(7043 bytes), error: Optional(Error Domain=NSURLErrorDomain Code=-1001 "Se ha agotado el tiempo de espera." UserInfo={_kCFStreamErrorCodeKey=-2102, NSURLSessionDownloadTaskResumeData=<CFData 0x1c0649390 [0x1b1491310]>{length = 7043, capacity = 16384, bytes = 0x3c3f786d6c2076657273696f6e3d2231 ... 2f706c6973743e0a}, NSUnderlyingError=0x1c0649e10 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSLocalizedDescription=Se ha agotado el tiempo de espera., NSErrorFailingURLStringKey=https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3, NSErrorFailingURLKey=https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3, _kCFStreamErrorDomainKey=4}), timeline: Timeline: { "Request Start Time": 531745370.759, "Initial Response Time": 531745371.441, "Request Completed Time": 531745468.447, "Serialization Completed Time": 531745468.450, "Latency": 0.682 secs, "Request Duration": 97.688 secs, "Serialization Duration": 0.003 secs, "Total Duration": 97.691 secs }, _metrics: Optional((Task Interval) <_NSConcreteDateInterval: 0x1c003f5c0> (Start Date) 2017-11-07 11:02:50 +0000 + (Duration) 97.667806 seconds = (End Date) 2017-11-07 11:04:28 +0000
(Redirect Count) 0
(Transaction Metrics) (Request) <NSURLRequest: 0x1c00019d0> { URL: https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3, Method GET, Headers {
Accept = (
"*/*"
);
"Accept-Encoding" = (
"gzip;q=1.0, compress;q=0.5"
);
"Accept-Language" = (
"es-ES;q=1.0, fr-ES;q=0.9, en-ES;q=0.8"
);
Connection = (
"keep-alive"
);
"Content-Type" = (
"application/json"
);
Host = (
"s3-eu-west-1.amazonaws.com"
);
"User-Agent" = (
"Targer/1.7 (com.xxxxx.xxxxx; build:156; iOS 11.1.0) Alamofire/4.5.1"
);
} }
(Response) <NSHTTPURLResponse: 0x1c0030ae0> { URL: https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3 } { Status Code: 200, Headers {
"Accept-Ranges" = (
bytes
);
"Content-Length" = (
28086272
);
"Content-Type" = (
"application/octet-stream"
);
Date = (
"Tue, 07 Nov 2017 11:02:52 GMT"
);
Etag = (
"\"6c9de7be53a1cdfser61ca7fa1a4\""
);
"Last-Modified" = (
"Tue, 07 Nov 2017 01:44:00 GMT"
);
Server = (
AmazonS3
);
"x-amz-id-2" = (
"LiCk24ajVvge+qcds5hgfbgdfxgnhFOhfUVLdZ/KlTWgLXdPNPU8iYnZIkeGoRvBkLbKwFFY="
);
"x-amz-request-id" = (
9CD8SDHD7B81DB
);
} }
(Fetch Start) 2017-11-07 11:02:50 +0000
(Domain Lookup Start) 2017-11-07 11:02:50 +0000
(Domain Lookup End) 2017-11-07 11:02:50 +0000
(Connect Start) 2017-11-07 11:02:50 +0000
(Secure Connection Start) 2017-11-07 11:02:50 +0000
(Secure Connection End) 2017-11-07 11:02:51 +0000
(Connect End) 2017-11-07 11:02:51 +0000
(Request Start) 2017-11-07 11:02:51 +0000
(Request End) 2017-11-07 11:02:51 +0000
(Response Start) 2017-11-07 11:02:51 +0000
(Response End) 2017-11-07 11:03:27 +0000
(Protocol Name) http/1.1
(Proxy Connection) NO
(Reused Connection) NO
(Fetch Type) Network Load
))
Descarga finalizada
However, the file has been downloaded to the path:
I have changed the destination of the file using a simpler version like:
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
But the problem is the same.
With iOS 10.3 works perfectly.
I appreciate any help, thx.
I have solved it by removing the additional parameters from:
Alamofire.download("https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3", method: .get, parameters: parameters, encoding: JSONEncoding.default, to: destination)
To:
Alamofire.download("https://s3-eu-west-1.amazonaws.com/xxx/xxx/xxx.sqlite3", to: destination)
I'm not sure what's wrong but that's how it works
Related
I'm trying to update an icon with axios and put method on a laravel/vue app.
I'm always getting the error : icon must be an image.
I've correctly inserted my headers : content-type": "multipart/form-data" in the config variable.
async updateSolution({
commit
}, payload) {
const id = payload.id;
const config = payload.config;
const solution = payload.data;
try {
console.log(solution.get('icon'));
const res = await this.$axios.$put(`/api/solutions/${id}`, {
config,
name: solution.get('name'),
description: solution.get('description'),
icon: solution.get('icon'),
});
commit('UPDATE_SOLUTION', res);
} catch (error) {}
},
If I do a console.log(solution.get('icon') here is the output :
File {name: 'img.png', lastModified: 1660039998282, lastModifiedDate: Tue Aug 09 2022 12:13:18 GMT+0200 (Central European Summer Time), webkitRelativePath: '', size: 9026, …}
lastModified: 1660039998282
lastModifiedDate: Tue Aug 09 2022 12:13:18 GMT+0200 (Central European Summer Time) {}
name: "img.png"
size: 9026
type: "image/png"
webkitRelativePath: ""
[[Prototype]]: File
So it understand well that there is a image file in actions.js vuex file.
Why does it tell me that this is not an image ?
I heard about the workaround with _method parameter, so I've first tried adding the method in formData object :
async editSolution() {
const result = await this.$refs.observer.validate();
this.message = null;
this.errors = [];
let formData = new FormData();
const id = this.id;
const config = {
headers: {
"content-type": "multipart/form-data",
},
};
formData.append("name", this.solutionName);
formData.append("description", this.solutionDesc);
formData.append("icon", this.solutionIcon);
formData.append("_method", "PUT");
this.$emit("edit-data", id, formData, config);
},
Here the output is :
The POST method is not supported for this route.
So the parameter is not recognized apparently.
I also tried to add the parameter in the actions.js vuex file directly.
const res = await this.$axios.$post(`/api/solutions/${id}`, {
_method: 'PUT',
config,
name: solution.get('name'),
description: solution.get('description'),
icon: solution.get('icon'),
})
It gives me the same error than using this.$axios.$put() call :
icon must be an image.
Thanks for your help,
I followed chainlink tutorial to build an external adapter. Unfortunately, after hours of debugging, my EA is still not working, flashing the 500 internal server error.
HTTP/1.1 500 Internal Server Error
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 186
ETag: W/"ba-z+FLILUhYUEw92/8nbj21rBflVg"
Date: Wed, 11 May 2022 05:05:45 GMT
Connection: close
{
"jobRunID": 0,
"status": "errored",
"error": {
"error": {
"name": "AdapterError",
"message": {
"error": {
"name": "AdapterError",
"message": "Required parameter not supplied: base"
}
}
}
},
"statusCode": 500
}
The API I am trying to fetch is AeroDataBox API (from RapidAPI marketplace). We need 2 params: flight number (AC1309) and date (2022-05-09).
This is the RapidAPI code snippet recommendation:
const fetch = require('node-fetch');
const url = 'https://aerodatabox.p.rapidapi.com/flights/number/AC1039/2022-05-09';
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Host': 'aerodatabox.p.rapidapi.com',
'X-RapidAPI-Key': 'db0eaaf009msh506491d3d299ed8p10a8d4jsnc705a04d3eb2'
}
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('error:' + err));
This is the snippet of my code in the index.js:
const customParams = {
flightNumber: ['flightNumber'],
date: ['yyyy-mm-dd'],
endpoint: false
}
const createRequest = (input, callback) => {
const validator = new Validator(callback, input, customParams)
const jobRunID = validator.validated.id
const API_KEY = process.env.API_KEY
const flightNumber = validator.validated.data.flightNumber
const date = validator.validated.data.date
const url = `https://aerodatabox.p.rapidapi.com/flights/number/${flightNumber}/${date}`
const params = {
flightNumber,
date
}
const headers = {
'X-RapidAPI-Host': 'aerodatabox.p.rapidapi.com',
'X-RapidAPI-Key': `${API_KEY}`
}
}
const config = {
url,
params,
headers
}
Requester.request(config, customError)
.then(response => {
callback(response.status, Requester.success(jobRunID, response.data))
})
.catch(error => {
callback(500, Requester.errored(jobRunID, error))
})
This is my curl command:
curl -X POST -H "content-type:application/json" "http://localhost:8080/" --data '{ "id": 0, "data": { "flightNumber": "AC1309", "date": "2022-05-09" } }'
I don't know what I am missing? Thank you for your help.
in my SwiftUI app i am storing images to IPFS Data Store and they have recently made the url as a POST request from GET request. In that case the third party library is not able to render the image. How can i resolve this?
This is the example url i am trying to render
link to the image
This is the exact error i get:
Error Domain=SDWebImageErrorDomain Code=2001 "Download marked as failed because of invalid response status code 405" UserInfo={SDWebImageErrorDownloadResponseKey=<NSHTTPURLResponse: 0x600000ed8340> { URL: https://ipfs.infura.io:5001/api/v0/cat?arg=QmVHLDEY4DhzJeW7G47QgpdibU6QX8g8He6CS83qRbpcDB } { Status Code: 405, Headers {
"Content-Length" = (
28
);
"Content-Type" = (
"text/plain; charset=utf-8"
);
Date = (
"Thu, 03 Mar 2022 17:20:01 GMT"
);
Vary = (
Origin
);
"X-Content-Type-Options" = (
nosniff
);
"X-Robots-Tag" = (
noindex
);
} }, NSLocalizedDescription=Download marked as failed because of invalid response status code 405, SDWebImageErrorDownloadStatusCodeKey=405}
My code snippet for SDWebImageSwiftUI:
ForEach(vm.item.tabImagesArray.indices, id: .self) { index in
WebImage(url: URL(string: vm.item.tabImagesArray[index]))
.resizable()
.placeholder {
Image("placeholder")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
.scaledToFit()
}
.onFailure { error in
print(error)
}
.onSuccess { img, data, _ in
print(img)
print(data)
}
.transition(.fade(duration: 0.5))
.frame(height: vm.index == index ? 200 : 150)
.cornerRadius(15)
.padding(.horizontal)
.tag(index)
.onTapGesture {
self.selectedImage = vm.item.tabImagesArray[index]
self.showImage.toggle()
}
}
I am using lambda edge to handle image compression with Sharp. The code works for now, but when I tried to add a new function to parse query parameter to let the user define the quality of the compression, Lambda/Cloudfront starts giving me a notice that the key is not exist even though it does exist.
The path that was used as an example is:
/compress/480/uploads/1000491600869812260.jpg?quality=30
Error that shows up on the browser:
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>compress/480/uploads/1000491600869812260.jpg</Key>
<RequestId>5KPMBD6RNETZCA3Z</RequestId>
<HostId>
brMd/eCi6uv9s3VIl4IRHg7FlIytNA8DkgPjGfGrej4SkUsMxuEm1YHGEEll5rydO24gecIOTtE=
</HostId>
</Error>
Errors log from cloudfront:
#Version: 1.0
#Fields: date time x-edge-location sc-bytes c-ip cs-method cs(Host) cs-uri-stem sc-status cs(Referer) cs(User-Agent) cs-uri-query cs(Cookie) x-edge-result-type x-edge-request-id x-host-header cs-protocol cs-bytes time-taken x-forwarded-for ssl-protocol ssl-cipher x-edge-response-result-type cs-protocol-version fle-status fle-encrypted-fields c-port time-to-first-byte x-edge-detailed-result-type sc-content-type sc-content-len sc-range-start sc-range-end
2021-06-09 06:06:43 ORD52-C3 689 182.253.36.23 GET d32xc09eirob59.cloudfront.net /compress/480/uploads/1000491600869812260.jpg 404 - Mozilla/5.0%20(Macintosh;%20Intel%20Mac%20OS%20X%2010_15_7)%20AppleWebKit/605.1.15%20(KHTML,%20like%20Gecko)%20Version/14.1.1%20Safari/605.1.15 quality=10 - Error FPFQE5Z-XuBeAK61KaJbNqDAbypyo3BhrH7xom7GZik--UgESIVQFw== d32xc09eirob59.cloudfront.net http 426 3.726 - - - Error HTTP/1.1 - - 54708 3.726 Error application/xml - - -
In the code below, if I comment the lines that call the function to parse the quality from query parameter (marked as "The problematic line" in the code), the code works again. But, from my point of view, there is nothing wrong with the code since it is a simple regex to fetch a value.
Is there any limitation or constraint in the AWS lambda that makes it behave like that? Is there anything that I can do to make it work?
P.S. I already tried to use URL and querystring library to parse the path, but it always shows me LambdaException error, hence why I try to parse it manually with regex
Problematic line/function:
const getQuality = (path) => {
const match = path.match(/quality=(\d+)/)
const quality = parseInt(match[1], 10)
return quality
}
const quality = getQuality(path)
Full code:
'use strict'
const AWS = require('aws-sdk')
const S3 = new AWS.S3({ signatureVersion: 'v4' })
const Sharp = require('sharp')
const BUCKET = 'some-bucket'
const QUALITY = 70
// Image types that can be handled by Sharp
const SUPPORTED_IMAGE_TYPES = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'tiff']
const JSON_CONTENT_HEADER = [{ key: 'Content-Type', value: 'application/json' }]
const WEBP_CONTENT_HEADER = [{ key: 'Content-Type', value: 'image/webp' }]
const getOriginalKey = (path) => {
const match = path.match(/\/(\d+)\/([A-Za-z0-9_\-]+)\/([A-Za-z0-9_\-]+)\.(\w+)\??/)
const imageWidth = parseInt(match[1], 10)
const prefix = match[2]
const imageName = match[3]
const imageFormat = match[4]
const originalKey = `${prefix}/${imageName}.${imageFormat}`
return { originalKey, imageWidth, imageFormat }
}
const getQuality = (path) => {
const match = path.match(/quality=(\d+)/)
const quality = parseInt(match[1], 10)
return quality
}
const responseUpdate = (
response,
status,
statusDescription,
body,
contentHeader,
bodyEncoding = undefined
) => {
response.status = status
response.statusDescription = statusDescription
response.body = body
response.headers['content-type'] = contentHeader
if (bodyEncoding) {
response.bodyEncoding = bodyEncoding
}
return response
}
exports.handler = async (event, context, callback) => {
let { request, response } = event.Records[0].cf
const { uri } = request
const headers = response.headers
console.log(JSON.stringify({ status_code: response.status, uri }))
// NOTE: Check whether the image is present or not
if (response.status == 404) {
const splittedUri = uri.split('compress')
if (splittedUri.length != 2) {
callback(null, response)
return
}
// NOTE: Parse the prefix, image name, imageWidth and format
const path = splittedUri[1] // Read the required path (/480/uploads/123.jpg)
const { originalKey, imageWidth, imageFormat } = getOriginalKey(path)
if (!SUPPORTED_IMAGE_TYPES.some((type) => type == imageFormat.toLowerCase())) {
response = responseUpdate(
response,
403,
'Forbidden',
'Unsupported image type',
JSON_CONTENT_HEADER
)
callback(null, response)
return
}
try {
// NOTE: Get original image from S3
const s3Object = await S3.getObject({ Bucket: BUCKET, Key: originalKey }).promise()
if (s3Object.ContentLength == 0) {
response = responseUpdate(
response,
404,
'Not Found',
'The image does not exist',
JSON_CONTENT_HEADER
)
callback(null, response)
return
}
// NOTE: Optimize the image
let sharpObject = await Sharp(s3Object.Body)
const metaData = await sharpObject.metadata()
if (imageWidth < metaData.width) {
sharpObject = await sharpObject.resize(imageWidth)
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// NOTE: The problematic line
const quality = getQuality(path)
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
const compressedImageBuffer = await sharpObject.webp({ quality: QUALITY }).toBuffer()
const byteLength = Buffer.byteLength(compressedImageBuffer, 'base64')
if (byteLength == metaData.size) {
callback(null, response)
return
}
if (byteLength >= 1046528) {
response = responseUpdate(
response,
400,
'Invalid size',
'The size of compressed image is too big',
JSON_CONTENT_HEADER
)
callback(null, response)
return
}
// NOTE: Generate a binary response with an optimized image
response = responseUpdate(
response,
200,
'OK',
compressedImageBuffer.toString('base64'),
WEBP_CONTENT_HEADER,
'base64'
)
response.headers['cache-control'] = [{ key: 'cache-control', value: 'max-age=31536000' }]
} catch (err) {
console.error(err)
}
} else {
headers['content-type'] = WEBP_CONTENT_HEADER
}
return response
}
the timeout that I defined does not throw any error when the duration parameter I defined is greater than 7000 ms. what is strange is that the timeout operator works well in my code from 0 to 7000 ms
pay(billing: Billing): Observable {
const httpOptions = {
headers: new HttpHeaders({
// 'Access-Control-Allow-Origin':'*'
}),
params: new HttpParams()
.append('timezone', billing.timezone)
.append('mode', billing.mode)
.append('responseFailURL', billing.responseFailURL)
.append('responseSuccessURL', billing.responseSuccessURL)
.append('hash', billing.hash)
.append('txndatetime', billing.txndatetime)
.append('chargetotal', billing.chargetotal.toString())
.append('storename', billing.storename.toString())
.append('currency', billing.currency.toString())
};
// Sending required payment infrmations to Authipay host url
return forkJoin(
of(2), timer(2000).pipe(mergeMap(value => this.getPayementStatus(billing.txndatetime))).pipe( timeout(7500))
).pipe(
map(
([articles, authorOfTheMonth]) => {
console.log(authorOfTheMonth);
return authorOfTheMonth;
}
)
).subscribe(
resp => {
this.router.navigate(['success'], { relativeTo: this.route });
} else {
form.setErrors({ paymentFailed: true });
this.alertify.error(this.translate.instant('error.payment'));
}
},
error => {
if (error instanceof TimeoutError) {
this.alertify.error(error.message);
} else {
this.alertify.error(this.translate.instant('error.payment'));
}
}
);
timeout seems to work as expected to me.
I wrote a test here where I replaced your this.getPayementStatus(billing.txndatetime)) function with a :
simulated response
const simulateResponseTime = (timeInMS)=> timer(timeInMS); // in milliseconds
Which will return a response in delayOfResponse milliseconds. With this tool we can test what happens when the response takes more time than timeout threshold:
Simulation parameters
const timeoutThreshold = 7500; // in ms
const delayOfResponse = 200; //in ms
Finally, a minimalist version of
Your code
forkJoin(of(2), timer(2000).pipe(
mergeMap(value => simulateResponseTime(delayOfResponse))
).pipe(timeout(timeoutThreshold))
).pipe(
...
).subscribe(
resp => {
console.log('Success')
},
error => {
console.log('Error message :', error.message)
console.log('Error type :', error.name)
console.log('Is a TimeoutError :', error.name === 'TimeoutError' )
}
);