Large file upload fails on node.js Hapi - android

I have a node.js script which should handle file uploads, also multiple at once. Uploading pictures and voices work just fine. However, video files at around 10 MB or larger do not upload. Sometimes it doesn't work at all and sometimes it gets stuck in the fs.writeFile function. Maybe there is a better way general as I came up with many parts in the code on my own. I need the md5 hash before creating the file on disk because its path will be generated from the hash. Also I get a SocketTimeoutException on the Android side. Code is mainly focused on that part right now, so don't worry about the missing input validation and onProgress.
NodeJS:
server.route({
method: 'POST',
path: '/uploadFile',
config: {
payload: {
output: 'stream',
allow: 'multipart/form-data',
maxBytes: 100*1024*1024 //100 mb
}
}, handler: async function (request, reply)
{
await incoming_uploadFile(request, reply);
}
});
...........
var joi = require('joi');
import { Paths } from "../util/Paths";
import * as fs from 'fs';
let data;
let numOfFiles: number;
export async function incoming_uploadFile(request, reply) {
data = request.payload;
await Application.InitializeSocket(null, "UploadFile");
let userID = await Application.AuthUser(JSON.parse(data['auth']));
numOfFiles = parseInt(data['numOfFiles']);
if (numOfFiles > 0)
upload(0);
}
async function upload(i: number)
{
const file = data['file' + i];
const meta = data['fileMeta' + i];
const metaJson = Application.StringToJson(meta);
const fileType: string = metaJson['fileType'];
const extension: string = metaJson['extension'];
var crypto = require('crypto');
const md5 = crypto.createHash('md5');
var length = parseInt(file.hapi.headers["content-length"]);
let buffer: Buffer = new Buffer(length);
let bufPos : number = 0;
file.on('data', function (b : Uint8Array) {
for (var i = 0; i < b.byteLength; ++i)
buffer.writeUInt8(b[i], bufPos++);
});
file.on('end', function (err) {
var hash = md5.update(buffer.toString("base64")).digest("hex");
const filePath: string = Paths.getFilePath(hash, fileType, extension);
// Creates all dirs that are missing on the path
var shell = require('shelljs');
shell.mkdir('-p', require('path').dirname(filePath));
console.log("writing buffer to file...");
fs.writeFile(filePath, buffer,null);
if ((++i) < numOfFiles)
upload(i);
});
}
Android uploading the file(s):
public static void uploadAttachments(ArrayList<EventAttachment> attachments)
{
OkHttpClient client = new OkHttpClient();
// Add attachments
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("numOfFiles",String.valueOf(attachments.size()));
for (int i = 0; i < attachments.size();++i) {
EventAttachment attachment = attachments.get(i);
File file = new File(attachment.getPath());
String extension = MimeTypeMap.getFileExtensionFromUrl(attachment.getPath());
String type = null;
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
} else {
Log.e("x", "Could not get extensions of file " + file.getAbsolutePath() + ". File upload aborted.");
return;
}
ProgressRequestBody p = new ProgressRequestBody(RequestBody.create(MediaType.parse(type), file), new ProgressRequestBody.Listener() {
#Override
public void onProgress(int progress) {
}
});
builder.addFormDataPart("file" + i, file.getName(), p);
HashMap<String, String> hm = new HashMap<>();
hm.put("extension", extension.replace(".", ""));
hm.put("fileType", String.valueOf(attachment.getType()));
builder.addFormDataPart("fileMeta" + i, new JSONObject(hm).toString());
}
JSONObject jObj = new JSONObject();
builder.addFormDataPart("auth", putDefaultHeader(jObj).toString());
MultipartBody mb = builder.build();
okhttp3.Request request = new Request.Builder().url(EndPoint+UPLOAD_FILE).post(mb).build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
Log.e("x", "Error uploading file");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
Thanks for your help.

Added
timeout: false,
parse: true
on the config payload and works for now.

Related

An error occurred while loading the image in VScode

I am recently developing new android project. I am trying to save image files into the server directory.
I use Retrofit for HttpConnection with server.
Storing image files into the server directory works well, but the image is not available. Everytime I upload files into the server, it says An error occurred while loading the image. I have been looking for solutions and trying to fix this problem, but I have no idea what causes this problem.
Here is my android code :
ArrayList<MultipartBody.Part> files = new ArrayList<>();
for(int a = 0; a < list.size(); a++) {
// list = uri image list for recyclerview.
RequestBody fileBody = RequestBody.create(MediaType.parse("image/jpeg"), String.valueOf(list.get(a)));
String fileName = "photo" + a + ".jpg";
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploaded_file"+a, fileName, fileBody);
files.add(filePart);
}
Call<String> uploadPost = posts.uploadPost(files,hashMap);
uploadPost.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful() && response.body() != null) {
Intent intent = new Intent(upload_sale.this, MainActivity.class);
startActivity(intent);
finish();
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("upload_post",t.getMessage());
}
});
Here is the php code :
$authNum = $_POST['authNum'];
$title = $_POST['title'];
$des = $_POST['description'];
$price = $_POST['price'];
$area = $_POST['area'];
$longitude = $_POST['longitude'];
$latitude = $_POST['latitude'];
$count = $_POST['count'];
$count_int = (int)$count;
if(isset($_FILES['uploaded_file0']['name'])) {
for($i = 0; $i<$count_int; $i++) {
$basename = basename($_FILES['uploaded_file'.$i]['name']);
$file_path = $file_path . $basename;
if(isset($_FILES['uploaded_file'.$i])) {
move_uploaded_file($_FILES['uploaded_file'.$i]['tmp_name'],"./postImage/".$fn.$basename);
$query_img =
"INSERT INTO post_img(path,authNum,img_del,post_authNum)
VALUES ('http://3.36.34.173/postImage/".$fn.$basename."',$authNum,'../postImage/".$fn.$basename."','$post_authNum')
";
}
Thank you in advance.enter image description here

How to save chatbot input from user using Dialogflow into firebase ( Android Studio )

I want to send money between different PaypalCustomerAccount, every user's transaction would be recorded in UserTransaction table. Example in the photo, PaypalCustomerAccount user_id rmMe7a68kOXIvblu4aah1ZHc7Qx2. When she makes a transaction it will be saved into UserTransaction table with its user_id with a new transaction_id -LOvXSpmHnjmN2sWkhap.
enter image description here
I want to use a chatbot from DialogFlow integrated in Android Studio to send money between the PaypalCustomerAccount.
In the screenshot is how to android app chatbot looks like, when user wants to send a "whoosh"(digital cheque), the conversation goes:
send a whoosh Sure
who would u like to send it to
enter image description here
send it to susie
May i know the post date for the cheque
enter image description here
send it tmr
Alright, ive sent a whoosh to susie it will be processed by
2018-10-17
enter image description here
Now after the user makes the request, i want to save the request of the new transaction to my firebase. From PaypalCustomerAccount rmMe7a68kOXIvblu4aah1ZHc7Qx2 to a2u4aqw3Hc7Qx2 .
Meaning a new Transaction record will appear under UserTransaction:
for a2u4aqw3Hc7Qx2 and the status will be receive.
for rmMe7a68kOXIvblu4aah1ZHc7Qx2 status will be sent.
The follow below is index.js code in fulfilment page for Dialog Flow. I do not know how to write the codes in order for the above described to happen (Meaning a new Transaction record will appear under UserTransaction)
Do i write the codes in dialog flow or in my android studio (the backend for chatbot code) for that to happen?
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
// initialise DB connection
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: 'ws://whooshapplication.firebaseio.com/',
});
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function SendWhoosh(agent)
{
const nameParam = agent.parameters.name;
const context = agent.getContext('send_a_whoosh');
const name = nameParam || context.parameters.name;
// push input into db
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// // Uncomment and edit to make your own intent handler
// // uncomment `intentMap.set('your intent name here', yourFunctionHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function yourFunctionHandler(agent) {
// agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
// agent.add(new Card({
// title: `Title: this is a card title`,
// imageUrl: 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
// text: `This is the body text of a card. You can even use line\n breaks and emoji! 馃拋`,
// buttonText: 'This is a button',
// buttonUrl: 'https://assistant.google.com/'
// })
// );
// agent.add(new Suggestion(`Quick Reply`));
// agent.add(new Suggestion(`Suggestion`));
// agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
// }
// // Uncomment and edit to make your own Google Assistant intent handler
// // uncomment `intentMap.set('your intent name here', googleAssistantHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function googleAssistantHandler(agent) {
// let conv = agent.conv(); // Get Actions on Google library conv instance
// conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library
// agent.add(conv); // Add Actions on Google library responses to your agent's response
// }
// // See https://github.com/dialogflow/dialogflow-fulfillment-nodejs/tree/master/samples/actions-on-google
// // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample
// Run the proper function handler based on the matched Dialogflow intent name
[enter image description here][1] let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
enter image description here
This is my android studio ChatBot.java codes for the chatbot to work
public class ChatBot extends AppCompatActivity implements AIListener
{
public Bot bot;
public static Chat chat;
private ListView mListView;
private Button mButtonSend;
private EditText mEditTextMessage;
private Button mImageView;
private ChatMessageAdapter mAdapter;
AIService aiService;
private static final String TAG = "ChatBot";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_bot);
mListView = (ListView) findViewById(R.id.listView);
mImageView = (Button)findViewById(R.id.voice_record);
mButtonSend = (Button) findViewById(R.id.btn_send);
mEditTextMessage = (EditText) findViewById(R.id.et_message);
mAdapter = new ChatMessageAdapter(this, new ArrayList<ChatMessage>());
mListView.setAdapter(mAdapter);
int permission = ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO);
if (permission != PackageManager.PERMISSION_GRANTED)
{
Log.i(TAG, "Permission to record denied");
makeRequest();
}
final AIConfiguration config = new AIConfiguration("c43d5450b1a54959a44158fb897f1dcb",
AIConfiguration.SupportedLanguages.English,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, config);
aiService.setListener(this);
mButtonSend.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
String message = mEditTextMessage.getText().toString();
//bot
String response = chat.multisentenceRespond(mEditTextMessage.getText().toString());
if (TextUtils.isEmpty(message))
{
return;
}
sendMessage(message);
mimicOtherMessage(response);
mEditTextMessage.setText("");
mListView.setSelection(mAdapter.getCount() - 1);
}
});
mImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
aiService.startListening();
}
});
// *************************************
//checking SD card availablility
boolean a = isSDCARDAvailable();
//receiving the assets from the app directory
AssetManager assets = getResources().getAssets();
File jayDir = new File(Environment.getExternalStorageDirectory().toString() + "/cheque/bots/whoosh");
boolean b = jayDir.mkdirs();
if (jayDir.exists())
{
//Reading the file
try {
for (String dir : assets.list("whoosh")) {
File subdir = new File(jayDir.getPath() + "/" + dir);
boolean subdir_check = subdir.mkdirs();
for (String file : assets.list("whoosh/" + dir)) {
File f = new File(jayDir.getPath() + "/" + dir + "/" + file);
if (f.exists())
{
continue;
}
InputStream in = null;
OutputStream out = null;
in = assets.open("whoosh/" + dir + "/" + file);
out = new FileOutputStream(jayDir.getPath() + "/" + dir + "/" + file);
//copy file from assets to the mobile's SD card or any secondary memory
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
}
}
} catch (IOException e)
{
e.printStackTrace();
}
}
//get the working directory
MagicStrings.root_path = Environment.getExternalStorageDirectory().toString() + "/cheque";
System.out.println("Working Directory = " + MagicStrings.root_path);
AIMLProcessor.extension = new PCAIMLProcessorExtension();
//Assign the AIML files to bot for processing
bot = new Bot("whoosh", MagicStrings.root_path, "chat");
chat = new Chat(bot);
String[] args = null;
mainFunction(args);
// *************************************
} // onCreate
protected void makeRequest()
{
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
101);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{
switch (requestCode)
{
case 101:
{
if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED)
{
Log.i(TAG, "Permission has been denied by user");
}
else
{
Log.i(TAG, "Permission has been granted by user");
}
return;
}
}
}
public void voiceclick(View view)
{
aiService.startListening();
}
//check SD card availability
public static boolean isSDCARDAvailable()
{
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)? true :false;
}
//copying the file
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
} //copyFile
//Request and response of user and the bot
public static void mainFunction (String[] args)
{
MagicBooleans.trace_mode = false;
System.out.println("trace mode = " + MagicBooleans.trace_mode);
Graphmaster.enableShortCuts = true;
Timer timer = new Timer();
String request = "Hello.";
String response = chat.multisentenceRespond(request);
System.out.println("Human: "+request);
System.out.println("Robot: " + response);
} //mainFunction
private void sendMessage(String message)
{
ChatMessage chatMessage = new ChatMessage(message, true, false);
mAdapter.add(chatMessage);
//respond as Helloworld
mimicOtherMessage("HelloWorld");
} //sendMessage
private void mimicOtherMessage(String message)
{
ChatMessage chatMessage = new ChatMessage(message, false, false);
mAdapter.add(chatMessage);
}
private void sendMessage()
{
ChatMessage chatMessage = new ChatMessage(null, true, true);
mAdapter.add(chatMessage);
mimicOtherMessage();
}
private void mimicOtherMessage()
{
ChatMessage chatMessage = new ChatMessage(null, false, true);
mAdapter.add(chatMessage);
}
#Override
public void onResult(AIResponse result)
{
Log.d("anu",result.toString());
Result result1 = result.getResult();
mEditTextMessage.setText("Query" + result1.getResolvedQuery() + " action: " + result1.getAction());
}
#Override
public void onError(AIError error) {
}
#Override
public void onAudioLevel(float level) {
}
#Override
public void onListeningStarted() {
}
#Override
public void onListeningCanceled() {
}
#Override
public void onListeningFinished() {
}
}
enter image description here
Here is also a screenshot of my intent in dialogflow
enter image description here
enter image description here
Please help me! and thank you in advance
First of all, Awesome Project on which you are working on, implementing the real-time chatbot transaction management.
I have reviewed each file you have attached and your asked question properly. I want to highlight some important steps that you can follow to implement the asked thing that are:
Checkout and implement Paypal SDK in your Android Application: https://github.com/paypal/PayPal-Android-SDK
Then, using the methods and objects you can simply put the returned values of any transaction from Paypal to your android application and thus, you can pass that on Realtime Database at Firebase.
The Chatbot Code is fine here, just you have to trigger action on particular intent calling of when the user says to send money to someone, to the android application backend where the Paypal code will run in Android Class File.
I hope you have got me! Better to know more, please feel free to ask doubts in reply section.
All the best for your future implementation!

