a2800276 / 8583

ruby implementation of iso 8583 financial messages
http://www.kuriositaet.de
MIT License
41 stars 44 forks source link

Using this gem with the TCP/IP Sockets network protocol #3

Closed dlbirch closed 9 years ago

dlbirch commented 11 years ago

Thank you for providing the iso8583 Ruby Gem. I've begun to explore its usage ... and in my scenario, I need to send a 'message header' to the service I'm consuming (using a TCP/IP Socket). The first field in the header is the message length.

My questions:

1) How can I get a message length for a message?

2) How can I use the iso8583 code to create the header?

Sincerely,

Douglas Birch

dlbirch commented 11 years ago

Hi Tim,

Here is what I ended up with for the 'header' portion ... I'm still working through how to get the message length.

require 'iso8583'

module ISO8583

  class UmsHeader

    attr_accessor :total_message_length, :bhn_signature, :product_category_code, :msg_status_code, :msg_spec_id

    def initialize(msg_length)

      # 2 byte message length in network byte order, exclusive of itself.
      @total_message_length = [ msg_length ].pack "n"

      # Fixed length alphanumeric field with ‘X’ characters.
      # Left justified with trailing spaces.
      # Padding should be done to ensure that field is exactly ‘X’ characters.  ASCII encoded.
      # Each byte on the wire will represent one character
      # an6
      bhnums = Array.[]( 'B', 'H', 'N', 'U', 'M', 'S' )
      @bhn_signature = bhnums.pack "AAAAAA"

      # Numeric data where ‘X’ represents the number of digits. Right justified with leading zeroes.
      # Padding should be done to ensure that there is an even number of digits. E.g. if value is ‘009’ then
      # this field should be padded to with a 0 to make it ‘0009’.
      # If ‘X’ is defined as a odd number the field should still be padded with 0 to make it
      # an even number  Packed unsigned Binary Coded Decimal (BCD).
      # Each byte on the wire will represent 2 digits.

      # Product Category Code.
      # 01 – Gift Card
      @product_category_code = [01.to_s].pack("H*")

      # Message Status Code
      # Status of message parsing.
      # 00 – Success
      # 01 – Message parsing failed.
      @msg_status_code = [00.to_s].pack("H*")

      # Identifies the version of the spec in use.
      # This spec has a version of ‘02’.
      @msg_spec_id     = [02.to_s].pack("H*")

    end

    def to_b
      byte_array = Array.[]
      byte_array << @total_message_length
      byte_array << @bhn_signature
      byte_array << @product_category_code
      byte_array << @msg_status_code
      byte_array << @msg_spec_id
    end

  end

end

# my_hdr = ISO8583::UmsHeader.new(1024)
# puts my_hdr.to_b.to_s
# puts my_hdr.to_s
a2800276 commented 11 years ago

1) How can I get a message length for a message?

Call to_b on the instance of the subclass of Message you created, that will be a byte array containing the message, from there it's straightfoward ruby to get the length of the array. (I'm not sure how this will behave in ruby 1.9, be sure that the string handling introduced in 1.9 doesn't interfere with the byte array handling, or if in doubt use 1.8.

It would probably be easiest to override the to_b message to do this automatically. I'm on the road right now, so no-tested pseudo-code:

class MyMessage < Message
    ... bla bla all the `bmp` definitions ...
    def to_b
        bytes = super
        length = bytes.length
        length_header = encode_length_header_according_to_your_protocol(length)
        return length_header + bytes
    end
end
a2800276 commented 11 years ago

2) How can I use the iso8583 code to create the header?

Can't say for sure about the header you're describing without knowing what protocal this is, but it looks as if it's another 8583 message tacked in front of the actual message, in that case I would make it a field in your message.

Again Pseudocode:

class MyHeader < Message
  (...)
  bmp 1, "Product Category Code", N, length => 2
  bmp_alias 1, :product_category_code
  (...)
  def to_b
     ... the stuff decribed above ...
  end
  (...)
end

class MyMessage < Message
  ... bla bla ...
  attr_accessor :header
  (...)
  def to_b
    bytes = super
    header_bytes = @header.to_b
    return header_bytes+bytes
  end
  (...)
end

(...)

my_message.header = ...
my_message.header.product_category_code = 1
my_message.header.status_code           = 0
my_message.header.spec_id               = 2

message_bytes = my_message.to_b