README.md

# esdee

[![Package Version](https://img.shields.io/hexpm/v/esdee)](https://hex.pm/packages/esdee)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/esdee/)

Esdee is a DNS-SD discovery client for Gleam on Erlang.
It provides both selector-based and actor-based mechanisms 
to discover available service types and details.

The following example uses the `discoverer` actor
to enumerate and print all service types and service details on you local network.

```sh
gleam add esdee@1
```
```gleam
import esdee
import esdee/discoverer.{type Discoverer}
import gleam/erlang/process.{type Subject}
import gleam/io
import glip

type Discovered {
  ServiceType(String)
  ServiceDetails(esdee.ServiceDescription)
}

pub fn main() {
  // Create new discoverer that listens to both IPv4 and IPv6 DNS-SD messages
  let assert Ok(sd) =
    esdee.new()
    |> esdee.use_ipv6(True)
    |> discoverer.start()
  let sd = sd.data

  // Set up subjects for both service type and details discovery results
  let types = process.new_subject()
  let details = process.new_subject()

  // Subscribe to available service types,
  // and send a query for all available service types.
  discoverer.subscribe_to_service_types(sd, types)
  let assert Ok(_) = discoverer.poll_service_types(sd)

  // Combine both types of updates into one selector for printing
  let selector =
    process.new_selector()
    |> process.select_map(types, ServiceType)
    |> process.select_map(details, ServiceDetails)

  // Start handling updates
  recieve_forever(sd, selector, details)
}

fn recieve_forever(
  discoverer: Discoverer,
  selector: process.Selector(Discovered),
  details: Subject(esdee.ServiceDescription),
) -> Nil {
  let discovered = process.selector_receive_forever(selector)

  case discovered {
    ServiceType(service_type) -> {
      io.println("Discovered service type: " <> service_type)

      // When a service type is discovered,
      // subscribe to the details of and send a query for that type.
      // No duplicate subscriptions will be created,
      // but duplicate detail queries might be sent,
      // as we aren't doing any filtering on the types.
      discoverer.subscribe_to_service_details(discoverer, service_type, details)
      let assert Ok(_) =
        discoverer.poll_service_details(discoverer, service_type)
      Nil
    }

    ServiceDetails(description) -> {
      io.println(
        description.service_type
        <> " -> "
        <> description.target_name
        <> " @ "
        <> glip.ip_to_string(description.ip),
      )
    }
  }

  recieve_forever(discoverer, selector, details)
}
```

Common tasks:

```sh
gleam run   # Run the project
gleam test  # Run the tests
gleam dev   # Discover all your local services
```