Made it better

This commit is contained in:
Mikko Ahlroth 2024-07-04 22:13:18 +03:00
parent 05b7a81139
commit 3e809e360b

View file

@ -39,19 +39,31 @@ pub type Dataset {
Dataset(production_info: ProductionInfo, modules: ModuleDataset)
}
pub type State {
InitialState(
username: String,
password: String,
error: option.Option(UpdateError),
)
LoadedState(
username: String,
password: String,
cookies: biscotto.CookieJar,
cookies_acquired: birl.Time,
ids: ModuleIDs,
pub type Credentials {
Credentials(username: String, password: String)
}
pub type Cookies {
Cookies(jar: biscotto.CookieJar, acquired: birl.Time)
}
pub type InitialisedState {
InitialisedState(
cookies: Cookies,
modules: ModuleIDs,
dataset: option.Option(Dataset),
)
}
pub type InnerState {
Pending
Initialised(InitialisedState)
}
pub type State {
State(
credentials: Credentials,
inner: InnerState,
error: option.Option(UpdateError),
)
}
@ -62,153 +74,93 @@ pub type UpdateError {
}
pub fn start(username: String, password: String) {
actor.start(InitialState(username, password, option.None), handle_message)
actor.start(
State(Credentials(username, password), Pending, option.None),
handle_message,
)
}
fn handle_message(message: Message, state: State) -> actor.Next(Message, State) {
let next =
with_loaded_state(
state,
fn(username, password, cookies, cookies_acquired, ids, dataset) {
with_initialised_state(state, fn(credentials, inner_state) {
case message {
Update -> {
use #(cookies, cookies_acquired, new_dataset) <- result.try(update(
username,
password,
cookies,
cookies_acquired,
ids,
dataset,
))
use new_state <- result.try(update(credentials, inner_state))
let new_state =
LoadedState(
username,
password,
cookies,
cookies_acquired,
ids,
option.Some(new_dataset),
option.None,
)
Ok(actor.continue(new_state))
Ok(actor.continue(State(..state, inner: Initialised(new_state))))
}
}
},
)
})
case next {
Ok(next) -> next
Error(err) -> {
let new_state = case state {
InitialState(username, password, ..) ->
InitialState(username, password, error: option.Some(err))
LoadedState(
username,
password,
cookies,
cookies_acquired,
ids,
dataset,
..,
) ->
LoadedState(
username,
password,
cookies,
cookies_acquired,
ids,
dataset,
option.Some(err),
)
}
let new_state = State(..state, error: option.Some(err))
actor.continue(new_state)
}
}
}
fn with_loaded_state(
fn with_initialised_state(
state: State,
fun: fn(
String,
String,
biscotto.CookieJar,
birl.Time,
ModuleIDs,
option.Option(Dataset),
) ->
fun: fn(Credentials, InitialisedState) ->
Result(actor.Next(Message, State), UpdateError),
) {
case state {
InitialState(username, password, ..) -> {
use loaded_state <- result.try(
init(username, password) |> result.map_error(APIError),
)
fun(
username,
password,
loaded_state.0,
loaded_state.1,
loaded_state.2,
loaded_state.3,
case state.inner {
Pending -> {
use initialised_state <- result.try(
init(state.credentials.username, state.credentials.password)
|> result.map_error(APIError),
)
fun(state.credentials, initialised_state)
}
LoadedState(username, password, cookies, cookies_acquired, ids, dataset, ..) ->
fun(username, password, cookies, cookies_acquired, ids, dataset)
Initialised(inner) -> fun(state.credentials, inner)
}
}
fn login(username: String, password: String) {
use cookies <- result.try(api.login(username, password))
Ok(#(cookies, birl.utc_now()))
Ok(Cookies(cookies, birl.utc_now()))
}
fn init(username: String, password: String) {
use #(cookies, cookies_acquired) <- result.try(login(username, password))
use module_ids <- result.try(api.get_module_ids(cookies))
use cookies <- result.try(login(username, password))
use module_ids <- result.try(api.get_module_ids(cookies.jar))
Ok(#(cookies, cookies_acquired, module_ids, option.None))
Ok(InitialisedState(cookies, module_ids, option.None))
}
fn update(
username: String,
password: String,
cookies: biscotto.CookieJar,
cookies_acquired: birl.Time,
module_ids: ModuleIDs,
dataset: option.Option(Dataset),
) {
fn update(credentials: Credentials, state: InitialisedState) {
let now = birl.utc_now()
let max_lifetime = duration.seconds(login_cookie_expiry)
let should_renew = case
duration.compare(birl.difference(now, cookies_acquired), max_lifetime)
duration.compare(birl.difference(now, state.cookies.acquired), max_lifetime)
{
order.Gt | order.Eq -> True
_ -> False
}
let cookies_result = case should_renew {
False -> Ok(#(cookies, cookies_acquired))
True -> login(username, password)
False -> Ok(state.cookies)
True -> login(credentials.username, credentials.password)
}
use #(cookies, cookies_acquired) <- result.try(
cookies_result |> result.map_error(APIError),
)
use cookies <- result.try(cookies_result |> result.map_error(APIError))
use production_info <- result.try(
api.get_production(cookies) |> result.map_error(APIError),
api.get_production(cookies.jar) |> result.map_error(APIError),
)
use module_datas <- result.try(
api.get_module_power(cookies, module_ids) |> result.map_error(APIError),
api.get_module_power(cookies.jar, state.modules)
|> result.map_error(APIError),
)
use parsed_module_datas <- result.try(
module_power.decode_api_data(module_datas)
|> result.map_error(DecodeError),
)
let new_dataset = case dataset {
let new_dataset = case state.dataset {
option.Some(existing_dataset) ->
Dataset(..existing_dataset, production_info: production_info)
option.None ->
@ -224,7 +176,13 @@ fn update(
modules: add_module_datasets(new_dataset.modules, parsed_module_datas),
)
Ok(#(cookies, cookies_acquired, new_dataset))
Ok(
InitialisedState(
..state,
cookies: cookies,
dataset: option.Some(new_dataset),
),
)
}
fn add_module_datasets(