2

I am currently trying to process an image on the server that was uploaded by a user. My goal is to take this image that was uploaded, process it on the server and then upload it to rackspace cloud files. I have had no luck in finding a way. I am hoping that someone can lead me into the correct direction.

Heres what I have so far on the server side for processing

Future < Null > handleUploadRequest(final HttpRequest httpRequest) async {
  print('handle upload -------------------------');

  var data;

  await httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d)).then((builder) {
    data = builder.takeBytes();

    String encodedData = JSON.encode(data);

    int dataLength = encodedData.length;

    // Uploading image to rackspace cloud files

   // Here we have to send a request with username & api key to get an auth token
http.post(tokens, headers : {'Content-Type':'application/json'}, body: JSON.encode({"auth": {"RAX-KSKEY:apiKeyCredentials":{"username":"XXXXXXXXXXXXXXX","apiKey":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}}})).then((response) {
   print("Response status: ${response.statusCode}");
   print("Response body: ${response.body}");
   return response;
}).then((response){
   authResponse = JSON.decode(response.body);
   String token = authResponse['access']['token']['id'];


/////////// This is where we upload the image to Rackspace ///////

  var request = new http.MultipartRequest("PUT", Uri.parse('https://storage101.iad3.clouddrive.com/v1/MossoCloudFS_XXXXXXX/TestContainer/testimage.jpg'));
  request.headers['X-Auth-Token'] = token;
  request.headers['Content-Type'] = 'image/jpeg';

  var stream = new http.ByteStream.fromBytes(data);

  request.files.add(new http.MultipartFile('file', stream, data.length, filename: 'testfile.jpg', contentType: 'image/jpeg');
  print('requesT: ${request}');
  request.send().then((response) {
   print(response.statusCode);
   print(response.headers);
   print(response.stream);
   if (response.statusCode == 200) print("Uploaded!");
  });


//// End of Upload to Rackspace //////////

    print('Upload Complete!');
    httpRequest.response.write(data);
    await httpRequest.response.close();
}

The only issue right now is that in https://pub.dartlang.org/packages/http, I need to call the type MediaType in the parameter content-type. I have no idea how to call this. It seems like it is a factory inside a class? If I do not call a content-type then it defaults to octet-stream which cannot be opened from the cdn storage container.

Reference to this way of uploading is from How can I upload a PDF using Dart's HttpClient?

Community
  • 1
  • 1
  • 1
    Do my suggestions result in different behavior? Can you please edit your question and add the error output directly in your question. There is an edit link below the [dart] and [dart-async] tag. – Günter Zöchbauer Aug 17 '15 at 05:37
  • Putting a return before http.put(..) will not let it run. it prints the bytes that it read and goes into .then((_). – Tyler James Thompson Aug 17 '15 at 05:41
  • 1
    I added a pure `async`/`await` implementation to my answer, I think it's easier to reason about it. Can you please try it and tell if it works better/worse/same? – Günter Zöchbauer Aug 17 '15 at 05:56

1 Answers1

1

Looks like an missing return before http.put(...) and httpRequest.response.close();

Either you use await before each async call (call to functions which return a Future) or return each such Future to the caller to preserve order of execution. Without any of these the async execution is scheduled for later execution and the next line of your code is executed instead before the async code you called even started.

Update pure async/await implementation

import 'package:http/http.dart' as http;
import 'dart:async' show Future, Stream;
import 'dart:io';

Future<Null> handleUploadRequest(final HttpRequest httpRequest) async {
  print('handle upload -------------------------');
  print('httpRequest: ${httpRequest.headers}');

  var data;

  var builder = await httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d));
  data = builder.takeBytes();
  print('bytes builder: ${data}');

  // Uploading image to rackspace cloud files
  var url =
      'https://storage101.dfw1.clouddrive.com/v1/{accountnumber}/{container}/';
  var response = await http.put(url,
      headers: {
        'X-Auth-Token': '{XXXXXXXXXAPI_KEYXXXXXXXXXX}',
        'Content-Type': 'image/jpeg',
        'Content-Length': '${httpRequest.headers.contentLength}',
      },
      body: data);

  print("Response status: ${response.statusCode}");
  print("Response body: ${response.body}");

  print('closing connection with data complete');
  httpRequest.response.write(data);
  await httpRequest.response.close();
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I am getting `SocketException: Write failed, address = storage101.dfw1.clouddrive.com, port = 62429` When Updated. This is far better then what I had before (Which was an Unhandled exception). Thank you for that :). Now I need to figure out why I am getting the SocketException issue. – Tyler James Thompson Aug 17 '15 at 06:10
  • 1
    I haven't used cloudfiles myself but looking at some documentation I found, you might need to add an object name in addition to account and container. – Günter Zöchbauer Aug 17 '15 at 06:22
  • When I used their service last time for php, they had a simple sdk I just had to import which is why this is way different for me. love dart though – Tyler James Thompson Aug 17 '15 at 06:28
  • so I should create the url like this https://storage101.dfw1.clouddrive.com/v1/{accountnumber}/{container}/{object}/ – Tyler James Thompson Aug 17 '15 at 06:28
  • 1
    I see, Dart is still quite new at least compared to PHP. It looks like the last `/` is redundant. I have the information from http://docs.rackspace.com/files/api/v1/cf-devguide/content/PUT_createobject_v1__account___container___object__objectServicesOperations_d1e000.html – Günter Zöchbauer Aug 17 '15 at 06:45
  • Thanks for your help! I appreciate it. If you do work with it in the future and find more about their api. let me know:) – Tyler James Thompson Aug 17 '15 at 13:35
  • No, I was unable to get it to work correctly. would some kind of curl function work better to upload an image to the cdn after it has been uploaded to my server? I've never used curl in dart before if so. – Tyler James Thompson Aug 17 '15 at 13:45
  • If you know how to do it in curl it wouldn't be hard to do it in Dart as well. Did you get another error message after adding an object name? You could take a look at the PHP library you used and check what they send and do the same in Dart. – Günter Zöchbauer Aug 17 '15 at 13:47
  • I was getting the same error when adding the object name. I checked out the php library and could not find the issue. – Tyler James Thompson Aug 17 '15 at 14:25
  • I am currently getting '''Unhandled exception: Uncaught Error: FormatException: Invalid radix-10 number''' with this code http.put('storage101.iad3.clouddrive.com/v1/AccountID/${CONTAINERID}/tes‌​timage.jpg?format=json', headers: {'X-Auth-Token': '${token}', 'Content-Type': 'image/jpeg', 'Content-Length': '${data}'}, body: JSON.encode(data)).then((v){ print('status: ${v.statusCode}'); print('v: ${v.body}'); }); – Tyler James Thompson Aug 28 '15 at 03:47
  • 1
    I guess this is because of `Content-length`. It should be the length of the data, not the data itself. Also the `body` argument doesn't work this way. This just sends `null`. I'll update my answer when I'm back on my pc. – Günter Zöchbauer Aug 28 '15 at 04:08
  • I was editing my comment and forgot to put 'Content-Length': '${httpRequest.headers.contentLength} in where data was. Sorry about that and okay – Tyler James Thompson Aug 28 '15 at 04:11
  • Shouldn't the `Conent-length` be the length of the data sent? Please update your question with the code of your previous comment. Code in comments is unreadable. – Günter Zöchbauer Aug 28 '15 at 04:16
  • I think so, I will change that – Tyler James Thompson Aug 28 '15 at 04:48
  • I misinterpreted your code in the comment a bit. `body` looks fine. Did you make progress. What is the current state? – Günter Zöchbauer Aug 28 '15 at 06:38
  • I added the content length to get the content of the data after it has been JSON.encoded. I am now getting a "Unhandled exception: Uncaught Error: SocketException: Write failed, address = storage101.iad3.clouddrive.com, port = 52152" – Tyler James Thompson Aug 28 '15 at 06:46
  • So you're back to square one. You should update your question again with the current state. The "radix" error was just because of the wrong content-length value. – Günter Zöchbauer Aug 28 '15 at 06:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88155/discussion-between-tyler-james-thompson-and-gunter-zochbauer). – Tyler James Thompson Aug 28 '15 at 06:59