Created
May 31, 2014 23:20
-
-
Save unixpickle/b104a4f9f5734f365ab5 to your computer and use it in GitHub Desktop.
Download Streaming Rough Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Page = require './page' | |
Session = require '../session' | |
Transfer = require '../transfer' | |
tar = require 'tar-stream' | |
url = require 'url' | |
getTarName = (path) -> | |
result = path.match /\/([^\/]*)$/ | |
str = if result? then result[1] else path | |
if str[str.length - 1] is '/' | |
str = str[0...str.length - 1] | |
return str + '.tar' | |
class Download extends Page | |
constructor: -> super() | |
path: -> '/download' | |
get: (req, res) -> | |
if not req.session.userInfo? | |
return res.redirect 'login' | |
if typeof req.query.hash isnt 'string' | |
return @error res, 'invalid hash parameter' | |
session = new Session req.session.userInfo | |
session.lookupDownload req.query.hash, (err, info) => | |
if err? | |
session.end() | |
return @error res, err.toString() | |
session.getFTP (err, ftp) => | |
throw err if err? | |
@doTransfer res, session, ftp, info | |
doTransfer: (res, session, ftp, info) -> | |
tarClient = tar.pack() | |
transfer = new Transfer info.path, ftp, tarClient, info.path | |
transfer.on 'error', => | |
session.end() | |
tarClient.finalize() | |
transfer.on 'end', => | |
session.end() | |
tarClient.finalize() | |
fileName = getTarName info.path | |
res.setHeader 'content-type', 'application/octet-stream' | |
res.setHeader 'content-disposition', 'attachment; filename=' + fileName | |
tarClient.pipe res | |
transfer.begin() | |
module.exports = Download |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{EventEmitter} = require 'events' | |
class Transfer extends EventEmitter | |
constructor: (@root, @ftp, @tar, @path) -> | |
@dirs = [] | |
@files = [] | |
begin: -> | |
@ftp.list @path, (args...) => @_gotListing args... | |
_gotListing: (err, list) -> | |
return @emit 'error', err if err? | |
for item in list | |
if item.type is 'd' | |
@dirs.push item | |
else if item.type is '-' | |
@files.push item | |
@_getNext() | |
_fullPath: (item) -> | |
if item.name[0] is '/' | |
return item.name | |
if @path[@path.length - 1] == '/' | |
return @path + item.name | |
else | |
return @path + '/' + item.name | |
_getRelative: (path) -> | |
res = path[@root.length..] | |
if res[0] == '/' | |
return res[1..] | |
return res | |
_getNext: -> | |
if @files.length | |
console.log 'getNext -> files' | |
file = @files.pop() | |
@_getFile file | |
else if @dirs.length | |
console.log 'getNext -> dirs' | |
dir = @dirs.pop() | |
@_getDir dir | |
else | |
console.log 'getNext -> end' | |
@emit 'end' | |
_getFile: (file) -> | |
path = @_fullPath file | |
@ftp.get path, (err, stream) => | |
return @emit error if err? | |
entryInfo = | |
name: @_getRelative path | |
size: parseInt file.size | |
entry = @tar.entry entryInfo, (err) => | |
console.log 'result', err | |
return @emit err if err? | |
@_getNext() | |
@tar.on 'end', -> console.log 'he' | |
stream.pipe entry | |
_getDir: (item) -> | |
path = @_fullPath item | |
sender = new Transfer @root, @ftp, @tar, path | |
sender.on 'error', (err) => @emit err | |
sender.on 'end', => @_getNext() | |
sender.begin() | |
module.exports = Transfer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment