#!/usr/bin/ruby # frozen_string_literal: true require "dhall" require "pg" require_relative "../lib/blather_notify" require_relative "../lib/to_form" CONFIG = Dhall.load(<<-DHALL).sync (#{ARGV[0]}) : { sgx_jmp: Text, notify_using: { jid: Text, password: Text, target: Text -> Text, body: Text -> Text -> Text } } DHALL using ToForm db = PG.connect(dbname: "jmp") db.type_map_for_results = PG::BasicTypeMapForResults.new(db) db.type_map_for_queries = PG::BasicTypeMapForQueries.new(db) BlatherNotify.start( CONFIG[:notify_using][:jid], CONFIG[:notify_using][:password] ) def format(item) if item.respond_to?(:note) && item.note && item.note.text != "" item.note.text elsif item.respond_to?(:to_xml) item.to_xml else item.inspect end end class ExpiringCustomer def initialize(customer_id) @customer_id = customer_id end def info BlatherNotify.execute( "customer info", { q: @customer_id }.to_form(:submit) ).then do |iq| @sessionid = iq.sessionid unless iq.form.field("customer_id") raise "#{@customer_id} not found" end iq end end def next raise "Call info first" unless @sessionid BlatherNotify.write_with_promise(BlatherNotify.command( "customer info", @sessionid )) end def bill_plan raise "Call info first" unless @sessionid BlatherNotify.write_with_promise(BlatherNotify.command( "customer info", @sessionid, action: :complete, form: { action: "bill_plan" }.to_form(:submit) )) end end one = Queue.new EM::Iterator.new(db.exec( <<-SQL SELECT customer_id FROM customer_plans WHERE expires_at <= LOCALTIMESTAMP + '4 days' SQL ), 3).each(nil, -> { one << :done }) do |row, iter| customer = ExpiringCustomer.new(row["customer_id"]) customer.info.then { customer.next }.then { customer.bill_plan }.then { |result| puts format(result) iter.next }.catch do |err| one << (err.is_a?(Exception) ? err : RuntimeError.new(format(err))) end end result = one.pop raise result if result.is_a?(Exception)