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