I am trying to upload image from client (flutter) to server (Aqueduct.io) using MultipartRequest.
It's working, but currently file names are assigned the current time, how can I pass the filename from a client and parse it on a server side?
Client code:
final String imageName = nameController.text.replaceAll(" ", "");
var postUri = Uri.parse("http://***:8888/media");
var request = new http.MultipartRequest("POST", postUri);
request.files.add(new http.MultipartFile.fromBytes('file', image,
filename: imageName, contentType: MediaType('image', 'jpeg')));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
}
Server code:
import 'dart:async';
import 'dart:io';
import 'package:aqueduct/aqueduct.dart';
import 'package:mime/mime.dart';
import 'package:http_server/http_server.dart';
class MediaController extends ResourceController {
MediaController() {
acceptedContentTypes = [ContentType("multipart", "form-data")];
}
#Operation.post()
Future<Response> postMultipartForm() async {
final transformer = MimeMultipartTransformer(
request.raw.headers.contentType.parameters["boundary"]);
final bodyStream =
Stream.fromIterable([await request.body.decode<List<int>>()]);
final parts = await transformer.bind(bodyStream).toList();
for (var part in parts) {
final HttpMultipartFormData multipart = HttpMultipartFormData.parse(part);
final content = multipart.cast<List<int>>();
final filePath =
"public/" + DateTime.now().millisecondsSinceEpoch.toString() + ".jpg"; // <---current filename implementation
final IOSink sink = File(filePath).openWrite();
await for (List<int> item in content) {
sink.add(item);
}
await sink.flush();
await sink.close();
}
return Response.ok({});
}
}
Okay, I have the asnwer
import 'dart:async';
import 'dart:io';
import 'package:aqueduct/aqueduct.dart';
import 'package:mime/mime.dart';
import 'package:http_server/http_server.dart';
class MediaController extends ResourceController {
MediaController() {
acceptedContentTypes = [ContentType("multipart", "form-data")];
}
#Operation.post()
Future<Response> postMultipartForm() async {
final transformer = MimeMultipartTransformer(
request.raw.headers.contentType.parameters["boundary"]);
final bodyStream =
Stream.fromIterable([await request.body.decode<List<int>>()]);
final parts = await transformer.bind(bodyStream).toList();
for (var part in parts) {
final HttpMultipartFormData multipart = HttpMultipartFormData.parse(part);
List<String> tokens = part.headers['content-disposition'].split(";");
String filename;
for (var i = 0; i < tokens.length; i++) {
if (tokens[i].contains('filename')) {
filename = tokens[i]
.substring(tokens[i].indexOf("=") + 2, tokens[i].length - 1);
}
}
print('file $filename.jpg uploaded');
final content = multipart.cast<List<int>>();
final filePath =
// "public/" + DateTime.now().millisecondsSinceEpoch.toString() + ".jpg";
'public/$filename.jpg';
final IOSink sink = File(filePath).openWrite();
await for (List<int> item in content) {
sink.add(item);
}
await sink.flush();
await sink.close();
}
return Response.ok({});
}
}
Related
I'm building a server and I need to serve binary files.
My code is this:
//lib/handler.dart
import 'dart:io';
import 'package:mime/mime.dart';
class FileResponse {
Object name;
ContentType type;
FileResponse(this.name, this.type);
}
Object tr(String f) {
Object res = File(f).readAsBytesSync();
try {
File(f).readAsStringSync();
res = File(f).readAsStringSync();
} catch(_) {}
return res;
}
FileResponse fileHandler(String uri) {
if(uri == "/") uri = "/index.html";
if(File("/Users/jett/Sites$uri").existsSync()) {
ContentType tpe = ContentType.parse(lookupMimeType(uri)!);
Object resp = tr("/Users/jett/Sites/$uri");
return FileResponse(resp, tpe);
} else if(File("/Users/jett/Sites$uri/index.html").existsSync()) {
ContentType tpe = ContentType.parse(lookupMimeType(uri)!);
Object resp = tr("/Users/jett/Sites/$uri/index.html");
return FileResponse(resp, tpe);
} else if(File("/Users/jett/Sites${uri}index.html").existsSync()) {
ContentType tpe = ContentType.parse(lookupMimeType(uri)!);
Object resp = tr("/Users/jett/Sites/${uri}index.html");
return FileResponse(resp, tpe);
} else {
return FileResponse(File("/Users/jett/Sites/404.html").readAsStringSync(), ContentType.html);
}
}
//bin/srv.dart
import 'package:srv/handler.dart';
import 'dart:io';
void main() async {
final HttpServer srvs = await HttpServer.bindSecure('127.0.0.1', 443, SecurityContext()..useCertificateChain("/Users/jett/srv/fc.pem"));
final HttpServer srv = await HttpServer.bind('127.0.0.1', 80);
await for(final HttpRequest request in srv) {
print(request.uri.path);
FileResponse res = fileHandler(request.uri.path);
request.response
..headers.contentType = res.type
..write(res.name);
request.response.close();
}
}
I created an empty server and added a handler to it. The file handler checks for an existing file or a 404 page. The text files work fine(html js css json)... but the image and video files crash.
And the docs tell me this:
// TODO(ajohnsen): Add documentation of how to pipe a file to the response.
So how do I pipe a binary file into the response.
I'm trying to create an alarm in Flutter where an alarm tone should go off after a certain time. It seems like this is easier said than done in Flutter!
Tried to use the audioplayer plugin to achieve this. Used the playLocal function wherein the asset is loaded from the rootbundle into the app directory and then played
According to an answer in the audioplayer github repo, this is the code that should do the trick:
class SoundManager {
AudioPlayer audioPlayer = new AudioPlayer();
Future playLocal(localFileName) async {
final dir = await getApplicationDocumentsDirectory();
final file = new File("${dir.path}/$localFileName");
if (!(await file.exists())) {
final soundData = await rootBundle.load("assets/$localFileName");
final bytes = soundData.buffer.asUint8List();
await file.writeAsBytes(bytes, flush: true);
}
await audioPlayer.play(file.path, isLocal: true);
}
}
I keep getting an error: "Unable to load asset". The asset (mp3/wav file) is obviously in the folder, and the folder is included in the pubspec.yaml file correctly (other image assets are loading properly from this folder, so specifying the folder itself is not the issue here)
You can use another audio library https://pub.dev/packages/audioplayers
AudioCache documentation.
https://github.com/luanpotter/audioplayers/blob/master/doc/audio_cache.md
Simple example:
import 'package:audioplayers/audio_cache.dart';
AudioCache player = AudioCache();
player.play('sounds/test_sound.m4a');
In this example my assets folder looks like this: assets/sounds/test_sound.m4a
This library cached audio as local file and then play audio
PS: If you want to play music from local files you can use AudioPlayer().
My example with listener on return, onPlayCompletion will be called when music end
AudioPlayer _advancedPlayer = AudioPlayer();
Stream<void> playFromLocal(int unitId, int id) {
var link = '/media/$unitId/words/$id.m4a';
_advancedPlayer.stop();
_advancedPlayer.release();
_advancedPlayer = AudioPlayer();
_advancedPlayer.play(Const.basePath + link, isLocal: true);
return _advancedPlayer.onPlayerCompletion;
}
This works well for both iOS and Android. Note: this downloads from url if not available locally.
AudioProvider audioProvider;
_playSound() async {
audioProvider = AudioProvider("http:...");
var soundToPlay = "myLocalSound";
String localUrl = await audioProvider.load(soundToPlay);
SoundController.play(localUrl);
}
}
audio_provider.dart
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:http/http.dart';
typedef void OnError(Exception exception);
class AudioProvider {
String url;
AudioProvider(String url) {
this.url = url;
}
Future<Uint8List> _loadFileBytes(String url, {OnError onError}) async {
Uint8List bytes;
try {
bytes = await readBytes(url);
} on ClientException {
rethrow;
}
return bytes;
}
Future<String> load(fileName) async {
final dir = await getApplicationDocumentsDirectory();
final file = new File('${dir.path}/$fileName');
if (await file.exists()) {print("file exists");
return file.path;
}
var filePath = url +fileName;
final bytes = await _loadFileBytes(filePath,
onError: (Exception exception) =>
print('audio_provider.load => exception ${exception}'));
await file.writeAsBytes(bytes);
if (await file.exists()) {
return file.path;
}
return '';
}
}
soundController.dart
import 'package:flutter/foundation.dart';
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'dart:io' show Platform;
void audioPlayerHandler(AudioPlayerState value) => null;
class SoundController {
static AudioPlayer audioPlayer = AudioPlayer(mode: PlayerMode.LOW_LATENCY);
static AudioCache audioCache = AudioCache(prefix: "assets/audio/", fixedPlayer: audioPlayer);
static void play(String sound) {
if (!kIsWeb && Platform.isIOS) {
audioPlayer.monitorNotificationStateChanges(audioPlayerHandler);
}
audioPlayer.play(sound, isLocal: true);
}
}
I am using the Flutter Plugin Image_picker to choose images so that I want to upload image after selected the image
Future<File> _imageFile;
void _onImageButtonPressed(ImageSource source) async {
setState(() {
_imageFile = ImagePicker.pickImage(source: source);
});
}
I find this code in flutter documentation but its not work
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'nweiz#google.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new MediaType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Use MultipartRequest class
Upload(File imageFile) async {
var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
//contentType: new MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
Check this answer
This code works properly.
Used MultipartRequest class
void uploadImage() async {
File _image;
File pickedImage = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = pickedImage;
});
// open a byteStream
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
// get file length
var length = await _image.length();
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "image_file" is a key of the API request
var multipartFile = new http.MultipartFile('image_file', stream, length, filename: basename(_image.path));
// add file to multipart
request.files.add(multipartFile);
// send request to upload image
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
name spaces:
import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
If you want the uploading function to return the server response, you can use toBytes() instead of transform(), in order to wait until data transmission is complete.
Future<String> upload() async {
String responseString = '';
// Pick image
final image = await ImagePicker().getImage(
source: ImageSource.gallery // or ImageSource.camera
imageQuality: 100,
maxWidth: 1000,
);
// Convert to File
final file = File(image.path);
// Set URI
final uri = Uri.parse('URL');
// Set the name of file parameter
final parameter = 'Name';
// Upload
final request = http.MultipartRequest('POST', uri)
..files.add(await http.MultipartFile.fromPath(parameter, file.path));
final response = await request.send();
if (response.statusCode == 200) {
responseString = String.fromCharCodes(await response.stream.toBytes());
}
return responseString;
}
I have already try to understand the API doc, the articles about them, and this post: How do you create a Stream in Dart
I'm making a simple web app using WebSocket. Actually, it's working well, but I want add a feature (enjoy learn).
This is my class (can be optimized I guess)
library Ask;
import 'dart:html';
import 'dart:async';
import 'dart:convert';
class Ask {
final String addr;
String _protocol;
String _port;
WebSocket _ws;
bool openned;
Map<int, Completer> _completer_list = {};
int _counter = 0;
static final Map<String, Ask> _cache = <String, Ask>{};
factory Ask(String addr) {
if (_cache.containsKey(addr)) {
return _cache[addr];
} else {
final ask_server = new Ask._internal(addr);
_cache[addr] = ask_server;
return ask_server;
}
}
Ask._internal(this.addr);
Future<bool> open() {
if (openned)
return true;
_completer_list[0] = new Completer();
if (window.location.protocol == 'http:') {
_port = ':8080/ws';
_protocol = 'ws://';
} else {
_port = ':8443/ws';
_protocol = 'wss://';
}
_ws = new WebSocket(_protocol + addr + _port);
_ws.onOpen.listen((e) {
_get_data();
_get_close();
openned = true;
_completer_list[0].complete(true);
});
return _completer_list[0].future;
}
Future<String> send(Map data) {
bool check = false;
int id;
_completer_list.forEach((k, v) {
if (v.isCompleted) {
id = data['ws_id'] = k;
_completer_list[k] = new Completer();
_ws.send(JSON.encode(data));
check = true;
}
});
if (!check) {
_counter++;
id = data['ws_id'] = _counter;
_completer_list[id] = new Completer();
_ws.send(JSON.encode(data));
}
return _completer_list[id].future;
}
void _get_data() {
_ws.onMessage.listen((MessageEvent data) {
var response = JSON.decode(data.data);
_completer_list[response['ws_id']].complete(response);
});
}
void _get_close() {
_ws.onClose.listen((_) {
print('Server have been lost. Try to reconnect in 3 seconds.');
new Timer(new Duration(seconds: 3), () {
_ws = new WebSocket(_protocol + addr + _port);
_get_data();
_get_close();
_ws.onOpen.listen((e) => print('Server is alive again.'));
});
});
}
}
Example of use:
void showIndex() {
Element main = querySelector('main');
Ask connect = new Ask('127.0.0.1');
Map request = {};
request['index'] = true;
connect.open().then((_) {
connect.send(request).then((data) {
main.setInnerHtml(data['response']);
});
});
}
I would replace the then by a listen who will be canceled when the message will completed. By this way, I can add a progress bar, I think...
So my question, my send function can be a stream and keep my concept of one websocket for all ? (yes, if my function is used when a request is in progress, it's sent and if she's finish before the first, I recovered her properly. Thank you ws_id).
Thank you.
I think what you need is a StreamController
https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-async.StreamController
I am trying to show image on screen by using client server, but I got exception
Protocol not found: net.rim.device.cldc.io.ftp.Protocol" , java.lang.IllegalArgumentException.
Here I have post the code where I get the exception(Currently on app I successfully login with client server, show folders & directories, now I want to click on any file it open on new screen.)
package com.rim.samples.device.mapactiondemo;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.container.MainScreen;
public class ShowData extends MainScreen {
String connParams;
public ShowData() {
// Check Type of connection
CheckConnection obj1 = new CheckConnection();
connParams = obj1.getConnParam();
Bitmap listThumb;
String path = "ftp://dice:pAssw0rd#64.207.149.236:21/images/facebook.png"
+ connParams + "";
listThumb = getImage.getImageFromUrl(path);
BitmapField bitmapField1 = new BitmapField(listThumb);
add(bitmapField1);
}
}
getImage.java
package com.rim.samples.device.mapactiondemo;
import javax.microedition.io.Connector;
import javax.microedition.io.SocketConnection;
import java.io.IOException;
import java.io.InputStream;
import java.lang.String;
import net.rim.device.api.system.Bitmap;
public final class getImage {
/**
* Fetches the content on the speicifed url. The url of the content to fetch
*/
public static Bitmap getImageFromUrl(String url) {
Bitmap bitmap = null;
try {
String bitmapData = getDataFromUrl(url);
bitmap = Bitmap.createBitmapFromBytes(bitmapData.getBytes(), 0,
bitmapData.length(), 1);
// Image.createImage(imageData.getBytes(), 0,imageData.length());
} catch (Exception e1) {
e1.printStackTrace();
System.out.println(e1);
}
return bitmap;
}
/**
* Fetches the content on the speicifed url. The url of the content to fetch
*/
private static String getDataFromUrl(String url) {
StringBuffer b = new StringBuffer();
InputStream is = null;
SocketConnection c = null;
long len = 0;
int ch = 0;
try {
c = (SocketConnection) Connector.open(url);
c.setSocketOption(SocketConnection.LINGER, 5);
c.setSocketOption(SocketConnection.DELAY, 5);
is = c.openInputStream();
//len = is.getLength();
if (len != -1) {
// Read exactly Content-Length bytes
for (int i = 0; i < len; i++)
if ((ch = is.read()) != -1) {
b.append((char) ch);
}
} else {
// Read until the connection is closed.
while ((ch = is.read()) != -1) {
len = is.available();
b.append((char) ch);
}
}
is.close();
c.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return b.toString();
}
}
As far as I know ftp protocol is not implemented in BlackBerry Java SDK. Use http protocol instead of ftp.