Add functioning sdk
Some checks are pending
test / test (push) Waiting to run

This commit is contained in:
Lily Rose 2025-06-17 01:43:06 +10:00
parent 356f279af6
commit cc8edbed02
124 changed files with 13962 additions and 6 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.ez
/build
erl_crash.dump
.env

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
import gleam/io
import oas/generator
import snag
pub fn main() {
case
generator.build(
"dev/spacetraders.openapi.json",
".",
"spacetraders_sdk",
[],
)
{
Ok(_) -> Nil
Error(reason) -> io.print(snag.pretty_print(reason))
}
}

View file

@ -7,6 +7,16 @@ repository = { type = "forgejo", host = "7cs.dev", user = "lily", repo = "gleam-
[dependencies]
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
snag = ">= 1.1.0 and < 2.0.0"
gleam_http = ">= 4.0.0 and < 5.0.0"
dot_env = ">= 1.2.0 and < 2.0.0"
stratus = ">= 0.9.7 and < 1.0.0"
gleam_httpc = ">= 4.2.0 and < 5.0.0"
gleam_otp = ">= 0.16.1 and < 1.0.0"
gleam_erlang = ">= 0.34.0 and < 1.0.0"
gleam_json = ">= 3.0.1 and < 4.0.0"
birl = ">= 1.8.0 and < 2.0.0"
[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
oas_generator = ">= 1.3.3 and < 2.0.0"

View file

@ -2,10 +2,44 @@
# You typically do not need to edit this file
packages = [
{ name = "birl", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_regexp", "gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "2AC7BA26F998E3DFADDB657148BD5DDFE966958AD4D6D6957DD0D22E5B56C400" },
{ name = "dot_env", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "simplifile"], otp_app = "dot_env", source = "hex", outer_checksum = "F2B4815F1B5AF8F20A6EADBB393E715C4C35203EBD5BE8200F766EA83A0B18DE" },
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
{ name = "glam", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "4932A2D139AB0389E149396407F89654928D7B815E212BB02F13C66F53B1BBA1" },
{ name = "glance", version = "3.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "F3458292AFB4136CEE23142A8727C1270494E7A96978B9B9F9D2C1618583EF3D" },
{ name = "glance_printer", version = "3.0.0", build_tools = ["gleam"], requirements = ["glam", "glance", "gleam_stdlib"], otp_app = "glance_printer", source = "hex", outer_checksum = "8386C156B413B90828884577F89AADD4C131AA1C3DAFC826607BAEE40E636ACE" },
{ name = "gleam_crypto", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "917BC8B87DBD584830E3B389CBCAB140FFE7CB27866D27C6D0FB87A9ECF35602" },
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
{ name = "gleam_http", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "0A62451FC85B98062E0907659D92E6A89F5F3C0FBE4AB8046C99936BF6F91DBC" },
{ name = "gleam_httpc", version = "4.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "5EE88F7AF296C09B578BAB4D5383F24AB3A9A7E9D4B4772D112A00405D1DC516" },
{ name = "gleam_json", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "5BA154440B22D9800955B1AB854282FA37B97F30F409D76B0824D0A60C934188" },
{ name = "gleam_otp", version = "0.16.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "50DA1539FC8E8FA09924EB36A67A2BBB0AD6B27BCDED5A7EF627057CF69D035E" },
{ name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
{ name = "gleam_stdlib", version = "0.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" },
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
{ name = "gleeunit", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D33B7736CF0766ED3065F64A1EBB351E72B2E8DE39BAFC8ADA0E35E92A6A934F" },
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
{ name = "gramps", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "59194B3980110B403EE6B75330DB82CDE05FC8138491C2EAEACBC7AAEF30B2E8" },
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
{ name = "oas", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "oas", source = "hex", outer_checksum = "01FF7BEDB4389084D96D11FB26902F14F75256FDAD812E3AE65C1E29B7BCA80E" },
{ name = "oas_generator", version = "1.3.3", build_tools = ["gleam"], requirements = ["glance", "glance_printer", "gleam_http", "gleam_json", "gleam_stdlib", "justin", "oas", "simplifile", "snag"], otp_app = "oas_generator", source = "hex", outer_checksum = "9E2AD137E6883D99F0D7C515B42D4CFBA60A8B00DD3ED62ADE0DED29B84D8328" },
{ name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" },
{ name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" },
{ name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" },
{ name = "stratus", version = "0.9.7", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gramps", "logging"], otp_app = "stratus", source = "hex", outer_checksum = "4B3344B24B0808AF5828EFE3BEB824D3298E0ECAC8069D85D14A6A33BAD85CBD" },
]
[requirements]
birl = { version = ">= 1.8.0 and < 2.0.0" }
dot_env = { version = ">= 1.2.0 and < 2.0.0" }
gleam_erlang = { version = ">= 0.34.0 and < 1.0.0" }
gleam_http = { version = ">= 4.0.0 and < 5.0.0" }
gleam_httpc = { version = ">= 4.2.0 and < 5.0.0" }
gleam_json = { version = ">= 3.0.1 and < 4.0.0" }
gleam_otp = { version = ">= 0.16.1 and < 1.0.0" }
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
oas_generator = { version = ">= 1.3.3 and < 2.0.0" }
snag = { version = ">= 1.1.0 and < 2.0.0" }
stratus = { version = ">= 0.9.7 and < 1.0.0" }

View file

@ -0,0 +1,82 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json
import models/account.{type Account}
import models/agent.{type Agent}
import models/agent_symbol.{type AgentSymbol}
import models/contract.{type Contract}
import models/faction.{type Faction}
import models/faction_symbol.{type FactionSymbol}
import models/ship.{type Ship}
import utils/auth.{type AccountToken, type AgentToken, AccountAuth, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse}
pub type GetAccountResponse {
GetAccountResponse(account: Account)
}
fn get_account_response_decoder() -> Decoder(GetAccountResponse) {
use account <- decode.field("account", account.decoder())
decode.success(GetAccountResponse(account:))
}
pub fn get_account(token: AgentToken) -> ApiResponse(GetAccountResponse) {
let request = request_utils.get(AgentAuth(token), "/my/account")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_account_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type RegisterNewAgentResponse {
RegisterNewAgentResponse(
token: AgentToken,
agent: Agent,
faction: Faction,
contract: Contract,
ships: List(Ship),
)
}
fn register_new_agent_response_decoder() -> Decoder(RegisterNewAgentResponse) {
use token <- decode.field("token", auth.agent_token_decoder())
use agent <- decode.field("agent", agent.decoder())
use faction <- decode.field("faction", faction.decoder())
use contract <- decode.field("contract", contract.decoder())
use ships <- decode.field("ships", decode.list(ship.decoder()))
decode.success(RegisterNewAgentResponse(
token:,
agent:,
faction:,
contract:,
ships:,
))
}
pub fn register_new_agent(
token: AccountToken,
agent_symbol: AgentSymbol,
faction_symbol: FactionSymbol,
) -> ApiResponse(RegisterNewAgentResponse) {
let request =
request_utils.post_json(
AccountAuth(token),
"/register",
json.object([
#("symbol", json.string(agent_symbol)),
#("faction", json.string(faction_symbol.to_string(faction_symbol))),
]),
)
use response <- request_utils.try_send(request)
case response.status {
201 ->
response_utils.data_parser(
response.body,
register_new_agent_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}

102
src/endpoints/agents.gleam Normal file
View file

@ -0,0 +1,102 @@
import gleam/dynamic/decode.{type Decoder}
import models/agent.{type Agent}
import models/agent_event.{type AgentEvent}
import models/public_agent.{type PublicAgent}
import utils/auth.{type AgentToken, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse, type PagedData}
pub type ListPublicAgentsResponse {
ListPublicAgentsResponse(agents: List(PublicAgent))
}
fn list_public_agents_response_decoder() -> Decoder(ListPublicAgentsResponse) {
use agents <- decode.then(decode.list(public_agent.decoder()))
decode.success(ListPublicAgentsResponse(agents:))
}
pub fn list_public_agents(
token: AgentToken,
page: Int,
limit: Int,
) -> ApiResponse(PagedData(ListPublicAgentsResponse)) {
let request = request_utils.get_page(AgentAuth(token), "/agents", page, limit)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
list_public_agents_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetPublicAgentResponse {
GetPublicAgentResponse(agent: PublicAgent)
}
fn get_public_agent_response_decoder() -> Decoder(GetPublicAgentResponse) {
use agent <- decode.then(public_agent.decoder())
decode.success(GetPublicAgentResponse(agent:))
}
pub fn get_public_agent(
token: AgentToken,
agent_symbol: String,
) -> ApiResponse(GetPublicAgentResponse) {
let request = request_utils.get(AgentAuth(token), "/agents/" <> agent_symbol)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
get_public_agent_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetAgentResponse {
GetAgentResponse(agent: Agent)
}
fn get_agent_response_decoder() -> decode.Decoder(GetAgentResponse) {
use agent <- decode.then(agent.decoder())
decode.success(GetAgentResponse(agent:))
}
pub fn get_agent(token: AgentToken) -> ApiResponse(GetAgentResponse) {
let request = request_utils.get(AgentAuth(token), "/my/account")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_agent_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type GetAgentEventsResponse {
GetAgentEventsResponse(events: List(AgentEvent))
}
fn get_agent_events_response_decoder() -> Decoder(GetAgentEventsResponse) {
use events <- decode.then(decode.list(agent_event.decoder()))
decode.success(GetAgentEventsResponse(events:))
}
pub fn get_agent_events(
token: AgentToken,
) -> ApiResponse(GetAgentEventsResponse) {
let request = request_utils.get(AgentAuth(token), "/my/agent/events")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
get_agent_events_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}

View file

@ -0,0 +1,161 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json
import models/agent.{type Agent}
import models/contract.{type Contract}
import models/ship_cargo.{type ShipCargo}
import models/ship_symbol.{type ShipSymbol}
import models/trade_symbol.{type TradeSymbol}
import utils/auth.{type AgentToken, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse, type PagedData}
pub type ListContractsResponse {
ListContractsResponse(contracts: List(Contract))
}
fn list_contracts_response_decoder() -> Decoder(ListContractsResponse) {
use contracts <- decode.then(decode.list(contract.decoder()))
decode.success(ListContractsResponse(contracts:))
}
pub fn list_contracts(
token: AgentToken,
page: Int,
limit: Int,
) -> ApiResponse(PagedData(ListContractsResponse)) {
let request =
request_utils.get_page(AgentAuth(token), "/my/contracts", page, limit)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
list_contracts_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetContractResponse {
GetContractResponse(contract: Contract)
}
fn get_contract_response_decoder() -> Decoder(GetContractResponse) {
use contract <- decode.then(contract.decoder())
decode.success(GetContractResponse(contract:))
}
pub fn get_contract(
token: AgentToken,
contract_id: String,
) -> ApiResponse(GetContractResponse) {
let request =
request_utils.get(AgentAuth(token), "/my/contracts/" <> contract_id)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_contract_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type AcceptContractResponse {
AcceptContractResponse(contract: Contract, agent: Agent)
}
fn accept_contract_response_decoder() -> Decoder(AcceptContractResponse) {
use contract <- decode.field("contract", contract.decoder())
use agent <- decode.field("agent", agent.decoder())
decode.success(AcceptContractResponse(contract:, agent:))
}
pub fn accept_contract(
token: AgentToken,
contract_id: String,
) -> ApiResponse(AcceptContractResponse) {
let request =
request_utils.post(
AgentAuth(token),
"/my/contracts/" <> contract_id <> "/accept",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
accept_contract_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type FulfillContractResponse {
FulfillContractResponse(contract: Contract, agent: Agent)
}
fn fulfill_contract_response_decoder() -> Decoder(FulfillContractResponse) {
use contract <- decode.field("contract", contract.decoder())
use agent <- decode.field("agent", agent.decoder())
decode.success(FulfillContractResponse(contract:, agent:))
}
pub fn fulfill_contract(
token: AgentToken,
contract_id,
) -> ApiResponse(FulfillContractResponse) {
let request =
request_utils.post(
AgentAuth(token),
"/my/contracts/" <> contract_id <> "/fulfill",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
fulfill_contract_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type DeliverContractCargoResponse {
DeliverContractCargoResponse(contract: Contract, cargo: ShipCargo)
}
fn deliver_contract_cargo_response_decoder() -> Decoder(
DeliverContractCargoResponse,
) {
use contract <- decode.field("contract", contract.decoder())
use cargo <- decode.field("cargo", ship_cargo.decoder())
decode.success(DeliverContractCargoResponse(contract:, cargo:))
}
pub fn deliver_contract_cargo(
token: AgentToken,
contract_id: String,
ship_symbol: ShipSymbol,
trade_symbol: TradeSymbol,
units: Int,
) -> ApiResponse(DeliverContractCargoResponse) {
let request =
request_utils.post_json(
AgentAuth(token),
"/my/contracts/" <> contract_id <> "/deliver",
json.object([
#("shipSymbol", json.string(ship_symbol)),
#("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))),
#("units", json.int(units)),
]),
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
deliver_contract_cargo_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}

63
src/endpoints/data.gleam Normal file
View file

@ -0,0 +1,63 @@
import gleam/dict.{type Dict}
import gleam/dynamic/decode.{type Decoder}
import gleam/erlang/process.{type Subject}
import gleam/http/request
import gleam/option
import gleam/otp/actor
import stratus
import utils/auth.{type AgentToken, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse}
pub type GetSupplyChainResponse {
GetSupplyChainResponse(export_to_import_map: Dict(String, String))
}
fn get_supply_chain_response_decoder() -> Decoder(GetSupplyChainResponse) {
use export_to_import_map <- decode.field(
"exportToImportMap",
decode.dict(decode.string, decode.string),
)
decode.success(GetSupplyChainResponse(export_to_import_map:))
}
pub fn get_supply_chain(
token: AgentToken,
) -> ApiResponse(GetSupplyChainResponse) {
let request = request_utils.get(AgentAuth(token), "/market/supply-chain")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
get_supply_chain_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub fn get_departure_events(
token: AgentToken,
initial_state: state,
on_message: fn(state, stratus.Message(user)) ->
Result(state, process.ExitReason),
on_close: fn(state) -> Nil,
) -> Result(Subject(stratus.InternalMessage(user)), actor.StartError) {
stratus.websocket(
request: request_utils.get(AgentAuth(token), "/my/socket.io")
|> request.set_body(""),
init: fn() { #(initial_state, option.None) },
loop: fn(msg, state, conn) {
case on_message(state, msg) {
Ok(state) -> actor.continue(state)
Error(reason) -> {
let _ = stratus.close(conn)
actor.Stop(reason)
}
}
},
)
|> stratus.on_close(on_close)
|> stratus.initialize
}

View file

@ -0,0 +1,99 @@
import gleam/dynamic/decode.{type Decoder}
import models/faction.{type Faction}
import models/faction_symbol.{type FactionSymbol}
import utils/auth.{type AgentToken, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse, type PagedData}
pub type ListFactionsResponse {
ListFactionsResponse(factions: List(Faction))
}
fn list_factions_response_decoder() -> Decoder(ListFactionsResponse) {
use factions <- decode.then(decode.list(faction.decoder()))
decode.success(ListFactionsResponse(factions:))
}
pub fn list_factions(
token: AgentToken,
page: Int,
limit: Int,
) -> ApiResponse(PagedData(ListFactionsResponse)) {
let request =
request_utils.get_page(AgentAuth(token), "/factions", page, limit)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
list_factions_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetFactionResponse {
GetFactionResponse(faction: Faction)
}
fn get_faction_response_decoder() -> Decoder(GetFactionResponse) {
use faction <- decode.then(faction.decoder())
decode.success(GetFactionResponse(faction:))
}
pub fn get_faction(
token: AgentToken,
symbol: FactionSymbol,
) -> ApiResponse(GetFactionResponse) {
let request =
request_utils.get(
AgentAuth(token),
"/factions/" <> faction_symbol.to_string(symbol),
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_faction_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type FactionReputation {
FactionReputation(symbol: FactionSymbol, reputation: Int)
}
fn faction_reputation_decoder() {
use symbol <- decode.field("symbol", faction_symbol.decoder())
use reputation <- decode.field("reputation", decode.int)
decode.success(FactionReputation(symbol:, reputation:))
}
pub type GetMyFactionsResponse {
GetMyFactionsResponse(faction_reputations: List(FactionReputation))
}
fn get_my_factions_response_decoder() -> Decoder(GetMyFactionsResponse) {
use faction_reputations <- decode.then(
decode.list(faction_reputation_decoder()),
)
decode.success(GetMyFactionsResponse(faction_reputations:))
}
pub fn get_my_factions(
token: AgentToken,
page: Int,
limit: Int,
) -> ApiResponse(PagedData(GetMyFactionsResponse)) {
let request =
request_utils.get_page(AgentAuth(token), "/my/factions", page, limit)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
get_my_factions_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}

1327
src/endpoints/fleet.gleam Normal file

File diff suppressed because it is too large Load diff

192
src/endpoints/global.gleam Normal file
View file

@ -0,0 +1,192 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import utils/auth.{NoAuth}
import utils/decode as decode_utils
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse}
pub type Stats {
Stats(
accounts: Option(Int),
agents: Int,
ships: Int,
systems: Int,
waypoints: Int,
)
}
fn stats_decoder() -> Decoder(Stats) {
use accounts <- decode_utils.field_key_value_optional("accounts", decode.int)
use agents <- decode.field("agents", decode.int)
use ships <- decode.field("ships", decode.int)
use systems <- decode.field("systems", decode.int)
use waypoints <- decode.field("waypoints", decode.int)
decode.success(Stats(accounts:, agents:, ships:, systems:, waypoints:))
}
pub type Health {
Health(last_market_update: Option(String))
}
fn health_decoder() -> Decoder(Health) {
use last_market_update <- decode_utils.field_key_value_optional(
"lastMarketUpdate",
decode.string,
)
decode.success(Health(last_market_update:))
}
pub type CreditLeaderboardEntry {
CreditLeaderboardEntry(agent_symbol: String, credits: Int)
}
fn credit_leaderboard_entry_decoder() -> Decoder(CreditLeaderboardEntry) {
use agent_symbol <- decode.field("agentSymbol", decode.string)
use credits <- decode.field("credits", decode.int)
decode.success(CreditLeaderboardEntry(agent_symbol:, credits:))
}
pub type ChartLeaderboardEntry {
ChartLeaderboardEntry(agent_symbol: String, chart_count: Int)
}
fn chart_leaderboard_entry_decoder() -> Decoder(ChartLeaderboardEntry) {
use agent_symbol <- decode.field("agentSymbol", decode.string)
use chart_count <- decode.field("chartCount", decode.int)
decode.success(ChartLeaderboardEntry(agent_symbol:, chart_count:))
}
pub type Leaderboards {
Leaderboards(
most_credits: List(CreditLeaderboardEntry),
most_submitted_charts: List(ChartLeaderboardEntry),
)
}
fn leaderboards_decoder() -> Decoder(Leaderboards) {
use most_credits <- decode.field(
"mostCredits",
decode.list(credit_leaderboard_entry_decoder()),
)
use most_submitted_charts <- decode.field(
"mostSubmittedCharts",
decode.list(chart_leaderboard_entry_decoder()),
)
decode.success(Leaderboards(most_credits:, most_submitted_charts:))
}
pub type ServerResets {
ServerResets(next: String, frequency: String)
}
fn server_resets_decoder() -> Decoder(ServerResets) {
use next <- decode.field("next", decode.string)
use frequency <- decode.field("frequency", decode.string)
decode.success(ServerResets(next:, frequency:))
}
pub type Announcement {
Announcement(title: String, body: String)
}
fn announcement_decoder() -> Decoder(Announcement) {
use title <- decode.field("title", decode.string)
use body <- decode.field("body", decode.string)
decode.success(Announcement(title:, body:))
}
pub type Link {
Link(name: String, url: String)
}
fn link_decoder() -> Decoder(Link) {
use name <- decode.field("name", decode.string)
use url <- decode.field("url", decode.string)
decode.success(Link(name:, url:))
}
pub type GetServerStatusResponse {
GetServerStatusResponse(
status: String,
version: String,
reset_date: String,
description: String,
stats: Stats,
health: Health,
leaderboards: Leaderboards,
server_resets: ServerResets,
announcements: List(Announcement),
links: List(Link),
)
}
fn get_server_status_response_decoder() -> Decoder(GetServerStatusResponse) {
use status <- decode.field("status", decode.string)
use version <- decode.field("version", decode.string)
use reset_date <- decode.field("resetDate", decode.string)
use description <- decode.field("description", decode.string)
use stats <- decode.field("stats", stats_decoder())
use health <- decode.field("health", health_decoder())
use leaderboards <- decode.field("leaderboards", leaderboards_decoder())
use server_resets <- decode.field("serverResets", server_resets_decoder())
use announcements <- decode.field(
"announcements",
decode.list(announcement_decoder()),
)
use links <- decode.field("links", decode.list(link_decoder()))
decode.success(GetServerStatusResponse(
status:,
version:,
reset_date:,
description:,
stats:,
health:,
leaderboards:,
server_resets:,
announcements:,
links:,
))
}
pub fn get_server_status() -> ApiResponse(GetServerStatusResponse) {
let request = request_utils.get(NoAuth, "/")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.parser(response.body, get_server_status_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type ErrorCode {
ErrorCode(code: Int, name: String)
}
fn error_code_decoder() -> Decoder(ErrorCode) {
use code <- decode.field("code", decode.int)
use name <- decode.field("name", decode.string)
decode.success(ErrorCode(code:, name:))
}
pub type ListErrorCodesResponse {
ListErrorCodesResponse(error_codes: List(ErrorCode))
}
fn list_error_codes_response_decoder() -> Decoder(ListErrorCodesResponse) {
use error_codes <- decode.field(
"errorCodes",
decode.list(error_code_decoder()),
)
decode.success(ListErrorCodesResponse(error_codes:))
}
pub fn list_error_codes() -> ApiResponse(ListErrorCodesResponse) {
let request = request_utils.get(NoAuth, "/error-codes")
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.parser(response.body, list_error_codes_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}

321
src/endpoints/systems.gleam Normal file
View file

@ -0,0 +1,321 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json
import gleam/list
import gleam/option.{type Option}
import models/construction.{type Construction}
import models/jump_gate.{type JumpGate}
import models/market.{type Market}
import models/ship_cargo.{type ShipCargo}
import models/ship_symbol.{type ShipSymbol}
import models/shipyard.{type Shipyard}
import models/system.{type System}
import models/system_symbol.{type SystemSymbol}
import models/trade_symbol.{type TradeSymbol}
import models/waypoint.{type Waypoint}
import models/waypoint_symbol.{type WaypointSymbol}
import models/waypoint_trait_symbol.{type WaypointTraitSymbol}
import models/waypoint_type.{type WaypointType}
import utils/auth.{type AgentToken, AgentAuth}
import utils/request as request_utils
import utils/response as response_utils
import utils/types.{type ApiResponse, type PagedData}
pub type ListSystemsResponse {
ListSystemsResponse(systems: List(System))
}
fn list_systems_response_decoder() -> Decoder(ListSystemsResponse) {
use systems <- decode.then(decode.list(system.decoder()))
decode.success(ListSystemsResponse(systems:))
}
pub fn list_systems(
token: AgentToken,
page: Int,
limit: Int,
) -> ApiResponse(PagedData(ListSystemsResponse)) {
let request =
request_utils.get_page(AgentAuth(token), "/systems", page, limit)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
list_systems_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetSystemResponse {
GetSystemResponse(system: System)
}
fn get_system_response_decoder() -> Decoder(GetSystemResponse) {
use system <- decode.then(system.decoder())
decode.success(GetSystemResponse(system:))
}
pub fn get_system(
token: AgentToken,
system_symbol: SystemSymbol,
) -> ApiResponse(GetSystemResponse) {
let request =
request_utils.get(AgentAuth(token), "/systems/" <> system_symbol)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_system_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type ListSystemWaypointsResponse {
ListSystemWaypointsResponse(waypoints: List(Waypoint))
}
fn list_system_waypoints_response_decoder() -> Decoder(
ListSystemWaypointsResponse,
) {
use waypoints <- decode.then(decode.list(waypoint.decoder()))
decode.success(ListSystemWaypointsResponse(waypoints:))
}
pub fn list_system_waypoints(
token: AgentToken,
system_symbol: SystemSymbol,
page: Int,
limit: Int,
type_: Option(WaypointType),
traits: List(WaypointTraitSymbol),
) -> ApiResponse(PagedData(ListSystemWaypointsResponse)) {
let traits_query =
traits
|> list.map(fn(trait) {
#("traits", waypoint_trait_symbol.to_string(trait))
})
let query = case type_ {
option.Some(type_) -> [
#("type", waypoint_type.to_string(type_)),
..traits_query
]
option.None -> traits_query
}
let request =
request_utils.get_page_query(
AgentAuth(token),
"/systems/" <> system_symbol <> "/waypoints",
page,
limit,
query,
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.paged_data_parser(
response.body,
list_system_waypoints_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetWaypointResponse {
GetWaypointResponse(waypoint: Waypoint)
}
fn get_waypoint_response_decoder() -> Decoder(GetWaypointResponse) {
use waypoint <- decode.then(waypoint.decoder())
decode.success(GetWaypointResponse(waypoint:))
}
pub fn get_waypoint(
token: AgentToken,
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
) -> ApiResponse(GetWaypointResponse) {
let request =
request_utils.get(
AgentAuth(token),
"/systems/" <> system_symbol <> "/waypoints/" <> waypoint_symbol,
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_waypoint_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type GetConstructionSiteResponse {
GetConstructionSiteResponse(construction: Construction)
}
fn get_construction_site_response_decoder() -> Decoder(
GetConstructionSiteResponse,
) {
use construction <- decode.then(construction.decoder())
decode.success(GetConstructionSiteResponse(construction:))
}
pub fn get_construction_site(
token: AgentToken,
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
) -> ApiResponse(GetConstructionSiteResponse) {
let request =
request_utils.get(
AgentAuth(token),
"/systems/"
<> system_symbol
<> "/waypoints/"
<> waypoint_symbol
<> "/construction",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
get_construction_site_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type SupplyConstructionSiteResponse {
SupplyConstructionSiteResponse(construction: Construction, cargo: ShipCargo)
}
fn supply_construction_site_response_decoder() -> Decoder(
SupplyConstructionSiteResponse,
) {
use construction <- decode.field("construction", construction.decoder())
use cargo <- decode.field("cargo", ship_cargo.decoder())
decode.success(SupplyConstructionSiteResponse(construction:, cargo:))
}
pub fn supply_construction_site(
token: AgentToken,
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
trade_symbol: TradeSymbol,
units: Int,
) -> ApiResponse(SupplyConstructionSiteResponse) {
let request =
request_utils.post_json(
AgentAuth(token),
"/systems/"
<> system_symbol
<> "/waypoints/"
<> waypoint_symbol
<> "/construction/supply",
json.object([
#("shipSymbol", json.string(ship_symbol)),
#("tradeSymbol", json.string(trade_symbol.to_string(trade_symbol))),
#("units", json.int(units)),
]),
)
use response <- request_utils.try_send(request)
case response.status {
201 ->
response_utils.data_parser(
response.body,
supply_construction_site_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetMarketResponse {
GetMarketResponse(market: Market)
}
fn get_market_response_decoder() -> Decoder(GetMarketResponse) {
use market <- decode.then(market.decoder())
decode.success(GetMarketResponse(market:))
}
pub fn get_market(
token: AgentToken,
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
) -> ApiResponse(GetMarketResponse) {
let request =
request_utils.get(
AgentAuth(token),
"/systems/"
<> system_symbol
<> "/waypoints/"
<> waypoint_symbol
<> "/market",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_market_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}
pub type GetJumpGateResponse {
GetJumpGateResponse(jump_gate: JumpGate)
}
fn get_jump_gate_response_decoder() -> Decoder(GetJumpGateResponse) {
use jump_gate <- decode.then(jump_gate.decoder())
decode.success(GetJumpGateResponse(jump_gate:))
}
pub fn get_jump_gate(
token: AgentToken,
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
) -> ApiResponse(GetJumpGateResponse) {
let request =
request_utils.get(
AgentAuth(token),
"/systems/"
<> system_symbol
<> "/waypoints/"
<> waypoint_symbol
<> "/jump-gate",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(
response.body,
get_jump_gate_response_decoder(),
)
_ -> response_utils.error_parser(response.body)
}
}
pub type GetShipyardResponse {
GetShipyardResponse(shipyard: Shipyard)
}
fn get_shipyard_response_decoder() -> Decoder(GetShipyardResponse) {
use shipyard <- decode.then(shipyard.decoder())
decode.success(GetShipyardResponse(shipyard:))
}
pub fn get_shipyard(token, system_symbol, waypoint_symbol) {
let request =
request_utils.get(
AgentAuth(token),
"/systems/"
<> system_symbol
<> "/waypoints/"
<> waypoint_symbol
<> "/shipyard",
)
use response <- request_utils.try_send(request)
case response.status {
200 ->
response_utils.data_parser(response.body, get_shipyard_response_decoder())
_ -> response_utils.error_parser(response.body)
}
}

20
src/models/account.gleam Normal file
View file

@ -0,0 +1,20 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import utils/decode as decode_utils
pub type Account {
Account(
id: String,
email: Option(String),
token: Option(String),
created_at: String,
)
}
pub fn decoder() -> Decoder(Account) {
use id <- decode.field("id", decode.string)
use email <- decode_utils.field_value_optional("email", decode.string)
use token <- decode_utils.field_key_value_optional("token", decode.string)
use created_at <- decode.field("createdAt", decode.string)
decode.success(Account(id:, email:, token:, created_at:))
}

View file

@ -0,0 +1,32 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ActivityLevel {
Weak
Growing
Strong
Restricted
}
pub fn to_string(activity_level: ActivityLevel) -> String {
case activity_level {
Weak -> "WEAK"
Growing -> "GROWING"
Strong -> "STRONG"
Restricted -> "RESTRICTED"
}
}
pub fn parse(activity_level_str: String) -> Result(ActivityLevel, ActivityLevel) {
case activity_level_str {
"WEAK" -> Ok(Weak)
"GROWING" -> Ok(Growing)
"STRONG" -> Ok(Strong)
"RESTRICTED" -> Ok(Restricted)
_ -> Error(Weak)
}
}
pub fn decoder() -> Decoder(ActivityLevel) {
decode_utils.enum_decoder(parse, "ActivityLevel")
}

30
src/models/agent.gleam Normal file
View file

@ -0,0 +1,30 @@
import gleam/dynamic/decode.{type Decoder}
import models/agent_symbol.{type AgentSymbol}
pub type Agent {
Agent(
account_id: String,
symbol: AgentSymbol,
headquarters: String,
credits: Int,
starting_faction: String,
ship_count: Int,
)
}
pub fn decoder() -> Decoder(Agent) {
use account_id <- decode.field("accountId", decode.string)
use symbol <- decode.field("symbol", agent_symbol.decoder())
use headquarters <- decode.field("headquarters", decode.string)
use credits <- decode.field("credits", decode.int)
use starting_faction <- decode.field("startingFaction", decode.string)
use ship_count <- decode.field("shipCount", decode.int)
decode.success(Agent(
account_id:,
symbol:,
headquarters:,
credits:,
starting_faction:,
ship_count:,
))
}

View file

@ -0,0 +1,23 @@
import gleam/dynamic.{type Dynamic}
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import utils/decode as decode_utils
pub type AgentEvent {
AgentEvent(
id: String,
type_: String,
message: String,
data: Option(Dynamic),
created_at: String,
)
}
pub fn decoder() -> Decoder(AgentEvent) {
use id <- decode.field("id", decode.string)
use type_ <- decode.field("type", decode.string)
use message <- decode.field("message", decode.string)
use data <- decode_utils.field_key_value_optional("data", decode.dynamic)
use created_at <- decode.field("createdAt", decode.string)
decode.success(AgentEvent(id:, type_:, message:, data:, created_at:))
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type AgentSymbol =
String
pub fn decoder() -> Decoder(AgentSymbol) {
decode.string
}

21
src/models/chart.gleam Normal file
View file

@ -0,0 +1,21 @@
import gleam/dynamic/decode.{type Decoder}
import models/agent_symbol.{type AgentSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type Chart {
Chart(
waypoint_symbol: WaypointSymbol,
submitted_by: AgentSymbol,
submitted_on: String,
)
}
pub fn decoder() -> Decoder(Chart) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use submitted_by <- decode.field("submittedBy", agent_symbol.decoder())
use submitted_on <- decode.field("submittedOn", decode.string)
decode.success(Chart(waypoint_symbol:, submitted_by:, submitted_on:))
}

View file

@ -0,0 +1,28 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type ChartTransaction {
ChartTransaction(
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
total_price: Int,
timestamp: String,
)
}
pub fn decoder() -> Decoder(ChartTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use total_price <- decode.field("totalPrice", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(ChartTransaction(
waypoint_symbol:,
ship_symbol:,
total_price:,
timestamp:,
))
}

View file

@ -0,0 +1,20 @@
import gleam/dynamic/decode.{type Decoder}
import models/construction_material.{type ConstructionMaterial}
pub type Construction {
Construction(
symbol: String,
materials: List(ConstructionMaterial),
is_complete: Bool,
)
}
pub fn decoder() -> Decoder(Construction) {
use symbol <- decode.field("symbol", decode.string)
use materials <- decode.field(
"materials",
decode.list(construction_material.decoder()),
)
use is_complete <- decode.field("isComplete", decode.bool)
decode.success(Construction(symbol:, materials:, is_complete:))
}

View file

@ -0,0 +1,13 @@
import gleam/dynamic/decode.{type Decoder}
import models/trade_symbol.{type TradeSymbol}
pub type ConstructionMaterial {
ConstructionMaterial(trade_symbol: TradeSymbol, required: Int, fulfilled: Int)
}
pub fn decoder() -> Decoder(ConstructionMaterial) {
use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder())
use required <- decode.field("required", decode.int)
use fulfilled <- decode.field("fulfilled", decode.int)
decode.success(ConstructionMaterial(trade_symbol:, required:, fulfilled:))
}

38
src/models/contract.gleam Normal file
View file

@ -0,0 +1,38 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/contract_terms.{type ContractTerms}
import utils/decode as decode_utils
pub type Contract {
Contract(
id: String,
faction_symbol: String,
type_: String,
terms: ContractTerms,
accepted: Bool,
fulfilled: Bool,
deadline_to_accept: Option(String),
)
}
pub fn decoder() -> Decoder(Contract) {
use id <- decode.field("id", decode.string)
use faction_symbol <- decode.field("factionSymbol", decode.string)
use type_ <- decode.field("type", decode.string)
use terms <- decode.field("terms", contract_terms.decoder())
use accepted <- decode.field("accepted", decode.bool)
use fulfilled <- decode.field("fulfilled", decode.bool)
use deadline_to_accept <- decode_utils.field_key_value_optional(
"deadlineToAccept",
decode.string,
)
decode.success(Contract(
id:,
faction_symbol:,
type_:,
terms:,
accepted:,
fulfilled:,
deadline_to_accept:,
))
}

View file

@ -0,0 +1,23 @@
import gleam/dynamic/decode.{type Decoder}
pub type ContractDeliverGood {
ContractDeliverGood(
trade_symbol: String,
destination_symbol: String,
units_required: Int,
units_fulfilled: Int,
)
}
pub fn decoder() -> Decoder(ContractDeliverGood) {
use trade_symbol <- decode.field("tradeSymbol", decode.string)
use destination_symbol <- decode.field("destinationSymbol", decode.string)
use units_required <- decode.field("unitsRequired", decode.int)
use units_fulfilled <- decode.field("unitsFulfilled", decode.int)
decode.success(ContractDeliverGood(
trade_symbol:,
destination_symbol:,
units_required:,
units_fulfilled:,
))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
pub type ContractPayment {
ContractPayment(on_accepted: Int, on_fulfilled: Int)
}
pub fn decoder() -> Decoder(ContractPayment) {
use on_accepted <- decode.field("onAccepted", decode.int)
use on_fulfilled <- decode.field("onFulfilled", decode.int)
decode.success(ContractPayment(on_accepted:, on_fulfilled:))
}

View file

@ -0,0 +1,23 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/contract_deliver_good.{type ContractDeliverGood}
import models/contract_payment.{type ContractPayment}
import utils/decode as decode_utils
pub type ContractTerms {
ContractTerms(
deadline: String,
payment: ContractPayment,
deliver: Option(List(ContractDeliverGood)),
)
}
pub fn decoder() -> Decoder(ContractTerms) {
use deadline <- decode.field("deadline", decode.string)
use payment <- decode.field("payment", contract_payment.decoder())
use deliver <- decode_utils.field_key_value_optional(
"deliver",
decode.list(contract_deliver_good.decoder()),
)
decode.success(ContractTerms(deadline:, payment:, deliver:))
}

29
src/models/cooldown.gleam Normal file
View file

@ -0,0 +1,29 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/ship_symbol.{type ShipSymbol}
import utils/decode as decode_utils
pub type Cooldown {
Cooldown(
ship_symbol: ShipSymbol,
total_seconds: Int,
remaining_seconds: Int,
expiration: Option(String),
)
}
pub fn decoder() -> Decoder(Cooldown) {
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use total_seconds <- decode.field("totalSeconds", decode.int)
use remaining_seconds <- decode.field("remainingSeconds", decode.int)
use expiration <- decode_utils.field_key_value_optional(
"expiration",
decode.string,
)
decode.success(Cooldown(
ship_symbol:,
total_seconds:,
remaining_seconds:,
expiration:,
))
}

View file

@ -0,0 +1,26 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type CrewRotation {
Strict
Relaxed
}
pub fn to_string(crew_rotation: CrewRotation) -> String {
case crew_rotation {
Strict -> "STRICT"
Relaxed -> "RELAXED"
}
}
pub fn parse(crew_rotation_str: String) -> Result(CrewRotation, CrewRotation) {
case crew_rotation_str {
"STRICT" -> Ok(Strict)
"RELAXED" -> Ok(Relaxed)
_ -> Error(Strict)
}
}
pub fn decoder() -> Decoder(CrewRotation) {
decode_utils.enum_decoder(parse, "CrewRotation")
}

View file

@ -0,0 +1,32 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type EngineSymbol {
EngineImpulseDriveI
EngineIonDriveI
EngineIonDriveII
EngineHyperDriveI
}
pub fn to_string(engine_symbol: EngineSymbol) -> String {
case engine_symbol {
EngineImpulseDriveI -> "ENGINE_IMPULSE_DRIVE_I"
EngineIonDriveI -> "ENGINE_ION_DRIVE_I"
EngineIonDriveII -> "ENGINE_ION_DRIVE_II"
EngineHyperDriveI -> "ENGINE_HYPER_DRIVE_I"
}
}
pub fn parse(engine_symbol_str: String) -> Result(EngineSymbol, EngineSymbol) {
case engine_symbol_str {
"ENGINE_IMPULSE_DRIVE_I" -> Ok(EngineImpulseDriveI)
"ENGINE_ION_DRIVE_I" -> Ok(EngineIonDriveI)
"ENGINE_ION_DRIVE_II" -> Ok(EngineIonDriveII)
"ENGINE_HYPER_DRIVE_I" -> Ok(EngineHyperDriveI)
_ -> Error(EngineImpulseDriveI)
}
}
pub fn decoder() -> Decoder(EngineSymbol) {
decode_utils.enum_decoder(parse, "EngineSymbol")
}

View file

@ -0,0 +1,13 @@
import gleam/dynamic/decode.{type Decoder}
import models/extraction_yield.{type ExtractionYield}
import models/ship_symbol.{type ShipSymbol}
pub type Extraction {
Extraction(ship_symbol: ShipSymbol, yield: ExtractionYield)
}
pub fn decoder() -> Decoder(Extraction) {
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use yield <- decode.field("yield", extraction_yield.decoder())
decode.success(Extraction(ship_symbol:, yield:))
}

View file

@ -0,0 +1,12 @@
import gleam/dynamic/decode.{type Decoder}
import models/trade_symbol.{type TradeSymbol}
pub type ExtractionYield {
ExtractionYield(symbol: TradeSymbol, units: Int)
}
pub fn decoder() -> Decoder(ExtractionYield) {
use symbol <- decode.field("symbol", trade_symbol.decoder())
use units <- decode.field("units", decode.int)
decode.success(ExtractionYield(symbol:, units:))
}

36
src/models/faction.gleam Normal file
View file

@ -0,0 +1,36 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/faction_symbol.{type FactionSymbol}
import models/faction_trait.{type FactionTrait}
import utils/decode as decode_utils
pub type Faction {
Faction(
symbol: FactionSymbol,
name: String,
description: String,
headquarters: Option(String),
traits: List(FactionTrait),
is_recruiting: Bool,
)
}
pub fn decoder() -> Decoder(Faction) {
use symbol <- decode.field("symbol", faction_symbol.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
use headquarters <- decode_utils.field_key_value_optional(
"headquarters",
decode.string,
)
use traits <- decode.field("traits", decode.list(faction_trait.decoder()))
use is_recruiting <- decode.field("isRecruiting", decode.bool)
decode.success(Faction(
symbol:,
name:,
description:,
headquarters:,
traits:,
is_recruiting:,
))
}

View file

@ -0,0 +1,77 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type FactionSymbol {
Cosmic
Void
Galactic
Quantum
Dominion
Astro
Corsairs
Obsidian
Aegis
United
Solitary
Cobalt
Omega
Echo
Lord
Cult
Ancients
Shadow
Ethereal
}
pub fn to_string(symbol: FactionSymbol) -> String {
case symbol {
Cosmic -> "COSMIC"
Void -> "VOID"
Galactic -> "GALACTIC"
Quantum -> "QUANTUM"
Dominion -> "DOMINION"
Astro -> "ASTRO"
Corsairs -> "CORSAIRS"
Obsidian -> "OBSIDIAN"
Aegis -> "AEGIS"
United -> "UNITED"
Solitary -> "SOLITARY"
Cobalt -> "COBALT"
Omega -> "OMEGA"
Echo -> "ECHO"
Lord -> "LORDS"
Cult -> "CULT"
Ancients -> "ANCIENTS"
Shadow -> "SHADOW"
Ethereal -> "ETHEREAL"
}
}
pub fn parse(symbol_str: String) -> Result(FactionSymbol, FactionSymbol) {
case symbol_str {
"COSMIC" -> Ok(Cosmic)
"VOID" -> Ok(Void)
"GALACTIC" -> Ok(Galactic)
"QUANTUM" -> Ok(Quantum)
"DOMINION" -> Ok(Dominion)
"ASTRO" -> Ok(Astro)
"CORSAIRS" -> Ok(Corsairs)
"OBSIDIAN" -> Ok(Obsidian)
"AEGIS" -> Ok(Aegis)
"UNITED" -> Ok(United)
"SOLITARY" -> Ok(Solitary)
"COBALT" -> Ok(Cobalt)
"OMEGA" -> Ok(Omega)
"ECHO" -> Ok(Echo)
"LORDS" -> Ok(Lord)
"CULT" -> Ok(Cult)
"ANCIENTS" -> Ok(Ancients)
"SHADOW" -> Ok(Shadow)
"ETHEREAL" -> Ok(Ethereal)
_ -> Error(Cosmic)
}
}
pub fn decoder() -> Decoder(FactionSymbol) {
decode_utils.enum_decoder(parse, "FactionSymbol")
}

View file

@ -0,0 +1,13 @@
import gleam/dynamic/decode.{type Decoder}
import models/faction_trait_symbol.{type FactionTraitSymbol}
pub type FactionTrait {
FactionTrait(symbol: FactionTraitSymbol, name: String, description: String)
}
pub fn decoder() -> Decoder(FactionTrait) {
use symbol <- decode.field("symbol", faction_trait_symbol.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
decode.success(FactionTrait(symbol:, name:, description:))
}

View file

@ -0,0 +1,199 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type FactionTraitSymbol {
Bureaucratic
Secretive
Capitalistic
Industrious
Peaceful
Distrustful
Welcoming
Smugglers
Scavengers
Rebellious
Exiles
Pirates
Raiders
Clan
Guild
Dominion
Fringe
Forsaken
Isolated
Localized
Established
Notable
Dominant
Inescapable
Innovative
Bold
Visionary
Curious
Daring
Exploratory
Resourceful
Flexible
Cooperative
United
Strategic
Intelligent
ResearchFocused
Collaborative
Progressive
Militaristic
TechnologicallyAdvanced
Aggressive
Imperialistic
TreasureHunters
Dexterous
Unpredictable
Brutal
Fleeting
Adaptable
SelfSufficient
Defensive
Proud
Diverse
Independent
SelfInterested
Fragmented
Commercial
FreeMarkets
Entrepreneurial
}
pub fn to_string(trait_symbol: FactionTraitSymbol) -> String {
case trait_symbol {
Bureaucratic -> "BUREAUCRATIC"
Secretive -> "SECRETIVE"
Capitalistic -> "CAPITALISTIC"
Industrious -> "INDUSTRIOUS"
Peaceful -> "PEACEFUL"
Distrustful -> "DISTRUSTFUL"
Welcoming -> "WELCOMING"
Smugglers -> "SMUGGLERS"
Scavengers -> "SCAVENGERS"
Rebellious -> "REBELLIOUS"
Exiles -> "EXILES"
Pirates -> "PIRATES"
Raiders -> "RAIDERS"
Clan -> "CLAN"
Guild -> "GUILD"
Dominion -> "DOMINION"
Fringe -> "FRINGE"
Forsaken -> "FORSAKEN"
Isolated -> "ISOLATED"
Localized -> "LOCALIZED"
Established -> "ESTABLISHED"
Notable -> "NOTABLE"
Dominant -> "DOMINANT"
Inescapable -> "INESCAPABLE"
Innovative -> "INNOVATIVE"
Bold -> "BOLD"
Visionary -> "VISIONARY"
Curious -> "CURIOUS"
Daring -> "DARING"
Exploratory -> "EXPLORATORY"
Resourceful -> "RESOURCEFUL"
Flexible -> "FLEXIBLE"
Cooperative -> "COOPERATIVE"
United -> "UNITED"
Strategic -> "STRATEGIC"
Intelligent -> "INTELLIGENT"
ResearchFocused -> "RESEARCH_FOCUSED"
Collaborative -> "COLLABORATIVE"
Progressive -> "PROGRESSIVE"
Militaristic -> "MILITARISTIC"
TechnologicallyAdvanced -> "TECHNOLOGICALLY_ADVANCED"
Aggressive -> "AGGRESSIVE"
Imperialistic -> "IMPERIALISTIC"
TreasureHunters -> "TREASURE_HUNTERS"
Dexterous -> "DEXTEROUS"
Unpredictable -> "UNPREDICTABLE"
Brutal -> "BRUTAL"
Fleeting -> "FLEETING"
Adaptable -> "ADAPTABLE"
SelfSufficient -> "SELF_SUFFICIENT"
Defensive -> "DEFENSIVE"
Proud -> "PROUD"
Diverse -> "DIVERSE"
Independent -> "INDEPENDENT"
SelfInterested -> "SELF_INTERESTED"
Fragmented -> "FRAGMENTED"
Commercial -> "COMMERCIAL"
FreeMarkets -> "FREE_MARKETS"
Entrepreneurial -> "ENTREPRENEURIAL"
}
}
pub fn parse(
trait_symbol_str: String,
) -> Result(FactionTraitSymbol, FactionTraitSymbol) {
case trait_symbol_str {
"BUREAUCRATIC" -> Ok(Bureaucratic)
"SECRETIVE" -> Ok(Secretive)
"CAPITALISTIC" -> Ok(Capitalistic)
"INDUSTRIOUS" -> Ok(Industrious)
"PEACEFUL" -> Ok(Peaceful)
"DISTRUSTFUL" -> Ok(Distrustful)
"WELCOMING" -> Ok(Welcoming)
"SMUGGLERS" -> Ok(Smugglers)
"SCAVENGERS" -> Ok(Scavengers)
"REBELLIOUS" -> Ok(Rebellious)
"EXILES" -> Ok(Exiles)
"PIRATES" -> Ok(Pirates)
"RAIDERS" -> Ok(Raiders)
"CLAN" -> Ok(Clan)
"GUILD" -> Ok(Guild)
"DOMINION" -> Ok(Dominion)
"FRINGE" -> Ok(Fringe)
"FORSAKEN" -> Ok(Forsaken)
"ISOLATED" -> Ok(Isolated)
"LOCALIZED" -> Ok(Localized)
"ESTABLISHED" -> Ok(Established)
"NOTABLE" -> Ok(Notable)
"DOMINANT" -> Ok(Dominant)
"INESCAPABLE" -> Ok(Inescapable)
"INNOVATIVE" -> Ok(Innovative)
"BOLD" -> Ok(Bold)
"VISIONARY" -> Ok(Visionary)
"CURIOUS" -> Ok(Curious)
"DARING" -> Ok(Daring)
"EXPLORATORY" -> Ok(Exploratory)
"RESOURCEFUL" -> Ok(Resourceful)
"FLEXIBLE" -> Ok(Flexible)
"COOPERATIVE" -> Ok(Cooperative)
"UNITED" -> Ok(United)
"STRATEGIC" -> Ok(Strategic)
"INTELLIGENT" -> Ok(Intelligent)
"RESEARCH_FOCUSED" -> Ok(ResearchFocused)
"COLLABORATIVE" -> Ok(Collaborative)
"PROGRESSIVE" -> Ok(Progressive)
"MILITARISTIC" -> Ok(Militaristic)
"TECHNOLOGICALLY_ADVANCED" -> Ok(TechnologicallyAdvanced)
"AGGRESSIVE" -> Ok(Aggressive)
"IMPERIALISTIC" -> Ok(Imperialistic)
"TREASURE_HUNTERS" -> Ok(TreasureHunters)
"DEXTEROUS" -> Ok(Dexterous)
"UNPREDICTABLE" -> Ok(Unpredictable)
"BRUTAL" -> Ok(Brutal)
"FLEETING" -> Ok(Fleeting)
"ADAPTABLE" -> Ok(Adaptable)
"SELF_SUFFICIENT" -> Ok(SelfSufficient)
"DEFENSIVE" -> Ok(Defensive)
"PROUD" -> Ok(Proud)
"DIVERSE" -> Ok(Diverse)
"INDEPENDENT" -> Ok(Independent)
"SELF_INTERESTED" -> Ok(SelfInterested)
"FRAGMENTED" -> Ok(Fragmented)
"COMMERCIAL" -> Ok(Commercial)
"FREE_MARKETS" -> Ok(FreeMarkets)
"ENTREPRENEURIAL" -> Ok(Entrepreneurial)
_ -> Error(Bureaucratic)
}
}
pub fn decoder() -> Decoder(FactionTraitSymbol) {
decode_utils.enum_decoder(parse, "FactionTraitSymbol")
}

View file

@ -0,0 +1,68 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type FrameSymbol {
FrameProbe
FrameDrone
FrameInterceptor
FrameRacer
FrameFighter
FrameFrigate
FrameShuttle
FrameExplorer
FrameMiner
FrameLightFreighter
FrameHeavyFreighter
FrameTransport
FrameDestroyer
FrameCruiser
FrameCarrier
FrameBulkFreighter
}
pub fn to_string(frame_symbol: FrameSymbol) -> String {
case frame_symbol {
FrameProbe -> "FRAME_PROBE"
FrameDrone -> "FRAME_DRONE"
FrameInterceptor -> "FRAME_INTERCEPTOR"
FrameRacer -> "FRAME_RACER"
FrameFighter -> "FRAME_FIGHTER"
FrameFrigate -> "FRAME_FRIGATE"
FrameShuttle -> "FRAME_SHUTTLE"
FrameExplorer -> "FRAME_EXPLORER"
FrameMiner -> "FRAME_MINER"
FrameLightFreighter -> "FRAME_LIGHT_FREIGHTER"
FrameHeavyFreighter -> "FRAME_HEAVY_FREIGHTER"
FrameTransport -> "FRAME_TRANSPORT"
FrameDestroyer -> "FRAME_DESTROYER"
FrameCruiser -> "FRAME_CRUISER"
FrameCarrier -> "FRAME_CARRIER"
FrameBulkFreighter -> "FRAME_BULK_FREIGHTER"
}
}
pub fn parse(frame_symbol_str: String) -> Result(FrameSymbol, FrameSymbol) {
case frame_symbol_str {
"FRAME_PROBE" -> Ok(FrameProbe)
"FRAME_DRONE" -> Ok(FrameDrone)
"FRAME_INTERCEPTOR" -> Ok(FrameInterceptor)
"FRAME_RACER" -> Ok(FrameRacer)
"FRAME_FIGHTER" -> Ok(FrameFighter)
"FRAME_FRIGATE" -> Ok(FrameFrigate)
"FRAME_SHUTTLE" -> Ok(FrameShuttle)
"FRAME_EXPLORER" -> Ok(FrameExplorer)
"FRAME_MINER" -> Ok(FrameMiner)
"FRAME_LIGHT_FREIGHTER" -> Ok(FrameLightFreighter)
"FRAME_HEAVY_FREIGHTER" -> Ok(FrameHeavyFreighter)
"FRAME_TRANSPORT" -> Ok(FrameTransport)
"FRAME_DESTROYER" -> Ok(FrameDestroyer)
"FRAME_CRUISER" -> Ok(FrameCruiser)
"FRAME_CARRIER" -> Ok(FrameCarrier)
"FRAME_BULK_FREIGHTER" -> Ok(FrameBulkFreighter)
_ -> Error(FrameProbe)
}
}
pub fn decoder() -> Decoder(FrameSymbol) {
decode_utils.enum_decoder(parse, "FrameSymbol")
}

View file

@ -0,0 +1,12 @@
import gleam/dynamic/decode.{type Decoder}
import models/waypoint_symbol.{type WaypointSymbol}
pub type JumpGate {
JumpGate(symbol: WaypointSymbol, connections: List(String))
}
pub fn decoder() -> Decoder(JumpGate) {
use symbol <- decode.field("symbol", waypoint_symbol.decoder())
use connections <- decode.field("connections", decode.list(decode.string))
decode.success(JumpGate(symbol:, connections:))
}

41
src/models/market.gleam Normal file
View file

@ -0,0 +1,41 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/market_symbol.{type MarketSymbol}
import models/market_trade_good.{type MarketTradeGood}
import models/market_transaction.{type MarketTransaction}
import models/trade_good.{type TradeGood}
import utils/decode as decode_utils
pub type Market {
Market(
symbol: MarketSymbol,
exports: List(TradeGood),
imports: List(TradeGood),
exchange: List(TradeGood),
transactions: Option(List(MarketTransaction)),
trade_goods: Option(List(MarketTradeGood)),
)
}
pub fn decoder() -> Decoder(Market) {
use symbol <- decode.field("symbol", decode.string)
use exports <- decode.field("exports", decode.list(trade_good.decoder()))
use imports <- decode.field("imports", decode.list(trade_good.decoder()))
use exchange <- decode.field("exchange", decode.list(trade_good.decoder()))
use transactions <- decode_utils.field_key_value_optional(
"transactions",
decode.list(market_transaction.decoder()),
)
use trade_goods <- decode_utils.field_key_value_optional(
"tradeGoods",
decode.list(market_trade_good.decoder()),
)
decode.success(Market(
symbol:,
exports:,
imports:,
exchange:,
transactions:,
trade_goods:,
))
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type MarketSymbol =
String
pub fn decoder() -> Decoder(MarketSymbol) {
decode.string
}

View file

@ -0,0 +1,41 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/activity_level.{type ActivityLevel}
import models/supply_level.{type SupplyLevel}
import models/trade_good_type.{type TradeGoodType}
import models/trade_symbol.{type TradeSymbol}
import utils/decode as decode_utils
pub type MarketTradeGood {
MarketTradeGood(
symbol: TradeSymbol,
type_: TradeGoodType,
trade_volume: Int,
supply: SupplyLevel,
activity: Option(ActivityLevel),
purchase_price: Int,
sell_price: Int,
)
}
pub fn decoder() -> Decoder(MarketTradeGood) {
use symbol <- decode.field("symbol", trade_symbol.decoder())
use type_ <- decode.field("type", trade_good_type.decoder())
use trade_volume <- decode.field("tradeVolume", decode.int)
use supply <- decode.field("supply", supply_level.decoder())
use activity <- decode_utils.field_key_value_optional(
"activity",
activity_level.decoder(),
)
use purchase_price <- decode.field("purchasePrice", decode.int)
use sell_price <- decode.field("sellPrice", decode.int)
decode.success(MarketTradeGood(
symbol:,
type_:,
trade_volume:,
supply:,
activity:,
purchase_price:,
sell_price:,
))
}

View file

@ -0,0 +1,42 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/trade_symbol.{type TradeSymbol}
import models/transaction_type.{type TransactionType}
import models/waypoint_symbol.{type WaypointSymbol}
pub type MarketTransaction {
MarketTransaction(
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
trade_symbol: TradeSymbol,
type_: TransactionType,
units: Int,
price_per_unit: Int,
total_price: Int,
timestamp: String,
)
}
pub fn decoder() -> Decoder(MarketTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_symbol <- decode.field("shipSymbol", decode.string)
use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder())
use type_ <- decode.field("type", transaction_type.decoder())
use units <- decode.field("units", decode.int)
use price_per_unit <- decode.field("pricePerUnit", decode.int)
use total_price <- decode.field("totalPrice", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(MarketTransaction(
waypoint_symbol:,
ship_symbol:,
trade_symbol:,
type_:,
units:,
price_per_unit:,
total_price:,
timestamp:,
))
}

12
src/models/meta.gleam Normal file
View file

@ -0,0 +1,12 @@
import gleam/dynamic/decode.{type Decoder}
pub type Meta {
Meta(limit: Int, page: Int, total: Int)
}
pub fn decoder() -> Decoder(Meta) {
use limit <- decode.field("limit", decode.int)
use page <- decode.field("page", decode.int)
use total <- decode.field("total", decode.int)
decode.success(Meta(limit: limit, page: page, total: total))
}

View file

@ -0,0 +1,80 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ModuleSymbol {
ModuleMineralProcessorI
ModuleGasProcessorI
ModuleCargoHoldI
ModuleCargoHoldII
ModuleCargoHoldIII
ModuleCrewQuartersI
ModuleEnvoyQuartersI
ModulePassengerCabinI
ModuleMicroRefineryI
ModuleOreRefineryI
ModuleFuelRefineryI
ModuleScienceLabI
ModuleJumpDriveI
ModuleJumpDriveII
ModuleJumpDriveIII
ModuleWarpDriveI
ModuleWarpDriveII
ModuleWarpDriveIII
ModuleShieldGeneratorI
ModuleShieldGeneratorII
}
pub fn to_string(module_symbol: ModuleSymbol) -> String {
case module_symbol {
ModuleMineralProcessorI -> "MODULE_MINERAL_PROCESSOR_I"
ModuleGasProcessorI -> "MODULE_GAS_PROCESSOR_I"
ModuleCargoHoldI -> "MODULE_CARGO_HOLD_I"
ModuleCargoHoldII -> "MODULE_CARGO_HOLD_II"
ModuleCargoHoldIII -> "MODULE_CARGO_HOLD_III"
ModuleCrewQuartersI -> "MODULE_CREW_QUARTERS_I"
ModuleEnvoyQuartersI -> "MODULE_ENVOY_QUARTERS_I"
ModulePassengerCabinI -> "MODULE_PASSENGER_CABIN_I"
ModuleMicroRefineryI -> "MODULE_MICRO_REFINERY_I"
ModuleOreRefineryI -> "MODULE_ORE_REFINERY_I"
ModuleFuelRefineryI -> "MODULE_FUEL_REFINERY_I"
ModuleScienceLabI -> "MODULE_SCIENCE_LAB_I"
ModuleJumpDriveI -> "MODULE_JUMP_DRIVE_I"
ModuleJumpDriveII -> "MODULE_JUMP_DRIVE_II"
ModuleJumpDriveIII -> "MODULE_JUMP_DRIVE_III"
ModuleWarpDriveI -> "MODULE_WARP_DRIVE_I"
ModuleWarpDriveII -> "MODULE_WARP_DRIVE_II"
ModuleWarpDriveIII -> "MODULE_WARP_DRIVE_III"
ModuleShieldGeneratorI -> "MODULE_SHIELD_GENERATOR_I"
ModuleShieldGeneratorII -> "MODULE_SHIELD_GENERATOR_II"
}
}
pub fn parse(module_symbol_str: String) -> Result(ModuleSymbol, ModuleSymbol) {
case module_symbol_str {
"MODULE_MINERAL_PROCESSOR_I" -> Ok(ModuleMineralProcessorI)
"MODULE_GAS_PROCESSOR_I" -> Ok(ModuleGasProcessorI)
"MODULE_CARGO_HOLD_I" -> Ok(ModuleCargoHoldI)
"MODULE_CARGO_HOLD_II" -> Ok(ModuleCargoHoldII)
"MODULE_CARGO_HOLD_III" -> Ok(ModuleCargoHoldIII)
"MODULE_CREW_QUARTERS_I" -> Ok(ModuleCrewQuartersI)
"MODULE_ENVOY_QUARTERS_I" -> Ok(ModuleEnvoyQuartersI)
"MODULE_PASSENGER_CABIN_I" -> Ok(ModulePassengerCabinI)
"MODULE_MICRO_REFINERY_I" -> Ok(ModuleMicroRefineryI)
"MODULE_ORE_REFINERY_I" -> Ok(ModuleOreRefineryI)
"MODULE_FUEL_REFINERY_I" -> Ok(ModuleFuelRefineryI)
"MODULE_SCIENCE_LAB_I" -> Ok(ModuleScienceLabI)
"MODULE_JUMP_DRIVE_I" -> Ok(ModuleJumpDriveI)
"MODULE_JUMP_DRIVE_II" -> Ok(ModuleJumpDriveII)
"MODULE_JUMP_DRIVE_III" -> Ok(ModuleJumpDriveIII)
"MODULE_WARP_DRIVE_I" -> Ok(ModuleWarpDriveI)
"MODULE_WARP_DRIVE_II" -> Ok(ModuleWarpDriveII)
"MODULE_WARP_DRIVE_III" -> Ok(ModuleWarpDriveIII)
"MODULE_SHIELD_GENERATOR_I" -> Ok(ModuleShieldGeneratorI)
"MODULE_SHIELD_GENERATOR_II" -> Ok(ModuleShieldGeneratorII)
_ -> Error(ModuleMineralProcessorI)
}
}
pub fn decoder() -> Decoder(ModuleSymbol) {
decode_utils.enum_decoder(parse, "ModuleSymbol")
}

View file

@ -0,0 +1,62 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type MountDeposit {
QuartzSand
SiliconCrystals
PreciousStones
IceWater
AmmoniaIce
IronOre
CopperOre
SilverOre
AluminumOre
GoldOre
PlatinumOre
Diamonds
UraniteOre
MeritiumOre
}
pub fn to_string(mount_deposit: MountDeposit) -> String {
case mount_deposit {
QuartzSand -> "QUARTZ_SAND"
SiliconCrystals -> "SILICON_CRYSTALS"
PreciousStones -> "PRECIOUS_STONES"
IceWater -> "ICE_WATER"
AmmoniaIce -> "AMMONIA_ICE"
IronOre -> "IRON_ORE"
CopperOre -> "COPPER_ORE"
SilverOre -> "SILVER_ORE"
AluminumOre -> "ALUMINUM_ORE"
GoldOre -> "GOLD_ORE"
PlatinumOre -> "PLATINUM_ORE"
Diamonds -> "DIAMONDS"
UraniteOre -> "URANITE_ORE"
MeritiumOre -> "MERITIUM_ORE"
}
}
pub fn parse(mount_deposit_str: String) -> Result(MountDeposit, MountDeposit) {
case mount_deposit_str {
"QUARTZ_SAND" -> Ok(QuartzSand)
"SILICON_CRYSTALS" -> Ok(SiliconCrystals)
"PRECIOUS_STONES" -> Ok(PreciousStones)
"ICE_WATER" -> Ok(IceWater)
"AMMONIA_ICE" -> Ok(AmmoniaIce)
"IRON_ORE" -> Ok(IronOre)
"COPPER_ORE" -> Ok(CopperOre)
"SILVER_ORE" -> Ok(SilverOre)
"ALUMINUM_ORE" -> Ok(AluminumOre)
"GOLD_ORE" -> Ok(GoldOre)
"PLATINUM_ORE" -> Ok(PlatinumOre)
"DIAMONDS" -> Ok(Diamonds)
"URANITE_ORE" -> Ok(UraniteOre)
"MERITIUM_ORE" -> Ok(MeritiumOre)
_ -> Error(QuartzSand)
}
}
pub fn decoder() -> Decoder(MountDeposit) {
decode_utils.enum_decoder(parse, "MountDeposit")
}

View file

@ -0,0 +1,65 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type MountSymbol {
MountGasSiphonI
MountGasSiphonII
MountGasSiphonIII
MountSurveyorI
MountSurveyorII
MountSurveyorIII
MountSensorArrayI
MountSensorArrayII
MountSensorArrayIII
MountMiningLaserI
MountMiningLaserII
MountMiningLaserIII
MountLaserCannonI
MountMissileLauncherI
MountTurretI
}
pub fn to_string(mount_symbol: MountSymbol) -> String {
case mount_symbol {
MountGasSiphonI -> "MOUNT_GAS_SIPHON_I"
MountGasSiphonII -> "MOUNT_GAS_SIPHON_II"
MountGasSiphonIII -> "MOUNT_GAS_SIPHON_III"
MountSurveyorI -> "MOUNT_SURVEYOR_I"
MountSurveyorII -> "MOUNT_SURVEYOR_II"
MountSurveyorIII -> "MOUNT_SURVEYOR_III"
MountSensorArrayI -> "MOUNT_SENSOR_ARRAY_I"
MountSensorArrayII -> "MOUNT_SENSOR_ARRAY_II"
MountSensorArrayIII -> "MOUNT_SENSOR_ARRAY_III"
MountMiningLaserI -> "MOUNT_MINING_LASER_I"
MountMiningLaserII -> "MOUNT_MINING_LASER_II"
MountMiningLaserIII -> "MOUNT_MINING_LASER_III"
MountLaserCannonI -> "MOUNT_LASER_CANNON_I"
MountMissileLauncherI -> "MOUNT_MISSILE_LAUNCHER_I"
MountTurretI -> "MOUNT_TURRET_I"
}
}
pub fn parse(mount_symbol_str: String) -> Result(MountSymbol, MountSymbol) {
case mount_symbol_str {
"MOUNT_GAS_SIPHON_I" -> Ok(MountGasSiphonI)
"MOUNT_GAS_SIPHON_II" -> Ok(MountGasSiphonII)
"MOUNT_GAS_SIPHON_III" -> Ok(MountGasSiphonIII)
"MOUNT_SURVEYOR_I" -> Ok(MountSurveyorI)
"MOUNT_SURVEYOR_II" -> Ok(MountSurveyorII)
"MOUNT_SURVEYOR_III" -> Ok(MountSurveyorIII)
"MOUNT_SENSOR_ARRAY_I" -> Ok(MountSensorArrayI)
"MOUNT_SENSOR_ARRAY_II" -> Ok(MountSensorArrayII)
"MOUNT_SENSOR_ARRAY_III" -> Ok(MountSensorArrayIII)
"MOUNT_MINING_LASER_I" -> Ok(MountMiningLaserI)
"MOUNT_MINING_LASER_II" -> Ok(MountMiningLaserII)
"MOUNT_MINING_LASER_III" -> Ok(MountMiningLaserIII)
"MOUNT_LASER_CANNON_I" -> Ok(MountLaserCannonI)
"MOUNT_MISSILE_LAUNCHER_I" -> Ok(MountMissileLauncherI)
"MOUNT_TURRET_I" -> Ok(MountTurretI)
_ -> Error(MountGasSiphonI)
}
}
pub fn decoder() -> Decoder(MountSymbol) {
decode_utils.enum_decoder(parse, "MountSymbol")
}

View file

@ -0,0 +1,26 @@
import gleam/dynamic/decode.{type Decoder}
pub type PublicAgent {
PublicAgent(
symbol: String,
headquarters: String,
credits: Int,
starting_faction: String,
ship_count: Int,
)
}
pub fn decoder() -> Decoder(PublicAgent) {
use symbol <- decode.field("symbol", decode.string)
use headquarters <- decode.field("headquarters", decode.string)
use credits <- decode.field("credits", decode.int)
use starting_faction <- decode.field("startingFaction", decode.string)
use ship_count <- decode.field("shipCount", decode.int)
decode.success(PublicAgent(
symbol:,
headquarters:,
credits:,
starting_faction:,
ship_count:,
))
}

View file

@ -0,0 +1,35 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ReactorSymbol {
ReactorSolarI
ReactorFusionI
ReactorFissionI
ReactorChemicalI
ReactorAntimatterI
}
pub fn to_string(reactor_symbol: ReactorSymbol) -> String {
case reactor_symbol {
ReactorSolarI -> "REACTOR_SOLAR_I"
ReactorFusionI -> "REACTOR_FUSION_I"
ReactorFissionI -> "REACTOR_FISSION_I"
ReactorChemicalI -> "REACTOR_CHEMICAL_I"
ReactorAntimatterI -> "REACTOR_ANTIMATTER_I"
}
}
pub fn parse(reactor_symbol_str: String) -> Result(ReactorSymbol, ReactorSymbol) {
case reactor_symbol_str {
"REACTOR_SOLAR_I" -> Ok(ReactorSolarI)
"REACTOR_FUSION_I" -> Ok(ReactorFusionI)
"REACTOR_FISSION_I" -> Ok(ReactorFissionI)
"REACTOR_CHEMICAL_I" -> Ok(ReactorChemicalI)
"REACTOR_ANTIMATTER_I" -> Ok(ReactorAntimatterI)
_ -> Error(ReactorSolarI)
}
}
pub fn decoder() -> Decoder(ReactorSymbol) {
decode_utils.enum_decoder(parse, "ReactorSymbol")
}

View file

@ -0,0 +1,49 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type RefinementProduce {
Iron
Copper
Silver
Gold
Aluminum
Platinum
Uranite
Meritium
Fuel
}
pub fn to_string(refinement_produce: RefinementProduce) -> String {
case refinement_produce {
Iron -> "IRON"
Copper -> "COPPER"
Silver -> "SILVER"
Gold -> "GOLD"
Aluminum -> "ALUMINUM"
Platinum -> "PLATINUM"
Uranite -> "URANITE"
Meritium -> "MERITIUM"
Fuel -> "FUEL"
}
}
pub fn parse(
refinement_produce_str: String,
) -> Result(RefinementProduce, RefinementProduce) {
case refinement_produce_str {
"IRON" -> Ok(Iron)
"COPPER" -> Ok(Copper)
"SILVER" -> Ok(Silver)
"GOLD" -> Ok(Gold)
"ALUMINUM" -> Ok(Aluminum)
"PLATINUM" -> Ok(Platinum)
"URANITE" -> Ok(Uranite)
"MERITIUM" -> Ok(Meritium)
"FUEL" -> Ok(Fuel)
_ -> Error(Iron)
}
}
pub fn decoder() -> Decoder(RefinementProduce) {
decode_utils.enum_decoder(parse, "RefinementProduce")
}

View file

@ -0,0 +1,12 @@
import gleam/dynamic/decode.{type Decoder}
import models/trade_symbol.{type TradeSymbol}
pub type RefinementYield {
RefinementYield(trade_symbol: TradeSymbol, units: Int)
}
pub fn decoder() -> Decoder(RefinementYield) {
use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder())
use units <- decode.field("units", decode.int)
decode.success(RefinementYield(trade_symbol:, units:))
}

View file

@ -0,0 +1,28 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type RepairTransaction {
RepairTransaction(
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
total_price: Int,
timestamp: String,
)
}
pub fn decoder() -> Decoder(RepairTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use total_price <- decode.field("totalPrice", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(RepairTransaction(
waypoint_symbol:,
ship_symbol:,
total_price:,
timestamp:,
))
}

View file

@ -0,0 +1,50 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/scanned_ship_engine.{type ScannedShipEngine}
import models/scanned_ship_frame.{type ScannedShipFrame}
import models/scanned_ship_mount.{type ScannedShipMount}
import models/scanned_ship_reactor.{type ScannedShipReactor}
import models/ship_nav.{type ShipNav}
import models/ship_registration.{type ShipRegistration}
import models/ship_symbol.{type ShipSymbol}
import utils/decode as decode_utils
pub type ScannedShip {
ScannedShip(
symbol: ShipSymbol,
registration: ShipRegistration,
nav: ShipNav,
frame: Option(ScannedShipFrame),
reactor: Option(ScannedShipReactor),
engine: ScannedShipEngine,
mounts: Option(List(ScannedShipMount)),
)
}
pub fn decoder() -> Decoder(ScannedShip) {
use symbol <- decode.field("symbol", decode.string)
use registration <- decode.field("registration", ship_registration.decoder())
use nav <- decode.field("nav", ship_nav.decoder())
use frame <- decode_utils.field_key_value_optional(
"frame",
scanned_ship_frame.decoder(),
)
use reactor <- decode_utils.field_key_value_optional(
"reactor",
scanned_ship_reactor.decoder(),
)
use engine <- decode.field("engine", scanned_ship_engine.decoder())
use mounts <- decode_utils.field_key_value_optional(
"mounts",
decode.list(scanned_ship_mount.decoder()),
)
decode.success(ScannedShip(
symbol:,
registration:,
nav:,
frame:,
reactor:,
engine:,
mounts:,
))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
import models/engine_symbol.{type EngineSymbol}
pub type ScannedShipEngine {
ScannedShipEngine(symbol: EngineSymbol)
}
pub fn decoder() -> Decoder(ScannedShipEngine) {
use symbol <- decode.field("symbol", engine_symbol.decoder())
decode.success(ScannedShipEngine(symbol:))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
import models/frame_symbol.{type FrameSymbol}
pub type ScannedShipFrame {
ScannedShipFrame(symbol: FrameSymbol)
}
pub fn decoder() -> Decoder(ScannedShipFrame) {
use symbol <- decode.field("symbol", frame_symbol.decoder())
decode.success(ScannedShipFrame(symbol:))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
import models/mount_symbol.{type MountSymbol}
pub type ScannedShipMount {
ScannedShipMount(symbol: MountSymbol)
}
pub fn decoder() -> Decoder(ScannedShipMount) {
use symbol <- decode.field("symbol", mount_symbol.decoder())
decode.success(ScannedShipMount(symbol:))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
import models/reactor_symbol.{type ReactorSymbol}
pub type ScannedShipReactor {
ScannedShipReactor(symbol: ReactorSymbol)
}
pub fn decoder() -> Decoder(ScannedShipReactor) {
use symbol <- decode.field("symbol", reactor_symbol.decoder())
decode.success(ScannedShipReactor(symbol:))
}

View file

@ -0,0 +1,31 @@
import gleam/dynamic/decode.{type Decoder}
import models/system_symbol.{type SystemSymbol}
import models/system_type.{type SystemType}
pub type ScannedSystem {
ScannedSystem(
symbol: SystemSymbol,
sector_symbol: String,
type_: SystemType,
x: Int,
y: Int,
distance: Int,
)
}
pub fn decoder() -> Decoder(ScannedSystem) {
use symbol <- decode.field("symbol", decode.string)
use sector_symbol <- decode.field("sectorSymbol", decode.string)
use type_ <- decode.field("type", system_type.decoder())
use x <- decode.field("x", decode.int)
use y <- decode.field("y", decode.int)
use distance <- decode.field("distance", decode.int)
decode.success(ScannedSystem(
symbol:,
sector_symbol:,
type_:,
x:,
y:,
distance:,
))
}

View file

@ -0,0 +1,57 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/chart.{type Chart}
import models/system_symbol.{type SystemSymbol}
import models/waypoint_faction.{type WaypointFaction}
import models/waypoint_orbital.{type WaypointOrbital}
import models/waypoint_symbol.{type WaypointSymbol}
import models/waypoint_trait.{type WaypointTrait}
import models/waypoint_type.{type WaypointType}
pub type ScannedWaypoint {
ScannedWaypoint(
symbol: WaypointSymbol,
type_: WaypointType,
system_symbol: SystemSymbol,
x: Int,
y: Int,
orbitals: List(WaypointOrbital),
faction: Option(WaypointFaction),
traits: List(WaypointTrait),
chart: Option(Chart),
)
}
pub fn decoder() -> Decoder(ScannedWaypoint) {
use symbol <- decode.field("symbol", waypoint_symbol.decoder())
use type_ <- decode.field("type", waypoint_type.decoder())
use system_symbol <- decode.field("systemSymbol", system_symbol.decoder())
use x <- decode.field("x", decode.int)
use y <- decode.field("y", decode.int)
use orbitals <- decode.field(
"orbitals",
decode.list(waypoint_orbital.decoder()),
)
use faction <- decode.optional_field(
"faction",
option.None,
decode.optional(waypoint_faction.decoder()),
)
use traits <- decode.field("traits", decode.list(waypoint_trait.decoder()))
use chart <- decode.optional_field(
"chart",
option.None,
decode.optional(chart.decoder()),
)
decode.success(ScannedWaypoint(
symbol:,
type_:,
system_symbol:,
x:,
y:,
orbitals:,
faction:,
traits:,
chart:,
))
}

View file

@ -0,0 +1,28 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type ScrapTransaction {
ScrapTransaction(
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
total_price: Int,
timestamp: String,
)
}
pub fn decoder() -> Decoder(ScrapTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use total_price <- decode.field("totalPrice", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(ScrapTransaction(
waypoint_symbol:,
ship_symbol:,
total_price:,
timestamp:,
))
}

59
src/models/ship.gleam Normal file
View file

@ -0,0 +1,59 @@
import gleam/dynamic/decode.{type Decoder}
import models/cooldown.{type Cooldown}
import models/ship_cargo.{type ShipCargo}
import models/ship_crew.{type ShipCrew}
import models/ship_engine.{type ShipEngine}
import models/ship_frame.{type ShipFrame}
import models/ship_fuel.{type ShipFuel}
import models/ship_module.{type ShipModule}
import models/ship_mount.{type ShipMount}
import models/ship_nav.{type ShipNav}
import models/ship_reactor.{type ShipReactor}
import models/ship_registration.{type ShipRegistration}
import models/ship_symbol.{type ShipSymbol}
pub type Ship {
Ship(
symbol: ShipSymbol,
registration: ShipRegistration,
nav: ShipNav,
crew: ShipCrew,
frame: ShipFrame,
reactor: ShipReactor,
engine: ShipEngine,
modules: List(ShipModule),
mounts: List(ShipMount),
cargo: ShipCargo,
cooldown: Cooldown,
fuel: ShipFuel,
)
}
pub fn decoder() -> Decoder(Ship) {
use symbol <- decode.field("symbol", decode.string)
use registration <- decode.field("registration", ship_registration.decoder())
use nav <- decode.field("nav", ship_nav.decoder())
use crew <- decode.field("crew", ship_crew.decoder())
use frame <- decode.field("frame", ship_frame.decoder())
use reactor <- decode.field("reactor", ship_reactor.decoder())
use engine <- decode.field("engine", ship_engine.decoder())
use modules <- decode.field("modules", decode.list(ship_module.decoder()))
use mounts <- decode.field("mounts", decode.list(ship_mount.decoder()))
use cargo <- decode.field("cargo", ship_cargo.decoder())
use cooldown <- decode.field("cooldown", cooldown.decoder())
use fuel <- decode.field("fuel", ship_fuel.decoder())
decode.success(Ship(
symbol:,
registration:,
nav:,
crew:,
frame:,
reactor:,
engine:,
modules:,
mounts:,
cargo:,
cooldown:,
fuel:,
))
}

View file

@ -0,0 +1,16 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_cargo_item.{type ShipCargoItem}
pub type ShipCargo {
ShipCargo(capacity: Int, units: Int, inventory: List(ShipCargoItem))
}
pub fn decoder() -> Decoder(ShipCargo) {
use capacity <- decode.field("capacity", decode.int)
use units <- decode.field("units", decode.int)
use inventory <- decode.field(
"inventory",
decode.list(ship_cargo_item.decoder()),
)
decode.success(ShipCargo(capacity:, units:, inventory:))
}

View file

@ -0,0 +1,19 @@
import gleam/dynamic/decode.{type Decoder}
import models/trade_symbol.{type TradeSymbol}
pub type ShipCargoItem {
ShipCargoItem(
symbol: TradeSymbol,
name: String,
description: String,
units: Int,
)
}
pub fn decoder() -> Decoder(ShipCargoItem) {
use symbol <- decode.field("symbol", trade_symbol.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
use units <- decode.field("units", decode.int)
decode.success(ShipCargoItem(symbol:, name:, description:, units:))
}

View file

@ -0,0 +1,29 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipComponent {
Frame
Reactor
Engine
}
pub fn to_string(ship_component: ShipComponent) -> String {
case ship_component {
Frame -> "FRAME"
Reactor -> "REACTOR"
Engine -> "ENGINE"
}
}
pub fn parse(ship_component_str: String) -> Result(ShipComponent, ShipComponent) {
case ship_component_str {
"FRAME" -> Ok(Frame)
"REACTOR" -> Ok(Reactor)
"ENGINE" -> Ok(Engine)
_ -> Error(Frame)
}
}
pub fn decoder() -> Decoder(ShipComponent) {
decode_utils.enum_decoder(parse, "ShipComponent")
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipComponentCondition =
Float
pub fn decoder() -> Decoder(ShipComponentCondition) {
decode.float
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipComponentIntegrity =
Float
pub fn decoder() -> Decoder(ShipComponentIntegrity) {
decode.float
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipComponentQuality =
Float
pub fn decoder() -> Decoder(ShipComponentQuality) {
decode.float
}

View file

@ -0,0 +1,20 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_component.{type ShipComponent}
import models/ship_condition_event_symbol.{type ShipConditionEventSymbol}
pub type ShipConditionEvent {
ShipConditionEvent(
symbol: ShipConditionEventSymbol,
component: ShipComponent,
name: String,
description: String,
)
}
pub fn decoder() -> Decoder(ShipConditionEvent) {
use symbol <- decode.field("symbol", ship_condition_event_symbol.decoder())
use component <- decode.field("component", ship_component.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
decode.success(ShipConditionEvent(symbol:, component:, name:, description:))
}

View file

@ -0,0 +1,105 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipConditionEventSymbol {
ReactorOverload
EnergySpikeFromMineral
SolarFlareInterference
CoolantLeak
PowerDistributionFluctuation
MagneticFieldDisruption
HullMicrometeoriteStrikes
StructuralStressFractures
CorrosiveMineralContamination
ThermalExpansionMismatch
VibrationDamageFromDrilling
ElectromagneticFieldInterference
ImpactWithExtractedDebris
FuelEfficiencyDegradation
CoolantSystemAgeing
DustMicroabrasions
ThrusterNozzleWear
ExhaustPortClogging
BearingLubricationFade
SensorCalibrationDrift
HullMicrometeoriteDamage
SpaceDebrisCollision
ThermalStress
VibrationOverload
PressureDifferentialStress
ElectromagneticSurgeEffects
AtmosphericEntryHeat
}
pub fn to_string(
ship_condition_event_symbol: ShipConditionEventSymbol,
) -> String {
case ship_condition_event_symbol {
ReactorOverload -> "REACTOR_OVERLOAD"
EnergySpikeFromMineral -> "ENERGY_SPIKE_FROM_MINERAL"
SolarFlareInterference -> "SOLAR_FLARE_INTERFERENCE"
CoolantLeak -> "COOLANT_LEAK"
PowerDistributionFluctuation -> "POWER_DISTRIBUTION_FLUCTUATION"
MagneticFieldDisruption -> "MAGNETIC_FIELD_DISRUPTION"
HullMicrometeoriteStrikes -> "HULL_MICROMETEORITE_STRIKES"
StructuralStressFractures -> "STRUCTURAL_STRESS_FRACTURES"
CorrosiveMineralContamination -> "CORROSIVE_MINERAL_CONTAMINATION"
ThermalExpansionMismatch -> "THERMAL_EXPANSION_MISMATCH"
VibrationDamageFromDrilling -> "VIBRATION_DAMAGE_FROM_DRILLING"
ElectromagneticFieldInterference -> "ELECTROMAGNETIC_FIELD_INTERFERENCE"
ImpactWithExtractedDebris -> "IMPACT_WITH_EXTRACTED_DEBRIS"
FuelEfficiencyDegradation -> "FUEL_EFFICIENCY_DEGRADATION"
CoolantSystemAgeing -> "COOLANT_SYSTEM_AGEING"
DustMicroabrasions -> "DUST_MICROABRASIONS"
ThrusterNozzleWear -> "THRUSTER_NOZZLE_WEAR"
ExhaustPortClogging -> "EXHAUST_PORT_CLOGGING"
BearingLubricationFade -> "BEARING_LUBRICATION_FADE"
SensorCalibrationDrift -> "SENSOR_CALIBRATION_DRIFT"
HullMicrometeoriteDamage -> "HULL_MICROMETEORITE_DAMAGE"
SpaceDebrisCollision -> "SPACE_DEBRIS_COLLISION"
ThermalStress -> "THERMAL_STRESS"
VibrationOverload -> "VIBRATION_OVERLOAD"
PressureDifferentialStress -> "PRESSURE_DIFFERENTIAL_STRESS"
ElectromagneticSurgeEffects -> "ELECTROMAGNETIC_SURGE_EFFECTS"
AtmosphericEntryHeat -> "ATMOSPHERIC_ENTRY_HEAT"
}
}
pub fn parse(
ship_condition_event_symbol_str: String,
) -> Result(ShipConditionEventSymbol, ShipConditionEventSymbol) {
case ship_condition_event_symbol_str {
"REACTOR_OVERLOAD" -> Ok(ReactorOverload)
"ENERGY_SPIKE_FROM_MINERAL" -> Ok(EnergySpikeFromMineral)
"SOLAR_FLARE_INTERFERENCE" -> Ok(SolarFlareInterference)
"COOLANT_LEAK" -> Ok(CoolantLeak)
"POWER_DISTRIBUTION_FLUCTUATION" -> Ok(PowerDistributionFluctuation)
"MAGNETIC_FIELD_DISRUPTION" -> Ok(MagneticFieldDisruption)
"HULL_MICROMETEORITE_STRIKES" -> Ok(HullMicrometeoriteStrikes)
"STRUCTURAL_STRESS_FRACTURES" -> Ok(StructuralStressFractures)
"CORROSIVE_MINERAL_CONTAMINATION" -> Ok(CorrosiveMineralContamination)
"THERMAL_EXPANSION_MISMATCH" -> Ok(ThermalExpansionMismatch)
"VIBRATION_DAMAGE_FROM_DRILLING" -> Ok(VibrationDamageFromDrilling)
"ELECTROMAGNETIC_FIELD_INTERFERENCE" -> Ok(ElectromagneticFieldInterference)
"IMPACT_WITH_EXTRACTED_DEBRIS" -> Ok(ImpactWithExtractedDebris)
"FUEL_EFFICIENCY_DEGRADATION" -> Ok(FuelEfficiencyDegradation)
"COOLANT_SYSTEM_AGEING" -> Ok(CoolantSystemAgeing)
"DUST_MICROABRASIONS" -> Ok(DustMicroabrasions)
"THRUSTER_NOZZLE_WEAR" -> Ok(ThrusterNozzleWear)
"EXHAUST_PORT_CLOGGING" -> Ok(ExhaustPortClogging)
"BEARING_LUBRICATION_FADE" -> Ok(BearingLubricationFade)
"SENSOR_CALIBRATION_DRIFT" -> Ok(SensorCalibrationDrift)
"HULL_MICROMETEORITE_DAMAGE" -> Ok(HullMicrometeoriteDamage)
"SPACE_DEBRIS_COLLISION" -> Ok(SpaceDebrisCollision)
"THERMAL_STRESS" -> Ok(ThermalStress)
"VIBRATION_OVERLOAD" -> Ok(VibrationOverload)
"PRESSURE_DIFFERENTIAL_STRESS" -> Ok(PressureDifferentialStress)
"ELECTROMAGNETIC_SURGE_EFFECTS" -> Ok(ElectromagneticSurgeEffects)
"ATMOSPHERIC_ENTRY_HEAT" -> Ok(AtmosphericEntryHeat)
_ -> Error(ReactorOverload)
}
}
pub fn decoder() -> Decoder(ShipConditionEventSymbol) {
decode_utils.enum_decoder(parse, "ShipConditionEventSymbol")
}

View file

@ -0,0 +1,30 @@
import gleam/dynamic/decode.{type Decoder}
import models/crew_rotation.{type CrewRotation}
pub type ShipCrew {
ShipCrew(
current: Int,
required: Int,
capacity: Int,
rotation: CrewRotation,
morale: Int,
wages: Int,
)
}
pub fn decoder() -> Decoder(ShipCrew) {
use current <- decode.field("current", decode.int)
use required <- decode.field("required", decode.int)
use capacity <- decode.field("capacity", decode.int)
use rotation <- decode.field("rotation", crew_rotation.decoder())
use morale <- decode.field("morale", decode.int)
use wages <- decode.field("wages", decode.int)
decode.success(ShipCrew(
current: current,
required: required,
capacity: capacity,
rotation: rotation,
morale: morale,
wages: wages,
))
}

View file

@ -0,0 +1,40 @@
import gleam/dynamic/decode.{type Decoder}
import models/engine_symbol.{type EngineSymbol}
import models/ship_component_condition.{type ShipComponentCondition}
import models/ship_component_integrity.{type ShipComponentIntegrity}
import models/ship_component_quality.{type ShipComponentQuality}
import models/ship_requirements.{type ShipRequirements}
pub type ShipEngine {
ShipEngine(
symbol: EngineSymbol,
name: String,
condition: ShipComponentCondition,
integrity: ShipComponentIntegrity,
description: String,
speed: Int,
requirements: ShipRequirements,
quality: ShipComponentQuality,
)
}
pub fn decoder() -> Decoder(ShipEngine) {
use symbol <- decode.field("symbol", engine_symbol.decoder())
use name <- decode.field("name", decode.string)
use condition <- decode.field("condition", ship_component_condition.decoder())
use integrity <- decode.field("integrity", ship_component_integrity.decoder())
use description <- decode.field("description", decode.string)
use speed <- decode.field("speed", decode.int)
use requirements <- decode.field("requirements", ship_requirements.decoder())
use quality <- decode.field("quality", ship_component_quality.decoder())
decode.success(ShipEngine(
symbol:,
name:,
condition:,
integrity:,
description:,
speed:,
requirements:,
quality:,
))
}

View file

@ -0,0 +1,46 @@
import gleam/dynamic/decode.{type Decoder}
import models/frame_symbol.{type FrameSymbol}
import models/ship_component_condition.{type ShipComponentCondition}
import models/ship_component_integrity.{type ShipComponentIntegrity}
import models/ship_component_quality.{type ShipComponentQuality}
import models/ship_requirements.{type ShipRequirements}
pub type ShipFrame {
ShipFrame(
symbol: FrameSymbol,
name: String,
condition: ShipComponentCondition,
integrity: ShipComponentIntegrity,
description: String,
module_slots: Int,
mounting_points: Int,
fuel_capacity: Int,
requirements: ShipRequirements,
quality: ShipComponentQuality,
)
}
pub fn decoder() -> Decoder(ShipFrame) {
use symbol <- decode.field("symbol", frame_symbol.decoder())
use name <- decode.field("name", decode.string)
use condition <- decode.field("condition", ship_component_condition.decoder())
use integrity <- decode.field("integrity", ship_component_integrity.decoder())
use description <- decode.field("description", decode.string)
use module_slots <- decode.field("moduleSlots", decode.int)
use mounting_points <- decode.field("mountingPoints", decode.int)
use fuel_capacity <- decode.field("fuelCapacity", decode.int)
use requirements <- decode.field("requirements", ship_requirements.decoder())
use quality <- decode.field("quality", ship_component_quality.decoder())
decode.success(ShipFrame(
symbol:,
name:,
condition:,
integrity:,
description:,
module_slots:,
mounting_points:,
fuel_capacity:,
requirements:,
quality:,
))
}

View file

@ -0,0 +1,18 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/ship_fuel_consumed.{type ShipFuelConsumed}
import utils/decode as decode_utils
pub type ShipFuel {
ShipFuel(current: Int, capacity: Int, consumed: Option(ShipFuelConsumed))
}
pub fn decoder() -> Decoder(ShipFuel) {
use current <- decode.field("current", decode.int)
use capacity <- decode.field("capacity", decode.int)
use consumed <- decode_utils.field_key_value_optional(
"consumed",
ship_fuel_consumed.decoder(),
)
decode.success(ShipFuel(current:, capacity:, consumed:))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipFuelConsumed {
ShipFuelConsumed(amount: Int, timestamp: String)
}
pub fn decoder() -> Decoder(ShipFuelConsumed) {
use amount <- decode.field("amount", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(ShipFuelConsumed(amount:, timestamp:))
}

View file

@ -0,0 +1,32 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/trade_symbol.{type TradeSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type ShipModificationTransaction {
ShipModificationTransaction(
waypoint_symbol: WaypointSymbol,
ship_symbol: ShipSymbol,
trade_symbol: TradeSymbol,
total_price: Int,
timestamp: String,
)
}
pub fn decoder() -> Decoder(ShipModificationTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use trade_symbol <- decode.field("tradeSymbol", trade_symbol.decoder())
use total_price <- decode.field("totalPrice", decode.int)
use timestamp <- decode.field("timestamp", decode.string)
decode.success(ShipModificationTransaction(
waypoint_symbol:,
ship_symbol:,
trade_symbol:,
total_price:,
timestamp:,
))
}

View file

@ -0,0 +1,33 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/module_symbol.{type ModuleSymbol}
import models/ship_requirements.{type ShipRequirements}
import utils/decode as decode_utils
pub type ShipModule {
ShipModule(
symbol: ModuleSymbol,
name: String,
description: String,
capacity: Option(Int),
range: Option(Int),
requirements: ShipRequirements,
)
}
pub fn decoder() -> Decoder(ShipModule) {
use symbol <- decode.field("symbol", module_symbol.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
use capacity <- decode_utils.field_key_value_optional("capacity", decode.int)
use range <- decode_utils.field_key_value_optional("range", decode.int)
use requirements <- decode.field("requirements", ship_requirements.decoder())
decode.success(ShipModule(
symbol:,
name:,
description:,
capacity:,
range:,
requirements:,
))
}

View file

@ -0,0 +1,37 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/mount_deposit.{type MountDeposit}
import models/mount_symbol.{type MountSymbol}
import models/ship_requirements.{type ShipRequirements}
import utils/decode as decode_utils
pub type ShipMount {
ShipMount(
symbol: MountSymbol,
name: String,
description: String,
strength: Option(Int),
deposits: Option(List(MountDeposit)),
requirements: ShipRequirements,
)
}
pub fn decoder() -> Decoder(ShipMount) {
use symbol <- decode.field("symbol", mount_symbol.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
use strength <- decode_utils.field_key_value_optional("strength", decode.int)
use deposits <- decode_utils.field_key_value_optional(
"deposits",
decode.list(mount_deposit.decoder()),
)
use requirements <- decode.field("requirements", ship_requirements.decoder())
decode.success(ShipMount(
symbol:,
name:,
description:,
strength:,
deposits:,
requirements:,
))
}

34
src/models/ship_nav.gleam Normal file
View file

@ -0,0 +1,34 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_nav_flight_mode.{type ShipNavFlightMode}
import models/ship_nav_route.{type ShipNavRoute}
import models/ship_nav_status.{type ShipNavStatus}
import models/system_symbol.{type SystemSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
pub type ShipNav {
ShipNav(
system_symbol: SystemSymbol,
waypoint_symbol: WaypointSymbol,
route: ShipNavRoute,
status: ShipNavStatus,
flight_mode: ShipNavFlightMode,
)
}
pub fn decoder() -> Decoder(ShipNav) {
use system_symbol <- decode.field("systemSymbol", system_symbol.decoder())
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use route <- decode.field("route", ship_nav_route.decoder())
use status <- decode.field("status", ship_nav_status.decoder())
use flight_mode <- decode.field("flightMode", ship_nav_flight_mode.decoder())
decode.success(ShipNav(
system_symbol:,
waypoint_symbol:,
route:,
status:,
flight_mode:,
))
}

View file

@ -0,0 +1,34 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipNavFlightMode {
Drift
Stealth
Cruise
Burn
}
pub fn to_string(ship_nav_flight_mode: ShipNavFlightMode) -> String {
case ship_nav_flight_mode {
Drift -> "DRIFT"
Stealth -> "STEALTH"
Cruise -> "CRUISE"
Burn -> "BURN"
}
}
pub fn parse(
ship_nav_flight_mode_str: String,
) -> Result(ShipNavFlightMode, ShipNavFlightMode) {
case ship_nav_flight_mode_str {
"DRIFT" -> Ok(Drift)
"STEALTH" -> Ok(Stealth)
"CRUISE" -> Ok(Cruise)
"BURN" -> Ok(Burn)
_ -> Error(Drift)
}
}
pub fn decoder() -> Decoder(ShipNavFlightMode) {
decode_utils.enum_decoder(parse, "ShipNavFlightMode")
}

View file

@ -0,0 +1,22 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_nav_route_waypoint.{type ShipNavRouteWaypoint}
pub type ShipNavRoute {
ShipNavRoute(
destination: ShipNavRouteWaypoint,
origin: ShipNavRouteWaypoint,
departure_time: String,
arrival: String,
)
}
pub fn decoder() -> Decoder(ShipNavRoute) {
use destination <- decode.field(
"destination",
ship_nav_route_waypoint.decoder(),
)
use origin <- decode.field("origin", ship_nav_route_waypoint.decoder())
use departure_time <- decode.field("departureTime", decode.string)
use arrival <- decode.field("arrival", decode.string)
decode.success(ShipNavRoute(destination:, origin:, departure_time:, arrival:))
}

View file

@ -0,0 +1,23 @@
import gleam/dynamic/decode.{type Decoder}
import models/system_symbol.{type SystemSymbol}
import models/waypoint_symbol.{type WaypointSymbol}
import models/waypoint_type.{type WaypointType}
pub type ShipNavRouteWaypoint {
ShipNavRouteWaypoint(
symbol: WaypointSymbol,
type_: WaypointType,
system_symbol: SystemSymbol,
x: Int,
y: Int,
)
}
pub fn decoder() -> Decoder(ShipNavRouteWaypoint) {
use symbol <- decode.field("symbol", waypoint_symbol.decoder())
use type_ <- decode.field("type", waypoint_type.decoder())
use system_symbol <- decode.field("systemSymbol", system_symbol.decoder())
use x <- decode.field("x", decode.int)
use y <- decode.field("y", decode.int)
decode.success(ShipNavRouteWaypoint(symbol:, type_:, system_symbol:, x:, y:))
}

View file

@ -0,0 +1,31 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipNavStatus {
InTransit
InOrbit
Docked
}
pub fn to_string(ship_nav_status: ShipNavStatus) -> String {
case ship_nav_status {
InTransit -> "IN_TRANSIT"
InOrbit -> "IN_ORBIT"
Docked -> "DOCKED"
}
}
pub fn parse(
ship_nav_status_str: String,
) -> Result(ShipNavStatus, ShipNavStatus) {
case ship_nav_status_str {
"IN_TRANSIT" -> Ok(InTransit)
"IN_ORBIT" -> Ok(InOrbit)
"DOCKED" -> Ok(Docked)
_ -> Error(InTransit)
}
}
pub fn decoder() -> Decoder(ShipNavStatus) {
decode_utils.enum_decoder(parse, "ShipNavStatus")
}

View file

@ -0,0 +1,40 @@
import gleam/dynamic/decode.{type Decoder}
import models/reactor_symbol.{type ReactorSymbol}
import models/ship_component_condition.{type ShipComponentCondition}
import models/ship_component_integrity.{type ShipComponentIntegrity}
import models/ship_component_quality.{type ShipComponentQuality}
import models/ship_requirements.{type ShipRequirements}
pub type ShipReactor {
ShipReactor(
symbol: ReactorSymbol,
name: String,
condition: ShipComponentCondition,
integrity: ShipComponentIntegrity,
description: String,
power_output: Int,
requirements: ShipRequirements,
quality: ShipComponentQuality,
)
}
pub fn decoder() -> Decoder(ShipReactor) {
use symbol <- decode.field("symbol", reactor_symbol.decoder())
use name <- decode.field("name", decode.string)
use condition <- decode.field("condition", ship_component_condition.decoder())
use integrity <- decode.field("integrity", ship_component_integrity.decoder())
use description <- decode.field("description", decode.string)
use power_output <- decode.field("powerOutput", decode.int)
use requirements <- decode.field("requirements", ship_requirements.decoder())
use quality <- decode.field("quality", ship_component_quality.decoder())
decode.success(ShipReactor(
symbol:,
name:,
condition:,
integrity:,
description:,
power_output:,
requirements:,
quality:,
))
}

View file

@ -0,0 +1,14 @@
import gleam/dynamic/decode.{type Decoder}
import models/faction_symbol.{type FactionSymbol}
import models/ship_role.{type ShipRole}
pub type ShipRegistration {
ShipRegistration(name: String, faction_symbol: FactionSymbol, role: ShipRole)
}
pub fn decoder() -> Decoder(ShipRegistration) {
use name <- decode.field("name", decode.string)
use faction_symbol <- decode.field("factionSymbol", faction_symbol.decoder())
use role <- decode.field("role", ship_role.decoder())
decode.success(ShipRegistration(name:, faction_symbol:, role:))
}

View file

@ -0,0 +1,14 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import utils/decode as decode_utils
pub type ShipRequirements {
ShipRequirements(power: Option(Int), crew: Option(Int), slots: Option(Int))
}
pub fn decoder() -> Decoder(ShipRequirements) {
use power <- decode_utils.field_key_value_optional("power", decode.int)
use crew <- decode_utils.field_key_value_optional("crew", decode.int)
use slots <- decode_utils.field_key_value_optional("slots", decode.int)
decode.success(ShipRequirements(power:, crew:, slots:))
}

View file

@ -0,0 +1,62 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipRole {
Fabricator
Harvester
Hauler
Interceptor
Excavator
Transport
Repair
Surveyor
Command
Carrier
Patrol
Satellite
Explorer
Refinery
}
pub fn to_string(ship_role: ShipRole) -> String {
case ship_role {
Fabricator -> "FABRICATOR"
Harvester -> "HARVESTER"
Hauler -> "HAULER"
Interceptor -> "INTERCEPTOR"
Excavator -> "EXCAVATOR"
Transport -> "TRANSPORT"
Repair -> "REPAIR"
Surveyor -> "SURVEYOR"
Command -> "COMMAND"
Carrier -> "CARRIER"
Patrol -> "PATROL"
Satellite -> "SATELLITE"
Explorer -> "EXPLORER"
Refinery -> "REFINERY"
}
}
pub fn parse(ship_role_str: String) -> Result(ShipRole, ShipRole) {
case ship_role_str {
"FABRICATOR" -> Ok(Fabricator)
"HARVESTER" -> Ok(Harvester)
"HAULER" -> Ok(Hauler)
"INTERCEPTOR" -> Ok(Interceptor)
"EXCAVATOR" -> Ok(Excavator)
"TRANSPORT" -> Ok(Transport)
"REPAIR" -> Ok(Repair)
"SURVEYOR" -> Ok(Surveyor)
"COMMAND" -> Ok(Command)
"CARRIER" -> Ok(Carrier)
"PATROL" -> Ok(Patrol)
"SATELLITE" -> Ok(Satellite)
"EXPLORER" -> Ok(Explorer)
"REFINERY" -> Ok(Refinery)
_ -> Error(Fabricator)
}
}
pub fn decoder() -> Decoder(ShipRole) {
decode_utils.enum_decoder(parse, "ShipRole")
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipSymbol =
String
pub fn decoder() -> Decoder(ShipSymbol) {
decode.string
}

View file

@ -0,0 +1,35 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type ShipType {
ShipProbe
ShipMiningDrone
ShipSiphonDrone
ShipInterceptor
ShipLightHauler
}
pub fn to_string(ship_type: ShipType) -> String {
case ship_type {
ShipProbe -> "SHIP_PROBE"
ShipMiningDrone -> "SHIP_MINING_DRONE"
ShipSiphonDrone -> "SHIP_SIPHON_DRONE"
ShipInterceptor -> "SHIP_INTERCEPTOR"
ShipLightHauler -> "SHIP_LIGHT_HAULER"
}
}
pub fn parse(ship_type_str: String) -> Result(ShipType, ShipType) {
case ship_type_str {
"SHIP_PROBE" -> Ok(ShipProbe)
"SHIP_MINING_DRONE" -> Ok(ShipMiningDrone)
"SHIP_SIPHON_DRONE" -> Ok(ShipSiphonDrone)
"SHIP_INTERCEPTOR" -> Ok(ShipInterceptor)
"SHIP_LIGHT_HAULER" -> Ok(ShipLightHauler)
_ -> Error(ShipProbe)
}
}
pub fn decoder() -> Decoder(ShipType) {
decode_utils.enum_decoder(parse, "ShipType")
}

38
src/models/shipyard.gleam Normal file
View file

@ -0,0 +1,38 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/ship_type.{type ShipType}
import models/shipyard_ship.{type ShipyardShip}
import models/shipyard_symbol.{type ShipyardSymbol}
import models/shipyard_transaction.{type ShipyardTransaction}
import utils/decode as decode_utils
pub type Shipyard {
Shipyard(
symbol: ShipyardSymbol,
ship_types: List(ShipType),
transactions: Option(List(ShipyardTransaction)),
ships: Option(List(ShipyardShip)),
modifications_fee: Int,
)
}
pub fn decoder() -> Decoder(Shipyard) {
use symbol <- decode.field("symbol", decode.string)
use ship_types <- decode.field("shipTypes", decode.list(ship_type.decoder()))
use transactions <- decode_utils.field_key_value_optional(
"transactions",
decode.list(shipyard_transaction.decoder()),
)
use ships <- decode_utils.field_key_value_optional(
"ships",
decode.list(shipyard_ship.decoder()),
)
use modifications_fee <- decode.field("modificationsFee", decode.int)
decode.success(Shipyard(
symbol:,
ship_types:,
transactions:,
ships:,
modifications_fee:,
))
}

View file

@ -0,0 +1,61 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/activity_level.{type ActivityLevel}
import models/ship_engine.{type ShipEngine}
import models/ship_frame.{type ShipFrame}
import models/ship_module.{type ShipModule}
import models/ship_mount.{type ShipMount}
import models/ship_reactor.{type ShipReactor}
import models/ship_type.{type ShipType}
import models/shipyard_ship_crew.{type ShipyardShipCrew}
import models/supply_level.{type SupplyLevel}
import utils/decode as decode_utils
pub type ShipyardShip {
ShipyardShip(
type_: ShipType,
name: String,
description: String,
activity: Option(ActivityLevel),
supply: SupplyLevel,
purchase_price: Int,
frame: ShipFrame,
reactor: ShipReactor,
engine: ShipEngine,
modules: List(ShipModule),
mounts: List(ShipMount),
crew: ShipyardShipCrew,
)
}
pub fn decoder() -> Decoder(ShipyardShip) {
use type_ <- decode.field("type", ship_type.decoder())
use name <- decode.field("name", decode.string)
use description <- decode.field("description", decode.string)
use activity <- decode_utils.field_key_value_optional(
"activity",
activity_level.decoder(),
)
use supply <- decode.field("supply", supply_level.decoder())
use purchase_price <- decode.field("purchasePrice", decode.int)
use frame <- decode.field("frame", ship_frame.decoder())
use reactor <- decode.field("reactor", ship_reactor.decoder())
use engine <- decode.field("engine", ship_engine.decoder())
use modules <- decode.field("modules", decode.list(ship_module.decoder()))
use mounts <- decode.field("mounts", decode.list(ship_mount.decoder()))
use crew <- decode.field("crew", shipyard_ship_crew.decoder())
decode.success(ShipyardShip(
type_:,
name:,
description:,
activity:,
supply:,
purchase_price:,
frame:,
reactor:,
engine:,
modules:,
mounts:,
crew:,
))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipyardShipCrew {
ShipCrew(required: Int, capacity: Int)
}
pub fn decoder() -> Decoder(ShipyardShipCrew) {
use required <- decode.field("required", decode.int)
use capacity <- decode.field("capacity", decode.int)
decode.success(ShipCrew(required:, capacity:))
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type ShipyardSymbol =
String
pub fn decoder() -> Decoder(ShipyardSymbol) {
decode.string
}

View file

@ -0,0 +1,32 @@
import gleam/dynamic/decode.{type Decoder}
import models/agent_symbol.{type AgentSymbol}
import models/ship_type.{type ShipType}
import models/waypoint_symbol.{type WaypointSymbol}
pub type ShipyardTransaction {
ShipyardTransaction(
waypoint_symbol: WaypointSymbol,
ship_type: ShipType,
price: Int,
agent_symbol: AgentSymbol,
timestamp: String,
)
}
pub fn decoder() -> Decoder(ShipyardTransaction) {
use waypoint_symbol <- decode.field(
"waypointSymbol",
waypoint_symbol.decoder(),
)
use ship_type <- decode.field("shipType", ship_type.decoder())
use price <- decode.field("price", decode.int)
use agent_symbol <- decode.field("agentSymbol", agent_symbol.decoder())
use timestamp <- decode.field("timestamp", decode.string)
decode.success(ShipyardTransaction(
waypoint_symbol:,
ship_type:,
price:,
agent_symbol:,
timestamp:,
))
}

13
src/models/siphon.gleam Normal file
View file

@ -0,0 +1,13 @@
import gleam/dynamic/decode.{type Decoder}
import models/ship_symbol.{type ShipSymbol}
import models/siphon_yield.{type SiphonYield}
pub type Siphon {
Siphon(ship_symbol: ShipSymbol, yield: SiphonYield)
}
pub fn decoder() -> Decoder(Siphon) {
use ship_symbol <- decode.field("shipSymbol", ship_symbol.decoder())
use yield <- decode.field("yield", siphon_yield.decoder())
decode.success(Siphon(ship_symbol:, yield:))
}

View file

@ -0,0 +1,12 @@
import gleam/dynamic/decode.{type Decoder}
import models/trade_symbol.{type TradeSymbol}
pub type SiphonYield {
SiphonYield(symbol: TradeSymbol, units: Int)
}
pub fn decoder() -> Decoder(SiphonYield) {
use symbol <- decode.field("symbol", trade_symbol.decoder())
use units <- decode.field("units", decode.int)
decode.success(SiphonYield(symbol:, units:))
}

View file

@ -0,0 +1,35 @@
import gleam/dynamic/decode.{type Decoder}
import utils/decode as decode_utils
pub type SupplyLevel {
Scarce
Limited
Moderate
High
Abundant
}
pub fn to_string(supply_level: SupplyLevel) -> String {
case supply_level {
Scarce -> "SCARCE"
Limited -> "LIMITED"
Moderate -> "MODERATE"
High -> "HIGH"
Abundant -> "ABUNDANT"
}
}
pub fn parse(supply_level_str: String) -> Result(SupplyLevel, SupplyLevel) {
case supply_level_str {
"SCARCE" -> Ok(Scarce)
"LIMITED" -> Ok(Limited)
"MODERATE" -> Ok(Moderate)
"HIGH" -> Ok(High)
"ABUNDANT" -> Ok(Abundant)
_ -> Error(Scarce)
}
}
pub fn decoder() -> Decoder(SupplyLevel) {
decode_utils.enum_decoder(parse, "SupplyLevel")
}

38
src/models/survey.gleam Normal file
View file

@ -0,0 +1,38 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json.{type Json}
import models/survey_deposit.{type SurveyDeposit}
import models/survey_signature.{type SurveySignature}
import models/survey_size.{type SurveySize}
import models/waypoint_symbol.{type WaypointSymbol}
pub type Survey {
Survey(
signature: SurveySignature,
symbol: WaypointSymbol,
deposits: List(SurveyDeposit),
expiration: String,
size: SurveySize,
)
}
pub fn encode(data: Survey) -> Json {
json.object([
#("signature", json.string(data.signature)),
#("symbol", json.string(data.symbol)),
#("deposits", json.array(data.deposits, survey_deposit.encode)),
#("expiration", json.string(data.expiration)),
#("size", survey_size.encode(data.size)),
])
}
pub fn decoder() -> Decoder(Survey) {
use signature <- decode.field("signature", survey_signature.decoder())
use symbol <- decode.field("symbol", waypoint_symbol.decoder())
use deposits <- decode.field(
"deposits",
decode.list(survey_deposit.decoder()),
)
use expiration <- decode.field("expiration", decode.string)
use size <- decode.field("size", survey_size.decoder())
decode.success(Survey(signature:, symbol:, deposits:, expiration:, size:))
}

View file

@ -0,0 +1,16 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json.{type Json}
import models/trade_symbol.{type TradeSymbol}
pub type SurveyDeposit {
SurveyDeposit(symbol: TradeSymbol)
}
pub fn encode(survey_deposit: SurveyDeposit) -> Json {
json.object([#("symbol", trade_symbol.encode(survey_deposit.symbol))])
}
pub fn decoder() -> Decoder(SurveyDeposit) {
use symbol <- decode.field("symbol", trade_symbol.decoder())
decode.success(SurveyDeposit(symbol:))
}

View file

@ -0,0 +1,8 @@
import gleam/dynamic/decode.{type Decoder}
pub type SurveySignature =
String
pub fn decoder() -> Decoder(SurveySignature) {
decode.string
}

View file

@ -0,0 +1,34 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/json.{type Json}
import utils/decode as decode_utils
pub type SurveySize {
Small
Moderate
Large
}
pub fn to_string(survey_size: SurveySize) -> String {
case survey_size {
Small -> "SMALL"
Moderate -> "MODERATE"
Large -> "LARGE"
}
}
pub fn parse(survey_size_str: String) -> Result(SurveySize, SurveySize) {
case survey_size_str {
"SMALL" -> Ok(Small)
"MODERATE" -> Ok(Moderate)
"LARGE" -> Ok(Large)
_ -> Error(Small)
}
}
pub fn encode(survey_size: SurveySize) -> Json {
json.string(to_string(survey_size))
}
pub fn decoder() -> Decoder(SurveySize) {
decode_utils.enum_decoder(parse, "SurveySize")
}

54
src/models/system.gleam Normal file
View file

@ -0,0 +1,54 @@
import gleam/dynamic/decode.{type Decoder}
import gleam/option.{type Option}
import models/system_faction.{type SystemFaction}
import models/system_symbol.{type SystemSymbol}
import models/system_type.{type SystemType}
import models/system_waypoint.{type SystemWaypoint}
import utils/decode as decode_utils
pub type System {
System(
constellation: Option(String),
symbol: SystemSymbol,
sector_symbol: String,
type_: SystemType,
x: Int,
y: Int,
waypoints: List(SystemWaypoint),
factions: List(SystemFaction),
name: Option(String),
)
}
pub fn decoder() -> Decoder(System) {
use constellation <- decode.optional_field(
"constellation",
option.None,
decode.optional(decode.string),
)
use symbol <- decode.field("symbol", decode.string)
use sector_symbol <- decode.field("sectorSymbol", decode.string)
use type_ <- decode.field("type", system_type.decoder())
use x <- decode.field("x", decode.int)
use y <- decode.field("y", decode.int)
use waypoints <- decode.field(
"waypoints",
decode.list(system_waypoint.decoder()),
)
use factions <- decode.field(
"factions",
decode.list(system_faction.decoder()),
)
use name <- decode_utils.field_key_value_optional("name", decode.string)
decode.success(System(
constellation:,
symbol:,
sector_symbol:,
type_:,
x:,
y:,
waypoints:,
factions:,
name:,
))
}

View file

@ -0,0 +1,11 @@
import gleam/dynamic/decode.{type Decoder}
import models/faction_symbol.{type FactionSymbol}
pub type SystemFaction {
SystemFaction(symbol: FactionSymbol)
}
pub fn decoder() -> Decoder(SystemFaction) {
use symbol <- decode.field("symbol", faction_symbol.decoder())
decode.success(SystemFaction(symbol:))
}

Some files were not shown because too many files have changed in this diff Show more