Packages

QUIC for Gleam, built on erlang_quic

Current section

Files

Jump to
glquic README.md
Raw

README.md

# glquic

[![check](https://trev.zip/llc/glquic/actions/workflows/check.yaml/badge.svg?branch=main&logo=forgejo&logoColor=%23bac2de&label=check&labelColor=%23313244)](https://trev.zip/llc/glquic/actions?workflow=check.yaml)
[![vulnerable](https://trev.zip/llc/glquic/actions/workflows/vulnerable.yaml/badge.svg?branch=main&logo=forgejo&logoColor=%23bac2de&label=vulnerable&labelColor=%23313244)](https://trev.zip/llc/glquic/actions?workflow=vulnerable.yaml)
[![nixpkgs](https://img.shields.io/endpoint?url=https%3A%2F%2Fnix-shield.trev.zip%2Fbadge%3Furl%3Dhttps%253A%252F%252Ftrev.zip%252Fllc%252Fglquic%252Fraw%252Fbranch%252Fmain%252Fflake.lock%26input%3Dnixpkgs&logoColor=%23bac2de&labelColor=%23313244&color=%235277C3)](https://nixos.org/)
[![gleam](https://img.shields.io/badge/dynamic/toml?url=https://trev.zip/llc/glquic/raw/branch/main/gleam.toml&query=%24.gleam&logo=gleam&logoColor=%23bac2de&label=version&labelColor=%23313244&color=%23FFAFF3)](https://gleam.run/)

QUIC for Gleam, built on [quicer](https://hex.pm/packages/quicer) and [msquic](https://github.com/microsoft/msquic)

## using

```sh
gleam add glquic
```

quicer compiles msquic into a NIF the first time it is built, which needs:

- Linux or macOS
- `cmake`, `make`, `perl`, `git` and a C compiler
- `libatomic` and `libnuma` on Linux

each listener, connection and stream sends its events as messages to the process that owns it: the one that accepted, connected or opened it

### client

```gleam
import glquic

pub fn main() {
  let options = glquic.client_options(alpn: ["echo"])
  let assert Ok(connection) =
    glquic.connect(to: "localhost", on: 4433, with: options, timeout: 5000)

  let assert Ok(stream) = glquic.open_stream(connection)
  let assert Ok(Nil) = glquic.send_and_finish(stream, <<"Hello, Joe!">>)

  case glquic.receive(within: 5000) {
    Ok(glquic.Data(data:, ..)) -> echo data
    _ -> panic as "no reply"
  }
}
```

### server

```gleam
import gleam/erlang/process
import glquic

pub fn main() {
  let options =
    glquic.server_options(
      alpn: ["echo"],
      certificate: "cert.pem",
      private_key: "key.pem",
    )
  let assert Ok(listener) = glquic.listen(on: 4433, with: options)
  accept_loop(listener)
}

fn accept_loop(listener: glquic.Listener) -> Nil {
  case glquic.accept(listener, 60_000) {
    Ok(connection) -> {
      let handler = process.spawn(fn() { handle(connection) })
      let assert Ok(Nil) = glquic.transfer_connection(connection, handler)
      Nil
    }
    Error(_) -> Nil
  }
  accept_loop(listener)
}

fn handle(connection: glquic.Connection) -> Nil {
  case glquic.accept_stream(connection, 60_000) {
    Ok(_stream) -> echo_loop()
    Error(_) -> Nil
  }
}

fn echo_loop() -> Nil {
  case glquic.receive(within: 60_000) {
    Ok(glquic.Data(stream:, data:, fin: True)) -> {
      let _ = glquic.send_and_finish(stream, data)
      echo_loop()
    }
    Ok(glquic.Data(stream:, data:, fin: False)) -> {
      let _ = glquic.send(stream, data)
      echo_loop()
    }
    Ok(glquic.ConnectionClosed(..)) | Error(Nil) -> Nil
    Ok(_) -> echo_loop()
  }
}
```

events can also be added to a selector with `glquic.select`, for use in actors

## contributing

see [CONTRIBUTING.md](CONTRIBUTING.md) for requirements and getting started