-- Default public interface of Fluence nodes
aqua Builtin declares *

alias Field : []string
alias Argument : []string
alias Bytes : []u8
alias PeerId : string
alias Pairs : [][]string
alias Base58String : string
alias Hash : string
alias IPLDBlueprint : string
alias CID : string
alias Path : string

data Service:
    id: string
    blueprint_id: string
    -- `spell` or `service`
    service_type: string
    owner_id: string
    aliases: []string
    worker_id: string

data FunctionSignature:
    arguments: []Argument
    name: string
    output_types: []string

data RecordType:
    fields: []Field
    id: u64
    name: string

data Interface:
    function_signatures: []FunctionSignature
    record_types: []RecordType

data VmInfo:
    ip: string
    default_ssh_port: u16
    forwarded_ports: []string

data Info:
    external_addresses: []string
    node_version: string
    air_version: string
    spell_version: string
    allowed_binaries: []string
    vm_info: ?VmInfo

data ModuleWASIConfig:
    envs: ?Pairs
    mapped_dirs: ?Pairs
    mounted_binaries: ?Pairs

data ModuleConfig:
    name: string
    mem_pages_count: ?u32
    max_heap_size: ?string
    logger_enabled: ?bool
    logging_mask: ?i32
    wasi: ?ModuleWASIConfig

data Module:
    name: string
    hash: string
    config: ModuleConfig

data Blueprint:
    id: string
    name: string
    dependencies: []CID

data Contact:
    peer_id: string
    addresses: []string

-- A collection of measurements of a stat.
-- `avg` and `total` fields are computed over all measured stats and
-- `series` stores only several last measurements. The number of measurements
--  is configured on each peer.
data SeriesStat:
   avg: f64
   series: []f64
   total: f64

data Stats:
  -- Number of successful request
  success_req_count: u64
  -- Number of failed request
  failed_req_count: u64
  -- Duration of call execution in seconds
  call_time_sec: SeriesStat
  -- Amount of addintionally allocated memory after a call
  memory_deltas_bytes: SeriesStat
  -- Timestamps of the last measurments
  timestamps: []u64

data FunctionStat:
  name: string
  -- Series contain last measurements that were taken from last N calls to this function
  stats: Stats

data ServiceStat:
  -- Stats for the requested service in total.
  -- Series contain last measurements that were taken from last N calls to the service
  total_stats: Stats
  -- Stats for each interface function of the service
  functions_stats: []FunctionStat

data StatResult:
  status: bool
  error: string
  result: ?ServiceStat

data MemoryStat:
  -- module name
  name: string
  memory_size_bytes: u64
  max_memory_size_bytes: u64

service Op("op"):
    -- does nothing
    noop()

    -- returns length of the passed array
    array_length(array: []string) -> u32

    -- takes any number of arguments and wraps them into a single array
    -- see the doc on varargs https://doc.fluence.dev/aqua-book/libraries/aqua-lib#functions-with-a-variable-number-of-arguments
    array(a: string, b: string, c: string, d: string) -> []string

    -- takes any number of arrays and flattens them by concatenating
    -- see the doc on varargs https://doc.fluence.dev/aqua-book/libraries/aqua-lib#functions-with-a-variable-number-of-arguments
    concat(a: []string, b: []string, c: []string, d: []string) -> []string

    -- takes a single argument and returns it back
    identity(s: ?string) -> ?string

    -- encodes string's utf8 bytes as base58
    string_to_b58(s: string) -> Base58String

    -- decodes base58 to bytes to utf8 string
    -- throws error on invalid UTF8
    string_from_b58(b: Base58String) -> string

    -- encodes bytes as base58
    bytes_to_b58(bs: []u8) -> Base58String

    -- decodes base58 to bytes
    bytes_from_b58(b: Base58String) -> []u8

    -- Applies SHA256 to the given string
    -- Argument: s - string to apply sha256 to (hash is applied to utf8 bytes of s)
    -- Returns: returns sha256 multihash encoded as base58
    sha256_string(s: string) -> Base58String

    -- concatenate strings (in AIR it takes any number of arguments)
    concat_strings(a: string, b: string) -> string

