Replace gleam_hackney with custom finch adapter

This commit is contained in:
Mikko Ahlroth 2023-01-14 00:52:06 +02:00
parent f469796260
commit bcba4a92b3
7 changed files with 159 additions and 11 deletions

12
mix.exs
View file

@ -38,7 +38,16 @@ defmodule GeoTherminator.MixProject do
def application do
[
mod: {GeoTherminator.Application, []},
extra_applications: [:logger, :runtime_tools, :logger, :ssl, :crypto, :sasl, :tools, :inets]
extra_applications: [
:logger,
:runtime_tools,
:logger,
:ssl,
:crypto,
:sasl,
:tools,
:inets
]
]
end
@ -69,7 +78,6 @@ defmodule GeoTherminator.MixProject do
{:cubdb, "~> 2.0"},
{:gleam_stdlib, "~> 0.25"},
{:gleam_http, "~> 3.1"},
{:gleam_hackney, "~> 0.2.1"},
{:gleam_erlang, "~> 0.17.1"},
{:gleam_json, "~> 0.5.0"}
]

View file

@ -18,7 +18,6 @@
"floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"},
"gettext": {:hex, :gettext, "0.21.0", "15bbceb20b317b706a8041061a08e858b5a189654128618b53746bf36c84352b", [:mix], [{:expo, "~> 0.1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "04a66db4103b6d1d18f92240bb2c73167b517229316b7bef84e4eebbfb2f14f6"},
"gleam_erlang": {:hex, :gleam_erlang, "0.17.1", "40fff501e8ca39fa166f4c12ed13bb57e94fc5bb59a93b4446687d82d4a12ff9", [:gleam], [{:gleam_stdlib, "~> 0.22", [hex: :gleam_stdlib, repo: "hexpm", optional: false]}], "hexpm", "baaa84f5bcc4477e809ba3e03bb3009a3894a6544c1511626c44408e39db2ae6"},
"gleam_hackney": {:hex, :gleam_hackney, "0.2.1", "ca3c5677b85f31885a4366c73a110803515d6d23a2e233e459dc164260315404", [:gleam], [{:gleam_http, "~> 3.0", [hex: :gleam_http, repo: "hexpm", optional: false]}, {:gleam_stdlib, "~> 0.18", [hex: :gleam_stdlib, repo: "hexpm", optional: false]}, {:hackney, "~> 1.18", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "ccaca00027c827436d8eb945651392b6e5798cfc9e69907a28be61832b0c02a4"},
"gleam_http": {:hex, :gleam_http, "3.1.1", "609158240630e21fc70c69b21384e5ebbcd86f71bd378a6f7c2b87f910ab3561", [:gleam], [{:gleam_stdlib, "~> 0.18", [hex: :gleam_stdlib, repo: "hexpm", optional: false]}], "hexpm", "b66b7a1539ccb577119e4dc80dd3484c1a652cb032967954498eedbae3355763"},
"gleam_json": {:hex, :gleam_json, "0.5.0", "aff4507ad7700ad794ada6671c6dfd0174696713659bd8782858135b19f41b58", [:gleam], [{:gleam_stdlib, "~> 0.19", [hex: :gleam_stdlib, repo: "hexpm", optional: false]}, {:thoas, "~> 0.2", [hex: :thoas, repo: "hexpm", optional: false]}], "hexpm", "e42443c98aa66e30143c24818f2cea801491c10ce6b1a5eddf3fc4abdc7601cb"},
"gleam_stdlib": {:hex, :gleam_stdlib, "0.25.0", "656f39258dcc8772719e463bbe7d1d1c7800238a520b41558fad53ea206ee3ab", [:gleam], [], "hexpm", "ad0f89928e0b919c8f8edf640484633b28dbf88630a9e6ae504617a3e3e5b9a2"},
@ -53,4 +52,5 @@
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"thoas": {:hex, :thoas, "0.4.0", "86a72ccdc5ec388a13f9f843bcd6c1076640233b95440e47ffb8e3c0dbdb5a17", [:rebar3], [], "hexpm", "442296847aca11db8d25180693d7ca3073d6d7179f66952f07b16415306513b6"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"wx": {:hex, :bridge, "1.0.10", "5051dfe881e498a0bc056603df97b734bfe5fdc084f5e56dc42fab8049247144", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b30941e57a194e557a123c5246f123f8b13acdd5c580f75590a52e72bda15632"},
}

View file

@ -5,7 +5,6 @@
import gleam/json
import gleam/base
import gleam/hackney
import gleam/uri
import gleam/http
import gleam/http/request
@ -16,6 +15,8 @@ import gleam/list
import gleam/result
import gleam/int
import azure/utils
import helpers/config
import helpers/finch
import helpers/crypto
import helpers/uri as uri_helpers
import helpers/parsing
@ -186,7 +187,8 @@ fn confirm(
try resp =
req
|> hackney.send()
|> finch.build()
|> finch.request(config.finch_server())
|> b2c_error("Confirm HTTP request failed.")
try resp = case resp.status {
@ -286,7 +288,8 @@ fn run_req(
) -> Result(response.Response(String), B2CError) {
try resp =
req
|> hackney.send()
|> finch.build()
|> finch.request(config.finch_server())
|> b2c_error("HTTP request failed.")
case resp.status {

View file

@ -3,9 +3,8 @@ import gleam/dynamic
import gleam/uri
import helpers/application
fn app_name() -> atom.Atom {
assert Ok(name) = atom.from_string("geo_therminator")
name
pub fn finch_server() -> atom.Atom {
atom.create_from_string("Elixir.GeoTherminator.PumpAPI.HTTP")
}
pub fn api_timeout() -> Int {
@ -27,6 +26,11 @@ pub fn api_installations_url() -> uri.Uri {
config_url("api_installations_url")
}
fn app_name() -> atom.Atom {
assert Ok(name) = atom.from_string("geo_therminator")
name
}
fn config_url(config_key: String) -> uri.Uri {
let url =
application.fetch_env_angry(app_name(), atom.create_from_string(config_key))

120
src/helpers/finch.gleam Normal file
View file

@ -0,0 +1,120 @@
import gleam/uri
import gleam/erlang/atom.{Atom}
import gleam/http
import gleam/http/request as gleam_request
import gleam/http/response as gleam_response
import gleam/dynamic.{Dynamic}
import helpers/keyword.{Keyword}
import helpers/config
pub type Method {
Head
Get
Put
Post
Patch
Delete
Options
}
pub type Headers =
List(#(String, String))
pub external type Request
pub external type Response
pub fn build(req: gleam_request.Request(String)) -> Request {
let opts =
keyword.init()
|> keyword.put_int(atom.create_from_string("timeout"), config.api_timeout())
let url_str =
req
|> gleam_request.to_uri()
|> uri.to_string()
build_ext(
gleam_method_to_finch_method(req.method),
url_str,
req.headers,
req.body,
opts,
)
}
pub fn request(
req: Request,
server: Atom,
) -> Result(gleam_response.Response(String), Dynamic) {
try resp = do_request(req, server)
Ok(gleam_response.Response(
body: response_body(resp),
headers: response_headers(resp),
status: response_status(resp),
))
}
pub external fn build_ext(
method: Method,
url: String,
headers: Headers,
body: String,
opts: Keyword,
) -> Request =
"Elixir.Finch" "build"
external fn do_request(req: Request, server: Atom) -> Result(Response, Dynamic) =
"Elixir.Finch" "request"
pub fn response_body(resp: Response) -> String {
get_response_body(resp, Body)
}
pub fn response_headers(resp: Response) -> Headers {
get_response_headers(resp, Headers)
}
pub fn response_status(resp: Response) -> Int {
get_response_status(resp, Status)
}
fn gleam_method_to_finch_method(method: http.Method) -> Method {
case method {
http.Get -> Get
http.Head -> Head
http.Post -> Post
http.Put -> Put
http.Patch -> Patch
http.Delete -> Delete
http.Options -> Options
// This should never happen
_other -> Get
}
}
type ResponseBodyKey {
Body
}
type ResponseHeadersKey {
Headers
}
type ResponseStatusKey {
Status
}
external fn get_response_body(resp: Response, key: ResponseBodyKey) -> String =
"Elixir.Map" "fetch!"
external fn get_response_status(resp: Response, key: ResponseStatusKey) -> Int =
"Elixir.Map" "fetch!"
external fn get_response_headers(
resp: Response,
key: ResponseHeadersKey,
) -> Headers =
"Elixir.Map" "fetch!"

12
src/helpers/keyword.gleam Normal file
View file

@ -0,0 +1,12 @@
import gleam/erlang/atom.{Atom}
pub external type Keyword
pub external fn init() -> Keyword =
"Elixir.Keyword" "new"
pub external fn put_int(data: Keyword, key: Atom, value: Int) -> Keyword =
"Elixir.Keyword" "put"
pub external fn put_string(data: Keyword, key: Atom, value: String) -> Keyword =
"Elixir.Keyword" "put"

View file

@ -1,6 +1,5 @@
import gleam/http/request
import gleam/json
import gleam/hackney
import gleam/result
import gleam/dynamic
import gleam/list
@ -12,6 +11,7 @@ import pump_api/http
import helpers/config
import helpers/date_time
import helpers/parsing
import helpers/finch
import azure/b2c.{B2CError}
pub type ApiError {
@ -69,7 +69,8 @@ pub fn installation_info(user: User) -> Result(List(InstallationInfo), ApiError)
fn run_req(req: request.Request(String)) {
try resp =
req
|> hackney.send()
|> finch.build()
|> finch.request(config.finch_server())
|> result.replace_error(ApiRequestFailed)
try body = case resp.status {