Compare commits

...

4 Commits

Author SHA1 Message Date
Arthur POULET 81dce33c45
add ships 2024-02-04 18:12:36 +01:00
Arthur POULET 9b55232894
add log 2024-02-03 16:49:06 +01:00
Arthur POULET ebe7ed8669
up 2024-02-03 15:49:17 +01:00
Arthur POULET 1d92eda857
up 2024-02-03 15:03:04 +01:00
11 changed files with 335 additions and 90 deletions

View File

@ -8,20 +8,16 @@ $LOAD_PATH << File.join(Dir.pwd, 'lib')
require 'pry'
require 'space_traders'
include SpaceTraders
c = SpaceTraders::Client.load_from_env
c = SpaceTraders::Client.register name: "Sceptique#{(rand * 10000).round}"
File.open(".env", "a") { |f| f.write("\nSPACETRADERS_TOKEN=#{c.token}\n") }
puts "client loaded"
c = Client.load_from_env
# c = Client.register name: "Sceptique#{(rand * 10000).round}"
# File.open(".env", "a") { |f| f.write("\nSPACETRADERS_TOKEN=#{c.token}\n") }
Log.debug "client loaded"
contracts = c.contract.my_contracts { _1 }
puts "contracts loaded"
contract = contracts.first
require "model"
contract = SpaceTraders::Contract.new(c, **contract)
pp contract
pp contract.accept!
contract.reload!
contracts = Contract.my_contracts(c)
contracts.first.accept!
contracts.first.reload!
ship = Ship.my_ships(c).first.reload!
binding.pry

View File

@ -4,80 +4,110 @@ require 'net/http'
require 'uri'
require 'json'
class SpaceTraders::Client
DEFAULT_BASE_URL = ENV['SPACETRADERS_DEFAULT_BASE_URL'] || 'https://api.spacetraders.io/v2'
module SpaceTraders
class Client
DEFAULT_BASE_URL = ENV['SPACETRADERS_DEFAULT_BASE_URL'] || 'https://api.spacetraders.io/v2'
attr_accessor :token, :base_url
def initialize(token:, base_url: DEFAULT_BASE_URL)
raise 'Invalid Nil token' if token.nil?
@token = token
@base_url = base_url
end
def self.register(name:, faction: 'COSMIC', base_url: DEFAULT_BASE_URL)
res = Net::HTTP.post(
URI("#{base_url}/register"),
{ symbol: name, faction: faction }.to_json,
'Content-Type' => 'application/json'
)
token = JSON.parse(res.body).dig('data', 'token')
new(token: token, base_url: base_url)
end
def self.load_from_env
new(token: ENV['SPACETRADERS_TOKEN'], base_url: DEFAULT_BASE_URL)
end
def post(endpoint:, body:)
res = Net::HTTP.post(
URI("#{base_url}/#{endpoint}"),
body ? body.to_json : nil,
'Authorization' => "Bearer #{@token}",
'Content-Type' => 'application/json'
)
if block_given?
yield JSON.parse(res.body), res
else
res
def self.register(name:, faction: 'COSMIC', base_url: DEFAULT_BASE_URL)
Log.debug("register new account #{name} faction #{faction}")
res = Net::HTTP.post(
URI("#{base_url}/register"),
{ symbol: name, faction: faction }.to_json,
'Content-Type' => 'application/json'
)
token = JSON.parse(res.body).dig('data', 'token')
new(token: token, base_url: base_url)
end
end
def get(endpoint:)
res = Net::HTTP.get_response(
URI("#{@base_url}/#{endpoint}"),
'Authorization' => "Bearer #{@token}",
'Content-Type' => 'application/json'
)
if block_given?
yield JSON.parse(res.body)["data"], res
else
res
def self.load_from_env
new(token: ENV['SPACETRADERS_TOKEN'], base_url: DEFAULT_BASE_URL)
end
end
end
require 'endpoint'
attr_accessor :token, :base_url
class SpaceTraders::Client
def self.add_endpoint(name)
define_method(name.to_s.downcase) do
variable_name = "@memoize_#{name}"
variable = instance_variable_get(variable_name)
if variable.nil?
endpoint = SpaceTraders::Endpoint::const_get(name.to_s.camelcase).new(client: self)
instance_variable_set(variable_name, endpoint)
endpoint
# @param parse : if false, get/post will return the raw response, not the parsed body
def initialize(token:, base_url: DEFAULT_BASE_URL, parse: true)
raise 'Invalid Nil token' if token.nil?
@parse = parse
@token = token
@base_url = base_url
end
def parse?
@parse
end
private def parse!(res)
@res = res
@body = JSON.parse(res.body)
@body["data"]
end
def meta
@body["meta"] if @body
end
def data
@body["data"] if @body
end
def post(endpoint:, body:)
Log.debug("post #{endpoint}")
res = Net::HTTP.post(
URI("#{base_url}/#{endpoint}"),
body ? body.to_json : nil,
'Authorization' => "Bearer #{@token}",
'Content-Type' => 'application/json'
)
if block_given?
yield JSON.parse(res.body), res
elsif parse?
parse!(res)
else
variable
res
end
end
def get(endpoint:)
Log.debug("get #{endpoint}")
res = Net::HTTP.get_response(
URI("#{@base_url}/#{endpoint}"),
'Authorization' => "Bearer #{@token}",
'Content-Type' => 'application/json'
)
if block_given?
yield JSON.parse(res.body), res
elsif parse?
parse!(res)
else
res
end
end
end
def self.add_endpoints(*names)
names.each { add_endpoint(_1) }
end
require 'endpoint'
add_endpoints :agent, :contract
class Client
def self.add_endpoint(name)
Log.debug("add_endpoint #{name}")
define_method(name.to_s.downcase) do
variable_name = "@memoize_#{name}"
variable = instance_variable_get(variable_name)
if variable.nil?
endpoint = SpaceTraders::Endpoint::const_get(name.to_s.camelcase).new(client: self)
instance_variable_set(variable_name, endpoint)
endpoint
else
variable
end
end
end
def self.add_endpoints(*names)
names.each { add_endpoint(_1) }
end
add_endpoints :agents, :contracts, :ships
end
end