What type of error is this Error: ENOENT: no such file or directory, open

I am getting stuck at this error and not able to resolve this issue.
Error: ENOENT: no such file or directory, open 'C:\Users\sagarkumar\AppData\Loca
l\Temp;C:\Program Files\Java\jdk1.7.0_51\bin\8852-120drlh.jpg'
This is app.js file
var express = require('express');
var connect = require('connect');
var app = express();
var port = process.env.PORT || 8080;
// Configuration
app.use(express.static(__dirname + '/public'));
app.use(connect.cookieParser());
app.use(connect.logger('dev'));
app.use(connect.bodyParser());
app.use(connect.json());
app.use(connect.urlencoded());
// Routes
require('./routes/routes.js')(app);
app.listen(port);
console.log('The App runs on port ' + port);
This is route.js file
var fs = require('fs');
module.exports = function(app) {
app.get('/',function(req,res){
res.end("Node-File-Upload");
});
/*
app.post('/upload', function(req, res) {
console.log(req.files.image.originalFilename);
console.log(req.files.image.path);
fs.readFile(req.files.image.path, function (err, data){
var dirname = "sagar/";
var newPath = dirname + "/uploads/" + req.files.image.originalFilename;
fs.writeFile(newPath, data, function (err) {
if(err){
res.json({'response':"Error"});
}else {
res.json({'response':"Saved"});
}
});
});
*/
app.post('/upload', function(req, res) {
res.json({'response':"Saved"});
}
);
This is android code(client side) making json request(Only requesting part).
There is select button which is choosing image from gallery and upload button making request to nodejs server.
upload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File f = new File(path);
Future uploading = Ion.with(nodejs.this)
.load("http://192.168.0.101:8080/upload")
.setMultipartFile("image",f)
.asString()
.withResponse()
.setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
try {
JSONObject jobj = new JSONObject(result.getResult());
}
catch (JSONException e1) {
e1.printStackTrace();
}
}
});
}
});
The file C:\Users\sagarkumar\AppData\Loca l\Temp;C:\Program Files\Java\jdk1.7.0_51\bin\8852-120drlh.jpg doesn't exist. It looks like you appended two filenames together.
ENOENT = Error NO ENTity.
You have a problem with the file, maybe your path its wrong or the name of the file, but sure the problem is with your file.

