Exemplo n.º 1
0
 fs.readdir(path.join(test_root, test_path), function (err, files) {
   if (err) return cb(err);
   files.sort();
   if (! /\.gz$/.test(files[0])) {
     files.push(files.shift());
   }
   var pend = new Pend();
   var results;
   files.forEach(function(file) {
     pend.go(function(cb) {
       fs.readFile(path.join(test_root, test_path, file), function (err, data) {
         if (err) return cb(err);
         if (/\.gz$/.test(file)) {
           zlib.gunzip(data, function (err, data) {
             if (err) return cb(err);
             results = {file: file, data: data};
             cb();
           });
         } else {
           results = {file: file, data: data};
           cb();
         }
       });
     });
   });
   pend.wait(function(err) {
     if (err) return cb(err);
     var fullData = "";
     results.forEach(function(item) {
       fullData += item.data.toString();
     });
     cb(null, results, fullData);
   });
 });
Exemplo n.º 2
0
 form.on('close', function() {
   res.end('OK');
   pend.wait(function(err) {
     if (err) throw err;
     callback(null, parts);
   });
 });
Exemplo n.º 3
0
 fn: function (cb) {
   var pend = new Pend();
   files.forEach(function(file) {
     rimraf(path.join(test_root, file), pend.hold());
   });
   pend.wait(cb);
 },
Exemplo n.º 4
0
PlayerServer.prototype.init = function(cb) {
  var self = this;

  var pend = new Pend();
  pend.go(loadAllUsers);
  pend.go(loadAllEvents);
  pend.go(loadLastFmState);
  pend.wait(cb);

  function loadAllUsers(cb) {
    dbIterate(self.db, USERS_KEY_PREFIX, processOne, function(err) {
      if (err) return cb(err);
      self.ensureGuestUser();
      self.computeUsersIndex();
      self.emit('users');
      self.emit('haveAdminUser');
      cb();
    });
    function processOne(key, value) {
      var user = deserializeUser(value);
      self.users[user.id] = user;
    }
  }

  function loadAllEvents(cb) {
    dbIterate(self.db, EVENTS_KEY_PREFIX, processOne, function(err) {
      if (err) return cb(err);
      self.cacheEventsArray();
      self.emit('events');
      cb();
    });
    function processOne(key, value) {
      var ev = deserializeEvent(value);
      self.events[ev.id] = ev;
    }
  }

  function loadLastFmState(cb) {
    self.db.get(LASTFM_DB_KEY, function(err, value) {
      if (err) {
        var notFoundError = /^NotFound/.test(err.message);
        if (!notFoundError) return cb(err);
      } else {
        var state;
        try {
          state = JSON.parse(value);
        } catch (err) {
          cb(new Error("unable to parse lastfm state: " + err.message));
          return;
        }
        self.scrobblers = state.scrobblers;
        self.scrobbles = state.scrobbles;
      }
      // in case scrobbling fails and then the user presses stop, this will still
      // flush the queue.
      setInterval(self.flushScrobbleQueue.bind(self), 120000);
      cb();
    });
  }
};
Exemplo n.º 5
0
function deployStart(cb){
  if (waitingFor === 'shutdown') {
    return cb('ErrorShuttingDown');
  } else if (waitingFor != null) {
    return cb('ErrorDeployInProgress');
  }
  assert.strictEqual(workers.booting.count, 0);
  waitingFor = 'new';
  var pend = new Pend();
  var count = workerCount;
  for (var i = 0; i < count; i += 1) {
    spawnNew(i, pend.hold());
  }
  pend.wait(function() {
    if (workers.new_online.count !== workerCount) {
      deployAbort(function() {
        cb('DeployFailed');
      });
      return;
    }
    waitingFor = 'old';
    var onlineCount = workers.online.count;
    for (var i = 0; i < onlineCount; ++i) {
      pend.go(shutdownOneWorker('online'));
    }
    pend.wait(function() {
      assert.strictEqual(workers.online.count, 0);
      waitingFor = null;
      forEachWorker('new_online', function(pid, worker){
        setWorkerStatus(worker, 'online');
      });
      cb('Ready');
    });
  });
}
Exemplo n.º 6
0
 function readKeyAndCert(cb) {
   var pend = new Pend();
   var options =  {};
   pend.go(function(cb) {
     fs.readFile(self.config.sslKey, function(err, data) {
       if (err) {
         console.error("Unable to read SSL key file: " + err.message);
         process.exit(1);
         return;
       }
       options.key = data;
       cb();
     });
   });
   pend.go(function(cb) {
     fs.readFile(self.config.sslCert, function(err, data) {
       if (err) {
         console.error("Unable to read SSL cert file: " + err.message);
         process.exit(1);
         return;
       }
       options.cert = data;
       cb();
     });
   });
   pend.wait(function() {
     self.httpServer = https.createServer(options, self.app);
     cb();
   });
 }