service Peer("peer"):
    -- Get information about the peer
    identify() -> Info

    -- Get Unix timestamp in milliseconds
    timestamp_ms() -> u64

    -- Get Unix timestamp in seconds
    timestamp_sec() -> u64

    -- Blocks for the given number of milliseconds. Meant to be used within `par` blocks.
    -- message is returned after duration has passed
    timeout(duration_ms: u64, message: string) -> string

    ---- Low level functions for accessing connection pool

    -- Checks if there is a direct connection to the peer identified by a given PeerId
    -- Argument: PeerId – id of the peer to check if there's a connection with
    -- Returns: bool - true if connected to the peer, false otherwise
    -- NOTE:
    --  This is a very low-level function, it most likely won't fit your goals.
    --  It's almost always better to use race pattern to check connectivity.
    --  See https://doc.fluence.dev/aqua-book/language/flow/parallel#timeout-and-race-patterns
    is_connected(peer: PeerId) -> bool

    -- Initiates a connection to the specified peer
    -- Arguments:
    --  id - id of the target peer
    --  multiaddrs – an array of target peer's addresses
    -- Returns: bool - true if connection was successful
    -- NOTE:
    --  This is a low-level function, it most likely won't fit your goals.
    --  Most often you just need to use `on id:` and connection will be established automatically.
    connect(id: PeerId, multiaddrs: []string) -> bool

    -- Returns known multiaddresses of a peer
    -- Argument: PeerId – id of the target peer
    -- Returns:
    --  Contact - if target peer is connected to current peer,
    --  return data structure with multiaddresses inside, and nil otherwise.
    get_contact(peer: PeerId) -> ?Contact

service Kademlia("kad"):
    -- Instructs node to return the locally-known nodes
    -- in the Kademlia neighborhood for a given key
    -- Arguments:
    --  key – base58 string
    --  already_hashed – default false; if set to true, key is considered to be a SHA256 multihash
    --  count – default 20; limits number of returned nodes
    neighborhood(key: Base58String, already_hashed: ?bool, count: ?u32) -> []PeerId

    -- Merges given lists and sorts them by distance to target
    -- Arguments:
    --  target – base58 string; result is sorted by XOR distance to target
    --  left – list of base58 strings
    --  right – list of base58 strings
    --  count – how many items to return; default 20
    -- Returns: list of base58 strings sorted by distance to target; list will contain at most count elements
    merge(target: Base58String, left: []string, right: []string, count: ?u32) -> []string

service Srv("srv"):
    -- Used to create a service on a certain node
    -- Arguments:
    --  blueprint_id – ID of the blueprint that has been added to the node specified in the service call by the dist add_blueprint service.
    -- Returns: service_id – the service ID of the created service.
    create(blueprint_id: string) -> string

    -- Used to remove a service from a certain node
    -- Arguments:
    --  service_id – ID of the service to remove
    remove(service_id: string)

    -- Returns a list of services running on a peer
    list() -> []Service

    -- Adds an alias on service, so, service could be called
    -- not only by service_id but by alias as well.
    -- Arguments:
    --  alias - settable service name
    --  service_id – ID of the service whose interface you want to name.
    add_alias(alias: string, service_id: string)

    -- Resolves given alias to a service id
    -- If there's no such alias, throws an error
    -- Returns: service id associated with the given alias
    resolve_alias(alias: string) -> string

    -- Resolves given alias to a service id
    -- If there's no such alias, returns nil
    -- Returns: service id associated with the given alias or nil
    resolve_alias_opt(alias: string) -> ?string

    -- Retrieves the functional interface of a service running
    -- on the node specified in the service call
    -- Argument: service_id – ID of the service whose interface you want to retrieve.
    get_interface(service_id: string) -> Interface

    -- Retrieves information about service
    -- Argument: service_id – ID or alias of the service
    info(service_id: string) -> Service