Unity3D, C# and uploading tracks to SoundCloud

I am working on an app in Unity3D which can upload tracks to SoundCloud. I have been working on this for a while but i can't get it to work. I am using HttpWebRequest for the request to SoundCloud and this works fine on Unity for Windows. But when i try it on my Android device i get the following message: 'Request entity contains invalid byte sequence. Please transmit valid UTF-8.'.
Below is the part of code that i use (got it from somewhere on the internet).
I made sure i was uploading the same file on Windows as on Android and did the request to RequestBin. Now, when i compared the two, i noticed that the raw data is almost completely identical except for the end:
Ending Windows: 每脿镁鲁镁D镁每媒毛媒脜媒脵媒
Ending Android: 每脿镁鲁镁D镁每媒毛媒脜媒脵媒[FF]镁脼媒镁没媒C镁x镁Z镁{镁
So as you can see, on Android there is more data. Can someone explain to me what is going on here?
I started with posts on the Unity community, now trying it here. Here you can find my question on the unity website for more information.
public class SoundCloudScript {
//Enter app credentials from here http://soundcloud.com/you/apps
private const string _clientId = "xxx";
private const string _clientSecret = "xxx";
//enter username and password a soundcloud user, e.g. your own credentials
private const string _username = "xxx";
private const string _password = "xxx";
private string soundCloudToken;
//private WebClient _webclient = new WebClient();
public string Status { get; set; }
public IEnumerator GetTokenAndUploadFile(MonoBehaviour mono, FileInfo file)
{
Debug.Log ( "GetTokenAndUploadFile() started");
ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
var form = new WWWForm ();
form.AddField ("client_id", _clientId);
form.AddField ("client_secret", _clientSecret);
form.AddField ("grant_type", "password");
form.AddField ("username", _username);
form.AddField ("password", _password);
//Authentication
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
Debug.Log ( "Try to get token");
WWW download = new WWW(soundCloudTokenRes, form);
yield return download;
if(!string.IsNullOrEmpty(download.error))
{
Debug.Log ( "Error downloading: " + download.error );
}
else
{
var tokenInfo = download.text;
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
soundCloudToken = tokenInfo.Remove(tokenInfo.IndexOf("\""));
Debug.Log(string.Format("Token set: {0}", soundCloudToken));
UploadFile(file);
}
}
public void UploadFile(FileInfo file)
{
Debug.Log ("Start uploading!");
ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks/") as HttpWebRequest;
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[]
{
new UploadFile(file.FullName, "track[asset_data]", "application/octet-stream")
};
//other form data
var form = new System.Collections.Specialized.NameValueCollection();
form.Add("track[title]", "Some title");
form.Add("track[sharing]", "private");
form.Add("oauth_token", soundCloudToken);
form.Add("format", "json");
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
reader.ReadToEnd();
}
}
Debug.Log ("Upload success!");
}
catch (WebException wex) {
if (wex.Response != null) {
using (var errorResponse = (HttpWebResponse)wex.Response) {
using (var reader = new StreamReader(errorResponse.GetResponseStream())) {
string error = reader.ReadToEnd();
Debug.Log ("Error(1/2): Message: " + wex.Message);
Debug.Log ("Error(2/2): " + error);
//TODO: use JSON.net to parse this string and look at the error message
}
}
}
}
//return "Nothing...";
}
}
public class StreamMimePart : MimePart
{
Stream _data;
public void SetStream(Stream stream)
{
_data = stream;
}
public override Stream Data
{
get
{
return _data;
}
}
}
public abstract class MimePart
{
NameValueCollection _headers = new NameValueCollection();
byte[] _header;
public NameValueCollection Headers
{
get { return _headers; }
}
public byte[] Header
{
get { return _header; }
}
public long GenerateHeaderFooterData(string boundary)
{
StringBuilder sb = new StringBuilder();
sb.Append("--");
sb.Append(boundary);
sb.AppendLine();
foreach (string key in _headers.AllKeys)
{
sb.Append(key);
sb.Append(": ");
sb.AppendLine(_headers[key]);
}
sb.AppendLine();
_header = Encoding.UTF8.GetBytes(sb.ToString());
return _header.Length + Data.Length + 2;
}
public abstract Stream Data { get; }
}
public class StringMimePart : MimePart
{
Stream _data;
public string StringData
{
set
{
_data = new MemoryStream(Encoding.UTF8.GetBytes(value));
}
}
public override Stream Data
{
get
{
return _data;
}
}
}
public class HttpUploadHelper
{
private HttpUploadHelper()
{ }
public static string Upload(string url, UploadFile[] files, NameValueCollection form)
{
HttpWebResponse resp = Upload((HttpWebRequest)WebRequest.Create(url), files, form);
using (Stream s = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(s))
{
return sr.ReadToEnd();
}
}
public static HttpWebResponse Upload(HttpWebRequest req, UploadFile[] files, NameValueCollection form)
{
List<MimePart> mimeParts = new List<MimePart>();
try
{
foreach (string key in form.AllKeys)
{
StringMimePart part = new StringMimePart();
part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
part.StringData = form[key];
mimeParts.Add(part);
}
int nameIndex = 0;
foreach (UploadFile file in files)
{
StreamMimePart part = new StreamMimePart();
if (string.IsNullOrEmpty(file.FieldName))
file.FieldName = "file" + nameIndex++;
part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
part.Headers["Content-Type"] = file.ContentType;
part.SetStream(file.Data);
mimeParts.Add(part);
}
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
long contentLength = 0;
byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
foreach (MimePart part in mimeParts)
{
contentLength += part.GenerateHeaderFooterData(boundary);
}
req.ContentLength = contentLength + _footer.Length;
Debug.Log ("ContentLength: " + req.ContentLength);
byte[] buffer = new byte[8192];
byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
int read;
foreach(var header in req.Headers)
{
Debug.Log(header);
}
using (Stream s = req.GetRequestStream())
{
foreach (MimePart part in mimeParts)
{
s.Write(part.Header, 0, part.Header.Length);
while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
{
s.Write(buffer, 0, read);
Debug.Log ("Buffer: >>" + System.Text.Encoding.UTF8.GetString(buffer) + "<<");
}
//Debug.Log ("Buffer: " + System.Text.Encoding.UTF8.GetString(buffer));
part.Data.Dispose();
s.Write(afterFile, 0, afterFile.Length);
Debug.Log ("Buffer-End: >>" + System.Text.Encoding.UTF8.GetString(afterFile) + "<<");
}
s.Write(_footer, 0, _footer.Length);
Debug.Log ("Footer: >>" + System.Text.Encoding.UTF8.GetString(_footer) + "<<");
}
return (HttpWebResponse)req.GetResponse();
}
catch (Exception e)
{
Debug.Log ("Crash! Message: " + e.Message);
foreach (MimePart part in mimeParts)
if (part.Data != null)
part.Data.Dispose();
throw;
}
}
}
public class UploadFile
{
Stream _data;
string _fieldName;
string _fileName;
string _contentType;
public UploadFile(Stream data, string fieldName, string fileName, string contentType)
{
_data = data;
_fieldName = fieldName;
_fileName = fileName;
_contentType = contentType;
}
public UploadFile(string fileName, string fieldName, string contentType)
: this(File.OpenRead(fileName), fieldName, Path.GetFileName(fileName), contentType)
{ }
public UploadFile(string fileName)
: this(fileName, null, "application/octet-stream")
{ }
public Stream Data
{
get { return _data; }
set { _data = value; }
}
public string FieldName
{
get { return _fieldName; }
set { _fieldName = value; }
}
public string FileName
{
get { return _fileName; }
set { _fileName = value; }
}
public string ContentType
{
get { return _contentType; }
set { _contentType = value; }
}
}
It's working!! The problem was that at some point i used StringBuilder.AppendLine() to add a new line. This works fine on Windows, but on Android it didn't work... (i figured it out because the Content-Length was not the same for Windows and Android.)
I fixed it by instead of using 'StringBuilding.AppendLine()', i use 'StringBuilder.Append("\r\n")'

