1# frozen_string_literal: true
2
3require "em-http"
4require "em-synchrony/em-http" # For apost vs post
5require "json"
6require "lazy_object"
7require "value_semantics/monkey_patched"
8
9require_relative "sim"
10
11class SIMRepo
12 value_semantics do
13 db Anything(), default: LazyObject.new { DB }
14 end
15
16 KEEPGO_HEADERS = {
17 "Accept" => "application/json",
18 "apiKey" => CONFIG[:keepgo][:api_key],
19 "accessToken" => CONFIG[:keepgo][:access_token]
20 }.freeze
21
22 def all(start_page=1)
23 req("lines").aget(
24 head: KEEPGO_HEADERS, query: { page: start_page, per_page: 1000 }
25 ).then { |req|
26 result = JSON.parse(req.response)
27 sims = result.dig("sim_cards", "items")&.map(&SIM.method(:extract))
28
29 next sims if result.dig("sim_cards", "last_page") == start_page
30 next [] if !sims || sims.empty?
31
32 all(start_page + 1).then { |next_page| sims + next_page }
33 }
34 end
35
36 def find(iccid)
37 req("line/#{iccid}/get_details").aget(head: KEEPGO_HEADERS).then { |req|
38 SIM.extract(JSON.parse(req.response)&.dig("sim_card"))
39 }
40 end
41
42 def refill(sim, **kwargs)
43 iccid = sim.is_a?(String) ? sim : sim.iccid
44
45 req("line/#{iccid}/refill").apost(
46 head: KEEPGO_HEADERS.merge("Content-Type" => "application/json"),
47 body: kwargs.to_json
48 ).then { |req| JSON.parse(req.response) }
49 end
50
51 def update_nicknames(sims)
52 iccids = PG::TextEncoder::Array.new.encode(sims.map(&:iccid))
53 nicknames = PG::TextEncoder::Array.new.encode(sims.map(&:nickname))
54 db.query_defer(<<~SQL, [iccids, nicknames])
55 UPDATE sims SET nickname = data_table.nickname
56 FROM
57 (SELECT UNNEST($1::text[]) AS iccid, UNNEST($2::text[]) AS nickname) AS data_table
58 WHERE sims.iccid = data_table.iccid
59 SQL
60 end
61
62 def owned_by(customer)
63 customer = customer.customer_id if customer.respond_to?(:customer_id)
64 promise = db.query_defer(<<~SQL, [customer])
65 SELECT iccid, nickname FROM sims WHERE customer_id=$1
66 SQL
67 promise.then { |result|
68 EMPromise.all(result.map { |row|
69 find(row["iccid"]).then { |sim| sim.with(nickname: row["nickname"]) }
70 })
71 }
72 end
73
74 def put_owner(sim, customer, nickname=nil)
75 db.exec(<<~SQL, [customer.customer_id, sim.iccid, nickname])
76 UPDATE sims SET customer_id=$1, nickname=COALESCE($3, nickname) WHERE iccid=$2 AND customer_id IS NULL
77 SQL
78 end
79
80 def available
81 db.query_defer(<<~SQL).then { |r| find(r.first["iccid"]) }
82 SELECT iccid FROM sims WHERE customer_id IS NULL LIMIT 1
83 SQL
84 end
85
86protected
87
88 def req(path)
89 EM::HttpRequest.new(
90 "https://myaccount.keepgo.com/api/v2/#{path}",
91 tls: { verify_peer: true }
92 )
93 end
94end