Expresso.Watch.Server (expresso v0.1.0)

Copy Markdown View Source

Serves the page of the watch mode, and makes the page reload

The server is :httpd from the inets application of OTP, so it needs no dependency. It listens on 127.0.0.1 only, so no other computer can read the deck. Expresso.Watch.Host also refuses a request for a different host name, so a web page cannot read the deck with DNS rebinding.

The server serves a private directory from Expresso.PrivateDir, and that directory holds two files:

  • index.html - the last good document, with a small reload script at the end of the body.
  • version - the number of that render.

The script asks for version two times each second. When the number is not the number of its own document, the script reloads the page. The address holds the slide and the step, so the page shows the same step after the reload. The speaker view opens the same address, so it reloads too.

publish/2 writes the new document, and then the new number. Each write goes to a temporary file, and a rename then replaces the old file. The server thus never sends a part of a file.

The address / with a query, such as /?speaker= or /?scheme=dark, also gets index.html. The speaker view and the variants of a theme thus work in the watch mode.

The directory goes away when the process that started the server stops, and when the VM stops. Expresso.PrivateDir tells how.

This module owns the server and the script, so the two always change together. The file version and the script are internal: a later version can push the reload over a WebSocket, and the user sees no difference. The section "The watch mode" of docs/architecture.md gives the details.

Summary

Types

t()

A running server

Functions

Serve a new document, and tell each open page to reload

Start the server on a port of 127.0.0.1

Stop the server, and remove its directory

The address of the page of the server

Types

t()

@type t() :: %Expresso.Watch.Server{
  directory: Path.t(),
  pid: pid(),
  port: :inet.port_number(),
  private_dir: Expresso.PrivateDir.t(),
  version: non_neg_integer()
}

A running server

Functions

publish(server, html)

@spec publish(t(), String.t()) :: t()

Serve a new document, and tell each open page to reload

start(port)

@spec start(:inet.port_number()) :: {:ok, t()} | {:error, String.t()}

Start the server on a port of 127.0.0.1

The port 0 gives a free port, and url/1 then returns the address with that port. Until the first call of publish/2, the page shows a short text. For a port in use, the function returns an error message that names --port.

stop(server)

@spec stop(t()) :: :ok

Stop the server, and remove its directory

url(server)

@spec url(t()) :: String.t()

The address of the page of the server