Flutter/Dart SocketException Uploading Video File to URL - ios

I am recieving this error message when attempting to upload a video file to the speicified URL:
DioError (DioError [DioErrorType.DEFAULT]: SocketException: OS Error: Connection reset by peer, errno = 54, address = storage.googleapis.com, port = 64995)
Note: It is a DioError as I am using the dio Dart/Flutter package: https://pub.dev/packages/dio I recieve the error using equivilent API such as the http library.
Code to upload the video file selected from storage:
//File videoFile...
FormData data = FormData.fromMap({
"videoFile": await MultipartFile.fromFile(videoFile.path),
});
Response response = await Dio().post(
directUpload.url,
data: data,
onSendProgress: (int sent, int total) {
print("$sent $total");
},
);
The URL (directUpload.url) is one generated from and provided by the Mux API to their Google Cloud Storage.
https://storage.googleapis.com/video-storage-us-east1-uploads/...
When post is called, a small amount is uploaded (e.g. 655524 / 17840042) and then the error occurs. The test video is 17.8 Mb in size.
Running this on an iOS device or the iOS simulator produces the same result/error.
I have tried: flutter clean, flutter upgrade, deleteing Podfile and pod repo update, deleting the app from device. All to no avail.

Change from a POST to a PUT request resolves the issue.

yes, I have same problem with Dio.
current can't upload data type Uint8List
My temporary solution:
use http lib
http: ^0.12.1
import 'package:http/http.dart' as http;
Future uploadData(Uint8List imageData) async {
await http.put(preData.url, headers: getHeader(), body: imageData);
}
use:
List<int> imageData = File(filePath).readAsBytesSync();
await uploadData(imageData);
hope to help you

The error message "Connection reset by peer" appears, if the web services client was waiting for a SOAP response from the remote web services provider and the connection was closed prematurely.
One of the most common causes for this error is a firewall in the middle closing the connection. In this case you could increase the connection timeout in the firewall.You can find the component that closes the connection by capturing and analyzing an IP trace.
Other possible causes are e.g.:
resource limitations on the server side like out of memory server
process killed
overload on the server due to a high amount of traffic
ALSO Try this..
cd ~/flutter
git checkout -b max-in-flight
code packages/flutter_tools/lib/src/devfs.dart # edit kMaxInFlight from 6 to 1
rm bin/cache/flutter_tools*
AND This
flutter clean
flutter channel stable

have you tried using http.MultipartRequest method ?
As it can be used to transfer large files, you can also try is DIO alternative if present in dio
and how to use http.MultipartRequest here is an article https://dev.to/carminezacc/advanced-flutter-networking-part-1-uploading-a-file-to-a-rest-api-from-flutter-using-a-multi-part-form-data-post-request-2ekm
let me know if it works or not.

When post is called, a small amount is uploaded (e.g. 655524 / 17840042) and then the error occurs. The test video is 17.8 Mb in size.
Answer-
Go your cpanel MultiPHP INI Editor file and increase post_max_size
No need to change u r flutter code, it is right .

Related

Protocol error when calling puppeteer.connect()