Exemplo n.º 7
0
PlayerServer.deleteAllUsers = function(db) {
  var cmds = [];
  var usersDeleted = 0;
  var eventsDeleted = 0;

  var pend = new Pend();
  pend.go(function(cb) {
    dbIterate(db, USERS_KEY_PREFIX, processOne, cb);

    function processOne(key, value) {
      cmds.push({type: 'del', key: key});
      usersDeleted += 1;
    }
  });
  pend.go(function(cb) {
    dbIterate(db, EVENTS_KEY_PREFIX, processOne, cb);
    function processOne(key, value) {
      cmds.push({type: 'del', key: key});
      eventsDeleted += 1;
    }
  });
  pend.wait(function(err) {
    if (err) throw err;
    db.batch(cmds, function(err) {
      if (err) throw err;
      log.info("Users deleted: " + usersDeleted);
      log.info("Events deleted: " + eventsDeleted);
      process.exit(0);
    });
  });
};
Exemplo n.º 8
0
 function createLogsAndIpcServer(cb) {
   var pend = new Pend();
   createLogs(pend.hold());
   mkdirp(path.dirname(socketPath), pend.hold());
   pend.wait(function(err) {
     if (err) return cb(err);
     server = net.createServer(function(newSocket){
       if (socket != null) {
         log("Warning: Only one connection to daemon allowed. Terminating old connection.\n");
         socket.destroy();
       }
       socket = newSocket;
       socket.on('error', function(err){
         log("Error: ipc channel socket: " + err.stack + "\n");
       });
       socket.once('end', function(){
         socket = null;
       });
       jsonSocket.listen(socket, function(msg){
         var response = handleSocketMessage(msg);
         if (response) {
           jsonSocket.send(response);
         }
       });
     });
     server.listen(socketPath, cb);
   });
 }
Exemplo n.º 9
0
function deployAbort(cb){
  switch (waitingFor) {
  case 'new':
    var pend = new Pend();
    var i;
    var newOnlineCount = workers.new_online.count;
    var bootingCount = workers.booting.count;
    for (i = 0; i < newOnlineCount; i += 1) {
      pend.go(destroyWorkers('new_online'));
    }
    for (i = 0; i < bootingCount; i += 1) {
      pend.go(destroyWorkers('booting'));
    }
    pend.wait(function() {
      waitingFor = null;
      cb();
    });
    break;
  case 'old':
    destroyDying();
    cb();
    break;
  default:
    event('ErrorNoDeployInProgress');
  }
}
Exemplo n.º 10
0
    form.parse(request, function(err, fields, files) {
      if (err) return next(err);

      var keys = [];
      var pend = new Pend();
      for (var key in files) {
        var arr = files[key];
        for (var i = 0; i < arr.length; i += 1) {
          var file = arr[i];
          pend.go(makeImportFn(file));
        }
      }
      pend.wait(function() {
        response.json(keys);
      });

      function makeImportFn(file) {
        return function(cb) {
          self.player.importFile(file.path, file.originalFilename, function(err, dbFile) {
            if (err) {
              console.error("Unable to import file:", file.path, "error:", err.stack);
            } else if (!dbFile) {
              console.error("Unable to locate new file due to race condition");
            } else {
              keys.push(dbFile.key);
            }
            cb();
          });
        };
      }
    });
Exemplo n.º 11
0
JobQueue.prototype.shutdown = function(callback) {
  var self = this;

  self.shuttingDown = true;
  clearInterval(self.flushStaleInterval);

  var pend = new Pend();
  pend.go(function(cb) {
    self.redisClient.quit(function(err) {
        /* We want to kill this instance of the redis client, so at at this point we
         * are not interested in what connection errors Redis comes up with.
         */

        self.redisClient.end();
      cb();
    });
  });
  self.childProcesses.forEach(function(child) {
    pend.go(function(cb) {
      child.on('exit', cb);
      child.send('shutdown');
    });
  });
  if (self.childWorker) {
    pend.go(shutdownChildWorker);
  }
  pend.wait(function() {
    callback();
  });

  function shutdownChildWorker(cb) {
    self.childWorker.shutdown(cb);
  }
};
Exemplo n.º 12
0
 form.on('close', function() {
   pend.wait(function() {
     if (allDbFiles.length > 0) {
       playerServer.handleImportedTracks(request.client, allDbFiles, autoQueue);
     }
     response.json({});
   });
 });
Exemplo n.º 13
0
 walker.on('file', function(file, stat, linkPath) {
   var usePath = linkPath || file;
   if (ignoreFile(usePath)) return;
   var relName = '/' + path.relative(dir, usePath).replace('\\', '/');
   var compressedSink = new StreamSink();
   var uncompressedSink = new StreamSink();
   var hashSink = new StreamSink();
   var inStream = fs.createReadStream(file);
   var cacheObj;
   cache[relName] = cacheObj = {
     sink: null,
     mime: mime.lookup(relName),
     mtime: stat.mtime,
     hash: null,
     compressed: null,
   };
   var fileDone = pend.hold();
   var thisPend = new Pend();
   var gzipPendCb = thisPend.hold();
   var hashPendCb = thisPend.hold();
   var uncompressedPendCb = thisPend.hold();
   inStream.on('error', function(err) {
     if (err.code === 'EISDIR') {
       delete cache[relName];
       gzipPendCb();
       uncompressedPendCb();
       hashPendCb();
     } else {
       walker.stop();
       gzipPendCb(err);
       uncompressedPendCb(err);
       hashPendCb(err);
     }
   });
   inStream.pipe(zlib.createGzip()).pipe(compressedSink);
   compressedSink.on('finish', gzipPendCb);
   inStream.pipe(uncompressedSink);
   uncompressedSink.on('finish', uncompressedPendCb);
   inStream.pipe(crypto.createHash('sha1')).pipe(hashSink);
   hashSink.on('finish', function() {
     cacheObj.hash = hashSink.toString('base64');
     hashPendCb();
   });
   thisPend.wait(function(err) {
     if (err) return fileDone(err);
     var compressionRatio = compressedSink.length / uncompressedSink.length;
     if (compressionRatio >= 0.95) {
       // 95% of original size or worse. discard compressed sink
       cacheObj.sink = uncompressedSink;
       cacheObj.compressed = false;
     } else {
       // better than 95% of original size. discard uncompressed sink
       cacheObj.sink = compressedSink;
       cacheObj.compressed = true;
     }
     fileDone();
   });
 });
Exemplo n.º 14
0
 zipfile.on("end", function() {
   entryProcessing.wait(function() {
     for (var fileName in expectedArchiveContents) {
       throw new Error(testId + fileName + ": missing file");
     }
     console.log(testId + "pass");
     zipfileCallback();
   });
 });
Exemplo n.º 15
0
 function readKeyAndCert(cb) {
   var pend = new Pend();
   var options =  {};
   pend.go(function(cb) {
     fs.readFile(config.sslKey, function(err, data) {
       if (err) {
         log.fatal("Unable to read SSL key file: " + err.message);
         process.exit(1);
         return;
       }
       options.key = data;
       cb();
     });
   });
   pend.go(function(cb) {
     fs.readFile(config.sslCert, function(err, data) {
       if (err) {
         log.fatal("Unable to read SSL cert file: " + err.message);
         process.exit(1);
         return;
       }
       options.cert = data;
       cb();
     });
   });
   pend.go(function(cb) {
     if (!config.sslCaDir) return cb();
     options.ca = [];
     fs.readdir(config.sslCaDir, function(err, fileList) {
       if (err) {
         log.fatal("Unable to read SSL CA dir: " + err.message);
         process.exit(1);
         return;
       }
       fileList.forEach(function(file) {
         pend.go(function(cb) {
           var caPath = path.join(config.sslCaDir, file);
           fs.readFile(caPath, function(err, data) {
             if (err) {
               log.fatal("Unable to read SSL CA file: " + err.message);
               process.exit(1);
               return;
             }
             options.ca.push(data);
             cb();
           });
         });
       });
       cb();
     });
   });
   pend.wait(function() {
     httpServer = httpolyglot.createServer(options, app);
     cb();
   });
 }
