void TransferSender::writeItemData()
{
    // Read the next chunk of data from the file - no more than either the size
    // of the buffer or the amount of data remaining in the file
    QByteArray buffer;
    buffer.resize(mBufferSize);

    qint64 bytesRead = mFile.read(buffer.data(), qMin(mFileBytesRemaining, static_cast<qint64>(mBufferSize)));

    // Ensure that a valid number of bytes were read
    if(bytesRead < 0 && mFileBytesRemaining) {
         writeErrorPacket(tr("Unable to read from %1").arg(mFile.fileName()));
         return;
    }

    // Write a packet containing the data that was just read
    writeBinaryPacket(buffer.left(bytesRead));

    // Update the number of bytes remaining in the file and the total transferred
    mFileBytesRemaining -= bytesRead;
    mTransferBytes += bytesRead;

    // Provide a progress update
    updateProgress();

    // If there are no bytes remaining in the file close it and move on
    if(!mFileBytesRemaining) {
        mFile.close();
        nextItem();
    }
}
Пример #2
0
void Transfer::processPacket()
{
    // Grab the data from the front of the buffer
    const char type = mBuffer.at(0);
    QByteArray data = mBuffer.mid(1, mBufferSize - 1);
    mBuffer.remove(0, mBufferSize);
    mBufferSize = 0;

    // Process the data based on the type
    switch (static_cast<PacketType>(type)) {
    case PacketType::Success:
    {
        finish(TransferModel::Succeeded);
        break;
    }
    case PacketType::Error:
    {
        // An error occurred - grab the error message
        mError = QString::fromUtf8(data);
        emit dataChanged({TransferModel::ErrorRole});

        finish(TransferModel::Failed);
        break;
    }
    case PacketType::Json:
    {
        // Verify the JSON is valid and pass it along
        QJsonDocument document = QJsonDocument::fromJson(data);
        if (document.isObject()) {
            processJsonPacket(document.object());
        } else {
            writeErrorPacket(tr("Unable to read JSON packet"));
        }
        break;
    }
    case PacketType::Binary:
    {
        // Pass the packet along unmodified
        processBinaryPacket(data);
        break;
    }
    default:
        // Any other type of packet is an error
        writeErrorPacket(tr("Unrecognized packet received"));
    }
}
Пример #3
0
void Transfer::cancel()
{
    // Ensure that the transfer is actually in progress before trying to cancel it
    if (mState == TransferModel::Failed || mState == TransferModel::Succeeded) {
        qWarning("Cannot cancel a transfer that has completed");
        return;
    }

    // Canceling a request is considered an "error" and is treated the same way
    // Only attempt to report the error if the transfer isn't already finished
    if (mProtocolState != ProtocolState::Finished) {
        writeErrorPacket(tr("Transfer was canceled"));
    }
}
Пример #4
0
void Transfer::onReadyRead()
{
    // Add all of the new data to the buffer
    mBuffer.append(mSocket->readAll());

    // Process as many packets as can be read from the buffer
    forever {

        // If the transfer is finished, ignore any packets being received
        if (mProtocolState == ProtocolState::Finished) {
            break;
        }

        // If the size of the packet is not yet known attempt to read it
        if (!mBufferSize) {

            // See if there is enough data in the buffer to read the size
            if (static_cast<size_t>(mBuffer.size()) >= sizeof(mBufferSize)) {

                // memcpy must be used in order to avoid alignment issues
                // Also, the integer uses little endian byte order
                // so convert it to the host format if necessary
                memcpy(&mBufferSize, mBuffer.constData(), sizeof(mBufferSize));
                mBufferSize = qFromLittleEndian(mBufferSize);
                mBuffer.remove(0, sizeof(mBufferSize));

                // A packet size of zero is an error
                if (!mBufferSize) {
                    writeErrorPacket(tr("Empty packet received"));
                    break;
                }

            } else {
                break;
            }
        }

        // If the buffer contains enough data to read the packet, then do so
        if (mBuffer.size() >= mBufferSize) {
            processPacket();
        } else {
            break;
        }
    }
}
void TransferSender::writeItemHeader()
{
    // Build the header describing the item
    QJsonObject header = QJsonObject::fromVariantMap({
        { "name", mCurrentItem->relativeFilename() },
        { "directory", mCurrentItem->isDir() },
        { "created", QString::number(mCurrentItem->created()) },
        { "last_modified", QString::number(mCurrentItem->lastModified()) },
        { "last_read", QString::number(mCurrentItem->lastRead()) }
    });

    if(mCurrentItem->isDir()) {

        // If the item is a directory, write the
        // header and move to the next item
        writeJsonPacket(header);
        nextItem();

    } else {

        // Set the filename and attempt to open the file
        mFile.setFileName(mCurrentItem->absoluteFilename());
        if(!mFile.open(QIODevice::ReadOnly)) {
            writeErrorPacket(tr("Unable to open %1").arg(mCurrentItem->absoluteFilename()));
            return;
        }

        // Obtain the file size, add it to the header, and send it
        mFileBytesRemaining = mFile.size();
        header.insert("size", QString::number(mFileBytesRemaining));
        writeJsonPacket(header);

        // If the file is empty, there's no need to send its contents
        if(!mFileBytesRemaining) {
            mFile.close();
            nextItem();
        }
    }
}
void TransferSender::processBinaryPacket(const QByteArray &)
{
    // Binary packets should never be received by the sender
    writeErrorPacket(tr("Unexpected binary packet received"));
}
void TransferSender::processJsonPacket(const QJsonObject &)
{
    // JSON packets should never be received by the sender
    writeErrorPacket(tr("Unexpected JSON packet received"));
}