View File

@ -12,10 +12,27 @@ class SpaceTraders::Endpoint
delegate :get, to: :client
delegate :post, to: :client
def self.fills_endpoint_placeholders(raw_endpoint, params)
Log.debug("raw_endpoint #{raw_endpoint}")
mutated = params.reduce(raw_endpoint) do |base, kv|
Log.debug("endpoint mutate #{base}")
if base.match?(/:#{kv[0]}\b/)
base.gsub(/:#{kv[0]}\b/, kv[1])
else
join = base.include?("?") ? "&" : "?"
"#{base}#{join}#{kv[0]}=#{kv[1]}"
end
end
Log.debug("endpoint mutate to #{mutated}")
mutated
end
def self.define_endpoint(method_name, get: nil, post: nil)
SpaceTraders::Log.debug("define endpoint #{method_name} to #{get || post}")
if get
define_method(method_name) do |params={}, &block|
endpoint = params.reduce(get || post) { _1.gsub(/:#{_2[0]}/, _2[1]) }
endpoint = SpaceTraders::Endpoint.fills_endpoint_placeholders(get || post, params)
SpaceTraders::Log.debug("filled_endpoint of #{method_name} to #{endpoint} with #{get || post} and #{params}")
if block
get(endpoint: endpoint, &block)
else
@ -25,7 +42,8 @@ class SpaceTraders::Endpoint
end
elsif post
define_method(method_name) do |params={}, body=nil, &block|
endpoint = params.reduce(get || post) { _1.gsub(/:#{_2[0]}/, _2[1]) }
endpoint = SpaceTraders::Endpoint.fills_endpoint_placeholders(get || post, params)
SpaceTraders::Log.debug("filled_endpoint of #{method_name} to #{endpoint} with #{get || post} and #{params}")
if block
post(endpoint: endpoint, body: body, &block)
else
@ -36,4 +54,7 @@ class SpaceTraders::Endpoint
end
end
Dir['lib/endpoint/*.rb'].each { load _1; warn "loaded #{_1}" }
Dir['lib/endpoint/*.rb'].each do
SpaceTraders::Log.warn("load #{_1}")
load _1
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class SpaceTraders::Endpoint::Agent < SpaceTraders::Endpoint
class SpaceTraders::Endpoint::Agents < SpaceTraders::Endpoint
define_endpoint :my_agent, get: 'my/agent'
define_endpoint :agents, get: 'agents'
define_endpoint :agents, get: 'agent/:id'
define_endpoint :agent, get: 'agent/:id'
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
class SpaceTraders::Endpoint::Contract < SpaceTraders::Endpoint
class SpaceTraders::Endpoint::Contracts < SpaceTraders::Endpoint
define_endpoint :my_contracts, get: 'my/contracts'
define_endpoint :my_contract, get: 'my/contracts/:id'
define_endpoint :my_contracts_accept, post: 'my/contracts/:id/accept'

16
lib/endpoint/ships.rb Normal file
View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class SpaceTraders::Endpoint::Ships < SpaceTraders::Endpoint
define_endpoint :my_ships, get: 'my/ships'
define_endpoint :my_ship, get: 'my/ships/:id'
define_endpoint :purchase_ship, post: 'my/ships' # shipType waypointSymbol
define_endpoint :my_ship_orbit, post: 'my/ships/:id/orbit'
define_endpoint :my_ship_survey, post: 'my/ships/:id/survey'
define_endpoint :my_ship_extract, post: 'my/ships/:id/extract/survey'
define_endpoint :my_ship_siphon, post: 'my/ships/:id/siphon'
define_endpoint :my_ship_jump, post: 'my/ships/:id/jump'
define_endpoint :my_ship_navigate, post: 'my/ships/:id/navigate'
define_endpoint :my_ship_warp, post: 'my/ships/:id/warp'
define_endpoint :my_ship_refuel, post: 'my/ships/:id/refuel'
define_endpoint :my_ship_sell, post: 'my/ships/:id/sell'
end

View File

@ -20,6 +20,8 @@ class SpaceTraders::Model
end
def initialize(client, **attrs)
raise "Cannot use model with client parse disabled" if !client.parse?
@_client = client
attrs.each { self.send("#{_1}=", _2) }
end
@ -45,4 +47,7 @@ class SpaceTraders::Model
end
end
Dir['lib/models/*.rb'].each { load _1; warn "loaded #{_1}" }
Dir['lib/models/*.rb'].each do
load _1
SpaceTraders::Log.warn("load #{_1}")
end

15
lib/models/agent.rb Normal file
View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class SpaceTraders::Agent < SpaceTraders::Model
attributes :id,
:accountId,
:symbol,
:headquarters,
:credits,
:startingFaction,
:shipCount
def self.my_agent(client)
data = client.agents.my_agent
new(client, **data)
end
end

View File

@ -3,22 +3,31 @@
class SpaceTraders::Contract < SpaceTraders::Model
attributes :id, :factionSymbol, :type, :terms, :accepted, :fulfilled, :expiration, :deadlineToAccept
def self.my_contracts(client)
list = client.contracts.my_contracts
list.map { new(client, **_1) }
end
def accept!
client.contract.my_contracts_accept(id: id) { _1 } # {agent, contract}
client.contracts.my_contracts_accept(id: id) # {agent, contract}
end
def deliver!
client.contract.my_contracts_deliver(id: id) { _1 } # {agent, contract}
client.contracts.my_contracts_deliver(id: id) # {agent, contract}
self
end
def fulfill!
client.contract.my_contracts_fulfill(id: id) { _1 } # {agent, contract}
client.contracts.my_contracts_fulfill(id: id) # {agent, contract}
self
end
# refresh the contract attributes
def reload!
reload = client.contract.my_contract(id: id) { _1 }
reload.each { self[_1] = _2 }
client.contracts.my_contract(id: id).each { self[_1] = _2 }
self
end
def destination
end
end

113
lib/models/ship.rb Normal file
View File

@ -0,0 +1,113 @@
# frozen_string_literal: true
class SpaceTraders::Ship < SpaceTraders::Model
attributes :symbol,
:registration,
:nav,
:crew,
:frame,
:reactor,
:engine,
:cooldown,
:modules,
:mounts,
:cargo,
:fuel
def self.my_ships(client)
list = client.ships.my_ships
list.map { new(client, **_1) }
end
def update(**params)
params = client.data if params.empty?
attributes.each do
if params[_1]
self[_1] = _2
end
end
end
def reload!
update(**client.ships.my_ship(id: symbol))
self
end
def orbit!
client.ships.my_ship_orbit(id: symbol)
self
end
def refine!(material:)
client.ships.my_ship_refine(id: symbol, produce: material)
self
end
def survey!
client.ships.my_ship_survey(id: symbol)
self
end
def extract!(signature:, symbol:, deposits:, expiration:, size:)
client.ships.my_ship_extract(id: symbol, signature:, symbol:, deposits:, expiration:, size:)
self
end
def siphon!
client.ships.my_ship_siphon(id: symbol)
self
end
def jump!(waypoint:)
client.ships.my_ship_jump(id: symbol, waypointSymbol: waypoint)
self
end
def navigate!(waypoint:)
client.ships.my_ship_navigate(id: symbol, waypointSymbol: waypoint)
self
end
def warp!(waypoint:)
client.ships.my_ship_warp(id: symbol, waypointSymbol: waypoint)
self
end
def refuel!
client.ships.my_ship_refuel(id: symbol)
self
end
def sell!(cargo:, unit:)
client.ships.my_ship_warp(id: symbol, cargo:, unit:)
self
end
module Type
PROBE = "SHIP_PROBE"
MINING_DRONE = "SHIP_MINING_DRONE"
SIPHON_DRONE = "SHIP_SIPHON_DRONE"
INTERCEPTOR = "SHIP_INTERCEPTOR"
LIGHT_HAULER = "SHIP_LIGHT_HAULER"
COMMAND_FRIGATE = "SHIP_COMMAND_FRIGATE"
EXPLORER = "SHIP_EXPLORER"
HEAVY_FREIGHTER = "SHIP_HEAVY_FREIGHTER"
LIGHT_SHUTTLE = "SHIP_LIGHT_SHUTTLE"
ORE_HOUND = "SHIP_ORE_HOUND"
REFINING_FREIGHTER = "SHIP_REFINING_FREIGHTER"
SURVEYOR = "SHIP_SURVEYOR"
end
module Material
IRON = "IRON"
COPPER = "COPPER"
SILVER = "SILVER"
GOLD = "GOLD"
ALUMINUM = "ALUMINUM"
PLATINUM = "PLATINUM"
URANITE = "URANITE"
MERITIUM = "MERITIUM"
FUEL = "FUEL"
end
end

View File

@ -1,9 +1,49 @@
# frozen_string_literal: true
require 'syslog'
# require 'syslog/logger'
module SpaceTraders
class Log
CRIT = 0
ERROR = 1
WARN = 2
INFO = 3
DEBUG = 4
LEVELS = {
:crit => CRIT,
:error => ERROR,
:warn => WARN,
:info => INFO,
:debug => DEBUG,
}
LEVELS_STR = [CRIT, ERROR, WARN, INFO, DEBUG]
LEVELS.each do |level_str, level|
define_singleton_method(level_str) do |message|
SpaceTraders.log(level_str, message)
end
end
end
@@log_io = STDERR
@@log_min = Log::DEBUG
def self.log(level, message)
level_str = level.is_a?(Symbol) ? level : Log::LEVELS_STR[level]
level = level.is_a?(Integer) ? level : Log::LEVELS[level]
@@log_io.puts "#{Time.now.to_s} #{level_str.to_s.rjust(5).ljust(8)}: #{message}" if level <= @@log_min
end
log_io = STDERR
log_min = Log::DEBUG
Log.debug "log_io = #{log_io}"
Log.debug "log_min = #{log_min}"
end
Dir['lib/*.rb'].filter { _1 != 'lib/space_traders.rb' }.each do |f|
SpaceTraders::Log.warn("load #{f}")
load f
warn "loaded #{f}"
end