Exemplo n.º 16
0
      db.open(function(err) {
        if (err) {
          if (exitGracefullyIfRunning &&
            /^IO error: lock.*: Resource temporarily unavailable$/.test(err.message))
          {
            return;
          } else {
            throw err;
          }
        }

        if (deleteAllUsers || deleteAllEvents) {
          // this will call process.exit when done
          PlayerServer.deleteUsersAndEvents(db, deleteAllUsers);
          return;
        }

        var app = express();
        var sslEnabled = !!(config.sslKey && config.sslCert);
        if (sslEnabled) {
          app.use(redirectHttpToHttps);
        }

        var pend = new Pend();
        pend.go(function(cb) {
          var options = {
            dir: path.join(__dirname, "../public"),
            aliases: [],
          };
          createGzipStatic(options, function(err, middleware) {
            if (err) return cb(err);
            app.use(middleware);
            cb();
          });
        });
        pend.go(function(cb) {
          createGzipStatic({dir: path.join(__dirname, "../src/public")}, function(err, middleware) {
            if (err) return cb(err);
            app.use(middleware);
            cb();
          });
        });
        pend.wait(function(err) {
          if (err) throw err;

          var player = new Player(db, config.musicDirectory,
            config.encodeQueueDuration, config.googleApiKey);
          player.initialize(function(err) {
            if (err) throw err;
            log.debug("Player initialization complete.");

            startServer(app, db, player, config, sslEnabled);
          });
        });
      });
Exemplo n.º 17
0
    return function(done) {
      this.timeout(4000);

      var testPath = path.join(templatePath, testName);

      var expectedHtml, actualHtml;
      var expectedText, actualText;

      var pend = new Pend();

      // Read the JSON file & render the HTML
      pend.go(function(cb) {
        attemptReadFile(testPath + '.json', 'utf8', function(err, data) {
          var context = {};

          if (err) return cb(err);
          if (data) context = JSON.parse(data);

          templates.render(testName + '.html', context, function(err, html, text) {
            actualHtml = html;
            actualText = text;
            cb(err);
          });
        });
      });

      // Load the expected HTML
      pend.go(function(cb) {
        attemptReadFile(testPath + '.out.html', 'utf8', function(err, html) {
          expectedHtml = html;
          cb(err);
        });
      });

      // Try loading the expected text (may not exist)
      pend.go(function(cb) {
        attemptReadFile(testPath + '.out.txt', 'utf8', function(err, text) {
          expectedText = text;
          cb(err);
        });
      });

      // And when they're all done...
      pend.wait(function(err) {
        if (err) return done(err);

        if (expectedHtml)
          assert.strictEqual(actualHtml.trim(), expectedHtml.trim());
        if (expectedText)
          assert.strictEqual(actualText.trim(), expectedText.trim());

        done();
      });
    };
Exemplo n.º 18
0
function getDeployDiff(packageJson, targetName, branch, format, cb) {
  var exec = require('child_process').exec;
  var pend = new Pend();
  var revision;
  pend.go(function(cb) {
    var sshConf = packageJson.rodent.targets[targetName].ssh;
    var firstHost = sshConf.hosts[0];
    var destAppPath = appPath(packageJson, targetName);
    var cmd = "ssh " +
      "-o ForwardAgent=yes " +
      "-p " + sshConf.port + " " +
      sshConf.user + "@" + firstHost + " " +
      "'cd " + destAppPath + " && git rev-parse HEAD'";
    exec(cmd, function(err, stdout, stderr) {
      if (err) {
        err.stderr = stderr;
        err.stdout = stdout;
        err.cmd = cmd;
        cb(err);
      } else {
        revision = stdout.trim();
        cb();
      }
    });
  });
  pend.go(function(cb) {
    var cmd = "git fetch origin";
    exec(cmd, function(err, stdout, stderr) {
      if (err) {
        err.stderr = stderr;
        err.stdout = stdout;
        err.cmd = cmd;
        cb(err);
      } else {
        cb();
      }
    });
  });
  pend.wait(function(err) {
    if (err) return cb(err);
    var cmd = "git log --pretty=format:\"" + format + "\" " + revision + "..origin/" + branch;
    exec(cmd, function(err, stdout, stderr) {
      if (err) {
        err.stderr = stderr;
        err.stdout = stdout;
        err.cmd = cmd;
        cb(err);
      } else {
        cb(null, stdout.trim());
      }
    });
  });
}
Exemplo n.º 19
0
 form.on('close', function() {
   pend.wait(function() {
     if (allDbFiles.length >= 1) {
       var user = request.client && request.client.user;
       playerServer.addEvent(user, 'import', null, allDbFiles[0].key, allDbFiles.length);
       if (autoQueue) {
         player.sortAndQueueTracks(allDbFiles);
         playerServer.addEvent(user, 'queue', null, allDbFiles[0].key, allDbFiles.length);
       }
     }
     response.json({});
   });
 });