I am using the basic approach as set out in this post to connect from a client docker container to any one of a number of chrome docker containers (in a docker swarm/service, potentially across several servers behind nginx, deployed using CapRover).
In each chrome container I maintain a pool (just a simple array) of browser objects, and direct incoming requests to an appropriate browser as follows (very similar to the linked post):
import http from 'node:http'; // https://nodejs.org/api/http.html
import httpProxy from 'http-proxy'; // https://www.npmjs.com/package/http-proxy
const proxy = new httpProxy.createProxyServer({ ws: true });
// an array (pool) of pre-launched and managed browser objects...
const browsers = [ ... ];
http
.createServer()
.on('upgrade', (req, socket, head) => {
const browser = browsers[Math.floor(Math.random() * browsers.length)]; // in reality I don't just pick a browser at random
const target = browser.wsEndpoint();
proxy.ws(req, socket, head, { target });
})
.listen(3222);
The above is listening at ws://srv-captain--chrome:3222 (communication is "internal" over the docker network between containers).
Then, in my client container, I connect to the common endpoint ws://srv-captain--chrome:3222 as follows:
import puppeteer from 'puppeteer'; // https://www.npmjs.com/package/puppeteer (using version 17.1.3 at time of posting this)
try {
const browser = await puppeteer.connect({ browserWSEndpoint: 'ws://srv-captain--chrome:3222' });
} catch (err) {
console.error('error connecting to browser', err);
}
This works really well, except that I am getting occasional/inconsistent errors like these when calling puppeteer.connect() in the client container above:
Protocol error (Emulation.setDeviceMetricsOverride): Session closed. Most likely the page has been closed.
Protocol error (Performance.enable): Target closed.
Almost always, if I simply try to connect again, the connection is made without further error, and at the first attempt.
I have no idea why the error is complaining that the page has been closed or Target closed since, at this point in the process, I'm not attempting to interact with any page, and I know from listening for browser.on('disconnected'...), and also monitoring the chromium processes themselves, that each browser in the array is still working fine... none has crashed.
Any idea what's going on here?
UPDATE after further testing
Of course, in the client container we don't connect to a browser just for the sake of it, like in the above snippet, but to open a page and do some stuff with the page. In practice, in the client container it's more like the following test snippet:
const doIteration = function (i) {
return new Promise(async (resolve, reject) => {
// mimic incoming requests coming in at random times over a short period by introducing a random initial delay...
await new Promise(resolve => setTimeout(resolve, Math.random() * 5000));
// now actually connect...
let browser;
try {
browser = await puppeteer.connect({ browserWSEndpoint: `ws://srv-captain--chrome:3222?queryParam=loop_${i}` });
} catch (err) {
reject(err);
return;
}
// now that we have a browser, open a new page...
const page = await browser.newPage();
// do something useful with the page (not shown here) and then close it..
await page.close();
// now disconnect (but don't close) the browser...
browser.disconnect();
resolve();
});
};
const promises = [];
for (let i = 0; i < 15; i++) {
promises.push( doIteration(i) );
}
try {
await Promise.all(promises);
} catch (err) {
console.error(`error doing stuff`, err);
}
Each iteration above is being performed multiple times concurrently... I am using Promise.all() on an array of iteration promises to mimic multiple concurrent incoming requests in my production code. The above is enough to reproduce the problem... the error doesn't happen on calling puppeteer.connect() with every iteration, just some.
So there seems to be some sort of interplay between opening/closing a page in one iteration, and calling puppeteer.connect() in another, despite closing the page and disconnecting the browser properly in each iteration? This probably also explains the Most likely the page has been closed error message when calling puppeteer.connect() if there is some hangover relating to a page closed in another iteration... though for some reason this error occurs when calling puppeteer.connect()?
With the use of a pool of browser objects in the browsers array, and a docker swarm having multiple containers on multiple servers, each upgrade message could be received at a different container (which could even be on a different server) and could be routed to a different browser in the browsers array. But I now think that this is a red herring, because in the further testing I narrowed the problem down by routing all requests to browsers[0] and also scaling the service down to just one container... so that the upgrade messages are always handled by the same container on the same server and routed to the same browser... and the problem still occurs.
Full stacktrace for the above-mentioned error:
Error: Protocol error (Emulation.setDeviceMetricsOverride): Session closed. Most likely the page has been closed.
at CDPSession.send (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Connection.js:281:35)
at EmulationManager.emulateViewport (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/EmulationManager.js:33:73)
at Page.setViewport (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Page.js:1776:93)
at Function._create (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Page.js:242:24)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Target.page (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Target.js:123:23)
at async Promise.all (index 0)
at async BrowserContext.pages (file:///root/workspace/myclientapp/node_modules/puppeteer/lib/esm/puppeteer/common/Browser.js:577:23)
at async Promise.all (index 0)
As I dug deeper and deeper into this problem, it become more and more apparent that I might not actually be doing anything fundamentally wrong, and that this might just be a bug in puppeteer itself. So I reported those as an issue over on puppeteer... and indeed, it is acknowledged as a bug for any version later than 15.5.0, and is being fixed. In the meantime, the workaround is to revert to puppeteer version 15.5.0 and to be careful when calling browser.pages() when concurrent connections are being used, because that might itself throw an error... but I understand that this too might be something that they can/will fix so that browser.pages() is more resilient to the presence of concurrent connections.

NestJS microservices error with "No matching message handler"

I'm building an application with microservices communicating through RabbitMQ (request-response pattern). Everything works fine but still I have a problem with error "There is no matching message handler defined in the remote service." - When I send POST to my Client app, it should simply send the message with data through client (ClientProxy) and the Consumer app should response. This functionality actually works, but always only for the second time. I know it sounds strange but on my first POST request there is always the error from Client and my every second POST request works. However this problem is everywhere in my whole application, so the particular POST request is just for the example.
Here is the code:
Client:
#Post('devices')
async pushDevices(
#Body(new ParseArrayPipe({ items: DeviceDto }))
devices: DeviceDto[]
) {
this.logger.log('Devices received');
return this.client.send(NEW_DEVICES_RECEIVED, devices)
}
Consumer:
#MessagePattern(NEW_DEVICES_RECEIVED)
async pushDevices(#Payload() devices: any, #Ctx() context: RmqContext) {
console.log('RECEIVED DEVICES');
console.log(devices);
const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
return 'ANSWER';
}
Client has the RMQ settings with queueOptions: {durable: true} and the consumer as well queueOptions: {durable: true} with noAck: false
Please do you have any ideas what may causes the problem? I have tried sending the data with JSON.stringify and changing the message structure to {data: devices} but the error is still there.
I had same error and finally solve it today.
In my project, there is an api-gateway as a hybrid application to receive requests and pass data to other systems, every second request gives an error like below.
error: There is no matching message handler defined in the remote service.
Then I tried to remove the api-gateway hybrid application scope in the code below, the error is gone, hope this helps you out with this.
// api-gateway main.ts
const app = await NestFactory.create(AppModule);
// run as a hybrid app —→ remove it
app.connectMicroservice({
transport: Transport.RMQ,
noACK: false,
options: {
urls: [`amqp://${rmqUser}:${rmqPassword}#127.0.0.1:5672`],
queue: 'main_queue',
queueOptions: {
durable: false,
},
},
});
// run hybrid app
await app.startAllMicroservices(); —→ remove it
await app.listen(3000);
I solved this issue by placing the #EventPattern decorator on to a #Controller decorator method
I had this error while NOT using RabbitMQ. I found very little help online around this error message outside of it being related to RabbitMQ.
For me it was an issue where I was importing a DTO from another microservice in my microservice's Controller. I had a new DTO in my microservice that has a similar name to one in another microservice. I accidentally selected the wrong one from the automated list.
Since there wasn't any real indicator that my build was bad, just this error, I wanted to share in case others made the same mistake I did.
I encountered this same issue today and could not find any solution online and stumbled upon your question. I solved it in a hacky way and am not sure how it will behave when the application scales.
I basically added one #EventPattern (#MessagePattern in your case) in the controller of the producer microservice itself. And I called the client.emit() function twice.
So essentially the first time it gets consumed by the function that is in the producer itself and the second emit actually goes to the actual consumer.
This way only one POST call is sufficient.
Producer Controller:
#EventPattern('video-uploaded')
async test() {
return 1;
}
Producer client :
async publishEvent(data: VideosDto) {
this.client.emit('video-uploaded', data);
this.client.emit('video-uploaded', data);
}
I've experienced the same error in my another project and after some research I've found out that problem is in the way of distributing messages in RabbitMQ - named round-robin. In my first project I've solved the issue by creating a second queue, in my second project I'm using the package #golevelup/nestjs-rabbitmq instead of default NestJS library, as it is much more configurable. I recommend reading this question

Download file with Playwright

How to download a file with Playwright?
I'm aware of this question
How to catch a download with playwright?
but that example code does not work. Using the latest released Playwright, there is no 'pageTarget' function on the browser instance:
const client = await browser.pageTarget(page).createCDPSession();
All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded files are deleted when the browser closes.
Download event is emitted once the download starts. Download path becomes available once download completes:
const [ download ] = await Promise.all([
page.waitForEvent('download'), // wait for download to start
page.click('a')
]);
// wait for download to complete
const path = await download.path();
...
https://github.com/microsoft/playwright/blob/master/docs/api.md#class-download
Playwright is going to support downloads in a cross-browser compatible way soon, you can track this feature request.
For now the above Chromium-specific snippet could be fixed by changing the line to:
const client = await context.newCDPSession(page);
which uses the new method for creating CDP sessions.

Error 400 with Stripe iOS Payment

I'm using Stripe to process payments in my iOS Swift app and Firebase Cloud Functions for the backend. I setup an example app using Stripe's Example project located here:
Stripe iOS Standard Integration
When I load the CheckoutView I get an Error 400 response. The issue I believe is with the backendURL that I set in CheckoutViewController (customized using the link to the example above):
// 2) Next, optionally, to have this demo save your user's payment details, head to
// https://github.com/stripe/example-ios-backend/tree/v13.0.3, click "Deploy to Heroku", and follow
// the instructions (don't worry, it's free). Replace nil on the line below with your
// Heroku URL (it looks like https://blazing-sunrise-1234.herokuapp.com ).
let backendBaseURL: String? = "https://us-central1-app-1253c.cloudfunctions.net/https-client-donateToUser"
I get the following messages in my Cloud Function logs:
Request has incorrect Content-Type. application/x-www-form-urlencoded
Invalid request IncomingMessage
Function execution took 498 ms, finished with status code: 400
I tried using the URL of the actual Firebase app (ex: appname123.firebaseapp.com) but that returns an Error 404 instead.
Any ideas for a solution would be greatly appreciated. Thank you.
EDIT:
Thanks to #psmvac I fixed the backend URL. However, I'm now getting error The data couldn't be read because it isn't in the correct format. I believe this is because I don't have a cloud function to accept ephemeral keys. This is what I have so far, what else does this need in order to match the iOS Stripe Example? I'm struggling to find any Cloud Function examples of this online.
export const ephemeral_keys = functions.https.onCall(async (data, context) => {
const stripe_version = data.api_version
stripe.ephemeralKeys.create(data.customer_id,stripe_version)
}
)

Sending files from iOS app to server running on google app engine

My iOS app interacts with a google app engine backend. I have the option for user to report an issue. When user enters the text describing the problem and presses the Submit button, I want to start a background upload of the issue description plus logs being collected in the app using CocoaLumberjack.
My current approach (almost working) is as follows. iOS sends a multipart/form-data POST request that contains a String with bug description and log file content (NSData) with each part separated by a boundary. The GAE server is able to successfully decode each part and I am able to see the file content when I print it out using logging.info(). However, when I try to store the file to GCS, I get an error. The code used to store to GCS and error are below.
I have one storage bucket configured and this has class = Durable Reduced Availability.
Can someone point me to what I'm doing wrong (I suspect it is something about how I set up the authorization lists in the GCS container)?
Alternatively, I am all ears if someone has an easier way to solve this problem.
Code used to store into GCS is:
logging.info('Creating file %s\n' % (filename))
write_retry_params = gcs.RetryParams(initial_delay=0.2,
max_delay=5.0,
backoff_factor=1.2,
max_retry_period=15)
gcs_file = gcs.open(filename,
'w',
content_type='text/plain',
retry_params=write_retry_params)
gcs_file.write(filename=getattr(request, 'fileAttached'))
gcs_file.close()
Error seen in GAE:
ForbiddenError: Expect status [201] from Google Storage. But got status 403.
Path: '/var/mobile/Containers/Data/Application/4FB6C1D7-9504-4215-BC25-FC490298EEF6/Library/Caches/Logs/com.apm.smartiothome.chatime%202016-01-20%2008-01.log'.
Request headers: {'x-goog-resumable': 'start', 'x-goog-api-version': '2', 'content-type': 'text/plain', 'accept-encoding': 'gzip, *'}.
Response headers: {'content-type': 'application/xml; charset=UTF-8', 'content-length': '195', 'vary': 'Origin', 'x-guploader-uploadid': 'AEnB2Uo1b-z2VGlHOnurusG2F9bgKcBVwmYWZrQFG4d4NBrHA_tk9wTPoa4kB1Aici7XP7Z6fNtuSJlGDokUmxtCFAl8aMnXGA'}.
Body: "AccessDeniedAccess denied.Caller does not have storage.objects.create access to bucket var.".
Extra info: None.
I opened the menu "IAM & Admin" > Service accounts and copied the "Service account ID" from the row "App Engine default service account". The name was my app followed by "#appspot.gserviceaccount.com".
Next, I opened Storage and click the "..." next to the default bucket > Edit bucket permissions. I added the service account as a user with Writer access.

Resources