README.md

# yell

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

A Simple Service Discovery Protocol (SSDP) library for Gleam on Erlang.

SSDP is a UDP multicast protocol for discovering services on a local area network. It is a component of the Universal Plug and Play (UPnP) architecture but can be used independently. This library includes Gleam OTP actors for both sides of the protocol. This library aspires to provide high-level convienience for standard use cases while exposing the underlying components for more complex situations.

To get started:

```sh
gleam add yell
```

### Advertising a Service

To set up a service that will advertise itself every 30 seconds while replying to discovery requests:

```gleam

import gleam/erlang/process
import gleam/otp/static_supervisor as supervisor
import glip
import yell/service

pub fn main() {
  let assert Ok(addr) = glip.parse_ip("192.168.1.100")
  let assert Ok(service) = service.new(
    "urn:schemas-upnp-org:service:ContentDirectory:1",
    "uuid:my-service-id::urn:schemas-upnp-org:service:ContentDirectory:1"
  )

  let assert Ok(_supervisor) =
    service
    |> service.bind(addr)
    |> service.with_location("http://192.168.1.100:8008/device.xml")
    |> service.max_age(1800)
    |> service.supervisor(30_000)
    |> supervisor.start

  process.sleep_forever()
}
```

For finer-grained control, the notification and reply actors can be started separately; see [yell/service](https://hexdocs.pm/yell/yell/service.html).

### Discovering Services

To monitor SSDP services on an interface, listening for advertisements while sending out periodic
discovery requests:

```gleam

import gleam/erlang/process
import gleam/otp/static_supervisor as supervisor
import glip
import yell/monitor

pub fn main() -> Nil {
  let assert Ok(addr) = glip.parse_ip("192.168.1.100")
  let name = process.new_name("monitor")
  let subject = process.new_subject()
  let Ok(_actor) =
    monitor.new(name, subject)
    |> monitor.supervisor(addr)
    |> supervisor.start

  // do something with service appearances and disappearances
  let update = process.receive_forever(subject)
}
```

If you want to monitor more than one interface, you'll need to set up your own supervision tree with multiple [listeners](https://hexdocs.pm/yell/yell/listener.html) and [discoverers](https://hexdocs.pm/yell/yell/discoverer.html). A single `monitor` actor can subscribe to more than one `listener`.

Further documentation can be found at <https://hexdocs.pm/yell>.

## Development

To run the tests, you need to specify an interface for the actors to listen on
using the `SSDP_IP` environment variable. Broadcast typically does not work on
loopback interfaces.

```sh
SSPD_IP=192.168.1.100 gleam test
```

### Notes and Planned Work

- IPv6 is not supported due to an apparent limitation in erlang - trying to join
  an IPv6 multicast group results in an error.