Browse Source

mconnect/{share,transfer,download): file sharing - download support

bboozzoo/self-announce
Maciek Borzecki 8 years ago
parent
commit
ae5f975175
3 changed files with 222 additions and 0 deletions
  1. +28
    -0
      src/mconnect/share.vala
  2. +136
    -0
      src/mconnect/transfer-download.vala
  3. +58
    -0
      src/mconnect/transfer.vala

+ 28
- 0
src/mconnect/share.vala View File

@ -20,6 +20,7 @@ class ShareHandler : Object, PacketHandlerInterface {
private const string SHARE = "kdeconnect.share.request";
private const string SHARE_PKT = "kdeconnect.share";
private static string DOWNLOADS = null;
public void use_device(Device dev) {
debug("use device %s for sharing", dev.to_string());
@ -30,9 +31,28 @@ class ShareHandler : Object, PacketHandlerInterface {
}
public static ShareHandler instance() {
if (ShareHandler.DOWNLOADS == null) {
GLib.warning("tutaj");
ShareHandler.DOWNLOADS = Path.build_filename(
Environment.get_user_special_dir(UserDirectory.DOWNLOAD),
"mconnect");
try {
DirUtils.create_with_parents(ShareHandler.DOWNLOADS,
0700);
} catch (IOError e) {
warning("failed to create downloads directory: %s", e.message);
}
}
info("downloads will be saved to %s", ShareHandler.DOWNLOADS);
return new ShareHandler();
}
private static string make_downloads_path(string name) {
return Path.build_filename(ShareHandler.DOWNLOADS, name);
}
public string get_pkt_type() {
return SHARE;
}
@ -56,5 +76,13 @@ class ShareHandler : Object, PacketHandlerInterface {
string name = pkt.body.get_string_member("filename");
debug("file: %s size: %lld", name, pkt.payload.size);
var t = new DownloadTransfer(
new InetSocketAddress(dev.host,
(uint16) pkt.payload.port),
pkt.payload.size,
make_downloads_path(name));
t.start();
}
}

+ 136
- 0
src/mconnect/transfer-download.vala View File

@ -0,0 +1,136 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
class DownloadTransfer : Object {
private InetSocketAddress isa = null;
private File file = null;
private FileOutputStream foutstream = null;
private Cancellable cancel = null;
private SocketConnection conn = null;
public uint64 size = 0;
public uint64 transferred = 0;
public string destination = "";
private Transfer transfer = null;
public DownloadTransfer(InetSocketAddress isa, uint64 size, string dest) {
this.isa = isa;
this.cancel = new Cancellable();
this.destination = dest;
this.size = size;
}
public bool start() {
try {
this.file = File.new_for_path(this.destination + ".part");
this.foutstream = this.file.replace(null, false,
FileCreateFlags.PRIVATE | FileCreateFlags.REPLACE_DESTINATION);
} catch (Error e) {
warning("failed to open destination path %s: %s",
this.destination, e.message);
return false;
}
var client = new SocketClient();
client.connect_async.begin(this.isa, null, this.connected);
return true;
}
private void connected(Object? obj, AsyncResult res) {
try {
var sc = (SocketClient)obj;
this.conn = sc.connect_async.end(res);
var sock = this.conn.get_socket();
socket_set_keepalive(sock);
this.start_transfer();
} catch (Error e) {
var err ="failed to connect: %s".printf(e.message);
warning(err);
this.cleanup_error(err);
}
}
private void start_transfer() {
this.transfer = new Transfer(this.conn.input_stream,
this.foutstream);
this.transfer.progress.connect((t, p) => {
int percent = (int) (100.0 * ((double)p / (double)this.size));
debug("progress: %llu/%llu %d %%", p, this.size, percent);
});
this.transfer.transfer_async.begin(this.cancel,
this.transfer_complete);
}
private void transfer_complete(Object? obj, AsyncResult res) {
info("transfer finished");
try {
var rcvd_bytes = this.transfer.transfer_async.end(res);
debug("transfer done, got %llu bytes", rcvd_bytes);
this.cleanup_success();
} catch (IOError err) {
warning("transfer failed: %s", err.message);
this.cleanup_error(err.message);
}
}
private void cleanup() {
if (this.foutstream != null)
this.foutstream.close();
this.file = null;
this.foutstream = null;
this.transfer = null;
}
private void cleanup_error(string reason) {
this.file.@delete();
this.cleanup();
this.error(reason);
}
private void cleanup_success() {
var failed = false;
try {
var dest = File.new_for_path(this.destination);
this.file.move(dest, FileCopyFlags.OVERWRITE);
this.cleanup();
this.finished();
} catch (IOError e) {
var err = "failed to rename temporary file %s to %s: %s".printf(this.file.get_path(),
this.destination,
e.message);
warning(err);
this.cleanup_error(err);
}
}
public signal void finished();
public signal void error(string reason);
}

+ 58
- 0
src/mconnect/transfer.vala View File

@ -0,0 +1,58 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* AUTHORS
* Maciek Borzecki <maciek.borzecki (at] gmail.com>
*/
class Transfer : Object {
private InputStream from = null;
private OutputStream to = null;
public Transfer(InputStream from, OutputStream to) {
this.from = from;
this.to = to;
}
public async uint64 transfer_async(Cancellable? cancel) throws IOError {
uint64 bytes_done = 0;
var chunk_size = 4096;
var max_chunk_size = 64 * 1024;
while (true) {
var data = yield this.from.read_bytes_async(chunk_size);
debug("read %d bytes", data.length);
if (data.length == 0) {
break;
}
yield this.to.write_bytes_async(data);
bytes_done += data.length;
this.progress(bytes_done);
if (data.length == chunk_size)
chunk_size = 2 * chunk_size;
if (chunk_size > max_chunk_size)
chunk_size = max_chunk_size;
}
debug("transfer done, got %llu bytes", bytes_done);
this.from.close();
this.to.close();
return bytes_done;
}
public signal void progress(uint64 bytes_done);
}

Loading…
Cancel
Save