Commit 9959da72 authored by Jeffrey Phillips Freeman's avatar Jeffrey Phillips Freeman 💥
Browse files

Adding IGATE support

parent 14ecafe3
require 'apex/aprs_kiss'
\ No newline at end of file
require 'apex/aprs_kiss'
require 'apex/igate/client'
require 'apex/igate/filter'
require 'apex/igate/gilter/constants'
require 'socket'
module Apex
module Igate
class Client
attr_reader :hostname, :port, :version
class Error < StandardError; end
def initialize(hostname:, port:, version: "Apex::Igate::Client v#{VERSION}")
@hostname = hostname
@port = port
@version = version
@line_cache = ""
end
def login(call_sign, filters = [])
send_message(login_message(call_sign, filters))
return self
end
def apply_filter(filter)
send_message(filter_message(filter))
end
def read
end
def read
read_char = socket_recv()
while not read_char.nil?
if read_char.eql? "\r" or read_char.eql? "\n"
if @line_cache.length > 0
complete_line = @line_cache
@line_cache = ""
return complete_line
end
else
@line_cache << read_char
end
read_char = socket_recv()
end
return nil
end
def read_all(&block)
while line = socket.gets
yield line
end
end
# :nocov:
def stream(&block)
loop do
read(&block)
end
end
# :nocov:
def send_message(message)
socket.puts message
end
private
def login_message(call_sign, filters = [])
filters.unshift('filter') if filters.any?
[
"user #{call_sign} pass #{passcode_for(call_sign)} vers #{version}",
filters.compact.collect(&:to_s)
].flatten.compact.join(" ")
end
def filter_message(filter)
"filter #{filter}"
end
def passcode_for(call_sign)
@passcode = Apex::Igate::Passcode.new(call_sign)
end
def socket
@socket ||= TCPSocket.open(hostname, port)
end
def socket_recv
ready = IO.select([@socket], nil, nil, 0)
return nil unless ready
read_char = @socket.recv(1)
return nil if read_char.eql? ""
return read_chat
end
end
end
end
require 'apex/igate/filter/constants'
module Apex
module Igate
class Filter
class InvalidTypeError < StandardError; end;
class ValueArityError < StandardError; end;
attr_reader :filter_type, :values
def initialize(type:, values: )
@filter_type = type
@values = values || []
validate_filter_type
validate_arity
end
def to_s
values.dup.unshift(prefix).compact.join("/")
end
private
def validate_arity
raise ValueArityError.new("Filter type '#{filter_type}' requires #{arity} values only #{values.length} given.") unless arity_matches?
end
def validate_filter_type
raise InvalidTypeError.new("'#{filter_type}' is not a valid type.") unless type_exists?
end
def arity_matches?
(arity == -1 && values.length > 0) || [arity].flatten.include?(values.length)
end
def type_exists?
Constants::FILTER_TYPE_MAP.has_key?(filter_type)
end
def arity
Constants::FILTER_TYPE_MAP[filter_type][:arity]
end
def prefix
Constants::FILTER_TYPE_MAP[filter_type][:prefix]
end
end
end
end
module Apex
module Igate
class Filter
module Constants
FILTER_TYPE_MAP = {
range: {
prefix: 'r',
arity: 3
},
prefix: {
prefix: 'p',
arity: -1
},
callsign: {
prefix: 'b',
arity: -1
},
object: {
prefix: 'o',
arity: -1
},
strict: {
prefix: 'os',
arity: -1
},
type: {
prefix: 't',
arity: [1,3]
},
symbol: {
prefix: 's',
arity: 3
},
digipeater: {
prefix: 'd',
arity: -1
},
area: {
prefix: 'a',
arity: 4
},
entry: {
prefix: 'e',
arity: -1
},
group: {
prefix: 'g',
arity: -1
},
unproto: {
prefix: 'u',
arity: -1
},
q: {
prefix: 'q',
arity: (1..2)
},
me: {
prefix: 'm',
arity: 1
},
friend: {
prefix: 'f',
arity: 2
},
}.freeze
end
end
end
end
module Apex
module Igate
class Passcode
attr_reader :call_sign
def initialize(call_sign)
@call_sign = call_sign
end
def to_s
generate.to_s
end
def generate
hash = 0x73e2
flag = true
call_sign_for_generation.split('').each do |c|
hash = if flag
(hash ^ (c.ord << 8))
else
(hash ^ c.ord)
end
flag = !flag
end
hash & 0x7fff
end
private
def call_sign_for_generation
call_sign.upcase.split('-').first
end
end
end
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment