blob: 296abde86a2b6b965d971765376c1a61b5db1687 [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#pragma once
#include "pw_assert/assert.h"
#include "pw_containers/intrusive_list.h"
#include "pw_result/result.h"
#include "pw_rpc/raw/server_reader_writer.h"
#include "pw_transfer/handler.h"
#include "pw_transfer/internal/client_connection.h"
#include "pw_transfer/internal/context.h"
namespace pw::transfer::internal {
// Transfer context for use within the transfer service (server-side). Stores a
// pointer to a transfer handler when active to stream the transfer data.
class ServerContext : public Context {
public:
ServerContext() : Context(OnCompletion), type_(kRead), handler_(nullptr) {}
// Begins a new transfer with the specified type and handler. Calls into the
// handler's Prepare method.
//
// Precondition: Context is not already active.
Status Start(TransferType type,
Handler& handler,
work_queue::WorkQueue& work_queue,
rpc::RawServerReaderWriter& stream,
chrono::SystemClock::duration timeout,
uint8_t max_retries);
// Ends the transfer with the given status, calling the handler's Finalize
// method. No chunks are sent.
//
// Returns DATA_LOSS if the finalize call fails.
//
// Precondition: Transfer context is active.
Status Finish(Status status);
private:
static Status OnCompletion(Context& ctx, Status status) {
return static_cast<ServerContext&>(ctx).Finish(status);
}
TransferType type_;
Handler* handler_;
};
// A fixed-size pool of allocatable transfer contexts.
class ServerContextPool {
public:
ServerContextPool(TransferType type,
IntrusiveList<internal::Handler>& handlers)
: type_(type), handlers_(handlers) {}
// Looks up an active context by ID. If none exists, tries to allocate and
// start a new context.
//
// Errors:
//
// NOT_FOUND - No handler exists for the specified transfer ID.
// RESOURCE_EXHAUSTED - Out of transfer context slots.
//
Result<ServerContext*> StartTransfer(uint32_t transfer_id,
work_queue::WorkQueue& work_queue,
rpc::RawServerReaderWriter& stream,
chrono::SystemClock::duration timeout,
uint8_t max_retries);
Result<ServerContext*> GetPendingTransfer(uint32_t transfer_id);
private:
// TODO(frolv): Initially, only one transfer at a time is supported. Once that
// is updated, this should be made configurable.
static constexpr int kMaxConcurrentTransfers = 1;
TransferType type_;
std::array<ServerContext, kMaxConcurrentTransfers> transfers_;
IntrusiveList<internal::Handler>& handlers_;
};
} // namespace pw::transfer::internal