Exemplo n.º 20
0
Client.prototype.deleteObjects = function(s3Params) {
  var self = this;
  var ee = new EventEmitter();

  var params = {
    Bucket: s3Params.Bucket,
    Delete: extend({}, s3Params.Delete),
    MFA: s3Params.MFA,
  };
  var slices = chunkArray(params.Delete.Objects, MAX_DELETE_COUNT);
  var errorOccurred = false;
  var pend = new Pend();

  ee.progressAmount = 0;
  ee.progressTotal = params.Delete.Objects.length;

  slices.forEach(uploadSlice);
  pend.wait(function(err) {
    if (err) {
      ee.emit('error', err);
      return;
    }
    ee.emit('end');
  });
  return ee;

  function uploadSlice(slice) {
    pend.go(function(cb) {
      doWithRetry(tryDeletingObjects, self.s3RetryCount, self.s3RetryDelay, function(err, data) {
        if (err) {
          cb(err);
        } else {
          ee.progressAmount += slice.length;
          ee.emit('progress');
          ee.emit('data', data);
          cb();
        }
      });
    });

    function tryDeletingObjects(cb) {
      self.s3Pend.go(function(pendCb) {
        params.Delete.Objects = slice;
        self.s3.deleteObjects(params, function(err, data) {
          pendCb();
          cb(err, data);
        });
      });
    }
  }
};
Exemplo n.º 21
0
function boot() {
  var pend = new Pend();
  db.open(pend.hold());
  pend.go(createHttpServer);
  pend.wait(function(err) {
    if (err) throw err;
    cacheAllDb(function(err) {
      if (err) throw err;
      httpServer.listen(httpPort, httpHost, function() {
        console.info("HTTP server listening at http://" + httpHost + ":" + httpPort + "/");
      });
    });
  });
}
Exemplo n.º 22
0
        return function(cb) {
            var pend = new Pend();
            var expectedHtml, actualHtml;
            var expectedText, actualText;
            pend.go(function(cb) {
                swigEmails.render(templateName + '.html', {
                    context: context,
                    urlRewrite: rewrite
                }, function(err, html, text) {
                    actualHtml = html;
                    actualText = text;
                    cb(err);
                });
            });
            pend.go(function(cb) {
                var filename = path.join(__dirname, "templates", templateName + ".out.html");
                fs.readFile(filename, 'utf8', function(err, val) {
                    expectedHtml = val;
                    cb(err);
                });
            });
            pend.go(function(cb) {
                var filename = path.join(__dirname, "templates", templateName + ".out.txt");
                fs.readFile(filename, 'utf8', function(err, val) {
                    if (err) {
                        if (err.code === 'ENOENT') {
                            expectedText = null;
                            cb();
                        } else {
                            cb(err);
                        }
                    } else {
                        expectedText = val;
                        cb();
                    }
                });
            });
            pend.wait(function(err) {
                if (err) return cb(err);

                if (actualHtml.trim() !== expectedHtml.trim()) {
                    return cb(new Error("Invalid html"));
                }

                if (expectedText) {
                    if (actualText.trim() !== expectedText.trim()) return cb(new Error("Invalid text"));
                }
                cb();
            });
        };
