Current section
Files
Jump to
Current section
Files
src/midas/browser.gleam
import gleam/fetch
import gleam/int
import gleam/io
import gleam/javascript/promise
import gleam/string
import gleam/uri
import midas/browser/zip
import midas/effect as e
import plinth/browser/window
// can't be part of main midas reliance on node stuff. would need to be sub package
pub fn run(task) {
case task {
e.Done(value) -> promise.resolve(value)
e.Fetch(request, resume) -> {
use return <- promise.await(do_fetch(request))
run(resume(return))
}
e.Follow(url, resume) -> {
use return <- promise.await(do_follow(url))
run(resume(uri.parse(return)))
}
e.Log(message, resume) -> {
io.println(message)
run(resume(Ok(Nil)))
}
e.Zip(files, resume) -> {
use zipped <- promise.await(zip.zip(files))
run(resume(Ok(zipped)))
}
e.Bundle(..) -> panic as { "Unsupported effect: " <> "Bundle" }
e.ExportJsonWebKey(..) ->
panic as { "Unsupported effect: " <> "ExportJsonWebKey" }
e.GenerateKeyPair(..) ->
panic as { "Unsupported effect: " <> "GenerateKeyPair" }
e.Hash(..) -> panic as { "Unsupported effect: " <> "Hash" }
e.List(..) -> panic as { "Unsupported effect: " <> "List" }
e.Read(..) -> panic as { "Unsupported effect: " <> "Read" }
e.Serve(..) -> panic as { "Unsupported effect: " <> "Serve" }
e.Sign(..) -> panic as { "Unsupported effect: " <> "Sign" }
e.StrongRandom(..) -> panic as { "Unsupported effect: " <> "StrongRandom" }
e.UnixNow(..) -> panic as { "Unsupported effect: " <> "UnixNow" }
e.Visit(..) -> panic as { "Unsupported effect: " <> "Visit" }
e.Write(..) -> panic as { "Unsupported effect: " <> "Write" }
}
}
pub fn do_fetch(request) {
use response <- promise.await(fetch.send_bits(request))
case response {
Ok(response) -> {
use response <- promise.await(fetch.read_bytes_body(response))
let response = case response {
Ok(response) -> Ok(response)
Error(fetch.NetworkError(s)) -> Error(e.NetworkError(s))
Error(fetch.UnableToReadBody) -> Error(e.UnableToReadBody)
Error(fetch.InvalidJsonBody) -> panic
}
promise.resolve(response)
}
Error(fetch.NetworkError(s)) -> promise.resolve(Error(e.NetworkError(s)))
Error(fetch.UnableToReadBody) -> promise.resolve(Error(e.UnableToReadBody))
Error(fetch.InvalidJsonBody) -> panic
}
}
fn do_follow(url) {
let url = uri.to_string(url)
let frame = #(600, 700)
let assert Ok(popup) = open(url, frame)
receive_redirect(popup, 100)
}
pub fn open(url, frame_size) {
let space = #(
window.outer_width(window.self()),
window.outer_height(window.self()),
)
let #(#(offset_x, offset_y), #(inner_x, inner_y)) = center(frame_size, space)
let features =
string.concat([
"popup",
",width=",
int.to_string(inner_x),
",height=",
int.to_string(inner_y),
",left=",
int.to_string(offset_x),
",top=",
int.to_string(offset_y),
])
window.open(url, "_blank", features)
}
pub fn center(inner, outer) {
let #(inner_x, inner_y) = inner
let #(outer_x, outer_y) = outer
let inner_x = int.min(inner_x, outer_x)
let inner_y = int.min(inner_y, outer_y)
let offset_x = { outer_x - inner_x } / 2
let offset_y = { outer_y - inner_y } / 2
#(#(offset_x, offset_y), #(inner_x, inner_y))
}
pub fn receive_redirect(popup, wait) {
use Nil <- promise.await(do_wait(wait))
case window.location_of(popup) {
Ok("http" <> _ as location) -> {
window.close(popup)
promise.resolve(location)
}
_ -> receive_redirect(popup, wait)
}
}
import plinth/javascript/global
pub fn do_wait(delay) {
promise.new(fn(resolve) {
global.set_timeout(delay, fn() { resolve(Nil) })
Nil
})
}