# frozen_string_literal: true
module ESM
class Message
#
# Creates an instance of ESM::Message from JSON. See #to_h for the structure
# @see #to_h
#
# @param json [String] The JSON to parse
#
# @return [Self]
#
def self.from_string(json)
from_hash(json.to_deep_h)
end
#
# Creates a instance from a hash
#
# @param hash [Hash] The hash that contains the message contents
#
# @return [Self] The message
#
def self.from_hash(hash)
hash = hash.deep_symbolize_keys
message = new
message.set_id(hash[:id]) if hash[:id].present?
message.set_type(hash[:type]) if hash[:type].present?
if hash[:data].present?
message.set_data(**hash[:data])
end
if hash[:metadata].present?
message.set_metadata(
player: hash.dig(:metadata, :player),
target: hash.dig(:metadata, :target)
)
end
message.add_errors(hash[:errors]) if hash[:errors].present?
message
end
attr_reader :id, :type, :data, :metadata, :errors
attr_predicate :data
def initialize
@id = SecureRandom.uuid
@type = :call
@data = Data.new
@metadata = Metadata.new
@errors = []
end
def set_id(id)
@id = id
self
end
def set_type(type)
@type = type.to_sym
self
end
# The primary data for this message. It's the good stuff.
def set_data(**data_attributes)
@data = Data.new(**data_attributes)
self
end
#
# Sets various values used by the arma mod and internally by Message::Error
#
# @param player [ESM::User, nil] The user that executed the command
# @param target [ESM::User, ESM::User::Ephemeral, nil] The user who is the target of this command
# @param server_id [String, nil] The server the command is being executed on
# Used for error messages
#
# @return [Message] A referenced to the modified message
#
def set_metadata(player: nil, target: nil, server_id: nil)
@metadata.player = Player.from(player) if player
@metadata.target = Target.from(target) if target
@metadata.server_id = server_id if server_id
self
end
# Each hash has the following attributes:
# type [Symbol, String] The type of error. Valid options are:
# code # Uses the message to look up a predefined message in the locales
# message # Treats the message like a string and sends it as is
# content [String] The content of this error.
def add_errors(errors = [])
errors.each do |error|
error = error.symbolize_keys
add_error(error[:type].to_s, error[:content])
end
self
end
#
# Adds the provided error to this message
#
# @param type [String] The error type. Valid types are: "code" and "message"
# @param message [String] The message or code for this error
#
def add_error(type, content)
# Return nil on purpose
return if type.nil? || content.nil?
@errors << Error.new(self, type, content)
self
end
def data_attributes
@data.to_h
end
#
# Converts the message to JSON
#
# @return [String] The message as JSON
#
def to_s
to_h.to_json
end
#
# Converts the message to a Hash
#
# @param for_arma [Boolean] Is this hash arma bound?
#
# @return [Hash] The message as a Hash. It has the following keys
# {
# id: The ID of this message as a UUID
# type: The context of this message
# data: {
# type: Describes the structure of content
# content: The actual "data"
# },
# metadata: {
# type: Describes the structure of content
# content: The actual "metadata"
# },
# errors: Any errors associated to this message
# }
#
def to_h
{
id: id,
type: type,
data: data_attributes,
metadata: metadata.to_h,
errors: errors.map(&:to_h)
}
end
#
# Returns if there are any errors on this message
#
# @return [Boolean]
#
def errors?
errors.any?
end
def error_messages
errors.map(&:to_s)
end
def inspect
"#<ESM::Message #{JSON.pretty_generate(to_h)}>"
end
end
end