Exemplo n.º 23
0
function cleanup() {
  playlist.clear();
  files.forEach(function(o) {
    pend.go(function(cb) {
      o.file.close(cb);
    });
  });
  pend.wait(function(err) {
    if (err) throw err;
    player.detach(function(err) {
      if (err) throw err;
      playlist.destroy();
    });
  });
}
Exemplo n.º 24
0
function shutdownAll(cb){
  if (waitingFor === 'shutdown') {
    event('AlreadyShuttingDown');
    return;
  }
  waitingFor = 'shutdown';
  var pend = new Pend();
  statusesToShutdown.forEach(function(status) {
    var count = workers[status].count;
    for (var i = 0; i < count; ++i) {
      pend.go(shutdownOneWorker(status));
    }
  });
  pend.wait(cb);
}
Exemplo n.º 25
0
  function createLogs(cb) {
    var pend = new Pend();
    pend.go(function(cb) {
      maybeCreateLog(logNaughtPath, function(err, results) {
        naughtLog = results.log;
        naughtLogBehavior = results.behavior;
        cb(err);
      });
    });
    pend.go(function(cb) {
      maybeCreateLog(logStderrPath, function(err, results) {
        stderrLog = results.log;
        stderrBehavior = results.behavior;
        cb(err);
      });
    });
    pend.go(function(cb) {
      maybeCreateLog(logStdoutPath, function(err, results) {
        stdoutLog = results.log;
        stdoutBehavior = results.behavior;
        cb(err);
      });
    });
    pend.wait(function(err) {
      if (err) return cb(err);

      if (naughtLogBehavior === 'inherit') {
        naughtLog = process.stderr;
      }

      if (stderrBehavior === 'pipe') {
        stderrLog.on('error', function(err) {
          log("Error writing to " + logStderrPath + ": " + err.stack + "\n");
        });
      }
      if (stdoutBehavior === 'pipe') {
        stdoutLog.on('error', function(err) {
          log("Error writing to " + logStdoutPath + ": " + err.stack + "\n");
        });
      }
      if (naughtLogBehavior === 'pipe') {
        naughtLog.on('error', function(err){
          process.stderr.write("Error writing to " + logNaughtPath + ": " + err.stack + "\n");
        });
      }
      cb();
    });
  }
Exemplo n.º 26
0
 self.s3.putObject(s3Params, function(err, data) {
   pendCb();
   if (fatalError) return;
   if (err) {
     cb(err);
     return;
   }
   pend.wait(function() {
     if (fatalError) return;
     if (!compareMultipartETag(data.ETag, localFileStat.multipartETag)) {
       cb(new Error("ETag does not match MD5 checksum"));
       return;
     }
     cb(null, data);
   });
 });
Exemplo n.º 27
0
function assertFilesMd5(list, cb) {
  var pend = new Pend();
  list.forEach(function(o) {
    pend.go(function(cb) {
      var inStream = fs.createReadStream(o.path);
      var hash = crypto.createHash('md5');
      inStream.pipe(hash);
      hash.on('data', function(digest) {
        var hexDigest = digest.toString('hex');
        assert.strictEqual(hexDigest, o.md5, o.path + " md5 mismatch");
        cb();
      });
    });
  });
  pend.wait(cb);
}
Exemplo n.º 28
0
 self.s3.putObject(s3Params, function(err, data) {
   pendCb();
   if (errorOccurred) return;
   if (err) {
     errorOccurred = true;
     cb(err);
     return;
   }
   pend.wait(function() {
     if (!compareETag(data.ETag, localFileStat.md5sum)) {
       errorOccurred = true;
       cb(new Error("ETag does not match MD5 checksum"));
       return;
     }
     cb(null, data);
   });
 });
Exemplo n.º 29
0
 extractRequires(source, function(err, requireList) {
   if (err) return cb(err);
   requireList.forEach(function(requireItem) {
     pend.go(function(cb) {
       requireResolve(requireItem, path.dirname(canonicalSourcePath), function(err, canonicalDepPath) {
         if (err) return cb(err);
         deps[canonicalSourcePath][canonicalDepPath] = true;
         depMap[canonicalSourcePath][requireItem] = canonicalDepPath;
         sourceQueue.push(canonicalDepPath);
         cb();
       });
     });
   });
   pend.wait(function(err) {
     if (err) return cb(err);
     collectDependencies(cb);
   });
 });
Exemplo n.º 30
0
  function doStatAndMd5Sum() {
    var md5sum;
    var pend = new Pend();
    pend.go(doStat);
    pend.go(doMd5Sum);
    pend.wait(function(err) {
      if (err) {
        uploader.emit('error', err);
        return;
      }
      localFileStat.md5sum = md5sum;
      startPuttingObject();
    });

    function doStat(cb) {
      fs.stat(localFile, function(err, stat) {
        if (!err) {
          localFileStat = stat;
          uploader.progressTotal = stat.size;
        }
        cb(err);
      });
    }

    function doMd5Sum(cb) {
      var inStream = fs.createReadStream(localFile);
      var counter = new StreamCounter();
      inStream.on('error', function(err) {
        cb(err);
      });
      uploader.emit('stream', inStream);
      var hash = crypto.createHash('md5');
      hash.on('data', function(digest) {
        md5sum = digest;
        cb();
      });
      counter.on('progress', function() {
        uploader.progressMd5Amount = counter.bytes;
        uploader.emit('progress');
      });
      inStream.pipe(hash);
      inStream.pipe(counter);
    }
  }