| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <iostream> |
| #include <streambuf> |
| |
| #include "garnet/bin/flog_viewer/accumulator.h" |
| #include "garnet/bin/flog_viewer/binding.h" |
| #include "garnet/bin/flog_viewer/channel_manager.h" |
| #include "lib/fidl/cpp/bindings/message.h" |
| #include "lib/fxl/logging.h" |
| #include "lib/media/fidl/flog/flog.fidl.h" |
| |
| namespace flog { |
| |
| class Channel; |
| |
| // Null ostream implementation. |
| template <class cT, class traits = std::char_traits<cT>> |
| class basic_nullbuf : public std::basic_streambuf<cT, traits> { |
| typename traits::int_type overflow(typename traits::int_type c) { |
| return traits::not_eof(c); // indicate success |
| } |
| }; |
| |
| template <class cT, class traits = std::char_traits<cT>> |
| class basic_onullstream : public std::basic_ostream<cT, traits> { |
| public: |
| basic_onullstream() |
| : std::basic_ios<cT, traits>(&sbuf_), |
| std::basic_ostream<cT, traits>(&sbuf_) { |
| std::basic_ostream<cT, traits>::init(&sbuf_); |
| } |
| |
| private: |
| basic_nullbuf<cT, traits> sbuf_; |
| }; |
| |
| typedef basic_onullstream<char> onullstream; |
| |
| // Handler for channel messages. |
| // |
| // A channel handler is created for each channel that appears in a viewed log. |
| // ChannelHandler::CreateHandler creates the right channel handler for a given |
| // type and format. If there's no specific handler for the type/format, the |
| // default handler is used. |
| // |
| // Some channel handlers (particularly the ones for the 'digest' format) will |
| // produce an 'accumulator', which reflects the handler's understanding of the |
| // messages that have been handled. The GetAccumulator method can be overridden |
| // to provide callers access to the accumulator. |
| class ChannelHandler { |
| public: |
| static const std::string kFormatTerse; |
| static const std::string kFormatFull; |
| static const std::string kFormatDigest; |
| |
| static std::unique_ptr<ChannelHandler> Create(const std::string& type_name, |
| const std::string& format, |
| ChannelManager* manager); |
| |
| virtual ~ChannelHandler(); |
| |
| // Handles a channel message. |
| void HandleMessage(std::shared_ptr<Channel> channel, |
| uint32_t entry_index, |
| const FlogEntryPtr& entry, |
| fidl::Message* message); |
| |
| // Gets the accumulator from the handler, if there is one. The default |
| // implementation returns a null pointer. |
| virtual std::shared_ptr<Accumulator> GetAccumulator(); |
| |
| protected: |
| ChannelHandler(const std::string& format); |
| |
| virtual void HandleMessage(fidl::Message* message) = 0; |
| |
| std::ostream& ReportProblem() { |
| FXL_DCHECK(entry_) << "ReportProblem called outside of HandleMessage"; |
| return GetAccumulator()->ReportProblem(entry_index(), entry()); |
| } |
| |
| uint32_t entry_index() const { |
| FXL_DCHECK(entry_) << "entry_index called outside of HandleMessage"; |
| return entry_index_; |
| } |
| |
| const FlogEntryPtr& entry() const { |
| FXL_DCHECK(entry_) << "entry called outside of HandleMessage"; |
| return *entry_; |
| } |
| |
| std::shared_ptr<Channel> AsChannel(uint64_t subject_address); |
| |
| void BindAs(uint64_t koid); |
| |
| void SetBindingKoid(Binding* binding, uint64_t koid); |
| |
| const std::string& format() const { return format_; } |
| |
| std::ostream& full_out() { |
| return format_ == kFormatFull ? std::cout : onull; |
| } |
| |
| std::ostream& terse_out() { |
| return format_ != kFormatDigest ? std::cout : onull; |
| } |
| |
| private: |
| ChannelManager* manager_; |
| std::string format_; |
| |
| // These fields are only used during calls to HandleMessage(). |
| std::shared_ptr<Channel> channel_ = nullptr; |
| uint32_t entry_index_ = 0; |
| const FlogEntryPtr* entry_ = nullptr; |
| onullstream onull; |
| }; |
| |
| } // namespace flog |