Ctrl K
ComunidadGuías…

src/zm_monitorlink_token.h

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot


//
// ZoneMinder Monitor Class Interfaces
// Copyright (C) 2022 ZoneMinder Inc
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

#ifndef ZM_MONITORLINK_TOKEN_H
#define ZM_MONITORLINK_TOKEN_H

#include "zm_monitor.h"

#include <limits>
#include <stdexcept>

class Token {
 public:
  /**
    * enum class token_type
    *
    * Represents a token type. Supported types are logical operators, relational operators, parentheses and monitorlink
    */
  enum class [[ nodiscard ]] TokenType : std::uint8_t {
    unknown,
    monitorlink,
    logical_and,
    logical_or,
    logical_comma,
    lp,
    rp
  };

  /**
   * @class token
   *
   * Represents all tokens ('and', 'or', 'eq', ...).
   */
 private:
  using token_type_pair = std::pair<std::string_view, TokenType>;
  constexpr static std::array symbols {
    token_type_pair{ "&", TokenType::logical_and },
    token_type_pair{ "|", TokenType::logical_or  },
    token_type_pair{ ",", TokenType::logical_comma  }, // or
    token_type_pair{ "(", TokenType::lp          },
    token_type_pair{ ")", TokenType::rp          }
  };

  //constexpr TokenType to_token_type( std::string_view const value ) noexcept;
  constexpr TokenType to_token_type( std::string_view const value ) noexcept {
    auto find_matching {
      [ value ]( auto const & collection ) noexcept {
        return utils::find_if
        (
          std::cbegin( collection ),
          std::cend  ( collection ),
        [ value ]( auto && item ) {
          return item.first == value;
        }
        );
      }
    };

    auto const symbol{ find_matching(symbols) };
    if (symbol != std::cend(symbols)) {
      return symbol->second;
    }

    return TokenType::monitorlink;
  } // end constexpr TokenType to_token_type( std::string_view const value )

  // A monitorlink token is "<monitor id>" or "<monitor id>:<zone id>". The
  // value comes from the LinkedMonitors column as typed, so one that isn't a
  // number is logged and leaves the token without a link (it scores 0).
  // std::stoul throws on it, and the constructor parse() uses is noexcept, so
  // letting the exception out ended zmc in std::terminate.
  void load_monitor_link() noexcept {
    unsigned int monitor_id = 0;
    unsigned int zone_id = 0;
    if (!parse_monitor_link(value_, monitor_id, zone_id)) {
      Warning("Ignoring linked monitor '%s': not a monitor id or monitor id:zone id",
              std::string(value_).c_str());
      return;
    }
    Debug(1, "Have linked monitor %d zone %d", monitor_id, zone_id);

    std::shared_ptr<Monitor> monitor = Monitor::Load(monitor_id, false, Monitor::QUERY);
    if (!monitor) {
      // No such row (a removed monitor, or a typo); MonitorLink dereferences it.
      Warning("Ignoring linked monitor %u: unable to load it", monitor_id);
      return;
    }
    monitor_link_ = std::make_shared<Monitor::MonitorLink>(monitor, zone_id);
  }

 public:

  // Splits "<monitor id>" or "<monitor id>:<zone id>" (zone id 0 when absent).
  // False when either isn't a number or doesn't fit an unsigned int: stoul
  // returns an unsigned long, so 99999999999 would otherwise be truncated to
  // some other monitor's id.
  static bool parse_monitor_link(std::string_view value, unsigned int &monitor_id, unsigned int &zone_id) noexcept {
    auto to_id = [](std::string_view digits) {
      unsigned long id = std::stoul(std::string(digits));
      if (id > std::numeric_limits<unsigned int>::max()) throw std::out_of_range("id");
      return static_cast<unsigned int>(id);
    };
    try {
      auto colon_position = value.find(':');
      if (colon_position != std::string::npos) {
        monitor_id = to_id(value.substr(0, colon_position));
        zone_id = to_id(value.substr(colon_position + 1));
      } else {
        monitor_id = to_id(value);
        zone_id = 0;
      }
    } catch (const std::exception &) {
      return false;
    }
    return true;
  }

  Token(TokenType const type, std::string_view const value)
    : type_(type)
    , value_(value)
    , monitor_link_(nullptr) {
    if (type_ == TokenType::monitorlink) {
      load_monitor_link();
    } else {
      Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
    }
  }

  constexpr Token() noexcept :
    type_(TokenType::unknown),
    value_(""),
    monitor_link_(nullptr)
  { }
  //Token( TokenType const type, std::string_view const value );

  // Copies share the MonitorLink: parse() copies tokens into the tree.
  Token( Token       && rhs ) noexcept = default;
  Token( Token const  & rhs ) noexcept = default;

  constexpr Token( TokenType const type ) noexcept
    : type_ ( type )
    , value_("")
    , monitor_link_(nullptr)
  {}

  Token( std::string_view const value ) noexcept
    : type_ (to_token_type(value))
    , value_(value)
    , monitor_link_(nullptr) {
    if (type_ == TokenType::monitorlink) {
      load_monitor_link();
    } else {
      Debug( 1, "Not a monitor link value is %s", std::string(value_).c_str());
    }
  }

  Token & operator=( Token       && rhs ) noexcept = default;
  Token & operator=( Token const  & rhs ) noexcept = default;

  [[ nodiscard ]] constexpr bool operator==( Token const & rhs ) const noexcept {
    return type_  == rhs.type_ && value_ == rhs.value_;
  }

  ~Token() noexcept = default;
  constexpr void type( TokenType const type ) noexcept {
    if ( type != type_ ) {
      type_  = type;
      value_ = "";//to_token_keyword( type );
    }

  }

  constexpr TokenType type() const noexcept { return type_; }

  constexpr void value( std::string_view const value ) noexcept {
    type_  = to_token_type( value );
    value_ = value;

  }

  [[ nodiscard ]] constexpr std::string_view value() const noexcept {
    return value_;
  }

  [[ nodiscard ]] constexpr bool is( TokenType const type ) const noexcept {
    return type_ == type;
  }

  [[ nodiscard ]] constexpr bool is_not( TokenType const type ) const noexcept {
    return type_ != type;
  }

  [[ nodiscard ]] constexpr bool is_one_of(
    TokenType const first,
    TokenType const second
  ) const noexcept {
    return is(first) || is(second);
  }

  [[ nodiscard ]] bool hasAlarmed() const {
    return (monitor_link_ && monitor_link_->connect() && monitor_link_->hasAlarmed());
  }

  [[ nodiscard ]] int score() const {
    if ( monitor_link_ ) {
      if (!monitor_link_->isConnected() ) {
        Debug(1, "connecting");
        if (!monitor_link_->connect()) {
          Debug(1, "failed");
          return 0;
        }
      }
      int s = monitor_link_->score();
      Debug(1, "Score from monitor %s is %d", monitor_link_->Name(), s);
      return s;
    }
    return 0;
  }

 private:
  TokenType         type_;
  std::string_view  value_;
  std::shared_ptr<Monitor::MonitorLink> monitor_link_;
};
#endif