service Dist("dist"):
    -- Constructs a ModuleConfig structure
    -- Arguments:
    --  module_name        - import name of the module
    --  mem_pages_count    - Maximum memory size accessible by a module in Wasm pages (64 Kb)
    --  logger_enabled     - Defines whether Marine should provide a special host log_utf8_string function for this module
    --  preopened_files    - Files available for this module. Module can access only files from this list
    --  envs               - environment variables available for this module
    --  mapped_dirs        - Directory mapping, e.g. [["/sites", "./web/data"]] so all
    --                       reads & writes to /sites will actually to go ./web/data
    --  mounted_binaries   - Mapping of host binaries available to call from module,
    --                       e.g. [["curl", "/usr/bin/curl"]] will allow module to
    --                       call /usr/bin/curl binary as function 'curl'
    --  logging_mask       - Binary mask to enable & disable logging targets. Targets are
    --                       configured in WasmLoggerBuilder::with_target_map
    --  mem_pages_count    - (deprecated) Maximum memory size accessible by a module in Wasm pages (64 Kb)
    --  max_heap_size      - Maximum module heap size, in bytes
    make_module_config(name: string, mem_pages_count: ?u32, max_heap_size: ?string, logger_enabled: ?bool, preopened_files: ?[]string, envs: ?Pairs, mapped_dirs: ?Pairs, mounted_binaries: ?Pairs, logging_mask: ?i32) -> ModuleConfig

    -- Constructs a ModuleConfig structure
    -- Arguments:
    --  module_name        - import name of the module
    default_module_config(module_name: string) -> ModuleConfig

    -- Used to add modules to the node specified in the service call
    -- Arguments:
    --  bytes – a base64 string containing the .wasm module to add.
    --  config – module info
    --  Returns: blake3 hash of the module
    -- NOTE: the config is IGNORED and only module's `name` is taken from it
    add_module(wasm_b56_content: Bytes, conf: ModuleConfig) -> string

    -- Adds module by copying it from Particle Vault directory
    -- Arguments:
    --  path   – path or a filename
    --  config - module config
    -- NOTE: the config is IGNORED and only module's `name` is taken from it
    add_module_from_vault(path: Path, config: ModuleConfig) -> Hash

    -- Adds module by copying it from Particle Vault directory
    -- Arguments:
    --  path   – path or a filename
    --  config - module config
    add_module_bytes_from_vault(name: string, module_cid: string) -> string

    -- Get a list of modules available on the node
    list_modules() -> []Module

    -- Get the interface of a module
    get_module_interface(module_hash: string) -> Interface

    -- Creates IPLD Blueprint structure from blueprint name and dependencies (modules)
    make_blueprint(name: string, dependencies: []CID) -> IPLDBlueprint
    -- Add an IPLD blueprint to the node
    add_blueprint(blueprint: IPLDBlueprint) -> string

    -- Loads blueprint by copying it from Particle Vault directory
    -- Arguments:
    --  blueprint_path   – path in Particle Vault
    load_blueprint(blueprint_path: Path) -> IPLDBlueprint

    -- Used to get the blueprints available on the node specified in the service call.
    -- A blueprint is an object of the following structure
    list_blueprints() -> []Blueprint

    -- Get a single blueprint
    get_blueprint(blueprint_id: string) -> Blueprint

data SignResult:
    -- Was call successful or not
    success: bool
    -- Error message. Will be null if the call is successful
    error: ?string
    -- Signature as byte array. Will be null if the call is not successful
    signature: ?[]u8

service Sig("sig"):
    -- Signs data with the service's private key.
    -- Depending on implementation the service might check call params to restrict usage for security reasons.
    -- By default it is only allowed to be used on the same peer the particle was initiated
    -- and accepts data only from the following sources:
    --   trust-graph.get_trust_bytes
    --   trust-graph.get_revocation_bytes
    --   registry.get_key_bytes (for FluenceJS only)
    --   registry.get_record_bytes
    --   registry.get_record_metadata_bytes
    -- Argument: data - byte array to sign
    -- Returns: signature as SignResult structure
    sign(data: []u8) -> SignResult

    -- Given the data and signature both as byte arrays, returns true if the signature is correct, false otherwise.
    verify(signature: []u8, data: []u8) -> bool

    -- Gets the peer id of the service's key pair.
    get_peer_id() -> string

-- Available only on rust peers
-- Aquire service statistic
service Stat("stat"):
  -- Detailed stats for the service and its interface functions
  service_stat(service_id: string) -> StatResult
  -- The amount of memeory allocated for each module of the service.
  service_memory(service_id: string) -> []MemoryStat

-- Service for debugging purposes only
service Debug("debug"):
    -- Convert any object into a string
    stringify(o: ⊤) -> string

service Console("run-console"):
    print(any: ⊤)

-- Particle File Vault
service Vault("vault"):
    -- Puts data into the vault and returns virtual path
    put(data: string) -> Path
    -- Returns the content of the file from the vault
    cat(path: Path) -> string