diff --git a/backend/src/aurinko/updater.gleam b/backend/src/aurinko/updater.gleam index 9575e90..13038c0 100644 --- a/backend/src/aurinko/updater.gleam +++ b/backend/src/aurinko/updater.gleam @@ -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) { - case message { - Update -> { - use #(cookies, cookies_acquired, new_dataset) <- result.try(update( - username, - password, - cookies, - cookies_acquired, - ids, - dataset, - )) + with_initialised_state(state, fn(credentials, inner_state) { + case message { + Update -> { + 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(