Retrofit file upload, objects are null on the server side

I want to send a photo from local android gallery to the server http Tomcat. For the communication I'm using retrofit. I've established the connection between device and server, and the programme get into servers function but all objects in params are null.
That's the device function declaration on the client side:
#Multipart
#POST("/monument/photo/upload")
void addMonumentPhoto(#Part("MonumentID") Integer monumentId,
#Part("name") String name,
#Part("subscript") String subscript,
#Part("photo") TypedFile photo,
Callback<Photo> callback);
... and that's how I call it:
photo = _resizePhoto(new File(monument.getUriZdjecie()));
typedFile = new TypedFile("multipart/mixed", photo);
//long bytes = photo.length();
if (photo.exists()) {
MonumentsUtil.getApi().addMonumentPhoto(monument.getIdZabytek(),
"podpis",
"Main photo",
typedFile,
new Callback<Photo>() {
#Override
public void success(Photo aPhoto, Response response) {
monument.setUriZdjecie(aPhoto.getUri());
MonumentsUtil.getApi().addMonument(monument.getNazwa(),
monument.getOpis(),
monument.getDataPowstania(),
monument.getWojewodztwo(),
monument.getUriZdjecie(),
monument.getMiejscowosc(),
monument.getKodPocztowy(),
monument.getUlica(),
monument.getNrDomu(),
monument.getNrLokalu(),
monument.getKategoria(),
monument.getLatitude(),
monument.getLongitude(),
new MonumentsCallback());
}
#Override
public void failure(RetrofitError retrofitError) {
Log.e(TAG, retrofitError.getMessage());
}
});
}
and the server's method:
#RequestMapping(value = "/monument/photo/upload")
public
#ResponseBody
Photo requestMonumentPhotoAdd(#RequestParam(value = "MonumentID", required = false) Integer monumentId,
#RequestParam(value = "name", required = false) String name,
#RequestParam(value = "subscript", required = false) String subscript,
#RequestParam(value = "photo", required = false) MultipartFile file,
HttpServletRequest request) {
Photo photo = new Photo();
if (monumentId != null)
photo.setIdZabytek(monumentId);
photo.setUri(URL + "/images/" + name);
photo.setPodpis(subscript);
photo = monumentsRepo.addPhoto(photo);
String filePath = "D:\\Projects\\Images\\" + monumentId + "_" + photo.getIdZjecia();
if (file != null) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(filePath)));
stream.write(bytes);
stream.close();
photo.setUri(filePath);
monumentsRepo.updatePhoto(photo);
return photo;
} catch (Exception e) {
return null;
}
} else {
return null;
}
}
else {
return null;
}
}
Can anybody help me and explain why all objects after geting into the servers method are null?
Maybe method is wrogly writen or the mime field of TypedFile is wrogly chosen but I read that the "multipart/mixed" mime type is for messages with various types of object included in message. I don't have any idea so any advice will be helpful.
Try when creating your TypedFile object to use "image/*" as your mime type. For that "part" it is of that specific type. The "mixed" is likely for the submit as a whole, not the single part that is the file.
typedFile = new TypedFile("image/*", photo);
I also had the similar problems and after few hours trying I finally built image uploading functionality to remote server.
To upload image you need to create the API properly and also need to pass the image properly.
This should work fine for you:
In Retrofit client you need to set up the image as followed:
String photoName = "20150219_222813.jpg";
File photo = new File(photoName );
TypedFile typedImage = new TypedFile("application/octet-stream", photo);
RetrofitClient.uploadImage(typedImage, new retrofit.Callback<Photo>() {
#Override
public void success(Photo photo, Response response) {
Log.d("SUCCESS ", "SUCCESS RETURN " + response);
}
#Override
public void failure(RetrofitError error) {
}
});
API SET UP:
#Multipart
#POST("/")
void uploadImage(#Part("file") TypedFile file, Callback<Photo> callback);
Remote Server Side PHP Code to handle the image:
........
$pic = 'uploaded_images/' . $imagename . '.jpg';
if (!move_uploaded_file($_FILES['file']['tmp_name'], $pic)) {
echo "posted";
}
.........
If it helps any one please recognize me..thanks a lot..

Categories

Resources